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
42 int
lws_conmon_append_copy_new_dns_results(struct lws * wsi,const struct addrinfo * cai)43 lws_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
124 void
lws_conmon_addrinfo_destroy(struct addrinfo * ai)125 lws_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
135 void
lws_conmon_wsi_take(struct lws * wsi,struct lws_conmon * dest)136 lws_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
146 void
lws_conmon_release(struct lws_conmon * conmon)147 lws_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