| 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 <arpa/inet.h> | 4 #include <arpa/inet.h> |
| 5 #include <stdint.h> | 5 #include <stdint.h> |
| 6 #include <string.h> | 6 #include <string.h> |
| 7 #include <poll.h> | 7 #include <poll.h> |
| 8 #include <time.h> | 8 #include <time.h> |
| 9 #include <ctype.h> | 9 #include <ctype.h> |
| 10 #include <unistd.h> | 10 #include <unistd.h> |
| 11 #include <errno.h> | 11 #include <errno.h> |
| 12 #include <pthread.h> | 12 #include <pthread.h> |
| 13 #include "stdio_impl.h" | 13 #include "stdio_impl.h" |
| 14 #include "syscall.h" | 14 #include "syscall.h" |
| 15 #include "lookup.h" | 15 #include "lookup.h" |
| 16 | 16 |
| 17 static void cleanup(void *p) | 17 static void cleanup(void *p) |
| 18 { | 18 { |
| 19 __syscall(SYS_close, (intptr_t)p); | 19 __syscall(SYS_close, (intptr_t)p); |
| 20 } | 20 } |
| 21 | 21 |
| 22 static unsigned long mtime() | 22 static unsigned long mtime() |
| 23 { | 23 { |
| 24 struct timespec ts; | 24 struct timespec ts; |
| 25 clock_gettime(CLOCK_REALTIME, &ts); | 25 clock_gettime(CLOCK_REALTIME, &ts); |
| 26 return (unsigned long)ts.tv_sec * 1000 | 26 return (unsigned long)ts.tv_sec * 1000 |
| 27 + ts.tv_nsec / 1000000; | 27 + ts.tv_nsec / 1000000; |
| 28 } | 28 } |
| 29 | 29 |
| 30 int __res_msend(int nqueries, const unsigned char *const *queries, | 30 int __res_msend_rc(int nqueries, const unsigned char *const *queries, |
| 31 » const int *qlens, unsigned char *const *answers, int *alens, int asize) | 31 » const int *qlens, unsigned char *const *answers, int *alens, int asize, |
| 32 » const struct resolvconf *conf) |
| 32 { | 33 { |
| 33 int fd; | 34 int fd; |
| 34 » FILE *f, _f; | 35 » int timeout, attempts, retry_interval, servfail_retry; |
| 35 » unsigned char _buf[256]; | |
| 36 » char line[64], *s, *z; | |
| 37 » int timeout = 5000, attempts = 2, retry_interval, servfail_retry; | |
| 38 union { | 36 union { |
| 39 struct sockaddr_in sin; | 37 struct sockaddr_in sin; |
| 40 struct sockaddr_in6 sin6; | 38 struct sockaddr_in6 sin6; |
| 41 » } sa = {0}, ns[3] = {{0}}; | 39 » } sa = {0}, ns[MAXNS] = {{0}}; |
| 42 socklen_t sl = sizeof sa.sin; | 40 socklen_t sl = sizeof sa.sin; |
| 43 int nns = 0; | 41 int nns = 0; |
| 44 int family = AF_INET; | 42 int family = AF_INET; |
| 45 int rlen; | 43 int rlen; |
| 46 int next; | 44 int next; |
| 47 int i, j; | 45 int i, j; |
| 48 int cs; | 46 int cs; |
| 49 struct pollfd pfd; | 47 struct pollfd pfd; |
| 50 unsigned long t0, t1, t2; | 48 unsigned long t0, t1, t2; |
| 51 struct address iplit; | |
| 52 | 49 |
| 53 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); | 50 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); |
| 54 | 51 |
| 55 » /* Get nameservers from resolv.conf, fallback to localhost */ | 52 » timeout = 1000*conf->timeout; |
| 56 » f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf); | 53 » attempts = conf->attempts; |
| 57 » if (!f) switch (errno) { | 54 |
| 58 » case ENOENT: | 55 » nns = conf->nns; |
| 59 » case ENOTDIR: | 56 » for (nns=0; nns<conf->nns; nns++) { |
| 60 » case EACCES: | 57 » » const struct address *iplit = &conf->ns[nns]; |
| 61 » » goto no_resolv_conf; | 58 » » if (iplit->family == AF_INET) { |
| 62 » default: | 59 » » » memcpy(&ns[nns].sin.sin_addr, iplit->addr, 4); |
| 63 » » return -1; | 60 » » » ns[nns].sin.sin_port = htons(53); |
| 64 » } | 61 » » » ns[nns].sin.sin_family = AF_INET; |
| 65 » for (nns=0; nns<3 && fgets(line, sizeof line, f); ) { | 62 » » } else { |
| 66 » » if (!strncmp(line, "options", 7) && isspace(line[7])) { | 63 » » » sl = sizeof sa.sin6; |
| 67 » » » unsigned long x; | 64 » » » memcpy(&ns[nns].sin6.sin6_addr, iplit->addr, 16); |
| 68 » » » char *p, *z; | 65 » » » ns[nns].sin6.sin6_port = htons(53); |
| 69 » » » p = strstr(line, "timeout:"); | 66 » » » ns[nns].sin6.sin6_scope_id = iplit->scopeid; |
| 70 » » » if (p && isdigit(p[8])) { | 67 » » » ns[nns].sin6.sin6_family = family = AF_INET6; |
| 71 » » » » p += 8; | |
| 72 » » » » x = strtoul(p, &z, 10); | |
| 73 » » » » if (z != p) timeout = x < 30 ? x*1000 : 30000; | |
| 74 » » » } | |
| 75 » » » p = strstr(line, "attempts:"); | |
| 76 » » » if (p && isdigit(p[9])) { | |
| 77 » » » » p += 9; | |
| 78 » » » » x = strtoul(p, &z, 10); | |
| 79 » » » » if (z != p) attempts = x < 10 ? x : 10; | |
| 80 » » » » if (!attempts) attempts = 1; | |
| 81 » » » } | |
| 82 } | 68 } |
| 83 if (strncmp(line, "nameserver", 10) || !isspace(line[10])) | |
| 84 continue; | |
| 85 for (s=line+11; isspace(*s); s++); | |
| 86 for (z=s; *z && !isspace(*z); z++); | |
| 87 *z=0; | |
| 88 | |
| 89 if (__lookup_ipliteral(&iplit, s, AF_UNSPEC)>0) { | |
| 90 if (iplit.family == AF_INET) { | |
| 91 memcpy(&ns[nns].sin.sin_addr, iplit.addr, 4); | |
| 92 ns[nns].sin.sin_port = htons(53); | |
| 93 ns[nns++].sin.sin_family = AF_INET; | |
| 94 } else { | |
| 95 sl = sizeof sa.sin6; | |
| 96 memcpy(&ns[nns].sin6.sin6_addr, iplit.addr, 16); | |
| 97 ns[nns].sin6.sin6_port = htons(53); | |
| 98 ns[nns].sin6.sin6_scope_id = iplit.scopeid; | |
| 99 ns[nns++].sin6.sin6_family = family = AF_INET6; | |
| 100 } | |
| 101 } | |
| 102 } | |
| 103 __fclose_ca(f); | |
| 104 no_resolv_conf: | |
| 105 if (!nns) { | |
| 106 ns[0].sin.sin_family = AF_INET; | |
| 107 ns[0].sin.sin_port = htons(53); | |
| 108 ns[0].sin.sin_addr.s_addr = htonl(0x7f000001); | |
| 109 nns=1; | |
| 110 } | 69 } |
| 111 | 70 |
| 112 /* Get local address and open/bind a socket */ | 71 /* Get local address and open/bind a socket */ |
| 113 sa.sin.sin_family = family; | 72 sa.sin.sin_family = family; |
| 114 fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); | 73 fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); |
| 115 | 74 |
| 116 /* Handle case where system lacks IPv6 support */ | 75 /* Handle case where system lacks IPv6 support */ |
| 117 if (fd < 0 && family == AF_INET6 && errno == EAFNOSUPPORT) { | 76 if (fd < 0 && family == AF_INET6 && errno == EAFNOSUPPORT) { |
| 118 fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); | 77 fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); |
| 119 family = AF_INET; | 78 family = AF_INET; |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 memcpy(answers[i], answers[next], rlen); | 168 memcpy(answers[i], answers[next], rlen); |
| 210 | 169 |
| 211 if (next == nqueries) goto out; | 170 if (next == nqueries) goto out; |
| 212 } | 171 } |
| 213 } | 172 } |
| 214 out: | 173 out: |
| 215 pthread_cleanup_pop(1); | 174 pthread_cleanup_pop(1); |
| 216 | 175 |
| 217 return 0; | 176 return 0; |
| 218 } | 177 } |
| 178 |
| 179 int __res_msend(int nqueries, const unsigned char *const *queries, |
| 180 const int *qlens, unsigned char *const *answers, int *alens, int asize) |
| 181 { |
| 182 struct resolvconf conf; |
| 183 if (__get_resolv_conf(&conf, 0, 0) < 0) return -1; |
| 184 return __res_msend_rc(nqueries, queries, qlens, answers, alens, asize, &
conf); |
| 185 } |
| OLD | NEW |