mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
564 lines
14 KiB
564 lines
14 KiB
#!/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
|