OLD | NEW |
1 #include <sys/socket.h> | 1 #include <sys/socket.h> |
2 #include <netinet/in.h> | 2 #include <netinet/in.h> |
3 #include <netdb.h> | 3 #include <netdb.h> |
4 #include <net/if.h> | 4 #include <net/if.h> |
5 #include <arpa/inet.h> | 5 #include <arpa/inet.h> |
6 #include <ctype.h> | 6 #include <ctype.h> |
7 #include <stdlib.h> | 7 #include <stdlib.h> |
8 #include <string.h> | 8 #include <string.h> |
9 #include <fcntl.h> | 9 #include <fcntl.h> |
10 #include <unistd.h> | 10 #include <unistd.h> |
11 #include <pthread.h> | 11 #include <pthread.h> |
12 #include <errno.h> | 12 #include <errno.h> |
13 #include "lookup.h" | 13 #include "lookup.h" |
14 #include "stdio_impl.h" | 14 #include "stdio_impl.h" |
15 #include "syscall.h" | 15 #include "syscall.h" |
16 | 16 |
17 static int is_valid_hostname(const char *host) | 17 static int is_valid_hostname(const char* host) { |
18 { | 18 const unsigned char* s; |
19 » const unsigned char *s; | 19 if (strnlen(host, 255) - 1 >= 254 || mbstowcs(0, host, 0) == -1) |
20 » if (strnlen(host, 255)-1 >= 254 || mbstowcs(0, host, 0) == -1) return 0; | 20 return 0; |
21 » for (s=(void *)host; *s>=0x80 || *s=='.' || *s=='-' || isalnum(*s); s++)
; | 21 for (s = (void*)host; *s >= 0x80 || *s == '.' || *s == '-' || isalnum(*s); |
22 » return !*s; | 22 s++) |
23 } | 23 ; |
24 | 24 return !*s; |
25 static int name_from_null(struct address buf[static 2], const char *name, int fa
mily, int flags) | 25 } |
26 { | 26 |
27 » int cnt = 0; | 27 static int name_from_null(struct address buf[static 2], |
28 » if (name) return 0; | 28 const char* name, |
29 » if (flags & AI_PASSIVE) { | 29 int family, |
30 » » if (family != AF_INET6) | 30 int flags) { |
31 » » » buf[cnt++] = (struct address){ .family = AF_INET }; | 31 int cnt = 0; |
32 » » if (family != AF_INET) | 32 if (name) |
33 » » » buf[cnt++] = (struct address){ .family = AF_INET6 }; | 33 return 0; |
34 » } else { | 34 if (flags & AI_PASSIVE) { |
35 » » if (family != AF_INET6) | 35 if (family != AF_INET6) |
36 » » » buf[cnt++] = (struct address){ .family = AF_INET, .addr
= { 127,0,0,1 } }; | 36 buf[cnt++] = (struct address){.family = AF_INET}; |
37 » » if (family != AF_INET) | 37 if (family != AF_INET) |
38 » » » buf[cnt++] = (struct address){ .family = AF_INET6, .addr
= { [15] = 1 } }; | 38 buf[cnt++] = (struct address){.family = AF_INET6}; |
39 » } | 39 } else { |
40 » return cnt; | 40 if (family != AF_INET6) |
41 } | 41 buf[cnt++] = (struct address){.family = AF_INET, .addr = {127, 0, 0, 1}}; |
42 | 42 if (family != AF_INET) |
43 static int name_from_numeric(struct address buf[static 1], const char *name, int
family) | 43 buf[cnt++] = (struct address){.family = AF_INET6, .addr = {[15] = 1}}; |
44 { | 44 } |
45 » return __lookup_ipliteral(buf, name, family); | 45 return cnt; |
46 } | 46 } |
47 | 47 |
48 static int name_from_hosts(struct address buf[static MAXADDRS], char canon[stati
c 256], const char *name, int family) | 48 static int name_from_numeric(struct address buf[static 1], |
49 { | 49 const char* name, |
50 » char line[512]; | 50 int family) { |
51 » size_t l = strlen(name); | 51 return __lookup_ipliteral(buf, name, family); |
52 » int cnt = 0; | 52 } |
53 » unsigned char _buf[1032]; | 53 |
54 » FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf); | 54 static int name_from_hosts(struct address buf[static MAXADDRS], |
55 » if (!f) switch (errno) { | 55 char canon[static 256], |
56 » case ENOENT: | 56 const char* name, |
57 » case ENOTDIR: | 57 int family) { |
58 » case EACCES: | 58 char line[512]; |
59 » » return 0; | 59 size_t l = strlen(name); |
60 » default: | 60 int cnt = 0; |
61 » » return EAI_SYSTEM; | 61 unsigned char _buf[1032]; |
62 » } | 62 FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf); |
63 » while (fgets(line, sizeof line, f) && cnt < MAXADDRS) { | 63 if (!f) |
64 » » char *p, *z; | 64 switch (errno) { |
65 | 65 case ENOENT: |
66 » » if ((p=strchr(line, '#'))) *p++='\n', *p=0; | 66 case ENOTDIR: |
67 » » for(p=line+1; (p=strstr(p, name)) && | 67 case EACCES: |
68 » » » (!isspace(p[-1]) || !isspace(p[l])); p++); | 68 return 0; |
69 » » if (!p) continue; | 69 default: |
70 | 70 return EAI_SYSTEM; |
71 » » /* Isolate IP address to parse */ | 71 } |
72 » » for (p=line; *p && !isspace(*p); p++); | 72 while (fgets(line, sizeof line, f) && cnt < MAXADDRS) { |
73 » » *p++ = 0; | 73 char *p, *z; |
74 » » if (name_from_numeric(buf+cnt, line, family)) | 74 |
75 » » » cnt++; | 75 if ((p = strchr(line, '#'))) |
76 | 76 *p++ = '\n', *p = 0; |
77 » » /* Extract first name as canonical name */ | 77 for (p = line + 1; |
78 » » for (; *p && isspace(*p); p++); | 78 (p = strstr(p, name)) && (!isspace(p[-1]) || !isspace(p[l])); p++) |
79 » » for (z=p; *z && !isspace(*z); z++); | 79 ; |
80 » » *z = 0; | 80 if (!p) |
81 » » if (is_valid_hostname(p)) memcpy(canon, p, z-p+1); | 81 continue; |
82 » } | 82 |
83 » __fclose_ca(f); | 83 /* Isolate IP address to parse */ |
84 » return cnt; | 84 for (p = line; *p && !isspace(*p); p++) |
| 85 ; |
| 86 *p++ = 0; |
| 87 if (name_from_numeric(buf + cnt, line, family)) |
| 88 cnt++; |
| 89 |
| 90 /* Extract first name as canonical name */ |
| 91 for (; *p && isspace(*p); p++) |
| 92 ; |
| 93 for (z = p; *z && !isspace(*z); z++) |
| 94 ; |
| 95 *z = 0; |
| 96 if (is_valid_hostname(p)) |
| 97 memcpy(canon, p, z - p + 1); |
| 98 } |
| 99 __fclose_ca(f); |
| 100 return cnt; |
85 } | 101 } |
86 | 102 |
87 struct dpc_ctx { | 103 struct dpc_ctx { |
88 » struct address *addrs; | 104 struct address* addrs; |
89 » char *canon; | 105 char* canon; |
90 » int cnt; | 106 int cnt; |
91 }; | 107 }; |
92 | 108 |
93 int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, i
nt, const void *), void *); | 109 int __dns_parse(const unsigned char*, |
94 int __dn_expand(const unsigned char *, const unsigned char *, const unsigned cha
r *, char *, int); | 110 int, |
95 int __res_mkquery(int, const char *, int, int, const unsigned char *, int, const
unsigned char*, unsigned char *, int); | 111 int (*)(void*, int, const void*, int, const void*), |
96 int __res_msend_rc(int, const unsigned char *const *, const int *, unsigned char
*const *, int *, int, const struct resolvconf *); | 112 void*); |
| 113 int __dn_expand(const unsigned char*, |
| 114 const unsigned char*, |
| 115 const unsigned char*, |
| 116 char*, |
| 117 int); |
| 118 int __res_mkquery(int, |
| 119 const char*, |
| 120 int, |
| 121 int, |
| 122 const unsigned char*, |
| 123 int, |
| 124 const unsigned char*, |
| 125 unsigned char*, |
| 126 int); |
| 127 int __res_msend_rc(int, |
| 128 const unsigned char* const*, |
| 129 const int*, |
| 130 unsigned char* const*, |
| 131 int*, |
| 132 int, |
| 133 const struct resolvconf*); |
97 | 134 |
98 #define RR_A 1 | 135 #define RR_A 1 |
99 #define RR_CNAME 5 | 136 #define RR_CNAME 5 |
100 #define RR_AAAA 28 | 137 #define RR_AAAA 28 |
101 | 138 |
102 static int dns_parse_callback(void *c, int rr, const void *data, int len, const
void *packet) | 139 static int dns_parse_callback(void* c, |
103 { | 140 int rr, |
104 » char tmp[256]; | 141 const void* data, |
105 » struct dpc_ctx *ctx = c; | 142 int len, |
106 » switch (rr) { | 143 const void* packet) { |
107 » case RR_A: | 144 char tmp[256]; |
108 » » if (len != 4) return -1; | 145 struct dpc_ctx* ctx = c; |
109 » » ctx->addrs[ctx->cnt].family = AF_INET; | 146 switch (rr) { |
110 » » ctx->addrs[ctx->cnt].scopeid = 0; | 147 case RR_A: |
111 » » memcpy(ctx->addrs[ctx->cnt++].addr, data, 4); | 148 if (len != 4) |
112 » » break; | 149 return -1; |
113 » case RR_AAAA: | 150 ctx->addrs[ctx->cnt].family = AF_INET; |
114 » » if (len != 16) return -1; | 151 ctx->addrs[ctx->cnt].scopeid = 0; |
115 » » ctx->addrs[ctx->cnt].family = AF_INET6; | 152 memcpy(ctx->addrs[ctx->cnt++].addr, data, 4); |
116 » » ctx->addrs[ctx->cnt].scopeid = 0; | 153 break; |
117 » » memcpy(ctx->addrs[ctx->cnt++].addr, data, 16); | 154 case RR_AAAA: |
118 » » break; | 155 if (len != 16) |
119 » case RR_CNAME: | 156 return -1; |
120 » » if (__dn_expand(packet, (const unsigned char *)packet + 512, | 157 ctx->addrs[ctx->cnt].family = AF_INET6; |
121 » » data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp)) | 158 ctx->addrs[ctx->cnt].scopeid = 0; |
122 » » » strcpy(ctx->canon, tmp); | 159 memcpy(ctx->addrs[ctx->cnt++].addr, data, 16); |
123 » » break; | 160 break; |
124 » } | 161 case RR_CNAME: |
125 » return 0; | 162 if (__dn_expand(packet, (const unsigned char*)packet + 512, data, tmp, |
126 } | 163 sizeof tmp) > 0 && |
127 | 164 is_valid_hostname(tmp)) |
128 static int name_from_dns(struct address buf[static MAXADDRS], char canon[static
256], const char *name, int family, const struct resolvconf *conf) | 165 strcpy(ctx->canon, tmp); |
129 { | 166 break; |
130 » unsigned char qbuf[2][280], abuf[2][512]; | 167 } |
131 » const unsigned char *qp[2] = { qbuf[0], qbuf[1] }; | 168 return 0; |
132 » unsigned char *ap[2] = { abuf[0], abuf[1] }; | 169 } |
133 » int qlens[2], alens[2]; | 170 |
134 » int i, nq = 0; | 171 static int name_from_dns(struct address buf[static MAXADDRS], |
135 » struct dpc_ctx ctx = { .addrs = buf, .canon = canon }; | 172 char canon[static 256], |
136 | 173 const char* name, |
137 » if (family != AF_INET6) { | 174 int family, |
138 » » qlens[nq] = __res_mkquery(0, name, 1, RR_A, 0, 0, 0, | 175 const struct resolvconf* conf) { |
139 » » » qbuf[nq], sizeof *qbuf); | 176 unsigned char qbuf[2][280], abuf[2][512]; |
140 » » nq++; | 177 const unsigned char* qp[2] = {qbuf[0], qbuf[1]}; |
141 » } | 178 unsigned char* ap[2] = {abuf[0], abuf[1]}; |
142 » if (family != AF_INET) { | 179 int qlens[2], alens[2]; |
143 » » qlens[nq] = __res_mkquery(0, name, 1, RR_AAAA, 0, 0, 0, | 180 int i, nq = 0; |
144 » » » qbuf[nq], sizeof *qbuf); | 181 struct dpc_ctx ctx = {.addrs = buf, .canon = canon}; |
145 » » nq++; | 182 |
146 » } | 183 if (family != AF_INET6) { |
147 | 184 qlens[nq] = |
148 » if (__res_msend_rc(nq, qp, qlens, ap, alens, sizeof *abuf, conf) < 0) | 185 __res_mkquery(0, name, 1, RR_A, 0, 0, 0, qbuf[nq], sizeof *qbuf); |
149 » » return EAI_SYSTEM; | 186 nq++; |
150 | 187 } |
151 » for (i=0; i<nq; i++) | 188 if (family != AF_INET) { |
152 » » __dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx); | 189 qlens[nq] = |
153 | 190 __res_mkquery(0, name, 1, RR_AAAA, 0, 0, 0, qbuf[nq], sizeof *qbuf); |
154 » if (ctx.cnt) return ctx.cnt; | 191 nq++; |
155 » if (alens[0] < 4 || (abuf[0][3] & 15) == 2) return EAI_AGAIN; | 192 } |
156 » if ((abuf[0][3] & 15) == 0) return EAI_NONAME; | 193 |
157 » if ((abuf[0][3] & 15) == 3) return 0; | 194 if (__res_msend_rc(nq, qp, qlens, ap, alens, sizeof *abuf, conf) < 0) |
158 » return EAI_FAIL; | 195 return EAI_SYSTEM; |
159 } | 196 |
160 | 197 for (i = 0; i < nq; i++) |
161 static int name_from_dns_search(struct address buf[static MAXADDRS], char canon[
static 256], const char *name, int family) | 198 __dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx); |
162 { | 199 |
163 » char search[256]; | 200 if (ctx.cnt) |
164 » struct resolvconf conf; | 201 return ctx.cnt; |
165 » size_t l, dots; | 202 if (alens[0] < 4 || (abuf[0][3] & 15) == 2) |
166 » char *p, *z; | 203 return EAI_AGAIN; |
167 | 204 if ((abuf[0][3] & 15) == 0) |
168 » if (__get_resolv_conf(&conf, search, sizeof search) < 0) return -1; | 205 return EAI_NONAME; |
169 | 206 if ((abuf[0][3] & 15) == 3) |
170 » /* Count dots, suppress search when >=ndots or name ends in | 207 return 0; |
171 » * a dot, which is an explicit request for global scope. */ | 208 return EAI_FAIL; |
172 » for (dots=l=0; name[l]; l++) if (name[l]=='.') dots++; | 209 } |
173 » if (dots >= conf.ndots || name[l-1]=='.') *search = 0; | 210 |
174 | 211 static int name_from_dns_search(struct address buf[static MAXADDRS], |
175 » /* This can never happen; the caller already checked length. */ | 212 char canon[static 256], |
176 » if (l >= 256) return EAI_NONAME; | 213 const char* name, |
177 | 214 int family) { |
178 » /* Name with search domain appended is setup in canon[]. This both | 215 char search[256]; |
179 » * provides the desired default canonical name (if the requested | 216 struct resolvconf conf; |
180 » * name is not a CNAME record) and serves as a buffer for passing | 217 size_t l, dots; |
181 » * the full requested name to name_from_dns. */ | 218 char *p, *z; |
182 » memcpy(canon, name, l); | 219 |
183 » canon[l] = '.'; | 220 if (__get_resolv_conf(&conf, search, sizeof search) < 0) |
184 | 221 return -1; |
185 » for (p=search; *p; p=z) { | 222 |
186 » » for (; isspace(*p); p++); | 223 /* Count dots, suppress search when >=ndots or name ends in |
187 » » for (z=p; *z && !isspace(*z); z++); | 224 * a dot, which is an explicit request for global scope. */ |
188 » » if (z==p) break; | 225 for (dots = l = 0; name[l]; l++) |
189 » » if (z-p < 256 - l - 1) { | 226 if (name[l] == '.') |
190 » » » memcpy(canon+l+1, p, z-p); | 227 dots++; |
191 » » » canon[z-p+1+l] = 0; | 228 if (dots >= conf.ndots || name[l - 1] == '.') |
192 » » » int cnt = name_from_dns(buf, canon, canon, family, &conf
); | 229 *search = 0; |
193 » » » if (cnt) return cnt; | 230 |
194 » » } | 231 /* This can never happen; the caller already checked length. */ |
195 » } | 232 if (l >= 256) |
196 | 233 return EAI_NONAME; |
197 » canon[l] = 0; | 234 |
198 » return name_from_dns(buf, canon, name, family, &conf); | 235 /* Name with search domain appended is setup in canon[]. This both |
| 236 * provides the desired default canonical name (if the requested |
| 237 * name is not a CNAME record) and serves as a buffer for passing |
| 238 * the full requested name to name_from_dns. */ |
| 239 memcpy(canon, name, l); |
| 240 canon[l] = '.'; |
| 241 |
| 242 for (p = search; *p; p = z) { |
| 243 for (; isspace(*p); p++) |
| 244 ; |
| 245 for (z = p; *z && !isspace(*z); z++) |
| 246 ; |
| 247 if (z == p) |
| 248 break; |
| 249 if (z - p < 256 - l - 1) { |
| 250 memcpy(canon + l + 1, p, z - p); |
| 251 canon[z - p + 1 + l] = 0; |
| 252 int cnt = name_from_dns(buf, canon, canon, family, &conf); |
| 253 if (cnt) |
| 254 return cnt; |
| 255 } |
| 256 } |
| 257 |
| 258 canon[l] = 0; |
| 259 return name_from_dns(buf, canon, name, family, &conf); |
199 } | 260 } |
200 | 261 |
201 static const struct policy { | 262 static const struct policy { |
202 » unsigned char addr[16]; | 263 unsigned char addr[16]; |
203 » unsigned char len, mask; | 264 unsigned char len, mask; |
204 » unsigned char prec, label; | 265 unsigned char prec, label; |
205 } defpolicy[] = { | 266 } defpolicy[] = { |
206 » { "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 15, 0xff, 50, 0 }, | 267 {"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 15, 0xff, 50, 0}, |
207 » { "\0\0\0\0\0\0\0\0\0\0\xff\xff", 11, 0xff, 35, 4 }, | 268 {"\0\0\0\0\0\0\0\0\0\0\xff\xff", 11, 0xff, 35, 4}, |
208 » { "\x20\2", 1, 0xff, 30, 2 }, | 269 {"\x20\2", 1, 0xff, 30, 2}, |
209 » { "\x20\1", 3, 0xff, 5, 5 }, | 270 {"\x20\1", 3, 0xff, 5, 5}, |
210 » { "\xfc", 0, 0xfe, 3, 13 }, | 271 {"\xfc", 0, 0xfe, 3, 13}, |
211 #if 0 | 272 #if 0 |
212 /* These are deprecated and/or returned to the address | 273 /* These are deprecated and/or returned to the address |
213 * pool, so despite the RFC, treating them as special | 274 * pool, so despite the RFC, treating them as special |
214 * is probably wrong. */ | 275 * is probably wrong. */ |
215 { "", 11, 0xff, 1, 3 }, | 276 { "", 11, 0xff, 1, 3 }, |
216 { "\xfe\xc0", 1, 0xc0, 1, 11 }, | 277 { "\xfe\xc0", 1, 0xc0, 1, 11 }, |
217 { "\x3f\xfe", 1, 0xff, 1, 12 }, | 278 { "\x3f\xfe", 1, 0xff, 1, 12 }, |
218 #endif | 279 #endif |
219 » /* Last rule must match all addresses to stop loop. */ | 280 /* Last rule must match all addresses to stop loop. */ |
220 » { "", 0, 0, 40, 1 }, | 281 {"", 0, 0, 40, 1}, |
221 }; | 282 }; |
222 | 283 |
223 static const struct policy *policyof(const struct in6_addr *a) | 284 static const struct policy* policyof(const struct in6_addr* a) { |
224 { | 285 int i; |
225 » int i; | 286 for (i = 0;; i++) { |
226 » for (i=0; ; i++) { | 287 if (memcmp(a->s6_addr, defpolicy[i].addr, defpolicy[i].len)) |
227 » » if (memcmp(a->s6_addr, defpolicy[i].addr, defpolicy[i].len)) | 288 continue; |
228 » » » continue; | 289 if ((a->s6_addr[defpolicy[i].len] & defpolicy[i].mask) != |
229 » » if ((a->s6_addr[defpolicy[i].len] & defpolicy[i].mask) | 290 defpolicy[i].addr[defpolicy[i].len]) |
230 » » != defpolicy[i].addr[defpolicy[i].len]) | 291 continue; |
231 » » » continue; | 292 return defpolicy + i; |
232 » » return defpolicy+i; | 293 } |
233 » } | |
234 } | 294 } |
235 | 295 |
236 static int labelof(const struct in6_addr *a) | 296 static int labelof(const struct in6_addr* a) { |
237 { | 297 return policyof(a)->label; |
238 » return policyof(a)->label; | |
239 } | 298 } |
240 | 299 |
241 static int scopeof(const struct in6_addr *a) | 300 static int scopeof(const struct in6_addr* a) { |
242 { | 301 if (IN6_IS_ADDR_MULTICAST(a)) |
243 » if (IN6_IS_ADDR_MULTICAST(a)) return a->s6_addr[1] & 15; | 302 return a->s6_addr[1] & 15; |
244 » if (IN6_IS_ADDR_LINKLOCAL(a)) return 2; | 303 if (IN6_IS_ADDR_LINKLOCAL(a)) |
245 » if (IN6_IS_ADDR_LOOPBACK(a)) return 2; | 304 return 2; |
246 » if (IN6_IS_ADDR_SITELOCAL(a)) return 5; | 305 if (IN6_IS_ADDR_LOOPBACK(a)) |
247 » return 14; | 306 return 2; |
| 307 if (IN6_IS_ADDR_SITELOCAL(a)) |
| 308 return 5; |
| 309 return 14; |
248 } | 310 } |
249 | 311 |
250 static int prefixmatch(const struct in6_addr *s, const struct in6_addr *d) | 312 static int prefixmatch(const struct in6_addr* s, const struct in6_addr* d) { |
251 { | 313 /* FIXME: The common prefix length should be limited to no greater |
252 » /* FIXME: The common prefix length should be limited to no greater | 314 * than the nominal length of the prefix portion of the source |
253 » * than the nominal length of the prefix portion of the source | 315 * address. However the definition of the source prefix length is |
254 » * address. However the definition of the source prefix length is | 316 * not clear and thus this limiting is not yet implemented. */ |
255 » * not clear and thus this limiting is not yet implemented. */ | 317 unsigned i; |
256 » unsigned i; | 318 for (i = 0; |
257 » for (i=0; i<128 && !((s->s6_addr[i/8]^d->s6_addr[i/8])&(128>>(i%8))); i+
+); | 319 i < 128 && !((s->s6_addr[i / 8] ^ d->s6_addr[i / 8]) & (128 >> (i % 8))); |
258 » return i; | 320 i++) |
| 321 ; |
| 322 return i; |
259 } | 323 } |
260 | 324 |
261 #define DAS_USABLE 0x40000000 | 325 #define DAS_USABLE 0x40000000 |
262 #define DAS_MATCHINGSCOPE 0x20000000 | 326 #define DAS_MATCHINGSCOPE 0x20000000 |
263 #define DAS_MATCHINGLABEL 0x10000000 | 327 #define DAS_MATCHINGLABEL 0x10000000 |
264 #define DAS_PREC_SHIFT 20 | 328 #define DAS_PREC_SHIFT 20 |
265 #define DAS_SCOPE_SHIFT 16 | 329 #define DAS_SCOPE_SHIFT 16 |
266 #define DAS_PREFIX_SHIFT 8 | 330 #define DAS_PREFIX_SHIFT 8 |
267 #define DAS_ORDER_SHIFT 0 | 331 #define DAS_ORDER_SHIFT 0 |
268 | 332 |
269 static int addrcmp(const void *_a, const void *_b) | 333 static int addrcmp(const void* _a, const void* _b) { |
270 { | 334 const struct address *a = _a, *b = _b; |
271 » const struct address *a = _a, *b = _b; | 335 return b->sortkey - a->sortkey; |
272 » return b->sortkey - a->sortkey; | |
273 } | 336 } |
274 | 337 |
275 int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], c
onst char *name, int family, int flags) | 338 int __lookup_name(struct address buf[static MAXADDRS], |
276 { | 339 char canon[static 256], |
277 » int cnt = 0, i, j; | 340 const char* name, |
| 341 int family, |
| 342 int flags) { |
| 343 int cnt = 0, i, j; |
278 | 344 |
279 » *canon = 0; | 345 *canon = 0; |
280 » if (name) { | 346 if (name) { |
281 » » /* reject empty name and check len so it fits into temp bufs */ | 347 /* reject empty name and check len so it fits into temp bufs */ |
282 » » size_t l = strnlen(name, 255); | 348 size_t l = strnlen(name, 255); |
283 » » if (l-1 >= 254) | 349 if (l - 1 >= 254) |
284 » » » return EAI_NONAME; | 350 return EAI_NONAME; |
285 » » memcpy(canon, name, l+1); | 351 memcpy(canon, name, l + 1); |
286 » } | 352 } |
287 | 353 |
288 » /* Procedurally, a request for v6 addresses with the v4-mapped | 354 /* Procedurally, a request for v6 addresses with the v4-mapped |
289 » * flag set is like a request for unspecified family, followed | 355 * flag set is like a request for unspecified family, followed |
290 » * by filtering of the results. */ | 356 * by filtering of the results. */ |
291 » if (flags & AI_V4MAPPED) { | 357 if (flags & AI_V4MAPPED) { |
292 » » if (family == AF_INET6) family = AF_UNSPEC; | 358 if (family == AF_INET6) |
293 » » else flags -= AI_V4MAPPED; | 359 family = AF_UNSPEC; |
294 » } | 360 else |
| 361 flags -= AI_V4MAPPED; |
| 362 } |
295 | 363 |
296 » /* Try each backend until there's at least one result. */ | 364 /* Try each backend until there's at least one result. */ |
297 » cnt = name_from_null(buf, name, family, flags); | 365 cnt = name_from_null(buf, name, family, flags); |
298 » if (!cnt) cnt = name_from_numeric(buf, name, family); | 366 if (!cnt) |
299 » if (!cnt && !(flags & AI_NUMERICHOST)) { | 367 cnt = name_from_numeric(buf, name, family); |
300 » » cnt = name_from_hosts(buf, canon, name, family); | 368 if (!cnt && !(flags & AI_NUMERICHOST)) { |
301 » » if (!cnt) cnt = name_from_dns_search(buf, canon, name, family); | 369 cnt = name_from_hosts(buf, canon, name, family); |
302 » } | 370 if (!cnt) |
303 » if (cnt<=0) return cnt ? cnt : EAI_NONAME; | 371 cnt = name_from_dns_search(buf, canon, name, family); |
| 372 } |
| 373 if (cnt <= 0) |
| 374 return cnt ? cnt : EAI_NONAME; |
304 | 375 |
305 » /* Filter/transform results for v4-mapped lookup, if requested. */ | 376 /* Filter/transform results for v4-mapped lookup, if requested. */ |
306 » if (flags & AI_V4MAPPED) { | 377 if (flags & AI_V4MAPPED) { |
307 » » if (!(flags & AI_ALL)) { | 378 if (!(flags & AI_ALL)) { |
308 » » » /* If any v6 results exist, remove v4 results. */ | 379 /* If any v6 results exist, remove v4 results. */ |
309 » » » for (i=0; i<cnt && buf[i].family != AF_INET6; i++); | 380 for (i = 0; i < cnt && buf[i].family != AF_INET6; i++) |
310 » » » if (i<cnt) { | 381 ; |
311 » » » » for (j=0; i<cnt; i++) { | 382 if (i < cnt) { |
312 » » » » » if (buf[i].family == AF_INET6) | 383 for (j = 0; i < cnt; i++) { |
313 » » » » » » buf[j++] = buf[i]; | 384 if (buf[i].family == AF_INET6) |
314 » » » » } | 385 buf[j++] = buf[i]; |
315 » » » » cnt = i = j; | 386 } |
316 » » » } | 387 cnt = i = j; |
317 » » } | 388 } |
318 » » /* Translate any remaining v4 results to v6 */ | 389 } |
319 » » for (i=0; i<cnt; i++) { | 390 /* Translate any remaining v4 results to v6 */ |
320 » » » if (buf[i].family != AF_INET) continue; | 391 for (i = 0; i < cnt; i++) { |
321 » » » memcpy(buf[i].addr+12, buf[i].addr, 4); | 392 if (buf[i].family != AF_INET) |
322 » » » memcpy(buf[i].addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); | 393 continue; |
323 » » » buf[i].family = AF_INET6; | 394 memcpy(buf[i].addr + 12, buf[i].addr, 4); |
324 » » } | 395 memcpy(buf[i].addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); |
325 » } | 396 buf[i].family = AF_INET6; |
| 397 } |
| 398 } |
326 | 399 |
327 » /* No further processing is needed if there are fewer than 2 | 400 /* No further processing is needed if there are fewer than 2 |
328 » * results or if there are only IPv4 results. */ | 401 * results or if there are only IPv4 results. */ |
329 » if (cnt<2 || family==AF_INET) return cnt; | 402 if (cnt < 2 || family == AF_INET) |
330 » for (i=0; buf[i].family == AF_INET; i++) | 403 return cnt; |
331 » » if (i==cnt) return cnt; | 404 for (i = 0; buf[i].family == AF_INET; i++) |
| 405 if (i == cnt) |
| 406 return cnt; |
332 | 407 |
333 » int cs; | 408 int cs; |
334 » pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); | 409 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); |
335 | 410 |
336 » /* The following implements a subset of RFC 3484/6724 destination | 411 /* The following implements a subset of RFC 3484/6724 destination |
337 » * address selection by generating a single 31-bit sort key for | 412 * address selection by generating a single 31-bit sort key for |
338 » * each address. Rules 3, 4, and 7 are omitted for having | 413 * each address. Rules 3, 4, and 7 are omitted for having |
339 » * excessive runtime and code size cost and dubious benefit. | 414 * excessive runtime and code size cost and dubious benefit. |
340 » * So far the label/precedence table cannot be customized. */ | 415 * So far the label/precedence table cannot be customized. */ |
341 » for (i=0; i<cnt; i++) { | 416 for (i = 0; i < cnt; i++) { |
342 » » int key = 0; | 417 int key = 0; |
343 » » struct sockaddr_in6 sa, da = { | 418 struct sockaddr_in6 sa, da = {.sin6_family = AF_INET6, |
344 » » » .sin6_family = AF_INET6, | 419 .sin6_scope_id = buf[i].scopeid, |
345 » » » .sin6_scope_id = buf[i].scopeid, | 420 .sin6_port = 65535}; |
346 » » » .sin6_port = 65535 | 421 if (buf[i].family == AF_INET6) { |
347 » » }; | 422 memcpy(da.sin6_addr.s6_addr, buf[i].addr, 16); |
348 » » if (buf[i].family == AF_INET6) { | 423 } else { |
349 » » » memcpy(da.sin6_addr.s6_addr, buf[i].addr, 16); | 424 memcpy(da.sin6_addr.s6_addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); |
350 » » } else { | 425 memcpy(da.sin6_addr.s6_addr + 12, buf[i].addr, 4); |
351 » » » memcpy(da.sin6_addr.s6_addr, | 426 } |
352 » » » » "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); | 427 const struct policy* dpolicy = policyof(&da.sin6_addr); |
353 » » » memcpy(da.sin6_addr.s6_addr+12, buf[i].addr, 4); | 428 int dscope = scopeof(&da.sin6_addr); |
354 » » } | 429 int dlabel = dpolicy->label; |
355 » » const struct policy *dpolicy = policyof(&da.sin6_addr); | 430 int dprec = dpolicy->prec; |
356 » » int dscope = scopeof(&da.sin6_addr); | 431 int prefixlen = 0; |
357 » » int dlabel = dpolicy->label; | 432 int fd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP); |
358 » » int dprec = dpolicy->prec; | 433 if (fd >= 0) { |
359 » » int prefixlen = 0; | 434 if (!connect(fd, (void*)&da, sizeof da)) { |
360 » » int fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_UDP); | 435 key |= DAS_USABLE; |
361 » » if (fd >= 0) { | 436 if (!getsockname(fd, (void*)&sa, &(socklen_t){sizeof sa})) { |
362 » » » if (!connect(fd, (void *)&da, sizeof da)) { | 437 if (dscope == scopeof(&sa.sin6_addr)) |
363 » » » » key |= DAS_USABLE; | 438 key |= DAS_MATCHINGSCOPE; |
364 » » » » if (!getsockname(fd, (void *)&sa, | 439 if (dlabel == labelof(&sa.sin6_addr)) |
365 » » » » &(socklen_t){sizeof sa})) { | 440 key |= DAS_MATCHINGLABEL; |
366 » » » » » if (dscope == scopeof(&sa.sin6_addr)) | 441 prefixlen = prefixmatch(&sa.sin6_addr, &da.sin6_addr); |
367 » » » » » » key |= DAS_MATCHINGSCOPE; | 442 } |
368 » » » » » if (dlabel == labelof(&sa.sin6_addr)) | 443 } |
369 » » » » » » key |= DAS_MATCHINGLABEL; | 444 close(fd); |
370 » » » » » prefixlen = prefixmatch(&sa.sin6_addr, | 445 } |
371 » » » » » » &da.sin6_addr); | 446 key |= dprec << DAS_PREC_SHIFT; |
372 » » » » } | 447 key |= (15 - dscope) << DAS_SCOPE_SHIFT; |
373 » » » } | 448 key |= prefixlen << DAS_PREFIX_SHIFT; |
374 » » » close(fd); | 449 key |= (MAXADDRS - i) << DAS_ORDER_SHIFT; |
375 » » } | 450 buf[i].sortkey = key; |
376 » » key |= dprec << DAS_PREC_SHIFT; | 451 } |
377 » » key |= (15-dscope) << DAS_SCOPE_SHIFT; | 452 qsort(buf, cnt, sizeof *buf, addrcmp); |
378 » » key |= prefixlen << DAS_PREFIX_SHIFT; | |
379 » » key |= (MAXADDRS-i) << DAS_ORDER_SHIFT; | |
380 » » buf[i].sortkey = key; | |
381 » } | |
382 » qsort(buf, cnt, sizeof *buf, addrcmp); | |
383 | 453 |
384 » pthread_setcancelstate(cs, 0); | 454 pthread_setcancelstate(cs, 0); |
385 | 455 |
386 » return cnt; | 456 return cnt; |
387 } | 457 } |
OLD | NEW |