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