examples/outbound/edge_websocket.cfg
96a1af2f
 #!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");
 }