• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  *
24  * This provides a clean way to interface lws user code to be able to
25  * work unchanged on different systems for fetching common system information,
26  * and performing common system operations like reboot.
27  */
28 
29 /*
30  * Types of system blob that can be set and retreived
31  */
32 
33 typedef enum {
34 	LWS_SYSBLOB_TYPE_AUTH,
35 	LWS_SYSBLOB_TYPE_CLIENT_CERT_DER = LWS_SYSBLOB_TYPE_AUTH + 2,
36 	LWS_SYSBLOB_TYPE_CLIENT_KEY_DER,
37 	LWS_SYSBLOB_TYPE_DEVICE_SERIAL,
38 	LWS_SYSBLOB_TYPE_DEVICE_FW_VERSION,
39 	LWS_SYSBLOB_TYPE_DEVICE_TYPE,
40 	LWS_SYSBLOB_TYPE_NTP_SERVER,
41 	LWS_SYSBLOB_TYPE_MQTT_CLIENT_ID,
42 	LWS_SYSBLOB_TYPE_MQTT_USERNAME,
43 	LWS_SYSBLOB_TYPE_MQTT_PASSWORD,
44 
45 #if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
46 	/* extend 4 more auth blobs, each has 2 slots */
47 	LWS_SYSBLOB_TYPE_EXT_AUTH1,
48 	LWS_SYSBLOB_TYPE_EXT_AUTH2 = LWS_SYSBLOB_TYPE_EXT_AUTH1 + 2,
49 	LWS_SYSBLOB_TYPE_EXT_AUTH3 = LWS_SYSBLOB_TYPE_EXT_AUTH2 + 2,
50 	LWS_SYSBLOB_TYPE_EXT_AUTH4 = LWS_SYSBLOB_TYPE_EXT_AUTH3 + 2,
51 	LWS_SYSBLOB_TYPE_EXT_AUTH4_1,
52 #endif
53 
54 	LWS_SYSBLOB_TYPE_COUNT /* ... always last */
55 } lws_system_blob_item_t;
56 
57 /* opaque generic blob whose content may be on-the-heap or pointed-to
58  * directly case by case.  When it's on the heap, it can be produced by
59  * appending (it's a buflist underneath).  Either way, it can be consumed by
60  * copying out a given length from a given offset.
61  */
62 
63 typedef struct lws_system_blob lws_system_blob_t;
64 
65 LWS_EXTERN LWS_VISIBLE void
66 lws_system_blob_direct_set(lws_system_blob_t *b, const uint8_t *ptr, size_t len);
67 
68 LWS_EXTERN LWS_VISIBLE void
69 lws_system_blob_heap_empty(lws_system_blob_t *b);
70 
71 LWS_EXTERN LWS_VISIBLE int
72 lws_system_blob_heap_append(lws_system_blob_t *b, const uint8_t *ptr, size_t len);
73 
74 LWS_EXTERN LWS_VISIBLE size_t
75 lws_system_blob_get_size(lws_system_blob_t *b);
76 
77 /* return 0 and sets *ptr to point to blob data if possible, nonzero = fail */
78 LWS_EXTERN LWS_VISIBLE int
79 lws_system_blob_get_single_ptr(lws_system_blob_t *b, const uint8_t **ptr);
80 
81 LWS_EXTERN LWS_VISIBLE int
82 lws_system_blob_get(lws_system_blob_t *b, uint8_t *ptr, size_t *len, size_t ofs);
83 
84 LWS_EXTERN LWS_VISIBLE void
85 lws_system_blob_destroy(lws_system_blob_t *b);
86 
87 /*
88  * Get the opaque blob for index idx of various system blobs.  Returns 0 if
89  * *b was set otherwise nonzero means out of range
90  */
91 
92 LWS_EXTERN LWS_VISIBLE lws_system_blob_t *
93 lws_system_get_blob(struct lws_context *context, lws_system_blob_item_t type,
94                     int idx);
95 
96 /*
97  * Lws view of system state... normal operation from user code perspective is
98  * dependent on implicit (eg, knowing the date for cert validation) and
99  * explicit dependencies.
100  *
101  * Bit of lws and user code can register notification handlers that can enforce
102  * dependent operations before state transitions can complete.
103  */
104 
105 typedef enum { /* keep system_state_names[] in sync in context.c */
106 	LWS_SYSTATE_UNKNOWN,
107 
108 	LWS_SYSTATE_CONTEXT_CREATED,	 /* context was just created */
109 	LWS_SYSTATE_INITIALIZED,	 /* protocols initialized.  Lws itself
110 					  * can operate normally */
111 	LWS_SYSTATE_IFACE_COLDPLUG,	 /* existing net ifaces iterated */
112 	LWS_SYSTATE_DHCP,		 /* at least one net iface configured */
113 	LWS_SYSTATE_CPD_PRE_TIME,	 /* Captive portal detect without valid
114 					  * time, good for non-https tests... if
115 					  * you care about it, implement and
116 					  * call lws_system_ops_t
117 					  * .captive_portal_detect_request()
118 					  * and move the state forward according
119 					  * to the result. */
120 	LWS_SYSTATE_TIME_VALID,		 /* ntpclient ran, or hw time valid...
121 					  * tls cannot work until we reach here
122 					  */
123 	LWS_SYSTATE_CPD_POST_TIME,	 /* Captive portal detect after time was
124 					  * time, good for https tests... if
125 					  * you care about it, implement and
126 					  * call lws_system_ops_t
127 					  * .captive_portal_detect_request()
128 					  * and move the state forward according
129 					  * to the result. */
130 
131 	LWS_SYSTATE_POLICY_VALID,	 /* user code knows how to operate... */
132 	LWS_SYSTATE_REGISTERED,		 /* device has an identity... */
133 	LWS_SYSTATE_AUTH1,		 /* identity used for main auth token */
134 	LWS_SYSTATE_AUTH2,		 /* identity used for optional auth */
135 
136 	LWS_SYSTATE_OPERATIONAL,	 /* user code can operate normally */
137 
138 	LWS_SYSTATE_POLICY_INVALID,	 /* user code is changing its policies
139 					  * drop everything done with old
140 					  * policy, switch to new then enter
141 					  * LWS_SYSTATE_POLICY_VALID */
142 	LWS_SYSTATE_CONTEXT_DESTROYING,	 /* Context is being destroyed */
143 } lws_system_states_t;
144 
145 /* Captive Portal Detect -related */
146 
147 typedef enum {
148 	LWS_CPD_UNKNOWN = 0,	/* test didn't happen ince last DHCP acq yet */
149 	LWS_CPD_INTERNET_OK,	/* no captive portal: our CPD test passed OK,
150 				 * we can go out on the internet */
151 	LWS_CPD_CAPTIVE_PORTAL,	/* we inferred we're behind a captive portal */
152 	LWS_CPD_NO_INTERNET,	/* we couldn't touch anything */
153 } lws_cpd_result_t;
154 
155 typedef void (*lws_attach_cb_t)(struct lws_context *context, int tsi, void *opaque);
156 struct lws_attach_item;
157 
158 LWS_EXTERN LWS_VISIBLE int
159 lws_tls_jit_trust_got_cert_cb(struct lws_context *cx, void *got_opaque,
160 			      const uint8_t *skid, size_t skid_len,
161 			      const uint8_t *der, size_t der_len);
162 
163 typedef struct lws_system_ops {
164 	int (*reboot)(void);
165 	int (*set_clock)(lws_usec_t us);
166 	int (*attach)(struct lws_context *context, int tsi, lws_attach_cb_t cb,
167 		      lws_system_states_t state, void *opaque,
168 		      struct lws_attach_item **get);
169 	/**< if \p get is NULL, add an attach callback request to the pt for
170 	 * \p cb with arg \p opaque, that should be called when we're at or past
171 	 * system state \p state.
172 	 *
173 	 * If \p get is non-NULL, look for the first listed item on the pt whose
174 	 * state situation is ready, and set *get to point to it.  If no items,
175 	 * or none where the system state is right, set *get to NULL.
176 	 *
177 	 * It's done like this so (*attach) can perform system-specific
178 	 * locking outside of lws core, for both getting and adding items the
179 	 * same so it is thread-safe.  A non-threadsafe helper
180 	 * __lws_system_attach() is provided to do the actual work inside the
181 	 * system-specific locking.
182 	 */
183 	int (*captive_portal_detect_request)(struct lws_context *context);
184 	/**< Check if we can go out on the internet cleanly, or if we are being
185 	 * redirected or intercepted by a captive portal.
186 	 * Start the check that proceeds asynchronously, and report the results
187 	 * by calling lws_captive_portal_detect_result() api
188 	 */
189 
190 	int (*metric_report)(lws_metric_pub_t *mdata);
191 	/**< metric \p item is reporting an event of kind \p rpt,
192 	 * held in \p mdata... return 0 to leave the metric object as it is,
193 	 * or nonzero to reset it. */
194 
195 	int (*jit_trust_query)(struct lws_context *cx, const uint8_t *skid,
196 			       size_t skid_len, void *got_opaque);
197 	/**< user defined trust store search, if we do trust a cert with SKID
198 	 * matching skid / skid_len, then it should get hold of the DER for the
199 	 * matching root CA and call
200 	 * lws_tls_jit_trust_got_cert_cb(..., got_opaque) before cleaning up and
201 	 * returning.  The DER should be destroyed if in heap before returning.
202 	 */
203 
204 	uint32_t	wake_latency_us;
205 	/**< time taken for this device to wake from suspend, in us
206 	 */
207 } lws_system_ops_t;
208 
209 #if defined(LWS_WITH_SYS_STATE)
210 
211 /**
212  * lws_system_get_state_manager() - return the state mgr object for system state
213  *
214  * \param context: the lws_context
215  *
216  * The returned pointer can be used with the lws_state_ apis
217  */
218 
219 LWS_EXTERN LWS_VISIBLE lws_state_manager_t *
220 lws_system_get_state_manager(struct lws_context *context);
221 
222 #endif
223 
224 /* wrappers handle NULL members or no ops struct set at all cleanly */
225 
226 #define LWSSYSGAUTH_HEX (1 << 0)
227 
228 /**
229  * lws_system_get_ops() - get ahold of the system ops struct from the context
230  *
231  * \param context: the lws_context
232  *
233  * Returns the system ops struct.  It may return NULL and if not, anything in
234  * there may be NULL.
235  */
236 LWS_EXTERN LWS_VISIBLE const lws_system_ops_t *
237 lws_system_get_ops(struct lws_context *context);
238 
239 #if defined(LWS_WITH_SYS_STATE)
240 
241 /**
242  * lws_system_context_from_system_mgr() - return context from system state mgr
243  *
244  * \param mgr: pointer to specifically the system state mgr
245  *
246  * Returns the context from the system state mgr.  Helper since the lws_context
247  * is opaque.
248  */
249 LWS_EXTERN LWS_VISIBLE struct lws_context *
250 lws_system_context_from_system_mgr(lws_state_manager_t *mgr);
251 
252 #endif
253 
254 /**
255  * __lws_system_attach() - get and set items on context attach list
256  *
257  * \param context: context to get or set attach items to
258  * \param tsi: thread service index (normally 0)
259  * \param cb: callback to call from context event loop thread
260  * \param state: the lws_system state we have to be in or have passed through
261  * \param opaque: optional pointer to user specific info given to callback
262  * \param get: NULL, or pointer to pointer to take detached tail item on exit
263  *
264  * This allows other threads to enqueue callback requests to happen from a pt's
265  * event loop thread safely.  The callback gets the context pointer and a user
266  * opaque pointer that can be optionally given when the item is added to the
267  * attach list.
268  *
269  * This api is the no-locking core function for getting and setting items on the
270  * pt's attach list.  The lws_system operation (*attach) is the actual
271  * api that user and internal code calls for this feature, it should perform
272  * system-specific locking, call this helper, release the locking and then
273  * return the result.  This api is public only so it can be used in the locked
274  * implementation of (*attach).
275  *
276  * If get is NULL, then the call adds to the head of the pt attach list using
277  * cb, state, and opaque; if get is non-NULL, then *get is set to the first
278  * waiting attached item that meets the state criteria and that item is removed
279  * from the list.
280  *
281  * This is a non-threadsafe helper only designed to be called from
282  * implementations of struct lws_system's (*attach) operation where system-
283  * specific locking has been applied around it, making it threadsafe.
284  */
285 LWS_EXTERN LWS_VISIBLE int
286 __lws_system_attach(struct lws_context *context, int tsi, lws_attach_cb_t cb,
287 		    lws_system_states_t state, void *opaque,
288 		    struct lws_attach_item **get);
289 
290 
291 enum {
292 	LWSDH_IPV4_SUBNET_MASK		= 0,
293 	LWSDH_IPV4_BROADCAST,
294 	LWSDH_LEASE_SECS,
295 	LWSDH_REBINDING_SECS,
296 	LWSDH_RENEWAL_SECS,
297 
298 	_LWSDH_NUMS_COUNT,
299 
300 	LWSDH_SA46_IP			= 0,
301 	LWSDH_SA46_DNS_SRV_1,
302 	LWSDH_SA46_DNS_SRV_2,
303 	LWSDH_SA46_DNS_SRV_3,
304 	LWSDH_SA46_DNS_SRV_4,
305 	LWSDH_SA46_IPV4_ROUTER,
306 	LWSDH_SA46_NTP_SERVER,
307 	LWSDH_SA46_DHCP_SERVER,
308 
309 	_LWSDH_SA46_COUNT,
310 };
311 
312 typedef struct lws_dhcpc_ifstate {
313 	char				ifname[16];
314 	char				domain[64];
315 	uint8_t				mac[6];
316 	uint32_t			nums[_LWSDH_NUMS_COUNT];
317 	lws_sockaddr46			sa46[_LWSDH_SA46_COUNT];
318 } lws_dhcpc_ifstate_t;
319 
320 typedef int (*dhcpc_cb_t)(void *opaque, lws_dhcpc_ifstate_t *is);
321 
322 /**
323  * lws_dhcpc_request() - add a network interface to dhcpc management
324  *
325  * \param c: the lws_context
326  * \param i: the interface name, like "eth0"
327  * \param af: address family
328  * \param cb: the change callback
329  * \param opaque: opaque pointer given to the callback
330  *
331  * Register a network interface as being managed by DHCP.  lws will proceed to
332  * try to acquire an IP.  Requires LWS_WITH_SYS_DHCP_CLIENT at cmake.
333  */
334 LWS_EXTERN LWS_VISIBLE int
335 lws_dhcpc_request(struct lws_context *c, const char *i, int af, dhcpc_cb_t cb,
336 		void *opaque);
337 
338 /**
339  * lws_dhcpc_remove() - remove a network interface to dhcpc management
340  *
341  * \param context: the lws_context
342  * \param iface: the interface name, like "eth0"
343  *
344  * Remove handling of the network interface from dhcp.
345  */
346 LWS_EXTERN LWS_VISIBLE int
347 lws_dhcpc_remove(struct lws_context *context, const char *iface);
348 
349 /**
350  * lws_dhcpc_status() - has any interface reached BOUND state
351  *
352  * \param context: the lws_context
353  * \param sa46: set to a DNS server from a bound interface, or NULL
354  *
355  * Returns 1 if any network interface managed by dhcpc has reached the BOUND
356  * state (has acquired an IP, gateway and DNS server), otherwise 0.
357  */
358 LWS_EXTERN LWS_VISIBLE int
359 lws_dhcpc_status(struct lws_context *context, lws_sockaddr46 *sa46);
360 
361 /**
362  * lws_system_cpd_start() - helper to initiate captive portal detection
363  *
364  * \param context: the lws_context
365  *
366  * Resets the context's captive portal state to LWS_CPD_UNKNOWN and calls the
367  * lws_system_ops_t captive_portal_detect_request() implementation to begin
368  * testing the captive portal state.
369  */
370 LWS_EXTERN LWS_VISIBLE int
371 lws_system_cpd_start(struct lws_context *context);
372 
373 LWS_EXTERN LWS_VISIBLE void
374 lws_system_cpd_start_defer(struct lws_context *cx, lws_usec_t defer_us);
375 
376 
377 /**
378  * lws_system_cpd_set() - report the result of the captive portal detection
379  *
380  * \param context: the lws_context
381  * \param result: one of the LWS_CPD_ constants representing captive portal state
382  *
383  * Sets the context's captive portal detection state to result.  User captive
384  * portal detection code would call this once it had a result from its test.
385  */
386 LWS_EXTERN LWS_VISIBLE void
387 lws_system_cpd_set(struct lws_context *context, lws_cpd_result_t result);
388 
389 
390 /**
391  * lws_system_cpd_state_get() - returns the last tested captive portal state
392  *
393  * \param context: the lws_context
394  *
395  * Returns one of the LWS_CPD_ constants indicating the system's understanding
396  * of the current captive portal situation.
397  */
398 LWS_EXTERN LWS_VISIBLE lws_cpd_result_t
399 lws_system_cpd_state_get(struct lws_context *context);
400