gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r19307 - in gnunet/src: exit vpn


From: gnunet
Subject: [GNUnet-SVN] r19307 - in gnunet/src: exit vpn
Date: Sat, 21 Jan 2012 23:30:54 +0100

Author: grothoff
Date: 2012-01-21 23:30:54 +0100 (Sat, 21 Jan 2012)
New Revision: 19307

Modified:
   gnunet/src/exit/gnunet-daemon-exit.c
   gnunet/src/vpn/gnunet-service-vpn.c
Log:
-implementing ICMP PT and generation if ICMP payloads on EXIT->TUN link (for 
both service and Internet exit)

Modified: gnunet/src/exit/gnunet-daemon-exit.c
===================================================================
--- gnunet/src/exit/gnunet-daemon-exit.c        2012-01-21 20:52:19 UTC (rev 
19306)
+++ gnunet/src/exit/gnunet-daemon-exit.c        2012-01-21 22:30:54 UTC (rev 
19307)
@@ -390,6 +390,12 @@
   GNUNET_HashCode key;
   struct TunnelState *state;
 
+  if (protocol == IPPROTO_ICMP)
+  {
+    /* ignore ports */
+    destination_port = 0;
+    local_port = 0;
+  }
   ri.remote_address.af = af;
   if (af == AF_INET)
     ri.remote_address.address.ipv4 = *((struct in_addr*) destination_ip);
@@ -1858,6 +1864,58 @@
 
 
 /**
+ * Synthesize a plausible ICMP payload for an ICMPv4 error
+ * response on the given tunnel.
+ *
+ * @param state tunnel information
+ * @param ipp IPv6 header to fill in (ICMP payload)
+ * @param udp "UDP" header to fill in (ICMP payload); might actually
+ *            also be the first 8 bytes of the TCP header
+ */
+static void
+make_up_icmpv4_payload (struct TunnelState *state,
+                       struct GNUNET_TUN_IPv4Header *ipp,
+                       struct GNUNET_TUN_UdpHeader *udp)
+{
+  GNUNET_TUN_initialize_ipv4_header (ipp,
+                                    state->ri.remote_address.proto,
+                                    sizeof (struct GNUNET_TUN_TcpHeader),
+                                    &state->ri.remote_address.address.ipv4,
+                                    &state->ri.local_address.address.ipv4);
+  udp->spt = htons (state->ri.remote_address.port);
+  udp->dpt = htons (state->ri.local_address.port);
+  udp->len = htons (0);
+  udp->crc = htons (0);
+}
+
+
+/**
+ * Synthesize a plausible ICMP payload for an ICMPv6 error
+ * response on the given tunnel.
+ *
+ * @param state tunnel information
+ * @param ipp IPv6 header to fill in (ICMP payload)
+ * @param udp "UDP" header to fill in (ICMP payload); might actually
+ *            also be the first 8 bytes of the TCP header
+ */
+static void
+make_up_icmpv6_payload (struct TunnelState *state,
+                       struct GNUNET_TUN_IPv6Header *ipp,
+                       struct GNUNET_TUN_UdpHeader *udp)
+{
+  GNUNET_TUN_initialize_ipv6_header (ipp,
+                                    state->ri.remote_address.proto,
+                                    sizeof (struct GNUNET_TUN_TcpHeader),
+                                    &state->ri.remote_address.address.ipv6,
+                                    &state->ri.local_address.address.ipv6);
+  udp->spt = htons (state->ri.remote_address.port);
+  udp->dpt = htons (state->ri.local_address.port);
+  udp->len = htons (0);
+  udp->crc = htons (0);
+}
+
+
+/**
  * Process a request to forward ICMP data to the Internet via this peer.
  *
  * @param cls closure, NULL
@@ -1882,6 +1940,7 @@
   const struct in_addr *v4;
   const struct in6_addr *v6;  
   const void *payload;
+  char buf[sizeof (struct GNUNET_TUN_IPv6Header) + 8];
   int af;
 
   GNUNET_STATISTICS_update (stats,
@@ -1899,7 +1958,14 @@
   pkt_len -= sizeof (struct GNUNET_EXIT_IcmpInternetMessage);  
 
   af = (int) ntohl (msg->af);
-  state->ri.remote_address.af = af;
+  if ( (NULL != state->heap_node) &&
+       (af != state->ri.remote_address.af) )
+  {
+    /* other peer switched AF on this tunnel; not allowed */
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+
   switch (af)
   {
   case AF_INET:
@@ -1917,6 +1983,48 @@
     payload = &v4[1];
     pkt_len -= sizeof (struct in_addr);
     state->ri.remote_address.address.ipv4 = *v4;
+    if (NULL == state->heap_node)
+    {
+      state->ri.remote_address.af = af;
+      state->ri.remote_address.proto = IPPROTO_ICMP;
+      setup_state_record (state);
+    }
+    /* check that ICMP type is something we want to support 
+       and possibly make up payload! */
+    switch (msg->icmp_header.type)
+    {
+    case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
+    case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
+      break;
+    case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
+    case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
+    case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
+      if (0 != pkt_len)
+      {
+       GNUNET_break_op (0);
+       return GNUNET_SYSERR;
+      }
+      /* make up payload */
+      {
+       struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) 
buf;
+       struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) 
&ipp[1];
+
+       GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
+       pkt_len = sizeof (struct GNUNET_TUN_IPv4Header) + 8;
+       make_up_icmpv4_payload (state, 
+                               ipp,
+                               udp);
+       payload = ipp;
+      }
+      break;
+    default:
+      GNUNET_break_op (0);
+      GNUNET_STATISTICS_update (stats,
+                               gettext_noop ("# ICMPv4 packets dropped (type 
not allowed)"),
+                               1, GNUNET_NO);
+      return GNUNET_SYSERR;      
+    }
+    /* end AF_INET */
     break;
   case AF_INET6:
     if (pkt_len < sizeof (struct in6_addr))
