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