| 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> |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 | 86 |
| 87 struct dpc_ctx { | 87 struct dpc_ctx { |
| 88 struct address *addrs; | 88 struct address *addrs; |
| 89 char *canon; | 89 char *canon; |
| 90 int cnt; | 90 int cnt; |
| 91 }; | 91 }; |
| 92 | 92 |
| 93 int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, i
nt, const void *), void *); | 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); | 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); | 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); | 96 int __res_msend_rc(int, const unsigned char *const *, const int *, unsigned char
*const *, int *, int, const struct resolvconf *); |
| 97 | 97 |
| 98 #define RR_A 1 | 98 #define RR_A 1 |
| 99 #define RR_CNAME 5 | 99 #define RR_CNAME 5 |
| 100 #define RR_AAAA 28 | 100 #define RR_AAAA 28 |
| 101 | 101 |
| 102 static int dns_parse_callback(void *c, int rr, const void *data, int len, const
void *packet) | 102 static int dns_parse_callback(void *c, int rr, const void *data, int len, const
void *packet) |
| 103 { | 103 { |
| 104 char tmp[256]; | 104 char tmp[256]; |
| 105 struct dpc_ctx *ctx = c; | 105 struct dpc_ctx *ctx = c; |
| 106 switch (rr) { | 106 switch (rr) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 118 break; | 118 break; |
| 119 case RR_CNAME: | 119 case RR_CNAME: |
| 120 if (__dn_expand(packet, (const unsigned char *)packet + 512, | 120 if (__dn_expand(packet, (const unsigned char *)packet + 512, |
| 121 data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp)) | 121 data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp)) |
| 122 strcpy(ctx->canon, tmp); | 122 strcpy(ctx->canon, tmp); |
| 123 break; | 123 break; |
| 124 } | 124 } |
| 125 return 0; | 125 return 0; |
| 126 } | 126 } |
| 127 | 127 |
| 128 static int name_from_dns(struct address buf[static MAXADDRS], char canon[static
256], const char *name, int family) | 128 static int name_from_dns(struct address buf[static MAXADDRS], char canon[static
256], const char *name, int family, const struct resolvconf *conf) |
| 129 { | 129 { |
| 130 unsigned char qbuf[2][280], abuf[2][512]; | 130 unsigned char qbuf[2][280], abuf[2][512]; |
| 131 const unsigned char *qp[2] = { qbuf[0], qbuf[1] }; | 131 const unsigned char *qp[2] = { qbuf[0], qbuf[1] }; |
| 132 unsigned char *ap[2] = { abuf[0], abuf[1] }; | 132 unsigned char *ap[2] = { abuf[0], abuf[1] }; |
| 133 int qlens[2], alens[2]; | 133 int qlens[2], alens[2]; |
| 134 int i, nq = 0; | 134 int i, nq = 0; |
| 135 struct dpc_ctx ctx = { .addrs = buf, .canon = canon }; | 135 struct dpc_ctx ctx = { .addrs = buf, .canon = canon }; |
| 136 | 136 |
| 137 if (family != AF_INET6) { | 137 if (family != AF_INET6) { |
| 138 qlens[nq] = __res_mkquery(0, name, 1, RR_A, 0, 0, 0, | 138 qlens[nq] = __res_mkquery(0, name, 1, RR_A, 0, 0, 0, |
| 139 qbuf[nq], sizeof *qbuf); | 139 qbuf[nq], sizeof *qbuf); |
| 140 nq++; | 140 nq++; |
| 141 } | 141 } |
| 142 if (family != AF_INET) { | 142 if (family != AF_INET) { |
| 143 qlens[nq] = __res_mkquery(0, name, 1, RR_AAAA, 0, 0, 0, | 143 qlens[nq] = __res_mkquery(0, name, 1, RR_AAAA, 0, 0, 0, |
| 144 qbuf[nq], sizeof *qbuf); | 144 qbuf[nq], sizeof *qbuf); |
| 145 nq++; | 145 nq++; |
| 146 } | 146 } |
| 147 | 147 |
| 148 » if (__res_msend(nq, qp, qlens, ap, alens, sizeof *abuf) < 0) return EAI_
SYSTEM; | 148 » if (__res_msend_rc(nq, qp, qlens, ap, alens, sizeof *abuf, conf) < 0) |
| 149 » » return EAI_SYSTEM; |
| 149 | 150 |
| 150 for (i=0; i<nq; i++) | 151 for (i=0; i<nq; i++) |
| 151 __dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx); | 152 __dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx); |
| 152 | 153 |
| 153 if (ctx.cnt) return ctx.cnt; | 154 if (ctx.cnt) return ctx.cnt; |
| 154 if (alens[0] < 4 || (abuf[0][3] & 15) == 2) return EAI_AGAIN; | 155 if (alens[0] < 4 || (abuf[0][3] & 15) == 2) return EAI_AGAIN; |
| 155 » if ((abuf[0][3] & 15) == 3) return EAI_NONAME; | 156 » if ((abuf[0][3] & 15) == 0) return EAI_NONAME; |
| 157 » if ((abuf[0][3] & 15) == 3) return 0; |
| 156 return EAI_FAIL; | 158 return EAI_FAIL; |
| 157 } | 159 } |
| 158 | 160 |
| 161 static int name_from_dns_search(struct address buf[static MAXADDRS], char canon[
static 256], const char *name, int family) |
| 162 { |
| 163 char search[256]; |
| 164 struct resolvconf conf; |
| 165 size_t l, dots; |
| 166 char *p, *z; |
| 167 |
| 168 if (__get_resolv_conf(&conf, search, sizeof search) < 0) return -1; |
| 169 |
| 170 /* Count dots, suppress search when >=ndots or name ends in |
| 171 * a dot, which is an explicit request for global scope. */ |
| 172 for (dots=l=0; name[l]; l++) if (name[l]=='.') dots++; |
| 173 if (dots >= conf.ndots || name[l-1]=='.') *search = 0; |
| 174 |
| 175 /* This can never happen; the caller already checked length. */ |
| 176 if (l >= 256) return EAI_NONAME; |
| 177 |
| 178 /* Name with search domain appended is setup in canon[]. This both |
| 179 * provides the desired default canonical name (if the requested |
| 180 * name is not a CNAME record) and serves as a buffer for passing |
| 181 * the full requested name to name_from_dns. */ |
| 182 memcpy(canon, name, l); |
| 183 canon[l] = '.'; |
| 184 |
| 185 for (p=search; *p; p=z) { |
| 186 for (; isspace(*p); p++); |
| 187 for (z=p; *z && !isspace(*z); z++); |
| 188 if (z==p) break; |
| 189 if (z-p < 256 - l - 1) { |
| 190 memcpy(canon+l+1, p, z-p); |
| 191 canon[z-p+1+l] = 0; |
| 192 int cnt = name_from_dns(buf, canon, canon, family, &conf
); |
| 193 if (cnt) return cnt; |
| 194 } |
| 195 } |
| 196 |
| 197 canon[l] = 0; |
| 198 return name_from_dns(buf, canon, name, family, &conf); |
| 199 } |
| 200 |
| 159 static const struct policy { | 201 static const struct policy { |
| 160 unsigned char addr[16]; | 202 unsigned char addr[16]; |
| 161 unsigned char len, mask; | 203 unsigned char len, mask; |
| 162 unsigned char prec, label; | 204 unsigned char prec, label; |
| 163 } defpolicy[] = { | 205 } defpolicy[] = { |
| 164 { "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 15, 0xff, 50, 0 }, | 206 { "\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 }, | 207 { "\0\0\0\0\0\0\0\0\0\0\xff\xff", 11, 0xff, 35, 4 }, |
| 166 { "\x20\2", 1, 0xff, 30, 2 }, | 208 { "\x20\2", 1, 0xff, 30, 2 }, |
| 167 { "\x20\1", 3, 0xff, 5, 5 }, | 209 { "\x20\1", 3, 0xff, 5, 5 }, |
| 168 { "\xfc", 0, 0xfe, 3, 13 }, | 210 { "\xfc", 0, 0xfe, 3, 13 }, |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 249 if (flags & AI_V4MAPPED) { | 291 if (flags & AI_V4MAPPED) { |
| 250 if (family == AF_INET6) family = AF_UNSPEC; | 292 if (family == AF_INET6) family = AF_UNSPEC; |
| 251 else flags -= AI_V4MAPPED; | 293 else flags -= AI_V4MAPPED; |
| 252 } | 294 } |
| 253 | 295 |
| 254 /* Try each backend until there's at least one result. */ | 296 /* Try each backend until there's at least one result. */ |
| 255 cnt = name_from_null(buf, name, family, flags); | 297 cnt = name_from_null(buf, name, family, flags); |
| 256 if (!cnt) cnt = name_from_numeric(buf, name, family); | 298 if (!cnt) cnt = name_from_numeric(buf, name, family); |
| 257 if (!cnt && !(flags & AI_NUMERICHOST)) { | 299 if (!cnt && !(flags & AI_NUMERICHOST)) { |
| 258 cnt = name_from_hosts(buf, canon, name, family); | 300 cnt = name_from_hosts(buf, canon, name, family); |
| 259 » » if (!cnt) cnt = name_from_dns(buf, canon, name, family); | 301 » » if (!cnt) cnt = name_from_dns_search(buf, canon, name, family); |
| 260 } | 302 } |
| 261 if (cnt<=0) return cnt ? cnt : EAI_NONAME; | 303 if (cnt<=0) return cnt ? cnt : EAI_NONAME; |
| 262 | 304 |
| 263 /* Filter/transform results for v4-mapped lookup, if requested. */ | 305 /* Filter/transform results for v4-mapped lookup, if requested. */ |
| 264 if (flags & AI_V4MAPPED) { | 306 if (flags & AI_V4MAPPED) { |
| 265 if (!(flags & AI_ALL)) { | 307 if (!(flags & AI_ALL)) { |
| 266 /* If any v6 results exist, remove v4 results. */ | 308 /* If any v6 results exist, remove v4 results. */ |
| 267 for (i=0; i<cnt && buf[i].family != AF_INET6; i++); | 309 for (i=0; i<cnt && buf[i].family != AF_INET6; i++); |
| 268 if (i<cnt) { | 310 if (i<cnt) { |
| 269 for (j=0; i<cnt; i++) { | 311 for (j=0; i<cnt; i++) { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 key |= prefixlen << DAS_PREFIX_SHIFT; | 378 key |= prefixlen << DAS_PREFIX_SHIFT; |
| 337 key |= (MAXADDRS-i) << DAS_ORDER_SHIFT; | 379 key |= (MAXADDRS-i) << DAS_ORDER_SHIFT; |
| 338 buf[i].sortkey = key; | 380 buf[i].sortkey = key; |
| 339 } | 381 } |
| 340 qsort(buf, cnt, sizeof *buf, addrcmp); | 382 qsort(buf, cnt, sizeof *buf, addrcmp); |
| 341 | 383 |
| 342 pthread_setcancelstate(cs, 0); | 384 pthread_setcancelstate(cs, 0); |
| 343 | 385 |
| 344 return cnt; | 386 return cnt; |
| 345 } | 387 } |
| OLD | NEW |