| 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 |