# # $Id$ # # iptel.org real world configuration # # ----------- global configuration parameters ------------------------ debug=3 fork=yes port=5060 log_stderror=no memlog=4 listen=195.37.77.101 # uncomment to override config values for test /* debug=4 # debug level (cmd line: -ddd) fork=no port=5068 log_stderror=yes # (cmd line: -E) */ check_via=yes # (cmd. line: -v) dns=no # (cmd. line: -r) rev_dns=no # (cmd. line: -R) children=4 fifo="/tmp/ser_fifo" # if changing fifo mode to a more restrictive value, put # decimal value in there, e.g. dec(rw|rw|rw)=dec(666)=438 #fifo_mode=438 # ------------------ module loading ---------------------------------- loadmodule "../new_ser/modules/tm/tm.so" loadmodule "../new_ser/modules/sl/sl.so" loadmodule "../new_ser/modules/acc/acc.so" loadmodule "../new_ser/modules/rr/rr.so" loadmodule "../new_ser/modules/maxfwd/maxfwd.so" loadmodule "../new_ser/modules/mysql/mysql.so" loadmodule "../new_ser/modules/usrloc/usrloc.so" loadmodule "../new_ser/modules/registrar/registrar.so" loadmodule "../new_ser/modules/auth/auth.so" loadmodule "../new_ser/modules/textops/textops.so" # ----------------- setting module-specific parameters --------------- # -- usrloc params -- /* 0 -- dont use mysql, 1 -- write_through, 2--write_back */ modparam("usrloc", "db_mode", 2) modparam("usrloc", "timer_interval", 10) modparam("usrloc", "db_url","sql://ser:heslo@dbhost/ser") # -- auth params -- #modparam("auth", "calculate_ha1", yes) modparam("auth", "db_url","sql://ser:heslo@dbhost/ser") modparam("auth", "user_column", "user_id") # nonce generation secret; particularly useful if multiple servers # in a proxy farm are configured to authenticate #modparam("auth", "secret", "43sjkl33T9kjj_5jvlA384hg") modparam("auth", "nonce_expire", 300) modparam("auth", "retry_count", 5) # -- acc params -- # report ACKs too for sake of completeness -- as we account PSTN # destinations which are RR, ACKs should show up modparam("acc", "report_ack", 1) modparam("acc", "log_level", 1) # that is the flag for which we will account -- don't forget to # set the same one :-) /* Usage of flags is as follows: 1==should account(all to gateway), 2==should rr (all to gateway, MESSAGES, etc), 3==should report on missed calls (transactions to iptel.org's users), 4==destination user wishes to use voicemail */ modparam("acc", "acc_flag", 1 ) modparam("acc", "missed_flag", 3 ) # -- tm params -- modparam("tm", "fr_timer", 20 ) modparam("tm", "fr_inv_timer", 90 ) modparam("tm", "wt_timer", 20 ) modparam("tm", "uac_from", "sip:daemon@iptel.org" ) # ------------------------- request routing logic ------------------- # main routing logic route{ /* ********* ROUTINE CHECKS ********************************** */ # filter too old messages if (!mf_process_maxfwd_header("10")) { log("LOG: Too many hops\n"); sl_send_reply("483","Too Many Hops"); break; }; if (len_gt( max_len )) { sl_send_reply("513", "Wow -- Message too large"); break; }; # Make sure that requests dont advertise addresses # from private IP space (RFC1918) in Contact HF # (note: does not match with folded lines) if (search("^(Contact|m): .*@(192\.168\.|10\.|172\.16)")) { # allow RR-ed requests, as these may indicate that # a NAT-enabled proxy takes care of it; unless it is # a REGISTER if ((method=="REGISTER" || ! search("^Record-Route:")) && !( src_ip==192.168.0.0/16 || src_ip==10.0.0.0/8 || src_ip==172.16.0.0/12 )) { log("LOG: Someone trying to register from private IP again\n"); sl_send_reply("479", "We dont accept private IP contacts" ); break; }; }; /* ********* RR ********************************** */ /* Do strict routing if route headers present */ rewriteFromRoute(); /* ********* DIVERSION ********************************** */ /* apply all diversions before we proceed with processing of requests for us */ /* IM gateway diversions */ if (search("[\n\r]((To)|t):.*@icq\.iptel\.org") | search("[\n\r]((To)|t):.*@msn\.iptel\.org") | search("[\n\r]((To)|t):.*@aim\.iptel\.org") | search("[\n\r]((To)|t):.*@yahoo\.iptel\.org") | search("[\n\r]((To)|t):.*@jabber\.iptel\.org") ) { append_hf("P-hint: IMGW\r\n"); if (!t_relay_to("195.37.77.100", "5070")) { sl_reply_error(); }; break; }; /* divert voicemail requests */ if (uri=~"mail\.iptel\.org" | uri=~":5066"| uri=~":6060") { sethost("iptel.org"); append_hf("P-hint: VOICEMAIL\r\n"); if ( !t_relay_to("fox.iptel.org", "6060")) { sl_reply_error(); }; break; }; # this host is excempted from default processing for our domain # for testing purposes if (uri=~"@bat\.iptel\.org") { append_hf("P-hint: BATTEST\r\n"); forward("bat.iptel.org", 5060); break; }; /* ********* RR ********************************** */ # look at whether we need record-routing; # - we need it for calls from gateways (otherwise, subsequent # requests from the other # party will attempt to contact gateway # directly through blocked ports) # - we need it for Windows Messanger's IM sessions to cross # some firewalls -- we force all MESSAGEs to go via our server # to avoid blocking port numbers (some firewalls can do # standard SIP but are puzzled by Microsoft's use of obsoleted # IM session model) # - some other places may decide to set the record-routing # flag (2 chosen) too; particularly, INVITEs to our gw if ( (src_ip==195.37.77.110 & method=="INVITE") || method=="MESSAGE" || method=="INFO" ) { setflag(2); }; /* ********* check for requests targeted out of our domain... ******* */ # sign of our domain: there is @ (username), : # (nothing) or . (host) in front of our domain name ; # if none of these cases matches, proceed with proessing of # outbound requests in route[2] if (!(uri=~"[@:\.]iptel\.org([;:].*)*" # ... some phones put IP address in URI instead ... | uri=~"[@:\.]195\.37\.77\.101([;:].*)*" # ... and we serve our gateway too (we RR requests to it, so that # its address may show up in subsequent requests after # rewriteFromRoute | uri=~"@195\.37\.77\.110([;:].*)*" )) { route(2); break; }; /* ************ requests for our domain ********** */ /* now, the request is for sure for our domain */ # registers always MUST be authenticated to # avoid stealing incoming calls if (method=="REGISTER") { # Make sure that user's dont register infinite loops # (note: does not match with folded lines) if (search("^(Contact|m): .*@(195\.37\.77\.101|iptel\.org)")) { log(1, "LOG: alert: someone trying to set aor==contact\n"); sl_send_reply("476", "No Server Address in Contacts Allowed" ); break; }; if (search("^(Contact|m): .*195\.37\.77\.110")) { log(1, "LOG: alert: protected contacts\n"); sl_send_reply("476", "No Server Address in Contacts Allowed" ); break; }; # prohibit attempts to grab someone else's To address # using valid credentials; the only exception is the user # 'replciator' permitted to generate 3-rd party registrations if (!www_authorize( "iptel.org" /* realm */, "subscriber" /* table name */ )) { # challenge if none or invalid credentials www_challenge( "iptel.org" /* realm */, "0" /* no qop -- some phones can't deal with it */); break; }; if (!is_user("replicator") & !check_to()) { log("LOG: To Cheating attempt\n"); sl_send_reply("403", "That is ugly -- use To=id next time"); break; }; # it is an authenticated request, update Contact database now if (!save("location")) { sl_reply_error(); }; /* XXX not tested yet t_replicate("bat.iptel.org", "5060"); */ break; }; /* some UACs might be fooled by Contacts our UACs generate to make MSN happy (web-im, e.g.) -- tell its urneachable */ if (uri=~"sip:daemon@" ) { sl_send_reply("410", "daemon is gone"); break; }; # various aliases (might use a database in future) lookup("aliases"); # check again, if it is still for our domain after aliases # we have to include '.iptel.org' not to proceed to outbound # authentication for calls to mail.iptel.org and other hosts # served by us if ( !(uri=~"[@:\.]iptel\.org([;:].*)*" | uri=~"[@:\.]195\.37\.77\.101([;:].*)*" | uri=~"@195\.37\.77\.110([;:].*)*" )) { route(5); break; }; # now check if it's about PSTN destinations through our gateway; # note that 8.... is exempted for numerical non-gw destinations if (uri=~"sip:\+?[0-79][0-9]*@.*") { route(3); break; }; # does the user wish redirection on no availability? (i.e., is he # in the voicemail group?) -- determine it now and store it in # flag 4, before we rewrite the flag using UsrLoc if (is_user_in("Request-URI", "voicemail")) { setflag(4); } ; # native SIP destinations are handled using our USRLOC DB if (!lookup("location")) { # handle user which was not found ... route(4); break; }; # check whether some inventive user has uploaded gateway # contacts to UsrLoc to bypass our authorization logic if (uri=~"@195\.37\.77\.110([;:].*)*" ) { log(1, "LOG: Weird! Gateway address in UsrLoc!\n"); route(3); break; }; # if user is on-line and is in voicemail group, enable redirection if (method=="INVITE" && isflagset(4)) { t_on_negative("1"); }; /* ... and also report on missed calls ... note that reporting on missed calls is mutually exclusive with silent C timer */ setflag(3); # add RR to messages which were previously labeled for that if (isflagset(2)) { addRecordRoute(); }; # we now know we may, we know where, let it go out now! append_hf("P-hint: USRLOC\r\n"); if (!t_relay()) { sl_reply_error(); break; }; } #------------------- OUTBOUND ---------------------------------------- # routing logic for outbound requests targeted out of our domain # (beware, messages to our users can end up here too: for example, # an INVITE may be UsrLoc-ed, then the other party uses outbound # proxy with r-uri=the usr_loced addredd (typically IP)) route[2] { # outbound requests are allowed only for our users -- we don't # support relaying and don't like strangers bothering us # with resolving DNS; except our gateway if (!(src_ip==195.37.77.110) & !(proxy_authorize( "iptel.org" /* realm */, "subscriber" /* table name */ ))) { # ACK/CANCEL have inherently no security -- just log if # included credentials are wrong and proceed if (method=="ACK" ) { log("LOG: failed outbound authentication for ACK granted\n"); } else if (method=="CANCEL") { log("LOG: failed outbound authentication for CANCEL granted\n"); } else { proxy_challenge("iptel.org" /* realm */, "0" /* no-qop */); break; }; }; # to maintain credibility of our proxy, we check From in INVITEs to be # equal to credential id so that user john.doe does not put bill.gates # in his From; we don't do that for other requests: within a dialogue, # subsequent transactions coming from the other side will have in From # To of the original transaction to match the dialog; it may be # however different from user's default From and digest; example: # user_a sends INVITE to secretary; secretary is translated to user_b; # user_b accepts and later BYEs; to match the dialog, it puts # secretary in From and sends user_b's credentials -- check_from # would fail if (!src_ip==195.37.77.110 & method=="INVITE" & !check_from()) { log("LOG: From Cheating attempt\n"); sl_send_reply("403", "That is ugly -- use From=id next time (OB)"); break; }; if (isflagset(2)) { addRecordRoute(); ; }; append_hf("P-hint: OUTBOUND\r\n"); if (!t_relay()) { sl_reply_error(); break; }; } #------- ALIASED OUTBOUND -------------------------------------------- # routing logic for inbound requests aliased outbound; unlike # with real outbound requests we do not force authentication # as these calls are server by our server and we do not want # to disqualify unathenticated request originatiors from other # domains route[5] { append_hf("P-hint: ALIASED-OUTBOUND\r\n"); if (!t_relay()) { sl_reply_error(); break; }; } #----------------- PSTN ---------------------------------------------- # logic for calls to the PSTN route[3] { # if it is a MESSAGE pass it "as is" over to our SMS gateway # (which unfortunately lives at a different host due to # lack of serial interfaces) if (method=="MESSAGE") { # set accounting setflag(1); rewritehostport("195.37.77.100:5070"); append_hf("P-hint: SMS\r\n"); if (!t_relay()) { sl_reply_error(); }; break; }; # continue with requests to PSTN gateway ... # the international + prefix if (uri=~"sip:\+" ) { strip(1); prefix("000"); }; # free call destinations ... no authentication needed if ( is_user_in("Request-URI", "free-pstn") /* free destinations */ | uri=~"sip:[79][0-9][0-9][0-9]@.*" /* local PBX */ | uri=~"sip:98[0-9][0-9][0-9][0-9]") { # just log it, no authentication setflag(1); } else { # all other PSTN destinations only for authenticated users # (Cisco GW, which has no digest support, is authenticated # by its IP address -- that's for sure not very strong; # wth confirmed that we filter packets coming from outside # and bearing SRC IP address of our network) # we are forgiving about ACK/CANCEL as digest provides no # real security for them if (!(src_ip==195.37.77.110 | method==ACK | method=="CANCEL" )) { if (!proxy_authorize( "iptel.org" /* realm */, "subscriber" /* table name */)) { proxy_challenge( "iptel.org" /* realm */, "0" /* no qop */ ); break; # let's check from=id ... avoids accounting confusion } else if (method=="INVITE" & !check_from()) { log("LOG: From Cheating attempt\n"); sl_send_reply("403", "That is ugly -- use From=id next time (gw)"); break; }; }; # authorize only for INVITEs -- RR/Contact may result in weird # things showing up in d-uri that would break our logic; our # major concern is INVITE which causes PSTN costs anyway if (method=="INVITE") { # does the authenticated user have a permission for local # calls? (i.e., is he in the "local" group?) if (uri=~"sip:0[1-9][0-9]+@.*") { if (!is_in_group("local")) { sl_send_reply("403", "Local Toodle Noodle..."); break; }; # the same for long-distance } else if (uri=~"sip:00[1-9][0-9]+@.*") { if (uri=~"sip:001[089]" | uri=~"sip:00900.*" ) { sl_send_reply("403", "Added Value Destinations not permitted..."); break; }; if (!is_in_group("ld")) { sl_send_reply("403", "LD Toodle Noodle..."); break; }; # the same for international calls } else if (uri=~"sip:000[1-9][0-9]+@.*") { if (!is_in_group("int")) { sl_send_reply("403", "International Toodle Noodle..."); break; }; # everything else (e.g., interplanetary calls) is denied } else { sl_send_reply("403", "interplanetary Toodle Noodle..."); break; }; }; # INVITE to authorized PSTN # we passed all authorization checks for PSTN -- move on! # tag this transaction for accounting setflag(1); }; # authorized PSTN # requests to gateway must be record-routed because the GW accepts # only reqeusts coming from our proxy if (isflagset(2) || method=="INVITE") addRecordRoute(); # if you have passed through all the checks, let your call go to GW! rewritehostport("195.37.77.110:5060"); append_hf("P-hint: GATEWAY\r\n"); if (!t_relay()) { sl_reply_error(); break; }; } /* *********** handling of unavailable user ******************* */ /* handling of users who are off-line */ route[4] { # user not found -- act as stateful UAS to avoid reporting # on each INVITE retranmission if (method=="INVITE" || method=="ACK" || method=="BYE" || method=="CANCEL" ) { /* requests to voicemail users will be fwded to voicemail */ if (isflagset(4)) { rewritehostport("mail.iptel.org:6060"); append_hf("P-hint: OFFLINE-VOICEMAIL\r\n"); if (!t_relay()) { sl_reply_error(); }; } else { /* non-voicemail users get 404 */ if (t_newtran()) { if (method=="ACK") { log("oops -- ACK to a non-existent transaction"); drop; }; # we reply statefuly to avoid accounting of all # retransmissions if (!t_reply("404", "Not Found")) { sl_reply_error(); }; } else { sl_reply_error(); }; }; /* we account missed calls for all off-line users */ if (method=="INVITE") acc_request("404 Not Found"); break; }; # non-VoIP messages: just return 404 statelessly sl_send_reply("404", "Not Found"); } # initiate serial forking to voicemail for users who registered for it # (those users will be accounted for missed calls too since the # accounting flag #3 is set) # note: accounting relates to the status immediately after a final # negative reply came back, i.e., the order of execution is # 1) account failed transaction 2) set up serial forking to voicemail reply_route[1] { /* XX: note: unsafe if preloaded routes without username used */ revert_uri(); rewritehostport("mail.iptel.org:6060"); append_branch(); }