1*1c60b9acSAndroid Build Coastguard Worker# Http fallback and raw proxying 2*1c60b9acSAndroid Build Coastguard Worker 3*1c60b9acSAndroid Build Coastguard WorkerLws has several interesting options and features that can be applied to get 4*1c60b9acSAndroid Build Coastguard Workersome special behaviours... this article discusses them and how they work. 5*1c60b9acSAndroid Build Coastguard Worker 6*1c60b9acSAndroid Build Coastguard Worker## Overview of normal vhost selection 7*1c60b9acSAndroid Build Coastguard Worker 8*1c60b9acSAndroid Build Coastguard WorkerLws supports multiple http or https vhosts sharing a listening socket on the 9*1c60b9acSAndroid Build Coastguard Workersame port. 10*1c60b9acSAndroid Build Coastguard Worker 11*1c60b9acSAndroid Build Coastguard WorkerFor unencrypted http, the Host: header is used to select which vhost the 12*1c60b9acSAndroid Build Coastguard Workerconnection should bind to, by comparing what is given there against the 13*1c60b9acSAndroid Build Coastguard Workernames the server was configured with for the various vhosts. If no match, it 14*1c60b9acSAndroid Build Coastguard Workerselects the first configured vhost. 15*1c60b9acSAndroid Build Coastguard Worker 16*1c60b9acSAndroid Build Coastguard WorkerFor TLS, it has an extension called SNI (Server Name Indication) which tells 17*1c60b9acSAndroid Build Coastguard Workerthe server early in the TLS handshake the host name the connection is aimed at. 18*1c60b9acSAndroid Build Coastguard WorkerThat allows lws to select the vhost early, and use vhost-specific TLS certs 19*1c60b9acSAndroid Build Coastguard Workerso everything is happy. Again, if there is no match the connection proceeds 20*1c60b9acSAndroid Build Coastguard Workerusing the first configured vhost and its certs. 21*1c60b9acSAndroid Build Coastguard Worker 22*1c60b9acSAndroid Build Coastguard Worker## Http(s) fallback options 23*1c60b9acSAndroid Build Coastguard Worker 24*1c60b9acSAndroid Build Coastguard WorkerWhat happens if you try to connect, eg, an ssh client to the http server port 25*1c60b9acSAndroid Build Coastguard Worker(this is not an idle question...)? Obviously the http server part or the tls 26*1c60b9acSAndroid Build Coastguard Workerpart of lws will fail the connection and close it. (We will look at that flow 27*1c60b9acSAndroid Build Coastguard Workerin a moment in detail for both unencrypted and tls listeners.) 28*1c60b9acSAndroid Build Coastguard Worker 29*1c60b9acSAndroid Build Coastguard WorkerHowever if the first configured vhost for the port was created with the 30*1c60b9acSAndroid Build Coastguard Workervhost creation info struct `.options` flag `LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG`, 31*1c60b9acSAndroid Build Coastguard Workerthen instead of the error, the connection transitions to whatever role was 32*1c60b9acSAndroid Build Coastguard Workergiven in the vhost creation info struct `.listen_accept_role` and `.listen_accept_protocol`. 33*1c60b9acSAndroid Build Coastguard Worker 34*1c60b9acSAndroid Build Coastguard WorkerWith lejp-conf / lwsws, the options can be applied to the first vhost using: 35*1c60b9acSAndroid Build Coastguard Worker 36*1c60b9acSAndroid Build Coastguard Worker``` 37*1c60b9acSAndroid Build Coastguard Worker "listen-accept-role": "the-role-name", 38*1c60b9acSAndroid Build Coastguard Worker "listen-accept-protocol": "the-protocol-name", 39*1c60b9acSAndroid Build Coastguard Worker "fallback-listen-accept": "1" 40*1c60b9acSAndroid Build Coastguard Worker``` 41*1c60b9acSAndroid Build Coastguard Worker 42*1c60b9acSAndroid Build Coastguard WorkerSee `./minimal-examples/raw/minimal-raw-fallback-http-server` for examples of 43*1c60b9acSAndroid Build Coastguard Workerall the options in use via commandline flags. 44*1c60b9acSAndroid Build Coastguard Worker 45*1c60b9acSAndroid Build Coastguard WorkerSo long as the first packet for the protocol doesn't look like GET, POST, or 46*1c60b9acSAndroid Build Coastguard Workera valid tls packet if connection to an https vhost, this allows the one listen 47*1c60b9acSAndroid Build Coastguard Workersocket to handle both http(s) and a second protocol, as we will see, like ssh. 48*1c60b9acSAndroid Build Coastguard Worker 49*1c60b9acSAndroid Build Coastguard WorkerNotice there is a restriction that no vhost selection processing is possible, 50*1c60b9acSAndroid Build Coastguard Workerneither for tls listeners nor plain http ones... the packet belonging to a 51*1c60b9acSAndroid Build Coastguard Workerdifferent protocol will not send any Host: header nor tls SNI. 52*1c60b9acSAndroid Build Coastguard Worker 53*1c60b9acSAndroid Build Coastguard WorkerTherefore although the flags and settings are applied to the first configured 54*1c60b9acSAndroid Build Coastguard Workervhost, actually their effect is global for a given listen port. If enabled, 55*1c60b9acSAndroid Build Coastguard Workerall vhosts on the same listen port will do the fallback action. 56*1c60b9acSAndroid Build Coastguard Worker 57*1c60b9acSAndroid Build Coastguard Worker### Plain http flow 58*1c60b9acSAndroid Build Coastguard Worker 59*1c60b9acSAndroid Build Coastguard Worker 60*1c60b9acSAndroid Build Coastguard Worker 61*1c60b9acSAndroid Build Coastguard WorkerNormally, if the first received packet does not contain a valid HTTP method, 62*1c60b9acSAndroid Build Coastguard Workerthen the connection is dropped. Which is what you want from an http server. 63*1c60b9acSAndroid Build Coastguard Worker 64*1c60b9acSAndroid Build Coastguard WorkerHowever if enabled, the connection can transition to the defined secondary 65*1c60b9acSAndroid Build Coastguard Workerrole / protocol. 66*1c60b9acSAndroid Build Coastguard Worker 67*1c60b9acSAndroid Build Coastguard Worker|Flag|lejp-conf / lwsws|Function| 68*1c60b9acSAndroid Build Coastguard Worker|---|---|---| 69*1c60b9acSAndroid Build Coastguard Worker|`LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG`|`"fallback-listen-accept": "1"`|Enable fallback processing| 70*1c60b9acSAndroid Build Coastguard Worker 71*1c60b9acSAndroid Build Coastguard Worker### TLS https flow 72*1c60b9acSAndroid Build Coastguard Worker 73*1c60b9acSAndroid Build Coastguard Worker 74*1c60b9acSAndroid Build Coastguard Worker 75*1c60b9acSAndroid Build Coastguard WorkerIf the port is listening with tls, the point that a packet from a different 76*1c60b9acSAndroid Build Coastguard Workerprotocol will fail is earlier, when the tls tunnel is being set up. 77*1c60b9acSAndroid Build Coastguard Worker 78*1c60b9acSAndroid Build Coastguard Worker|Flag|lejp-conf / lwsws|Function| 79*1c60b9acSAndroid Build Coastguard Worker|---|---|---| 80*1c60b9acSAndroid Build Coastguard Worker|`LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG`|`"fallback-listen-accept": "1"`|Enable fallback processing| 81*1c60b9acSAndroid Build Coastguard Worker|`LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS`|`"redirect-http": "1"`|Treat invalid tls packet as http, issue http redirect to https://| 82*1c60b9acSAndroid Build Coastguard Worker|`LWS_SERVER_OPTION_ALLOW_HTTP_ON_HTTPS_LISTENER`|`"allow-http-on-https": "1"`|Accept unencrypted http connections on this tls port (dangerous)| 83*1c60b9acSAndroid Build Coastguard Worker 84*1c60b9acSAndroid Build Coastguard WorkerThe latter two options are higher priority than, and defeat, the first one. 85*1c60b9acSAndroid Build Coastguard Worker 86*1c60b9acSAndroid Build Coastguard Worker### Non-http listener 87*1c60b9acSAndroid Build Coastguard Worker 88*1c60b9acSAndroid Build Coastguard Worker 89*1c60b9acSAndroid Build Coastguard Worker 90*1c60b9acSAndroid Build Coastguard WorkerIt's also possible to skip the fallback processing and just force the first 91*1c60b9acSAndroid Build Coastguard Workervhost on the port to use the specified role and protocol in the first place. 92*1c60b9acSAndroid Build Coastguard Worker 93*1c60b9acSAndroid Build Coastguard Worker|Flag|lejp-conf / lwsws|Function| 94*1c60b9acSAndroid Build Coastguard Worker|---|---|---| 95*1c60b9acSAndroid Build Coastguard Worker|LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG|`"apply-listen-accept": "1"`|Force vhost to use listen-accept-role / listen-accept-protocol| 96*1c60b9acSAndroid Build Coastguard Worker 97*1c60b9acSAndroid Build Coastguard Worker## Using http(s) fallback with raw-proxy 98*1c60b9acSAndroid Build Coastguard Worker 99*1c60b9acSAndroid Build Coastguard WorkerIf enabled for build with `cmake .. -DLWS_ROLE_RAW_PROXY=1 -DLWS_WITH_PLUGINS=1` 100*1c60b9acSAndroid Build Coastguard Workerthen lws includes ready-to-use support for raw tcp proxying. 101*1c60b9acSAndroid Build Coastguard Worker 102*1c60b9acSAndroid Build Coastguard WorkerThis can be used standalone on the first vhost on a port, but most intriguingly 103*1c60b9acSAndroid Build Coastguard Workerit can be specified as the fallback for http(s)... 104*1c60b9acSAndroid Build Coastguard Worker 105*1c60b9acSAndroid Build Coastguard WorkerSee `./minimal-examples/raw/minimal-raw-proxy-fallback.c` for a working example. 106*1c60b9acSAndroid Build Coastguard Worker 107*1c60b9acSAndroid Build Coastguard Worker### fallback with raw-proxy in code 108*1c60b9acSAndroid Build Coastguard Worker 109*1c60b9acSAndroid Build Coastguard WorkerOn the first vhost for the port, specify the required "onward" pvo to configure 110*1c60b9acSAndroid Build Coastguard Workerthe raw-proxy protocol...you can adjust the "ipv4:127.0.0.1:22" to whatever you 111*1c60b9acSAndroid Build Coastguard Workerwant... 112*1c60b9acSAndroid Build Coastguard Worker 113*1c60b9acSAndroid Build Coastguard Worker``` 114*1c60b9acSAndroid Build Coastguard Worker static struct lws_protocol_vhost_options pvo1 = { 115*1c60b9acSAndroid Build Coastguard Worker NULL, 116*1c60b9acSAndroid Build Coastguard Worker NULL, 117*1c60b9acSAndroid Build Coastguard Worker "onward", /* pvo name */ 118*1c60b9acSAndroid Build Coastguard Worker "ipv4:127.0.0.1:22" /* pvo value */ 119*1c60b9acSAndroid Build Coastguard Worker }; 120*1c60b9acSAndroid Build Coastguard Worker 121*1c60b9acSAndroid Build Coastguard Worker static const struct lws_protocol_vhost_options pvo = { 122*1c60b9acSAndroid Build Coastguard Worker NULL, /* "next" pvo linked-list */ 123*1c60b9acSAndroid Build Coastguard Worker &pvo1, /* "child" pvo linked-list */ 124*1c60b9acSAndroid Build Coastguard Worker "raw-proxy", /* protocol name we belong to on this vhost */ 125*1c60b9acSAndroid Build Coastguard Worker "" /* ignored */ 126*1c60b9acSAndroid Build Coastguard Worker }; 127*1c60b9acSAndroid Build Coastguard Worker``` 128*1c60b9acSAndroid Build Coastguard Worker 129*1c60b9acSAndroid Build Coastguard Worker... and set up the fallback enable and bindings... 130*1c60b9acSAndroid Build Coastguard Worker 131*1c60b9acSAndroid Build Coastguard Worker``` 132*1c60b9acSAndroid Build Coastguard Worker info.options |= LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG; 133*1c60b9acSAndroid Build Coastguard Worker info.listen_accept_role = "raw_proxy"; 134*1c60b9acSAndroid Build Coastguard Worker info.listen_accept_proxy = "raw_proxy"; 135*1c60b9acSAndroid Build Coastguard Worker info.pvo = &pvo; 136*1c60b9acSAndroid Build Coastguard Worker``` 137*1c60b9acSAndroid Build Coastguard Worker 138*1c60b9acSAndroid Build Coastguard Worker### fallback with raw-proxy in JSON conf 139*1c60b9acSAndroid Build Coastguard Worker 140*1c60b9acSAndroid Build Coastguard WorkerOn the first vhost for the port, enable the raw-proxy protocol on the vhost and 141*1c60b9acSAndroid Build Coastguard Workerset the pvo config 142*1c60b9acSAndroid Build Coastguard Worker 143*1c60b9acSAndroid Build Coastguard Worker``` 144*1c60b9acSAndroid Build Coastguard Worker "ws-protocols": [{ 145*1c60b9acSAndroid Build Coastguard Worker "raw-proxy": { 146*1c60b9acSAndroid Build Coastguard Worker "status": "ok", 147*1c60b9acSAndroid Build Coastguard Worker "onward": "ipv4:127.0.0.1:22" 148*1c60b9acSAndroid Build Coastguard Worker } 149*1c60b9acSAndroid Build Coastguard Worker }], 150*1c60b9acSAndroid Build Coastguard Worker``` 151*1c60b9acSAndroid Build Coastguard Worker 152*1c60b9acSAndroid Build Coastguard WorkerEnable the fallback behaviour on the vhost and the role / protocol binding 153*1c60b9acSAndroid Build Coastguard Worker 154*1c60b9acSAndroid Build Coastguard Worker``` 155*1c60b9acSAndroid Build Coastguard Worker "listen-accept-role": "raw-proxy", 156*1c60b9acSAndroid Build Coastguard Worker "listen-accept-protocol": "raw-proxy", 157*1c60b9acSAndroid Build Coastguard Worker "fallback-listen-accept": "1" 158*1c60b9acSAndroid Build Coastguard Worker``` 159*1c60b9acSAndroid Build Coastguard Worker 160*1c60b9acSAndroid Build Coastguard Worker### Testing 161*1c60b9acSAndroid Build Coastguard Worker 162*1c60b9acSAndroid Build Coastguard WorkerWith this configured, the listen port will function normally for http or https 163*1c60b9acSAndroid Build Coastguard Workerdepending on how it was set up. 164*1c60b9acSAndroid Build Coastguard Worker 165*1c60b9acSAndroid Build Coastguard WorkerBut if you try to connect to it with an ssh client, that will also work fine. 166*1c60b9acSAndroid Build Coastguard Worker 167*1c60b9acSAndroid Build Coastguard WorkerThe libwebsockets.org server is set up in this way, you can confirm it by 168*1c60b9acSAndroid Build Coastguard Workervisiting `https://libwebsockets.org` on port 443 as usual, but also trying 169*1c60b9acSAndroid Build Coastguard Worker`ssh -p 443 [email protected]`... you will get permission denied from 170*1c60b9acSAndroid Build Coastguard Workeryour ssh client. With valid credentials in fact that works perfectly for 171*1c60b9acSAndroid Build Coastguard Workerssh, scp, git-over-ssh etc all on port 443... 172*1c60b9acSAndroid Build Coastguard Worker 173