[sr-dev] Websocket module

Iñaki Baz Castillo ibc at aliax.net
Wed Aug 8 00:57:14 CEST 2012


2012/8/7 Peter Dunkley <peter.dunkley at crocodile-rcs.com>:
> 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.

Note that, even if RFC 6455 gives the door open to HTTP basic/digest
authentication, currently no one browser with WebSocket support reacts
on a 401/407 for the WS GET.

I strongly know that WWW people does not like authentication
mechanisms other than those based on HTML forms ;)




> 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") {

But the Sec-WebSocket-Accept header is generated (and added to the 101
response) by the WS module itself, am I right?


>                 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.

Ok.


>> 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.

Sure, ok.



>> 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).

Makes sense :)



>> 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.

It seems a good decision :)


Thanks a lot for your explanations, and congratulations for your work.


-- 
Iñaki Baz Castillo
<ibc at aliax.net>



More information about the sr-dev mailing list