summaryrefslogtreecommitdiff
path: root/src/openvpn/dhcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvpn/dhcp.c')
-rw-r--r--src/openvpn/dhcp.c321
1 files changed, 169 insertions, 152 deletions
diff --git a/src/openvpn/dhcp.c b/src/openvpn/dhcp.c
index 8d0b18a..c17a22e 100644
--- a/src/openvpn/dhcp.c
+++ b/src/openvpn/dhcp.c
@@ -5,7 +5,7 @@
* packet encryption, packet authentication, and
* packet compression.
*
- * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -37,176 +37,193 @@
#include "memdbg.h"
static int
-get_dhcp_message_type (const struct dhcp *dhcp, const int optlen)
+get_dhcp_message_type(const struct dhcp *dhcp, const int optlen)
{
- const uint8_t *p = (uint8_t *) (dhcp + 1);
- int i;
+ const uint8_t *p = (uint8_t *) (dhcp + 1);
+ int i;
- for (i = 0; i < optlen; ++i)
+ for (i = 0; i < optlen; ++i)
{
- const uint8_t type = p[i];
- const int room = optlen - i;
- if (type == DHCP_END) /* didn't find what we were looking for */
- return -1;
- else if (type == DHCP_PAD) /* no-operation */
- ;
- else if (type == DHCP_MSG_TYPE) /* what we are looking for */
- {
- if (room >= 3)
- {
- if (p[i+1] == 1) /* option length should be 1 */
- return p[i+2]; /* return message type */
- }
- return -1;
- }
- else /* some other option */
- {
- if (room >= 2)
- {
- const int len = p[i+1]; /* get option length */
- i += (len + 1); /* advance to next option */
- }
- }
+ const uint8_t type = p[i];
+ const int room = optlen - i;
+ if (type == DHCP_END) /* didn't find what we were looking for */
+ {
+ return -1;
+ }
+ else if (type == DHCP_PAD) /* no-operation */
+ {
+ }
+ else if (type == DHCP_MSG_TYPE) /* what we are looking for */
+ {
+ if (room >= 3)
+ {
+ if (p[i+1] == 1) /* option length should be 1 */
+ {
+ return p[i+2]; /* return message type */
+ }
+ }
+ return -1;
+ }
+ else /* some other option */
+ {
+ if (room >= 2)
+ {
+ const int len = p[i+1]; /* get option length */
+ i += (len + 1); /* advance to next option */
+ }
+ }
}
- return -1;
+ return -1;
}
static in_addr_t
-do_extract (struct dhcp *dhcp, int optlen)
+do_extract(struct dhcp *dhcp, int optlen)
{
- uint8_t *p = (uint8_t *) (dhcp + 1);
- int i;
- in_addr_t ret = 0;
+ uint8_t *p = (uint8_t *) (dhcp + 1);
+ int i;
+ in_addr_t ret = 0;
- for (i = 0; i < optlen; )
+ 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)
- {
- 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);
- ret = ntohl (ret);
- }
- {
- /* 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 */
- }
- }
- else
- break;
- }
- else
- break;
- }
- else /* some other option */
- {
- if (room >= 2)
- {
- const int len = p[i+1]; /* get option length */
- i += (len + 2); /* advance to next option */
- }
- else
- break;
- }
+ 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)
+ {
+ 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);
+ ret = ntohl(ret);
+ }
+ {
+ /* 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 */
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ else /* some other option */
+ {
+ if (room >= 2)
+ {
+ const int len = p[i+1]; /* get option length */
+ i += (len + 2); /* advance to next option */
+ }
+ else
+ {
+ break;
+ }
+ }
}
- return ret;
+ return ret;
}
static uint16_t
-udp_checksum (const uint8_t *buf,
- const int len_udp,
- const uint8_t *src_addr,
- const uint8_t *dest_addr)
+udp_checksum(const uint8_t *buf,
+ const int len_udp,
+ const uint8_t *src_addr,
+ const uint8_t *dest_addr)
{
- uint16_t word16;
- uint32_t sum = 0;
- int i;
-
- /* make 16 bit words out of every two adjacent 8 bit words and */
- /* calculate the sum of all 16 bit words */
- for (i = 0; i < len_udp; i += 2){
- word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_udp) ? (buf[i+1] & 0xFF) : 0);
- sum += word16;
- }
-
- /* add the UDP pseudo header which contains the IP source and destination addresses */
- for (i = 0; i < 4; i += 2){
- word16 =((src_addr[i] << 8) & 0xFF00) + (src_addr[i+1] & 0xFF);
- sum += word16;
- }
- for (i = 0; i < 4; i += 2){
- word16 =((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i+1] & 0xFF);
- sum += word16;
- }
-
- /* the protocol number and the length of the UDP packet */
- sum += (uint16_t) OPENVPN_IPPROTO_UDP + (uint16_t) len_udp;
-
- /* keep only the last 16 bits of the 32 bit calculated sum and add the carries */
- while (sum >> 16)
- sum = (sum & 0xFFFF) + (sum >> 16);
-
- /* Take the one's complement of sum */
- return ((uint16_t) ~sum);
+ uint16_t word16;
+ uint32_t sum = 0;
+ int i;
+
+ /* make 16 bit words out of every two adjacent 8 bit words and */
+ /* calculate the sum of all 16 bit words */
+ for (i = 0; i < len_udp; i += 2) {
+ word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_udp) ? (buf[i+1] & 0xFF) : 0);
+ sum += word16;
+ }
+
+ /* add the UDP pseudo header which contains the IP source and destination addresses */
+ for (i = 0; i < 4; i += 2) {
+ word16 = ((src_addr[i] << 8) & 0xFF00) + (src_addr[i+1] & 0xFF);
+ sum += word16;
+ }
+ for (i = 0; i < 4; i += 2) {
+ word16 = ((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i+1] & 0xFF);
+ sum += word16;
+ }
+
+ /* the protocol number and the length of the UDP packet */
+ sum += (uint16_t) OPENVPN_IPPROTO_UDP + (uint16_t) len_udp;
+
+ /* keep only the last 16 bits of the 32 bit calculated sum and add the carries */
+ while (sum >> 16)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+
+ /* Take the one's complement of sum */
+ return ((uint16_t) ~sum);
}
in_addr_t
-dhcp_extract_router_msg (struct buffer *ipbuf)
+dhcp_extract_router_msg(struct buffer *ipbuf)
{
- struct dhcp_full *df = (struct dhcp_full *) BPTR (ipbuf);
- const int optlen = BLEN (ipbuf) - (sizeof (struct openvpn_iphdr) + sizeof (struct openvpn_udphdr) + sizeof (struct dhcp));
-
- if (optlen >= 0
- && df->ip.protocol == OPENVPN_IPPROTO_UDP
- && df->udp.source == htons (BOOTPS_PORT)
- && df->udp.dest == htons (BOOTPC_PORT)
- && df->dhcp.op == BOOTREPLY)
+ struct dhcp_full *df = (struct dhcp_full *) BPTR(ipbuf);
+ const int optlen = BLEN(ipbuf) - (sizeof(struct openvpn_iphdr) + sizeof(struct openvpn_udphdr) + sizeof(struct dhcp));
+
+ if (optlen >= 0
+ && df->ip.protocol == OPENVPN_IPPROTO_UDP
+ && df->udp.source == htons(BOOTPS_PORT)
+ && df->udp.dest == htons(BOOTPC_PORT)
+ && df->dhcp.op == BOOTREPLY)
{
- const int message_type = get_dhcp_message_type (&df->dhcp, optlen);
- if (message_type == DHCPACK || message_type == DHCPOFFER)
- {
- /* 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;
- }
- }
+ const int message_type = get_dhcp_message_type(&df->dhcp, optlen);
+ if (message_type == DHCPACK || message_type == DHCPOFFER)
+ {
+ /* 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 0;
+ return 0;
}