[sr-dev] Websocket module

Peter Dunkley peter.dunkley at crocodile-rcs.com
Tue Aug 7 23:21:32 CEST 2012


Hi Inaki,

> 1) A callback (i.e. a script "route[X]" in kamailio.cfg) that is called
> when a new WebSocket connection is requested by a client, by providing
> access to the HTTP GET request (so the admin, based on local policy can
> inspect the HTTP request and allow/dissalow the connection after checking
> the Cookie header, the Origin header, the Host header or whatever).
>

All new WebSocket connections are handled by an
event_route[xhttp:request].  This allows any inspection of the headers you
want, and you can perform HTTP digest authentication using this
event_route.  Once you are happy that the connection should be allowed you
call the ws_handle_handshake() function to do some further checks,
generate the handshake response, and upgrade the connection in Kamailio
core.  So, for example:

event_route[xhttp:request] {
        set_reply_close();
        set_reply_no_connect();

        if ($Rp != 80 && $Rp != 443) {
                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") {
                xlog("L_DBG", "WebSocket\n");
                xlog("L_DBG", " Host: $hdr(Host)\n");
                xlog("L_DBG", " Origin: $hdr(Origin)\n");

                if ($hdr(Host) == $null || !is_myself($hdr(Host))) {
                        xlog("L_WARN", "Bad host $hdr(Host)\n");
                        xhttp_reply("403", "Forbidden", "", "");
                        exit;
                }

                # Optional... validate Origin
                # Optional... perform HTTP authentication

                # ws_handle_handshake() exits (no further configuration file
                # processing of the request) when complete.
                ws_handle_handshake();
        }

        xhttp_reply("404", "Not found", "", "");
}

> 2) A mechanism to associate custom attributes for each WebSocket
> connection
> (i.e. an authorized user identifier, which has been authorized by means of
> the previous HTTP GET request inspection in step 1).
>

You can do this by creating a hash table using the htable module
(http://kamailio.org/docs/modules/stable/modules_k/htable.html).  This
table can be filled in as part of the event_route[xhttp:request] above. 
If required ws_handle_handshake() could easily be updated to return
success/failure instead of exiting on completion to help with this (but
that change may not be needed).

The hash table should be indexed on the source address and port of the
connection.

> 3) A mechanism to retrieve, in the kamailio.cfg script, the attributes of
> the WebSocket connection from which a SIP request arrives to Kamailio
> (i.e.
> useful to enforce that the From URI matches the connection user identifier
> retrieved in any custom way in step 1).
>

This information can be put in the hash table and retrieved on demand. 
You can always get the source address and port (which the hash table would
be indexed on) of a request in the Kamailio configuration.

> 4) A mechanism to close an existing WebSocket connection from the
> kamailio.cfg script (i.e: during the WebSocket handshake we decided,
> somehow, that the user identifier is "alice", but at some point we receive
> an INVITE from that WS connection with From user "bob", so it could be an
> attacker and we want to close the connection).
>

I believe that calling the existing "set_reply_close()" function and then
sending a SIP reply to the INVITE will kill the connection.  Adding an API
to explicitly kill the WebSocket connection immediately wouldn't be hard -
but shouldn't be needed.

> 5) A callback that is called when a previously accepted WebSocket
> connection is closed (by passing as argument the terminator of the
> connection: the client or kamailio.cfg).
>

There is no support for this at the moment, but it would be relatively
easy to add an event_route[] to the WebSocket module (probably just a few
lines in ws_conn.c:wsconn_close_now() or ws_conn.c:wsconn_rm()).  If the
event_route[] makes sure appropriate pseudo-vars (containing information
like source address and port of the terminated connection and so on) are
provided then this can be used to clean-up the hash-table (otherwise
entries will just have to time-out).

>
> Said that, WWW people WON'T like the idea of providing a SIP username and
> SIP password in the JavaScript code retrieved by the user when visiting
> the
> web page, and for sure most of WWW people will prefer to
> validate/authenticate/authorize the WebSocket connections by inspecting
> the
> HTTP GET request (Origin, Cookie, some custom API_KEY in the request-URI
> of
> the GET method or whatever).
>

Yes I thought that.  That is one of the reasons I decided to use the xhttp
module to handle the WebSocket handshake instead of coding it all in the
module.

Regards,

Peter

-- 
Peter Dunkley
Technical Director
Crocodile RCS Ltd




More information about the sr-dev mailing list