X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fnetwork%2Fgetaddrinfo.c;h=70b6cfdab1436e01d895f06ae2c6f4f0509f7b2f;hb=6f409bff008a83fa6bc640c10366765874de35e2;hp=5d45be747a455ed3f9a5101d0f89f694c80cd78f;hpb=cabe9aa974aca34c0fda91028c770dee96ba51dc;p=musl diff --git a/src/network/getaddrinfo.c b/src/network/getaddrinfo.c index 5d45be74..70b6cfda 100644 --- a/src/network/getaddrinfo.c +++ b/src/network/getaddrinfo.c @@ -1,249 +1,115 @@ #include -#include -#include -#include #include -#include +#include +#include #include -#include -#include "__dns.h" -#include "stdio_impl.h" - -static int is_valid(const char *host) -{ - const unsigned char *s; - if (strlen(host)-1 > 254 || mbstowcs(0, host, 0) > 255) return 0; - for (s=(void *)host; *s>=0x80 || *s=='.' || *s=='-' || isalnum(*s); s++); - return !*s; -} - -#if 0 -static int have_af(int family) -{ - struct sockaddr_in6 sin6 = { .sin6_family = family }; - socklen_t sl = family == AF_INET - ? sizeof(struct sockaddr_in) - : sizeof(struct sockaddr_in6); - int sock = socket(family, SOCK_STREAM, 0); - int have = !bind(sock, (void *)&sin6, sl); - close(sock); - return have; -} -#endif - -union sa { - struct sockaddr_in sin; - struct sockaddr_in6 sin6; -}; - -struct aibuf { - struct addrinfo ai; - union sa sa; -}; - -/* Extra slots needed for storing canonical name */ -#define EXTRA ((256+sizeof(struct aibuf)-1)/sizeof(struct aibuf)) +#include "lookup.h" int getaddrinfo(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, struct addrinfo **restrict res) { - int flags = hint ? hint->ai_flags : 0; - int family = hint ? hint->ai_family : AF_UNSPEC; - int type = hint ? hint->ai_socktype : 0; - int proto = hint ? hint->ai_protocol : 0; - unsigned long port = 0; - struct aibuf *buf; - union sa sa = {{0}}; - unsigned char reply[1024]; - int i, j; - char line[512]; - FILE *f, _f; - unsigned char _buf[1024]; - char *z; - int result; - int cnt; - - if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC) - return EAI_FAMILY; - - if (host && strlen(host)>255) return EAI_NONAME; - if (serv && strlen(serv)>32) return EAI_SERVICE; - - if (type && !proto) - proto = type==SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; - if (!type && proto) - type = proto==IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; - - if (serv) { - if (!*serv) return EAI_SERVICE; - port = strtoul(serv, &z, 10); - if (*z) { - size_t servlen = strlen(serv); - char *end = line; - - if (flags & AI_NUMERICSERV) return EAI_SERVICE; + struct service ports[MAXSERVS]; + struct address addrs[MAXADDRS]; + char canon[256], *outcanon; + int nservs, naddrs, nais, canon_len, i, j, k; + int family = AF_UNSPEC, flags = 0, proto = 0; + struct aibuf { + struct addrinfo ai; + union sa { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } sa; + } *out; + + if (hint) { + family = hint->ai_family; + flags = hint->ai_flags; + proto = hint->ai_protocol; + + const int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | + AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG | AI_NUMERICSERV; + if ((flags & mask) != flags) + return EAI_BADFLAGS; + + switch (family) { + case AF_INET: + case AF_INET6: + case AF_UNSPEC: + break; + default: + return EAI_FAMILY; + } - f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf); - if (!f) return EAI_SERVICE; - while (fgets(line, sizeof line, f)) { - if (strncmp(line, serv, servlen) || !isspace(line[servlen])) - continue; - port = strtoul(line+servlen, &end, 10); - if (strncmp(end, proto==IPPROTO_UDP ? "/udp" : "/tcp", 4)) - continue; + switch (hint->ai_socktype) { + case SOCK_STREAM: + switch (proto) { + case 0: + proto = IPPROTO_TCP; + case IPPROTO_TCP: break; + default: + return EAI_SERVICE; } - __fclose_ca(f); - if (feof(f)) return EAI_SERVICE; - } - if (port > 65535) return EAI_SERVICE; - port = htons(port); - } - - if (!host) { - if (family == AF_UNSPEC) { - cnt = 2; family = AF_INET; - } else { - cnt = 1; - } - buf = calloc(sizeof *buf, cnt); - if (!buf) return EAI_MEMORY; - for (i=0; iai; - return 0; - } - - if (!*host) return EAI_NONAME; - - /* Try as a numeric address */ - if (__ipparse(&sa, family, host) >= 0) { - buf = calloc(sizeof *buf, 1+EXTRA); - if (!buf) return EAI_MEMORY; - family = sa.sin.sin_family; - buf->ai.ai_protocol = proto; - buf->ai.ai_socktype = type; - buf->ai.ai_addr = (void *)&buf->sa; - buf->ai.ai_addrlen = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin; - buf->ai.ai_family = family; - buf->ai.ai_canonname = (char *)host; - buf->sa = sa; - buf->sa.sin.sin_port = port; - *res = &buf->ai; - return 0; } - if (flags & AI_NUMERICHOST) return EAI_NONAME; + nservs = __lookup_serv(ports, serv, proto, flags); + if (nservs < 0) return nservs; - f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf); - if (f) while (fgets(line, sizeof line, f)) { - char *p; - size_t l = strlen(host); + naddrs = __lookup_name(addrs, canon, host, family, flags); + if (naddrs < 0) return naddrs; - if ((p=strchr(line, '#'))) *p++='\n', *p=0; - for(p=line+1; (p=strstr(p, host)) && - (!isspace(p[-1]) || !isspace(p[l])); p++); - if (!p) continue; - __fclose_ca(f); - - /* Isolate IP address to parse */ - for (p=line; *p && !isspace(*p); p++); - *p++ = 0; - if (__ipparse(&sa, family, line) < 0) return EAI_NONAME; - - /* Allocate and fill result buffer */ - buf = calloc(sizeof *buf, 1+EXTRA); - if (!buf) return EAI_MEMORY; - family = sa.sin.sin_family; - buf->ai.ai_protocol = proto; - buf->ai.ai_socktype = type; - buf->ai.ai_addr = (void *)&buf->sa; - buf->ai.ai_addrlen = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin; - buf->ai.ai_family = family; - buf->sa = sa; - buf->sa.sin.sin_port = port; - - /* Extract first name as canonical name */ - for (; *p && isspace(*p); p++); - buf->ai.ai_canonname = (void *)(buf+1); - snprintf(buf->ai.ai_canonname, 256, "%s", p); - for (p=buf->ai.ai_canonname; *p && !isspace(*p); p++); - *p = 0; - if (!is_valid(buf->ai.ai_canonname)) - buf->ai.ai_canonname = 0; - - *res = &buf->ai; - return 0; - } - if (f) __fclose_ca(f); + nais = nservs * naddrs; + canon_len = strlen(canon); + out = calloc(1, nais * sizeof(*out) + canon_len + 1); + if (!out) return EAI_MEMORY; -#if 0 - f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf); - if (f) while (fgets(line, sizeof line, f)) { - if (!isspace(line[10]) || (strncmp(line, "search", 6) - && strncmp(line, "domain", 6))) continue; + if (canon_len) { + outcanon = (void *)&out[nais]; + memcpy(outcanon, canon, canon_len+1); + } else { + outcanon = 0; } - if (f) __fclose_ca(f); -#endif - /* Perform one or more DNS queries for host */ - memset(reply, 0, sizeof reply); - result = __dns_query(reply, host, family, 0); - if (result < 0) return result; - - cnt = __dns_count_addrs(reply, result); - if (cnt <= 0) return EAI_NONAME; - - buf = calloc(sizeof *buf, cnt+EXTRA); - if (!buf) return EAI_MEMORY; - - i = 0; - if (family != AF_INET6) { - j = __dns_get_rr(&buf[i].sa.sin.sin_addr, sizeof *buf, 4, cnt-i, reply, RR_A, 0); - while (j--) buf[i++].sa.sin.sin_family = AF_INET; - } - if (family != AF_INET) { - j = __dns_get_rr(&buf[i].sa.sin6.sin6_addr, sizeof *buf, 16, cnt-i, reply, RR_AAAA, 0); - while (j--) buf[i++].sa.sin.sin_family = AF_INET6; - } - if (result>1) { - j = __dns_get_rr(&buf[i].sa.sin.sin_addr, sizeof *buf, 4, cnt-i, reply+512, RR_A, 0); - while (j--) buf[i++].sa.sin.sin_family = AF_INET; - j = __dns_get_rr(&buf[i].sa.sin6.sin6_addr, sizeof *buf, 16, cnt-i, reply+512, RR_AAAA, 0); - while (j--) buf[i++].sa.sin.sin_family = AF_INET6; - } - - if (__dns_get_rr((void *)&buf[cnt], 0, 256, 1, reply, RR_CNAME, 1) <= 0) - strcpy((void *)&buf[cnt], host); - - for (i=0; iai; - + out[nais-1].ai.ai_next = 0; + *res = &out->ai; return 0; }