diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-01-14 20:58:36 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-01-14 20:58:36 +0000 |
commit | 4f285bb38af149f35a1bd3e730ac6bac7b14fd53 (patch) | |
tree | 690774a9d24d61f7713f38ca3574d0b620ff661b /src/exit/gnunet-helper-exit.c | |
parent | c1e66b2a4e2ccf3fc4f3396d97254fa058c6ae73 (diff) | |
download | gnunet-4f285bb38af149f35a1bd3e730ac6bac7b14fd53.tar.gz gnunet-4f285bb38af149f35a1bd3e730ac6bac7b14fd53.zip |
changing exit helper code to automatically do the network configuration for an exit node (by running sysctl/iptables commands as necessary)
Diffstat (limited to 'src/exit/gnunet-helper-exit.c')
-rw-r--r-- | src/exit/gnunet-helper-exit.c | 175 |
1 files changed, 147 insertions, 28 deletions
diff --git a/src/exit/gnunet-helper-exit.c b/src/exit/gnunet-helper-exit.c index 84b6e6e65..d1db2a6e6 100644 --- a/src/exit/gnunet-helper-exit.c +++ b/src/exit/gnunet-helper-exit.c | |||
@@ -19,16 +19,21 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @file exit/gnunet-helper-exit.c | 22 | * @file exit/gnunet-helper-exit.c |
23 | * @brief the helper for exit nodes. Opens a virtual network-interface, | 23 | * |
24 | * sends data received on the if to stdout, sends data received on stdin to the | 24 | * @brief the helper for exit nodes. Opens a virtual |
25 | * interface | 25 | * network-interface, sends data received on the if to stdout, sends |
26 | * @author Philipp Tölke | 26 | * data received on stdin to the interface. The code also enables |
27 | * IPv4/IPv6 forwarding and NAT on the current system (the latter on | ||
28 | * an interface specified on the command-line); these changes to the | ||
29 | * network configuration are NOT automatically undone when the program | ||
30 | * is stopped (this is because we cannot be sure that some other | ||
31 | * application didn't enable them before or after us; also, these | ||
32 | * changes should be mostly harmless as it simply turns the system | ||
33 | * into a router). | ||
27 | * | 34 | * |
28 | * TODO: | 35 | * @author Philipp Tölke |
29 | * - need to add code to setup ip_forwarding and NAT (for IPv4) so that | 36 | * @author Christian Grothoff |
30 | * users don't need to ALSO do admin work; this is what will set | ||
31 | * gnunet-helper-exit.c apart from gnunet-helper-vpn.c | ||
32 | * | 37 | * |
33 | * The following list of people have reviewed this code and considered | 38 | * The following list of people have reviewed this code and considered |
34 | * it safe since the last modification (if you reviewed it, please | 39 | * it safe since the last modification (if you reviewed it, please |
@@ -54,6 +59,17 @@ | |||
54 | */ | 59 | */ |
55 | #define MAX_SIZE 65536 | 60 | #define MAX_SIZE 65536 |
56 | 61 | ||
62 | /** | ||
63 | * Path to 'sysctl' binary. | ||
64 | */ | ||
65 | #define SBIN_SYSCTL "/sbin/sysctl" | ||
66 | |||
67 | /** | ||
68 | * Path to 'iptables' binary. | ||
69 | */ | ||
70 | #define SBIN_IPTABLES "/sbin/iptables" | ||
71 | |||
72 | |||
57 | #ifndef _LINUX_IN6_H | 73 | #ifndef _LINUX_IN6_H |
58 | /** | 74 | /** |
59 | * This is in linux/include/net/ipv6.h, but not always exported... | 75 | * This is in linux/include/net/ipv6.h, but not always exported... |
@@ -67,6 +83,58 @@ struct in6_ifreq | |||
67 | #endif | 83 | #endif |
68 | 84 | ||
69 | 85 | ||
86 | |||
87 | /** | ||
88 | * Run the given command and wait for it to complete. | ||
89 | * | ||
90 | * @param file name of the binary to run | ||
91 | * @param cmd command line arguments (as given to 'execv') | ||
92 | * @return 0 on success, 1 on any error | ||
93 | */ | ||
94 | static int | ||
95 | fork_and_exec (const char *file, | ||
96 | char *const cmd[]) | ||
97 | { | ||
98 | int status; | ||
99 | pid_t pid; | ||
100 | pid_t ret; | ||
101 | |||
102 | pid = fork (); | ||
103 | if (-1 == pid) | ||
104 | { | ||
105 | fprintf (stderr, | ||
106 | "fork failed: %s\n", | ||
107 | strerror (errno)); | ||
108 | return 1; | ||
109 | } | ||
110 | if (0 == pid) | ||
111 | { | ||
112 | /* we are the child process */ | ||
113 | (void) execv (file, cmd); | ||
114 | /* can only get here on error */ | ||
115 | fprintf (stderr, | ||
116 | "exec `%s' failed: %s\n", | ||
117 | file, | ||
118 | strerror (errno)); | ||
119 | _exit (1); | ||
120 | } | ||
121 | /* keep running waitpid as long as the only error we get is 'EINTR' */ | ||
122 | while ( (-1 == (ret = waitpid (pid, &status, 0))) && | ||
123 | (errno == EINTR) ); | ||
124 | if (-1 == ret) | ||
125 | { | ||
126 | fprintf (stderr, | ||
127 | "waitpid failed: %s\n", | ||
128 | strerror (errno)); | ||
129 | return 1; | ||
130 | } | ||
131 | if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)))) | ||
132 | return 1; | ||
133 | /* child process completed and returned success, we're happy */ | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | |||
70 | /** | 138 | /** |
71 | * Creates a tun-interface called dev; | 139 | * Creates a tun-interface called dev; |
72 | * | 140 | * |
@@ -521,12 +589,13 @@ PROCESS_BUFFER: | |||
521 | * Open VPN tunnel interface. | 589 | * Open VPN tunnel interface. |
522 | * | 590 | * |
523 | * @param argc must be 6 | 591 | * @param argc must be 6 |
524 | * @param argv 0: binary name (gnunet-helper-vpn) | 592 | * @param argv 0: binary name ("gnunet-helper-vpn") |
525 | * 1: tunnel interface name (gnunet-vpn) | 593 | * 1: tunnel interface name ("gnunet-vpn") |
526 | * 2: IPv6 address (::1) | 594 | * 2: IPv4 "physical" interface name ("eth0"), or "%" to not do IPv4 NAT |
527 | * 3: IPv6 netmask length in bits (64) | 595 | * 3: IPv6 address ("::1"), or "-" to skip IPv6 |
528 | * 4: IPv4 address (1.2.3.4) | 596 | * 4: IPv6 netmask length in bits ("64") [ignored if #4 is "-"] |
529 | * 5: IPv4 netmask (255.255.0.0) | 597 | * 5: IPv4 address ("1.2.3.4"), or "-" to skip IPv4 |
598 | * 6: IPv4 netmask ("255.255.0.0") [ignored if #4 is "-"] | ||
530 | */ | 599 | */ |
531 | int | 600 | int |
532 | main (int argc, char **argv) | 601 | main (int argc, char **argv) |
@@ -535,11 +604,17 @@ main (int argc, char **argv) | |||
535 | int fd_tun; | 604 | int fd_tun; |
536 | int global_ret; | 605 | int global_ret; |
537 | 606 | ||
538 | if (6 != argc) | 607 | if (7 != argc) |
539 | { | 608 | { |
540 | fprintf (stderr, "Fatal: must supply 5 arguments!\n"); | 609 | fprintf (stderr, "Fatal: must supply 5 arguments!\n"); |
541 | return 1; | 610 | return 1; |
542 | } | 611 | } |
612 | if ( (0 == strcmp (argv[3], "-")) && | ||
613 | (0 == strcmp (argv[5], "-")) ) | ||
614 | { | ||
615 | fprintf (stderr, "Fatal: disabling both IPv4 and IPv6 makes no sense.\n"); | ||
616 | return 1; | ||
617 | } | ||
543 | 618 | ||
544 | strncpy (dev, argv[1], IFNAMSIZ); | 619 | strncpy (dev, argv[1], IFNAMSIZ); |
545 | dev[IFNAMSIZ - 1] = '\0'; | 620 | dev[IFNAMSIZ - 1] = '\0'; |
@@ -550,24 +625,66 @@ main (int argc, char **argv) | |||
550 | return 1; | 625 | return 1; |
551 | } | 626 | } |
552 | 627 | ||
628 | if (0 != strcmp (argv[3], "-")) | ||
553 | { | 629 | { |
554 | const char *address = argv[2]; | ||
555 | long prefix_len = atol (argv[3]); | ||
556 | |||
557 | if ((prefix_len < 1) || (prefix_len > 127)) | ||
558 | { | 630 | { |
559 | fprintf (stderr, "Fatal: prefix_len out of range\n"); | 631 | const char *address = argv[3]; |
560 | return 1; | 632 | long prefix_len = atol (argv[4]); |
633 | |||
634 | if ((prefix_len < 1) || (prefix_len > 127)) | ||
635 | { | ||
636 | fprintf (stderr, "Fatal: prefix_len out of range\n"); | ||
637 | return 1; | ||
638 | } | ||
639 | set_address6 (dev, address, prefix_len); | ||
640 | } | ||
641 | { | ||
642 | char *const sysctl_args[] = | ||
643 | { | ||
644 | "sysctl", "-w", "net.ipv6.conf.all.forwarding=1", NULL | ||
645 | }; | ||
646 | if (0 != fork_and_exec (SBIN_SYSCTL, | ||
647 | sysctl_args)) | ||
648 | { | ||
649 | fprintf (stderr, | ||
650 | "Failed to enable IPv6 forwarding. Will continue anyway.\n"); | ||
651 | } | ||
561 | } | 652 | } |
562 | |||
563 | set_address6 (dev, address, prefix_len); | ||
564 | } | 653 | } |
565 | 654 | ||
655 | if (0 != strcmp (argv[5], "-")) | ||
566 | { | 656 | { |
567 | const char *address = argv[4]; | 657 | { |
568 | const char *mask = argv[5]; | 658 | const char *address = argv[5]; |
569 | 659 | const char *mask = argv[6]; | |
570 | set_address4 (dev, address, mask); | 660 | |
661 | set_address4 (dev, address, mask); | ||
662 | } | ||
663 | { | ||
664 | char *const sysctl_args[] = | ||
665 | { | ||
666 | "sysctl", "-w", "net.ipv4.ip_forward=1", NULL | ||
667 | }; | ||
668 | if (0 != fork_and_exec (SBIN_SYSCTL, | ||
669 | sysctl_args)) | ||
670 | { | ||
671 | fprintf (stderr, | ||
672 | "Failed to enable IPv4 forwarding. Will continue anyway.\n"); | ||
673 | } | ||
674 | } | ||
675 | if (0 != strcmp (argv[2], "%")) | ||
676 | { | ||
677 | char *const iptables_args[] = | ||
678 | { | ||
679 | "iptables", "-t", "nat", "-A", "POSTROUTING", "-o", argv[2], "-j", "MASQUERADE", NULL | ||
680 | }; | ||
681 | if (0 != fork_and_exec (SBIN_IPTABLES, | ||
682 | iptables_args)) | ||
683 | { | ||
684 | fprintf (stderr, | ||
685 | "Failed to enable IPv4 masquerading (NAT). Will continue anyway.\n"); | ||
686 | } | ||
687 | } | ||
571 | } | 688 | } |
572 | 689 | ||
573 | uid_t uid = getuid (); | 690 | uid_t uid = getuid (); |
@@ -599,3 +716,5 @@ main (int argc, char **argv) | |||
599 | close (fd_tun); | 716 | close (fd_tun); |
600 | return global_ret; | 717 | return global_ret; |
601 | } | 718 | } |
719 | |||
720 | /* end of gnunet-helper-exit.c */ | ||