• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2020 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  *
25  *  Either the libc getaddrinfo() or ASYNC_DNS provides a chain of addrinfo,
26  *  we use lws_sort_dns() to convert it to an lws_dll2 of lws_dns_sort_t, after
27  *  which the addrinfo results are freed.
28  *
29  *  If the system has no routing table info (from, eg, NETLINK), then that's
30  *  it the sorted results are bound to the wsi and used.
31  *
32  *  If the system has routing table info, we study the routing table and the
33  *  DNS results in order to sort the lws_dns_sort_t result linked-list into
34  *  most desirable at the head, and strip results we can't see a way to route.
35  */
36 
37 #include "private-lib-core.h"
38 
39 #if defined(__linux__)
40 #include <linux/if_addr.h>
41 #endif
42 
43 #if defined(__FreeBSD__)
44 #include <net/if.h>
45 #include <netinet6/in6_var.h>
46 #endif
47 
48 #if defined(LWS_WITH_IPV6) && defined(LWS_WITH_NETLINK)
49 
50 /*
51  * RFC6724 default policy table
52  *
53  *      Prefix        Precedence Label
54  *    ::1/128               50     0
55  *    ::/0                  40     1
56  *    ::ffff:0:0/96         35     4  (override prec to 100 to prefer ipv4)
57  *    2002::/16             30     2
58  *    2001::/32              5     5
59  *    fc00::/7               3    13
60  *    ::/96                  1     3
61  *    fec0::/10              1    11
62  *    3ffe::/16              1    12
63  *
64  * implemented using offsets into a combined 40-byte table below
65  */
66 
67 static const uint8_t ma[] = {
68 	/*  0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
69 	/* 16 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff,
70 	/* 28 */ 0x20, 0x02,
71 	/* 30 */ 0x20, 0x01, 0x00, 0x00,
72 	/* 34 */ 0xfc, 0x00,
73 	/* 36 */ 0xfe, 0xc0,
74 	/* 38 */ 0x3f, 0xfe
75 };
76 
77 static const uint8_t frac[] = {
78 	0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
79 };
80 
81 /* 9 x 4 byte = 36 byte policy index table */
82 
83 static const struct score_policy {
84 	uint8_t			ma_ofs;
85 	uint8_t			prefix;
86 	lws_dns_score_t		score;
87 } rfc6724_policy[] = {
88 
89 	{  0,	128,	{  50,  0 } },		/* ::1/128 */
90 	{  0,	  0,	{  40,  1 } },		/* ::0 */
91 #if 1
92 	/* favour ipv6 as a general policy */
93 	{ 16,	 96,	{  35,  4 } },		/* ::ffff:0:0/96 */
94 #else
95 	/* favour ipv4 as a general policy */
96 	{ 16,	 96,	{ 100,  4 } },		/* ::ffff:0:0/96 */
97 #endif
98 	{ 28,	 16,	{  30,  2 } },		/* 2002::/16 */
99 	{ 30,	 32,	{   5,  5 } },		/* 2001::/32 */
100 	{ 34,	  7,	{   3, 13 } },		/* fc00::/7 */
101 	{  0,	 96,	{   1,  3 } },		/* ::/96 */
102 	{ 36,	 10,	{   1, 11 } },		/* fec0::/10 */
103 	{ 38,	 16,	{   1, 12 } },		/* 3ffe::/16 */
104 
105 };
106 
107 static int
lws_ipv6_prefix_match_len(const struct sockaddr_in6 * a,const struct sockaddr_in6 * b)108 lws_ipv6_prefix_match_len(const struct sockaddr_in6 *a,
109 			  const struct sockaddr_in6 *b)
110 {
111 	const uint8_t *ads_a = (uint8_t *)&a->sin6_addr,
112 		      *ads_b = (uint8_t *)&b->sin6_addr;
113 	int n = 0, match = 0;
114 
115 	for (n = 0; n < 16; n++) {
116 		if (ads_a[n] == ads_b[n])
117 			match += 8;
118 		else
119 			break;
120 	}
121 
122 	if (match != 128) {
123 		int m;
124 
125 		for (m = 1; m < 8; m++) {
126 			if ((ads_a[n] & frac[m]) == (ads_b[n] & frac[m]))
127 				match++;
128 			else
129 				break;
130 		}
131 	}
132 
133 	return match;
134 }
135 
136 static int
lws_ipv6_unicast_scope(const struct sockaddr_in6 * sa)137 lws_ipv6_unicast_scope(const struct sockaddr_in6 *sa)
138 {
139 	uint64_t *u;
140 
141 	u = (uint64_t *)&sa->sin6_addr;
142 	if (*u == 0xfe80000000000000ull)
143 		return 2; /* link-local */
144 
145 	return 0xe;
146 }
147 
148 static int
lws_sort_dns_scope(lws_sockaddr46 * sa46)149 lws_sort_dns_scope(lws_sockaddr46 *sa46)
150 {
151 	if (sa46->sa4.sin_family == AF_INET) {
152 		uint8_t *p = (uint8_t *)&sa46->sa4.sin_addr;
153 
154 		/* RFC6724 3.2 */
155 
156 		if (p[0] == 127 || (p[0] == 169 && p[1] == 254))
157 			return 2; /* link-local */
158 
159 		return 0xe; /* global */
160 	}
161 
162 	return lws_ipv6_unicast_scope(&sa46->sa6);
163 }
164 
165 static int
lws_sort_dns_classify(lws_sockaddr46 * sa46,lws_dns_score_t * score)166 lws_sort_dns_classify(lws_sockaddr46 *sa46, lws_dns_score_t *score)
167 {
168 	const struct score_policy *pol = rfc6724_policy;
169 	const uint8_t *p, *po;
170 	lws_sockaddr46 s;
171 	int n, m;
172 
173 	memset(score, 0, sizeof(*score));
174 
175 	if (sa46->sa4.sin_family == AF_INET) {
176 		memset(&s, 0, sizeof(s));
177 		s.sa6.sin6_family = AF_INET6;
178 		lws_4to6((uint8_t *)s.sa6.sin6_addr.s6_addr,
179 			 (const uint8_t *)&sa46->sa4.sin_addr);
180 
181 		/* use the v6 version of the v4 address */
182 		sa46 = &s;
183 	}
184 
185 	for (n = 0; n < (int)LWS_ARRAY_SIZE(rfc6724_policy); n++) {
186 		po = (uint8_t *)&sa46->sa6.sin6_addr.s6_addr;
187 		p = &ma[pol->ma_ofs];
188 		for (m = 0; m < pol->prefix >> 3; m++)
189 			if (*p++ != *po++)
190 				goto next;
191 
192 		if ((pol->prefix & 7) && (*p & frac[pol->prefix & 7]) !=
193 					  (*po & frac[pol->prefix & 7]))
194 			goto next;
195 
196 		*score = pol->score;
197 
198 		return 0;
199 
200 next:
201 		pol++;
202 	}
203 
204 	return 1;
205 }
206 
207 
208 enum {
209 	SAS_PREFER_A	=  1,
210 	SAS_SAME	=  0,
211 	SAS_PREFER_B	= -1
212 };
213 
214 /* ifa is laid out with types for ipv4, if it's AF_INET6 case to sockaddr_in6 */
215 #define to_v6_sa(x) ((struct sockaddr_in6 *)x)
216 #define to_sa46_sa(x) ((lws_sockaddr46 *)x)
217 
218 /*
219  * The source address selection algorithm produces as output a single
220  * source address for use with a given destination address.  This
221  * algorithm only applies to IPv6 destination addresses, not IPv4
222  * addresses.
223  *
224  * This implements RFC6724 Section 5.
225  *
226  * Either or both sa and sb can be dest or gateway routes
227  */
228 
229 static int
lws_sort_dns_scomp(struct lws_context_per_thread * pt,const lws_route_t * sa,const lws_route_t * sb,const struct sockaddr_in6 * dst)230 lws_sort_dns_scomp(struct lws_context_per_thread *pt, const lws_route_t *sa,
231 		   const lws_route_t *sb, const struct sockaddr_in6 *dst)
232 {
233 	const struct sockaddr_in6 *sa6 = to_v6_sa(&sa->dest),
234 				  *sb6 = to_v6_sa(&sb->dest);
235 	lws_dns_score_t scorea, scoreb, scoredst;
236 	int scopea, scopeb, scoped, mla, mlb;
237 	lws_route_t *rd;
238 
239 	if (!sa->dest.sa4.sin_family)
240 		sa6 = to_v6_sa(&sa->gateway);
241 	if (!sb->dest.sa4.sin_family)
242 		sb6 = to_v6_sa(&sb->gateway);
243 
244 	/*
245 	 * We shouldn't come here unless sa and sb both have AF_INET6 addresses
246 	 */
247 
248 	assert(sa6->sin6_family == AF_INET6);
249 	assert(sb6->sin6_family == AF_INET6);
250 
251 	/*
252 	 * Rule 1: Prefer same address.
253 	 * If SA = D, then prefer SA.  Similarly, if SB = D, then prefer SB.
254 	 */
255 
256 	if (!memcmp(&sa6->sin6_addr, &dst->sin6_addr, 16))
257 		return SAS_PREFER_A;
258 	if (!memcmp(&sb6->sin6_addr, &dst->sin6_addr, 16))
259 		return SAS_PREFER_B;
260 
261 	/*
262 	 * Rule 2: Prefer appropriate scope.
263 	 * If Scope(SA) < Scope(SB): If Scope(SA) < Scope(D), then prefer SB
264 	 * and otherwise prefer SA.
265 	 *
266 	 * Similarly, if Scope(SB) < Scope(SA): If Scope(SB) < Scope(D), then
267 	 * prefer SA and otherwise prefer SB.
268 	 */
269 
270 	scopea = lws_sort_dns_scope(to_sa46_sa(sa6));
271 	scopeb = lws_sort_dns_scope(to_sa46_sa(sb6));
272 	scoped = lws_sort_dns_scope(to_sa46_sa(dst));
273 
274 	if (scopea < scopeb)
275 		return scopea < scoped ? SAS_PREFER_B : SAS_PREFER_A;
276 
277 	if (scopeb < scopea)
278 		return scopeb < scoped ? SAS_PREFER_A : SAS_PREFER_B;
279 
280 	/*
281 	 * Rule 3: Avoid deprecated addresses.
282 	 * If one of the two source addresses is "preferred" and one of them
283 	 * is "deprecated" (in the RFC 4862 sense), then prefer the one that
284 	 * is "preferred".
285 	 */
286 
287 	if (!(sa->ifa_flags & IFA_F_DEPRECATED) &&
288 	     (sb->ifa_flags & IFA_F_DEPRECATED))
289 		return SAS_PREFER_A;
290 
291 	if ( (sa->ifa_flags & IFA_F_DEPRECATED) &&
292 	    !(sb->ifa_flags & IFA_F_DEPRECATED))
293 		return SAS_PREFER_B;
294 
295 	/*
296 	 * Rule 4: Prefer home addresses.
297 	 * If SA is simultaneously a home address and care-of address and SB is
298 	 * not, then prefer SA.  Similarly, if SB is simultaneously a home
299 	 * address and care-of address and SA is not, then prefer SB.  If SA is
300 	 * just a home address and SB is just a care-of address, then prefer SA.
301 	 * Similarly, if SB is just a home address and SA is just a care-of
302 	 * address, then prefer SB.
303 	 *
304 	 * !!! not sure how to determine if care-of address
305 	 */
306 
307 	if ( (sa->ifa_flags & IFA_F_HOMEADDRESS) &&
308 	    !(sb->ifa_flags & IFA_F_HOMEADDRESS))
309 		return SAS_PREFER_A;
310 
311 	if (!(sa->ifa_flags & IFA_F_HOMEADDRESS) &&
312 	     (sb->ifa_flags & IFA_F_HOMEADDRESS))
313 		return SAS_PREFER_B;
314 
315 	/*
316 	 * Rule 5: Prefer outgoing interface.
317 	 * If SA is assigned to the interface that will be used to send to D
318 	 * and SB is assigned to a different interface, then prefer SA.
319 	 * Similarly, if SB is assigned to the interface that will be used
320 	 * to send to D and SA is assigned to a different interface, then
321 	 * prefer SB.
322 	 */
323 
324 	rd = _lws_route_est_outgoing(pt, (lws_sockaddr46 *)dst);
325 	if (rd) {
326 		if (rd->if_idx == sa->if_idx)
327 			return SAS_PREFER_A;
328 		if (rd->if_idx == sb->if_idx)
329 			return SAS_PREFER_B;
330 	}
331 
332 	/*
333 	 * Rule 6: Prefer matching label.
334 	 * If Label(SA) = Label(D) and Label(SB) <> Label(D), then prefer SA.
335 	 * Similarly, if Label(SB) = Label(D) and Label(SA) <> Label(D), then
336 	 * prefer SB.
337 	 */
338 
339 	lws_sort_dns_classify(to_sa46_sa(sa6), &scorea);
340 	lws_sort_dns_classify(to_sa46_sa(sb6), &scoreb);
341 	lws_sort_dns_classify(to_sa46_sa(dst), &scoredst);
342 
343 	if (scorea.label == scoredst.label && scoreb.label != scoredst.label)
344 		return SAS_PREFER_A;
345 	if (scoreb.label == scoredst.label && scorea.label != scoredst.label)
346 		return SAS_PREFER_B;
347 
348 	/*
349 	 * Rule 7: Prefer temporary addresses.
350 	 * If SA is a temporary address and SB is a public address, then
351 	 * prefer SA.  Similarly, if SB is a temporary address and SA is a
352 	 * public address, then prefer SB.
353 	 */
354 
355 	if ( (sa->ifa_flags & IFA_F_TEMPORARY) &&
356 	    !(sb->ifa_flags & IFA_F_TEMPORARY))
357 		return SAS_PREFER_A;
358 
359 	if (!(sa->ifa_flags & IFA_F_TEMPORARY) &&
360 	     (sb->ifa_flags & IFA_F_TEMPORARY))
361 		return SAS_PREFER_B;
362 
363 	/*
364 	 * Rule 8: Use longest matching prefix.
365 	 * If CommonPrefixLen(SA, D) > CommonPrefixLen(SB, D), then prefer SA.
366 	 * Similarly, if CommonPrefixLen(SB, D) > CommonPrefixLen(SA, D), then
367 	 * prefer SB.
368 	 */
369 
370 	mla = lws_ipv6_prefix_match_len(sa6, dst);
371 	mlb = lws_ipv6_prefix_match_len(sb6, dst);
372 
373 	if (mla > mlb)
374 		return SAS_PREFER_A;
375 
376 	return SAS_SAME;
377 }
378 
379 /*
380  * Given two possible source addresses and the destination address, we attempt
381  * to pick which one is "better".
382  *
383  * This implements RFC6724 Section 6.
384  */
385 
386 static int
lws_sort_dns_dcomp(const lws_dns_sort_t * da,const lws_dns_sort_t * db)387 lws_sort_dns_dcomp(const lws_dns_sort_t *da, const lws_dns_sort_t *db)
388 {
389 	int scopea, scopeb, scope_srca, scope_srcb, cpla, cplb;
390 	const uint8_t *da_ads = (const uint8_t *)&da->dest.sa6.sin6_addr,
391 		      *db_ads = (const uint8_t *)&db->dest.sa6.sin6_addr;
392 	lws_dns_score_t score_srca, score_srcb;
393 
394 	/*
395 	 * Rule 1: Avoid unusable destinations
396 	 *
397 	 * We already strip destinations with no usable source
398 	 */
399 
400 	/*
401 	 * Rule 2: Prefer matching scope
402 	 *
403 	 * If Scope(DA) = Scope(Source(DA)) and Scope(DB) <> Scope(Source(DB)),
404 	 * then prefer DA.  Similarly, if Scope(DA) <> Scope(Source(DA)) and
405 	 * Scope(DB) = Scope(Source(DB)), then prefer DB.
406 	 */
407 
408 	scopea = lws_ipv6_unicast_scope(to_v6_sa(&da->dest));
409 	scopeb = lws_ipv6_unicast_scope(to_v6_sa(&db->dest));
410 	scope_srca = lws_ipv6_unicast_scope(to_v6_sa(&da->source));
411 	scope_srcb = lws_ipv6_unicast_scope(to_v6_sa(&db->source));
412 
413 	if (scopea == scope_srca && scopeb != scope_srcb)
414 		return SAS_PREFER_A;
415 
416 	if (scopea != scope_srca && scopeb == scope_srcb)
417 		return SAS_PREFER_B;
418 
419 #if defined(IFA_F_DEPRECATED)
420 	/*
421 	 * Rule 3: Avoid deprecated addresses.
422 	 *
423 	 * If Source(DA) is deprecated and Source(DB) is not, then prefer DB.
424 	 * Similarly, if Source(DA) is not deprecated and Source(DB) is
425 	 * deprecated, then prefer DA.
426 	 */
427 
428 	if (!(da->ifa_flags & IFA_F_DEPRECATED) &&
429 	     (db->ifa_flags & IFA_F_DEPRECATED))
430 		return SAS_PREFER_A;
431 
432 	if ( (da->ifa_flags & IFA_F_DEPRECATED) &&
433 	    !(db->ifa_flags & IFA_F_DEPRECATED))
434 		return SAS_PREFER_B;
435 #endif
436 
437 	/*
438 	 * Rule 4: Prefer home addresses.
439 	 *
440 	 * If Source(DA) is simultaneously a home address and care-of address
441 	 * and Source(DB) is not, then prefer DA.  Similarly, if Source(DB) is
442 	 * simultaneously a home address and care-of address and Source(DA) is
443 	 * not, then prefer DB.
444 	 *
445 	 * If Source(DA) is just a home address and Source(DB) is just a care-of
446 	 * address, then prefer DA.  Similarly, if Source(DA) is just a care-of
447 	 * address and Source(DB) is just a home address, then prefer DB.
448 	 *
449 	 * !!! not sure how to determine if care-of address
450 	 */
451 
452 	if ( (da->ifa_flags & IFA_F_HOMEADDRESS) &&
453 	    !(db->ifa_flags & IFA_F_HOMEADDRESS))
454 		return SAS_PREFER_A;
455 
456 	if (!(da->ifa_flags & IFA_F_HOMEADDRESS) &&
457 	     (db->ifa_flags & IFA_F_HOMEADDRESS))
458 		return SAS_PREFER_B;
459 
460 	/*
461 	 * Rule 5: Prefer matching label.
462 	 *
463 	 * If Label(Source(DA)) = Label(DA) and Label(Source(DB)) <> Label(DB),
464 	 * then prefer DA.  Similarly, if Label(Source(DA)) <> Label(DA) and
465 	 * Label(Source(DB)) = Label(DB), then prefer DB
466 	 */
467 
468 	if (!da->source)
469 		return SAS_PREFER_B;
470 	if (!db->source)
471 		return SAS_PREFER_A;
472 
473 	lws_sort_dns_classify(&da->source->dest, &score_srca);
474 	lws_sort_dns_classify(&db->source->dest, &score_srcb);
475 
476 	if (score_srca.label == da->score.label &&
477 	    score_srcb.label != db->score.label)
478 		return SAS_PREFER_A;
479 	if (score_srca.label != da->score.label &&
480 	    score_srcb.label == db->score.label)
481 		return SAS_PREFER_B;
482 
483 	/*
484 	 * Rule 6: Prefer higher precedence.
485 	 *
486 	 * If Precedence(DA) > Precedence(DB), then prefer DA.  Similarly, if
487 	 * Precedence(DA) < Precedence(DB), then prefer DB.
488 	 */
489 
490 	if (da->score.precedence > db->score.precedence)
491 		return SAS_PREFER_A;
492 
493 	if (da->score.precedence < db->score.precedence)
494 		return SAS_PREFER_B;
495 
496 	/*
497 	 * Rule 7: Prefer native transport.
498 	 * If DA is reached via an encapsulating transition mechanism (e.g.,
499 	 * IPv6 in IPv4) and DB is not, then prefer DB.  Similarly, if DB is
500 	 * reached via encapsulation and DA is not, then prefer DA.
501 	 */
502 
503 	if (!memcmp(&ma[16], da_ads, 12) && memcmp(&ma[16], db_ads, 12))
504 		return SAS_PREFER_B;
505 
506 	if (memcmp(&ma[16], da_ads, 12) && !memcmp(&ma[16], db_ads, 12))
507 		return SAS_PREFER_A;
508 
509 	/*
510 	 * Rule 8: Prefer smaller scope.
511 	 * If Scope(DA) < Scope(DB), then prefer DA.  Similarly, if Scope(DA) >
512 	 * Scope(DB), then prefer DB.
513 	 */
514 
515 	if (scopea < scopeb)
516 		return SAS_PREFER_A;
517 
518 	if (scopea > scopeb)
519 		return SAS_PREFER_B;
520 
521 	/*
522 	 * Rule 9: Use longest matching prefix.
523 	 * When DA and DB belong to the same address family (both are IPv6 or
524 	 * both are IPv4): If CommonPrefixLen(Source(DA), DA) >
525 	 * CommonPrefixLen(Source(DB), DB), then prefer DA.  Similarly, if
526 	 * CommonPrefixLen(Source(DA), DA) < CommonPrefixLen(Source(DB), DB),
527 	 * then prefer DB.
528 	 */
529 
530 	cpla = lws_ipv6_prefix_match_len(&da->source->dest.sa6, &da->dest.sa6);
531 	cplb = lws_ipv6_prefix_match_len(&db->source->dest.sa6, &db->dest.sa6);
532 
533 	if (cpla > cplb)
534 		return SAS_PREFER_A;
535 
536 	if (cpla < cplb)
537 		return SAS_PREFER_B;
538 
539 	/*
540 	 * Rule 10: Otherwise, leave the order unchanged.
541 	 */
542 
543 	return SAS_SAME;
544 }
545 
546 static int
lws_sort_dns_compare(const lws_dll2_t * a,const lws_dll2_t * b)547 lws_sort_dns_compare(const lws_dll2_t *a, const lws_dll2_t *b)
548 {
549 	const lws_dns_sort_t *sa = lws_container_of(a, lws_dns_sort_t, list),
550 			     *sb = lws_container_of(b, lws_dns_sort_t, list);
551 
552 	return lws_sort_dns_dcomp(sa, sb);
553 }
554 
555 #endif /* ipv6 + netlink */
556 
557 #if defined(_DEBUG)
558 
559 static void
lws_sort_dns_dump(struct lws * wsi)560 lws_sort_dns_dump(struct lws *wsi)
561 {
562 	int n = 1;
563 
564 	(void)n; /* nologs */
565 
566 	if (!lws_dll2_get_head(&wsi->dns_sorted_list))
567 		lwsl_wsi_notice(wsi, "empty");
568 
569 	lws_start_foreach_dll(struct lws_dll2 *, d,
570 			      lws_dll2_get_head(&wsi->dns_sorted_list)) {
571 		lws_dns_sort_t *s = lws_container_of(d, lws_dns_sort_t, list);
572 		char dest[48], gw[48];
573 
574 		lws_sa46_write_numeric_address(&s->dest, dest, sizeof(dest));
575 		lws_sa46_write_numeric_address(&s->gateway, gw, sizeof(gw));
576 
577 		lwsl_wsi_info(wsi, "%d: (%d)%s, gw (%d)%s, idi: %d, "
578 				"lbl: %d, prec: %d", n++,
579 			    s->dest.sa4.sin_family, dest,
580 			    s->gateway.sa4.sin_family, gw,
581 			    s->if_idx, s->score.label, s->score.precedence);
582 
583 	} lws_end_foreach_dll(d);
584 }
585 
586 #endif
587 
588 int
lws_sort_dns(struct lws * wsi,const struct addrinfo * result)589 lws_sort_dns(struct lws *wsi, const struct addrinfo *result)
590 {
591 #if defined(LWS_WITH_NETLINK)
592 	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
593 #endif
594 	const struct addrinfo *ai = result;
595 
596 	lwsl_wsi_info(wsi, "sort_dns: %p", result);
597 
598 	/*
599 	 * We're going to take the dns results and produce our own linked-list
600 	 * of them, if we can sorted into descending preferability order, and
601 	 * possibly filtered.
602 	 *
603 	 * First let's just convert the addrinfo list into our expanded
604 	 * lws_dns_sort_t list, we can discard the addrinfo list then
605 	 */
606 
607 	while (ai) {
608 #if defined(LWS_WITH_NETLINK) || \
609 	(defined(LWS_WITH_NETLINK) && defined(LWS_WITH_IPV6))
610 		lws_route_t
611 #if defined(LWS_WITH_NETLINK)
612 			*estr = NULL
613 #endif
614 #if defined(LWS_WITH_NETLINK) && defined(LWS_WITH_IPV6)
615 			, *bestsrc = NULL
616 #endif
617 		;
618 #endif
619 		lws_dns_sort_t *ds;
620 		char afip[48];
621 
622 		/*
623 		 * Only transfer address families we can cope with
624 		 */
625 		if ((int)ai->ai_addrlen > (int)sizeof(lws_sockaddr46) ||
626 		    (ai->ai_family != AF_INET && ai->ai_family != AF_INET6))
627 			goto next;
628 
629 		ds = lws_zalloc(sizeof(*ds), __func__);
630 		if (!ds)
631 			return 1;
632 
633 		memcpy(&ds->dest, ai->ai_addr, (size_t)ai->ai_addrlen);
634 		ds->dest.sa4.sin_family = (sa_family_t)ai->ai_family;
635 
636 		lws_sa46_write_numeric_address(&ds->dest, afip, sizeof(afip));
637 
638 		lwsl_wsi_info(wsi, "unsorted entry (af %d) %s",
639 				   ds->dest.sa4.sin_family, afip);
640 
641 #if defined(LWS_WITH_NETLINK)
642 
643 		/*
644 		 * Let's assess this DNS result in terms of route
645 		 * selection, eg, if no usable net route or gateway for it,
646 		 * we don't have a way to use it if we listed it
647 		 */
648 
649 		if (pt->context->routing_table.count) {
650 
651 			estr = _lws_route_est_outgoing(pt, &ds->dest);
652 			if (!estr) {
653 				lws_free(ds);
654 				lwsl_wsi_notice(wsi, "%s has no route out\n",
655 						afip);
656 				/*
657 				 * There's no outbound route for this, it's
658 				 * unusable, so don't add it to the list
659 				 */
660 				goto next;
661 			}
662 
663 			ds->if_idx = estr->if_idx;
664 			ds->uidx = estr->uidx;
665 
666 			/*
667 			 * ...evidently, there's a way for it to go out...
668 			 */
669 		}
670 #endif
671 
672 #if defined(LWS_WITH_NETLINK) && defined(LWS_WITH_IPV6)
673 
674 		/*
675 		 * These sorting rules only apply to ipv6.  If we have ipv4
676 		 * dest and estimate we will use an ipv4 source address to
677 		 * route it, then skip this.
678 		 *
679 		 * However if we have ipv4 dest and estimate we will use an
680 		 * ipv6 source address to route it, because of ipv6-only
681 		 * egress, then promote it to ipv6 and sort it
682 		 */
683 
684 		if (ds->dest.sa4.sin_family == AF_INET) {
685 			if (!estr ||
686 			    estr->dest.sa4.sin_family == AF_INET ||
687 			    estr->gateway.sa4.sin_family == AF_INET)
688 				/*
689 				 * No estimated route, or v4 estimated route,
690 				 * just add it to sorted list
691 				 */
692 				goto just_add;
693 
694 			/*
695 			 * v4 dest on estimated v6 source ads route, because
696 			 * eg, there's no active v4 source ads just ipv6...
697 			 * promote v4 -> v6 address using ::ffff:xx:yy
698 			 */
699 
700 			lwsl_wsi_info(wsi, "promoting v4->v6");
701 
702 			lws_sa46_4to6(&ds->dest,
703 				      (uint8_t *)&ds->dest.sa4.sin_addr, 0);
704 		}
705 
706 		/* first, classify this destination ads */
707 		lws_sort_dns_classify(&ds->dest, &ds->score);
708 
709 		/*
710 		 * RFC6724 Section 5: Source Address Selection
711 		 *
712 		 * Go through the source options choosing the best for this
713 		 * destination... this can only operate on ipv6 destination
714 		 * address
715 		 */
716 
717 		lws_start_foreach_dll(struct lws_dll2 *, d,
718 				      lws_dll2_get_head(&pt->context->routing_table)) {
719 			lws_route_t *r = lws_container_of(d, lws_route_t, list);
720 
721 			/* gateway routes are skipped here */
722 
723 			if (ds->dest.sa6.sin6_family == AF_INET6 &&
724 			    r->dest.sa4.sin_family == AF_INET6 && (!bestsrc ||
725 			    lws_sort_dns_scomp(pt, bestsrc, r, &ds->dest.sa6) ==
726 							    SAS_PREFER_B))
727 				bestsrc = r;
728 
729 		} lws_end_foreach_dll(d);
730 
731 		/* bestsrc is the best source route, or NULL if none */
732 
733 		if (!bestsrc && pt->context->routing_table.count) {
734 			/* drop it, no usable source route */
735 			lws_free(ds);
736 			goto next;
737 		}
738 
739 just_add:
740 		if (!bestsrc) {
741 			lws_dll2_add_tail(&ds->list, &wsi->dns_sorted_list);
742 			goto next;
743 		}
744 
745 		ds->source = bestsrc;
746 
747 		/*
748 		 * RFC6724 Section 6: Destination Address Selection
749 		 *
750 		 * Insert the destination into the list at a position reflecting
751 		 * its preferability, so the head entry is the most preferred
752 		 */
753 
754 		lws_dll2_add_sorted(&ds->list, &wsi->dns_sorted_list,
755 				    lws_sort_dns_compare);
756 #else
757 		/*
758 		 * We don't have the routing table + source address details in
759 		 * order to sort the DNS results... simply make entries in the
760 		 * order of the addrinfo results
761 		 */
762 
763 		lws_dll2_add_tail(&ds->list, &wsi->dns_sorted_list);
764 #endif
765 
766 next:
767 		ai = ai->ai_next;
768 	}
769 
770 	//lwsl_notice("%s: sorted table: %d\n", __func__,
771 	//		wsi->dns_sorted_list.count);
772 
773 #if defined(_DEBUG)
774 	lws_sort_dns_dump(wsi);
775 #endif
776 
777 	return !wsi->dns_sorted_list.count;
778 }
779