]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Fixed client issues with DHCP Router option extraction/deletion when
authorJames Yonan <james@openvpn.net>
Thu, 3 Nov 2011 02:03:35 +0000 (02:03 +0000)
committerDavid Sommerseth <davids@redhat.com>
Wed, 14 Dec 2011 16:04:05 +0000 (17:04 +0100)
using layer 2 with DHCP proxy:

* Extract/delete Router option from both DHCPOFFER and DHCPACK
  messages.  Prevously we only considered DHCPACK messages.
  With DHCPACK messages, we extract the Router IP for
  use as the vpn_gateway, as well as delete the Router option from
  the DHCP message.  For DHCPOFFER, we only delete the Router
  message.

* Monitor all DHCPOFFER and DHCPACK messages for possible Router
  options needing to be extracted/deleted.  Previously, we turned
  off monitoring after the first successful extraction/deletion
  from a DHCPACK message.

* Previously, we deleted Router options by padding them with DHCP
  PAD options.  This has proven not to work with some DHCP clients,
  so we now delete the message entirely, and add PADs to the end of
  the message so as not to change its length.

* In some cases, UDP checksum was not being correctly updated for
  modified DHCP packets.

To properly use this feature on Linux, after tunnel comes up,
run these commands:

  ifconfig tap0 up
  dhclient tap0

Version 2.1.17

git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7682 e7ae566f-a301-0410-adde-c780ea21d3b5

dhcp.c
forward.c

diff --git a/dhcp.c b/dhcp.c
index 3474a17fd6b2065947f4526b729104299d3676ea..280a4af302434540cb1c0206646a65d8ba6c70ce 100644 (file)
--- a/dhcp.c
+++ b/dhcp.c
@@ -66,20 +66,20 @@ get_dhcp_message_type (const struct dhcp *dhcp, const int optlen)
 }
 
 static in_addr_t
-do_extract (struct dhcp *dhcp, const int optlen)
+do_extract (struct dhcp *dhcp, int optlen)
 {
   uint8_t *p = (uint8_t *) (dhcp + 1);
   int i;
   in_addr_t ret = 0;
 
-  for (i = 0; i < optlen; ++i)
+  for (i = 0; i < optlen; )
     {
       const uint8_t type = p[i];
       const int room = optlen - i;
       if (type == DHCP_END)
        break;
       else if (type == DHCP_PAD)
-       ;
+       ++i;
       else if (type == DHCP_ROUTER)
        {
          if (room >= 2)
@@ -87,23 +87,39 @@ do_extract (struct dhcp *dhcp, const int optlen)
              const int len = p[i+1]; /* get option length */
              if (len <= (room-2))
                {
+                 /* get router IP address */
                  if (!ret && len >= 4 && (len & 3) == 0)
                    {
-                     memcpy (&ret, p+i+2, 4);      /* get router IP address */
+                     memcpy (&ret, p+i+2, 4);
                      ret = ntohl (ret);
                    }
-                 memset (p+i, DHCP_PAD, len+2);    /* delete the router option by padding it out */
+                 {
+                   /* delete the router option */
+                   uint8_t *dest = p + i;
+                   const int owlen = len + 2;            /* len of data to overwrite */
+                   uint8_t *src = dest + owlen;
+                   uint8_t *end = p + optlen;
+                   const int movlen = end - src;
+                   if (movlen > 0)
+                     memmove(dest, src, movlen);         /* overwrite router option */
+                   memset(end - owlen, DHCP_PAD, owlen); /* pad tail */                    
+                 }
                }
-             i += (len + 1);         /* advance to next option */
+             else
+               break;
            }
+         else
+           break;
        }
-      else                            /* some other option */
+      else                              /* some other option */
        {
          if (room >= 2)
            {
-             const int len = p[i+1]; /* get option length */
-             i += (len + 1);         /* advance to next option */
+             const int len = p[i+1];   /* get option length */
+             i += (len + 2);           /* advance to next option */
            }
+         else
+           break;
        }
     }
   return ret;
@@ -157,27 +173,34 @@ dhcp_extract_router_msg (struct buffer *ipbuf)
       && df->ip.protocol == OPENVPN_IPPROTO_UDP
       && df->udp.source == htons (BOOTPS_PORT)
       && df->udp.dest == htons (BOOTPC_PORT)
-      && df->dhcp.op == BOOTREPLY
-      && get_dhcp_message_type (&df->dhcp, optlen) == DHCPACK)
+      && df->dhcp.op == BOOTREPLY)
     {
-      /* get the router IP address while padding out all DHCP router options */
-      const in_addr_t ret = do_extract (&df->dhcp, optlen);
-
-      /* recompute the UDP checksum */
-      df->udp.check = htons (udp_checksum ((uint8_t *) &df->udp, 
-                                          sizeof (struct openvpn_udphdr) + sizeof (struct dhcp) + optlen,
-                                          (uint8_t *)&df->ip.saddr,
-                                          (uint8_t *)&df->ip.daddr));
-
-      if (ret)
+      const int message_type = get_dhcp_message_type (&df->dhcp, optlen);
+      if (message_type == DHCPACK || message_type == DHCPOFFER)
        {
-         struct gc_arena gc = gc_new ();
-         msg (D_ROUTE, "Extracted DHCP router address: %s", print_in_addr_t (ret, 0, &gc));
-         gc_free (&gc);
-       }
+         /* get the router IP address while padding out all DHCP router options */
+         const in_addr_t ret = do_extract (&df->dhcp, optlen);
+
+         /* recompute the UDP checksum */
+         df->udp.check = 0;
+         df->udp.check = htons (udp_checksum ((uint8_t *) &df->udp, 
+                                              sizeof (struct openvpn_udphdr) + sizeof (struct dhcp) + optlen,
+                                              (uint8_t *)&df->ip.saddr,
+                                              (uint8_t *)&df->ip.daddr));
+
+         /* only return the extracted Router address if DHCPACK */
+         if (message_type == DHCPACK)
+           {
+             if (ret)
+               {
+                 struct gc_arena gc = gc_new ();
+                 msg (D_ROUTE, "Extracted DHCP router address: %s", print_in_addr_t (ret, 0, &gc));
+                 gc_free (&gc);
+               }
 
-      return ret;
+             return ret;
+           }
+       }
     }
-  else
-    return 0;
+  return 0;
 }
index c66031f9e1139acedeb41a66c331bd0d04f47c93..dfef4effca20f539e02b39dd943eda1ad03ea5c8 100644 (file)
--- a/forward.c
+++ b/forward.c
@@ -1011,7 +1011,7 @@ process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf)
   if (!c->options.passtos)
     flags &= ~PIPV4_PASSTOS;
 #endif
-  if (!c->options.route_gateway_via_dhcp || !route_list_vpn_gateway_needed (c->c1.route_list))
+  if (!c->options.route_gateway_via_dhcp)
     flags &= ~PIPV4_EXTRACT_DHCP_ROUTER;
 
   if (buf->len > 0)