xref: /aosp_15_r20/external/libwebsockets/READMEs/README.http-fallback.md (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
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![plain http flow](/doc-assets/accept-flow-1.svg)
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![tls https flow](/doc-assets/accept-flow-2.svg)
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![non-http flow](/doc-assets/accept-flow-3.svg)
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