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