Ejemplo n.º 1
0
bool
init_redirector() {
  if ( !init_tun( TUN_INTERFACE ) ) {
    error( "Cannot create a tun interface." );
    return false;
  }

  if ( host_db != NULL ) {
    error( "Host database is already created." );
    return false;
  }

  host_db = create_hash( compare_ip_address, hash_ip_address );

  set_fd_handler( fd, read_tun_fd, NULL, NULL, NULL );
  set_readable( fd, true );

  add_periodic_event_callback( HOST_DB_AGING_INTERVAL, age_host_db, NULL );

  return true;
}
Ejemplo n.º 2
0
/**
 * Open VPN tunnel interface.
 *
 * @param argc must be 6
 * @param argv 0: binary name ("gnunet-helper-exit")
 *             1: tunnel interface name ("gnunet-exit")
 *             2: IPv4 "physical" interface name ("eth0"), or "%" to not do IPv4 NAT
 *             3: IPv6 address ("::1"), or "-" to skip IPv6
 *             4: IPv6 netmask length in bits ("64") [ignored if #4 is "-"]
 *             5: IPv4 address ("1.2.3.4"), or "-" to skip IPv4
 *             6: IPv4 netmask ("255.255.0.0") [ignored if #4 is "-"]
 */
int
main (int argc, char **argv)
{
  char dev[IFNAMSIZ];
  int fd_tun;
  int global_ret;

  if (7 != argc)
  {
    fprintf (stderr, "Fatal: must supply 6 arguments!\n");
    return 1;
  }
  if ( (0 == strcmp (argv[3], "-")) &&
       (0 == strcmp (argv[5], "-")) )
  {
    fprintf (stderr, "Fatal: disabling both IPv4 and IPv6 makes no sense.\n");
    return 1;
  }
  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, 
	     "Fatal: executable iptables not found in approved directories: %s\n",
	     strerror (errno));
    return 1;
  }
  if (0 == access ("/sbin/sysctl", X_OK))
    sbin_sysctl = "/sbin/sysctl";
  else if (0 == access ("/usr/sbin/sysctl", X_OK))
    sbin_sysctl = "/usr/sbin/sysctl";
  else
  {
    fprintf (stderr,
	     "Fatal: executable sysctl not found in approved directories: %s\n",
	     strerror (errno));
    return 1;
  }

  strncpy (dev, argv[1], IFNAMSIZ);
  dev[IFNAMSIZ - 1] = '\0';

  if (-1 == (fd_tun = init_tun (dev)))
  {
    fprintf (stderr, 
	     "Fatal: could not initialize tun-interface `%s' with IPv6 %s/%s and IPv4 %s/%s\n",
	     dev,
	     argv[3],
	     argv[4],
	     argv[5],
	     argv[6]);
    return 1;
  }

  if (0 != strcmp (argv[3], "-"))
  {
    {
      const char *address = argv[3];
      long prefix_len = atol (argv[4]);
      
      if ((prefix_len < 1) || (prefix_len > 127))
      {
	fprintf (stderr, "Fatal: prefix_len out of range\n");
	return 1;
      }      
      set_address6 (dev, address, prefix_len);    
    }
    {
      char *const sysctl_args[] =
	{
	  "sysctl", "-w", "net.ipv6.conf.all.forwarding=1", NULL
	};
      if (0 != fork_and_exec (sbin_sysctl,
			      sysctl_args))
      {
	fprintf (stderr,
		 "Failed to enable IPv6 forwarding.  Will continue anyway.\n");
      }    
    }
  }

  if (0 != strcmp (argv[5], "-"))
  {
    {
      const char *address = argv[5];
      const char *mask = argv[6];
      
      set_address4 (dev, address, mask);
    }
    {
      char *const sysctl_args[] =
	{
	  "sysctl", "-w", "net.ipv4.ip_forward=1", NULL
	};
      if (0 != fork_and_exec (sbin_sysctl,
			      sysctl_args))
      {
	fprintf (stderr,
		 "Failed to enable IPv4 forwarding.  Will continue anyway.\n");
      }    
    }
    if (0 != strcmp (argv[2], "%"))
    {
      char *const iptables_args[] =
	{
	  "iptables", "-t", "nat", "-A", "POSTROUTING", "-o", argv[2], "-j", "MASQUERADE", NULL
	};
      if (0 != fork_and_exec (sbin_iptables,
			      iptables_args))
      {
	fprintf (stderr,
		 "Failed to enable IPv4 masquerading (NAT).  Will continue anyway.\n");
      }    
    }
  }
  
  uid_t uid = getuid ();
