#!KAMAILIO # # Edge proxy configuration with SIP over WebSocket support # #!substdef "!DBURL!sqlite:///etc/kamailio/db.sqlite!g" #!substdef "!MY_IP_ADDR!a.b.c.d!g" #!substdef "!MY_DOMAIN!example.com!g" #!substdef "!MY_WS_PORT!80!g" #!substdef "!MY_WSS_PORT!443!g" #!substdef "!MY_WS_ADDR!tcp:MY_IP_ADDR:MY_WS_PORT!g" #!substdef "!MY_WSS_ADDR!tls:MY_IP_ADDR:MY_WSS_PORT!g" #!substdef "!REGISTRAR_IP!e.f.g.h!g" #!substdef "!REGISTRAR_PORT!5060!g" #!substdef "!FLOW_TIMER!20!g" #!define WITH_TLS #!define WITH_WEBSOCKETS ####### Global Parameters ######### debug=2 log_stderror=no log_facility=LOG_LOCAL0 fork=yes children=4 mpath="/usr/lib64/kamailio/modules/" force_rport=yes #!ifdef WITH_TLS enable_tls=1 #!endif listen=MY_IP_ADDR #!ifdef WITH_WEBSOCKETS listen=MY_WS_ADDR #!ifdef WITH_TLS listen=MY_WSS_ADDR #!endif #!endif tcp_connection_lifetime=30 # FLOW_TIMER + 10 tcp_accept_no_cl=yes tcp_rd_buf_size=16384 ####### Modules Section ######## loadmodule "tm.so" loadmodule "sl.so" loadmodule "outbound.so" loadmodule "rr.so" loadmodule "path.so" loadmodule "pv.so" loadmodule "maxfwd.so" loadmodule "xlog.so" loadmodule "sanity.so" loadmodule "ctl.so" loadmodule "mi_rpc.so" loadmodule "mi_fifo.so" loadmodule "textops.so" loadmodule "siputils.so" loadmodule "stun.so" loadmodule "kex.so" loadmodule "corex.so" #!ifdef WITH_TLS loadmodule "tls.so" #!endif #!ifdef WITH_WEBSOCKETS loadmodule "xhttp.so" loadmodule "websocket.so" #!endif # ----------------- setting module-specific parameters --------------- # ----- mi_fifo params ----- modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo") # ----- tm params ----- modparam("tm", "failure_reply_mode", 3) # ----- rr params ----- modparam("rr", "append_fromtag", 0) # ----- corex params ----- modparam("corex", "alias_subdomains", "MY_DOMAIN") #!ifdef WITH_TLS # ----- tls params ----- modparam("tls", "tls_method", "SSLv23") modparam("tls", "certificate", "/etc/pki/CA/ser1_cert.pem") modparam("tls", "private_key", "/etc/pki/CA/privkey.pem") modparam("tls", "ca_list", "/etc/pki/CA/calist.pem") #!endif #!ifdef WITH_WEBSOCKETS # ----- websocket params ----- modparam("websocket", "keepalive_timeout", 25) # FLOW_TIMER + 5 #!endif ####### Routing Logic ######## request_route { if (($Rp == MY_WS_PORT || $Rp == MY_WSS_PORT) && !(proto == WS || proto == WSS)) { xlog("L_WARN", "SIP request received on $Rp\n"); sl_send_reply("403", "Forbidden"); exit; } route(REQINIT); if (is_method("CANCEL")) { if (t_check_trans()) { route(RELAY); } exit; } route(WITHINDLG); t_check_trans(); if (is_method("REGISTER")) { remove_hf("Route"); add_path(); $du = "sip:REGISTRAR_IP:REGISTRAR_PORT"; } else { if (is_method("INVITE|SUBSCRIBE")) record_route(); if (@via[2] == "") { # From client so route to registrar... if ($rU == $null) { sl_send_reply("484", "Address Incomplete"); exit; } remove_hf("Route"); $du = "sip:REGISTRAR_IP:REGISTRAR_PORT"; } else { # From registrar so route using "Route:" headers... if (!loose_route()) { switch($rc) { case -2: sl_send_reply("403", "Forbidden"); exit; default: xlog("L_ERR", "in request_route\n"); sl_reply_error(); exit; } } t_on_failure("FAIL_OUTBOUND"); } } route(RELAY); } route[RELAY] { if (!t_relay()) { sl_reply_error(); } exit; } route[REQINIT] { if (!mf_process_maxfwd_header("10")) { sl_send_reply("483","Too Many Hops"); exit; } if(!sanity_check("1511", "7")) { xlog("Malformed SIP message from $si:$sp\n"); exit; } } route[WITHINDLG] { if (has_totag()) { if (!loose_route()) { switch($rc) { case -2: sl_send_reply("403", "Forbidden"); exit; default: if (is_method("ACK")) { if ( t_check_trans() ) { route(RELAY); exit; } else { exit; } } sl_send_reply("404","Not Found"); } } else { if (is_method("NOTIFY")) { record_route(); } route(RELAY); } exit; } } onreply_route { if (($Rp == MY_WS_PORT || $Rp == MY_WSS_PORT) && !(proto == WS || proto == WSS)) { xlog("L_WARN", "SIP response received on $Rp\n"); drop; } if (!t_check_trans()) { drop; } if ($rm == "REGISTER" && $rs >= 200 && $rs <= 299) { remove_hf("Flow-Timer"); if ($(hdr(Require)[*])=~"outbound") insert_hf("Flow-Timer: FLOW_TIMER\r\n", "Call-ID"); } } failure_route[FAIL_OUTBOUND] { if (t_branch_timeout() || !t_branch_replied()) { send_reply("430", "Flow Failed"); } } event_route[xhttp:request] { set_reply_close(); set_reply_no_connect(); if ($Rp != MY_WS_PORT #!ifdef WITH_TLS && $Rp != MY_WSS_PORT #!endif ) { xlog("L_WARN", "HTTP request received on $Rp\n"); xhttp_reply("403", "Forbidden", "", ""); exit; } xlog("L_DBG", "HTTP Request Received\n"); if ($hdr(Upgrade)=~"websocket" && $hdr(Connection)=~"Upgrade" && $rm=~"GET") { # Validate Host - make sure the client is using the correct # alias for WebSockets if ($hdr(Host) == $null || !is_myself("sip:" + $hdr(Host))) { xlog("L_WARN", "Bad host $hdr(Host)\n"); xhttp_reply("403", "Forbidden", "", ""); exit; } # Optional... validate Origin - make sure the client is from an # authorised website. For example, # # if ($hdr(Origin) != "http://communicator.MY_DOMAIN" # && $hdr(Origin) != "https://communicator.MY_DOMAIN") { # xlog("L_WARN", "Unauthorised client $hdr(Origin)\n"); # xhttp_reply("403", "Forbidden", "", ""); # exit; # } # Optional... perform HTTP authentication # ws_handle_handshake() exits (no further configuration file # processing of the request) when complete. if (ws_handle_handshake()) { # Optional... cache some information about the # successful connection exit; } } xhttp_reply("404", "Not Found", "", ""); } event_route[websocket:closed] { xlog("L_INFO", "WebSocket connection from $si:$sp has closed\n"); }