/* * $Id: reg_mod.c 2210 2007-05-11 11:56:59Z henningw $ * * Registrar module interface * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of openser, a free SIP server. * * openser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * openser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2003-03-11 updated to the new module exports interface (andrei) * 2003-03-16 flags export parameter added (janakj) * 2003-03-21 save_noreply added, provided by Maxim Sobolev * (janakj) * 2005-07-11 added sip_natping_flag for nat pinging with SIP method * instead of UDP package (bogdan) * 2006-09-19 AOR may be provided via an AVP instead of being fetched * from URI (bogdan) * 2006-10-04 removed the "desc_time_order" parameter, as its functionality * was moved to usrloc (Carsten Bock, BASIS AudioNet GmbH) * 2006-11-22 save_noreply and save_memory merged into save(); * removed the module parameter "use_domain" - now it is * imported from usrloc module (bogdan) * 2006-11-28 Added statistics tracking for the number of accepted/rejected * registrations, as well as for the max expiry time, max * contacts and default expiry time(Jeffrey Magder-SOMA Networks) * 2007-02-24 sip_natping_flag moved into branch flags, so migrated to * nathelper module (bogdan) * */ #include #include "../../sr_module.h" #include "../../timer.h" #include "../../dprint.h" #include "../../error.h" #include "../../socket_info.h" #include "../../items.h" #include "../usrloc/ul_mod.h" #include "../sl/sl_api.h" #include "save.h" #include "lookup.h" #include "reply.h" #include "reg_mod.h" MODULE_VERSION /* Module init & destroy function */ static int mod_init(void); static int child_init(int); static void mod_destroy(void); /* Fixup functions */ static int domain_fixup(void** param, int param_no); static int save_fixup(void** param, int param_no); static int str_fixup(void** param, int param_no); /* Functions */ static int add_sock_hdr(struct sip_msg* msg, char *str, char *foo); /* Default expires value in seconds */ int default_expires = 3600; /* Default q value multiplied by 1000 */ qvalue_t default_q = Q_UNSPECIFIED; /* If set to 1, lookup will put all contacts found in msg structure */ int append_branches = 1; /* If set to 1, username in aor will be case sensitive */ int case_sensitive = 0; /* if the TCP connection should be kept open */ int tcp_persistent_flag = -1; /* Minimum expires the phones are allowed to use in seconds * use 0 to switch expires checking off */ int min_expires = 60; /* Maximum expires the phones are allowed to use in seconds, * use 0 to switch expires checking off */ int max_expires = 0; /* Maximum number of contacts per AOR */ int max_contacts = 0; /* The value of Retry-After HF in 5xx replies */ int retry_after = 0; /* if the looked up contacts should be filtered based on supported methods */ int method_filtering = 0; /* if the Path HF should be handled */ int path_enabled = 0; /* if the Path HF should be inserted in the reply. * - STRICT (2): always insert, error if no support indicated in request * - LAZY (1): insert only if support indicated in request * - OFF (0): never insert */ int path_mode = PATH_MODE_STRICT; /* if the received- and nat-parameters of last Path uri should be used * to determine if UAC is nat'ed */ int path_use_params = 0; /* if instead of extacting the AOR from the request, it should be * fetched via this AVP ID */ char *aor_avp_param =0; unsigned short aor_avp_type=0; int_str aor_avp_name; char* rcv_avp_param = 0; unsigned short rcv_avp_type = 0; int_str rcv_avp_name; int use_domain = 0; char* realm_pref = ""; /* Realm prefix to be removed */ str realm_prefix; int sock_flag = -1; str sock_hdr_name = {0,0}; #define RCV_NAME "received" str rcv_param = str_init(RCV_NAME); stat_var *accepted_registrations; stat_var *rejected_registrations; stat_var *max_expires_stat; stat_var *max_contacts_stat; stat_var *default_expire_stat; /** SL binds */ struct sl_binds slb; /* * Exported functions */ static cmd_export_t cmds[] = { {"save", save, 1, save_fixup, REQUEST_ROUTE }, {"save", save, 2, save_fixup, REQUEST_ROUTE }, {"lookup", lookup, 1, domain_fixup, REQUEST_ROUTE | FAILURE_ROUTE }, {"registered", registered, 1, domain_fixup, REQUEST_ROUTE | FAILURE_ROUTE }, {"add_sock_hdr", add_sock_hdr, 1, str_fixup, REQUEST_ROUTE }, {0, 0, 0, 0, 0} }; /* * Exported parameters */ static param_export_t params[] = { {"default_expires", INT_PARAM, &default_expires }, {"default_q", INT_PARAM, &default_q }, {"append_branches", INT_PARAM, &append_branches }, {"case_sensitive", INT_PARAM, &case_sensitive }, {"tcp_persistent_flag",INT_PARAM, &tcp_persistent_flag }, {"realm_prefix", STR_PARAM, &realm_pref }, {"min_expires", INT_PARAM, &min_expires }, {"max_expires", INT_PARAM, &max_expires }, {"received_param", STR_PARAM, &rcv_param }, {"received_avp", STR_PARAM, &rcv_avp_param }, {"aor_avp", STR_PARAM, &aor_avp_param }, {"max_contacts", INT_PARAM, &max_contacts }, {"retry_after", INT_PARAM, &retry_after }, {"sock_flag", INT_PARAM, &sock_flag }, {"sock_hdr_name", STR_PARAM, &sock_hdr_name.s }, {"method_filtering", INT_PARAM, &method_filtering }, {"use_path", INT_PARAM, &path_enabled }, {"path_mode", INT_PARAM, &path_mode }, {"path_use_received", INT_PARAM, &path_use_params }, {0, 0, 0} }; /* We expose internal variables via the statistic framework below.*/ stat_export_t mod_stats[] = { {"max_expires", STAT_NO_RESET, &max_expires_stat }, {"max_contacts", STAT_NO_RESET, &max_contacts_stat }, {"default_expire", STAT_NO_RESET, &default_expire_stat }, {"accepted_regs", 0, &accepted_registrations }, {"rejected_regs", 0, &rejected_registrations }, {0, 0, 0} }; /* * Module exports structure */ struct module_exports exports = { "registrar", DEFAULT_DLFLAGS, /* dlopen flags */ cmds, /* Exported functions */ params, /* Exported parameters */ mod_stats, /* exported statistics */ 0, /* exported MI functions */ 0, /* exported pseudo-variables */ mod_init, /* module initialization function */ 0, mod_destroy, /* destroy function */ child_init, /* Per-child init function */ }; /* * Initialize parent */ static int mod_init(void) { xl_spec_t avp_spec; bind_usrloc_t bind_usrloc; DBG("registrar - initializing\n"); /* load the SL API */ if (load_sl_api(&slb)!=0) { LOG(L_ERR, "ERROR:registrar:mod_init: can't load SL API\n"); return -1; } realm_prefix.s = realm_pref; realm_prefix.len = strlen(realm_pref); rcv_param.len = strlen(rcv_param.s); if (rcv_avp_param && *rcv_avp_param) { if (xl_parse_spec(rcv_avp_param, &avp_spec, XL_THROW_ERROR|XL_DISABLE_MULTI|XL_DISABLE_COLORS)==0 || avp_spec.type!=XL_AVP) { LOG(L_ERR, "ERROR:registrar:mod_init: malformed or non AVP %s " "AVP definition\n", rcv_avp_param); return -1; } if(xl_get_avp_name(0, &avp_spec, &rcv_avp_name, &rcv_avp_type)!=0) { LOG(L_ERR, "ERROR:registrar:mod_init: [%s]- invalid " "AVP definition\n", rcv_avp_param); return -1; } } else { rcv_avp_name.n = 0; rcv_avp_type = 0; } if (aor_avp_param && *aor_avp_param) { if (xl_parse_spec(aor_avp_param, &avp_spec, XL_THROW_ERROR|XL_DISABLE_MULTI|XL_DISABLE_COLORS)==0 || avp_spec.type!=XL_AVP) { LOG(L_ERR, "ERROR:registrar:mod_init: malformed or non AVP %s " "AVP definition\n", aor_avp_param); return -1; } if(xl_get_avp_name(0, &avp_spec, &aor_avp_name, &aor_avp_type)!=0) { LOG(L_ERR, "ERROR:registrar:mod_init: [%s]- invalid " "AVP definition\n", aor_avp_param); return -1; } } else { aor_avp_name.n = 0; aor_avp_type = 0; } bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0); if (!bind_usrloc) { LOG(L_ERR, "registrar: Can't bind usrloc\n"); return -1; } /* Normalize default_q parameter */ if (default_q != Q_UNSPECIFIED) { if (default_q > MAX_Q) { DBG("registrar: default_q = %d, lowering to MAX_Q: %d\n", default_q, MAX_Q); default_q = MAX_Q; } else if (default_q < MIN_Q) { DBG("registrar: default_q = %d, raising to MIN_Q: %d\n", default_q, MIN_Q); default_q = MIN_Q; } } if (bind_usrloc(&ul) < 0) { return -1; } /* * Import use_domain parameter from usrloc */ use_domain = ul.use_domain; if (sock_hdr_name.s) { sock_hdr_name.len = strlen(sock_hdr_name.s); if (sock_hdr_name.len==0 || sock_flag==-1) { LOG(L_WARN,"WARN:registrar:init: empty sock_hdr_name or " "sock_flag no set -> reseting\n"); pkg_free(sock_hdr_name.s); sock_hdr_name.s = 0; sock_hdr_name.len = 0; sock_flag = -1; } } else if (sock_flag!=-1) { LOG(L_WARN,"WARN:registrar:init: sock_flag defined but no " "sock_hdr_name -> reseting flag\n"); sock_flag = -1; } /* fix the flags */ sock_flag = (sock_flag!=-1)?(1<REG_SAVE_ALL_FL) ) { LOG(L_ERR, "ERROR:registrar:save_fixup: bad flags <%s>\n", (char *)(*param)); return E_CFG; } if (ul.db_mode==DB_ONLY && flags®_SAVE_MEM_FL) { LOG(L_ERR, "ERROR:registrar:save_fixup: MEM flag set while " "using the DB_ONLY mode in USRLOC\n"); return E_CFG; } pkg_free(*param); *param = (void*)(unsigned long int)flags; return 0; } } /* * Convert char* parameter to str* */ static int str_fixup(void** param, int param_no) { str *s; if (param_no == 1) { s = (str*)pkg_malloc( sizeof(str) ); if (s==0) { LOG(L_ERR,"ERROR:registrar:str_fixup: no more pkg mem\n"); return E_UNSPEC; } s->s = (char*)*param; s->len = strlen(s->s); *param = (void*)s; } return 0; } static void mod_destroy(void) { free_contact_buf(); } #include "../../data_lump.h" #include "../../ip_addr.h" #include "../../ut.h" static int add_sock_hdr(struct sip_msg* msg, char *name, char *foo) { struct socket_info* si; struct lump* anchor; str *hdr_name; str hdr; char *p; hdr_name = (str*)name; si = msg->rcv.bind_address; if (parse_headers( msg, HDR_EOH_F, 0) == -1) { LOG(L_ERR,"ERROR:registrar:add_sock_hdr: failed to parse message\n"); goto error; } anchor = anchor_lump( msg, msg->unparsed-msg->buf, 0, 0); if (anchor==0) { LOG(L_ERR,"ERROR:registrar:add_sock_hdr: can't get anchor\n"); goto error; } hdr.len = hdr_name->len + 2 + si->sock_str.len + CRLF_LEN; if ( (hdr.s=(char*)pkg_malloc(hdr.len))==0 ) { LOG(L_ERR,"ERROR:registrar:add_sock_hdr: no more pkg mem\n"); goto error; } p = hdr.s; memcpy( p, hdr_name->s, hdr_name->len); p += hdr_name->len; *(p++) = ':'; *(p++) = ' '; memcpy( p, si->sock_str.s, si->sock_str.len); p += si->sock_str.len; memcpy( p, CRLF, CRLF_LEN); p += CRLF_LEN; if ( p-hdr.s!=hdr.len ) { LOG(L_CRIT,"BUG:registrar:add_sock_hdr: buffer overflow (%d!=%d)\n", (int)(long)(p-hdr.s),hdr.len); goto error1; } if (insert_new_lump_before( anchor, hdr.s, hdr.len, 0) == 0) { LOG(L_ERR, "ERROR:registrar:add_sock_hdr: can't insert lump\n"); goto error1; } return 1; error1: pkg_free(hdr.s); error: return -1; }