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