Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1201)

Unified Diff: fusl/src/network/lookup_name.c

Issue 1714623002: [fusl] clang-format fusl (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: headers too Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: fusl/src/network/lookup_name.c
diff --git a/fusl/src/network/lookup_name.c b/fusl/src/network/lookup_name.c
index a26ad535143e7651807c5d153fb4c1fab4ea5a73..b1f2487160eac328adddb37f1f2a672a4efadcb8 100644
--- a/fusl/src/network/lookup_name.c
+++ b/fusl/src/network/lookup_name.c
@@ -14,200 +14,261 @@
#include "stdio_impl.h"
#include "syscall.h"
-static int is_valid_hostname(const char *host)
-{
- const unsigned char *s;
- if (strnlen(host, 255)-1 >= 254 || mbstowcs(0, host, 0) == -1) return 0;
- for (s=(void *)host; *s>=0x80 || *s=='.' || *s=='-' || isalnum(*s); s++);
- return !*s;
+static int is_valid_hostname(const char* host) {
+ const unsigned char* s;
+ if (strnlen(host, 255) - 1 >= 254 || mbstowcs(0, host, 0) == -1)
+ return 0;
+ for (s = (void*)host; *s >= 0x80 || *s == '.' || *s == '-' || isalnum(*s);
+ s++)
+ ;
+ return !*s;
}
-static int name_from_null(struct address buf[static 2], const char *name, int family, int flags)
-{
- int cnt = 0;
- if (name) return 0;
- if (flags & AI_PASSIVE) {
- if (family != AF_INET6)
- buf[cnt++] = (struct address){ .family = AF_INET };
- if (family != AF_INET)
- buf[cnt++] = (struct address){ .family = AF_INET6 };
- } else {
- if (family != AF_INET6)
- buf[cnt++] = (struct address){ .family = AF_INET, .addr = { 127,0,0,1 } };
- if (family != AF_INET)
- buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } };
- }
- return cnt;
+static int name_from_null(struct address buf[static 2],
+ const char* name,
+ int family,
+ int flags) {
+ int cnt = 0;
+ if (name)
+ return 0;
+ if (flags & AI_PASSIVE) {
+ if (family != AF_INET6)
+ buf[cnt++] = (struct address){.family = AF_INET};
+ if (family != AF_INET)
+ buf[cnt++] = (struct address){.family = AF_INET6};
+ } else {
+ if (family != AF_INET6)
+ buf[cnt++] = (struct address){.family = AF_INET, .addr = {127, 0, 0, 1}};
+ if (family != AF_INET)
+ buf[cnt++] = (struct address){.family = AF_INET6, .addr = {[15] = 1}};
+ }
+ return cnt;
}
-static int name_from_numeric(struct address buf[static 1], const char *name, int family)
-{
- return __lookup_ipliteral(buf, name, family);
+static int name_from_numeric(struct address buf[static 1],
+ const char* name,
+ int family) {
+ return __lookup_ipliteral(buf, name, family);
}
-static int name_from_hosts(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family)
-{
- char line[512];
- size_t l = strlen(name);
- int cnt = 0;
- unsigned char _buf[1032];
- FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf);
- if (!f) switch (errno) {
- case ENOENT:
- case ENOTDIR:
- case EACCES:
- return 0;
- default:
- return EAI_SYSTEM;
- }
- while (fgets(line, sizeof line, f) && cnt < MAXADDRS) {
- char *p, *z;
-
- if ((p=strchr(line, '#'))) *p++='\n', *p=0;
- for(p=line+1; (p=strstr(p, name)) &&
- (!isspace(p[-1]) || !isspace(p[l])); p++);
- if (!p) continue;
-
- /* Isolate IP address to parse */
- for (p=line; *p && !isspace(*p); p++);
- *p++ = 0;
- if (name_from_numeric(buf+cnt, line, family))
- cnt++;
-
- /* Extract first name as canonical name */
- for (; *p && isspace(*p); p++);
- for (z=p; *z && !isspace(*z); z++);
- *z = 0;
- if (is_valid_hostname(p)) memcpy(canon, p, z-p+1);
- }
- __fclose_ca(f);
- return cnt;
+static int name_from_hosts(struct address buf[static MAXADDRS],
+ char canon[static 256],
+ const char* name,
+ int family) {
+ char line[512];
+ size_t l = strlen(name);
+ int cnt = 0;
+ unsigned char _buf[1032];
+ FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf);
+ if (!f)
+ switch (errno) {
+ case ENOENT:
+ case ENOTDIR:
+ case EACCES:
+ return 0;
+ default:
+ return EAI_SYSTEM;
+ }
+ while (fgets(line, sizeof line, f) && cnt < MAXADDRS) {
+ char *p, *z;
+
+ if ((p = strchr(line, '#')))
+ *p++ = '\n', *p = 0;
+ for (p = line + 1;
+ (p = strstr(p, name)) && (!isspace(p[-1]) || !isspace(p[l])); p++)
+ ;
+ if (!p)
+ continue;
+
+ /* Isolate IP address to parse */
+ for (p = line; *p && !isspace(*p); p++)
+ ;
+ *p++ = 0;
+ if (name_from_numeric(buf + cnt, line, family))
+ cnt++;
+
+ /* Extract first name as canonical name */
+ for (; *p && isspace(*p); p++)
+ ;
+ for (z = p; *z && !isspace(*z); z++)
+ ;
+ *z = 0;
+ if (is_valid_hostname(p))
+ memcpy(canon, p, z - p + 1);
+ }
+ __fclose_ca(f);
+ return cnt;
}
struct dpc_ctx {
- struct address *addrs;
- char *canon;
- int cnt;
+ struct address* addrs;
+ char* canon;
+ int cnt;
};
-int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *), void *);
-int __dn_expand(const unsigned char *, const unsigned char *, const unsigned char *, char *, int);
-int __res_mkquery(int, const char *, int, int, const unsigned char *, int, const unsigned char*, unsigned char *, int);
-int __res_msend_rc(int, const unsigned char *const *, const int *, unsigned char *const *, int *, int, const struct resolvconf *);
+int __dns_parse(const unsigned char*,
+ int,
+ int (*)(void*, int, const void*, int, const void*),
+ void*);
+int __dn_expand(const unsigned char*,
+ const unsigned char*,
+ const unsigned char*,
+ char*,
+ int);
+int __res_mkquery(int,
+ const char*,
+ int,
+ int,
+ const unsigned char*,
+ int,
+ const unsigned char*,
+ unsigned char*,
+ int);
+int __res_msend_rc(int,
+ const unsigned char* const*,
+ const int*,
+ unsigned char* const*,
+ int*,
+ int,
+ const struct resolvconf*);
#define RR_A 1
#define RR_CNAME 5
#define RR_AAAA 28
-static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet)
-{
- char tmp[256];
- struct dpc_ctx *ctx = c;
- switch (rr) {
- case RR_A:
- if (len != 4) return -1;
- ctx->addrs[ctx->cnt].family = AF_INET;
- ctx->addrs[ctx->cnt].scopeid = 0;
- memcpy(ctx->addrs[ctx->cnt++].addr, data, 4);
- break;
- case RR_AAAA:
- if (len != 16) return -1;
- ctx->addrs[ctx->cnt].family = AF_INET6;
- ctx->addrs[ctx->cnt].scopeid = 0;
- memcpy(ctx->addrs[ctx->cnt++].addr, data, 16);
- break;
- case RR_CNAME:
- if (__dn_expand(packet, (const unsigned char *)packet + 512,
- data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp))
- strcpy(ctx->canon, tmp);
- break;
- }
- return 0;
+static int dns_parse_callback(void* c,
+ int rr,
+ const void* data,
+ int len,
+ const void* packet) {
+ char tmp[256];
+ struct dpc_ctx* ctx = c;
+ switch (rr) {
+ case RR_A:
+ if (len != 4)
+ return -1;
+ ctx->addrs[ctx->cnt].family = AF_INET;
+ ctx->addrs[ctx->cnt].scopeid = 0;
+ memcpy(ctx->addrs[ctx->cnt++].addr, data, 4);
+ break;
+ case RR_AAAA:
+ if (len != 16)
+ return -1;
+ ctx->addrs[ctx->cnt].family = AF_INET6;
+ ctx->addrs[ctx->cnt].scopeid = 0;
+ memcpy(ctx->addrs[ctx->cnt++].addr, data, 16);
+ break;
+ case RR_CNAME:
+ if (__dn_expand(packet, (const unsigned char*)packet + 512, data, tmp,
+ sizeof tmp) > 0 &&
+ is_valid_hostname(tmp))
+ strcpy(ctx->canon, tmp);
+ break;
+ }
+ return 0;
}
-static int name_from_dns(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, const struct resolvconf *conf)
-{
- unsigned char qbuf[2][280], abuf[2][512];
- const unsigned char *qp[2] = { qbuf[0], qbuf[1] };
- unsigned char *ap[2] = { abuf[0], abuf[1] };
- int qlens[2], alens[2];
- int i, nq = 0;
- struct dpc_ctx ctx = { .addrs = buf, .canon = canon };
-
- if (family != AF_INET6) {
- qlens[nq] = __res_mkquery(0, name, 1, RR_A, 0, 0, 0,
- qbuf[nq], sizeof *qbuf);
- nq++;
- }
- if (family != AF_INET) {
- qlens[nq] = __res_mkquery(0, name, 1, RR_AAAA, 0, 0, 0,
- qbuf[nq], sizeof *qbuf);
- nq++;
- }
-
- if (__res_msend_rc(nq, qp, qlens, ap, alens, sizeof *abuf, conf) < 0)
- return EAI_SYSTEM;
-
- for (i=0; i<nq; i++)
- __dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx);
-
- if (ctx.cnt) return ctx.cnt;
- if (alens[0] < 4 || (abuf[0][3] & 15) == 2) return EAI_AGAIN;
- if ((abuf[0][3] & 15) == 0) return EAI_NONAME;
- if ((abuf[0][3] & 15) == 3) return 0;
- return EAI_FAIL;
+static int name_from_dns(struct address buf[static MAXADDRS],
+ char canon[static 256],
+ const char* name,
+ int family,
+ const struct resolvconf* conf) {
+ unsigned char qbuf[2][280], abuf[2][512];
+ const unsigned char* qp[2] = {qbuf[0], qbuf[1]};
+ unsigned char* ap[2] = {abuf[0], abuf[1]};
+ int qlens[2], alens[2];
+ int i, nq = 0;
+ struct dpc_ctx ctx = {.addrs = buf, .canon = canon};
+
+ if (family != AF_INET6) {
+ qlens[nq] =
+ __res_mkquery(0, name, 1, RR_A, 0, 0, 0, qbuf[nq], sizeof *qbuf);
+ nq++;
+ }
+ if (family != AF_INET) {
+ qlens[nq] =
+ __res_mkquery(0, name, 1, RR_AAAA, 0, 0, 0, qbuf[nq], sizeof *qbuf);
+ nq++;
+ }
+
+ if (__res_msend_rc(nq, qp, qlens, ap, alens, sizeof *abuf, conf) < 0)
+ return EAI_SYSTEM;
+
+ for (i = 0; i < nq; i++)
+ __dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx);
+
+ if (ctx.cnt)
+ return ctx.cnt;
+ if (alens[0] < 4 || (abuf[0][3] & 15) == 2)
+ return EAI_AGAIN;
+ if ((abuf[0][3] & 15) == 0)
+ return EAI_NONAME;
+ if ((abuf[0][3] & 15) == 3)
+ return 0;
+ return EAI_FAIL;
}
-static int name_from_dns_search(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family)
-{
- char search[256];
- struct resolvconf conf;
- size_t l, dots;
- char *p, *z;
-
- if (__get_resolv_conf(&conf, search, sizeof search) < 0) return -1;
-
- /* Count dots, suppress search when >=ndots or name ends in
- * a dot, which is an explicit request for global scope. */
- for (dots=l=0; name[l]; l++) if (name[l]=='.') dots++;
- if (dots >= conf.ndots || name[l-1]=='.') *search = 0;
-
- /* This can never happen; the caller already checked length. */
- if (l >= 256) return EAI_NONAME;
-
- /* Name with search domain appended is setup in canon[]. This both
- * provides the desired default canonical name (if the requested
- * name is not a CNAME record) and serves as a buffer for passing
- * the full requested name to name_from_dns. */
- memcpy(canon, name, l);
- canon[l] = '.';
-
- for (p=search; *p; p=z) {
- for (; isspace(*p); p++);
- for (z=p; *z && !isspace(*z); z++);
- if (z==p) break;
- if (z-p < 256 - l - 1) {
- memcpy(canon+l+1, p, z-p);
- canon[z-p+1+l] = 0;
- int cnt = name_from_dns(buf, canon, canon, family, &conf);
- if (cnt) return cnt;
- }
- }
-
- canon[l] = 0;
- return name_from_dns(buf, canon, name, family, &conf);
+static int name_from_dns_search(struct address buf[static MAXADDRS],
+ char canon[static 256],
+ const char* name,
+ int family) {
+ char search[256];
+ struct resolvconf conf;
+ size_t l, dots;
+ char *p, *z;
+
+ if (__get_resolv_conf(&conf, search, sizeof search) < 0)
+ return -1;
+
+ /* Count dots, suppress search when >=ndots or name ends in
+ * a dot, which is an explicit request for global scope. */
+ for (dots = l = 0; name[l]; l++)
+ if (name[l] == '.')
+ dots++;
+ if (dots >= conf.ndots || name[l - 1] == '.')
+ *search = 0;
+
+ /* This can never happen; the caller already checked length. */
+ if (l >= 256)
+ return EAI_NONAME;
+
+ /* Name with search domain appended is setup in canon[]. This both
+ * provides the desired default canonical name (if the requested
+ * name is not a CNAME record) and serves as a buffer for passing
+ * the full requested name to name_from_dns. */
+ memcpy(canon, name, l);
+ canon[l] = '.';
+
+ for (p = search; *p; p = z) {
+ for (; isspace(*p); p++)
+ ;
+ for (z = p; *z && !isspace(*z); z++)
+ ;
+ if (z == p)
+ break;
+ if (z - p < 256 - l - 1) {
+ memcpy(canon + l + 1, p, z - p);
+ canon[z - p + 1 + l] = 0;
+ int cnt = name_from_dns(buf, canon, canon, family, &conf);
+ if (cnt)
+ return cnt;
+ }
+ }
+
+ canon[l] = 0;
+ return name_from_dns(buf, canon, name, family, &conf);
}
static const struct policy {
- unsigned char addr[16];
- unsigned char len, mask;
- unsigned char prec, label;
+ unsigned char addr[16];
+ unsigned char len, mask;
+ unsigned char prec, label;
} defpolicy[] = {
- { "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 15, 0xff, 50, 0 },
- { "\0\0\0\0\0\0\0\0\0\0\xff\xff", 11, 0xff, 35, 4 },
- { "\x20\2", 1, 0xff, 30, 2 },
- { "\x20\1", 3, 0xff, 5, 5 },
- { "\xfc", 0, 0xfe, 3, 13 },
+ {"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 15, 0xff, 50, 0},
+ {"\0\0\0\0\0\0\0\0\0\0\xff\xff", 11, 0xff, 35, 4},
+ {"\x20\2", 1, 0xff, 30, 2},
+ {"\x20\1", 3, 0xff, 5, 5},
+ {"\xfc", 0, 0xfe, 3, 13},
#if 0
/* These are deprecated and/or returned to the address
* pool, so despite the RFC, treating them as special
@@ -216,172 +277,181 @@ static const struct policy {
{ "\xfe\xc0", 1, 0xc0, 1, 11 },
{ "\x3f\xfe", 1, 0xff, 1, 12 },
#endif
- /* Last rule must match all addresses to stop loop. */
- { "", 0, 0, 40, 1 },
+ /* Last rule must match all addresses to stop loop. */
+ {"", 0, 0, 40, 1},
};
-static const struct policy *policyof(const struct in6_addr *a)
-{
- int i;
- for (i=0; ; i++) {
- if (memcmp(a->s6_addr, defpolicy[i].addr, defpolicy[i].len))
- continue;
- if ((a->s6_addr[defpolicy[i].len] & defpolicy[i].mask)
- != defpolicy[i].addr[defpolicy[i].len])
- continue;
- return defpolicy+i;
- }
+static const struct policy* policyof(const struct in6_addr* a) {
+ int i;
+ for (i = 0;; i++) {
+ if (memcmp(a->s6_addr, defpolicy[i].addr, defpolicy[i].len))
+ continue;
+ if ((a->s6_addr[defpolicy[i].len] & defpolicy[i].mask) !=
+ defpolicy[i].addr[defpolicy[i].len])
+ continue;
+ return defpolicy + i;
+ }
}
-static int labelof(const struct in6_addr *a)
-{
- return policyof(a)->label;
+static int labelof(const struct in6_addr* a) {
+ return policyof(a)->label;
}
-static int scopeof(const struct in6_addr *a)
-{
- if (IN6_IS_ADDR_MULTICAST(a)) return a->s6_addr[1] & 15;
- if (IN6_IS_ADDR_LINKLOCAL(a)) return 2;
- if (IN6_IS_ADDR_LOOPBACK(a)) return 2;
- if (IN6_IS_ADDR_SITELOCAL(a)) return 5;
- return 14;
+static int scopeof(const struct in6_addr* a) {
+ if (IN6_IS_ADDR_MULTICAST(a))
+ return a->s6_addr[1] & 15;
+ if (IN6_IS_ADDR_LINKLOCAL(a))
+ return 2;
+ if (IN6_IS_ADDR_LOOPBACK(a))
+ return 2;
+ if (IN6_IS_ADDR_SITELOCAL(a))
+ return 5;
+ return 14;
}
-static int prefixmatch(const struct in6_addr *s, const struct in6_addr *d)
-{
- /* FIXME: The common prefix length should be limited to no greater
- * than the nominal length of the prefix portion of the source
- * address. However the definition of the source prefix length is
- * not clear and thus this limiting is not yet implemented. */
- unsigned i;
- for (i=0; i<128 && !((s->s6_addr[i/8]^d->s6_addr[i/8])&(128>>(i%8))); i++);
- return i;
+static int prefixmatch(const struct in6_addr* s, const struct in6_addr* d) {
+ /* FIXME: The common prefix length should be limited to no greater
+ * than the nominal length of the prefix portion of the source
+ * address. However the definition of the source prefix length is
+ * not clear and thus this limiting is not yet implemented. */
+ unsigned i;
+ for (i = 0;
+ i < 128 && !((s->s6_addr[i / 8] ^ d->s6_addr[i / 8]) & (128 >> (i % 8)));
+ i++)
+ ;
+ return i;
}
-#define DAS_USABLE 0x40000000
-#define DAS_MATCHINGSCOPE 0x20000000
-#define DAS_MATCHINGLABEL 0x10000000
-#define DAS_PREC_SHIFT 20
-#define DAS_SCOPE_SHIFT 16
-#define DAS_PREFIX_SHIFT 8
-#define DAS_ORDER_SHIFT 0
-
-static int addrcmp(const void *_a, const void *_b)
-{
- const struct address *a = _a, *b = _b;
- return b->sortkey - a->sortkey;
+#define DAS_USABLE 0x40000000
+#define DAS_MATCHINGSCOPE 0x20000000
+#define DAS_MATCHINGLABEL 0x10000000
+#define DAS_PREC_SHIFT 20
+#define DAS_SCOPE_SHIFT 16
+#define DAS_PREFIX_SHIFT 8
+#define DAS_ORDER_SHIFT 0
+
+static int addrcmp(const void* _a, const void* _b) {
+ const struct address *a = _a, *b = _b;
+ return b->sortkey - a->sortkey;
}
-int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, int flags)
-{
- int cnt = 0, i, j;
-
- *canon = 0;
- if (name) {
- /* reject empty name and check len so it fits into temp bufs */
- size_t l = strnlen(name, 255);
- if (l-1 >= 254)
- return EAI_NONAME;
- memcpy(canon, name, l+1);
- }
-
- /* Procedurally, a request for v6 addresses with the v4-mapped
- * flag set is like a request for unspecified family, followed
- * by filtering of the results. */
- if (flags & AI_V4MAPPED) {
- if (family == AF_INET6) family = AF_UNSPEC;
- else flags -= AI_V4MAPPED;
- }
-
- /* Try each backend until there's at least one result. */
- cnt = name_from_null(buf, name, family, flags);
- if (!cnt) cnt = name_from_numeric(buf, name, family);
- if (!cnt && !(flags & AI_NUMERICHOST)) {
- cnt = name_from_hosts(buf, canon, name, family);
- if (!cnt) cnt = name_from_dns_search(buf, canon, name, family);
- }
- if (cnt<=0) return cnt ? cnt : EAI_NONAME;
-
- /* Filter/transform results for v4-mapped lookup, if requested. */
- if (flags & AI_V4MAPPED) {
- if (!(flags & AI_ALL)) {
- /* If any v6 results exist, remove v4 results. */
- for (i=0; i<cnt && buf[i].family != AF_INET6; i++);
- if (i<cnt) {
- for (j=0; i<cnt; i++) {
- if (buf[i].family == AF_INET6)
- buf[j++] = buf[i];
- }
- cnt = i = j;
- }
- }
- /* Translate any remaining v4 results to v6 */
- for (i=0; i<cnt; i++) {
- if (buf[i].family != AF_INET) continue;
- memcpy(buf[i].addr+12, buf[i].addr, 4);
- memcpy(buf[i].addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
- buf[i].family = AF_INET6;
- }
- }
-
- /* No further processing is needed if there are fewer than 2
- * results or if there are only IPv4 results. */
- if (cnt<2 || family==AF_INET) return cnt;
- for (i=0; buf[i].family == AF_INET; i++)
- if (i==cnt) return cnt;
-
- int cs;
- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
-
- /* The following implements a subset of RFC 3484/6724 destination
- * address selection by generating a single 31-bit sort key for
- * each address. Rules 3, 4, and 7 are omitted for having
- * excessive runtime and code size cost and dubious benefit.
- * So far the label/precedence table cannot be customized. */
- for (i=0; i<cnt; i++) {
- int key = 0;
- struct sockaddr_in6 sa, da = {
- .sin6_family = AF_INET6,
- .sin6_scope_id = buf[i].scopeid,
- .sin6_port = 65535
- };
- if (buf[i].family == AF_INET6) {
- memcpy(da.sin6_addr.s6_addr, buf[i].addr, 16);
- } else {
- memcpy(da.sin6_addr.s6_addr,
- "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
- memcpy(da.sin6_addr.s6_addr+12, buf[i].addr, 4);
- }
- const struct policy *dpolicy = policyof(&da.sin6_addr);
- int dscope = scopeof(&da.sin6_addr);
- int dlabel = dpolicy->label;
- int dprec = dpolicy->prec;
- int prefixlen = 0;
- int fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_UDP);
- if (fd >= 0) {
- if (!connect(fd, (void *)&da, sizeof da)) {
- key |= DAS_USABLE;
- if (!getsockname(fd, (void *)&sa,
- &(socklen_t){sizeof sa})) {
- if (dscope == scopeof(&sa.sin6_addr))
- key |= DAS_MATCHINGSCOPE;
- if (dlabel == labelof(&sa.sin6_addr))
- key |= DAS_MATCHINGLABEL;
- prefixlen = prefixmatch(&sa.sin6_addr,
- &da.sin6_addr);
- }
- }
- close(fd);
- }
- key |= dprec << DAS_PREC_SHIFT;
- key |= (15-dscope) << DAS_SCOPE_SHIFT;
- key |= prefixlen << DAS_PREFIX_SHIFT;
- key |= (MAXADDRS-i) << DAS_ORDER_SHIFT;
- buf[i].sortkey = key;
- }
- qsort(buf, cnt, sizeof *buf, addrcmp);
-
- pthread_setcancelstate(cs, 0);
-
- return cnt;
+int __lookup_name(struct address buf[static MAXADDRS],
+ char canon[static 256],
+ const char* name,
+ int family,
+ int flags) {
+ int cnt = 0, i, j;
+
+ *canon = 0;
+ if (name) {
+ /* reject empty name and check len so it fits into temp bufs */
+ size_t l = strnlen(name, 255);
+ if (l - 1 >= 254)
+ return EAI_NONAME;
+ memcpy(canon, name, l + 1);
+ }
+
+ /* Procedurally, a request for v6 addresses with the v4-mapped
+ * flag set is like a request for unspecified family, followed
+ * by filtering of the results. */
+ if (flags & AI_V4MAPPED) {
+ if (family == AF_INET6)
+ family = AF_UNSPEC;
+ else
+ flags -= AI_V4MAPPED;
+ }
+
+ /* Try each backend until there's at least one result. */
+ cnt = name_from_null(buf, name, family, flags);
+ if (!cnt)
+ cnt = name_from_numeric(buf, name, family);
+ if (!cnt && !(flags & AI_NUMERICHOST)) {
+ cnt = name_from_hosts(buf, canon, name, family);
+ if (!cnt)
+ cnt = name_from_dns_search(buf, canon, name, family);
+ }
+ if (cnt <= 0)
+ return cnt ? cnt : EAI_NONAME;
+
+ /* Filter/transform results for v4-mapped lookup, if requested. */
+ if (flags & AI_V4MAPPED) {
+ if (!(flags & AI_ALL)) {
+ /* If any v6 results exist, remove v4 results. */
+ for (i = 0; i < cnt && buf[i].family != AF_INET6; i++)
+ ;
+ if (i < cnt) {
+ for (j = 0; i < cnt; i++) {
+ if (buf[i].family == AF_INET6)
+ buf[j++] = buf[i];
+ }
+ cnt = i = j;
+ }
+ }
+ /* Translate any remaining v4 results to v6 */
+ for (i = 0; i < cnt; i++) {
+ if (buf[i].family != AF_INET)
+ continue;
+ memcpy(buf[i].addr + 12, buf[i].addr, 4);
+ memcpy(buf[i].addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
+ buf[i].family = AF_INET6;
+ }
+ }
+
+ /* No further processing is needed if there are fewer than 2
+ * results or if there are only IPv4 results. */
+ if (cnt < 2 || family == AF_INET)
+ return cnt;
+ for (i = 0; buf[i].family == AF_INET; i++)
+ if (i == cnt)
+ return cnt;
+
+ int cs;
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
+
+ /* The following implements a subset of RFC 3484/6724 destination
+ * address selection by generating a single 31-bit sort key for
+ * each address. Rules 3, 4, and 7 are omitted for having
+ * excessive runtime and code size cost and dubious benefit.
+ * So far the label/precedence table cannot be customized. */
+ for (i = 0; i < cnt; i++) {
+ int key = 0;
+ struct sockaddr_in6 sa, da = {.sin6_family = AF_INET6,
+ .sin6_scope_id = buf[i].scopeid,
+ .sin6_port = 65535};
+ if (buf[i].family == AF_INET6) {
+ memcpy(da.sin6_addr.s6_addr, buf[i].addr, 16);
+ } else {
+ memcpy(da.sin6_addr.s6_addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
+ memcpy(da.sin6_addr.s6_addr + 12, buf[i].addr, 4);
+ }
+ const struct policy* dpolicy = policyof(&da.sin6_addr);
+ int dscope = scopeof(&da.sin6_addr);
+ int dlabel = dpolicy->label;
+ int dprec = dpolicy->prec;
+ int prefixlen = 0;
+ int fd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
+ if (fd >= 0) {
+ if (!connect(fd, (void*)&da, sizeof da)) {
+ key |= DAS_USABLE;
+ if (!getsockname(fd, (void*)&sa, &(socklen_t){sizeof sa})) {
+ if (dscope == scopeof(&sa.sin6_addr))
+ key |= DAS_MATCHINGSCOPE;
+ if (dlabel == labelof(&sa.sin6_addr))
+ key |= DAS_MATCHINGLABEL;
+ prefixlen = prefixmatch(&sa.sin6_addr, &da.sin6_addr);
+ }
+ }
+ close(fd);
+ }
+ key |= dprec << DAS_PREC_SHIFT;
+ key |= (15 - dscope) << DAS_SCOPE_SHIFT;
+ key |= prefixlen << DAS_PREFIX_SHIFT;
+ key |= (MAXADDRS - i) << DAS_ORDER_SHIFT;
+ buf[i].sortkey = key;
+ }
+ qsort(buf, cnt, sizeof *buf, addrcmp);
+
+ pthread_setcancelstate(cs, 0);
+
+ return cnt;
}

Powered by Google App Engine
This is Rietveld 408576698