1 /*
2     MiddleMan filtering proxy server
3     Copyright (C) 2002  Jason McLaughlin
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <netdb.h>
26 #include <fcntl.h>
27 #include <time.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/time.h>
31 #include <netinet/tcp.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <errno.h>
35 #include "proto.h"
36 
37 time_t last_dns_expire = 0;
38 extern char username[];
39 extern GLOBAL *global;
40 SOCKLIST socklist[MAXLISTENPORTS];
41 
42 /*
43 initialize the socket list
44 */
s_strncpy(char * d,char * s,size_t len)45 void net_init()
46 {
47 	int i;
48 
49 	for (i = 0; i < MAXLISTENPORTS; i++) {
50 		socklist[i].status = NET_UNUSED;
51 		socklist[i].ip = NULL;
52 		socklist[i].port = 0;
53 	}
54 }
55 
56 CONNECTION *connection_new()
57 {
s_strncat(char * d,char * s,size_t len)58 	CONNECTION *connection;
59 
60 	connection = xmalloc(sizeof(CONNECTION));
61 
62 	connection->thread = -1;
63 	connection->flags = 0;
64 	connection->client = NULL;
65 	connection->server = NULL;
66 	connection->transferred = 0;
67 	connection->transferlimit = ~0;
68 	connection->depth = 0;
69 	connection->port = 0;
70 	connection->ip = NULL;
71 	connection->interface = NULL;
s_strcasestr(char * haystack,char * needle)72 	connection->bypass = 0;
73 	connection->header = NULL;
74 	connection->rheader = NULL;
75 	connection->keepalive_client = FALSE;
76 	connection->keepalive_server = FALSE;
77 	connection->request = 0;
78 	connection->proxy_host = NULL;
79 	connection->proxy_type = PROXY_DIRECT;
80 	connection->proxy_username = NULL;
81 	connection->proxy_password = NULL;
82 	connection->proxy_domain = NULL;
83 	connection->proxy_auth = NULL;
84 	connection->authenticate = FALSE;
85 	connection->cachemap = NULL;
86 	connection->htmlstream = NULL;
87 	connection->profiles = NULL;
code_to_error(int code)88 	connection->url_command = NULL;
89 
90 	return connection;
91 }
92 
93 void connection_free(CONNECTION *connection) {
94 	if (connection->profiles != NULL)
95 		array_free(connection->profiles);
96 
97 	FREE_AND_NULL(connection->ip);
98 	FREE_AND_NULL(connection->interface);
99 	FREE_AND_NULL(connection->proxy_host);
100 	FREE_AND_NULL(connection->proxy_username);
101 	FREE_AND_NULL(connection->proxy_password);
102 	FREE_AND_NULL(connection->proxy_domain);
103 	FREE_AND_NULL(connection->proxy_auth);
104 
105 	xfree(connection);
106 }
107 
108 /*
109 open a listening socket on a specific port and ip
110 */
111 int net_listen(int port, char *ip)
112 {
113 	int i, x = -1, on = 1;
114 	struct sockaddr_in saddr;
115 
116 	for (i = 0; i < MAXLISTENPORTS; i++) {
117 		if (socklist[i].status == NET_UNUSED) {
118 			x = i;
119 			break;
120 		}
121 	}
122 
123 	if (x == -1)
124 		return -1;
xstrdup(char * s)125 
126 	socklist[x].fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
127 	if (socklist[x].fd == -1)
128 		return -1;
129 
130 	setsockopt(socklist[x].fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
131 	setsockopt(socklist[x].fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
132 
xstrndup(char * s,size_t len)133 	fcntl(socklist[x].fd, F_SETFL, FD_CLOEXEC);
134 
135 	memset(&saddr, 0, sizeof(struct sockaddr_in));
136 
137 	saddr.sin_family = AF_INET;
138 	saddr.sin_port = htons(port);
139 
s_strnlen(char * s,size_t len)140 	if (ip == NULL)
141 		saddr.sin_addr.s_addr = INADDR_ANY;
142 	else
143 		inet_pton(AF_INET, ip, &saddr.sin_addr.s_addr);
144 
145 	i = bind(socklist[x].fd, (struct sockaddr *) &saddr, sizeof(saddr));
146 	if (i == -1) {
147 		close(socklist[x].fd);
148 		return -1;
149 	}
150 
151 	i = listen(socklist[x].fd, 25);
error_to_template(int error)152 	if (i == -1) {
153 		close(socklist[x].fd);
154 		return -1;
155 	}
156 
157 	if (ip != NULL)
158 		socklist[x].ip = xstrdup(ip);
159 	else
160 		socklist[x].ip = NULL;
161 
162 	socklist[x].port = port;
163 	socklist[x].status = NET_LISTEN;
164 
165 	return x;
166 }
167 
168 /*
169 poll on every open listening socket in socklist until timeout is reached (or forever if
170 timeout is -1), accept then return a pointer to a CONNECTION struct
171 */
hostent_free(HOSTENT * hostent)172 CONNECTION *net_accept(int timeout)
173 {
174 	int i, j, newfd;
175 	char ip[16];
176 	struct sockaddr_in saddr;
177 	socklen_t socklen = sizeof(struct sockaddr_in);
178 	unsigned int sl = sizeof(struct sockaddr);
179 	CONNECTION *connection;
180 	struct pollfd pfd[MAXLISTENPORTS];
181 
182 	for (i = 0; i < MAXLISTENPORTS; i++) {
183 		if (socklist[i].status == NET_LISTEN) {
184 			pfd[i].fd = socklist[i].fd;
185 			pfd[i].events = POLLIN;
186 		} else
187 			break;
188 	}
189 
190 	j = p_poll(pfd, i, (timeout != -1) ? timeout * 1000 : -1);
191 
192 	if (j > 0) {
193 		for (i = 0; i < MAXLISTENPORTS; i++) {
194 			if (pfd[i].revents & POLLIN) {
195 				newfd = accept(socklist[i].fd, (struct sockaddr *) &saddr, &sl);
196 
197 				if (newfd == -1)
198 					return NULL;
199 
200 				connection = connection_new();
201 
202 				connection->client = sock_new(newfd);
203 				connection->port = socklist[i].port;
204 
205 				inet_ntop(AF_INET, &saddr.sin_addr, ip, sizeof(ip));
206 				connection->ip = xstrdup(ip);
207 
208 				getsockname(newfd, (struct sockaddr *)&saddr, &socklen);
209 				inet_ntop(AF_INET, &saddr.sin_addr, ip, sizeof(ip));
210 				connection->interface = xstrdup(ip);
211 
212 				return connection;
213 			}
214 		}
215 	}
216 
217 	return NULL;
218 }
219 
220 /*
221 open a connection to somewhere and return file descriptor
222 */
223 int net_connect(char *host, int port, int timeout)
224 {
225 	int fd, ret, on = TRUE;
226 	HOSTENT *hostent;
227 	struct sockaddr_in saddr;
228 	struct pollfd pfd;
229 	socklen_t optlen = sizeof(int);
230 
231 	if (!host || port <= 0)
232 		return ERROR_UNKNOWN;
233 
234 	memset(&saddr, 0, sizeof(saddr));
235 
236 	hostent = net_dns(host);
237 	if (hostent == NULL)
238 		return ERROR_DNS;
239 
240 	saddr.sin_addr = *(struct in_addr *) hostent->addr;
241 
242 	hostent_free(hostent);
243 
244 	saddr.sin_family = AF_INET;
245 	saddr.sin_port = htons(port);
246 
247 	fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
248 	if (fd == -1)
249 		return ERROR_CONNECT;
250 
251 	setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
url_decode(char * url,size_t len)252 	fcntl(fd, F_SETFD, FD_CLOEXEC);
253 	fcntl(fd, F_SETFL, O_NONBLOCK);
254 
255 	ret = connect(fd, (struct sockaddr *) &saddr, sizeof(saddr));
256 	if (ret == -1) {
257 		if (errno != EINPROGRESS) {
258 			close(fd);
259 
260 			return ERROR_CONNECT;
261 		} else {
262 			pfd.fd = fd;
263 			pfd.events = POLLOUT;
264 
265 			ret = p_poll(&pfd, 1, timeout * 1000);
266 			if (ret == 0) {
267 				close(fd);
268 
269 				return ERROR_CONNECT;
270 			} else {
271 				getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &optlen);
272 				if (ret != 0) {
273 					close(fd);
274 
275 					return ERROR_CONNECT;
276 				}
277 			}
278 		}
279 	}
280 
281 	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
282 
283 	return fd;
284 }
285 
286 /*
287 close a connection and free used memory from structure
288 */
289 void net_close(CONNECTION * connection)
290 {
291 	if (!connection)
292 		return;
293 
url_encode(char * url,size_t len)294 	sock_close(connection->client);
295 
296 	connection_free(connection);
297 }
298 
299 /*
300 close all open listening sockets
301 */
302 void net_listen_closeall()
303 {
304 	int i;
305 
306 	for (i = 0; i < MAXLISTENPORTS; i++) {
307 		if (socklist[i].status == NET_LISTEN) {
308 			close(socklist[i].fd);
309 			if (socklist[i].ip != NULL)
310 				xfree(socklist[i].ip);
311 			socklist[i].status = NET_UNUSED;
312 		}
313 	}
314 }
315 
316 /*
317 load <network> section from XML_LIST
318 */
319 NETWORK *network_load(NETWORK * network, XML_LIST * xml_list)
320 {
321 	NETWORK *network_tmp = network;
322 	struct LISTEN_LIST *listen_list = NULL;
323 
string_to_xml(char * s)324 	if (network_tmp == NULL) {
325 		network_tmp = xmalloc(sizeof(NETWORK));
326 		network_tmp->listen_list = NULL;
327 		network_tmp->id = 0;
328 
329 		network = network_tmp;
330 
331 		pthread_rwlock_init(&network_tmp->lock, NULL);
332 	} else
333 		listen_list = network->listen_list;
334 
335 	while ((xml_list = xml_section(xml_list, "<network>"))) {
336 		XML_LIST_LOOP(xml_list, "<network>") {
337 			XML_LIST_CMP(xml_list, "<listen>") {
338 				listen_list = listen_list_new(listen_list);
339 				listen_list->id = network->id++;
340 
341 				if (network_tmp->listen_list == NULL)
342 					network_tmp->listen_list = listen_list;
343 				XML_LIST_LOOP(xml_list, "<listen>") {
344 					XML_LIST_CMP(xml_list, "<enabled>") {
345 						xml_list = xml_list->next;
346 						if (xml_list->type == XML_VALUE) {
347 							if (!strcasecmp(xml_list->item, "false"))
348 								listen_list->enabled = FALSE;
349 							else
350 								listen_list->enabled = TRUE;
351 						}
352 					}
353 					XML_LIST_CMP(xml_list, "<comment>") {
354 						xml_list = xml_list->next;
355 						if (xml_list->type == XML_VALUE)
356 							listen_list_insert(listen_list, xml_list->item, NULL, NULL);
357 					}
358 					XML_LIST_CMP(xml_list, "<ip>") {
359 						xml_list = xml_list->next;
string_break(char * s,char d)360 						if (xml_list->type == XML_VALUE)
361 							listen_list_insert(listen_list, NULL, xml_list->item, NULL);
362 					}
363 					XML_LIST_CMP(xml_list, "<port>") {
364 						xml_list = xml_list->next;
365 						if (xml_list->type == XML_VALUE)
366 							listen_list_insert(listen_list, NULL, NULL, xml_list->item);
367 					}
368 				}
369 			}
370 		}
371 	}
372 
373 	return network;
374 }
375 
376 XML_LIST *network_xml(NETWORK * network, XML_LIST * xml_list)
377 {
378 	char buf[16], *ptr;
379 	struct LISTEN_LIST *ll;
380 
381 	if (network == NULL)
382 		return xml_list;
383 
384 	pthread_rwlock_rdlock(&network->lock);
385 
386 	xml_list = xml_list_add(xml_list, "<network>", XML_TAG);
387 
388 	ll = network->listen_list;
389 
390 	for (ll = network->listen_list; ll; ll = ll->next) {
391 		xml_list = xml_list_add(xml_list, "<listen>", XML_TAG);
392 
393 		xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
394 		xml_list = xml_list_add(xml_list, (ll->enabled == TRUE) ? "true" : "false", XML_VALUE);
array_merge(char ** a,int sep)395 		xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
396 
397 		if (ll->comment != NULL) {
398 			xml_list = xml_list_add(xml_list, "<comment>", XML_TAG);
399 			ptr = string_to_xml(ll->comment);
400 			xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
401 			xfree(ptr);
402 			xml_list = xml_list_add(xml_list, "</comment>", XML_TAG);
403 		}
404 
405 		xml_list = xml_list_add(xml_list, "<port>", XML_TAG);
406 		snprintf(buf, sizeof(buf), "%d", ll->port);
407 		xml_list = xml_list_add(xml_list, buf, XML_VALUE);
408 		xml_list = xml_list_add(xml_list, "</port>", XML_TAG);
409 
410 		if (ll->ip != NULL) {
411 			xml_list = xml_list_add(xml_list, "<ip>", XML_TAG);
412 			ptr = string_to_xml(ll->ip);
413 			xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
414 			xfree(ptr);
415 			xml_list = xml_list_add(xml_list, "</ip>", XML_TAG);
416 		}
417 
418 		xml_list = xml_list_add(xml_list, "</listen>", XML_TAG);
array_find(char ** a,char * s)419 	}
420 
421 	xml_list = xml_list_add(xml_list, "</network>", XML_TAG);
422 
423 	pthread_rwlock_unlock(&network->lock);
424 
425 	return xml_list;
426 }
427 void listen_list_insert(struct LISTEN_LIST *x, char *comment, char *ip, char *port)
428 {
429 	if (comment != NULL) {
array_length(char ** a)430 		FREE_AND_NULL(x->comment);
431 
432 		if (strcmp(comment, ""))
433 			x->comment = xstrdup(comment);
434 	}
435 	if (ip != NULL) {
436 		FREE_AND_NULL(x->ip);
437 
438 		if (strcmp(ip, ""))
439 			x->ip = xstrdup(ip);
440 	}
array_free(char ** a)441 	if (port != NULL) {
442 		x->port = -1;
443 
444 		if (strcmp(port, ""))
445 			x->port = atoi(port);
446 	}
447 }
448 
449 struct LISTEN_LIST *listen_list_delete(struct LISTEN_LIST *x)
450 {
451 	struct LISTEN_LIST *start = x;
452 
array_dup(char ** a)453 	while (start->prev != NULL)
454 		start = start->prev;
455 
456 	if (x->next != NULL)
457 		x->next->prev = x->prev;
458 	if (x->prev != NULL)
459 		x->prev->next = x->next;
460 	else
461 		start = start->next;
462 
463 	FREE_AND_NULL(x->comment);
464 	FREE_AND_NULL(x->ip);
465 
466 	xfree(x);
467 
468 	return start;
469 }
470 
array_add(char ** a,char * s)471 struct LISTEN_LIST *listen_list_new(struct LISTEN_LIST *x)
472 {
473 	if (x == NULL) {
474 		x = xmalloc(sizeof(struct LISTEN_LIST));
475 		x->prev = NULL;
476 	} else {
477 		while (x->next != NULL)
478 			x = x->next;
479 		x->next = xmalloc(sizeof(struct LISTEN_LIST));
480 		x->next->prev = x;
481 		x = x->next;
482 	}
483 	x->enabled = TRUE;
484 	x->comment = NULL;
485 	x->port = -1;
486 	x->ip = NULL;
487 	x->next = NULL;
488 
489 	return x;
490 }
491 
492 /*
493 free memory allocated by network_load
494 */
495 void network_free(NETWORK * network)
496 {
497 	struct LISTEN_LIST *listen_list, *tmp_list;
498 
499 	if (!network)
range_check(char * range,unsigned int number)500 		return;
501 
502 	listen_list = network->listen_list;
503 
504 	while (listen_list != NULL) {
505 		tmp_list = listen_list->next;
506 
507 		FREE_AND_NULL(listen_list->comment);
508 		FREE_AND_NULL(listen_list->ip);
509 
510 		xfree(listen_list);
511 		listen_list = tmp_list;
512 	}
513 
514 	pthread_rwlock_destroy(&network->lock);
515 
516 	xfree(network);
517 }
518 
519 /*
520 look through network->listen_list linked list and bind to listening ports
521 */
522 void network_check(NETWORK * network)
523 {
524 	int ret;
525 	struct LISTEN_LIST *listen_list;
526 
527 	if (!network)
stack_free(STACK * stack)528 		return;
529 
530 	listen_list = network->listen_list;
531 
532 	pthread_rwlock_rdlock(&network->lock);
533 
534 	while (listen_list != NULL) {
535 		if (listen_list->enabled == TRUE && listen_list->port != -1) {
536 			ret = net_listen(listen_list->port, listen_list->ip);
537 
538 			if (ret != -1)
539 				putlog(MMLOG_NETWORK, "listening on %s:%d", (listen_list->ip != NULL) ? listen_list->ip : "0.0.0.0", listen_list->port);
540 			else
541 				putlog(MMLOG_NETWORK, "failed to bind to %s:%d", (listen_list->ip != NULL) ? listen_list->ip : "0.0.0.0", listen_list->port);
542 		}
543 
544 		listen_list = listen_list->next;
545 	}
546 
547 	pthread_rwlock_unlock(&network->lock);
548 }
mode_parse(char * mode)549 
550 /*
551 relay anything from one socket to another, and vice versa
552 */
553 int net_proxy(CONNECTION * connection, int len)
554 {
555 	int x, bytes = 0;
556 	char buf[BLOCKSIZE];
557 	struct pollfd pfd[2];
558 	SOCKET *sock1, *sock2;
559 
560 	sock1 = connection->client;
561 	sock2 = connection->server;
562 
563 	pfd[0].fd = sock1->fd;
564 	pfd[0].events = POLLIN;
565 	pfd[1].fd = sock2->fd;
566 	pfd[1].events = POLLIN;
567 
568 	while (1) {
569 		x = p_poll(pfd, 2, (sock1->inbuf_len != 0 || sock2->inbuf_len != 0) ? 0 : -1);
570 		if (x == -1) {
571 			if (errno == EINTR)
572 				continue;
573 			else
574 				break;
575 		}
576 
577 		if (sock1->inbuf_len != 0 || pfd[0].revents & POLLIN) {
578 			x = sock_read(sock1, buf, (len != -1) ? (len - bytes < sizeof(buf)) ? len - bytes : sizeof(buf) : sizeof(buf), -1);
579 			if (x > 0)
580 				sock_write(sock2, buf, x);
581 			else
582 				break;
583 
584 			bytes += x;
585 		} else if (pfd[0].revents & (POLLHUP | POLLERR))
586 			break;
587 
588 		if (sock1->inbuf_len != 0 || pfd[1].revents & POLLIN) {
589 			x = sock_read(sock2, buf, (len != -1) ? (len - bytes < sizeof(buf)) ? len - bytes : sizeof(buf) : sizeof(buf), -1);
590 			if (x > 0)
591 				sock_write(sock1, buf, x);
592 			else
593 				break;
594 
595 			bytes += x;
596 		} else if (pfd[1].revents & (POLLHUP | POLLERR))
597 			break;
598 
599 		if (len != -1 && bytes == len)
600 			break;
601 	}
602 
603 	return bytes;
604 }
605 
606 /*
607 tranfer data one way between two sockets
608 */
609 int net_transfer(CONNECTION * connection, int flags, int bytes)
610 {
611 	int i, x, sent = 0;
612 	char buf[BLOCKSIZE];
613 	struct pollfd pfd[2];
614 	SOCKET *sock1, *sock2;
615 
616 	sock1 = (flags == SERVER) ? connection->server : connection->client;
617 	sock2 = (flags == SERVER) ? connection->client : connection->server;
618 
619 	pfd[0].fd = sock1->fd;
620 	pfd[0].events = POLLIN;
621 
622 	if (sock2 != NULL) {
623 		pfd[1].fd = sock2->fd;
624 		pfd[1].events = POLLIN;
625 	} else
626 		pfd[1].revents = 0;
627 
628 	while ((bytes == -1 || bytes > 0) && connection->transferlimit > 0) {
629 		x = p_poll(pfd, (sock2 != NULL) ? 2 : 1, (sock1->inbuf_len != 0) ? 0 : -1);
630 		if (x == -1) {
631 			if (errno == EINTR)
632 				continue;
633 			else
634 				break;
635 		}
636 
637 		if (sock1->inbuf_len != 0 || pfd[0].revents & POLLIN) {
638 			x = sock_read(sock1, buf, (bytes != -1) ? (bytes < sizeof(buf)) ? bytes : sizeof(buf) : sizeof(buf), -1);
639 
640 			if (x > 0) {
641 				if (bytes != -1)
642 					bytes -= x;
643 
644 				sent += x;
645 
646 				if (flags == SERVER) {
ftpport_parse(char * ftpport)647 					if (connection->cachemap != NULL) {
648 						i = cache_add(global->cache, connection->cachemap, buf, x);
649 						if (i == -1 && (connection->flags & CONNECTION_PREFETCH))
650 							break;
651 					}
652 
653 					if (connection->htmlstream != NULL)
654 						htmlstream_add(connection->htmlstream, buf, x);
655 
656 					connection->transferred += x;
657 					connection->transferlimit -= (x > connection->transferlimit) ? connection->transferlimit : x;
658 				}
659 
660 				if (sock2 != NULL) {
661 					x = sock_write(sock2, buf, x);
662 					if (x == -1)
663 						break;
664 				}
665 			} else
666 				break;
667 		} else if (pfd[0].revents & (POLLHUP | POLLERR))
668 			break;
669 
670 		if (pfd[1].revents & POLLIN) {
671 			x = sock_read(sock2, NULL, -1, -1);
ftpport_create(struct sockaddr_in * saddr)672 			if (x <= 0)
673 				break;
674 		} else if (pfd[1].revents & (POLLHUP | POLLERR))
675 			break;
676 	}
677 
678 	if (bytes != 0 && bytes != -1) {
679 		connection->keepalive_server = FALSE;
680 		connection->keepalive_client = FALSE;
681 
682 		if (connection->cachemap != NULL) {
filesize(size_t size)683 			cache_invalidate(global->cache, connection->cachemap);
684 			connection->cachemap = NULL;
685 		}
686 	} else if (connection->htmlstream != NULL)
687 		htmlstream_add(connection->htmlstream, NULL, 0);
688 
689 	return sent;
690 }
691 
692 int putsock(SOCKET * sock, char *format, ...)
693 {
694 	int ret;
695 	char buf[8192];
696 	va_list va;
697 
698 	va_start(va, format);
699 	ret = vsnprintf(buf, sizeof(buf), format, va);
700 	va_end(va);
701 
702 	return sock_write(sock, buf, (ret > sizeof(buf) || ret == -1) ? sizeof(buf) : ret);
703 }
704 
705 int net_filebuf_read(FILEBUF * filebuf, CONNECTION * connection, int flags, int bytes)
706 {
string_to_size(char * s)707 	int x;
708 	char buf[BLOCKSIZE];
709 	struct pollfd pfd[2];
710 	SOCKET *sock1, *sock2;
711 
712 	sock1 = (flags == SERVER) ? connection->server : connection->client;
713 	sock2 = (flags == SERVER) ? connection->client : connection->server;
714 
715 	pfd[0].fd = sock1->fd;
716 	pfd[0].events = POLLIN;
717 
718 	if (sock2 != NULL) {
719 		pfd[1].fd = sock2->fd;
720 		pfd[1].events = POLLIN;
721 	} else
722 		pfd[1].revents = 0;
723 
724 	while ((bytes == -1 || bytes > 0) && connection->transferlimit > 0) {
725 		x = p_poll(pfd, (sock2 != NULL) ? 2 : 1, (sock1->inbuf_len != 0) ? 0 : -1);
local_mktime(struct tm * t)726 		if (x == -1) {
727 			if (errno == EINTR)
728 				continue;
729 			else
730 				break;
731 		}
732 
733 		if (sock1->inbuf_len != 0 || pfd[0].revents & POLLIN) {
utc_time(time_t * t)734 			x = sock_read(sock1, buf, (bytes != -1) ? (bytes < sizeof(buf)) ? bytes : sizeof(buf) : sizeof(buf), -1);
735 			if (x > 0) {
736 				if (flags == SERVER) {
737 					connection->transferred += x;
738 					connection->transferlimit -= (x > connection->transferlimit) ? connection->transferlimit : x;
739 				}
740 
741 				if (filebuf != NULL)
742 					filebuf_add(filebuf, buf, x);
cmdline_parse(char * cmdline)743 
744 				if (bytes != -1)
745 					bytes -= x;
746 			} else
747 				return FALSE;
748 		} else if (pfd[0].revents & (POLLHUP | POLLERR))
749 			break;
750 
751 		if (pfd[1].revents & POLLIN) {
752 			x = sock_read(sock2, NULL, -1, -1);
753 			if (x <= 0)
754 				break;
755 		} else if (pfd[1].revents & (POLLHUP | POLLERR))
756 			break;
757 	}
758 
759 	if ((bytes != -1 && bytes != 0) || connection->transferlimit == 0) {
760 		/* transfer terminated prematurely */
761 		connection->keepalive_server = FALSE;
762 
763 		return FALSE;
764 	}
765 
766 	return TRUE;
767 }
768 
769 int net_filebuf_send(FILEBUF * filebuf, CONNECTION * connection, int flags)
770 {
771 	SOCKET *sock;
772 
773 	if (flags == CLIENT && (connection->flags & CONNECTION_PREFETCH)) return filebuf->size;
774 
775 	sock = (flags == SERVER) ? connection->server : connection->client;
776 
777 	return sock_write(sock, filebuf->data, filebuf->size);
778 }
779 
780 int net_cache_send(CACHEMAP * cachemap, CONNECTION * connection, int flags, int offset)
781 {
782 	SOCKET *sock;
783 
784 	sock = (flags == SERVER) ? connection->server : connection->client;
785 
786 	offset += cachemap->offset;
787 	if (offset > cachemap->size)
788 		offset = cachemap->size;
789 
790 	return sock_write(sock, cachemap->data + offset, cachemap->size - offset);
791 }
792 
793 /*
794 perform a dns lookup, using cached response from a previous lookup if possible
795 */
796 HOSTENT *net_dns(char *host)
797 {
798 	time_t t;
799 	char hst[128], buf[24];
800 	HOSTENT *hostent;
801 	struct HASH_LIST *hl;
802 
803 	pthread_mutex_lock(&global->dns_cache_lock);
804 
805 	t = time(NULL);
806 
807 	s_strncpy(hst, host, sizeof(hst));
string_append(char * s1,char * s2)808 	string_tolower(hst);
809 
810 	if (last_dns_expire == 0)
811 		last_dns_expire = t;
812 
813 	if (t - last_dns_expire >= DNS_EXPIRE) {
814 		putlog(MMLOG_DEBUG, "dns cache expire: entry > %d seconds", DNS_EXPIRE);
815 
816 		hash_expire(global->dns_cache, DNS_EXPIRE);
817 		last_dns_expire = t;
818 	}
819 
path_to_url(char * path)820 	if (isip(host)) {
821 		hostent = xmalloc(sizeof(HOSTENT));
822 		hostent->addr = xmalloc(sizeof(struct in_addr));
823 		hostent->len = sizeof(struct in_addr);
824 
825 		inet_aton(host, hostent->addr);
826 	} else {
827 		hl = hash_search(global->dns_cache, hst);
828 		if (hl == NULL) {
829 			pthread_mutex_unlock(&global->dns_cache_lock);
830 
831 			hostent = p_gethostbyname(host);
832 			if (hostent == NULL)
833 				return NULL;
834 
835 			pthread_mutex_lock(&global->dns_cache_lock);
836 
837 			inet_ntop(AF_INET, hostent->addr, buf, sizeof(buf));
838 
839 			hl = hash_insert(global->dns_cache, hst, xstrdup(buf));
840 			hl->age = t;
841 
842 			putlog(MMLOG_DEBUG, "dns cache insert: %s -> %s", hst, buf);
843 		} else {
844 			putlog(MMLOG_DEBUG, "dns cache hit: %s -> %s", hst, hl->data);
845 
in_absolutetimerange(struct tm * subject,struct tm * from,struct tm * to)846 			hostent = xmalloc(sizeof(HOSTENT));
847 			hostent->addr = xmalloc(sizeof(struct in_addr));
848 			hostent->len = sizeof(struct in_addr);
849 
850 			inet_aton(hl->data, hostent->addr);
851 		}
852 	}
853 
854 	pthread_mutex_unlock(&global->dns_cache_lock);
855 
856 	return hostent;
857 }
858 
859 /*
860 connect through socks4 server
861 */
862 int proxy_socks4(CONNECTION * connection)
863 {
864 	int ret, bytes = 0;
865 	char buf[64];
866 	HOSTENT *hostent;
867 
868 	hostent = net_dns(connection->header->host);
869 	if (hostent == NULL)
870 		return ERROR_DNS;
871 
872 	ret = snprintf(buf, sizeof(buf), "\004\001%c%c%c%c%c%c%s", (connection->header->port >> 8) % 256, connection->header->port % 256, '0', '0', '0', '0', username);
873 	memcpy(&buf[4], hostent->addr, hostent->len);
874 
875 	hostent_free(hostent);
876 
877 	sock_write(connection->server, buf, ret + 1);
878 
879 	while (bytes < 8) {
880 		ret = sock_read(connection->server, buf + bytes, 8 - bytes, -1);
881 		if (ret != -1)
882 			bytes += ret;
883 		else
884 			return ERROR_CONNECT;
885 	}
886 
887 	switch (buf[1]) {
888 	case SOCKS_GRANTED:
889 		return TRUE;
890 		break;
891 	case SOCKS_FAILED:
892 		return ERROR_CONNECT;
893 		break;
894 	case SOCKS_BADIDENT:
895 	case SOCKS_NOIDENT:
896 		return ERROR_AUTH;
897 		break;
898 	default:
899 		return ERROR_UNKNOWN;
900 	}
901 }
902