diff --git a/ChangeLog b/ChangeLog index 6070c79..697cd2a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ 0.5.12 ====== + 1-Jan-2006: - short-dial: use "302 Moved" to point to target 28-Dec-2005: - Call logging: display FROM & TO for calls. 26-Dec-2005: - Added a short-dial feature ("pi_shortdial_*" config options) 18-Dec-2005: - Grandstream "unregister at startup" works now diff --git a/doc/siproxd.conf.example b/doc/siproxd.conf.example index 3feb655..c1bdaf7 100644 --- a/doc/siproxd.conf.example +++ b/doc/siproxd.conf.example @@ -244,13 +244,19 @@ debug_port = 0 # # Quick Dial (Short Dial) # ability to define quick dial numbers that can be accessed by -# dialing "*nn" from a local phone. 'nn' corresponds to the entry number +# dialing "*00" from a local phone. '00' 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" +# Note: If this module is enabled, there does NOT exist a way to dial +# a "real" number like *01, siproxd will try to replace it by it's +# quick dial entry. # pi_shortdial_enable = 1 -pi_shortdial_akey = * +# +# the first character is the "key", the following characters give +# the length of the number string. E.g. "*00" allows qpeed dials +# from *01 to *99. (the number "*100" will be passed through unprocessed) +pi_shortdial_akey = *00 # # *01 sipphone echo test pi_shortdial_entry = 17474743246 diff --git a/src/plugin_shortdial.c b/src/plugin_shortdial.c index 69a2e0e..58d550b 100644 --- a/src/plugin_shortdial.c +++ b/src/plugin_shortdial.c @@ -40,95 +40,114 @@ static char const ident[]="$Id$"; /* configuration storage */ extern struct siproxd_config configuration; - - /* local prototypes */ -static int plugin_shortdial_process(sip_ticket_t *ticket); +static int plugin_shortdial_redirect(sip_ticket_t *ticket, int shortcut_no); +/* returns STS_SIP_SENT if processing is to be terminated, + * otherwise STS_SUCCESS (go on with processing) */ /* code (entry point) */ int plugin_shortdial(sip_ticket_t *ticket) { + int sts=STS_SUCCESS; + osip_uri_t *req_url; + int shortcut_no=0; + + if (!ticket || !ticket->sipmsg) return STS_FAILURE; DEBUGC(DBCLASS_PLUGIN,"plugin entered"); - - /* only deal with outoing calls (outgoing INVITE requests) */ - sip_find_direction(ticket, NULL); - if ((ticket->direction == DIR_OUTGOING) || - (MSG_IS_INVITE(ticket->sipmsg))) { - /* To header with username must exist, max of 2 characters */ - if (ticket && ticket->sipmsg && ticket->sipmsg && - ticket->sipmsg->to && ticket->sipmsg->to->url && - ticket->sipmsg->to->url->username && - (strlen(ticket->sipmsg->to->url->username) >= 2) && - configuration.pi_shortdial_akey) { - char digit1=ticket->sipmsg->to->url->username[0]; - /* check for "activation key" - 1st character in number dialled */ - if (digit1 == configuration.pi_shortdial_akey[0]) { - DEBUGC(DBCLASS_PLUGIN,"processing"); - plugin_shortdial_process(ticket); - } - } - } - - DEBUGC(DBCLASS_PLUGIN,"plugin left"); - return STS_SUCCESS; -} - - -/* private code */ -static int plugin_shortdial_process(sip_ticket_t *ticket) { - osip_uri_t *to_url=ticket->sipmsg->to->url; - osip_uri_t *req_url; - char *to_user=to_url->username; - char *new_to_user=NULL; - int shortcut_no=0; - int i, len; - - DEBUGC(DBCLASS_PLUGIN,"process: username=[%s]", to_user); - req_url=osip_message_get_uri(ticket->sipmsg); - /* escaped akey? (if it appears twice: e.g. "**1234" -> "*1234") */ - if (to_user[1] == configuration.pi_shortdial_akey[0]) { - /* shift left the whole string for 1 position (incl \0 termination)*/ - for (i=0; idirection != DIR_OUTGOING) return STS_SUCCESS; - } - /* extract number */ - shortcut_no = atoi(&(to_user[1])); + /* only INVITE and ACK are handled */ + if (!MSG_IS_INVITE(ticket->sipmsg) && !MSG_IS_ACK(ticket->sipmsg)) + return STS_SUCCESS; + + /* REQ URI with username must exist, length as defined in config, + * shortdial must be enabled and short dial key must match */ + if (!req_url || !req_url->username || + !configuration.pi_shortdial_akey || + (strlen(req_url->username) != strlen(configuration.pi_shortdial_akey)) || + (req_url->username[0] != configuration.pi_shortdial_akey[0])) + return STS_SUCCESS; /* ignore */ + + shortcut_no = atoi(&(req_url->username[1])); if (shortcut_no <= 0) return STS_SUCCESS; /* not a number */ - /* requested number is not defined */ + /* requested number is not defined (out of range) */ if (shortcut_no > configuration.pi_shortdial_entry.used) { - INFO ("shortdial: requested shortcut %i > available shortcuts", + DEBUGC(DBCLASS_PLUGIN, "shortdial: shortcut %i > available shortcuts", shortcut_no, configuration.pi_shortdial_entry.used); return STS_SUCCESS; } - /* actual replacement INVITE and To header */ - new_to_user=configuration.pi_shortdial_entry.string[shortcut_no-1]; - if (new_to_user) { - DEBUGC(DBCLASS_PLUGIN,"process: rewriting [%s]->[%s]", - to_user, new_to_user); - len=strlen(new_to_user)+1; /* include trailing "\0" */ - - /* Request URI */ - if (req_url && req_url->username) { - osip_free(req_url->username); - req_url->username=osip_malloc(len); - strncpy(req_url->username, new_to_user, len); - } - - /* To header */ - to_user=NULL; - osip_free(to_url->username); - to_url->username=osip_malloc(len); - strncpy(to_url->username, new_to_user, len); + /* requested number is not defined (empty) */ + if (!configuration.pi_shortdial_entry.string[shortcut_no-1]) { + DEBUGC(DBCLASS_PLUGIN, "shortdial: shortcut %i empty", shortcut_no); + return STS_SUCCESS; } - /* done */ - return STS_SUCCESS; + /* + * called number does match the short dial specification + */ + + /* outgoing INVITE request */ + if (MSG_IS_INVITE(ticket->sipmsg)) { + DEBUGC(DBCLASS_PLUGIN,"processing INVITE"); + sts=plugin_shortdial_redirect(ticket, shortcut_no); + } + /* outgoing ACK request: is result of a local 3xx answer (moved...) */ + else if (MSG_IS_ACK(ticket->sipmsg)) { + /* make sure we only catch ACKs caused by myself (**02 -> *02 legitime) */ + DEBUGC(DBCLASS_PLUGIN,"processing ACK"); + sts=STS_SIP_SENT; /* eat up the ACK that was directed to myself */ + } + + return sts; +} + + +/* private code */ +static int plugin_shortdial_redirect(sip_ticket_t *ticket, int shortcut_no) { + osip_uri_t *to_url=ticket->sipmsg->to->url; + char *to_user=to_url->username; + char *new_to_user=NULL; + int i, len; + osip_contact_t *contact = NULL; + + new_to_user=configuration.pi_shortdial_entry.string[shortcut_no-1]; + if (!new_to_user) return STS_SUCCESS; + + DEBUGC(DBCLASS_PLUGIN,"redirect: redirecting [%s]->[%s]", + to_user, new_to_user); + len=strlen(new_to_user)+1; /* include trailing "\0" */ + + /* use a "302 Moved temporarily" response back to the client */ + /* new target is within the Contact Header */ + + /* remove all Contact headers in message */ + for (i=0; (contact != NULL) || (i == 0); i++) { + osip_message_get_contact(ticket->sipmsg, 0, &contact); + if (contact) { + osip_list_remove(ticket->sipmsg->contacts,0); + osip_contact_free(contact); + } + } /* for i */ + + /* insert one new Contact header containing the new target address */ + osip_contact_init(&contact); + osip_uri_clone(to_url, &contact->url); + osip_free(contact->url->username); + contact->url->username=osip_malloc(len); + strcpy(contact->url->username, new_to_user); + + osip_list_add(ticket->sipmsg->contacts,contact,0); + + /* sent redirect message back to local client */ + sip_gen_response(ticket, 302 /*Moved temporarily*/); + + return STS_SIP_SENT; } diff --git a/src/proxy.c b/src/proxy.c index f3c67c4..1a506be 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -110,6 +110,7 @@ int proxy_request (sip_ticket_t *ticket) { /* * logging of passing calls */ +/*&&&& this should be moved to its own loggin plugin */ if (configuration.log_calls) { osip_uri_t *from_url = NULL; osip_uri_t *to_url = NULL; @@ -117,12 +118,13 @@ int proxy_request (sip_ticket_t *ticket) { char *to_host = NULL; char *from_username =NULL; char *from_host = NULL; + char *call_type = NULL; - /* From: 1st preference is contact header, then use From field */ - if (!osip_list_eol(request->contacts, 0)) { - from_url = ((osip_contact_t*)(request->contacts->node->element))->url; - } else { + /* From: 1st preference is From header, then try contact header */ + if (request->from->url) { from_url = request->from->url; + } else { + from_url = (osip_uri_t *)osip_list_get(request->contacts, 0); } to_url = request->to->url; @@ -139,20 +141,24 @@ int proxy_request (sip_ticket_t *ticket) { /* INVITE */ if (MSG_IS_INVITE(request)) { - INFO("%s Call: %s@%s -> %s@%s", - (type==REQTYP_INCOMING) ? "Incoming":"Outgoing", - from_username ? from_username: "*NULL*", - from_host ? from_host : "*NULL*", - to_username ? to_username : "*NULL*", - to_host ? to_host : "*NULL*"); + if (type==REQTYP_INCOMING) call_type="Incoming"; + else call_type="Outgoing"; /* BYE / CANCEL */ + } else if (MSG_IS_ACK(request)) { + call_type="ACK"; } else if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) { - INFO("Ending Call: %s@%s -> %s@%s", + call_type="Ending"; + } + + if (call_type) { + INFO("%s Call: %s@%s -> %s@%s", + call_type, from_username ? from_username: "*NULL*", from_host ? from_host : "*NULL*", to_username ? to_username : "*NULL*", to_host ? to_host : "*NULL*"); } + } /* log_calls */ diff --git a/src/register.c b/src/register.c index 5d42ed5..6012342 100644 --- a/src/register.c +++ b/src/register.c @@ -256,7 +256,7 @@ int register_client(sip_ticket_t *ticket, int force_lcl_masq) { /* answer the request myself. Most likely this is an UNREGISTER * request when the client just booted */ sts = register_response(ticket, STS_SUCCESS); - return STS_RESP_SENT; + return STS_SIP_SENT; } return STS_SUCCESS; diff --git a/src/security.c b/src/security.c index 20de850..68a0ad6 100644 --- a/src/security.c +++ b/src/security.c @@ -97,7 +97,23 @@ int security_check_raw(char *sip_buffer, int size) { DEBUGC(DBCLASS_SIP,"security_check_raw: found only one space"); return STS_FAILURE; } - + + /* libosip2 can be put into an endless loop by trying to parse: + ---BUFFER DUMP follows--- + 49 4e 56 49 54 45 20 20 53 49 50 2f 32 2e 30 0d INVITE SIP/2.0. + 0a 56 69 61 3a 20 53 49 50 2f 32 2e 30 2f 55 44 .Via: SIP/2.0/UD + Note, this is an INVITE with no valid SIP URI (INVITE SIP/2.0) + */ + /* clumsy... */ + if (size >20) { + if (strncmp(sip_buffer, "INVITE SIP/2.0", 15)==0) return STS_FAILURE; + else if (strncmp(sip_buffer, "ACK SIP/2.0", 12)==0) return STS_FAILURE; + else if (strncmp(sip_buffer, "BYE SIP/2.0", 12)==0) return STS_FAILURE; + else if (strncmp(sip_buffer, "CANCEL SIP/2.0", 15)==0) return STS_FAILURE; + else if (strncmp(sip_buffer, "REGISTER SIP/2.0",17)==0) return STS_FAILURE; + else if (strncmp(sip_buffer, "OPTIONS SIP/2.0", 16)==0) return STS_FAILURE; + else if (strncmp(sip_buffer, "INFO SIP/2.0", 13)==0) return STS_FAILURE; + } /* TODO: still way to go here ... */ return STS_SUCCESS; diff --git a/src/sip_utils.c b/src/sip_utils.c index ecc119e..f0aaca9 100644 --- a/src/sip_utils.c +++ b/src/sip_utils.c @@ -84,6 +84,14 @@ osip_message_t *msg_make_template_reply (sip_ticket_t *ticket, int code) { osip_to_clone (request->to, &response->to); osip_from_clone (request->from, &response->from); + /* if 3xx, also include 1st contact header */ + if ((code>=300) && (code<400)) { + osip_contact_t *req_contact = NULL; + osip_contact_t *res_contact = NULL; + osip_message_get_contact(request, 0, &req_contact); + osip_contact_clone (req_contact, &res_contact); + osip_list_add(response->contacts,res_contact,0); + } /* via headers */ pos = 0; diff --git a/src/siproxd.c b/src/siproxd.c index fa773ff..0c33ff7 100644 --- a/src/siproxd.c +++ b/src/siproxd.c @@ -426,7 +426,10 @@ int main (int argc, char *argv[]) * additional preprocessing *********************************/ /* Dial shortcuts */ - if (configuration.pi_shortdial) plugin_shortdial(&ticket); + if (configuration.pi_shortdial) { + sts = plugin_shortdial(&ticket); + if (sts == STS_SIP_SENT) goto end_loop; + } /********************************* diff --git a/src/siproxd.h b/src/siproxd.h index d0d5685..8336363 100644 --- a/src/siproxd.h +++ b/src/siproxd.h @@ -262,7 +262,7 @@ int sip_message_set_body(osip_message_t * sip, const char *buf, int len); #define STS_FAILURE 1 /* FAILURE */ #define STS_FALSE 1 /* FALSE */ #define STS_NEED_AUTH 1001 /* need authentication */ -#define STS_RESP_SENT 2001 /* response is already sent */ +#define STS_SIP_SENT 2001 /* SIP packet is already sent */ /* symbolic direction of data */ #define DIR_INCOMING 1