X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fnetwork%2F__dns.c;h=97d8031ca1d50e110d30e12575c2957bca5e682f;hb=6739b13a172aad9c01572c04cadacc99c7041811;hp=b8547bbafe307b41c5ddd6f1f7f112dfebfff5ba;hpb=6fbf8bfd750a5c982b716bea0802692847918951;p=musl diff --git a/src/network/__dns.c b/src/network/__dns.c index b8547bba..97d8031c 100644 --- a/src/network/__dns.c +++ b/src/network/__dns.c @@ -5,59 +5,68 @@ #include #include #include -#include -#include +#include #include #include #include #include +#include +#include #include "__dns.h" #include "stdio_impl.h" #define TIMEOUT 5 -#define RETRY 1 +#define RETRY 1000 #define PACKET_MAX 512 #define PTR_MAX (64 + sizeof ".in-addr.arpa") +static void cleanup(void *p) +{ + close((intptr_t)p); +} + int __dns_doqueries(unsigned char *dest, const char *name, int *rr, int rrcnt) { time_t t0 = time(0); int fd; FILE *f, _f; - unsigned char _buf[64]; + unsigned char _buf[256]; char line[64], *s, *z; union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } sa = {0}, ns[3] = {{0}}; - socklen_t sl; - int nns; - int family; + socklen_t sl = sizeof sa.sin; + int nns = 0; + int family = AF_INET; unsigned char q[280] = "", *r = dest; int ql; int rlen; int got = 0, failed = 0; int errcode = EAI_AGAIN; int i, j; - struct timeval tv; - fd_set fds; + struct timespec ts; + struct pollfd pfd; int id; + int cs; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); /* Construct query template - RR and ID will be filled later */ - if (strlen(name)-1 >= 254U) return -1; + if (strlen(name)-1 >= 254U) return EAI_NONAME; q[2] = q[5] = 1; strcpy((char *)q+13, name); for (i=13; q[i]; i=j+1) { for (j=i; q[j] && q[j] != '.'; j++); - if (j-i-1u > 62u) return -1; + if (j-i-1u > 62u) return EAI_NONAME; q[i-1] = j-i; } q[i+3] = 1; ql = i+4; /* Make a reasonably unpredictable id */ - gettimeofday(&tv, 0); - id = tv.tv_usec + tv.tv_usec/256 & 0xffff; + clock_gettime(CLOCK_REALTIME, &ts); + id = ts.tv_nsec + ts.tv_nsec/65536UL & 0xffff; /* Get nameservers from resolv.conf, fallback to localhost */ f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf); @@ -67,28 +76,59 @@ int __dns_doqueries(unsigned char *dest, const char *name, int *rr, int rrcnt) for (s=line+11; isspace(*s); s++); for (z=s; *z && !isspace(*z); z++); *z=0; - if (__ipparse(ns+nns, family, s) < 0) continue; + if (__ipparse(ns+nns, AF_UNSPEC, s) < 0) continue; ns[nns].sin.sin_port = htons(53); - family = ns[nns++].sin.sin_family; - sl = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin; + if (ns[nns++].sin.sin_family == AF_INET6) { + family = AF_INET6; + sl = sizeof sa.sin6; + } } if (f) __fclose_ca(f); if (!nns) { - ns[0].sin.sin_family = AF_INET; + ns[0].sin.sin_family = family = AF_INET; ns[0].sin.sin_port = htons(53); + ns[0].sin.sin_addr.s_addr = htonl(0x7f000001); nns=1; sl = sizeof sa.sin; } /* Get local address and open/bind a socket */ sa.sin.sin_family = family; - fd = socket(family, SOCK_DGRAM, 0); + fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + + /* Handle case where system lacks IPv6 support */ + if (fd < 0 && errno == EAFNOSUPPORT) { + if (family != AF_INET6) return EAI_SYSTEM; + fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + family = AF_INET; + } + if (fd < 0) return EAI_SYSTEM; + + /* Convert any IPv4 addresses in a mixed environment to v4-mapped */ + if (family == AF_INET6) { + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0); + for (i=0; i=pz) return -1; - else if (*p&0xc0) { - int j = (p[0]&1) | p[1]; - if (BITOP(seen, j, &)) return -1; - BITOP(seen, j, |=); - p = b + j; - } else if (*p) { - if (p+*p+1>=pz || s+*p>=sz) return -1; - memcpy(s, p+1, *p); - s += *p+1; - p += *p+1; - s[-1] = *p ? '.' : 0; - } else return 0; - } -} +int __dn_expand(const unsigned char *, const unsigned char *, const unsigned char *, char *, int); int __dns_get_rr(void *dest, size_t stride, size_t maxlen, size_t limit, const unsigned char *r, int rr, int dec) { @@ -238,7 +250,8 @@ int __dns_get_rr(void *dest, size_t stride, size_t maxlen, size_t limit, const u len = p[8]*256 + p[9]; if (p+len > r+512) return -1; if (p[1]==rr && len <= maxlen) { - if (dec && decname(tmp, r, p+10)<0) return -1; + if (dec && __dn_expand(r, r+512, p+10, tmp, sizeof tmp)<0) + return -1; if (dest && limit) { if (dec) strcpy(dest, tmp); else memcpy(dest, p+10, len); @@ -257,10 +270,12 @@ int __dns_count_addrs(const unsigned char *r, int cnt) int found=0, res, i; static const int p[2][2] = { { 4, RR_A }, { 16, RR_AAAA } }; - while (cnt--) for (i=0; i<2; i++) { - res = __dns_get_rr(0, 0, p[i][0], -1, r, p[i][1], 0); - if (res < 0) return res; - found += res; + while (cnt--) { + for (i=0; i<2; i++) { + res = __dns_get_rr(0, 0, p[i][0], -1, r, p[i][1], 0); + if (res < 0) return res; + found += res; + } r += 512; } return found;