summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Yonan <james@openvpn.net>2011-11-03 02:03:35 +0000
committerDavid Sommerseth <davids@redhat.com>2011-12-14 17:04:05 +0100
commit840799182c0769c8ac9d014d09a497563516fc0d (patch)
treededdc036a7ccebde4aa757bd43b25b707e2892c1
parentffea644ce62a67ea06e375c17277cea4e9cb9873 (diff)
downloadopenvpn-840799182c0769c8ac9d014d09a497563516fc0d.tar.gz
openvpn-840799182c0769c8ac9d014d09a497563516fc0d.tar.xz
openvpn-840799182c0769c8ac9d014d09a497563516fc0d.zip
Fixed client issues with DHCP Router option extraction/deletion when
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
-rw-r--r--dhcp.c79
-rw-r--r--forward.c2
2 files changed, 52 insertions, 29 deletions
diff --git a/dhcp.c b/dhcp.c
index 3474a17..280a4af 100644
--- 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;
}
diff --git a/forward.c b/forward.c
index c66031f..dfef4ef 100644
--- 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)