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 __syscall(SYS_close, (intptr_t)p); |
19 » __syscall(SYS_close, (intptr_t)p); | |
20 } | 19 } |
21 | 20 |
22 static unsigned long mtime() | 21 static unsigned long mtime() { |
23 { | 22 struct timespec ts; |
24 » struct timespec ts; | 23 clock_gettime(CLOCK_REALTIME, &ts); |
25 » clock_gettime(CLOCK_REALTIME, &ts); | 24 return (unsigned long)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; |
26 » return (unsigned long)ts.tv_sec * 1000 | |
27 » » + ts.tv_nsec / 1000000; | |
28 } | 25 } |
29 | 26 |
30 int __res_msend_rc(int nqueries, const unsigned char *const *queries, | 27 int __res_msend_rc(int nqueries, |
31 » const int *qlens, unsigned char *const *answers, int *alens, int asize, | 28 const unsigned char* const* queries, |
32 » const struct resolvconf *conf) | 29 const int* qlens, |
33 { | 30 unsigned char* const* answers, |
34 » int fd; | 31 int* alens, |
35 » int timeout, attempts, retry_interval, servfail_retry; | 32 int asize, |
36 » union { | 33 const struct resolvconf* conf) { |
37 » » struct sockaddr_in sin; | 34 int fd; |
38 » » struct sockaddr_in6 sin6; | 35 int timeout, attempts, retry_interval, servfail_retry; |
39 » } sa = {0}, ns[MAXNS] = {{0}}; | 36 union { |
40 » socklen_t sl = sizeof sa.sin; | 37 struct sockaddr_in sin; |
41 » int nns = 0; | 38 struct sockaddr_in6 sin6; |
42 » int family = AF_INET; | 39 } sa = {0}, ns[MAXNS] = {{0}}; |
43 » int rlen; | 40 socklen_t sl = sizeof sa.sin; |
44 » int next; | 41 int nns = 0; |
45 » int i, j; | 42 int family = AF_INET; |
46 » int cs; | 43 int rlen; |
47 » struct pollfd pfd; | 44 int next; |
48 » unsigned long t0, t1, t2; | 45 int i, j; |
| 46 int cs; |
| 47 struct pollfd pfd; |
| 48 unsigned long t0, t1, t2; |
49 | 49 |
50 » pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); | 50 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); |
51 | 51 |
52 » timeout = 1000*conf->timeout; | 52 timeout = 1000 * conf->timeout; |
53 » attempts = conf->attempts; | 53 attempts = conf->attempts; |
54 | 54 |
55 » nns = conf->nns; | 55 nns = conf->nns; |
56 » for (nns=0; nns<conf->nns; nns++) { | 56 for (nns = 0; nns < conf->nns; nns++) { |
57 » » const struct address *iplit = &conf->ns[nns]; | 57 const struct address* iplit = &conf->ns[nns]; |
58 » » if (iplit->family == AF_INET) { | 58 if (iplit->family == AF_INET) { |
59 » » » memcpy(&ns[nns].sin.sin_addr, iplit->addr, 4); | 59 memcpy(&ns[nns].sin.sin_addr, iplit->addr, 4); |
60 » » » ns[nns].sin.sin_port = htons(53); | 60 ns[nns].sin.sin_port = htons(53); |
61 » » » ns[nns].sin.sin_family = AF_INET; | 61 ns[nns].sin.sin_family = AF_INET; |
62 » » } else { | 62 } else { |
63 » » » sl = sizeof sa.sin6; | 63 sl = sizeof sa.sin6; |
64 » » » memcpy(&ns[nns].sin6.sin6_addr, iplit->addr, 16); | 64 memcpy(&ns[nns].sin6.sin6_addr, iplit->addr, 16); |
65 » » » ns[nns].sin6.sin6_port = htons(53); | 65 ns[nns].sin6.sin6_port = htons(53); |
66 » » » ns[nns].sin6.sin6_scope_id = iplit->scopeid; | 66 ns[nns].sin6.sin6_scope_id = iplit->scopeid; |
67 » » » ns[nns].sin6.sin6_family = family = AF_INET6; | 67 ns[nns].sin6.sin6_family = family = AF_INET6; |
68 » » } | 68 } |
69 » } | 69 } |
70 | 70 |
71 » /* Get local address and open/bind a socket */ | 71 /* Get local address and open/bind a socket */ |
72 » sa.sin.sin_family = family; | 72 sa.sin.sin_family = family; |
73 » fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); | 73 fd = socket(family, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); |
74 | 74 |
75 » /* Handle case where system lacks IPv6 support */ | 75 /* Handle case where system lacks IPv6 support */ |
76 » if (fd < 0 && family == AF_INET6 && errno == EAFNOSUPPORT) { | 76 if (fd < 0 && family == AF_INET6 && errno == EAFNOSUPPORT) { |
77 » » fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); | 77 fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); |
78 » » family = AF_INET; | 78 family = AF_INET; |
79 » } | 79 } |
80 » if (fd < 0 || bind(fd, (void *)&sa, sl) < 0) return -1; | 80 if (fd < 0 || bind(fd, (void*)&sa, sl) < 0) |
| 81 return -1; |
81 | 82 |
82 » /* Past this point, there are no errors. Each individual query will | 83 /* Past this point, there are no errors. Each individual query will |
83 » * yield either no reply (indicated by zero length) or an answer | 84 * yield either no reply (indicated by zero length) or an answer |
84 » * packet which is up to the caller to interpret. */ | 85 * packet which is up to the caller to interpret. */ |
85 | 86 |
86 » pthread_cleanup_push(cleanup, (void *)(intptr_t)fd); | 87 pthread_cleanup_push(cleanup, (void*)(intptr_t)fd); |
87 » pthread_setcancelstate(cs, 0); | 88 pthread_setcancelstate(cs, 0); |
88 | 89 |
89 » /* Convert any IPv4 addresses in a mixed environment to v4-mapped */ | 90 /* Convert any IPv4 addresses in a mixed environment to v4-mapped */ |
90 » if (family == AF_INET6) { | 91 if (family == AF_INET6) { |
91 » » setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0); | 92 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0); |
92 » » for (i=0; i<nns; i++) { | 93 for (i = 0; i < nns; i++) { |
93 » » » if (ns[i].sin.sin_family != AF_INET) continue; | 94 if (ns[i].sin.sin_family != AF_INET) |
94 » » » memcpy(ns[i].sin6.sin6_addr.s6_addr+12, | 95 continue; |
95 » » » » &ns[i].sin.sin_addr, 4); | 96 memcpy(ns[i].sin6.sin6_addr.s6_addr + 12, &ns[i].sin.sin_addr, 4); |
96 » » » memcpy(ns[i].sin6.sin6_addr.s6_addr, | 97 memcpy(ns[i].sin6.sin6_addr.s6_addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); |
97 » » » » "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); | 98 ns[i].sin6.sin6_family = AF_INET6; |
98 » » » ns[i].sin6.sin6_family = AF_INET6; | 99 ns[i].sin6.sin6_flowinfo = 0; |
99 » » » ns[i].sin6.sin6_flowinfo = 0; | 100 ns[i].sin6.sin6_scope_id = 0; |
100 » » » ns[i].sin6.sin6_scope_id = 0; | 101 } |
101 » » } | 102 } |
102 » } | |
103 | 103 |
104 » memset(alens, 0, sizeof *alens * nqueries); | 104 memset(alens, 0, sizeof *alens * nqueries); |
105 | 105 |
106 » pfd.fd = fd; | 106 pfd.fd = fd; |
107 » pfd.events = POLLIN; | 107 pfd.events = POLLIN; |
108 » retry_interval = timeout / attempts; | 108 retry_interval = timeout / attempts; |
109 » next = 0; | 109 next = 0; |
110 » t0 = t2 = mtime(); | 110 t0 = t2 = mtime(); |
111 » t1 = t2 - retry_interval; | 111 t1 = t2 - retry_interval; |
112 | 112 |
113 » for (; t2-t0 < timeout; t2=mtime()) { | 113 for (; t2 - t0 < timeout; t2 = mtime()) { |
114 » » if (t2-t1 >= retry_interval) { | 114 if (t2 - t1 >= retry_interval) { |
115 » » » /* Query all configured namservers in parallel */ | 115 /* Query all configured namservers in parallel */ |
116 » » » for (i=0; i<nqueries; i++) | 116 for (i = 0; i < nqueries; i++) |
117 » » » » if (!alens[i]) | 117 if (!alens[i]) |
118 » » » » » for (j=0; j<nns; j++) | 118 for (j = 0; j < nns; j++) |
119 » » » » » » sendto(fd, queries[i], | 119 sendto(fd, queries[i], qlens[i], MSG_NOSIGNAL, (void*)&ns[j], sl); |
120 » » » » » » » qlens[i], MSG_NOSIGNAL, | 120 t1 = t2; |
121 » » » » » » » (void *)&ns[j], sl); | 121 servfail_retry = 2 * nqueries; |
122 » » » t1 = t2; | 122 } |
123 » » » servfail_retry = 2 * nqueries; | |
124 » » } | |
125 | 123 |
126 » » /* Wait for a response, or until time to retry */ | 124 /* Wait for a response, or until time to retry */ |
127 » » if (poll(&pfd, 1, t1+retry_interval-t2) <= 0) continue; | 125 if (poll(&pfd, 1, t1 + retry_interval - t2) <= 0) |
| 126 continue; |
128 | 127 |
129 » » while ((rlen = recvfrom(fd, answers[next], asize, 0, | 128 while ((rlen = recvfrom(fd, answers[next], asize, 0, (void*)&sa, |
130 » » (void *)&sa, (socklen_t[1]){sl})) >= 0) { | 129 (socklen_t[1]){sl})) >= 0) { |
| 130 /* Ignore non-identifiable packets */ |
| 131 if (rlen < 4) |
| 132 continue; |
131 | 133 |
132 » » » /* Ignore non-identifiable packets */ | 134 /* Ignore replies from addresses we didn't send to */ |
133 » » » if (rlen < 4) continue; | 135 for (j = 0; j < nns && memcmp(ns + j, &sa, sl); j++) |
| 136 ; |
| 137 if (j == nns) |
| 138 continue; |
134 | 139 |
135 » » » /* Ignore replies from addresses we didn't send to */ | 140 /* Find which query this answer goes with, if any */ |
136 » » » for (j=0; j<nns && memcmp(ns+j, &sa, sl); j++); | 141 for (i = next; i < nqueries && (answers[next][0] != queries[i][0] || |
137 » » » if (j==nns) continue; | 142 answers[next][1] != queries[i][1]); |
| 143 i++) |
| 144 ; |
| 145 if (i == nqueries) |
| 146 continue; |
| 147 if (alens[i]) |
| 148 continue; |
138 | 149 |
139 » » » /* Find which query this answer goes with, if any */ | 150 /* Only accept positive or negative responses; |
140 » » » for (i=next; i<nqueries && ( | 151 * retry immediately on server failure, and ignore |
141 » » » » answers[next][0] != queries[i][0] || | 152 * all other codes such as refusal. */ |
142 » » » » answers[next][1] != queries[i][1] ); i++); | 153 switch (answers[next][3] & 15) { |
143 » » » if (i==nqueries) continue; | 154 case 0: |
144 » » » if (alens[i]) continue; | 155 case 3: |
| 156 break; |
| 157 case 2: |
| 158 if (servfail_retry && servfail_retry--) |
| 159 sendto(fd, queries[i], qlens[i], MSG_NOSIGNAL, (void*)&ns[j], sl); |
| 160 default: |
| 161 continue; |
| 162 } |
145 | 163 |
146 » » » /* Only accept positive or negative responses; | 164 /* Store answer in the right slot, or update next |
147 » » » * retry immediately on server failure, and ignore | 165 * available temp slot if it's already in place. */ |
148 » » » * all other codes such as refusal. */ | 166 alens[i] = rlen; |
149 » » » switch (answers[next][3] & 15) { | 167 if (i == next) |
150 » » » case 0: | 168 for (; next < nqueries && alens[next]; next++) |
151 » » » case 3: | 169 ; |
152 » » » » break; | 170 else |
153 » » » case 2: | 171 memcpy(answers[i], answers[next], rlen); |
154 » » » » if (servfail_retry && servfail_retry--) | |
155 » » » » » sendto(fd, queries[i], | |
156 » » » » » » qlens[i], MSG_NOSIGNAL, | |
157 » » » » » » (void *)&ns[j], sl); | |
158 » » » default: | |
159 » » » » continue; | |
160 » » » } | |
161 | 172 |
162 » » » /* Store answer in the right slot, or update next | 173 if (next == nqueries) |
163 » » » * available temp slot if it's already in place. */ | 174 goto out; |
164 » » » alens[i] = rlen; | 175 } |
165 » » » if (i == next) | 176 } |
166 » » » » for (; next<nqueries && alens[next]; next++); | 177 out: |
167 » » » else | 178 pthread_cleanup_pop(1); |
168 » » » » memcpy(answers[i], answers[next], rlen); | |
169 | 179 |
170 » » » if (next == nqueries) goto out; | 180 return 0; |
171 » » } | |
172 » } | |
173 out: | |
174 » pthread_cleanup_pop(1); | |
175 | |
176 » return 0; | |
177 } | 181 } |
178 | 182 |
179 int __res_msend(int nqueries, const unsigned char *const *queries, | 183 int __res_msend(int nqueries, |
180 » const int *qlens, unsigned char *const *answers, int *alens, int asize) | 184 const unsigned char* const* queries, |
181 { | 185 const int* qlens, |
182 » struct resolvconf conf; | 186 unsigned char* const* answers, |
183 » if (__get_resolv_conf(&conf, 0, 0) < 0) return -1; | 187 int* alens, |
184 » return __res_msend_rc(nqueries, queries, qlens, answers, alens, asize, &
conf); | 188 int asize) { |
| 189 struct resolvconf conf; |
| 190 if (__get_resolv_conf(&conf, 0, 0) < 0) |
| 191 return -1; |
| 192 return __res_msend_rc(nqueries, queries, qlens, answers, alens, asize, &conf); |
185 } | 193 } |
OLD | NEW |