diff options
author | James Yonan | 2011-11-03 02:03:35 +0000 |
---|---|---|
committer | David Sommerseth | 2011-12-14 17:04:05 +0100 |
commit | 840799182c0769c8ac9d014d09a497563516fc0d (patch) | |
tree | deddc036a7ccebde4aa757bd43b25b707e2892c1 | |
parent | ffea644ce62a67ea06e375c17277cea4e9cb9873 (diff) | |
download | openvpn-840799182c0769c8ac9d014d09a497563516fc0d.zip openvpn-840799182c0769c8ac9d014d09a497563516fc0d.tar.gz |
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.c | 79 | ||||
-rw-r--r-- | forward.c | 2 |
2 files changed, 52 insertions, 29 deletions
@@ -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; } @@ -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) |