1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci *
24d4afb5ceSopenharmony_ci * Client Connection Latency and DNS reporting
25d4afb5ceSopenharmony_ci */
26d4afb5ceSopenharmony_ci
27d4afb5ceSopenharmony_ci/*
28d4afb5ceSopenharmony_ci * We want to allocate copies for and append DNS results that we don't already
29d4afb5ceSopenharmony_ci * have.  We take this approach because a) we may be getting duplicated results
30d4afb5ceSopenharmony_ci * from multiple DNS servers, and b) we may be getting results stacatto over
31d4afb5ceSopenharmony_ci * time.
32d4afb5ceSopenharmony_ci *
33d4afb5ceSopenharmony_ci * We capture DNS results from either getaddrinfo or ASYNC_DNS the same here,
34d4afb5ceSopenharmony_ci * before they are sorted and filtered.
35d4afb5ceSopenharmony_ci *
36d4afb5ceSopenharmony_ci * Because this is relatively expensive, we only do it on client wsi that
37d4afb5ceSopenharmony_ci * explicitly indicated that they want it with the LCCSCF_CONMON flag.
38d4afb5ceSopenharmony_ci */
39d4afb5ceSopenharmony_ci
40d4afb5ceSopenharmony_ci#include <private-lib-core.h>
41d4afb5ceSopenharmony_ci
42d4afb5ceSopenharmony_ciint
43d4afb5ceSopenharmony_cilws_conmon_append_copy_new_dns_results(struct lws *wsi,
44d4afb5ceSopenharmony_ci				       const struct addrinfo *cai)
45d4afb5ceSopenharmony_ci{
46d4afb5ceSopenharmony_ci	if (!(wsi->flags & LCCSCF_CONMON))
47d4afb5ceSopenharmony_ci		return 0;
48d4afb5ceSopenharmony_ci
49d4afb5ceSopenharmony_ci	/*
50d4afb5ceSopenharmony_ci	 * Let's go through the incoming guys, seeing if we already have them,
51d4afb5ceSopenharmony_ci	 * or if we want to take a copy
52d4afb5ceSopenharmony_ci	 */
53d4afb5ceSopenharmony_ci
54d4afb5ceSopenharmony_ci	while (cai) {
55d4afb5ceSopenharmony_ci		struct addrinfo *ai = wsi->conmon.dns_results_copy;
56d4afb5ceSopenharmony_ci		char skip = 0;
57d4afb5ceSopenharmony_ci
58d4afb5ceSopenharmony_ci		/* do we already have this guy? */
59d4afb5ceSopenharmony_ci
60d4afb5ceSopenharmony_ci		while (ai) {
61d4afb5ceSopenharmony_ci
62d4afb5ceSopenharmony_ci			if (ai->ai_family != cai->ai_family &&
63d4afb5ceSopenharmony_ci			    ai->ai_addrlen != cai->ai_addrlen &&
64d4afb5ceSopenharmony_ci			    ai->ai_protocol != cai->ai_protocol &&
65d4afb5ceSopenharmony_ci			    ai->ai_socktype != cai->ai_socktype &&
66d4afb5ceSopenharmony_ci			    /* either ipv4 or v6 address must match */
67d4afb5ceSopenharmony_ci			    ((ai->ai_family == AF_INET &&
68d4afb5ceSopenharmony_ci			      ((struct sockaddr_in *)ai->ai_addr)->
69d4afb5ceSopenharmony_ci							     sin_addr.s_addr ==
70d4afb5ceSopenharmony_ci			      ((struct sockaddr_in *)cai->ai_addr)->
71d4afb5ceSopenharmony_ci							     sin_addr.s_addr)
72d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6)
73d4afb5ceSopenharmony_ci					    ||
74d4afb5ceSopenharmony_ci			    (ai->ai_family == AF_INET6 &&
75d4afb5ceSopenharmony_ci			     !memcmp(((struct sockaddr_in6 *)ai->ai_addr)->
76d4afb5ceSopenharmony_ci							     sin6_addr.s6_addr,
77d4afb5ceSopenharmony_ci				     ((struct sockaddr_in6 *)cai->ai_addr)->
78d4afb5ceSopenharmony_ci						     sin6_addr.s6_addr, 16))
79d4afb5ceSopenharmony_ci#endif
80d4afb5ceSopenharmony_ci			    )) {
81d4afb5ceSopenharmony_ci				/* yes, we already got a copy then */
82d4afb5ceSopenharmony_ci				skip = 1;
83d4afb5ceSopenharmony_ci				break;
84d4afb5ceSopenharmony_ci			}
85d4afb5ceSopenharmony_ci
86d4afb5ceSopenharmony_ci			ai = ai->ai_next;
87d4afb5ceSopenharmony_ci		}
88d4afb5ceSopenharmony_ci
89d4afb5ceSopenharmony_ci		if (!skip) {
90d4afb5ceSopenharmony_ci			/*
91d4afb5ceSopenharmony_ci			 * No we don't already have a copy of this one, let's
92d4afb5ceSopenharmony_ci			 * allocate and append it then
93d4afb5ceSopenharmony_ci			 */
94d4afb5ceSopenharmony_ci			size_t al = sizeof(struct addrinfo) +
95d4afb5ceSopenharmony_ci				    (size_t)cai->ai_addrlen;
96d4afb5ceSopenharmony_ci			size_t cl = cai->ai_canonname ?
97d4afb5ceSopenharmony_ci					strlen(cai->ai_canonname) + 1 : 0;
98d4afb5ceSopenharmony_ci
99d4afb5ceSopenharmony_ci			ai = lws_malloc(al + cl + 1, __func__);
100d4afb5ceSopenharmony_ci			if (!ai) {
101d4afb5ceSopenharmony_ci				lwsl_wsi_warn(wsi, "OOM");
102d4afb5ceSopenharmony_ci				return 1;
103d4afb5ceSopenharmony_ci			}
104d4afb5ceSopenharmony_ci			*ai = *cai;
105d4afb5ceSopenharmony_ci			ai->ai_addr = (struct sockaddr *)&ai[1];
106d4afb5ceSopenharmony_ci			memcpy(ai->ai_addr, cai->ai_addr, (size_t)cai->ai_addrlen);
107d4afb5ceSopenharmony_ci
108d4afb5ceSopenharmony_ci			if (cl) {
109d4afb5ceSopenharmony_ci				ai->ai_canonname = ((char *)ai->ai_addr) +
110d4afb5ceSopenharmony_ci							cai->ai_addrlen;
111d4afb5ceSopenharmony_ci				memcpy(ai->ai_canonname, cai->ai_canonname,
112d4afb5ceSopenharmony_ci				       cl + 1);
113d4afb5ceSopenharmony_ci			}
114d4afb5ceSopenharmony_ci			ai->ai_next = wsi->conmon.dns_results_copy;
115d4afb5ceSopenharmony_ci			wsi->conmon.dns_results_copy = ai;
116d4afb5ceSopenharmony_ci		}
117d4afb5ceSopenharmony_ci
118d4afb5ceSopenharmony_ci		cai = cai->ai_next;
119d4afb5ceSopenharmony_ci	}
120d4afb5ceSopenharmony_ci
121d4afb5ceSopenharmony_ci	return 0;
122d4afb5ceSopenharmony_ci}
123d4afb5ceSopenharmony_ci
124d4afb5ceSopenharmony_civoid
125d4afb5ceSopenharmony_cilws_conmon_addrinfo_destroy(struct addrinfo *ai)
126d4afb5ceSopenharmony_ci{
127d4afb5ceSopenharmony_ci	while (ai) {
128d4afb5ceSopenharmony_ci		struct addrinfo *ai1 = ai->ai_next;
129d4afb5ceSopenharmony_ci
130d4afb5ceSopenharmony_ci		lws_free(ai);
131d4afb5ceSopenharmony_ci		ai = ai1;
132d4afb5ceSopenharmony_ci	}
133d4afb5ceSopenharmony_ci}
134d4afb5ceSopenharmony_ci
135d4afb5ceSopenharmony_civoid
136d4afb5ceSopenharmony_cilws_conmon_wsi_take(struct lws *wsi, struct lws_conmon *dest)
137d4afb5ceSopenharmony_ci{
138d4afb5ceSopenharmony_ci	memcpy(dest, &wsi->conmon, sizeof(*dest));
139d4afb5ceSopenharmony_ci	dest->peer46 = wsi->sa46_peer;
140d4afb5ceSopenharmony_ci
141d4afb5ceSopenharmony_ci	/* wsi no longer has to free it... */
142d4afb5ceSopenharmony_ci	wsi->conmon.dns_results_copy = NULL;
143d4afb5ceSopenharmony_ci	wsi->perf_done = 1;
144d4afb5ceSopenharmony_ci}
145d4afb5ceSopenharmony_ci
146d4afb5ceSopenharmony_civoid
147d4afb5ceSopenharmony_cilws_conmon_release(struct lws_conmon *conmon)
148d4afb5ceSopenharmony_ci{
149d4afb5ceSopenharmony_ci	if (!conmon)
150d4afb5ceSopenharmony_ci		return;
151d4afb5ceSopenharmony_ci
152d4afb5ceSopenharmony_ci	lws_conmon_addrinfo_destroy(conmon->dns_results_copy);
153d4afb5ceSopenharmony_ci	conmon->dns_results_copy = NULL;
154d4afb5ceSopenharmony_ci}
155