Project homepage Mailing List  API Docs  Github Mirror 
{"schema":"libjg2-1", "vpath":"/git/", "avatar":"/git/avatar/", "alang":"en-US,en;q\u003d0.5", "gen_ut":1635070915, "reponame":"libwebsockets", "desc":"libwebsockets lightweight C networking library", "owner": { "name": "Andy Green", "email": "", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"", "f":3, "items": [ {"schema":"libjg2-1", "cid":"7f70a23200ad5e839f57866534525e76", "oid":{ "oid": "7fa96facbb189706cabe121a81c0dd2cdcb02f2b", "alias": [ "refs/heads/main"]},"blobname": "READMEs/", "blob": "# Http fallback and raw proxying\n\nLws has several interesting options and features that can be applied to get\nsome special behaviours... this article discusses them and how they work.\n\n## Overview of normal vhost selection\n\nLws supports multiple http or https vhosts sharing a listening socket on the\nsame port.\n\nFor unencrypted http, the Host: header is used to select which vhost the\nconnection should bind to, by comparing what is given there against the\nnames the server was configured with for the various vhosts. If no match, it\nselects the first configured vhost.\n\nFor TLS, it has an extension called SNI (Server Name Indication) which tells\nthe server early in the TLS handshake the host name the connection is aimed at.\nThat allows lws to select the vhost early, and use vhost-specific TLS certs\nso everything is happy. Again, if there is no match the connection proceeds\nusing the first configured vhost and its certs.\n\n## Http(s) fallback options\n\nWhat happens if you try to connect, eg, an ssh client to the http server port\n(this is not an idle question...)? Obviously the http server part or the tls\npart of lws will fail the connection and close it. (We will look at that flow\nin a moment in detail for both unencrypted and tls listeners.)\n\nHowever if the first configured vhost for the port was created with the\nvhost creation info struct `.options` flag `LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG`,\nthen instead of the error, the connection transitions to whatever role was\ngiven in the vhost creation info struct `.listen_accept_role` and `.listen_accept_protocol`.\n\nWith lejp-conf / lwsws, the options can be applied to the first vhost using:\n\n```\n \u0022listen-accept-role\u0022: \u0022the-role-name\u0022,\n \u0022listen-accept-protocol\u0022: \u0022the-protocol-name\u0022,\n \u0022fallback-listen-accept\u0022: \u00221\u0022\n```\n\nSee `./minimal-examples/raw/minimal-raw-fallback-http-server` for examples of\nall the options in use via commandline flags.\n\nSo long as the first packet for the protocol doesn't look like GET, POST, or\na valid tls packet if connection to an https vhost, this allows the one listen\nsocket to handle both http(s) and a second protocol, as we will see, like ssh.\n\nNotice there is a restriction that no vhost selection processing is possible,\nneither for tls listeners nor plain http ones... the packet belonging to a\ndifferent protocol will not send any Host: header nor tls SNI.\n\nTherefore although the flags and settings are applied to the first configured\nvhost, actually their effect is global for a given listen port. If enabled,\nall vhosts on the same listen port will do the fallback action.\n\n### Plain http flow\n\n![plain http flow](/doc-assets/accept-flow-1.svg)\n\nNormally, if the first received packet does not contain a valid HTTP method,\nthen the connection is dropped. Which is what you want from an http server.\n\nHowever if enabled, the connection can transition to the defined secondary\nrole / protocol.\n\n|Flag|lejp-conf / lwsws|Function|\n|---|---|---|\n|`LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG`|`\u0022fallback-listen-accept\u0022: \u00221\u0022`|Enable fallback processing|\n\n### TLS https flow\n\n![tls https flow](/doc-assets/accept-flow-2.svg)\n\nIf the port is listening with tls, the point that a packet from a different\nprotocol will fail is earlier, when the tls tunnel is being set up.\n\n|Flag|lejp-conf / lwsws|Function|\n|---|---|---|\n|`LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG`|`\u0022fallback-listen-accept\u0022: \u00221\u0022`|Enable fallback processing|\n|`LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS`|`\u0022redirect-http\u0022: \u00221\u0022`|Treat invalid tls packet as http, issue http redirect to https://|\n|`LWS_SERVER_OPTION_ALLOW_HTTP_ON_HTTPS_LISTENER`|`\u0022allow-http-on-https\u0022: \u00221\u0022`|Accept unencrypted http connections on this tls port (dangerous)|\n\nThe latter two options are higher priority than, and defeat, the first one.\n\n### Non-http listener\n\n![non-http flow](/doc-assets/accept-flow-3.svg)\n\nIt's also possible to skip the fallback processing and just force the first\nvhost on the port to use the specified role and protocol in the first place.\n\n|Flag|lejp-conf / lwsws|Function|\n|---|---|---|\n|LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG|`\u0022apply-listen-accept\u0022: \u00221\u0022`|Force vhost to use listen-accept-role / listen-accept-protocol|\n\n## Using http(s) fallback with raw-proxy\n\nIf enabled for build with `cmake .. -DLWS_ROLE_RAW_PROXY\u003d1 -DLWS_WITH_PLUGINS\u003d1`\nthen lws includes ready-to-use support for raw tcp proxying.\n\nThis can be used standalone on the first vhost on a port, but most intriguingly\nit can be specified as the fallback for http(s)...\n\nSee `./minimal-examples/raw/minimal-raw-proxy-fallback.c` for a working example.\n\n### fallback with raw-proxy in code\n\nOn the first vhost for the port, specify the required \u0022onward\u0022 pvo to configure\nthe raw-proxy can adjust the \u0022ipv4:\u0022 to whatever you\nwant...\n\n```\n\tstatic struct lws_protocol_vhost_options pvo1 \u003d {\n\t NULL,\n\t NULL,\n\t \u0022onward\u0022,\t\t/* pvo name */\n\t \u0022ipv4:\u0022\t/* pvo value */\n\t};\n\n\tstatic const struct lws_protocol_vhost_options pvo \u003d {\n\t NULL, \t/* \u0022next\u0022 pvo linked-list */\n\t \u0026pvo1,\t\t\t/* \u0022child\u0022 pvo linked-list */\n\t \u0022raw-proxy\u0022,\t\t/* protocol name we belong to on this vhost */\n\t \u0022\u0022 \t/* ignored */\n\t};\n```\n\n... and set up the fallback enable and bindings...\n\n```\n\tinfo.options |\u003d LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG;\n\tinfo.listen_accept_role \u003d \u0022raw_proxy\u0022;\n\tinfo.listen_accept_proxy \u003d \u0022raw_proxy\u0022;\n\tinfo.pvo \u003d \u0026pvo;\n```\n\n### fallback with raw-proxy in JSON conf\n\nOn the first vhost for the port, enable the raw-proxy protocol on the vhost and\nset the pvo config\n\n```\n \u0022ws-protocols\u0022: [{\n \u0022raw-proxy\u0022: {\n \u0022status\u0022: \u0022ok\u0022,\n \u0022onward\u0022: \u0022ipv4:\u0022\n }\n }],\n```\n\nEnable the fallback behaviour on the vhost and the role / protocol binding\n\n```\n\t\u0022listen-accept-role\u0022: \u0022raw-proxy\u0022,\n\t\u0022listen-accept-protocol\u0022: \u0022raw-proxy\u0022,\n\t\u0022fallback-listen-accept\u0022: \u00221\u0022\n```\n\n### Testing\n\nWith this configured, the listen port will function normally for http or https\ndepending on how it was set up.\n\nBut if you try to connect to it with an ssh client, that will also work fine.\n\nThe server is set up in this way, you can confirm it by\nvisiting `` on port 443 as usual, but also trying\n`ssh -p 443`... you will get permission denied from\nyour ssh client. With valid credentials in fact that works perfectly for\nssh, scp, git-over-ssh etc all on port 443...\n\n","s":{"c":1634852130,"u": 470}} ],"g": 1005,"chitpc": 0,"ehitpc": 0,"indexed":0 , "ab": 0, "si": 0, "db":0, "di":0, "sat":0, "lfc": "7d0a"}