X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fdns%2Fgnunet-helper-dns.c;h=43d3954e44e033991c2feddb0b4c150f09730c32;hb=2156a54c589c358442a366e00f3aeb9de6d89af0;hp=c5d36958fa4d94ae7da8695713872db575b21c5a;hpb=a8e3c72d3d1e4609423d4089f5e966a6c8d06564;p=oweals%2Fgnunet.git diff --git a/src/dns/gnunet-helper-dns.c b/src/dns/gnunet-helper-dns.c index c5d36958f..43d3954e4 100644 --- a/src/dns/gnunet-helper-dns.c +++ b/src/dns/gnunet-helper-dns.c @@ -35,7 +35,9 @@ * administrators must take care to not cause conflicts with these * values (it was deemed safest to hardcode them as passing these * values as arguments might permit messing with arbitrary firewall - * rules, which would be dangerous). + * rules, which would be dangerous). Traffic coming from the same + * group ID as the effective group ID that this process is running + * as is not intercepted. * * The code first sets up the virtual interface, then begins to * redirect the DNS traffic to it, and then on errors or SIGTERM shuts @@ -95,12 +97,12 @@ struct in6_ifreq /** * Name and full path of IPTABLES binary. */ -#define SBIN_IPTABLES "/sbin/iptables" +static const char *sbin_iptables; /** * Name and full path of IPTABLES binary. */ -#define SBIN_IP "/sbin/ip" +static const char *sbin_ip; /** * Port for DNS traffic. @@ -173,6 +175,10 @@ fork_and_exec (const char *file, if (0 == pid) { /* we are the child process */ + /* close stdin/stdout to not cause interference + with the helper's main protocol! */ + (void) close (0); + (void) close (1); (void) execv (file, cmd); /* can only get here on error */ fprintf (stderr, @@ -573,6 +579,7 @@ run (int fd_tun) bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos); if (-1 == bufin_size) { + bufin_read = NULL; if ( (errno == EINTR) || (errno == EAGAIN) ) continue; @@ -581,6 +588,7 @@ run (int fd_tun) } if (0 == bufin_size) { + bufin_read = NULL; fprintf (stderr, "EOF on stdin\n"); return; } @@ -653,7 +661,6 @@ PROCESS_BUFFER: * 3: IPv6 netmask length in bits ("64") * 4: IPv4 address for the tunnel ("1.2.3.4") * 5: IPv4 netmask ("255.255.0.0") - * 6: PORT to not hijack ("55533") * @return 0 on success, otherwise code indicating type of error: * 1 wrong number of arguments * 2 invalid arguments (i.e. port number / prefix length wrong) @@ -662,7 +669,7 @@ PROCESS_BUFFER: * 5 failed to initialize tunnel interface * 6 failed to initialize control pipe * 8 failed to change routing table, cleanup successful - * 9-23 failed to undo some changes to routing table + * 9-23 failed to change routing table and failed to undo some changes to routing table * 24 failed to drop privs * 25-39 failed to drop privs and then failed to undo some changes to routing table * 40 failed to regain privs @@ -672,50 +679,43 @@ PROCESS_BUFFER: int main (int argc, char *const*argv) { - unsigned int port; - char localport[6]; int r; char dev[IFNAMSIZ]; + char mygid[32]; int fd_tun; - if (7 != argc) + if (6 != argc) { fprintf (stderr, "Fatal: must supply 6 arguments!\n"); return 1; } /* verify that the binaries were care about are executable */ - if (0 != access (SBIN_IPTABLES, X_OK)) + if (0 == access ("/sbin/iptables", X_OK)) + sbin_iptables = "/sbin/iptables"; + else if (0 == access ("/usr/sbin/iptables", X_OK)) + sbin_iptables = "/usr/sbin/iptables"; + else { fprintf (stderr, - "`%s' is not executable: %s\n", - SBIN_IPTABLES, + "Fatal: executable iptables not found in approved directories: %s\n", strerror (errno)); return 3; } - if (0 != access (SBIN_IP, X_OK)) + if (0 == access ("/sbin/ip", X_OK)) + sbin_ip = "/sbin/ip"; + else if (0 == access ("/usr/sbin/ip", X_OK)) + sbin_ip = "/usr/sbin/ip"; + else { - fprintf (stderr, - "`%s' is not executable: %s\n", - SBIN_IP, + fprintf (stderr, + "Fatal: executable ip not found in approved directories: %s\n", strerror (errno)); return 4; } - /* validate port number */ - port = atoi (argv[6]); - if ( (port == 0) || (port >= 65536) ) - { - fprintf (stderr, - "Port `%u' is invalid\n", - port); - return 2; - } - /* print port number to string for command-line use*/ - (void) snprintf (localport, - sizeof (localport), - "%u", - port); + /* setup 'mygid' string */ + snprintf (mygid, sizeof (mygid), "%d", (int) getegid()); /* do not die on SIGPIPE */ if (SIG_ERR == signal (SIGPIPE, SIG_IGN)) @@ -760,7 +760,9 @@ main (int argc, char *const*argv) return 6; } } - if (SIG_ERR == signal (SIGINT, &signal_handler)) + if ( (SIG_ERR == signal (SIGTERM, &signal_handler)) || + (SIG_ERR == signal (SIGINT, &signal_handler)) || + (SIG_ERR == signal (SIGHUP, &signal_handler)) ) { fprintf (stderr, "Fatal: could not initialize signal handler: %s\n", @@ -779,7 +781,9 @@ main (int argc, char *const*argv) if (-1 == (fd_tun = init_tun (dev))) { fprintf (stderr, "Fatal: could not initialize tun-interface\n"); + (void) signal (SIGTERM, SIG_IGN); (void) signal (SIGINT, SIG_IGN); + (void) signal (SIGHUP, SIG_IGN); (void) close (cpipe[0]); (void) close (cpipe[1]); return 5; @@ -793,7 +797,9 @@ main (int argc, char *const*argv) if ((prefix_len < 1) || (prefix_len > 127)) { fprintf (stderr, "Fatal: prefix_len out of range\n"); + (void) signal (SIGTERM, SIG_IGN); (void) signal (SIGINT, SIG_IGN); + (void) signal (SIGHUP, SIG_IGN); (void) close (cpipe[0]); (void) close (cpipe[1]); return 2; @@ -809,29 +815,30 @@ main (int argc, char *const*argv) } /* update routing tables -- next part why we need SUID! */ - /* Forward everything from the given local port (with destination - to port 53, and only for UDP) without hijacking */ + /* Forward everything from our EGID (which should only be held + by the 'gnunet-service-dns') and with destination + to port 53 on UDP, without hijacking */ r = 8; /* failed to fully setup routing table */ { char *const mangle_args[] = { - "iptables", "-t", "mangle", "-I", "OUTPUT", "1", "-p", - "udp", "--sport", localport, "--dport", DNS_PORT, "-j", + "iptables", "-m", "owner", "-t", "mangle", "-I", "OUTPUT", "1", "-p", + "udp", "--gid-owner", mygid, "--dport", DNS_PORT, "-j", "ACCEPT", NULL }; - if (0 != fork_and_exec (SBIN_IPTABLES, mangle_args)) - goto cleanup_mangle_1; + if (0 != fork_and_exec (sbin_iptables, mangle_args)) + goto cleanup_rest; } /* Mark all of the other DNS traffic using our mark DNS_MARK */ { char *const mark_args[] = { - "iptables", "-t", "mangle", "-I", "OUTPUT", DNS_TABLE, "-p", + "iptables", "-t", "mangle", "-I", "OUTPUT", "2", "-p", "udp", "--dport", DNS_PORT, "-j", "MARK", "--set-mark", DNS_MARK, NULL }; - if (0 != fork_and_exec (SBIN_IPTABLES, mark_args)) - goto cleanup_mark_2; + if (0 != fork_and_exec (sbin_iptables, mark_args)) + goto cleanup_mangle_1; } /* Forward all marked DNS traffic to our DNS_TABLE */ { @@ -839,18 +846,18 @@ main (int argc, char *const*argv) { "ip", "rule", "add", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL }; - if (0 != fork_and_exec (SBIN_IP, forward_args)) - goto cleanup_forward_3; + if (0 != fork_and_exec (sbin_ip, forward_args)) + goto cleanup_mark_2; } /* Finally, add rule in our forwarding table to pass to our virtual interface */ { char *const route_args[] = { - "ip", "route", "add", "default", "via", dev, + "ip", "route", "add", "default", "dev", dev, "table", DNS_TABLE, NULL }; - if (0 != fork_and_exec (SBIN_IP, route_args)) - goto cleanup_route_4; + if (0 != fork_and_exec (sbin_ip, route_args)) + goto cleanup_forward_3; } /* drop privs *except* for the saved UID; this is not perfect, but better @@ -877,7 +884,6 @@ main (int argc, char *const*argv) /* now forward until we hit a problem */ run (fd_tun); - (void) close (fd_tun); /* now need to regain privs so we can remove the firewall rules we added! */ #ifdef HAVE_SETRESUID @@ -902,10 +908,10 @@ main (int argc, char *const*argv) { char *const route_clean_args[] = { - "ip", "route", "del", "default", "via", dev, + "ip", "route", "del", "default", "dev", dev, "table", DNS_TABLE, NULL }; - if (0 != fork_and_exec (SBIN_IP, route_clean_args)) + if (0 != fork_and_exec (sbin_ip, route_clean_args)) r += 1; } cleanup_forward_3: @@ -914,7 +920,7 @@ main (int argc, char *const*argv) { "ip", "rule", "del", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL }; - if (0 != fork_and_exec (SBIN_IP, forward_clean_args)) + if (0 != fork_and_exec (sbin_ip, forward_clean_args)) r += 2; } cleanup_mark_2: @@ -924,26 +930,31 @@ main (int argc, char *const*argv) "iptables", "-t", "mangle", "-D", "OUTPUT", "-p", "udp", "--dport", DNS_PORT, "-j", "MARK", "--set-mark", DNS_MARK, NULL }; - if (0 != fork_and_exec (SBIN_IPTABLES, mark_clean_args)) + if (0 != fork_and_exec (sbin_iptables, mark_clean_args)) r += 4; } cleanup_mangle_1: { char *const mangle_clean_args[] = { - "iptables", "-t", "mangle", "-D", "OUTPUT", "-p", "udp", - "--sport", localport, "--dport", DNS_PORT, "-j", "ACCEPT", + "iptables", "-m", "owner", "-t", "mangle", "-D", "OUTPUT", "-p", "udp", + "--gid-owner", mygid, "--dport", DNS_PORT, "-j", "ACCEPT", NULL }; - if (0 != fork_and_exec (SBIN_IPTABLES, mangle_clean_args)) + if (0 != fork_and_exec (sbin_iptables, mangle_clean_args)) r += 8; } - /* remove SIGINT handler so we can close the pipes */ + cleanup_rest: + /* close virtual interface */ + (void) close (fd_tun); + /* remove signal handler so we can close the pipes */ + (void) signal (SIGTERM, SIG_IGN); (void) signal (SIGINT, SIG_IGN); + (void) signal (SIGHUP, SIG_IGN); (void) close (cpipe[0]); (void) close (cpipe[1]); return r; } -/* end of gnunet-helper-hijack-dns.c */ +/* end of gnunet-helper-dns.c */