123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563 |
- #!/bin/sh
- #
- # $Id$
- #
- # SER configuration script
- #
- # disclaimer: extremely simplistic and experimental
- # useful only for people who know what they are doing
- # and want to save some typing
- #
- # call it to generate a basic script -- you have to
- # carry out any subsequent changes manually
- #
- # ------------------- Variables ------------------------
- # prompted variables
- # SER_DOMAIN -- name of served domain, e.g., foo.bar.com
- # SER_GWIP -- IP address of PSTN gateway, e.g. 10.0.0.1
- # parameters that are typically not changed
- SER_SQL_URI="mysql://ser:heslo@localhost/ser"
- # set LIB_PATH if all modules are installed in a single
- # directory; otherwise, modules are sought in 'modules'
- # subdirectories
- #SER_LIB_PATH="/usr/local/lib/ser/modules"
- # --------------------- functions ---------------------------
- function go_to_pstn()
- {
- if [ -n "$SER_GWIP" ] ; then
- cat << EOGOTOPSTN
- # 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;
- };
- EOGOTOPSTN
- fi
- }
- function addr2re()
- {
- echo $1 | sed -ne "s/\./\\\./gp"
- }
- function gw_check()
- {
- if [ -n "$SER_GWIP" ] ; then
- cat << EOGWTEST
- if (uri=~"sip:[+0-9]+@$SER_GWIP_RE") {
- # it is gateway -- proceed to ACLs
- route(3);
- break;
- };
- EOGWTEST
- fi
- }
- function mine_check()
- {
- printf "uri=~\"[@:](sip[\.)?$SER_DOMAIN_TEST_RE([;:].*)*\" $SER_GW_TEST_RE"
- }
- function gw_m_check()
- {
- if [ -n "$SER_GWIP" ] ; then
- cat << EOMCHECK
- if (search("^(Contact|m): .*$SER_GWIP_RE")) {
- log(1, "LOG: alert: protected contacts\n");
- sl_send_reply("476", "No Server Address in Contacts Allowed" );
- break;
- };
- EOMCHECK
- fi
- }
- function help()
- {
- cat << EOHELP
- Numbering plan is as follows:
- - numbers beginning with 8 are considered aliases
- - numbers beginning with + are considered ENUM destinations
- EOHELP
- if [ -n "$SER_GWIP" ] ; then
- cat << EOHELP2
- - all other numbers are considered PSTN destinations
- ... to dial PSTN, a user must have 'int' privilege
- EOHELP2
- else
- echo "- all other numbers are considered usernames"
- fi
- }
- function usage()
- {
- echo "Usage: $0 <domain_name> [<ip_address_of_gateway>]" \
- '> <config_file>' > /dev/stderr
- exit 1
- }
- function load_mod()
- {
- if [ -n "$SER_LIB_PATH" ] ; then
- echo "loadmodule \"$SER_LIB_PATH/$1.so\""
- else
- echo "loadmodule \"modules/$1/$1.so\""
- fi
- }
- # ----------------------- user-parameter check ---------------
- # SER_DOMAIN -- name of served domain, e.g., foo.bar.com
- # SER_GWIP -- IP address of PSTN gateway, e.g. 10.0.0.1
- if [ $# -gt 0 ] ; then
- SER_DOMAIN="$1"
- shift
- if [ $# -gt 0 ] ; then
- SER_GWIP="$1"
- shift
- fi
- if [ $# -gt 0 ] ; then
- usage
- fi
- else
- usage
- fi
- # ---------------------- initialization -------------------------
- # autodetection parameters
- SER_IP=`/sbin/ifconfig eth0 |
- sed -ne 's/\( \)*\(inet addr:\)\([0-9\.]*\).*/\3/gp'`
- # construction of regular expressions
- SER_IP_RE=`addr2re $SER_IP`
- SER_DOMAIN_RE=`addr2re $SER_DOMAIN`
- # tests
- # - is this for my domain
- SER_DOMAIN_TEST_RE=`printf "($SER_DOMAIN_RE|$SER_IP_RE)"`
- # - is this for my gateway ?
- if [ -n "$SER_GWIP" ] ; then
- SER_GWIP_RE=`addr2re $SER_GWIP`
- SER_GW_TEST_RE=`printf "| uri=~\"@$SER_GWIP_RE([;:].*)*\""`
- fi
- SER_REGISTRAR="registrar@$SER_DOMAIN"
- # ---------------------- verficiation --------------------------
- set | grep ^SER_ > /dev/stderr
- echo > /dev/stderr
- echo "IS EVERYTHING OK ???? (press ^C to interrupt)" > /dev/stderr
- read
- # --------------------- dump it here -------------------------
- cat << EOF
- #
- # \$Id$
- #
- # autogenerated SER configuration
- #
- # user: `id`
- # system: `uname -a`
- # date: `date`
- #
- # ----------- global configuration parameters ------------------------
- debug=3
- fork=yes
- port=5060
- log_stderror=no
- memlog=5
- mhomed=yes
- fifo="/tmp/ser_fifo"
- alias=$SER_DOMAIN
- # uncomment to override config values for test
- /*
- debug=3 # debug level (cmd line: -ddd)
- fork=no
- port=5068
- log_stderror=yes # (cmd line: -E)
- fifo="/tmp/ser_fifox"
- */
- check_via=no # (cmd. line: -v)
- dns=no # (cmd. line: -r)
- rev_dns=no # (cmd. line: -R)
- children=16
- # 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 ----------------------------------
- `load_mod tm`
- `load_mod sl`
- `load_mod acc`
- `load_mod rr`
- `load_mod maxfwd`
- `load_mod mysql`
- `load_mod usrloc`
- `load_mod registrar`
- `load_mod auth`
- `load_mod auth_db`
- `load_mod textops`
- `load_mod uri`
- `load_mod group`
- `load_mod msilo`
- `load_mod enum`
- # ----------------- setting module-specific parameters ---------------
- # all DB urls here
- modparam("usrloc|acc|auth_db|group|msilo|uri", "db_url",
- "$SER_SQL_URI")
- # -- usrloc params --
- /* 0 -- dont use mysql, 1 -- write_through, 2--write_back */
- modparam("usrloc", "db_mode", 2)
- modparam("usrloc", "timer_interval", 10)
- # -- auth params --
- modparam("auth_db", "calculate_ha1", yes)
- #modparam("auth_db", "user_column", "user_id")
- modparam("auth_db", "password_column", "password")
- modparam("auth", "nonce_expire", 300)
- # -- rr params --
- # add value to ;lr param to make some broken UAs happy
- modparam("rr", "enable_full_lr", 1)
- # -- acc params --
- # that is the flag for which we will account -- don't forget to
- modparam("acc", "db_flag", 1 )
- modparam("acc", "db_missed_flag", 3 )
- # -- tm params --
- modparam("tm", "fr_timer", 20 )
- modparam("tm", "fr_inv_timer", 90 )
- modparam("tm", "wt_timer", 20 )
- # -- msilo params
- modparam("msilo", "registrar", "sip:$SER_REGISTRAR")
- # -- enum params --
- #
- modparam("enum", "domain_suffix", "e164.arpa.")
- # ------------------------- 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","Alas Too Many Hops");
- break;
- };
- if (len_gt( max_len )) {
- sl_send_reply("513", "Message too large sorry");
- 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;
- };
- };
- # anti-spam -- if somene claims to belong to our domain in From,
- # challenge him (skip REGISTERs -- we will chalenge them later)
- if (search("(From|F):.*$SER_DOMAIN_TEST_RE")) {
- # invites forwarded to other domains, like FWD may cause subsequent
- # request to come from there but have iptel in From -> verify
- # only INVITEs (ignore FIFO/UAC's requests, i.e. src_ip==myself)
- if (method=="INVITE" & !(src_ip==$SER_IP)) {
- if (!(proxy_authorize( "$SER_DOMAIN" /* realm */,
- "subscriber" /* table name */ ))) {
- proxy_challenge("$SER_DOMAIN" /* realm */, "0" /* no-qop */);
- break;
- };
- # to maintain outside credibility of our proxy, we enforce
- # username in From to equal digest username; user with
- # "john.doe" id could advertise "bill.gates" in From otherwise;
- if (!check_from()) {
- log("LOG: From Cheating attempt in INVITE\n");
- sl_send_reply("403", "That is ugly -- use From=id next time (OB)");
- break;
- };
- # we better don't consume credentials -- some requests may be
- # spiraled through our server (sfo@iptel->7141@iptel) and the
- # subsequent iteration may challenge too, for example because of
- # iptel claim in From; UACs then give up because they
- # already submitted credentials for the given realm
- #consume_credentials();
- }; # INVITEs claiming to come from our domain
- } else if (method=="INVITE" && !(uri=~"[@:\.]$SER_DOMAIN_TEST_RE([;:].*)*"
- # ... and we serve our gateway too if present
- $SER_GW_TEST_RE )) {
- #the INVITE neither claims to come from our domain nor is it targeted to it
- # -> junk it
- sl_send_reply("403", "No relaying");
- break;
- };
- /* ********* RR ********************************** */
- # to be safe, record route everything; UAs may use different
- # transport protocols and need to have SER in path
- record_route();
- # if route forces us to forward to some explicit destination,
- # do so; check however first that a cheater didn't preload
- # a gateway destination to bypass PSTN ACLs
- if (loose_route()) {
- `gw_check`
- # route HF determined next hop; forward there
- append_hf("P-hint: rr-enforced\r\n");
- t_relay();
- break;
- };
- /* ********* check for requests targeted out of our domain... ******* */
- # sign of our domain: there is '@' (username) or : (nothing) in
- # front of our domain name ; ('.' is not there -- we handle all
- # xxx.iptel.org as outbound hosts);if none of these cases matches,
- # proceed with processing of outbound requests in route[2]
- if (!(`mine_check`)) {
- 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): .*@$SER_DOMAIN_TEST_RE")) {
- log(1, "LOG: alert: someone trying to set aor==contact\n");
- sl_send_reply("476", "No Server Address in Contacts Allowed" );
- break;
- };
- `gw_m_check`
- if (!www_authorize( "$SER_DOMAIN" /* realm */,
- "subscriber" /* table name */ )) {
- # challenge if none or invalid credentials
- www_challenge( "$SER_DOMAIN" /* realm */,
- "0" /* no qop -- some phones can't deal with it */);
- break;
- };
- # prohibit attempts to grab someone else's To address
- # using valid credentials;
- if (!check_to()) {
- log("LOG: To Cheating attempt\n");
- sl_send_reply("403", "That is ugly -- use To=id in REGISTERs");
- break;
- };
- # it is an authenticated request, update Contact database now
- if (!save("location")) {
- sl_reply_error();
- };
- m_dump();
- 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;
- };
- # is this an ENUM destination (leading +?)? give it a try, if the lookup
- # doesn't change URI, just continue
- if (uri=~"sip:\+[0-9]+@") {
- if (!enum_query("voice")) { # if parameter empty, it defaults to "e2u+sip"
- enum_query(""); # E2U+sip
- };
- } else {
- # aliases (take precedences over PSTN number; provisioning interface
- # is set up to assinge aliases beginning with 8)
- lookup("aliases");
- };
- # check again, if it is still for our domain after aliases are resolved
- if (!(`mine_check`)) {
- route(5);
- break;
- };
- `go_to_pstn`
- # 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
- `gw_check`
- /* ... and also report on missed calls ... */
- setflag(3);
- # 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
- # (keep in mind 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] {
- append_hf("P-hint: OUTBOUND\r\n");
- t_relay();
- }
- #------- 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");
- t_relay();
- }
- #----------------- PSTN ----------------------------------------------
- # logic for calls to the PSTN
- route[3] {
- # turn accounting on
- setflag(1);
- /* require all who call PSTN to be members of the "int" group;
- apply ACLs only to INVITEs -- we don't need to protect other requests, as they
- don't imply charges; also it could cause troubles when a call comes in via PSTN
- and goes to a party that can't authenticate (voicemail, other domain) -- BYEs would
- fail then; exempt Cisco gateway from authentication by IP address -- it does not
- support digest
- */
- if (method=="INVITE" && (!src_ip==$SER_GWIP)) {
- if (!proxy_authorize( "$SER_DOMAIN" /* realm */,
- "subscriber" /* table name */)) {
- proxy_challenge( "$SER_DOMAIN" /* realm */, "0" /* no qop */ );
- break;
- };
- # let's check from=id ... avoids accounting confusion
- 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;
- };
- if(!is_user_in("credentials", "int")) {
- sl_send_reply("403", "NO PSTN Privileges...");
- break;
- };
- consume_credentials();
- }; # INVITE to authorized PSTN
- # if you have passed through all the checks, let your call go to GW!
- rewritehostport("$SER_GWIP:5060");
- # snom conditioner
- if (method=="INVITE" && search("User-Agent: snom")) {
- replace("100rel, ", "");
- };
- append_hf("P-hint: GATEWAY\r\n");
- # use UDP to guarantee well-known sender port (TCP ephemeral)
- t_relay_to_udp("$SER_GWIP","5060");
- }
- /* *********** handling of unavailable user ******************* */
- route[4] {
- /**/
- # message store
- if (method=="MESSAGE") {
- t_newtran();
- if (m_store("0")) {
- t_reply("202", "Accepted for Later Delivery");
- } else {
- t_reply("503", "Service Unavailable");
- };
- break;
- };
- /**/
- # non-Voip -- just send "off-line"
- if (!(method=="INVITE" || method=="ACK" || method=="CANCEL")) {
- sl_send_reply("404", "Not Found");
- break;
- };
- # voicemail subscribers ...
- t_newtran();
- t_reply("404", "Not Found");
- # we account missed incoming calls; previous statteful processing
- # guarantees that retransmissions are not accounted
- if (method=="INVITE") {
- acc_db_request("404 missed call", "missed_calls");
- };
- }
- EOF
- help > /dev/stderr
|