@@ -1933,8 +2041,52 @@
     payload = &v6[1];
     pkt_len -= sizeof (struct in6_addr);
     state->ri.remote_address.address.ipv6 = *v6;
-    break;
+    if (NULL == state->heap_node)
+    {
+      state->ri.remote_address.af = af;
+      state->ri.remote_address.proto = IPPROTO_ICMP;
+      setup_state_record (state);
+    }
+    /* check that ICMP type is something we want to support 
+       and possibly make up payload! */
+    switch (msg->icmp_header.type)
+    {
+    case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
+    case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
+      break;
+    case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
+    case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
+    case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
+    case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
+      if (0 != pkt_len)
+      {
+       GNUNET_break_op (0);
+       return GNUNET_SYSERR;
+      }
+      /* make up payload */
+      {
+       struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) 
buf;
+       struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) 
&ipp[1];
+
+       GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
+       pkt_len = sizeof (struct GNUNET_TUN_IPv6Header) + 8;
+       make_up_icmpv6_payload (state, 
+                               ipp,
+                               udp);
+       payload = ipp;
+      }
+      break;
+    default:
+      GNUNET_break_op (0);
+      GNUNET_STATISTICS_update (stats,
+                               gettext_noop ("# ICMPv6 packets dropped (type 
not allowed)"),
+                               1, GNUNET_NO);
+      return GNUNET_SYSERR;      
+    }
+    /* end AF_INET6 */
+    break;    
   default:
+    /* bad AF */
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
@@ -1948,15 +2100,6 @@
                           &state->ri.remote_address.address,
                           buf, sizeof (buf)));
   }
