1 #include "ldapdns.h"
2 #include "ip.h"
3 #include "env.h"
4 #include "config.h"
5 #include "sio.h"
6 #include "bin.h"
7
8 static int server_fd = -1;
9 static char tcpserver_ip[IP_LEN];
10 static int tcpserver_port;
11 static bin_t tcpserver_active;
12 #ifdef HAVE_IPV6
13 static int using_6 = 0;
14 #endif
15
tp_close(dns_ctx * c)16 void tp_close(dns_ctx *c)
17 {
18 if (server_fd != -1) {
19 /* shutdown this connection */
20 pthread_mutex_lock(&c->lock);
21 close(c->sock);
22 c->sock = -1;
23 pthread_mutex_unlock(&c->lock);
24 } else {
25 /* then exit; we're a uniprocess hosted by
26 * tcpserver or something */
27 exit(0);
28 }
29 }
tp_housekeeping(long * now)30 void inline tp_housekeeping(long *now)
31 {
32 dns_ctx *p;
33
34 if (server_fd == -1)
35 return;
36
37 /* run a poll on all sockets */
38 reload_l:
39 sio_flush(tcpserver_active);
40 sio_add(tcpserver_active, server_fd, sio_read);
41
42 for (p = handler; p; p = p->next) {
43 if (p->sock == -1) continue;
44 sio_add(tcpserver_active, p->sock, sio_read);
45 }
46
47 if (ldapdns.timeout_tcp > 0) {
48 if (sio_block(tcpserver_active, ldapdns.timeout_tcp) == 0) {
49 goto reload_l;
50 }
51 } else {
52 sio_block(tcpserver_active, sio_infinity);
53 }
54 }
55
tp_initialize(void)56 void tp_initialize(void)
57 {
58 char *x;
59 int port;
60
61 server_fd = -1;
62 ldapdns.dns_threads = 1; /* always 1; we use select */
63
64 x = env_get("TCPREMOTEIP");
65 if (!x || !ipv4_scan(x, tcpserver_ip) ) {
66 tcpserver_ip[0] = 0;
67 tcpserver_ip[1] = 0;
68 tcpserver_ip[2] = 0;
69 tcpserver_ip[3] = 0;
70 } else {
71 /* tcpserver or clone */
72 ldapdns.ldap_threads = 1;
73 ldapdns.handlers = 1;
74
75 x = env_get("TCPREMOTEPORT");
76 if (!x) {
77 tcpserver_port = 0;
78 } else if ((tcpserver_port = atoi(x)) < 1) {
79 tcpserver_port = 0;
80 }
81 return;
82 }
83
84 if (socket_peer4(0, tcpserver_ip, &tcpserver_port)) {
85 /* okay, we're running xinetd */
86 ldapdns.ldap_threads = 1;
87 ldapdns.dns_threads = 1;
88 ldapdns.handlers = 1;
89 return;
90 }
91
92 /* okay, we're not attached to a socket; let's change that */
93 x = env_get("IP");
94 if (!x)
95 x = "0.0.0.0";
96 if (!ipv4_scan(x, tcpserver_ip)) {
97 #ifdef HAVE_IPV6
98 if (ipv6_scan(x, tcpserver_ip))
99 using_6 = 1;
100 else
101 #endif
102 fatal("cannot parse IP: %s", x);
103 }
104
105 x = env_get("PORT");
106 if (!x)
107 port = 53;
108 else {
109 port = atoi(x);
110 if (port < 1)
111 fatal("cannot parse PORT: %s", x);
112 if (port != 53)
113 warning("running on non-standard port: %d", port);
114 }
115
116 #ifdef HAVE_IPV6
117 if (using_6)
118 server_fd = socket_tcp6();
119 else
120 #endif
121 server_fd = socket_tcp4();
122 if (server_fd == -1)
123 cfatal("socket_tcp: %s");
124 #ifdef HAVE_IPV6
125 if (using_6) {
126 if (socket_bind6_reuse(server_fd, tcpserver_ip, port) == -1)
127 cfatal("socket_bind4_reuse: %s");
128 } else
129 #endif
130 if (socket_bind4_reuse(server_fd, tcpserver_ip, port) == -1)
131 cfatal("socket_bind4_reuse: %s");
132 socket_listen(server_fd);
133 ndelay_on(server_fd);
134 bin_init(tcpserver_active);
135 }
tp_write(dns_ctx * c)136 int inline tp_write(dns_ctx *c)
137 {
138 int x, r;
139 unsigned short ntcplen;
140
141 /* we lock here to make certain our socket isn't pulled out from
142 * under us
143 */
144 pthread_mutex_lock(&c->lock);
145 if (c->sock == -1) {
146 pthread_mutex_unlock(&c->lock);
147 return 0;
148 }
149
150 /* Clib */
151 ntcplen = ntohs(clen(c->response));
152
153 /* this COULD hang. however, i don't find it too likely to cause
154 * any problems: the client will hangup eventually and we'll get EPIPE
155 */
156
157 do {
158 r = write(c->sock, &ntcplen, 2);
159 } while (r == -1 && errno == EINTR);
160 pthread_mutex_unlock(&c->lock);
161
162 for (x = 0; x < clen(c->response);) {
163 /* we're spinning this lock because this process cannot
164 * tell when hangup occurs
165 */
166 pthread_mutex_lock(&c->lock);
167 if (c->sock == -1) {
168 /* stolen out from under us */
169 pthread_mutex_unlock(&c->lock);
170 return 0;
171 }
172 /* still valid */
173 r = write(c->sock,
174 caddr(c->response) + x,
175 clen(c->response) - x);
176 pthread_mutex_unlock(&c->lock);
177
178 if (r == -1) {
179 if (errno == EPIPE || errno == EBADF || errno == EINVAL || errno == EFAULT) {
180 /* failed output */
181 return 0;
182 }
183 continue;
184 }
185
186 if (!r) {
187 /* sleep for a moment;
188 * just in case it was kernel related */
189 usleep(100);
190 }
191
192 x += r;
193 }
194 return 1;
195 }
trash_message(dns_ctx * c)196 static int inline trash_message (dns_ctx *c)
197 {
198 register int i, j;
199
200 if (c->tcplen == 0) return 0;
201 if (c->tcppos < c->tcplen) return 0;
202
203 /* move memory in request_buf */
204 j = c->tcplen+2;
205 for (i = 0; i < j;) {
206 c->request_buf[i] = c->request_buf[j]; i++; if (i == j) break;
207 c->request_buf[i] = c->request_buf[j]; i++; if (i == j) break;
208 c->request_buf[i] = c->request_buf[j]; i++; if (i == j) break;
209 c->request_buf[i] = c->request_buf[j]; i++; if (i == j) break;
210 c->request_buf[i] = c->request_buf[j]; i++; if (i == j) break;
211 c->request_buf[i] = c->request_buf[j]; i++; if (i == j) break;
212 c->request_buf[i] = c->request_buf[j]; i++; if (i == j) break;
213 c->request_buf[i] = c->request_buf[j]; i++; if (i == j) break;
214 }
215 c->tcppos -= j;
216 c->tcplen = 0;
217 c->request_len = 0;
218 c->request_pos = 0;
219 if (c->tcppos == 0)
220 return 0;
221 return 1;
222 }
tp_read(dns_ctx * c)223 int inline tp_read(dns_ctx *c)
224 {
225 int fd, len = 0;
226 unsigned short ntcplen;
227 list_t ax;
228 str_t retbuf;
229
230 if (server_fd == -1) {
231 c->ip[0] = tcpserver_ip[0];
232 c->ip[1] = tcpserver_ip[1];
233 c->ip[2] = tcpserver_ip[2];
234 c->ip[3] = tcpserver_ip[3];
235 c->port = tcpserver_port;
236 c->sock = 1;
237 fd = 0;
238 } else {
239 /* could be hung at this point */
240 pthread_mutex_lock(&c->lock);
241 if (c->sock == -1) {
242 pthread_mutex_unlock(&c->lock);
243
244 /* see if we can accept server_fd */
245 if (!sio_test(tcpserver_active, server_fd)) {
246 /* we'll come back later */
247 return -1;
248 }
249 sio_remove(tcpserver_active, server_fd);
250
251 /* we'll have to do a round before this guy can have
252 * activity performed
253 */
254 #ifdef HAVE_IPV6
255 if (using_6) {
256 c->sock = socket_accept6(server_fd, c->ip, &c->port);
257 } else
258 c->sock = socket_accept4(server_fd, c->ip, &c->port);
259 #endif
260 c->tcppos = 0;
261 c->tcplen = 0;
262 c->request_pos = 0;
263 return 0;
264 } else {
265 /* both sides are socket */
266 if (!sio_test(tcpserver_active, c->sock)) {
267 pthread_mutex_unlock(&c->lock);
268 if (trash_message(c))
269 goto past_read_shortcut_l;
270 return 0;
271 }
272 sio_remove(tcpserver_active, c->sock);
273
274 /* fall through */
275 fd = c->sock;
276 pthread_mutex_unlock(&c->lock);
277 }
278 }
279
280 trash_message(c);
281 reread_shortcut_l:
282 do {
283 /* fd cannot be stolen out from under us;
284 * because the thread that does this is the only
285 * one that closes the socket
286 */
287 len = read(fd, /* stdin */
288 c->request_buf + c->tcppos,
289 512 - c->tcppos);
290 /* infinite if 0 hangs up */
291 if (len == -1) {
292 /* we'll be back */
293 if (errno == EAGAIN || errno == EINTR) {
294 return 0;
295 }
296
297 if (errno == EBADF || errno == EINVAL
298 || errno == EFAULT)
299 goto FATAL;
300 } else if (len == 0) {
301 /* hung up */
302 goto FATAL;
303 }
304 } while (len <= 0);
305 if (len >= 512) {
306 warning("read too long");
307 goto FATAL;
308 }
309 past_read_shortcut_l:
310 if (c->tcplen == 0) {
311 /* the BEGINNING of a tcp message is packet length */
312 c->request_len += len; /* fudge for now */
313 if (!dns_packet_copy(c, (char *)&ntcplen, 2)) {
314 /* not enough room yet... */
315 if (server_fd == -1)
316 goto reread_shortcut_l;
317 return 0;
318 }
319 /* Clib */
320 c->tcplen = ntohs(ntcplen);
321 if (c->tcplen > 512) {
322 warning("read too long");
323 goto FATAL;
324 }
325 }
326
327 c->tcppos += len;
328 if (c->tcppos < c->tcplen) {
329 if (server_fd == -1)
330 goto reread_shortcut_l;
331 /* incomplete message */
332 return 0;
333 }
334 if (ldapdns.update)
335 c->update = str_dup(ldapdns.update);
336 else
337 c->update = 0;
338 if (ldapdns.axfr_base)
339 c->axfr_base = str_dup(ldapdns.axfr_base);
340 else
341 c->axfr_base = 0;
342 c->request_len = c->tcplen + 2;
343
344 /* not in server mode? we don't need to do anything else */
345 if (server_fd == -1)
346 return 1;
347
348 /* calculated AXFR support */
349 for (ax = ldapdns.swaxfr; ax; ax = ax->next) {
350 if (!ax->str) continue;
351 if (ax->str[0] == 0x04) {
352 if (ipv4_in_subnet(ax->str+1, c->ip)) {
353 if (!ax->str[9]) {
354 if (c->axfr_base) mem_free(c->axfr_base);
355 c->axfr_base = 0;
356 if (!ipv4_null(ax->str+1))
357 break;
358 continue;
359 }
360 name_to_dns(retbuf, ax->str + 9);
361 if (c->axfr_base) mem_free(c->axfr_base);
362 c->axfr_base = str(retbuf);
363 if (!ipv4_null(ax->str+1))
364 break;
365 }
366 #ifdef HAVE_IPV6
367 } else if (ax->str[0] == 0x06) {
368 if (ipv6_in_subnet(ax->str+1, c->ip)) {
369 if (!ax->str[33]) {
370 if (c->axfr_base) mem_free(c->axfr_base);
371 c->axfr_base = 0;
372 if (!ipv4_null(ax->str+1))
373 break;
374 continue;
375 }
376 name_to_dns(retbuf, ax->str + 33);
377 if (c->axfr_base) mem_free(c->axfr_base);
378 c->axfr_base = str(retbuf);
379 if (!ipv6_null(ax->str+1))
380 break;
381 }
382 #endif
383 }
384 }
385
386 return 1;
387 FATAL:
388 if (server_fd == -1)
389 exit(0);
390
391 /* lock to remove */
392 pthread_mutex_lock(&c->lock);
393 close(c->sock);
394 c->sock = -1;
395 pthread_mutex_unlock(&c->lock);
396 return 0;
397 }
398
399