You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

194 lines
7.1 KiB

tcp_accept_no_cl=yes
#!ifndef WITHOUT_DEFAULT_LISTENER
#!ifdef WS_LISTEN_PLAIN
listen=TCP_LISTENER_WS
#!endif
#!ifdef TLS_ROLE
listen=TLS_LISTENER_WSS
#!endif
#!endif
#!ifdef WITH_EXTERNAL_WEBSOCKETS_LISTENER
#!ifdef WS_LISTEN_PLAIN
listen=TCP_EXTERNAL_LISTENER_WS
#!endif
#!ifdef TLS_ROLE
listen=TLS_EXTERNAL_LISTENER_WSS
#!endif
#!else
#!ifdef WITH_EXTERNAL_WS_LISTENER
#!ifdef WS_LISTEN_PLAIN
listen=TCP_EXTERNAL_LISTENER_WS
#!endif
#!endif
#!ifdef WITH_EXTERNAL_WSS_LISTENER
#!ifdef TLS_ROLE
listen=TLS_EXTERNAL_LISTENER_WSS
#!endif
#!endif
#!endif
#!ifdef WITH_LOAD_BALANCED_WEBSOCKETS_LISTENER
#!ifdef WS_LISTEN_PLAIN
listen=TCP_LOAD_BALANCED_LISTENER_WS
#!endif
#!ifdef TLS_ROLE
listen=TLS_LOAD_BALANCED_LISTENER_WSS
#!endif
#!else
#!ifdef WITH_LOAD_BALANCED_WS_LISTENER
#!ifdef WS_LISTEN_PLAIN
listen=TCP_LOAD_BALANCED_LISTENER_WS
#!endif
#!endif
#!ifdef WITH_LOAD_BALANCED_WSS_LISTENER
#!ifdef TLS_ROLE
listen=TLS_LOAD_BALANCED_LISTENER_WSS
#!endif
#!endif
#!endif
######## NAT Traversal module - signaling functions ########
#!ifndef NATHELPER_LOADED
#!trydef NATHELPER_LOADED
loadmodule "nathelper.so"
#!endif
######## Generic Hash Table container in shared memory ########
modparam("htable", "htable", "websockets=>size=16;initval=0")
#!trydef WS_KEEPALIVE_MECHANISM 3
#!trydef WS_KEEPALIVE_TIMEOUT 30
#!trydef WS_KEEPALIVE_PROCESSES 3
#!trydef WS_KEEPALIVE_INTERVAL 1
#!trydef WS_KEEPALIVE_DATA "Kazoo encourages you to keep alive"
#!trydef WS_MAX_CONNECTIONS_PER_IP 50
#!trydef WS_MAX_CONNECTIONS_PER_PROXY 0
#!trydef WS_ALLOWED_PROXIES "0.0.0.0/0"
#!trydef WS_CONNECTIONS_FROM_PROXY_ONLY 0
#!trydef WS_CONNECTIONS_RESTRICT_ORIGIN 1
######## Websocket module ########
loadmodule "websocket.so"
modparam("websocket", "keepalive_mechanism", WS_KEEPALIVE_MECHANISM)
modparam("websocket", "keepalive_timeout", WS_KEEPALIVE_TIMEOUT)
modparam("websocket", "keepalive_processes", WS_KEEPALIVE_PROCESSES)
modparam("websocket", "keepalive_interval", WS_KEEPALIVE_INTERVAL)
modparam("websocket", "ping_application_data", WS_KEEPALIVE_DATA)
modparam("websocket", "sub_protocols", 1)
####### Websocket Logic ########
kazoo.ws_allowed_proxies = WS_ALLOWED_PROXIES desc "comma separated list of allowed proxies in cidr notation"
kazoo.ws_max_connection_per_ip = WS_MAX_CONNECTIONS_PER_IP desc "max connections per ip"
kazoo.ws_max_connection_per_proxy = WS_MAX_CONNECTIONS_PER_PROXY desc "max connections per proxy"
kazoo.ws_connections_via_proxy_only = WS_CONNECTIONS_FROM_PROXY_ONLY desc "only allow connections via proxy"
kazoo.ws_connections_restrict_origin = WS_CONNECTIONS_RESTRICT_ORIGIN desc "restrict origin if MY_WEBSOCKET_DOMAIN is defined"
route[WEBSOCKET_REQUEST]
{
if (!($rm =~ "GET")) {
xlog("L_INFO", "http|websocket|rejecting HTTP request $rm from $si:$sp\n");
xhttp_reply("405", "Method Not Allowed", "", "");
exit;
}
if (!($hdr(Connection) =~ "Upgrade")) {
xlog("L_INFO", "http|websocket|rejecting HTTP connection $hdr(Connection) request from $si:$sp\n");
xhttp_reply("400", "Bad Request", "", "");
exit;
}
if (!($hdr(Upgrade) =~ "websocket")) {
xlog("L_INFO", "http|websocket|rejecting HTTP upgrade $hdr(Upgrade) request from $si:$sp\n");
xhttp_reply("400", "Bad Request", "", "");
exit;
}
if (!($hdr(Sec-WebSocket-Protocol) =~ "sip")) {
xlog("L_INFO", "http|websocket|rejecting request for websocket protocol $hdr(Sec-WebSocket-Protocol) from $si:$sp\n");
xhttp_reply("400", "Bad Request", "", "");
exit;
}
#!ifndef WEBSOCKET_NO_ORIGIN_RESTRICTION
if($sel(cfg_get.kazoo.ws_connections_restrict_origin) == 1) {
if (!($hdr(Origin) =~ "MY_WEBSOCKET_DOMAIN")) {
xlog("L_INFO", "http|websocket|rejecting HTTP request with unauthorized origin $hdr(Origin) from $si:$sp, allowed origin is MY_WEBSOCKET_DOMAIN\n");
xhttp_reply("400", "Bad Request", "", "");
exit;
}
}
#!endif
if ($hdr(X-Forwarded-For) == $null) {
if($sel(cfg_get.kazoo.ws_connections_via_proxy_only) == 1) {
xlog("L_INFO", "http|websocket|request from $si without X-Forwarded-For Header and only allowed connections are via proxy\n");
xhttp_reply("403", "Forbidden", "", "");
exit;
} else {
$var(ws_orig_ip) = $si;
}
} else {
xlog("L_INFO", "http|websocket|request X-Forwarded-For $hdr(X-Forwarded-For) from $si\n");
$var(ws_orig_ip) = $hdr(X-Forwarded-For);
}
if($si != $var(ws_orig_ip)) {
if(!is_in_subnet($si, $sel(cfg_get.kazoo.ws_allowed_proxies))) {
xlog("L_WARNING", "http|websocket|request X-Forwarded-For $hdr(X-Forwarded-For) from invalid ip $si - allowed $sel(cfg_get.kazoo.ws_allowed_proxies)\n");
xhttp_reply("403", "Forbidden", "", "");
exit;
}
if($sel(cfg_get.kazoo.ws_max_connection_per_proxy) > 0 && $sht(websockets=>$si::count) > $sel(cfg_get.kazoo.ws_max_connection_per_proxy)) {
xlog("L_WARN", "http|websocket|$si is at the maximum $sel(cfg_get.kazoo.ws_max_connection_per_proxy) allowable sockets per PROXY IP, rejecting request for another websocket\n");
xhttp_reply("403", "Forbidden", "", "");
exit;
}
}
if($sel(cfg_get.kazoo.ws_max_connection_per_ip) > 0 && $sht(websockets=>$var(ws_orig_ip)::count) > $sel(cfg_get.kazoo.ws_max_connection_per_ip)) {
xlog("L_WARN", "http|websocket|$var(ws_orig_ip) is at the maximum $sel(cfg_get.kazoo.ws_max_connection_per_ip) allowable sockets per IP, rejecting request for another websocket\n");
xhttp_reply("403", "Forbidden", "", "");
exit;
}
route_if_exists("WS_ON_BEFORE_HANSHAKE");
if (ws_handle_handshake()) {
$var(count) = $shtinc(websockets=>$var(ws_orig_ip)::count);
$sht(websockets=>$ws_conid::ws_orig_ip) = $var(ws_orig_ip);
if($si != $var(ws_orig_ip)) {
$var(proxy_count) = $shtinc(websockets=>$si::count);
xlog("L_INFO", "http|websocket|opened proxied websocket $ws_conid from $si for $var(ws_orig_ip):$sp\n");
} else {
xlog("L_INFO", "http|websocket|opened websocket $ws_conid from $var(ws_orig_ip):$sp\n");
}
route_if_exists("WS_ON_SUCCESSFULL_HANSHAKE");
exit;
}
xlog("L_INFO", "http|websocket|unhandled HTTP request $rm from $si:$sp\n");
xhttp_reply("404", "Not Found", "", "");
}
event_route[websocket:closed]
{
$var(ws_orig_ip) = $sht(websockets=>$ws_conid::ws_orig_ip);
$sht(websockets=>$ws_conid::ws_orig_ip) = $null;
$var(count) = $shtdec(websockets=>$si::count);
if($var(ws_orig_ip) != $null && $si != $var(ws_orig_ip)) {
$var(countip) = $shtdec(websockets=>$var(ws_orig_ip)::count);
xlog("L_INFO", "http|websocket|$si closed proxied websocket $ws_conid for $var(ws_orig_ip):$sp\n");
if ($var(countip) < 1) $sht(websockets=>$var(ws_orig_ip)::count) = $null;
} else {
xlog("L_INFO", "http|websocket|closed websocket $ws_conid from $var(ws_orig_ip):$sp\n");
}
if ($var(count) < 1) $sht(websockets=>$si::count) = $null;
route_if_exists("WS_ON_CLOSE");
}