websocket.cfg 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. #!KAMAILIO
  2. #
  3. # Simple/sample kamailio.cfg for running a proxy/registrar with TLS and
  4. # WebSockets support.
  5. #!substdef "!DBURL!sqlite:///etc/kamailio/db.sqlite!g"
  6. #!substdef "!MY_IP_ADDR!a.b.c.d!g"
  7. #!substdef "!MY_DOMAIN!example.com!g"
  8. #!substdef "!MY_WS_PORT!80!g"
  9. #!substdef "!MY_WSS_PORT!443!g"
  10. #!substdef "!MY_MSRP_PORT!9000!g"
  11. #!substdef "!MY_WS_ADDR!tcp:MY_IP_ADDR:MY_WS_PORT!g"
  12. #!substdef "!MY_WSS_ADDR!tls:MY_IP_ADDR:MY_WSS_PORT!g"
  13. #!substdef "!MY_MSRP_ADDR!tls:MY_IP_ADDR:MY_MSRP_PORT!g"
  14. #!substdef "!MSRP_MIN_EXPIRES!1800!g"
  15. #!substdef "!MSRP_MAX_EXPIRES!3600!g"
  16. ##!define LOCAL_TEST_RUN
  17. #!define WITH_TLS
  18. #!define WITH_WEBSOCKETS
  19. #!define WITH_MSRP
  20. ####### Global Parameters #########
  21. fork=yes
  22. children=4
  23. #!ifdef WITH_TLS
  24. enable_tls=1
  25. #!endif
  26. listen=MY_IP_ADDR
  27. #!ifdef WITH_WEBSOCKETS
  28. listen=MY_WS_ADDR
  29. #!ifdef WITH_TLS
  30. listen=MY_WSS_ADDR
  31. #!endif
  32. #!endif
  33. #!ifdef WITH_MSRP
  34. listen=MY_MSRP_ADDR
  35. #!endif
  36. tcp_connection_lifetime=3604
  37. tcp_accept_no_cl=yes
  38. tcp_rd_buf_size=16384
  39. syn_branch=0
  40. #!ifdef LOCAL_TEST_RUN
  41. debug=2
  42. mpath="modules_k:modules"
  43. #!else
  44. debug=0
  45. mpath="/usr/lib64/kamailio/modules_k/:/usr/lib64/kamailio/modules/"
  46. #!endif
  47. loadmodule "db_sqlite.so"
  48. loadmodule "tm.so"
  49. loadmodule "sl.so"
  50. loadmodule "rr.so"
  51. loadmodule "pv.so"
  52. loadmodule "maxfwd.so"
  53. loadmodule "usrloc.so"
  54. loadmodule "registrar.so"
  55. loadmodule "textops.so"
  56. loadmodule "siputils.so"
  57. loadmodule "xlog.so"
  58. loadmodule "sanity.so"
  59. loadmodule "ctl.so"
  60. loadmodule "auth.so"
  61. loadmodule "auth_db.so"
  62. loadmodule "kex.so"
  63. loadmodule "mi_rpc.so"
  64. loadmodule "corex.so"
  65. #!ifdef WITH_TLS
  66. loadmodule "tls.so"
  67. #!endif
  68. #!ifdef WITH_MSRP
  69. loadmodule "msrp.so"
  70. loadmodule "htable.so"
  71. loadmodule "cfgutils.so"
  72. #!endif
  73. #!ifdef WITH_WEBSOCKETS
  74. loadmodule "xhttp.so"
  75. loadmodule "websocket.so"
  76. loadmodule "nathelper.so"
  77. #!endif
  78. # ----------------- setting module-specific parameters ---------------
  79. # ----- tm params -----
  80. # auto-discard branches from previous serial forking leg
  81. modparam("tm", "failure_reply_mode", 3)
  82. # default retransmission timeout: 30sec
  83. modparam("tm", "fr_timer", 30000)
  84. # default invite retransmission timeout after 1xx: 120sec
  85. modparam("tm", "fr_inv_timer", 120000)
  86. # ----- rr params -----
  87. # add value to ;lr param to cope with most of the UAs
  88. modparam("rr", "enable_full_lr", 1)
  89. # do not append from tag to the RR (no need for this script)
  90. modparam("rr", "append_fromtag", 0)
  91. # ----- registrar params -----
  92. modparam("registrar", "method_filtering", 1)
  93. modparam("registrar", "max_expires", 3600)
  94. modparam("registrar", "gruu_enabled", 0)
  95. # ----- usrloc params -----
  96. modparam("usrloc", "db_url", "DBURL")
  97. modparam("usrloc", "db_mode", 0)
  98. # ----- auth params -----
  99. modparam("auth", "nonce_count", 1)
  100. modparam("auth", "qop", "auth")
  101. # ----- auth_db params -----
  102. modparam("auth_db", "db_url", "DBURL")
  103. modparam("auth_db", "calculate_ha1", yes)
  104. modparam("auth_db", "password_column", "password")
  105. modparam("auth_db", "load_credentials", "id")
  106. # ----- corex params -----
  107. modparam("corex", "alias_subdomains", "MY_DOMAIN")
  108. #!ifdef WITH_TLS
  109. # ----- tls params -----
  110. modparam("tls", "tls_method", "SSLv23")
  111. modparam("tls", "certificate", "/etc/pki/CA/ser1_cert.pem")
  112. modparam("tls", "private_key", "/etc/pki/CA/privkey.pem")
  113. modparam("tls", "ca_list", "/etc/pki/CA/calist.pem")
  114. #!endif
  115. #!ifdef WITH_WEBSOCKETS
  116. # ----- nathelper params -----
  117. modparam("nathelper|registrar", "received_avp", "$avp(RECEIVED)")
  118. # Note: leaving NAT pings turned off here as nathelper is _only_ being used for
  119. # WebSocket connections. NAT pings are not needed as WebSockets have
  120. # their own keep-alives.
  121. #!endif
  122. #!ifdef WITH_MSRP
  123. # ----- htable params -----
  124. modparam("htable", "htable", "msrp=>size=8;autoexpire=MSRP_MAX_EXPIRES;")
  125. #!endif
  126. ####### Routing Logic ########
  127. # Main SIP request routing logic
  128. # - processing of any incoming SIP request starts with this route
  129. # - note: this is the same as route { ... }
  130. request_route {
  131. if ((($Rp == MY_WS_PORT || $Rp == MY_WSS_PORT)
  132. && !(proto == WS || proto == WSS)) || $Rp == MY_MSRP_PORT) {
  133. xlog("L_WARN", "SIP request received on $Rp\n");
  134. sl_send_reply("403", "Forbidden");
  135. exit;
  136. }
  137. # per request initial checks
  138. route(REQINIT);
  139. #!ifdef WITH_WEBSOCKETS
  140. if (nat_uac_test(64)) {
  141. # Do NAT traversal stuff for requests from a WebSocket
  142. # connection - even if it is not behind a NAT!
  143. # This won't be needed in the future if Kamailio and the
  144. # WebSocket client support Outbound and Path.
  145. force_rport();
  146. if (is_method("REGISTER")) {
  147. fix_nated_register();
  148. } else {
  149. if (!add_contact_alias()) {
  150. xlog("L_ERR", "Error aliasing contact <$ct>\n");
  151. sl_send_reply("400", "Bad Request");
  152. exit;
  153. }
  154. }
  155. }
  156. #!endif
  157. # handle requests within SIP dialogs
  158. route(WITHINDLG);
  159. ### only initial requests (no To tag)
  160. # CANCEL processing
  161. if (is_method("CANCEL")) {
  162. if (t_check_trans()) {
  163. t_relay();
  164. }
  165. exit;
  166. }
  167. t_check_trans();
  168. # authentication
  169. route(AUTH);
  170. # record routing for dialog forming requests (in case they are routed)
  171. # - remove preloaded route headers
  172. remove_hf("Route");
  173. if (is_method("INVITE")) {
  174. record_route();
  175. }
  176. # handle registrations
  177. route(REGISTRAR);
  178. if ($rU==$null) {
  179. # request with no Username in RURI
  180. sl_send_reply("484", "Address Incomplete");
  181. exit;
  182. }
  183. # user location service
  184. route(LOCATION);
  185. route(RELAY);
  186. }
  187. route[RELAY] {
  188. if (!t_relay()) {
  189. sl_reply_error();
  190. }
  191. exit;
  192. }
  193. # Per SIP request initial checks
  194. route[REQINIT] {
  195. if (!mf_process_maxfwd_header("10")) {
  196. sl_send_reply("483", "Too Many Hops");
  197. exit;
  198. }
  199. if (!sanity_check("1511", "7")) {
  200. xlog("Malformed SIP message from $si:$sp\n");
  201. exit;
  202. }
  203. if (uri == myself && is_method("OPTIONS") && !(uri=~"sip:.*[@]+.*")) {
  204. options_reply();
  205. exit;
  206. }
  207. }
  208. # Handle requests within SIP dialogs
  209. route[WITHINDLG] {
  210. if (has_totag()) {
  211. # sequential request withing a dialog should
  212. # take the path determined by record-routing
  213. if (loose_route()) {
  214. #!ifdef WITH_WEBSOCKETS
  215. if ($du == "") {
  216. if (!handle_ruri_alias()) {
  217. xlog("L_ERR", "Bad alias <$ru>\n");
  218. sl_send_reply("400", "Bad Request");
  219. exit;
  220. }
  221. }
  222. #!endif
  223. route(RELAY);
  224. } else {
  225. if ( is_method("ACK") ) {
  226. if ( t_check_trans() ) {
  227. # no loose-route, but stateful ACK;
  228. # must be an ACK after a 487
  229. # or e.g. 404 from upstream server
  230. t_relay();
  231. exit;
  232. } else {
  233. # ACK without matching transaction...
  234. # ignore and discard
  235. exit;
  236. }
  237. }
  238. sl_send_reply("404", "Not Found");
  239. }
  240. exit;
  241. }
  242. }
  243. # Handle SIP registrations
  244. route[REGISTRAR] {
  245. if (is_method("REGISTER")) {
  246. if (!save("location")) {
  247. sl_reply_error();
  248. }
  249. exit;
  250. }
  251. }
  252. # USER location service
  253. route[LOCATION] {
  254. if (!is_subscriber("$ru", "subscriber", "1")) {
  255. t_newtran();
  256. send_reply("404", "Not Found");
  257. exit;
  258. }
  259. if (!lookup("location")) {
  260. $var(rc) = $rc;
  261. t_newtran();
  262. switch ($var(rc)) {
  263. case -1:
  264. send_reply("480", "Temporarily Unavailable");
  265. exit;
  266. case -2:
  267. send_reply("405", "Method Not Allowed");
  268. exit;
  269. case -3:
  270. send_reply("500", "Server Internal Error");
  271. exit;
  272. }
  273. }
  274. }
  275. # Authentication route
  276. route[AUTH] {
  277. if (is_method("REGISTER") || from_uri==myself) {
  278. # authenticate requests
  279. if (!auth_check("$fd", "subscriber", "1")) {
  280. auth_challenge("$fd", "0");
  281. exit;
  282. }
  283. # user authenticated - remove auth header
  284. if(!is_method("REGISTER")) {
  285. consume_credentials();
  286. }
  287. }
  288. # if caller is not local subscriber, then check if it calls
  289. # a local destination, otherwise deny, not an open relay here
  290. if (from_uri!=myself && uri!=myself) {
  291. sl_send_reply("403", "Forbidden");
  292. exit;
  293. }
  294. }
  295. #!ifdef WITH_WEBSOCKETS
  296. onreply_route {
  297. if ((($Rp == MY_WS_PORT || $Rp == MY_WSS_PORT)
  298. && !(proto == WS || proto == WSS)) || $Rp == MY_MSRP_PORT) {
  299. xlog("L_WARN", "SIP response received on $Rp\n");
  300. drop;
  301. exit;
  302. }
  303. if (nat_uac_test(64)) {
  304. # Do NAT traversal stuff for replies to a WebSocket connection
  305. # - even if it is not behind a NAT!
  306. # This won't be needed in the future if Kamailio and the
  307. # WebSocket client support Outbound and Path.
  308. add_contact_alias();
  309. }
  310. }
  311. event_route[xhttp:request] {
  312. set_reply_close();
  313. set_reply_no_connect();
  314. if ($Rp != MY_WS_PORT
  315. #!ifdef WITH_TLS
  316. && $Rp != MY_WSS_PORT
  317. #!endif
  318. ) {
  319. xlog("L_WARN", "HTTP request received on $Rp\n");
  320. xhttp_reply("403", "Forbidden", "", "");
  321. exit;
  322. }
  323. xlog("L_DBG", "HTTP Request Received\n");
  324. if ($hdr(Upgrade)=~"websocket"
  325. && $hdr(Connection)=~"Upgrade"
  326. && $rm=~"GET") {
  327. # Validate Host - make sure the client is using the correct
  328. # alias for WebSockets
  329. if ($hdr(Host) == $null || !is_myself("sip:" + $hdr(Host))) {
  330. xlog("L_WARN", "Bad host $hdr(Host)\n");
  331. xhttp_reply("403", "Forbidden", "", "");
  332. exit;
  333. }
  334. # Optional... validate Origin - make sure the client is from an
  335. # authorised website. For example,
  336. #
  337. # if ($hdr(Origin) != "http://communicator.MY_DOMAIN"
  338. # && $hdr(Origin) != "https://communicator.MY_DOMAIN") {
  339. # xlog("L_WARN", "Unauthorised client $hdr(Origin)\n");
  340. # xhttp_reply("403", "Forbidden", "", "");
  341. # exit;
  342. # }
  343. # Optional... perform HTTP authentication
  344. # ws_handle_handshake() exits (no further configuration file
  345. # processing of the request) when complete.
  346. if (ws_handle_handshake())
  347. {
  348. # Optional... cache some information about the
  349. # successful connection
  350. exit;
  351. }
  352. }
  353. xhttp_reply("404", "Not Found", "", "");
  354. }
  355. event_route[websocket:closed] {
  356. xlog("L_INFO", "WebSocket connection from $si:$sp has closed\n");
  357. }
  358. #!endif
  359. #!ifdef WITH_MSRP
  360. event_route[msrp:frame-in] {
  361. msrp_reply_flags("1");
  362. if ((($Rp == MY_WS_PORT || $Rp == MY_WSS_PORT)
  363. && !(proto == WS || proto == WSS)) && $Rp != MY_MSRP_PORT) {
  364. xlog("L_WARN", "MSRP request received on $Rp\n");
  365. msrp_reply("403", "Action-not-allowed");
  366. exit;
  367. }
  368. if (msrp_is_reply()) {
  369. msrp_relay();
  370. } else if($msrp(method)=="AUTH") {
  371. if($msrp(nexthops)>0) {
  372. msrp_relay();
  373. exit;
  374. }
  375. if (!www_authenticate("MY_DOMAIN", "subscriber",
  376. "$msrp(method)")) {
  377. if (auth_get_www_authenticate("MY_DOMAIN", "1",
  378. "$var(wauth)")) {
  379. msrp_reply("401", "Unauthorized",
  380. "$var(wauth)");
  381. } else {
  382. msrp_reply("500", "Server Error");
  383. }
  384. exit;
  385. }
  386. if ($hdr(Expires) != $null) {
  387. $var(expires) = (int) $hdr(Expires);
  388. if ($var(expires) < MSRP_MIN_EXPIRES) {
  389. msrp_reply("423", "Interval Out-of-Bounds",
  390. "Min-Expires: MSRP_MIN_EXPIRES\r\n");
  391. exit;
  392. } else if ($var(expires) > MSRP_MAX_EXPIRES) {
  393. msrp_reply("423", "Interval Out-of-Bounds",
  394. "Max-Expires: MSRP_MAX_EXPIRES\r\n");
  395. exit;
  396. }
  397. } else {
  398. $var(expires) = MSRP_MAX_EXPIRES;
  399. }
  400. $var(cnt) = $var(cnt) + 1;
  401. pv_printf("$var(sessid)", "s.$(pp).$(var(cnt)).$(RANDOM)");
  402. $sht(msrp=>$var(sessid)::srcaddr) = $msrp(srcaddr);
  403. $sht(msrp=>$var(sessid)::srcsock) = $msrp(srcsock);
  404. $shtex(msrp=>$var(sessid)) = $var(expires) + 5;
  405. # - Use-Path: the MSRP address for server + session id
  406. $var(hdrs) = "Use-Path: msrps://MY_IP_ADDR:MY_MSRP_PORT/"
  407. + $var(sessid) + ";tcp\r\n"
  408. + "Expires: " + $var(expires) + "\r\n";
  409. msrp_reply("200", "OK", "$var(hdrs)");
  410. } else if ($msrp(method)=="SEND" || $msrp(method)=="REPORT") {
  411. if ($msrp(nexthops)>1) {
  412. if ($msrp(method)!="REPORT") {
  413. msrp_reply("200", "OK");
  414. }
  415. msrp_relay();
  416. exit;
  417. }
  418. $var(sessid) = $msrp(sessid);
  419. if ($sht(msrp=>$var(sessid)::srcaddr) == $null) {
  420. # one more hop, but we don't have address in htable
  421. msrp_reply("481", "Session-does-not-exist");
  422. exit;
  423. } else if ($msrp(method)!="REPORT") {
  424. msrp_reply("200", "OK");
  425. }
  426. msrp_relay_flags("1");
  427. msrp_set_dst("$sht(msrp=>$var(sessid)::srcaddr)",
  428. "$sht(msrp=>$var(sessid)::srcsock)");
  429. msrp_relay();
  430. } else {
  431. msrp_reply("501", "Request-method-not-understood");
  432. }
  433. }
  434. #!endif