version 2.1
[rofl0r-portredir.git] / redir.c
bloba2ecc1193d8160b6f6c2d0b0045f3ecb49c422ba
1 /* $Id$
3 * redir - a utility for redirecting tcp connections
5 * Author: Nigel Metheringham
6 * Nigel.Metheringham@ThePLAnet.net
8 * Based on, but much modified from, code originally written by
9 * sammy@freenet.akron.oh.us - original header is below.
11 * redir is released under the GNU General Public license,
12 * version 2, or at your discretion, any later version.
16 /* Redir, the code to which is below, is actually a horrible hack of my
17 * other cool network utility, daemon, which is actually a horrible hack
18 * of ora's using C sample code, 12.2.c. But, hey, they do something.
19 * (and that's the key.)
20 * -- Sammy (sammy@freenet.akron.oh.us)
23 /* oh, incidentally, Sammy is now sammy@oh.verio.com */
25 /* 980601: dl9sau
26 * added some nice new features:
28 * --bind_addr=my.other.ip.address
29 * forces to use my.other.ip.address for the outgoing connection
31 * you can also specify, that redir listens not on all IP addresses of
32 * your system but only for the given one, i.e.:
33 * if my host has the addresses
34 * irc.thishost.my.domain and mail.thishost.my.domain
35 * but you want that your users do connect for the irc redir service
36 * only on irc.thishost.my.domain, then do it this way:
37 * redir irc.fu-berlin.de irc.thishost.mydomain:6667 6667
38 * my need was that:
39 * addr1.first.domain 6667 redirects to irc.first.net port 6667
40 * and addr2.second.domain 6667 redirects to irc.second.net port 6667
41 * while addr1 and addr2 are the same maschine and the ports can be equal.
43 * enjoy it!
44 * - thomas <thomas@x-berg.in-berlin.de>, <dl9sau@db0tud.ampr.org>
46 * btw: i tried without success implementing code for the following scenario:
47 * redir --force_addr irc.fu-berlin.de 6667 6667
48 * if "--force_addr" is given and a user connects to my system, that address
49 * of my system will be used on the outgoing connection that the user
50 * connected to.
51 * i was not successful to determine, to which of my addresses the user
52 * has connected.
55 #define VERSION "2.0"
57 #include <stdio.h>
58 #include <unistd.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <signal.h>
62 #include <getopt.h>
63 #include <syslog.h>
64 #include <sys/types.h>
65 #include <sys/socket.h>
66 #include <sys/time.h>
67 #include <sys/wait.h>
68 #include <netinet/in.h>
69 #include <arpa/inet.h>
70 #include <netdb.h>
71 #include <errno.h>
73 #ifdef USE_TCP_WRAPPERS
74 #include <tcpd.h>
75 #endif
77 #define debug(x) if (dodebug) fprintf(stderr, x)
78 #define debug1(x,y) if (dodebug) fprintf(stderr, x, y)
80 /* let's set up some globals... */
81 int dodebug = 0;
82 int dosyslog = 0;
83 unsigned char reuse_addr = 1;
84 unsigned char linger_opt = 0;
85 char * bind_addr = NULL;
86 struct sockaddr_in addr_out;
87 int timeout = 0;
88 int ftp = 0;
89 int transproxy = 0;
90 char * ident = NULL;
92 #ifdef USE_TCP_WRAPPERS
93 struct request_info request;
94 int allow_severity = LOG_INFO;
95 int deny_severity = LOG_WARNING;
96 #endif /* USE_TCP_WRAPPERS */
98 #ifdef NEED_STRRCHR
99 #define strrchr rindex
100 #endif /* NEED_STRRCHR */
102 /* prototype anything needing it */
103 void do_accept(int servsock, struct sockaddr_in *target);
104 int bindsock(char *addr, int port, int fail);
107 #ifdef NEED_STRDUP
108 char *
109 strdup(char * str)
111 char * result;
113 if (result = (char *) malloc(strlen(str) + 1))
114 strcpy(result, str);
116 return result;
118 #endif /* NEED_STRDUP */
120 void
121 redir_usage(char *name)
123 fprintf(stderr,"usage:\n");
124 fprintf(stderr,
125 "\t%s --lport=<n> --cport=<n> [options]\n",
126 name);
127 fprintf(stderr, "\t%s --inetd --cport=<n>\n", name);
128 fprintf(stderr, "\n\tOptions are:-\n");
129 fprintf(stderr, "\t\t--lport=<n>\t\tport to listen on\n");
130 fprintf(stderr, "\t\t--laddr=IP\t\taddress of interface to listen on\n");
131 fprintf(stderr, "\t\t--cport=<n>\t\tport to connect to\n");
132 fprintf(stderr, "\t\t--caddr=<host>\t\tremote host to connect to\n");
133 fprintf(stderr, "\t\t--inetd\t\trun from inetd\n");
134 fprintf(stderr, "\t\t--debug\t\toutput debugging info\n");
135 fprintf(stderr, "\t\t--timeout=<n>\tset timeout to n seconds\n");
136 fprintf(stderr, "\t\t--syslog\tlog messages to syslog\n");
137 fprintf(stderr, "\t\t--name=<str>\ttag syslog messages with 'str'\n");
138 #ifdef USE_TCP_WRAPPERS
139 fprintf(stderr, "\t\t \tAlso used as service name for TCP wrappers\n");
140 #endif /* USE_TCP_WRAPPERS */
141 fprintf(stderr, "\t\t--bind_addr=IP\tbind() outgoing IP to given addr\n");
142 fprintf(stderr, "\t\t--ftp\t\tredirect passive ftp connections\n");
143 fprintf(stderr, "\t\t--transproxy\trun in linux's transparent proxy mode\n");
144 fprintf(stderr, "\n\tVersion %s - $Id$\n", VERSION);
145 exit(2);
148 void
149 parse_args(int argc,
150 char * argv[],
151 char ** target_addr,
152 int * target_port,
153 char ** local_addr,
154 int * local_port,
155 int * timeout,
156 int * dodebug,
157 int * inetd,
158 int * dosyslog,
159 char ** bind_addr,
160 int * ftp,
161 int * transproxy)
163 static struct option long_options[] = {
164 {"lport", required_argument, 0, 'l'},
165 {"laddr", required_argument, 0, 'a'},
166 {"cport", required_argument, 0, 'r'},
167 {"caddr", required_argument, 0, 'c'},
168 {"bind_addr", required_argument, 0, 'b'},
169 {"debug", no_argument, 0, 'd'},
170 {"timeout", required_argument, 0, 't'},
171 {"inetd", no_argument, 0, 'i'},
172 {"ident", required_argument, 0, 'n'},
173 {"name", required_argument, 0, 'n'},
174 {"syslog", no_argument, 0, 's'},
175 {"ftp", no_argument, 0, 'f'},
176 {"transproxy", no_argument, 0, 'p'},
177 {0,0,0,0} /* End marker */
180 int option_index = 0;
181 extern int optind;
182 int opt;
183 struct servent *portdesc;
184 char *lport = NULL;
185 char *tport = NULL;
187 *local_addr = NULL;
188 *target_addr = NULL;
189 *target_port = 0;
190 *local_port = 0;
192 while ((opt = getopt_long(argc, argv, "disfpn:t:b:a:l:r:c:",
193 long_options, &option_index)) != -1) {
194 switch (opt) {
195 case 'a':
196 *local_addr = optarg;
197 break;
199 case 'l':
200 lport = optarg;
201 break;
203 case 'r':
204 tport = optarg;
205 break;
207 case 'c':
208 *target_addr = optarg;
209 break;
211 case 'b':
212 *bind_addr = optarg;
213 break;
215 case 'd':
216 (*dodebug)++;
217 break;
219 case 't':
220 *timeout = atol(optarg);
221 break;
223 case 'i':
224 (*inetd)++;
225 break;
227 case 'n':
228 /* This is the ident which is added to syslog messages */
229 ident = optarg;
230 break;
232 case 's':
233 (*dosyslog)++;
234 break;
236 case 'f':
237 (*ftp)++;
238 break;
240 case 'p':
241 (*transproxy)++;
242 break;
244 default:
245 redir_usage(argv[0]);
246 exit(1);
247 break;
251 if(tport == NULL)
253 redir_usage(argv[0]);
254 exit(1);
257 if ((portdesc = getservbyname(tport, "tcp")) != NULL) {
258 *target_port = ntohs(portdesc->s_port);
259 } else {
260 *target_port = atol(tport);
263 /* only check local port if not running from inetd */
264 if(!(*inetd)) {
265 if(lport == NULL)
267 redir_usage(argv[0]);
268 exit(1);
271 if ((portdesc = getservbyname(lport, "tcp")) != NULL)
272 *local_port = ntohs(portdesc->s_port);
273 else
274 *local_port = atol(lport);
275 } /* if *inetd */
277 if (!ident) {
278 if ((ident = (char *) strrchr(argv[0], '/'))) {
279 ident++;
280 } else {
281 ident = argv[0];
285 openlog(ident, LOG_PID, LOG_DAEMON);
287 return;
290 /* with the --ftp option, this one changes passive mode replies from
291 the ftp server to point to a new redirector which we spawn */
292 void ftp_clean(int send, char *buf, unsigned long *bytes)
295 char *port_start;
296 int rporthi, lporthi;
297 int lportlo, rportlo;
298 int lport, rport;
299 int remip[4];
300 int localsock;
301 int socksize = sizeof(struct sockaddr_in);
302 int i;
304 struct sockaddr_in newsession;
305 struct sockaddr_in sockname;
307 /* is this a passive mode return ? */
308 if(strncmp(buf, "227", 3)) {
309 write(send, buf, (*bytes));
310 return;
313 /* get the outside interface so we can listen */
314 if(getsockname(send, (struct sockaddr *)&sockname, &socksize) != 0) {
316 perror("getsockname");
318 if (dosyslog)
319 syslog(LOG_ERR, "getsockname failed: %m");
321 exit(1);
324 /* parse the old address out of the buffer */
325 port_start = strchr(buf, '(');
327 sscanf(port_start, "(%d,%d,%d,%d,%d,%d", &remip[0], &remip[1],
328 &remip[2], &remip[3], &rporthi, &rportlo);
330 /* we need to listen on a port for the incoming connection.
331 we'll use this strategy. start at 32768 for hi byte, then
332 sweep using the low byte of our pid and try to bind 5 times.
333 if we can't bind to any of those ports, fail */
335 lporthi = 0x80;
336 lportlo = getpid() & 0xf0;
337 rport = (rporthi << 8) | rportlo;
339 for(i = 0, localsock = -1; ((localsock == -1) && (i < 5));
340 i++, lportlo++) {
342 lport = ((lporthi << 8) | lportlo) +1; /* weird off by 1 bug */
343 localsock = bindsock(inet_ntoa(sockname.sin_addr), lport, 1);
346 /* check to see if we bound */
347 if(localsock == -1) {
348 fprintf(stderr, "ftp: unable to bind new listening address\n");
349 exit(1);
352 (*bytes) = sprintf(buf, "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\n",
353 sockname.sin_addr.s_addr & 0xff,
354 (sockname.sin_addr.s_addr >> 8) & 0xff,
355 (sockname.sin_addr.s_addr >> 16) & 0xff,
356 sockname.sin_addr.s_addr >> 24, lporthi, lportlo);
358 newsession.sin_port = htons(rport);
359 newsession.sin_family = AF_INET;
360 newsession.sin_addr.s_addr = remip[0] | (remip[1] << 8)
361 | (remip[2] << 16) | (remip[3] << 24);
363 debug1("ftp server ip: %s\n", inet_ntoa(newsession.sin_addr));
364 debug1("ftp server port: %d\n", rport);
365 debug1("listening on port %d\n", lport);
366 debug1("listening on addr %s\n",
367 inet_ntoa(sockname.sin_addr));
370 /* now that we're bound and listening, we can safely send the new
371 passive string without fear of them getting a connection
372 refused. */
373 write(send, buf, (*bytes));
375 /* turn off ftp checking while the data connection is active */
376 ftp = 0;
377 do_accept(localsock, &newsession);
378 close(localsock);
379 ftp = 1;
381 return;
386 void
387 copyloop(int insock,
388 int outsock,
389 int timeout_secs)
391 fd_set iofds;
392 fd_set c_iofds;
393 int max_fd; /* Maximum numbered fd used */
394 struct timeval timeout;
395 unsigned long bytes;
396 unsigned long bytes_in = 0;
397 unsigned long bytes_out = 0;
398 unsigned int start_time, end_time;
399 char buf[4096];
401 /* Record start time */
402 start_time = (unsigned int) time(NULL);
404 /* Set up timeout */
405 timeout.tv_sec = timeout_secs;
406 timeout.tv_usec = 0;
408 /* file descriptor bits */
409 FD_ZERO(&iofds);
410 FD_SET(insock, &iofds);
411 FD_SET(outsock, &iofds);
414 if (insock > outsock) {
415 max_fd = insock;
416 } else {
417 max_fd = outsock;
420 debug1("Entering copyloop() - timeout is %d\n", timeout_secs);
421 while(1) {
422 (void) memcpy(&c_iofds, &iofds, sizeof(iofds));
425 if (select(max_fd + 1,
426 &c_iofds,
427 (fd_set *)0,
428 (fd_set *)0,
429 (timeout_secs ? &timeout : NULL)) <= 0) {
430 /* syslog(LLEV,"connection timeout: %d sec",timeout.tv_sec);*/
431 break;
434 if(FD_ISSET(insock, &c_iofds)) {
435 if((bytes = read(insock, buf, sizeof(buf))) <= 0)
436 break;
437 if(write(outsock, buf, bytes) != bytes)
438 break;
439 bytes_out += bytes;
441 if(FD_ISSET(outsock, &c_iofds)) {
442 if((bytes = read(outsock, buf, sizeof(buf))) <= 0)
443 break;
444 /* if we're correcting for PASV on ftp redirections, then
445 fix buf and bytes to have the new address, among other
446 things */
447 if(ftp)
448 ftp_clean(insock, buf, &bytes);
449 else
450 if(write(insock, buf, bytes) != bytes)
451 break;
452 bytes_in += bytes;
455 debug("Leaving main copyloop\n");
458 setsockopt(insock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr));
459 setsockopt(insock, SOL_SOCKET, SO_LINGER, &linger_opt, sizeof(SO_LINGER));
460 setsockopt(outsock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr));
461 setsockopt(outsock, SOL_SOCKET, SO_LINGER, &linger_opt, sizeof(SO_LINGER));
464 shutdown(insock,0);
465 shutdown(outsock,0);
466 close(insock);
467 close(outsock);
468 debug("copyloop - sockets shutdown and closed\n");
469 end_time = (unsigned int) time(NULL);
470 debug1("copyloop - connect time: %8d seconds\n", end_time - start_time);
471 debug1("copyloop - transfer in: %8ld bytes\n", bytes_in);
472 debug1("copyloop - transfer out: %8ld bytes\n", bytes_out);
473 if (dosyslog) {
474 syslog(LOG_NOTICE, "disconnect %d secs, %ld in %ld out",
475 (end_time - start_time), bytes_in, bytes_out);
477 return;
480 /* lwait for a connection and move into copyloop... again,
481 passive ftp's will call this, so we don't dupilcate it. */
483 void
484 do_accept(int servsock, struct sockaddr_in *target)
487 int clisock;
488 int targetsock;
489 struct sockaddr_in client;
490 int clientlen = sizeof(client);
492 debug("top of accept loop\n");
493 if ((clisock = accept(servsock, (struct sockaddr *) &client,
494 &clientlen)) < 0) {
496 perror("server: accept");
498 if (dosyslog)
499 syslog(LOG_ERR, "accept failed: %m");
501 return;
504 debug1("peer IP is %s\n", inet_ntoa(client.sin_addr));
505 debug1("peer socket is %d\n", ntohs(client.sin_port));
508 * Double fork here so we don't have to wait later
509 * This detaches us from our parent so that the parent
510 * does not need to pick up dead kids later.
512 * This needs to be done before the hosts_access stuff, because
513 * extended hosts_access options expect to be run from a child.
515 switch(fork())
517 case -1: /* Error */
518 perror("(server) fork");
520 if (dosyslog)
521 syslog(LOG_ERR, "(server) fork failed: %m");
523 _exit(1);
524 case 0: /* Child */
525 break;
526 default: /* Parent */
528 int status;
530 /* Wait for child (who has forked off grandchild) */
531 (void) wait(&status);
533 /* Close sockets to prevent confusion */
534 close(clisock);
536 return;
540 /* We are now the first child. Fork again and exit */
542 switch(fork())
544 case -1: /* Error */
545 perror("(child) fork");
547 if (dosyslog)
548 syslog(LOG_ERR, "(child) fork failed: %m");
550 _exit(1);
551 case 0: /* Child */
552 break;
553 default: /* Parent */
554 _exit(0);
557 /* We are now the grandchild */
559 #ifdef USE_TCP_WRAPPERS
560 request_init(&request, RQ_DAEMON, ident, RQ_FILE, clisock, 0);
561 sock_host(&request);
562 sock_hostname(&request);
563 sock_hostaddr(&request);
565 if (!hosts_access(&request)) {
566 refuse(&request);
567 _exit(0);
570 if (dosyslog)
571 syslog(LOG_INFO, "accepted connect from %s", eval_client(&request));
572 #endif /* USE_TCP_WRAPPERS */
574 if ((targetsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
576 perror("target: socket");
578 if (dosyslog)
579 syslog(LOG_ERR, "socket failed: %m");
581 _exit(1);
584 if(transproxy) {
585 memcpy(&addr_out, &client, sizeof(struct sockaddr_in));
586 addr_out.sin_port = 0;
589 if (bind_addr || transproxy) {
590 /* this only makes sense if an outgoing IP addr has been forced;
591 * at this point, we have a valid targetsock to bind() to.. */
592 /* also, if we're in transparent proxy mode, this option
593 never makes sense */
595 if (bind(targetsock, (struct sockaddr *) &addr_out,
596 sizeof(struct sockaddr_in)) < 0) {
597 perror("bind_addr: cannot bind to forcerd outgoing addr");
599 if (dosyslog)
600 syslog(LOG_ERR, "bind failed: %m");
602 _exit(1);
604 debug1("outgoing IP is %s\n", inet_ntoa(addr_out.sin_addr));
607 if (connect(targetsock, (struct sockaddr *) target,
608 sizeof(struct sockaddr_in)) < 0) {
609 perror("target: connect");
611 if (dosyslog)
612 syslog(LOG_ERR, "bind failed: %m");
614 _exit(1);
617 debug1("connected to %s\n", inet_ntoa(target->sin_addr));
619 /* thanks to Anders Vannman for the fix to make proper syslogging
620 happen here... */
622 if (dosyslog) {
623 char tmp1[20], tmp2[20];
624 strcpy(tmp1, inet_ntoa(client.sin_addr));
625 strcpy(tmp2, inet_ntoa(target->sin_addr));
627 syslog(LOG_NOTICE, "connecting %s/%d to %s/%d",
628 tmp1, ntohs(client.sin_port),
629 tmp2, ntohs(target->sin_port));
631 copyloop(clisock, targetsock, timeout);
632 exit(0); /* Exit after copy */
635 /* bind to a new socket, we do this out here because passive-fixups
636 are going to call it too, and there's no sense dupliciting the
637 code. */
638 /* fail is true if we should just return a -1 on error, false if we
639 should bail. */
641 int bindsock(char *addr, int port, int fail)
644 int servsock;
645 struct sockaddr_in server;
648 * Get a socket to work with. This socket will
649 * be in the Internet domain, and will be a
650 * stream socket.
653 if ((servsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
654 if(fail) {
655 return -1;
657 else {
658 perror("server: socket");
660 if (dosyslog)
661 syslog(LOG_ERR, "socket failed: %m");
663 exit(1);
667 server.sin_family = AF_INET;
668 server.sin_port = htons(port);
669 if (addr != NULL) {
670 struct hostent *hp;
672 debug1("listening on %s\n", addr);
673 if ((hp = gethostbyname(addr)) == NULL) {
674 fprintf(stderr, "%s: cannot resolve hostname.\n", addr);
675 exit(1);
677 memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
678 } else {
679 debug("local IP is default\n");
680 server.sin_addr.s_addr = htonl(inet_addr("0.0.0.0"));
683 setsockopt(servsock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr));
684 setsockopt(servsock, SOL_SOCKET, SO_LINGER, &linger_opt, sizeof(SO_LINGER));
687 * Try to bind the address to the socket.
690 if (bind(servsock, (struct sockaddr *) &server,
691 sizeof(server)) < 0) {
692 if(fail) {
693 close(servsock);
694 return -1;
695 } else {
696 perror("server: bind");
698 if (dosyslog)
699 syslog(LOG_ERR, "bind failed: %m");
701 exit(1);
706 * Listen on the socket.
709 if (listen(servsock, 10) < 0) {
710 if(fail) {
711 close(servsock);
712 return -1;
713 } else {
714 perror("server: listen");
716 if (dosyslog)
717 syslog(LOG_ERR, "listen failed: %m");
719 exit(1);
723 return servsock;
727 main(int argc, char *argv[])
730 struct sockaddr_in target;
731 char *target_addr;
732 int target_port;
733 char *local_addr;
734 int local_port;
735 int inetd = 0;
736 char * target_ip;
737 char * ip_to_target;
739 debug("parse args\n");
740 parse_args(argc, argv, &target_addr, &target_port, &local_addr,
741 &local_port, &timeout, &dodebug, &inetd, &dosyslog, &bind_addr,
742 &ftp, &transproxy);
744 /* Set up target */
745 target.sin_family = AF_INET;
746 target.sin_port = htons(target_port);
747 if (target_addr != NULL) {
748 struct hostent *hp;
750 debug1("target is %s\n", target_addr);
751 if ((hp = gethostbyname(target_addr)) == NULL) {
752 fprintf(stderr, "%s: host unknown.\n", target_addr);
753 exit(1);
755 memcpy(&target.sin_addr, hp->h_addr, hp->h_length);
756 } else {
757 debug("target is default\n");
758 target.sin_addr.s_addr = htonl(inet_addr("0.0.0.0"));
761 target_ip = strdup(inet_ntoa(target.sin_addr));
762 debug1("target IP address is %s\n", target_ip);
763 debug1("target port is %d\n", target_port);
765 /* Set up outgoing IP addr (optional);
766 * we have to wait for bind until targetsock = socket() is done
768 if (bind_addr && !transproxy) {
769 struct hostent *hp;
771 fprintf(stderr, "bind_addr is %s\n", bind_addr);
772 addr_out.sin_family = AF_INET;
773 addr_out.sin_port = 0;
774 if ((hp = gethostbyname(bind_addr)) == NULL) {
775 fprintf(stderr, "%s: cannot resolve forced outgoing IP address.\n", bind_addr);
776 exit(1);
778 memcpy(&addr_out.sin_addr, hp->h_addr, hp->h_length);
780 ip_to_target = strdup(inet_ntoa(addr_out.sin_addr));
781 debug1("IP address for target is %s\n", ip_to_target);
785 if (inetd) {
786 int targetsock;
787 struct sockaddr_in client;
788 int client_size = sizeof(client);
790 #ifdef USE_TCP_WRAPPERS
791 request_init(&request, RQ_DAEMON, ident, RQ_FILE, 0, 0);
792 sock_host(&request);
793 sock_hostname(&request);
794 sock_hostaddr(&request);
796 if (!hosts_access(&request))
797 refuse(&request);
798 #endif /* USE_TCP_WRAPPERS */
800 if (!getpeername(0, (struct sockaddr *) &client, &client_size)) {
801 debug1("peer IP is %s\n", inet_ntoa(client.sin_addr));
802 debug1("peer socket is %d\n", ntohs(client.sin_port));
804 if ((targetsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
805 perror("target: socket");
807 if (dosyslog)
808 syslog(LOG_ERR, "targetsock failed: %m");
810 exit(1);
813 if(transproxy) {
814 memcpy(&addr_out, &client, sizeof(struct sockaddr_in));
815 addr_out.sin_port = 0;
818 if (bind_addr || transproxy) {
819 /* this only makes sense if an outgoing IP addr has been forced;
820 * at this point, we have a valid targetsock to bind() to.. */
821 if (bind(targetsock, (struct sockaddr *) &addr_out,
822 sizeof(addr_out)) < 0) {
823 perror("bind_addr: cannot bind to forcerd outgoing addr");
825 if (dosyslog)
826 syslog(LOG_ERR, "bind failed: %m");
828 exit(1);
830 debug1("outgoing IP is %s\n", inet_ntoa(addr_out.sin_addr));
833 if (connect(targetsock, (struct sockaddr *) &target,
834 sizeof(target)) < 0) {
835 perror("target: connect");
837 if (dosyslog)
838 syslog(LOG_ERR, "connect failed: %m");
840 exit(1);
843 if (dosyslog) {
844 syslog(LOG_NOTICE, "connecting %s/%d to %s/%d",
845 inet_ntoa(client.sin_addr), ntohs(client.sin_port),
846 target_ip, ntohs(target.sin_port));
849 /* Just start copying - one side of the loop is stdin - 0 */
850 copyloop(0, targetsock, timeout);
851 } else {
852 int servsock;
854 if(local_addr)
855 servsock = bindsock(local_addr, local_port, 0);
856 else
857 servsock = bindsock(NULL, local_port, 0);
860 * Accept connections. When we accept one, ns
861 * will be connected to the client. client will
862 * contain the address of the client.
865 while (1)
866 do_accept(servsock, &target);
869 /* this should really never be reached */
871 exit(0);