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