-
-  /* FIXME: check that ICMP type is something we want to support */
-
-  state->ri.remote_address.proto = IPPROTO_ICMP;
-  state->ri.remote_address.port = 0;
-  state->ri.local_address.port = 0;
-  if (NULL == state->heap_node)
-    setup_state_record (state);
-
   send_icmp_packet_via_tun (&state->ri.remote_address,
                            &state->ri.local_address,
                            &msg->icmp_header,
@@ -1966,6 +2109,56 @@
 
 
 /**
+ * Setup ICMP payload for ICMP error messages. Called
+ * for both IPv4 and IPv6 addresses.
+ *
+ * @param state context for creating the IP Packet
+ * @param buf where to create the payload, has at least
+ *       sizeof (struct GNUNET_TUN_IPv6Header) + 8 bytes
+ * @return number of bytes of payload we created in buf
+ */
+static uint16_t
+make_up_icmp_service_payload (struct TunnelState *state,
+                             char *buf)
+{
+  switch (state->serv->address.af)
+  {
+  case AF_INET:
+    {
+      struct GNUNET_TUN_IPv4Header *ipv4;
+      struct GNUNET_TUN_UdpHeader *udp;
+      
+      ipv4 = (struct GNUNET_TUN_IPv4Header *)buf;
+      udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
+      make_up_icmpv4_payload (state,
+                             ipv4,
+                             udp);
+      GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
+      return sizeof (struct GNUNET_TUN_IPv4Header) + 8;
+    }
+    break;
+  case AF_INET6:
+    {
+      struct GNUNET_TUN_IPv6Header *ipv6;
+      struct GNUNET_TUN_UdpHeader *udp;
+
+      ipv6 = (struct GNUNET_TUN_IPv6Header *)buf;
+      udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
+      make_up_icmpv6_payload (state,
+                             ipv6,
+                             udp);
+      GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
+      return sizeof (struct GNUNET_TUN_IPv6Header) + 8;      
+    }
+    break;
+  default:
+    GNUNET_break (0);
+  }
+  return 0;
+}
+
+
+/**
  * Process a request via mesh to send ICMP data to a service
  * offered by this system.
  *
@@ -1988,6 +2181,9 @@
   struct TunnelState *state = *tunnel_ctx;
   const struct GNUNET_EXIT_IcmpServiceMessage *msg;
   uint16_t pkt_len = ntohs (message->size);
+  struct GNUNET_TUN_IcmpHeader icmp;
+  char buf[sizeof (struct GNUNET_TUN_IPv6Header) + 8];
+  const void *payload;
 
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# Bytes received from MESH"),
@@ -2013,23 +2209,141 @@
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
-  if (state->serv->address.af != ntohl (msg->af))
+  icmp = msg->icmp_header;
+  payload = &msg[1];
+  state->ri.remote_address = state->serv->address;    
+  setup_state_record (state);
+
+  /* check that ICMP type is something we want to support,
+     perform ICMP PT if needed ans possibly make up payload */
+  switch (msg->af)
   {
-    GNUNET_STATISTICS_update (stats,
-                             gettext_noop ("# ICMP service requests discarded 
(incompatible af)"),
-                             1, GNUNET_NO);
+  case AF_INET:
+    switch (msg->icmp_header.type)
+    {
+    case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
+      if (state->serv->address.af == AF_INET6)
+       icmp.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
+      break;
+    case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
+      if (state->serv->address.af == AF_INET6)
+       icmp.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
+      break;
+    case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
+      if (state->serv->address.af == AF_INET6)
+       icmp.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
+      if (0 != pkt_len)
+      {
+       GNUNET_break_op (0);
+       return GNUNET_SYSERR;
+      }
+      payload = buf;
+      pkt_len = make_up_icmp_service_payload (state, buf);
+      break;
+    case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
+      if (state->serv->address.af == AF_INET6)
+       icmp.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
+      if (0 != pkt_len)
+      {
+       GNUNET_break_op (0);
+       return GNUNET_SYSERR;
+      }
+      payload = buf;
+      pkt_len = make_up_icmp_service_payload (state, buf);
+      break;
+    case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
+      if (state->serv->address.af == AF_INET6)
+      {
+       GNUNET_STATISTICS_update (stats,
+                                 gettext_noop ("# ICMPv4 packets dropped 
(impossible PT to v6)"),
+                                 1, GNUNET_NO);
+       return GNUNET_OK;
+      }
+      if (0 != pkt_len)
+      {
+       GNUNET_break_op (0);
+       return GNUNET_SYSERR;
+      }
+      payload = buf;
+      pkt_len = make_up_icmp_service_payload (state, buf);
+      break;
+    default:
+      GNUNET_break_op (0);
+      GNUNET_STATISTICS_update (stats,
+                               gettext_noop ("# ICMPv4 packets dropped (type 
not allowed)"),
+                               1, GNUNET_NO);
+      return GNUNET_SYSERR;
+    }
+    /* end of AF_INET */
+    break;
+  case AF_INET6:
+    switch (msg->icmp_header.type)
+    {
+    case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
+      if (state->serv->address.af == AF_INET)
+       icmp.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
+      break;
+    case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
+      if (state->serv->address.af == AF_INET)
+       icmp.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
+      break;
+    case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
+      if (state->serv->address.af == AF_INET)
+       icmp.type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
+      if (0 != pkt_len)
+      {
+       GNUNET_break_op (0);
+       return GNUNET_SYSERR;
+      }
+      payload = buf;
+      pkt_len = make_up_icmp_service_payload (state, buf);
+      break;
+    case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
+      if (state->serv->address.af == AF_INET)
+       icmp.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
+      if (0 != pkt_len)
+      {
+       GNUNET_break_op (0);
+       return GNUNET_SYSERR;
+      }
+      payload = buf;
+      pkt_len = make_up_icmp_service_payload (state, buf);
+      break;
+    case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
+    case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
+      if (state->serv->address.af == AF_INET)
+      {
+       GNUNET_STATISTICS_update (stats,
+                                 gettext_noop ("# ICMPv6 packets dropped 
(impossible PT to v4)"),
+                                 1, GNUNET_NO);
+       return GNUNET_OK;
+      }
+      if (0 != pkt_len)
+      {
+       GNUNET_break_op (0);
+       return GNUNET_SYSERR;
+      }
+      payload = buf;
+      pkt_len = make_up_icmp_service_payload (state, buf);
+      break;
+    default:
+      GNUNET_break_op (0);
+      GNUNET_STATISTICS_update (stats,
+                               gettext_noop ("# ICMPv6 packets dropped (type 
not allowed)"),
+                               1, GNUNET_NO);
+      return GNUNET_SYSERR;
+    }
+    /* end of AF_INET6 */
+    break;
+  default:
+    GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
 
-  /* FIXME: check that ICMP type is something we want to support */
-
-  state->ri.remote_address = state->serv->address;    
-  setup_state_record (state);
-
   send_icmp_packet_via_tun (&state->ri.remote_address,
                            &state->ri.local_address,
-                           &msg->icmp_header,
-                           &msg[1], pkt_len);
+                           &icmp,
+                           payload, pkt_len);
   return GNUNET_YES;
 }
 

Modified: gnunet/src/vpn/gnunet-service-vpn.c
===================================================================
--- gnunet/src/vpn/gnunet-service-vpn.c 2012-01-21 20:52:19 UTC (rev 19306)
+++ gnunet/src/vpn/gnunet-service-vpn.c 2012-01-21 22:30:54 UTC (rev 19307)
@@ -25,13 +25,6 @@
  *        IP traffic received on those IPs via the GNUnet mesh 
  * @author Philipp Toelke
  * @author Christian Grothoff
- *
- * TODO:
- * Basics:
- * - test!
- *
- * Features:
- * - add back ICMP support (especially needed for IPv6)
  */
 #include "platform.h"
 #include "gnunet_util_lib.h"




reply via email to

[Prev in Thread] Current Thread [Next in Thread]