#ifdef HAVE_SETRESUID
  if (0 != setresuid (uid, uid, uid))
  {
    fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
    global_ret = 2;
    goto cleanup;
  }
#else
  if (0 != (setuid (uid) | seteuid (uid)))
  {
    fprintf (stderr, "Failed to setuid: %s\n", strerror (errno));
    global_ret = 2;
    goto cleanup;
  }
#endif

  if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
  {
    fprintf (stderr, "Failed to protect against SIGPIPE: %s\n",
             strerror (errno));
    /* no exit, we might as well die with SIGPIPE should it ever happen */
  }
  run (fd_tun);
  global_ret = 0;
 cleanup:
  (void) close (fd_tun);
  return global_ret;
}
Ejemplo n.º 3
0
/**
 * Main function of "gnunet-helper-dns", which opens a VPN tunnel interface,
 * redirects all outgoing DNS traffic (except from the specified port) to that
 * interface and then passes traffic from and to the interface via stdin/stdout.
 *
 * Once stdin/stdout close or have other errors, the tunnel is closed and the
 * DNS traffic redirection is stopped.
 *
 * @param argc number of arguments
 * @param argv 0: binary name (should be "gnunet-helper-vpn")
 *             1: tunnel interface name (typically "gnunet-dns")
 *             2: IPv6 address for the tunnel ("FE80::1")
 *             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: skip sysctl, routing and iptables setup ("0")
 * @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)
 *         3 iptables not executable
 *         4 ip not executable
 *         5 failed to initialize tunnel interface
 *         6 failed to initialize control pipe
 *         8 failed to change routing table, cleanup successful
 *         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
 *         41-55 failed to regain prisv and then failed to undo some changes to routing table
 *         254 insufficient priviledges
 *         255 failed to handle kill signal properly
 */
