1/* 2 * libwebsockets - small server side websockets and web server implementation 3 * 4 * Copyright (C) 2019 - 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 * Client Connection Latency and DNS reporting 25 */ 26 27/* 28 * We want to allocate copies for and append DNS results that we don't already 29 * have. We take this approach because a) we may be getting duplicated results 30 * from multiple DNS servers, and b) we may be getting results stacatto over 31 * time. 32 * 33 * We capture DNS results from either getaddrinfo or ASYNC_DNS the same here, 34 * before they are sorted and filtered. 35 * 36 * Because this is relatively expensive, we only do it on client wsi that 37 * explicitly indicated that they want it with the LCCSCF_CONMON flag. 38 */ 39 40#include <private-lib-core.h> 41 42int 43lws_conmon_append_copy_new_dns_results(struct lws *wsi, 44 const struct addrinfo *cai) 45{ 46 if (!(wsi->flags & LCCSCF_CONMON)) 47 return 0; 48 49 /* 50 * Let's go through the incoming guys, seeing if we already have them, 51 * or if we want to take a copy 52 */ 53 54 while (cai) { 55 struct addrinfo *ai = wsi->conmon.dns_results_copy; 56 char skip = 0; 57 58 /* do we already have this guy? */ 59 60 while (ai) { 61 62 if (ai->ai_family != cai->ai_family && 63 ai->ai_addrlen != cai->ai_addrlen && 64 ai->ai_protocol != cai->ai_protocol && 65 ai->ai_socktype != cai->ai_socktype && 66 /* either ipv4 or v6 address must match */ 67 ((ai->ai_family == AF_INET && 68 ((struct sockaddr_in *)ai->ai_addr)-> 69 sin_addr.s_addr == 70 ((struct sockaddr_in *)cai->ai_addr)-> 71 sin_addr.s_addr) 72#if defined(LWS_WITH_IPV6) 73 || 74 (ai->ai_family == AF_INET6 && 75 !memcmp(((struct sockaddr_in6 *)ai->ai_addr)-> 76 sin6_addr.s6_addr, 77 ((struct sockaddr_in6 *)cai->ai_addr)-> 78 sin6_addr.s6_addr, 16)) 79#endif 80 )) { 81 /* yes, we already got a copy then */ 82 skip = 1; 83 break; 84 } 85 86 ai = ai->ai_next; 87 } 88 89 if (!skip) { 90 /* 91 * No we don't already have a copy of this one, let's 92 * allocate and append it then 93 */ 94 size_t al = sizeof(struct addrinfo) + 95 (size_t)cai->ai_addrlen; 96 size_t cl = cai->ai_canonname ? 97 strlen(cai->ai_canonname) + 1 : 0; 98 99 ai = lws_malloc(al + cl + 1, __func__); 100 if (!ai) { 101 lwsl_wsi_warn(wsi, "OOM"); 102 return 1; 103 } 104 *ai = *cai; 105 ai->ai_addr = (struct sockaddr *)&ai[1]; 106 memcpy(ai->ai_addr, cai->ai_addr, (size_t)cai->ai_addrlen); 107 108 if (cl) { 109 ai->ai_canonname = ((char *)ai->ai_addr) + 110 cai->ai_addrlen; 111 memcpy(ai->ai_canonname, cai->ai_canonname, 112 cl + 1); 113 } 114 ai->ai_next = wsi->conmon.dns_results_copy; 115 wsi->conmon.dns_results_copy = ai; 116 } 117 118 cai = cai->ai_next; 119 } 120 121 return 0; 122} 123 124void 125lws_conmon_addrinfo_destroy(struct addrinfo *ai) 126{ 127 while (ai) { 128 struct addrinfo *ai1 = ai->ai_next; 129 130 lws_free(ai); 131 ai = ai1; 132 } 133} 134 135void 136lws_conmon_wsi_take(struct lws *wsi, struct lws_conmon *dest) 137{ 138 memcpy(dest, &wsi->conmon, sizeof(*dest)); 139 dest->peer46 = wsi->sa46_peer; 140 141 /* wsi no longer has to free it... */ 142 wsi->conmon.dns_results_copy = NULL; 143 wsi->perf_done = 1; 144} 145 146void 147lws_conmon_release(struct lws_conmon *conmon) 148{ 149 if (!conmon) 150 return; 151 152 lws_conmon_addrinfo_destroy(conmon->dns_results_copy); 153 conmon->dns_results_copy = NULL; 154} 155