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