* 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
* 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)
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;
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))
}
/* 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))
{
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))
};
-
/**
* State we keep for each DNS tunnel that terminates at this node.
*/
*/
static GNUNET_SCHEDULER_TaskIdentifier read6_task;
-/**
- * The port bound to the socket dnsout (and/or dnsout6). We always (try) to bind
- * both sockets to the same port.
- */
-static uint16_t dnsoutport;
-
/**
* The configuration to use
*/
/**
* Command-line arguments we are giving to the hijacker process.
*/
-static char *helper_argv[8];
+static char *helper_argv[7];
/**
* Head of DLL of clients we consult.
*/
static struct GNUNET_MESH_Handle *mesh;
+/**
+ * Number of active DNS requests.
+ */
+static unsigned int dns_active;
+
/**
* We're done processing a DNS request, free associated memory.
GNUNET_HELPER_stop (hijacker);
hijacker = NULL;
- for (i=0;i<8;i++)
+ for (i=0;i<7;i++)
GNUNET_free_non_null (helper_argv[i]);
if (NULL != dnsout4)
{
}
+/**
+ * Try to change the source ports we are bound to.
+ */
+static void
+change_source_ports ();
+
+
/**
* A client has completed its processing for this
* request. Move on.
return;
case RP_QUERY:
rr->phase = RP_INTERNET_DNS;
+ dns_active++;
switch (rr->dst_addr.ss_family)
{
case AF_INET:
salen);
return;
case RP_INTERNET_DNS:
+ dns_active--;
+ if (0 == dns_active)
+ change_source_ports ();
rr->phase = RP_MODIFY;
for (cr = clients_head; NULL != cr; cr = cr->next)
{
open_port4 ()
{
struct sockaddr_in addr;
- socklen_t addrlen;
dnsout4 = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
if (dnsout4 == NULL)
dnsout4 = NULL;
return GNUNET_SYSERR;
}
-
- /* Read the port we bound to */
- addrlen = sizeof (struct sockaddr_in);
- if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout4),
- (struct sockaddr *) &addr,
- &addrlen))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Could not determine port I got: %s\n"),
- STRERROR (errno));
- GNUNET_NETWORK_socket_close (dnsout4);
- dnsout4 = NULL;
- return GNUNET_SYSERR;
- }
- dnsoutport = htons (addr.sin_port);
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("GNUnet DNS will exit on source port %u\n"),
- (unsigned int) dnsoutport);
read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
dnsout4,
&read_response, dnsout4);
open_port6 ()
{
struct sockaddr_in6 addr;
- socklen_t addrlen;
dnsout6 = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_DGRAM, 0);
if (dnsout6 == NULL)
}
memset (&addr, 0, sizeof (struct sockaddr_in6));
addr.sin6_family = AF_INET6;
- addr.sin6_port = htons (dnsoutport);
int err = GNUNET_NETWORK_socket_bind (dnsout6,
(struct sockaddr *) &addr,
sizeof (struct sockaddr_in6));
if (err != GNUNET_OK)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Could not bind to port %u: %s\n"),
- (unsigned int) dnsoutport,
+ _("Could not bind: %s\n"),
STRERROR (errno));
GNUNET_NETWORK_socket_close (dnsout6);
dnsout6 = NULL;
return GNUNET_SYSERR;
}
- if (0 == dnsoutport)
- {
- addrlen = sizeof (struct sockaddr_in6);
- if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout6),
- (struct sockaddr *) &addr,
- &addrlen))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Could not determine port I got: %s\n"),
- STRERROR (errno));
- GNUNET_NETWORK_socket_close (dnsout6);
- dnsout6 = NULL;
- return GNUNET_SYSERR;
- }
- }
- dnsoutport = htons (addr.sin6_port);
read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
dnsout6,
&read_response, dnsout6);
}
+/**
+ * Try to change the source ports we are bound to.
+ */
+static void
+change_source_ports ()
+{
+ struct GNUNET_NETWORK_Handle *old4;
+ struct GNUNET_NETWORK_Handle *old6;
+
+ if (GNUNET_SCHEDULER_NO_TASK != read4_task)
+ {
+ GNUNET_SCHEDULER_cancel (read4_task);
+ read4_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != read6_task)
+ {
+ GNUNET_SCHEDULER_cancel (read6_task);
+ read6_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ old4 = dnsout4;
+ if (GNUNET_OK != open_port4 ())
+ {
+ dnsout4 = old4;
+ read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+ dnsout4,
+ &read_response, dnsout4);
+ }
+ else
+ {
+ if (NULL != old4)
+ GNUNET_NETWORK_socket_close (old4);
+ }
+ old6 = dnsout6;
+ if (GNUNET_OK != open_port6 ())
+ {
+ dnsout6 = old6;
+ read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+ dnsout6,
+ &read_response, dnsout6);
+ }
+ else
+ {
+ if (NULL != old6)
+ GNUNET_NETWORK_socket_close (old6);
+ }
+}
+
+
/**
* We got a new client. Make sure all new DNS requests pass by its desk.
*
/* clean up from previous request */
GNUNET_free_non_null (rr->payload);
+ if (RP_INTERNET_DNS == rr->phase)
+ {
+ dns_active--;
+ if (0 == dns_active)
+ change_source_ports ();
+ }
rr->payload = NULL;
GNUNET_array_grow (rr->client_wait_list,
rr->client_wait_list_length,
{&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0},
{NULL, NULL, 0, 0}
};
- char port_s[6];
char *ifc_name;
char *ipv4addr;
char *ipv4mask;
return;
}
helper_argv[5] = ipv4mask;
- GNUNET_snprintf (port_s,
- sizeof (port_s),
- "%u",
- (unsigned int) dnsoutport);
- helper_argv[6] = GNUNET_strdup (port_s);
- helper_argv[7] = NULL;
+ helper_argv[6] = NULL;
if (NULL != dns_exit)
{