"Fossies" - the Fresh Open Source Software Archive 
Member "portfwd-0.29/src/forward.cc" (30 May 2005, 23174 Bytes) of package /linux/privat/old/portfwd-0.29.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 forward.c
3
4 $Id: forward.cc,v 1.12 2005/05/30 02:13:28 evertonm Exp $
5 */
6
7 #include <stdlib.h>
8 #include <sys/time.h>
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <netinet/in.h>
12 #include <errno.h>
13 #include <string.h>
14 #include <strings.h>
15 #include <unistd.h>
16 #include <arpa/inet.h>
17 #include <syslog.h>
18 #include <signal.h>
19 #include "portfwd.h"
20 #include "forward.h"
21 #include "util.h"
22 #include "solve.h"
23 #include "host_map.hpp"
24 #include "iterator.hpp"
25
26 int grandchild_pid[PORTFWD_MAX_FD];
27
28 /*
29 * Returns -1 on failure; file descriptor on success.
30 */
31 int tcp_connect(const struct ip_addr *ip, int port)
32 {
33 int rsd = socket(PF_INET, SOCK_STREAM, get_protonumber(P_TCP));
34 if (rsd == -1) {
35 syslog(LOG_ERR, "tcp_connect: Can't create TCP socket: %m");
36 return -1;
37 }
38 DEBUGFD(syslog(LOG_DEBUG, "socket open: FD %d", rsd));
39
40 struct sockaddr_in sa;
41 sa.sin_family = PF_INET;
42 sa.sin_port = htons(port);
43 sa.sin_addr.s_addr = *((unsigned int *) ip->addr);
44 memset((char *) sa.sin_zero, 0, sizeof(sa.sin_zero));
45
46 if (connect(rsd, (struct sockaddr *) &sa, sizeof(sa))) {
47 syslog(LOG_ERR, "tcp_connect: Can't connect to %s:%d: %m", inet_ntoa(sa.sin_addr), port);
48 socket_close(rsd);
49 return -1;
50 }
51
52 return rsd;
53 }
54
55 /*
56 * Returns host_map success; NULL on failure.
57 */
58 host_map *tcp_match(const vector<host_map*> *map_list, const struct ip_addr *ip, int port)
59 {
60 host_map *hm;
61 iterator<vector<host_map*>,host_map*> it(*map_list);
62 for (it.start(); it.cont(); it.next()) {
63 hm = it.get();
64 if (hm->tcp_match(ip, port))
65 return hm;
66 }
67 return 0;
68 }
69
70 void quit_handler(int sig)
71 {
72 ONVERBOSE(syslog(LOG_DEBUG, "child: quit_handler: Grandchild with PID %d exiting under request", getpid()));
73
74 exit(0);
75 }
76
77 int simple_buf_copy(int src_fd, int trg_fd)
78 {
79 char buf[BUF_SZ];
80 int rd = read(src_fd, buf, BUF_SZ);
81 if (!rd)
82 return -1;
83 if (rd < 0) {
84 syslog(LOG_ERR, "simple_copy: Failure reading from socket: %m");
85 return -1;
86 }
87
88 int wr = write(trg_fd, buf, rd);
89 if (wr == -1) {
90 if (errno == EPIPE)
91 ONVERBOSE2(syslog(LOG_DEBUG, "simple_copy: Broken pipe: %m"));
92 return -1;
93 }
94 if (wr < rd) {
95 ONVERBOSE(syslog(LOG_WARNING, "simple_copy: Partial write to socket: %m"));
96 return -1;
97 }
98
99 return 0;
100 }
101
102 void simple_tcp_forward(int sd, struct ip_addr *remote_ip, int remote_port)
103 {
104 int dest_fd[PORTFWD_MAX_FD];
105
106 fd_set fds, tmp_fds;
107 int fd_set_len = sizeof(fd_set);
108 FD_ZERO(&fds);
109 int maxfd = 0;
110 fdset(sd, &fds, &maxfd);
111 int nd;
112
113 for (;;) { /* forever */
114 /*
115 * Restores tmp_fds from fds.
116 */
117 memcpy(&tmp_fds, &fds, fd_set_len);
118
119 /*
120 * Wait for event: connection on sd or data on anyone else.
121 */
122 DEBUGFD(syslog(LOG_DEBUG, "simple_forward: TCP select(): %d FDs", maxfd));
123 nd = select(maxfd, &tmp_fds, 0, 0, 0);
124 if (nd == -1) {
125 syslog(LOG_ERR, "simple_forward: TCP select() failed: %m");
126 continue;
127 }
128
129 /*
130 * Let's handle sd here (mother socket).
131 */
132 if (FD_ISSET(sd, &tmp_fds)) {
133
134 --nd;
135
136 /*
137 * Clear sd so it's ignored below in the
138 * loop for the client sockets.
139 */
140 FD_CLR(sd, &tmp_fds);
141
142 struct sockaddr_in cli_sa;
143 socklen_t cli_sa_len = sizeof(cli_sa);
144 int csd = accept(sd, (struct sockaddr *) &cli_sa, &cli_sa_len);
145 if (csd < 0)
146 syslog(LOG_ERR, "simple_forward: Can't accept TCP socket: %m");
147 else {
148 int cli_port = ntohs(cli_sa.sin_port);
149 ONVERBOSE(syslog(LOG_DEBUG, "simple_forward: TCP connection from %s:%d", inet_ntoa(cli_sa.sin_addr), cli_port));
150
151 /*
152 * Connect to destination.
153 */
154
155 int rsd = tcp_connect(remote_ip, remote_port);
156 if (rsd != -1) {
157 if ((csd >= PORTFWD_MAX_FD) || (rsd >= PORTFWD_MAX_FD)) {
158 syslog(LOG_ERR, "simple_forward: Destination socket descriptors overflow");
159 socket_close(csd);
160 socket_close(rsd);
161 }
162 else {
163 /*
164 * Add pair of communicating sockets.
165 */
166 fdset(csd, &fds, &maxfd);
167 fdset(rsd, &fds, &maxfd);
168
169 /*
170 * Save peers so they can be remembered later.
171 */
172 dest_fd[csd] = rsd;
173 dest_fd[rsd] = csd;
174 }
175 }
176 }
177
178 } /* sd (mother socket) handled */
179
180 /*
181 * Now all other sockets.
182 */
183 for (int src_fd = 0; nd; ++src_fd)
184 if (FD_ISSET(src_fd, &tmp_fds)) {
185 --nd;
186 int trg_fd = dest_fd[src_fd];
187 /*
188 * Copy data.
189 */
190 int fail = simple_buf_copy(src_fd, trg_fd);
191 if (fail) {
192 /*
193 * Remove pair of communicating sockets.
194 */
195 DEBUGFD(syslog(LOG_DEBUG, "simple_forward: closed socket (FD %d or %d)", src_fd, trg_fd));
196
197 fdclear(src_fd, &fds, &maxfd);
198 fdclear(trg_fd, &fds, &maxfd);
199 socket_close(src_fd);
200 socket_close(trg_fd);
201 }
202 }
203
204 } /* main loop */
205
206 }
207
208 int ftp_spawn(struct ip_addr *local_ip, int *local_port, struct ip_addr *remote_ip, int remote_port)
209 {
210 int sd = tcp_listen(local_ip, local_port, 3);
211 if (sd == -1) {
212 syslog(LOG_ERR, "FTP spawn: Can't listen: %m");
213 return -1;
214 }
215
216 pid_t pid = fork();
217
218 /* Fork failed? */
219 if (pid < 0) {
220
221 /* Fork failed */
222
223 syslog(LOG_ERR, "FTP spawn: fork() failed: %m");
224
225 socket_close(sd); /* the socket won't be used at all */
226 return pid;
227 }
228
229 if (pid) {
230
231 /* Child */
232
233 socket_close(sd); /* the child won't use the socket */
234 return pid;
235 }
236
237 /* Grandchild */
238
239 void (*prev_handler)(int);
240 prev_handler = signal(SIGCHLD, SIG_IGN);
241 if (prev_handler == SIG_ERR) {
242 syslog(LOG_ERR, "signal() failed on ignore: %m");
243 exit(1);
244 }
245 prev_handler = signal(SIGUSR1, quit_handler);
246 if (prev_handler == SIG_ERR) {
247 syslog(LOG_ERR, "signal() failed for grandchild's quit handler: %m");
248 exit(1);
249 }
250
251 simple_tcp_forward(sd, remote_ip, remote_port);
252
253 syslog(LOG_ERR, "Grandchild exiting (!)");
254 exit(1);
255 }
256
257 void gc_clean(int fd)
258 {
259 pid_t pid = grandchild_pid[fd];
260 if (pid != -1) {
261 ONVERBOSE(syslog(LOG_DEBUG, "Requesting termination of PID %d for FD %d", pid, fd));
262
263 if (kill(pid, SIGUSR1))
264 syslog(LOG_ERR, "Can't request grandchild termination for PID: %d: %m", pid);
265 grandchild_pid[fd] = -1;
266 }
267 }
268
269 void gc_fill(int fd, pid_t pid)
270 {
271 gc_clean(fd);
272
273 grandchild_pid[fd] = pid;
274
275 ONVERBOSE(syslog(LOG_DEBUG, "PID %d stored for termination request on FD %d", pid, fd));
276 }
277
278 int ftp_active(const struct ip_addr *actv_ip, char *buf, int *rd, int src_fd, int trg_fd)
279 {
280 if (strncasecmp(buf, "port", 4))
281 return 0;
282
283 ONVERBOSE(syslog(LOG_DEBUG, "Active FTP request detected: %s", buf));
284
285 char *i = strchr(buf, ' ');
286 if (!i) {
287 syslog(LOG_ERR, "Missing remote address in active FTP request");
288 return -1;
289 }
290 ++i;
291
292 int ad[4];
293 int port[2];
294
295 if (sscanf(i, "%d,%d,%d,%d,%d,%d",
296 &ad[0], &ad[1], &ad[2], &ad[3],
297 &port[0], &port[1]) < 6) {
298 syslog(LOG_ERR, "Active FTP request mismatch");
299 return -1;
300 }
301
302 /*
303 * Remote address.
304 */
305
306 char addr[4];
307 addr[0] = ad[0];
308 addr[1] = ad[1];
309 addr[2] = ad[2];
310 addr[3] = ad[3];
311
312 struct ip_addr remote_ip;
313 remote_ip.len = addr_len;
314 remote_ip.addr = addr;
315 int remote_port = (port[0] << 8) | port[1];
316
317 ONVERBOSE(syslog(LOG_DEBUG, "Remote address extracted: %s:%d", addrtostr(&remote_ip), remote_port));
318
319 /*
320 * Local address (0.0.0.0).
321 */
322
323 int laddr = INADDR_ANY;
324 struct ip_addr local_ip;
325 local_ip.len = addr_len;
326 local_ip.addr = (char *) &laddr;
327
328 /*
329 * FTP forwarder.
330 */
331
332 int local_port = 0;
333
334 pid_t pid = ftp_spawn(&local_ip, &local_port, &remote_ip, remote_port);
335 if (pid == -1) {
336 syslog(LOG_ERR, "Can't spawn FTP forwarder");
337 /* free(local_ip.addr); */
338 return -1;
339 }
340
341 /*
342 * Address rewriting (IP given by ftp-active-mode-on).
343 */
344 const char *local_addr = actv_ip->addr;
345 if (snprintf(buf, BUF_SZ, "PORT %u,%u,%u,%u,%u,%u\n",
346 (unsigned char) local_addr[0],
347 (unsigned char) local_addr[1],
348 (unsigned char) local_addr[2],
349 (unsigned char) local_addr[3],
350 (local_port >> 8) & 0xFF, local_port & 0xFF) == -1)
351 syslog(LOG_WARNING, "Active FTP request truncated");
352
353 *rd = strlen(buf);
354
355 /*
356 * Store forwarder's PID so it can be terminated.
357 */
358 gc_fill(src_fd, pid);
359 gc_fill(trg_fd, pid);
360
361 return 0;
362 }
363
364 int ftp_passive(const struct ip_addr *pasv_ip, char *buf, int *rd, int src_fd, int trg_fd)
365 {
366 if (memcmp(buf, "227", 3))
367 return 0;
368
369 ONVERBOSE(syslog(LOG_DEBUG, "Passive FTP reply detected: %s", buf));
370
371 char *i = strchr(buf, '(');
372 if (!i) {
373 syslog(LOG_ERR, "Missing remote address in passive FTP reply");
374 return -1;
375 }
376 ++i;
377
378 int ad[4];
379 int port[2];
380
381 if (sscanf(i, "%d,%d,%d,%d,%d,%d",
382 &ad[0], &ad[1], &ad[2], &ad[3],
383 &port[0], &port[1]) < 6) {
384 syslog(LOG_ERR, "Passive FTP reply mismatch");
385 return -1;
386 }
387
388 /*
389 * Remote address.
390 */
391
392 char addr[4];
393 addr[0] = ad[0];
394 addr[1] = ad[1];
395 addr[2] = ad[2];
396 addr[3] = ad[3];
397
398 struct ip_addr remote_ip;
399 remote_ip.len = addr_len;
400 remote_ip.addr = addr;
401 int remote_port = (port[0] << 8) | port[1];
402
403 ONVERBOSE(syslog(LOG_DEBUG, "Remote address extracted: %s:%d", addrtostr(&remote_ip), remote_port));
404
405 /*
406 * Local address (0.0.0.0).
407 */
408
409 int laddr = INADDR_ANY;
410 struct ip_addr local_ip;
411 local_ip.len = addr_len;
412 local_ip.addr = (char *) &laddr;
413
414 /*
415 * FTP forwarder.
416 */
417
418 int local_port = 0;
419
420 pid_t pid = ftp_spawn(&local_ip, &local_port, &remote_ip, remote_port);
421 if (pid == -1) {
422 syslog(LOG_ERR, "Can't spawn FTP forwarder");
423 return -1;
424 }
425
426 /*
427 * Address rewriting (IP given by ftp-passive-mode-on).
428 */
429 const char *local_addr = pasv_ip->addr;
430 if (snprintf(buf, BUF_SZ, "227 Portfwd Passive Mode (%u,%u,%u,%u,%u,%u)\n",
431 (unsigned char) local_addr[0],
432 (unsigned char) local_addr[1],
433 (unsigned char) local_addr[2],
434 (unsigned char) local_addr[3],
435 (local_port >> 8) & 0xFF, local_port & 0xFF) == -1)
436 syslog(LOG_WARNING, "Passive FTP reply truncated");
437
438 *rd = strlen(buf);
439
440 /*
441 * Store forwarder's PID so it can be terminated.
442 */
443 gc_fill(src_fd, pid);
444 gc_fill(trg_fd, pid);
445
446 return 0;
447 }
448
449 int buf_copy(int src_fd, int trg_fd, const struct ip_addr *actv_ip, const struct ip_addr *pasv_ip)
450 {
451 char buf[BUF_SZ];
452 int rd = read(src_fd, buf, BUF_SZ);
453 if (!rd)
454 return -1;
455 if (rd < 0) {
456 syslog(LOG_ERR, "copy: Failure reading from socket: %m");
457 return -1;
458 }
459
460 if (actv_ip)
461 if (ftp_active(actv_ip, buf, &rd, src_fd, trg_fd))
462 return -1;
463
464 if (pasv_ip)
465 if (ftp_passive(pasv_ip, buf, &rd, src_fd, trg_fd))
466 return -1;
467
468 int wr = write(trg_fd, buf, rd);
469 if (wr == -1) {
470 if (errno == EPIPE)
471 ONVERBOSE2(syslog(LOG_DEBUG, "copy: Broken pipe: %m"));
472 return -1;
473 }
474 if (wr < rd) {
475 ONVERBOSE(syslog(LOG_WARNING, "copy: Partial write to socket: %m"));
476 return -1;
477 }
478
479 return 0;
480 }
481
482 int drop_privileges(int uid, int gid)
483 {
484 if (gid != -1)
485 if (setregid(gid, gid)) {
486 syslog(LOG_ERR, "Can't switch to group: %d: %m", gid);
487 return -1;
488 }
489
490 if (uid != -1)
491 if (setreuid(uid, uid)) {
492 syslog(LOG_ERR, "Can't switch to user: %d: %m", uid);
493 return -1;
494 }
495
496 return 0;
497 }
498
499 int tcp_listen(const struct ip_addr *ip, int *port, int queue)
500 {
501 int sd = socket(PF_INET, SOCK_STREAM, get_protonumber(P_TCP));
502 if (sd == -1) {
503 syslog(LOG_ERR, "listen: Can't create TCP socket: %m");
504 return -1;
505 }
506 DEBUGFD(syslog(LOG_DEBUG, "socket open: FD %d", sd));
507
508 int prt = port ? *port : 0;
509
510 struct sockaddr_in sa;
511 socklen_t sa_len = sizeof(sa);
512 sa.sin_family = PF_INET;
513 sa.sin_port = htons(prt);
514 sa.sin_addr.s_addr = *((unsigned int *) ip->addr);
515 memset((char *) sa.sin_zero, 0, sizeof(sa.sin_zero));
516
517
518 #ifndef NO_SO_REUSEADDR
519 /*
520 * Allow reuse of local addresses
521 */
522 {
523 int one = 1;
524
525 ONVERBOSE(syslog(LOG_DEBUG, "Setting SO_REUSEADDR for TCP listening socket on port %d", prt));
526
527 if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1)
528 syslog(LOG_WARNING, "tcp_listen(): Can't allow reuse of local addresses: setsockopt(SO_REUSEADDR) failed: %m") ;
529 }
530 #endif /* NO_SO_REUSEADDR */
531
532
533 if (bind(sd, (struct sockaddr *) &sa, sa_len)) {
534 syslog(LOG_ERR, "listen: Can't bind TCP socket: %m: %s:%d", inet_ntoa(sa.sin_addr), prt);
535 fprintf(stderr, "listen: Can't bind TCP socket: %m: %s:%d", inet_ntoa(sa.sin_addr), prt);
536 socket_close(sd);
537 return -1;
538 }
539
540 if (getsockname(sd, (struct sockaddr *) &sa, &sa_len)) {
541 syslog(LOG_ERR, "listen: Can't get local sockname: %m");
542 fprintf(stderr, "listen: Can't get local sockname: %m");
543 return -1;
544 }
545 prt = ntohs(sa.sin_port);
546
547 if (listen(sd, queue)) {
548 syslog(LOG_ERR, "listen: Can't listen TCP socket: %m");
549 fprintf(stderr, "listen: Can't listen TCP socket: %m");
550 socket_close(sd);
551 return -1;
552 }
553
554 syslog(LOG_DEBUG, "Listening TCP connection on %s:%d", inet_ntoa(sa.sin_addr), prt);
555
556 if (port)
557 *port = prt;
558
559 return sd;
560 }
561
562 void close_sockets(vector<int> *port_list)
563 {
564 iterator<vector<int>,int> it(*port_list);
565 for (it.start(); it.cont(); it.next())
566 close(it.get());
567 DEBUGFD(syslog(LOG_DEBUG, "close_sockets(): Sockets closed: %d", port_list->get_size()));
568 }
569
570
571 class sleeper {
572 private:
573 static sleeper *sleepers;
574 static sleeper *tail;
575
576 time_t timeout;
577 host_map *hm;
578 struct sockaddr_in cli_sa;
579 struct ip_addr ip;
580 int cli_port;
581 const struct ip_addr *src;
582 struct sockaddr_in local_cli_sa;
583 int csd;
584 fd_set *fds;
585 int *maxfd;
586 int *dest_fd;
587
588 sleeper *next;
589
590 public:
591 sleeper(host_map *hm, struct sockaddr_in *cli_sa, struct ip_addr *ip,
592 int cli_port, const struct ip_addr *src, struct sockaddr_in *local_cli_sa,
593 int csd, fd_set *fds, int *dest_fd, int *maxfd) {
594 this->hm = hm;
595 this->cli_sa = *cli_sa;
596 this->ip = *ip;
597 this->cli_port = cli_port;
598 this->src = src;
599 this->local_cli_sa = *local_cli_sa;
600 this->csd = csd;
601 this->fds = fds;
602 this->dest_fd = dest_fd;
603 this->maxfd = maxfd;
604 this->next = NULL;
605 }
606
607 void queue() {
608 this->timeout = time(NULL) + 10;
609 if (tail)
610 tail->next = this;
611 else
612 sleepers = tail = this;
613 }
614
615 int pipe() {
616 int rsd = 0;
617 socklen_t cli_sa_len = sizeof(cli_sa);
618
619 if (hm->pipe(&rsd, &cli_sa, cli_sa_len, &ip, cli_port, src, &local_cli_sa)) {
620 return 1;
621 }
622
623 if ((csd >= PORTFWD_MAX_FD) || (rsd >= PORTFWD_MAX_FD)) {
624 syslog(LOG_ERR, "Destination socket descriptors overflow");
625 socket_close(csd);
626 socket_close(rsd);
627 return 0;
628 }
629
630 /*
631 * Add pair of communicating sockets.
632 */
633 fdset(csd, fds, maxfd);
634 fdset(rsd, fds, maxfd);
635
636 /*
637 * Save peers so they can be remembered later.
638 */
639 dest_fd[csd] = rsd;
640 dest_fd[rsd] = csd;
641 return 0;
642 }
643
644 static void handle_first() {
645 sleeper *s = sleepers;
646 sleepers = sleepers->next;
647 if (sleepers == NULL)
648 tail = NULL;
649 if (s->pipe()) {
650 s->queue();
651 } else {
652 delete s;
653 }
654 }
655
656 static int ready() {
657 return sleepers != NULL && sleepers->timeout <= time(NULL);
658 }
659
660 static int queued() {
661 return sleepers != NULL;
662 }
663
664 static time_t earliest() {
665 return sleepers->timeout;
666 }
667
668 };
669
670
671 sleeper *sleeper::sleepers = NULL;
672 sleeper *sleeper::tail = NULL;
673
674
675 void mother_socket(int sd, fd_set *fds, int dest_fd[], int *maxfd, vector<host_map*> *map_list, const struct ip_addr *src, int fragile)
676 {
677 struct sockaddr_in cli_sa;
678 socklen_t cli_sa_len = sizeof(cli_sa);
679
680 /*
681 * Accept new client on "csd"
682 */
683 int csd = accept(sd, (struct sockaddr *) &cli_sa, &cli_sa_len);
684 if (csd < 0) {
685 syslog(LOG_ERR, "Can't accept TCP socket: %m");
686 return;
687 }
688
689 int cli_port = ntohs(cli_sa.sin_port);
690
691 /*
692 * Get local address
693 */
694 struct sockaddr_in local_cli_sa;
695 socklen_t local_cli_sa_len = sizeof(local_cli_sa);
696 if (getsockname(sd, (struct sockaddr *) &local_cli_sa, &local_cli_sa_len)) {
697 syslog(LOG_ERR, "mother_socket(): Can't get local sockname: %m");
698 socket_close(csd);
699 return;
700 }
701
702 ONVERBOSE(syslog(LOG_DEBUG, "TCP connection from %s:%d", inet_ntoa(cli_sa.sin_addr), cli_port));
703
704 /*
705 * Check client address (ip, port).
706 */
707 struct ip_addr ip;
708 ip.addr = (char *) &(cli_sa.sin_addr.s_addr);
709 ip.len = addr_len;
710
711 host_map *hm = tcp_match(map_list, &ip, cli_port);
712 if (!hm) {
713 ONVERBOSE(syslog(LOG_DEBUG, "Address miss"));
714 socket_close(csd);
715 return;
716 }
717 ONVERBOSE(syslog(LOG_DEBUG, "Address match"));
718
719 /*
720 * Connect to destination on "rsd"
721 */
722 sleeper *s = new sleeper(hm, &cli_sa, &ip, cli_port, src, &local_cli_sa,
723 csd, fds, dest_fd, maxfd);
724 if (s->pipe()) {
725 if (fragile)
726 s->queue();
727 else {
728 ONVERBOSE(syslog(LOG_DEBUG, "Could not connect to remote destination"));
729 socket_close(csd);
730 delete s;
731 }
732 }
733 }
734
735 void client_socket(int src_fd, fd_set *fds, int dest_fd[], int *maxfd, const struct ip_addr *actv_ip, const struct ip_addr *pasv_ip)
736 {
737 /*
738 * Copy data.
739 */
740 int trg_fd = dest_fd[src_fd];
741 int fail = buf_copy(src_fd, trg_fd, actv_ip, pasv_ip);
742 if (fail) {
743 /*
744 * Remove pair of communicating sockets.
745 */
746 DEBUGFD(syslog(LOG_DEBUG, "client_socket: closed socket (FD %d or %d)", src_fd, trg_fd));
747
748 fdclear(src_fd, fds, maxfd);
749 fdclear(trg_fd, fds, maxfd);
750 socket_close(src_fd);
751 socket_close(trg_fd);
752 gc_clean(src_fd);
753 gc_clean(trg_fd);
754 }
755 }
756
757 void tcp_forward(const struct ip_addr *listen, const struct ip_addr *source, vector<int> *port_list,
758 vector<host_map*> *map_list, const struct ip_addr *actv_ip, const struct ip_addr *pasv_ip,
759 int uid, int gid, int fragile)
760 {
761 fd_set fds, tmp_fds, ms_fds;
762 int fd_set_len = sizeof(fd_set);
763 int maxfd = 0;
764
765 FD_ZERO(&fds);
766 FD_ZERO(&ms_fds);
767
768 iterator<vector<int>,int> it(*port_list);
769 for (it.start(); it.cont(); it.next()) {
770
771 int port = it.get();
772 int sd = tcp_listen(listen, &port, 3);
773 if (sd == -1) {
774 close_sockets(port_list);
775 return;
776 }
777
778 fdset(sd, &fds, &maxfd); /* Add sd to set for select() */
779 FD_SET(sd, &ms_fds); /* Mark sd as mother socket */
780 }
781
782 if (drop_privileges(uid, gid)) {
783 close_sockets(port_list);
784 return;
785 }
786
787 int dest_fd[PORTFWD_MAX_FD];
788
789 for (int fd = 0; fd < PORTFWD_MAX_FD; ++fd)
790 grandchild_pid[fd] = -1;
791
792 for (;;) { /* forever */
793 /*
794 * Restores tmp_fds from fds.
795 */
796 memcpy(&tmp_fds, &fds, fd_set_len);
797
798 struct timeval tv;
799 struct timeval *tvp = NULL;
800 if (sleeper::queued()) {
801 time_t now = time(NULL);
802 tv.tv_sec = MAX(sleeper::earliest() - now, 0);
803 tv.tv_usec = 0;
804 tvp = &tv;
805 }
806
807 /*
808 * Wait for event: connection on mother sockets or data on anything else.
809 */
810 DEBUGFD(syslog(LOG_DEBUG, "TCP select(): %d FDs", maxfd));
811 int nd = select(maxfd, &tmp_fds, 0, 0, tvp);
812 if (nd == -1) {
813 if (errno != EINTR)
814 syslog(LOG_ERR, "TCP select() failed: %m");
815 continue;
816 }
817
818 while (sleeper::ready())
819 sleeper::handle_first();
820
821 for (int fd = 0; nd; ++fd)
822 if (FD_ISSET(fd, &tmp_fds)) {
823 --nd;
824 if (FD_ISSET(fd, &ms_fds))
825 mother_socket(fd, &fds, dest_fd, &maxfd, map_list, source, fragile);
826 else
827 client_socket(fd, &fds, dest_fd, &maxfd, actv_ip, pasv_ip);
828 }
829
830 } /* main loop */
831
832 }
833
834 static void do_udp_forward(const struct ip_addr *source,
835 const struct sockaddr_in *cli_sa,
836 const struct sockaddr_in *local_cli_sa,
837 vector<host_map*> *map_list,
838 const char *buf, int buf_len)
839 {
840 int port = ntohs(cli_sa->sin_port);
841 struct ip_addr ip;
842
843 ONVERBOSE(syslog(LOG_DEBUG, "UDP packet from: %s:%d\n",
844 inet_ntoa(cli_sa->sin_addr),
845 ntohs(cli_sa->sin_port)));
846
847 ip.addr = (char *) &(cli_sa->sin_addr.s_addr);
848 ip.len = addr_len;
849
850 iterator<vector<host_map*>,host_map*> it(*map_list);
851 for (it.start(); it.cont(); it.next()) {
852 host_map *hm = it.get();
853 if (hm->udp_match(&ip, port, buf, buf_len)) {
854 hm->udp_forward(source, cli_sa, local_cli_sa, &ip, port, buf, buf_len);
855 break;
856 }
857 }
858 }
859
860 int udp_listen(const struct ip_addr *ip, int port)
861 {
862 int sd = socket(PF_INET, SOCK_DGRAM, get_protonumber(P_UDP));
863 if (sd == -1) {
864 syslog(LOG_ERR, "Can't create UDP socket: %m");
865 return -1;
866 }
867 DEBUGFD(syslog(LOG_DEBUG, "socket open: FD %d", sd));
868
869 struct sockaddr_in sa;
870 sa.sin_family = PF_INET;
871 sa.sin_port = htons(port);
872 sa.sin_addr.s_addr = *((unsigned int *) ip->addr);
873 memset((char *) sa.sin_zero, 0, sizeof(sa.sin_zero));
874
875 if (bind(sd, (struct sockaddr *) &sa, sizeof(sa))) {
876 syslog(LOG_ERR, "Can't bind UDP socket: %m: %s:%d", inet_ntoa(sa.sin_addr), port);
877 socket_close(sd);
878 return -1;
879 }
880
881 /*
882 * Allow incoming broadcast datagrams
883 */
884 #ifndef NO_SO_BROADCAST
885 {
886 int one = 1;
887
888 ONVERBOSE2(syslog(LOG_DEBUG, "Setting SO_BROADCAST for incoming UDP socket"));
889
890 if (setsockopt(sd, SOL_SOCKET, SO_BROADCAST, (char *) &one, sizeof(one)))
891 syslog(LOG_ERR, "host_map::udp_forward(): Can't allow broadcast datagrams for incoming UDP socket port %d: setsockopt(SO_BROADCAST) failed: %m", port);
892 }
893 #endif /* NO_SO_BROADCAST */
894
895 ONVERBOSE(syslog(LOG_DEBUG, "Waiting UDP packet on %s:%d", inet_ntoa(sa.sin_addr), port));
896
897 return sd;
898 }
899
900 void udp_forward(const struct ip_addr *listen_addr, const struct ip_addr *source, vector<int> *port_list, vector<host_map*> *map_list, int uid, int gid)
901 {
902 fd_set fds, tmp_fds;
903 int fd_set_len = sizeof(fd_set);
904 int maxfd = 0;
905
906 FD_ZERO(&fds);
907
908 iterator<vector<int>,int> it(*port_list);
909 for (it.start(); it.cont(); it.next()) {
910
911 int port = it.get();
912 int sd = udp_listen(listen_addr, port);
913 if (sd == -1) {
914 close_sockets(port_list);
915 return;
916 }
917
918 fdset(sd, &fds, &maxfd);
919 }
920
921 if (drop_privileges(uid, gid)) {
922 close_sockets(port_list);
923 return;
924 }
925
926 char buf[BUF_SZ];
927 struct sockaddr_in cli_sa;
928 socklen_t cli_sa_len = sizeof(struct sockaddr_in);
929
930 for (;;) { /* forever */
931 /*
932 * Restores tmp_fds from fds.
933 */
934 memcpy(&tmp_fds, &fds, fd_set_len);
935
936 /*
937 * Wait for data.
938 */
939 DEBUGFD(syslog(LOG_DEBUG, "UDP select(): %d FDs", maxfd));
940 int nd = select(maxfd, &tmp_fds, 0, 0, 0);
941 if (nd == -1) {
942 if (errno != EINTR)
943 syslog(LOG_ERR, "UDP select() failed: %m");
944 continue;
945 }
946
947 for (int fd = 0; nd; ++fd)
948 if (FD_ISSET(fd, &tmp_fds)) {
949 --nd;
950
951 int rd = recvfrom(fd, buf, BUF_SZ, 0, (struct sockaddr *) &cli_sa, &cli_sa_len);
952 if (rd == -1) {
953 syslog(LOG_ERR, "Can't receive UDP packet: %m");
954 continue;
955 }
956
957 /*
958 * Get local address
959 */
960 struct sockaddr_in local_cli_sa;
961 socklen_t local_cli_sa_len = sizeof(local_cli_sa);
962 if (getsockname(fd, (struct sockaddr *) &local_cli_sa, &local_cli_sa_len)) {
963 syslog(LOG_ERR, "udp_forward(): Can't get local sockname: %m");
964 memset(&local_cli_sa, 0, local_cli_sa_len);
965 }
966
967 do_udp_forward(source, &cli_sa, &local_cli_sa, map_list, buf, rd);
968 }
969
970 } /* main loop */
971
972 }
973