diff --git a/doc/siproxd.conf.example b/doc/siproxd.conf.example index e7b5701..7733668 100644 --- a/doc/siproxd.conf.example +++ b/doc/siproxd.conf.example @@ -325,8 +325,9 @@ plugin_shortdial_entry = 17474745000 ###################################################################### # Plugin_defaulttarget # +# Log redirects to syslog plugin_defaulttarget_log = 1 # target must be a full SIP URI with the syntax -# sip:user@hst[:port] +# sip:user@host[:port] plugin_defaulttarget_target = sip:internal@dddd:port diff --git a/doc/siproxd_guide.sgml b/doc/siproxd_guide.sgml index 8cba4d2..0749077 100644 --- a/doc/siproxd_guide.sgml +++ b/doc/siproxd_guide.sgml @@ -47,7 +47,7 @@ 0.7.1 2008-01-27 tries@users.sourceforge.net - Plugin API + Plug-in API @@ -308,11 +308,6 @@ daemonize = 1 silence_log = 0 - - - Siproxd can log call establishment to syslog. - -log_calls = 1 If siproxd is started as root, it can drop the root @@ -468,23 +463,6 @@ debug_port = 0 #outbound_domain_name = freenet.de #outbound_domain_host = proxy.for.domain.freende.de #outbound_domain_port = 5060 - - - Quick-Dial "Plug-in": - ability to define quick dial numbers that can be accessed by - dialing "*nn" from a local phone. 'nn' corresponds to the entry number - pi_shortdial_entry) below. The '*' character can be chosen freely - (pi_shortdial_akey). - Note: To call a real number like "*1234" you would have to dial - "**1234" - -pi_shortdial_enable = 1 -pi_shortdial_akey = * -# -# *01 sipphone echo test -pi_shortdial_entry = 17474743246 -# *02 sipphone welcome message -pi_shortdial_entry = 17474745000 @@ -497,6 +475,7 @@ pi_shortdial_entry = 17474745000 -h, --help help -d, --debug <pattern> set debug-pattern -c, --config <cfgfile> use the specified config file +-p, --pid-file <pidfile> create pid file at <pidfile> These options take precedence over the values configured in the configuration file. @@ -527,31 +506,31 @@ pi_shortdial_entry = 17474745000 Chroot() Jail Create chroot jail - What files must be present? + What files must be present? To be completed! - - + + - Plugins + Plug-ins - + - Plugin API - Siproxd plugins are dynamic loadable libraries and must provide + Plug-in API + Siproxd plug-ins are dynamic loadable libraries and must provide 3 functions towards siproxd: + int plugin_init(plugin_def_t *plugin_def); int plugin_process(int stage, sip_ticket_t *ticket); int plugin_end(plugin_def_t *plugin_def); - The plugin_init function is called when - the plugin is loaded during startup of siproxd. The plugin must - defined the following 4 fields of the plugin_def structure: + the plug-in is loaded during startup of siproxd. The plug-in must + define the following 4 fields of the plugin_def structure: api_version name @@ -560,21 +539,23 @@ int plugin_end(plugin_def_t *plugin_def); Example code fragment: + -/* API version number of siproxd that this plugin is built against. +/* API version number of siproxd that this plug-in is built against. * This constant will change whenever changes to the API are made - * that require adaptions in the plugin. */ + * that require adaptions in the plug-in. */ plugin_def->api_version=SIPROXD_API_VERSION; -/* Name and descriptive text of the plugin */ +/* Name and descriptive text of the plug-in. Those item MUST NOT be + on the stack but either allocated via malloc (and then freed + of course) or a static string in the plug-in. */ plugin_def->name=strdup("plugin_demo"); plugin_def->desc=strdup("This is just a demo plugin without any purpose"); /* Execution mask - during what stages of SIP processing shall - * the plugin be called. */ + * the plug-in be called. */ plugin_def->exe_mask=PLUGIN_DETERMINE_TARGET|PLUGIN_PRE_PROXY; - The plugin_process function is called at the requested SIP processing stages (see 'execution mask'). @@ -582,15 +563,16 @@ plugin_def->exe_mask=PLUGIN_DETERMINE_TARGET|PLUGIN_PRE_PROXY; The plugin_end function is called at - shutdown of siproxd and gives the plugin the opportunity + shutdown of siproxd and gives the plug-in the opportunity to clean up and properly shutdown itself. Note: The previously allocated 'name' and 'desc' must be - freed by the plugin. + freed by the plug-in. If you did use a static string then of + course you must not try to free() anything. Minimum required clean up procedure: int plugin_end(plugin_def_t *plugin_def){ - /* free my allocated rescources */ + /* free my allocated rescources (if allocated via malloc only) */ if (plugin_def->name) {free(plugin_def->name); plugin_def->name=NULL;} if (plugin_def->desc) {free(plugin_def->desc); plugin_def->desc=NULL;} return STS_SUCCESS; @@ -598,49 +580,130 @@ int plugin_end(plugin_def_t *plugin_def){ - For a simple example refer to the simple demonstration plugin + For a simple example refer to the simple demonstration plug-in plugin_demo. - . + + + Each plug-in can have its own set of configuration parameters + in siproxd.conf. The plug-in has to define + a cfgopts_t structure and call + read_config during its initialization. Look at + plugin_demo for a simple example. The naming of + the config parameters is by definition + plugin_name_option. + - + - Available Plugins - The following plugins are provided with siproxd: + Available Plug-ins + The following plug-ins are provided with siproxd: plugin_demo - Demo plugin. Provides the basic framework to - be used for plugins. + Demo plug-in. Provides the basic framework to + be used for plug-ins. + + plugin_logcall + Very simplistic call logging to syslog. plugin_shortdial Quick Dial feature. + plugin_defaulttarget + Incoming calls to a non-existing UA are + redirected to a specific target (catch-all). + - Some of the plugins are described in more detail in the + Some of the plug-ins are described in more detail in the following chapters. - - - - - Quick Dial - - Since 0.5.12, Siproxd includes a Quick-Dial feature. This - allows you to define SIP numbers that can be accessed by - using a shortctu (like "*nn") from any local SIP phone. - For example, the following lines in your siproxd.conf will - configure 2 Quick-Dial numbers: + + + + Demo Plug-in + Name: plugin_demo + Purpose: To be used as skeletton for your own plug-ins. + Configuration options: -# *01 sipphone echo test -pi_shortdial_entry = 17474743246 -# *02 sipphone welcome message -pi_shortdial_entry = 17474745000 +plugin_demo_string = This_is_a_string_passed_to_the_demo_plugin - The numbering starts with "1" ("*01") and every following - "pi_shortdial_entry" entry will allocate the following position. - Curently it is not possible to freely assign the positions. + Description: + This plug-in can be used as framework for your own plug-ins. + It contains the required code for the API and also shows + how to load plug-in specific configuration parameters. + + + + + + + Call Logging Plug-in + Name: plugin_logcall + Purpose: Does a very simplistic call logging to syslog. + Configuration options: + +none + + Description: + XXXXXXXXXXXXXXXXxThe numbering starts with "1" ("*01") and every following + "plugin_shortdial_entry" entry will allocate the following position. + It is not possible to freely assign the positions. + + + + + + Short Dial Plug-in + Name: plugin_shortdial.c + Purpose: Provides a quick-Dial feature. + + +# The first character is the "key", the following characters give +# the length of the number string. E.g. "*00" allows speed dials +# from *01 to *99. (the number "*100" will be passed through unprocessed) +plugin_shortdial_akey = *00 +# +# *01 sipphone echo test +plugin_shortdial_entry = 17474743246 +# *02 sipphone welcome message +plugin_shortdial_entry = 17474745000 + + Description: + Allows the definition of quick dial entries. E.g. + *01 to *99 can be defined to redirect the caller. + Note: Currently only the user part (phone number) can + be replaced, the domain part will not be changed (means + a short dial tarket of sip:111@other.domain.com will + not work). The '*' character can be chosen freely + (plugin_shortdial_akey). + Note: To call a real number like "*12" you have to dial + "**12" + + + + + + + Default Target Plug-in + Name: plugin_defaulttarget + Purpose: Incoming calls to non-existing local UAs are + redirected to another SIP URI. + Configuration options: + +# Log redirects to syslog +plugin_defaulttarget_log = 1 +# target must be a full SIP URI with the syntax +# sip:user@host[:port] +plugin_defaulttarget_target = sip:defaulttarget@some.sip.domain:port + + Description: + Incoming SIP calls directed to a non-existing (registered) + local UA will be redirected to another target. This basically + implements a catch-all feature. The new target can be any SIP + URI and is not required to be local. + @@ -734,14 +797,14 @@ pi_shortdial_entry = 17474745000 - - + + Sample Configurations Check also the FAQ in the siproxd package. - - - + + + The "Standard Scenario" Scenario: @@ -783,9 +846,9 @@ ipchains -A input --proto udp --dport 7070:7089 -j ACCEPT incoming RTP traffic). - - - + + + GS BT-100 behind NAT Router running Siproxd Scenario: @@ -812,7 +875,6 @@ hosts_allow_reg = 10.0.0.0/24 sip_listen_port = 5060 daemonize = 1 silence_log = 1 -log_calls = 1 user = siproxd registration_file = /var/lib/siproxd_registrations pid_file = /var/run/siproxd/siproxd.pid @@ -858,9 +920,9 @@ Send DTMF: via RTP (RFC2833) - - - + + + GS BT-100 with Siproxd running "in front of" a NAT router Scenario: @@ -894,7 +956,6 @@ hosts_allow_reg = 10.0.0.0/24 sip_listen_port = 5060 daemonize = 1 silence_log = 1 -log_calls = 1 user = siproxd registration_file = /var/lib/siproxd_registrations pid_file = /var/run/siproxd/siproxd.pid @@ -940,9 +1001,9 @@ Send DTMF: via RTP (RFC2833) - - - + + + Transparent SIP Proxy Scenario: @@ -971,7 +1032,6 @@ hosts_allow_reg = 10.0.0.0/24 sip_listen_port = 5060 daemonize = 1 silence_log = 1 -log_calls = 1 user = siproxd registration_file = /var/lib/siproxd_registrations pid_file = /var/run/siproxd/siproxd.pid @@ -994,9 +1054,9 @@ iptables -A INPUT -m udp -p udp -i ppp0 --dport 7070:7089 -j ACCEPT - - - + + + Masquerading an Asterisk box Scenario: @@ -1029,7 +1089,6 @@ hosts_allow_reg = 10.0.0.0/24 sip_listen_port = 5060 daemonize = 1 silence_log = 1 -log_calls = 1 user = siproxd registration_file = /var/lib/siproxd_registrations pid_file = /var/run/siproxd/siproxd.pid diff --git a/src/proxy.c b/src/proxy.c index 28213ea..9d37b91 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -383,6 +383,11 @@ sts=sip_obscure_callid(ticket); */ } else { /* get the destination from the SIP URI */ +/*&&&& Here, the SRV record lookup magic must go. +In a first implementation we may just try to get the lowest priority, +max weighted '_sip._udp.domain' entry and port number. +No load balancing and no failover are supported with this. +&&&*/ sts = get_ip_by_host(url->host, &sendto_addr); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_PROXY, "proxy_request: cannot resolve URI [%s]", @@ -667,7 +672,7 @@ sts=sip_obscure_callid(ticket); /*&&&& priority probably should be: * 1) Route header * 2) fixed outbound proxy - * 3) SIP URI + * 3) Via header */ /* * check if we need to send to an outbound proxy diff --git a/src/resolve.c b/src/resolve.c index 708f94f..580d22f 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -35,36 +35,44 @@ static char const ident[]="$Id$"; /* local functions */ -static int _resolve(char *name, int proto, int type, +static int _resolve(char *name, int class, int type, char *dname, int dnamelen, int *port); -#define PROTO_UDP 1 -#define PROTO_TCP 2 - /* * perform a SRV record lookup + * + * name name of service + * dname return + * dnamelen length of return buffer + * port port number of service */ -int resolve_SRV(char *name, int proto, char *dname, int dnamelen, int *port) { - return _resolve(name, proto, T_SRV, dname, dnamelen, port); +int resolve_SRV(char *name, char *dname, int dnamelen, int *port) { + char nname[256]; + snprintf(nname, sizeof(nname), "_sip._udp.%s", name); + return _resolve(name, C_IN, T_SRV, dname, dnamelen, port); } +#if 0 /* * perform a NAPTR lookup + * + * name name of service + * dname return + * dnamelen length of return buffer */ int resolve_NAPTR(char *name, char *dname, int dnamelen) { int port=0; - return _resolve(name, 0, T_NAPTR, dname, dnamelen, &port); + return _resolve(name, C_ANY, T_NAPTR, dname, dnamelen, &port); } - +#endif /* * query the DNS for a specific record type */ -static int _resolve(char *name, int proto, int type, +static int _resolve(char *name, int class, int type, char *dname, int dnamelen, int *port) { int sts; - int class=C_ANY; // message buffer unsigned char msg[PACKETSZ]; @@ -90,7 +98,6 @@ static int _resolve(char *name, int proto, int type, dname[0]='\0'; *port=0; - // issue request sts=res_query(name, class, type, msg, msglen); if (sts<0) { @@ -141,7 +148,44 @@ static int _resolve(char *name, int proto, int type, mptr += sizeof(short); xptr = mptr; mptr += j; - if( ty == T_NAPTR ) { + if( ty == T_SRV ) { + u_short pr; + u_short we; + u_short po; + usp = (unsigned short *)xptr; + pr = ntohs( *usp ); + xptr += sizeof( short ); + usp = (unsigned short *)xptr; + we = ntohs( *usp ); + xptr += sizeof( short ); + usp = (unsigned short *)xptr; + po = ntohs( *usp ); + xptr += sizeof( short ); + j = dn_expand( msg, msg + PACKETSZ, xptr, tmpname, MAXDNAME ); + if( j < 0 ) { + break; + } else { + DEBUGC(DBCLASS_DNS, "_resolve: A[%i] - type SRV pr=%i, we=%i, " + "po=%i name=[%s]", i, pr, we, po, tmpname); + if( !priority || pr < priority || + (pr == priority && we > weight) ) { + priority = pr; + weight = we; + *port = po; + strncpy(dname, tmpname, dnamelen); +/*&&& here the magic with the priorities should go. +which one do we use? RFC3263 talks a bit on how a stateless +SIP proxy should handle it - BY GOING STATEFUL if the lowest priority +is unavailable. Why do I have a stateless proxy? Exactly, because I +do NOT want to do the whole stateful crap. +Rethinking needed. +Currently just the first (lowest prio, highest weight) entry is returned. +*/ + xptr+=j; + } + } +#if 0 + } else if( ty == T_NAPTR ) { DEBUGC(DBCLASS_DNS, "_resolve: A - type NAPTR"); usp = (unsigned short *)xptr; xptr += sizeof(short); @@ -171,7 +215,10 @@ static int _resolve(char *name, int proto, int type, } else { /* * there should be some REGEX magic, no? + * Not yet used nor implemented. Just complain in + * case somebody feels lucky enough trying to use it. */ +ERROR("_resolve: NAPTR lookup not yet supported."); if( proto == PROTO_UDP ) { if( strstr(tmpname, "_udp" ) ) { strncpy(dname, tmpname, dnamelen); @@ -185,34 +232,7 @@ static int _resolve(char *name, int proto, int type, i, tmpname); xptr+=j; } - } else if( ty == T_SRV ) { - u_short pr; - u_short we; - u_short po; - usp = (unsigned short *)xptr; - pr = ntohs( *usp ); - xptr += sizeof( short ); - usp = (unsigned short *)xptr; - we = ntohs( *usp ); - xptr += sizeof( short ); - usp = (unsigned short *)xptr; - po = ntohs( *usp ); - xptr += sizeof( short ); - j = dn_expand( msg, msg + PACKETSZ, xptr, tmpname, MAXDNAME ); - if( j < 0 ) { - break; - } else { - DEBUGC(DBCLASS_DNS, "_resolve: A[%i] - type SRV pr=%i, we=%i, " - "po=%i name=[%s]", i, pr, we, po, tmpname); - if( !priority || pr < priority || - (pr == priority && we < weight) ) { - priority = pr; - weight = we; - *port = po; - strncpy(dname, tmpname, dnamelen); - xptr+=j; - } - } +#endif } else { ERROR("_resolve: unknown type in DNS answer [type=%i]\n", ty); } // if ty