int
main (int argc, char *const*argv)
{
  int r;
  char dev[IFNAMSIZ];
  char mygid[32];
  int fd_tun;
  uid_t uid;
  int nortsetup = 0;

  if (7 != argc)
  {
    fprintf (stderr, "Fatal: must supply 6 arguments!\n");
    return 1;
  }

  /* assert privs so we can modify the firewall rules! */
  uid = getuid ();
#ifdef HAVE_SETRESUID
  if (0 != setresuid (uid, 0, 0))
  {
    fprintf (stderr, "Failed to setresuid to root: %s\n", strerror (errno));
    return 254;
  }
#else
  if (0 != seteuid (0))
  {
    fprintf (stderr, "Failed to seteuid back to root: %s\n", strerror (errno));
    return 254;
  }
#endif
  if (0 == strncmp (argv[6], "1", 2))
    nortsetup = 1;

  if (0 == nortsetup)
  {
    /* verify that the binaries we care about are executable */
    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,
	       "Fatal: executable iptables not found in approved directories: %s\n",
	       strerror (errno));
      return 3;
    }
    if (0 == access ("/sbin/ip6tables", X_OK))
      sbin_ip6tables = "/sbin/ip6tables";
    else if (0 == access ("/usr/sbin/ip6tables", X_OK))
      sbin_ip6tables = "/usr/sbin/ip6tables";
    else
    {
      fprintf (stderr,
	       "Fatal: executable ip6tables not found in approved directories: %s\n",
	       strerror (errno));
      return 3;
    }
    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,
	       "Fatal: executable ip not found in approved directories: %s\n",
	       strerror (errno));
      return 4;
    }
    if (0 == access ("/sbin/sysctl", X_OK))
      sbin_sysctl = "/sbin/sysctl";
    else if (0 == access ("/usr/sbin/sysctl", X_OK))
      sbin_sysctl = "/usr/sbin/sysctl";
    else
    {
      fprintf (stderr,
               "Fatal: executable sysctl not found in approved directories: %s\n",
               strerror (errno));
      return 5;
    }
  }

  /* setup 'mygid' string */
  snprintf (mygid, sizeof (mygid), "%d", (int) getegid());

  /* do not die on SIGPIPE */
  if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
  {
    fprintf (stderr, "Failed to protect against SIGPIPE: %s\n",
             strerror (errno));
    return 7;
  }

  /* setup pipe to shutdown nicely on SIGINT */
  if (0 != pipe (cpipe))
  {
    fprintf (stderr,
	     "Fatal: could not setup control pipe: %s\n",
	     strerror (errno));
    return 6;
  }
  if (cpipe[0] >= FD_SETSIZE)
  {
    fprintf (stderr, "Pipe file descriptor to large: %d", cpipe[0]);
    (void) close (cpipe[0]);
    (void) close (cpipe[1]);
    return 6;
  }
  {
    /* make pipe non-blocking, as we theoretically could otherwise block
       in the signal handler */
    int flags = fcntl (cpipe[1], F_GETFL);
    if (-1 == flags)
    {
      fprintf (stderr, "Failed to read flags for pipe: %s", strerror (errno));
      (void) close (cpipe[0]);
      (void) close (cpipe[1]);
      return 6;
    }
    flags |= O_NONBLOCK;
    if (0 != fcntl (cpipe[1], F_SETFL, flags))
    {
      fprintf (stderr, "Failed to make pipe non-blocking: %s", strerror (errno));
      (void) close (cpipe[0]);
      (void) close (cpipe[1]);
      return 6;
    }
  }
  if ( (SIG_ERR == signal (SIGTERM, &signal_handler)) ||
#if (SIGTERM != GNUNET_TERM_SIG)
       (SIG_ERR == signal (GNUNET_TERM_SIG, &signal_handler)) ||
#endif
       (SIG_ERR == signal (SIGINT, &signal_handler)) ||
       (SIG_ERR == signal (SIGHUP, &signal_handler)) )
  {
    fprintf (stderr,
	     "Fatal: could not initialize signal handler: %s\n",
	     strerror (errno));
    (void) close (cpipe[0]);
    (void) close (cpipe[1]);
    return 7;
  }


  /* get interface name */
  strncpy (dev, argv[1], IFNAMSIZ);
  dev[IFNAMSIZ - 1] = '\0';

  /* Disable rp filtering */
  if (0 == nortsetup)
  {
    char *const sysctl_args[] = {"sysctl", "-w",
      "net.ipv4.conf.all.rp_filter=0", NULL};
    char *const sysctl_args2[] = {"sysctl", "-w",
      "net.ipv4.conf.default.rp_filter=0", NULL};
    if ((0 != fork_and_exec (sbin_sysctl, sysctl_args)) ||
        (0 != fork_and_exec (sbin_sysctl, sysctl_args2)))
    {
      fprintf (stderr,
               "Failed to disable rp filtering.\n");
      return 5;
    }
  }


  /* now open virtual interface (first part that requires root) */
  if (-1 == (fd_tun = init_tun (dev)))
  {
    fprintf (stderr, "Fatal: could not initialize tun-interface\n");
    (void) signal (SIGTERM, SIG_IGN);
#if (SIGTERM != GNUNET_TERM_SIG)
    (void) signal (GNUNET_TERM_SIG, SIG_IGN);
#endif
    (void) signal (SIGINT, SIG_IGN);
    (void) signal (SIGHUP, SIG_IGN);
    (void) close (cpipe[0]);
    (void) close (cpipe[1]);
    return 5;
  }

  /* now set interface addresses */
  {
    const char *address = argv[2];
    long prefix_len = atol (argv[3]);

    if ((prefix_len < 1) || (prefix_len > 127))
    {
      fprintf (stderr, "Fatal: prefix_len out of range\n");
      (void) signal (SIGTERM, SIG_IGN);
#if (SIGTERM != GNUNET_TERM_SIG)
    (void) signal (GNUNET_TERM_SIG, SIG_IGN);
#endif
      (void) signal (SIGINT, SIG_IGN);
      (void) signal (SIGHUP, SIG_IGN);
      (void) close (cpipe[0]);
      (void) close (cpipe[1]);
      return 2;
    }
    set_address6 (dev, address, prefix_len);
  }

  {
    const char *address = argv[4];
    const char *mask = argv[5];

    set_address4 (dev, address, mask);
  }


  /* update routing tables -- next part why we need SUID! */
  /* 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 */
  if (0 == nortsetup)
  {
    r = 8; /* failed to fully setup routing table */
    {
      char *const mangle_args[] =
        {
	 "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_rest;
    }
    {
      char *const mangle_args[] =
        {
	 "ip6tables", "-m", "owner", "-t", "mangle", "-I", "OUTPUT", "1", "-p",
	 "udp", "--gid-owner", mygid, "--dport", DNS_PORT, "-j",
	 "ACCEPT", NULL
        };
      if (0 != fork_and_exec (sbin_ip6tables, mangle_args))
        goto cleanup_mangle_1b;
    }
    /* Mark all of the other DNS traffic using our mark DNS_MARK,
       unless it is on a link-local IPv6 address, which we cannot support. */
    {
      char *const mark_args[] =
        {
	 "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_mangle_1;
    }
    {
      char *const mark_args[] =
        {
	 "ip6tables", "-t", "mangle", "-I", "OUTPUT", "2", "-p",
	 "udp", "--dport", DNS_PORT,
         "!", "-s", "fe80::/10", /* this line excludes link-local traffic */
         "-j", "MARK", "--set-mark", DNS_MARK,
	 NULL
        };
      if (0 != fork_and_exec (sbin_ip6tables, mark_args))
        goto cleanup_mark_2b;
    }
    /* Forward all marked DNS traffic to our DNS_TABLE */
    {
      char *const forward_args[] =
        {
	 "ip", "rule", "add", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL
        };
      if (0 != fork_and_exec (sbin_ip, forward_args))
        goto cleanup_mark_2;
    }
    {
      char *const forward_args[] =
        {
          "ip", "-6", "rule", "add", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL
        };
      if (0 != fork_and_exec (sbin_ip, forward_args))
        goto cleanup_forward_3b;
    }
    /* Finally, add rule in our forwarding table to pass to our virtual interface */
    {
      char *const route_args[] =
        {
	 "ip", "route", "add", "default", "dev", dev,
	 "table", DNS_TABLE, NULL
        };
      if (0 != fork_and_exec (sbin_ip, route_args))
        goto cleanup_forward_3;
    }
    {
      char *const route_args[] =
        {
          "ip", "-6", "route", "add", "default", "dev", dev,
          "table", DNS_TABLE, NULL
        };
      if (0 != fork_and_exec (sbin_ip, route_args))
        goto cleanup_route_4b;
    }
  }

  /* drop privs *except* for the saved UID; this is not perfect, but better
     than doing nothing */
#ifdef HAVE_SETRESUID
  if (0 != setresuid (uid, uid, 0))
  {
    fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
    r = 24;
    goto cleanup_route_4;
  }
#else
  /* Note: no 'setuid' here as we must keep our saved UID as root */
  if (0 != seteuid (uid))
  {
    fprintf (stderr, "Failed to seteuid: %s\n", strerror (errno));
    r = 24;
    goto cleanup_route_4;
  }
#endif

  r = 0; /* did fully setup routing table (if nothing else happens, we were successful!) */

  /* now forward until we hit a problem */
  run (fd_tun);

  /* now need to regain privs so we can remove the firewall rules we added! */
#ifdef HAVE_SETRESUID
  if (0 != setresuid (uid, 0, 0))
  {
    fprintf (stderr, "Failed to setresuid back to root: %s\n", strerror (errno));
    r = 40;
    goto cleanup_route_4;
  }
#else
  if (0 != seteuid (0))
  {
    fprintf (stderr, "Failed to seteuid back to root: %s\n", strerror (errno));
    r = 40;
    goto cleanup_route_4;
  }
#endif

  /* update routing tables again -- this is why we could not fully drop privs */
  /* now undo updating of routing tables; normal exit or clean-up-on-error case */
 cleanup_route_4:
  if (0 == nortsetup)
  {
    char *const route_clean_args[] =
      {
	"ip", "-6", "route", "del", "default", "dev", dev,
	"table", DNS_TABLE, NULL
      };
    if (0 != fork_and_exec (sbin_ip, route_clean_args))
      r += 1;
  }
 cleanup_route_4b:
  if (0 == nortsetup)
  {
    char *const route_clean_args[] =
      {
	"ip", "route", "del", "default", "dev", dev,
	"table", DNS_TABLE, NULL
      };
    if (0 != fork_and_exec (sbin_ip, route_clean_args))
      r += 1;
  }
 cleanup_forward_3:
  if (0 == nortsetup)
  {
    char *const forward_clean_args[] =
      {
	"ip", "-6", "rule", "del", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL
      };
    if (0 != fork_and_exec (sbin_ip, forward_clean_args))
      r += 2;
  }
 cleanup_forward_3b:
  if (0 == nortsetup)
  {
    char *const forward_clean_args[] =
      {
	"ip", "rule", "del", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL
      };
    if (0 != fork_and_exec (sbin_ip, forward_clean_args))
      r += 2;
  }
 cleanup_mark_2:
  if (0 == nortsetup)
  {
    char *const mark_clean_args[] =
      {
	"ip6tables", "-t", "mangle", "-D", "OUTPUT", "-p", "udp",
	"--dport", DNS_PORT,
        "!", "-s", "fe80::/10", /* this line excludes link-local traffic */
        "-j", "MARK", "--set-mark", DNS_MARK, NULL
      };
    if (0 != fork_and_exec (sbin_ip6tables, mark_clean_args))
      r += 4;
  }
 cleanup_mark_2b:
  if (0 == nortsetup)
  {
    char *const mark_clean_args[] =
      {
	"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))
      r += 4;
  }
 cleanup_mangle_1:
  if (0 == nortsetup)
  {
    char *const mangle_clean_args[] =
      {
	"ip6tables", "-m", "owner", "-t", "mangle", "-D", "OUTPUT", "-p", "udp",
	 "--gid-owner", mygid, "--dport", DNS_PORT, "-j", "ACCEPT",
	NULL
      };
    if (0 != fork_and_exec (sbin_ip6tables, mangle_clean_args))
      r += 8;
  }
 cleanup_mangle_1b:
  if (0 == nortsetup)
  {
    char *const mangle_clean_args[] =
      {
	"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))
      r += 8;
  }

 cleanup_rest:
  /* close virtual interface */
  (void) close (fd_tun);
  /* remove signal handler so we can close the pipes */
  (void) signal (SIGTERM, SIG_IGN);
#if (SIGTERM != GNUNET_TERM_SIG)
    (void) signal (GNUNET_TERM_SIG, SIG_IGN);
#endif
  (void) signal (SIGINT, SIG_IGN);
  (void) signal (SIGHUP, SIG_IGN);
  (void) close (cpipe[0]);
  (void) close (cpipe[1]);
  return r;
}
Ejemplo n.º 4
0
int main(int argc, char **argv) {
	pingtun_t handle;

	handle.ret = -1;
	memset(&handle, 0, sizeof(handle));

	DBG("parsing options");
	parse_opts(&handle, argc, argv);

	if (handle.flags.is_server) {
		if (0 != set_ignore_echo(&handle)) {
			goto exit;
		}
	}
	
	DBG("initializing event base");
	if (0 != init_base_ev(&handle)) {
		goto exit;
	}

	DBG("initializing ping socket");
	if (handle.flags.is_server) {
		if (0 != init_sping(&handle)) {
			goto exit;
		}
	}
	
	if (handle.flags.is_client) {
		if (0 != init_cping(&handle)) {
			goto exit;
		}
	}

	if (handle.flags.is_server && !handle.flags.ignore_pings) {
		if (0 != init_reply(&handle)) {
			goto exit;
		}
	}


	DBG("initializing tun device");
	if (0 != init_tun(&handle)) {
		goto exit;
	}

	if (0 != init_signals(&handle)) {
		goto exit;
	}

	switch (event_base_dispatch(handle.base_ev)) {
		case 0:
			break;
		case -1:
			ERR("dispatch event loop failed");
			goto exit;
		case 1:
			ERR("no more active/pending events");
			goto exit;
	}

exit:
	if (handle.flags.is_server) {
		reset_ignore_echo(&handle);
	}
	//TODO: de-allocate all the shit. Do I really care?
	return handle.ret;
}