[Libwebsockets] Logging WS HS

Andy Green andy at warmcat.com
Mon Feb 24 03:30:42 CET 2020



On February 23, 2020 10:02:42 PM GMT, Olivier Langlois <olivier at olivierlanglois.net> wrote:
>On Sun, 2020-02-16 at 18:12 +0000, Andy Green wrote:
>> > You don't need that info when developing a server but when
>developing a
>> > client to use a service that you don't control, you are vulnerable
>to
>> > unannounced server changes. One day the HS works. Then it doesn't.
>With
>> > those logs, a simple glance at the logs would show what has changed
>and
>> > we aren't talking about multi-MB logs. It is 1-2 hundred extra
>bytes.
>> > IMHO, this is something that even lightweight systems could afford.
>> > 
>> > Another scenario that would be interesting to have some more help
>from
>> > lws is when the server returns a HTTP error code during the WS HS.
>ie:
>> > I get a 503. I suspect that along with it, in the reply body, the
>> > server provides some useful info such as: 'Service disabled for
>> > maintenance. Service resuming expected at HH:MM'. Recuperating
>those
>> > messages is something that I would like lws to help with.
>> 
>> Feel free to propose a patch, but at that point, it's http body,
>unrelated to ws protocol, so this is probably a job about generic
>handling of http bodies for 4xx / 5xx... not sure if it already appears
>at the cb or the transaction is abandoned.
>
>Andy,
>
>I think that I have found a way to do it without any modification on
>the lws side (well almost).
>
>I need to test this option to validate that it works but I'm not seeing
>why it wouldn't. FYI, my server is using chunked encoding.
>
>In my callback:
>
>     case LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: {
>          int code = lws_hdr_http_response(wsi);
>          if (code == 503) {
>              char buf[4096];
>              char *ptr = buf;
>              int len = sizeof(buf);
>              lws_http_client_read(wsi, &ptr, &len);
>          }
>        }
>        break;
>      case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
>          INFO2("HTTP 503 reply body:\n%.*s", len, (const char *)in);
>        break;
>
>Ok, yes I wrote a small utility function. Feel free to add it to lws:
>
>LWS_VISIBLE int
>lws_hdr_http_response(struct lws *wsi)
>{
>        if (!wsi->http.ah)
>                return 0;
>        return wsi->http.ah->http_response;
>}
>
>because otherwise, what is the alternative?

We're talking about this, which has been around a few years?

https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-client.h#n232-244

>1. lws_hdr_copy(wsi, buf, 4, WSI_TOKEN_HTTP_COLON_STATUS);

COLON_STATUS refers to the h2 header :status, it's only present when h2 was negotiated.  Lws apis take care to conceal from the user code almost completely whether it's actually doing h1 or h2 / hpack underneath... even if you thought your user code was talking to an h2 server that's something only discovered after the connection.

>2. int code = atoi(buf);
>
>All that for a value that is stored in the ah struct... that seems a
>bit overkill...
>
>If interested, I can prepare you a well formatted patch for that new
>function.
>
>In the same order of ideas, why lws_hdr_simple_ptr() isn't exposed?

A fun quirk of http is the headers may be arbitrarily fragmented, repeated headers append to the previous.  In some places lws code is okay with dropping the connection if key headers aren't in one fragment and can use ..._simple_ptr() to consider only the first fragment... it shouldn't buy an attacker much if he fragmanted content-type: application/json into appli   cation/   json, it should just break on unknown content type.  User code should always consider the whole logical header to be immune from fragmentation attacks, the copy version of the api appends the fragments as it makes the copy.

>inside lws, it is a breeze to inspect the various header fields, if
>someone wanted to inspect the header in any way from
>LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, he would have to resort to a
>bunch of field copies...

If you want to 'inspect' the headers programmatically, you must write the corresponding code.

If you wanted to see what was sent by the peer in detail, enable verbose logging with -DCMAKE_BUILD_TYPE=DEBUG and use a logging bitfield like 1151 to see the whole parsing action, or 65535 for really everything.

If you want to dump the headers, it's not so hard

https://libwebsockets.org/git/libwebsockets/tree/test-apps/test-server.c#n103

... it's enough already.

-Andy

>Greetings,


More information about the Libwebsockets mailing list