serconf.sh 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. #!/bin/sh
  2. #
  3. # $Id$
  4. #
  5. # SER configuration script
  6. #
  7. # disclaimer: extremely simplistic and experimental
  8. # useful only for people who know what they are doing
  9. # and want to save some typing
  10. #
  11. # call it to generate a basic script -- you have to
  12. # carry out any subsequent changes manually
  13. #
  14. # ------------------- Variables ------------------------
  15. # prompted variables
  16. # SER_DOMAIN -- name of served domain, e.g., foo.bar.com
  17. # SER_GWIP -- IP address of PSTN gateway, e.g. 10.0.0.1
  18. # parameters that are typically not changed
  19. SER_SQL_URI="mysql://ser:heslo@localhost/ser"
  20. # set LIB_PATH if all modules are installed in a single
  21. # directory; otherwise, modules are sought in 'modules'
  22. # subdirectories
  23. #SER_LIB_PATH="/usr/local/lib/ser/modules"
  24. # --------------------- functions ---------------------------
  25. function go_to_pstn()
  26. {
  27. if [ -n "$SER_GWIP" ] ; then
  28. cat << EOGOTOPSTN
  29. # now check if it's about PSTN destinations through our gateway;
  30. # note that 8.... is exempted for numerical non-gw destinations
  31. if (uri=~"sip:\+?[0-79][0-9]*@.*") {
  32. route(3);
  33. break;
  34. };
  35. EOGOTOPSTN
  36. fi
  37. }
  38. function addr2re()
  39. {
  40. echo $1 | sed -ne "s/\./\\\./gp"
  41. }
  42. function gw_check()
  43. {
  44. if [ -n "$SER_GWIP" ] ; then
  45. cat << EOGWTEST
  46. if (uri=~"sip:[+0-9]+@$SER_GWIP_RE") {
  47. # it is gateway -- proceed to ACLs
  48. route(3);
  49. break;
  50. };
  51. EOGWTEST
  52. fi
  53. }
  54. function mine_check()
  55. {
  56. printf "uri=~\"[@:](sip[\.)?$SER_DOMAIN_TEST_RE([;:].*)*\" $SER_GW_TEST_RE"
  57. }
  58. function gw_m_check()
  59. {
  60. if [ -n "$SER_GWIP" ] ; then
  61. cat << EOMCHECK
  62. if (search("^(Contact|m): .*$SER_GWIP_RE")) {
  63. log(1, "LOG: alert: protected contacts\n");
  64. sl_send_reply("476", "No Server Address in Contacts Allowed" );
  65. break;
  66. };
  67. EOMCHECK
  68. fi
  69. }
  70. function help()
  71. {
  72. cat << EOHELP
  73. Numbering plan is as follows:
  74. - numbers beginning with 8 are considered aliases
  75. - numbers beginning with + are considered ENUM destinations
  76. EOHELP
  77. if [ -n "$SER_GWIP" ] ; then
  78. cat << EOHELP2
  79. - all other numbers are considered PSTN destinations
  80. ... to dial PSTN, a user must have 'int' privilege
  81. EOHELP2
  82. else
  83. echo "- all other numbers are considered usernames"
  84. fi
  85. }
  86. function usage()
  87. {
  88. echo "Usage: $0 <domain_name> [<ip_address_of_gateway>]" \
  89. '> <config_file>' > /dev/stderr
  90. exit 1
  91. }
  92. function load_mod()
  93. {
  94. if [ -n "$SER_LIB_PATH" ] ; then
  95. echo "loadmodule \"$SER_LIB_PATH/$1.so\""
  96. else
  97. echo "loadmodule \"modules/$1/$1.so\""
  98. fi
  99. }
  100. # ----------------------- user-parameter check ---------------
  101. # SER_DOMAIN -- name of served domain, e.g., foo.bar.com
  102. # SER_GWIP -- IP address of PSTN gateway, e.g. 10.0.0.1
  103. if [ $# -gt 0 ] ; then
  104. SER_DOMAIN="$1"
  105. shift
  106. if [ $# -gt 0 ] ; then
  107. SER_GWIP="$1"
  108. shift
  109. fi
  110. if [ $# -gt 0 ] ; then
  111. usage
  112. fi
  113. else
  114. usage
  115. fi
  116. # ---------------------- initialization -------------------------
  117. # autodetection parameters
  118. SER_IP=`/sbin/ifconfig eth0 |
  119. sed -ne 's/\( \)*\(inet addr:\)\([0-9\.]*\).*/\3/gp'`
  120. # construction of regular expressions
  121. SER_IP_RE=`addr2re $SER_IP`
  122. SER_DOMAIN_RE=`addr2re $SER_DOMAIN`
  123. # tests
  124. # - is this for my domain
  125. SER_DOMAIN_TEST_RE=`printf "($SER_DOMAIN_RE|$SER_IP_RE)"`
  126. # - is this for my gateway ?
  127. if [ -n "$SER_GWIP" ] ; then
  128. SER_GWIP_RE=`addr2re $SER_GWIP`
  129. SER_GW_TEST_RE=`printf "| uri=~\"@$SER_GWIP_RE([;:].*)*\""`
  130. fi
  131. SER_REGISTRAR="registrar@$SER_DOMAIN"
  132. # ---------------------- verficiation --------------------------
  133. set | grep ^SER_ > /dev/stderr
  134. echo > /dev/stderr
  135. echo "IS EVERYTHING OK ???? (press ^C to interrupt)" > /dev/stderr
  136. read
  137. # --------------------- dump it here -------------------------
  138. cat << EOF
  139. #
  140. # \$Id$
  141. #
  142. # autogenerated SER configuration
  143. #
  144. # user: `id`
  145. # system: `uname -a`
  146. # date: `date`
  147. #
  148. # ----------- global configuration parameters ------------------------
  149. debug=3
  150. fork=yes
  151. port=5060
  152. log_stderror=no
  153. memlog=5
  154. mhomed=yes
  155. fifo="/tmp/ser_fifo"
  156. alias=$SER_DOMAIN
  157. # uncomment to override config values for test
  158. /*
  159. debug=3 # debug level (cmd line: -ddd)
  160. fork=no
  161. port=5068
  162. log_stderror=yes # (cmd line: -E)
  163. fifo="/tmp/ser_fifox"
  164. */
  165. check_via=no # (cmd. line: -v)
  166. dns=no # (cmd. line: -r)
  167. rev_dns=no # (cmd. line: -R)
  168. children=16
  169. # if changing fifo mode to a more restrictive value, put
  170. # decimal value in there, e.g. dec(rw|rw|rw)=dec(666)=438
  171. #fifo_mode=438
  172. # ------------------ module loading ----------------------------------
  173. `load_mod tm`
  174. `load_mod sl`
  175. `load_mod acc`
  176. `load_mod rr`
  177. `load_mod maxfwd`
  178. `load_mod mysql`
  179. `load_mod usrloc`
  180. `load_mod registrar`
  181. `load_mod auth`
  182. `load_mod auth_db`
  183. `load_mod textops`
  184. `load_mod uri`
  185. `load_mod group`
  186. `load_mod msilo`
  187. `load_mod enum`
  188. # ----------------- setting module-specific parameters ---------------
  189. # all DB urls here
  190. modparam("usrloc|acc|auth_db|group|msilo|uri", "db_url",
  191. "$SER_SQL_URI")
  192. # -- usrloc params --
  193. /* 0 -- dont use mysql, 1 -- write_through, 2--write_back */
  194. modparam("usrloc", "db_mode", 2)
  195. modparam("usrloc", "timer_interval", 10)
  196. # -- auth params --
  197. modparam("auth_db", "calculate_ha1", yes)
  198. #modparam("auth_db", "user_column", "user_id")
  199. modparam("auth_db", "password_column", "password")
  200. modparam("auth", "nonce_expire", 300)
  201. # -- rr params --
  202. # add value to ;lr param to make some broken UAs happy
  203. modparam("rr", "enable_full_lr", 1)
  204. # -- acc params --
  205. # that is the flag for which we will account -- don't forget to
  206. modparam("acc", "db_flag", 1 )
  207. modparam("acc", "db_missed_flag", 3 )
  208. # -- tm params --
  209. modparam("tm", "fr_timer", 20 )
  210. modparam("tm", "fr_inv_timer", 90 )
  211. modparam("tm", "wt_timer", 20 )
  212. # -- msilo params
  213. modparam("msilo", "registrar", "sip:$SER_REGISTRAR")
  214. # -- enum params --
  215. #
  216. modparam("enum", "domain_suffix", "e164.arpa.")
  217. # ------------------------- request routing logic -------------------
  218. # main routing logic
  219. route{
  220. /* ********* ROUTINE CHECKS ********************************** */
  221. # filter too old messages
  222. if (!mf_process_maxfwd_header("10")) {
  223. log("LOG: Too many hops\n");
  224. sl_send_reply("483","Alas Too Many Hops");
  225. break;
  226. };
  227. if (len_gt( max_len )) {
  228. sl_send_reply("513", "Message too large sorry");
  229. break;
  230. };
  231. # Make sure that requests dont advertise addresses
  232. # from private IP space (RFC1918) in Contact HF
  233. # (note: does not match with folded lines)
  234. if (search("^(Contact|m): .*@(192\.168\.|10\.|172\.16)")) {
  235. # allow RR-ed requests, as these may indicate that
  236. # a NAT-enabled proxy takes care of it; unless it is
  237. # a REGISTER
  238. if ((method=="REGISTER" || ! search("^Record-Route:"))
  239. && !( src_ip==192.168.0.0/16 ||
  240. src_ip==10.0.0.0/8 || src_ip==172.16.0.0/12 )) {
  241. log("LOG: Someone trying to register from private IP again\n");
  242. sl_send_reply("479", "We dont accept private IP contacts" );
  243. break;
  244. };
  245. };
  246. # anti-spam -- if somene claims to belong to our domain in From,
  247. # challenge him (skip REGISTERs -- we will chalenge them later)
  248. if (search("(From|F):.*$SER_DOMAIN_TEST_RE")) {
  249. # invites forwarded to other domains, like FWD may cause subsequent
  250. # request to come from there but have iptel in From -> verify
  251. # only INVITEs (ignore FIFO/UAC's requests, i.e. src_ip==myself)
  252. if (method=="INVITE" & !(src_ip==$SER_IP)) {
  253. if (!(proxy_authorize( "$SER_DOMAIN" /* realm */,
  254. "subscriber" /* table name */ ))) {
  255. proxy_challenge("$SER_DOMAIN" /* realm */, "0" /* no-qop */);
  256. break;
  257. };
  258. # to maintain outside credibility of our proxy, we enforce
  259. # username in From to equal digest username; user with
  260. # "john.doe" id could advertise "bill.gates" in From otherwise;
  261. if (!check_from()) {
  262. log("LOG: From Cheating attempt in INVITE\n");
  263. sl_send_reply("403", "That is ugly -- use From=id next time (OB)");
  264. break;
  265. };
  266. # we better don't consume credentials -- some requests may be
  267. # spiraled through our server (sfo@iptel->7141@iptel) and the
  268. # subsequent iteration may challenge too, for example because of
  269. # iptel claim in From; UACs then give up because they
  270. # already submitted credentials for the given realm
  271. #consume_credentials();
  272. }; # INVITEs claiming to come from our domain
  273. } else if (method=="INVITE" && !(uri=~"[@:\.]$SER_DOMAIN_TEST_RE([;:].*)*"
  274. # ... and we serve our gateway too if present
  275. $SER_GW_TEST_RE )) {
  276. #the INVITE neither claims to come from our domain nor is it targeted to it
  277. # -> junk it
  278. sl_send_reply("403", "No relaying");
  279. break;
  280. };
  281. /* ********* RR ********************************** */
  282. # to be safe, record route everything; UAs may use different
  283. # transport protocols and need to have SER in path
  284. record_route();
  285. # if route forces us to forward to some explicit destination,
  286. # do so; check however first that a cheater didn't preload
  287. # a gateway destination to bypass PSTN ACLs
  288. if (loose_route()) {
  289. `gw_check`
  290. # route HF determined next hop; forward there
  291. append_hf("P-hint: rr-enforced\r\n");
  292. t_relay();
  293. break;
  294. };
  295. /* ********* check for requests targeted out of our domain... ******* */
  296. # sign of our domain: there is '@' (username) or : (nothing) in
  297. # front of our domain name ; ('.' is not there -- we handle all
  298. # xxx.iptel.org as outbound hosts);if none of these cases matches,
  299. # proceed with processing of outbound requests in route[2]
  300. if (!(`mine_check`)) {
  301. route(2);
  302. break;
  303. };
  304. /* ************ requests for our domain ********** */
  305. /* now, the request is for sure for our domain */
  306. # registers always MUST be authenticated to
  307. # avoid stealing incoming calls
  308. if (method=="REGISTER") {
  309. # Make sure that user's dont register infinite loops
  310. # (note: does not match with folded lines)
  311. if (search("^(Contact|m): .*@$SER_DOMAIN_TEST_RE")) {
  312. log(1, "LOG: alert: someone trying to set aor==contact\n");
  313. sl_send_reply("476", "No Server Address in Contacts Allowed" );
  314. break;
  315. };
  316. `gw_m_check`
  317. if (!www_authorize( "$SER_DOMAIN" /* realm */,
  318. "subscriber" /* table name */ )) {
  319. # challenge if none or invalid credentials
  320. www_challenge( "$SER_DOMAIN" /* realm */,
  321. "0" /* no qop -- some phones can't deal with it */);
  322. break;
  323. };
  324. # prohibit attempts to grab someone else's To address
  325. # using valid credentials;
  326. if (!check_to()) {
  327. log("LOG: To Cheating attempt\n");
  328. sl_send_reply("403", "That is ugly -- use To=id in REGISTERs");
  329. break;
  330. };
  331. # it is an authenticated request, update Contact database now
  332. if (!save("location")) {
  333. sl_reply_error();
  334. };
  335. m_dump();
  336. break;
  337. };
  338. # some UACs might be fooled by Contacts our UACs generate to make MSN
  339. # happy (web-im, e.g.) -- tell its urneachable
  340. if (uri=~"sip:daemon@" ) {
  341. sl_send_reply("410", "daemon is gone");
  342. break;
  343. };
  344. # is this an ENUM destination (leading +?)? give it a try, if the lookup
  345. # doesn't change URI, just continue
  346. if (uri=~"sip:\+[0-9]+@") {
  347. if (!enum_query("voice")) { # if parameter empty, it defaults to "e2u+sip"
  348. enum_query(""); # E2U+sip
  349. };
  350. } else {
  351. # aliases (take precedences over PSTN number; provisioning interface
  352. # is set up to assinge aliases beginning with 8)
  353. lookup("aliases");
  354. };
  355. # check again, if it is still for our domain after aliases are resolved
  356. if (!(`mine_check`)) {
  357. route(5);
  358. break;
  359. };
  360. `go_to_pstn`
  361. # native SIP destinations are handled using our USRLOC DB
  362. if (!lookup("location")) {
  363. # handle user which was not found ...
  364. route(4);
  365. break;
  366. };
  367. # check whether some inventive user has uploaded gateway
  368. # contacts to UsrLoc to bypass our authorization logic
  369. `gw_check`
  370. /* ... and also report on missed calls ... */
  371. setflag(3);
  372. # we now know we may, we know where, let it go out now!
  373. append_hf("P-hint: USRLOC\r\n");
  374. if (!t_relay()) {
  375. sl_reply_error();
  376. break;
  377. };
  378. }
  379. #------------------- OUTBOUND ----------------------------------------
  380. # routing logic for outbound requests targeted out of our domain
  381. # (keep in mind messages to our users can end up here too: for example,
  382. # an INVITE may be UsrLoc-ed, then the other party uses outbound
  383. # proxy with r-uri=the usr_loced addredd (typically IP))
  384. route[2] {
  385. append_hf("P-hint: OUTBOUND\r\n");
  386. t_relay();
  387. }
  388. #------- ALIASED OUTBOUND --------------------------------------------
  389. # routing logic for inbound requests aliased outbound; unlike
  390. # with real outbound requests we do not force authentication
  391. # as these calls are server by our server and we do not want
  392. # to disqualify unathenticated request originatiors from other
  393. # domains
  394. route[5] {
  395. append_hf("P-hint: ALIASED-OUTBOUND\r\n");
  396. t_relay();
  397. }
  398. #----------------- PSTN ----------------------------------------------
  399. # logic for calls to the PSTN
  400. route[3] {
  401. # turn accounting on
  402. setflag(1);
  403. /* require all who call PSTN to be members of the "int" group;
  404. apply ACLs only to INVITEs -- we don't need to protect other requests, as they
  405. don't imply charges; also it could cause troubles when a call comes in via PSTN
  406. and goes to a party that can't authenticate (voicemail, other domain) -- BYEs would
  407. fail then; exempt Cisco gateway from authentication by IP address -- it does not
  408. support digest
  409. */
  410. if (method=="INVITE" && (!src_ip==$SER_GWIP)) {
  411. if (!proxy_authorize( "$SER_DOMAIN" /* realm */,
  412. "subscriber" /* table name */)) {
  413. proxy_challenge( "$SER_DOMAIN" /* realm */, "0" /* no qop */ );
  414. break;
  415. };
  416. # let's check from=id ... avoids accounting confusion
  417. if (method=="INVITE" & !check_from()) {
  418. log("LOG: From Cheating attempt\n");
  419. sl_send_reply("403", "That is ugly -- use From=id next time (gw)");
  420. break;
  421. };
  422. if(!is_user_in("credentials", "int")) {
  423. sl_send_reply("403", "NO PSTN Privileges...");
  424. break;
  425. };
  426. consume_credentials();
  427. }; # INVITE to authorized PSTN
  428. # if you have passed through all the checks, let your call go to GW!
  429. rewritehostport("$SER_GWIP:5060");
  430. # snom conditioner
  431. if (method=="INVITE" && search("User-Agent: snom")) {
  432. replace("100rel, ", "");
  433. };
  434. append_hf("P-hint: GATEWAY\r\n");
  435. # use UDP to guarantee well-known sender port (TCP ephemeral)
  436. t_relay_to_udp("$SER_GWIP","5060");
  437. }
  438. /* *********** handling of unavailable user ******************* */
  439. route[4] {
  440. /**/
  441. # message store
  442. if (method=="MESSAGE") {
  443. t_newtran();
  444. if (m_store("0")) {
  445. t_reply("202", "Accepted for Later Delivery");
  446. } else {
  447. t_reply("503", "Service Unavailable");
  448. };
  449. break;
  450. };
  451. /**/
  452. # non-Voip -- just send "off-line"
  453. if (!(method=="INVITE" || method=="ACK" || method=="CANCEL")) {
  454. sl_send_reply("404", "Not Found");
  455. break;
  456. };
  457. # voicemail subscribers ...
  458. t_newtran();
  459. t_reply("404", "Not Found");
  460. # we account missed incoming calls; previous statteful processing
  461. # guarantees that retransmissions are not accounted
  462. if (method=="INVITE") {
  463. acc_db_request("404 missed call", "missed_calls");
  464. };
  465. }
  466. EOF
  467. help > /dev/stderr