OpenVPN
dhcp.c
Go to the documentation of this file.
1 /*
2  * OpenVPN -- An application to securely tunnel IP networks
3  * over a single TCP/UDP port, with support for SSL/TLS-based
4  * session authentication and key exchange,
5  * packet encryption, packet authentication, and
6  * packet compression.
7  *
8  * Copyright (C) 2002-2023 OpenVPN Inc <sales@openvpn.net>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2
12  * as published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #elif defined(_MSC_VER)
27 #include "config-msvc.h"
28 #endif
29 
30 #include "syshead.h"
31 
32 #include "dhcp.h"
33 #include "socket.h"
34 #include "error.h"
35 
36 #include "memdbg.h"
37 
38 static int
39 get_dhcp_message_type(const struct dhcp *dhcp, const int optlen)
40 {
41  const uint8_t *p = (uint8_t *) (dhcp + 1);
42  int i;
43 
44  for (i = 0; i < optlen; ++i)
45  {
46  const uint8_t type = p[i];
47  const int room = optlen - i;
48  if (type == DHCP_END) /* didn't find what we were looking for */
49  {
50  return -1;
51  }
52  else if (type == DHCP_PAD) /* no-operation */
53  {
54  }
55  else if (type == DHCP_MSG_TYPE) /* what we are looking for */
56  {
57  if (room >= 3)
58  {
59  if (p[i+1] == 1) /* option length should be 1 */
60  {
61  return p[i+2]; /* return message type */
62  }
63  }
64  return -1;
65  }
66  else /* some other option */
67  {
68  if (room >= 2)
69  {
70  const int len = p[i+1]; /* get option length */
71  i += (len + 1); /* advance to next option */
72  }
73  }
74  }
75  return -1;
76 }
77 
78 static in_addr_t
79 do_extract(struct dhcp *dhcp, int optlen)
80 {
81  uint8_t *p = (uint8_t *) (dhcp + 1);
82  int i;
83  in_addr_t ret = 0;
84 
85  for (i = 0; i < optlen; )
86  {
87  const uint8_t type = p[i];
88  const int room = optlen - i;
89  if (type == DHCP_END)
90  {
91  break;
92  }
93  else if (type == DHCP_PAD)
94  {
95  ++i;
96  }
97  else if (type == DHCP_ROUTER)
98  {
99  if (room >= 2)
100  {
101  const int len = p[i+1]; /* get option length */
102  if (len <= (room-2))
103  {
104  /* get router IP address */
105  if (!ret && len >= 4 && (len & 3) == 0)
106  {
107  memcpy(&ret, p+i+2, 4);
108  ret = ntohl(ret);
109  }
110  {
111  /* delete the router option */
112  uint8_t *dest = p + i;
113  const int owlen = len + 2; /* len of data to overwrite */
114  uint8_t *src = dest + owlen;
115  uint8_t *end = p + optlen;
116  const int movlen = end - src;
117  if (movlen > 0)
118  {
119  memmove(dest, src, movlen); /* overwrite router option */
120  }
121  memset(end - owlen, DHCP_PAD, owlen); /* pad tail */
122  }
123  }
124  else
125  {
126  break;
127  }
128  }
129  else
130  {
131  break;
132  }
133  }
134  else /* some other option */
135  {
136  if (room >= 2)
137  {
138  const int len = p[i+1]; /* get option length */
139  i += (len + 2); /* advance to next option */
140  }
141  else
142  {
143  break;
144  }
145  }
146  }
147  return ret;
148 }
149 
150 in_addr_t
152 {
153  struct dhcp_full *df = (struct dhcp_full *) BPTR(ipbuf);
154  const int optlen = BLEN(ipbuf) - (sizeof(struct openvpn_iphdr) + sizeof(struct openvpn_udphdr) + sizeof(struct dhcp));
155 
156  if (optlen >= 0
158  && df->udp.source == htons(BOOTPS_PORT)
159  && df->udp.dest == htons(BOOTPC_PORT)
160  && df->dhcp.op == BOOTREPLY)
161  {
162  const int message_type = get_dhcp_message_type(&df->dhcp, optlen);
163  if (message_type == DHCPACK || message_type == DHCPOFFER)
164  {
165  /* get the router IP address while padding out all DHCP router options */
166  const in_addr_t ret = do_extract(&df->dhcp, optlen);
167 
168  /* recompute the UDP checksum */
169  df->udp.check = 0;
170  df->udp.check = htons(ip_checksum(AF_INET, (uint8_t *)&df->udp,
171  sizeof(struct openvpn_udphdr) + sizeof(struct dhcp) + optlen,
172  (uint8_t *)&df->ip.saddr, (uint8_t *)&df->ip.daddr,
174 
175  /* only return the extracted Router address if DHCPACK */
176  if (message_type == DHCPACK)
177  {
178  if (ret)
179  {
180  struct gc_arena gc = gc_new();
181  msg(D_ROUTE, "Extracted DHCP router address: %s", print_in_addr_t(ret, 0, &gc));
182  gc_free(&gc);
183  }
184 
185  return ret;
186  }
187  }
188  }
189  return 0;
190 }
dhcp_full::ip
struct openvpn_iphdr ip
Definition: dhcp.h:75
openvpn_udphdr::source
uint16_t source
Definition: proto.h:169
error.h
gc_new
static struct gc_arena gc_new(void)
Definition: buffer.h:1011
in_addr_t
#define in_addr_t
Definition: config-msvc.h:67
D_ROUTE
#define D_ROUTE
Definition: errlevel.h:80
OPENVPN_IPPROTO_UDP
#define OPENVPN_IPPROTO_UDP
Definition: proto.h:122
BOOTREPLY
#define BOOTREPLY
Definition: dhcp.h:55
config-msvc.h
dhcp_full::udp
struct openvpn_udphdr udp
Definition: dhcp.h:76
get_dhcp_message_type
static int get_dhcp_message_type(const struct dhcp *dhcp, const int optlen)
Definition: dhcp.c:39
DHCP_MSG_TYPE
#define DHCP_MSG_TYPE
Definition: dhcp.h:36
do_extract
static in_addr_t do_extract(struct dhcp *dhcp, int optlen)
Definition: dhcp.c:79
DHCP_PAD
#define DHCP_PAD
Definition: dhcp.h:34
openvpn_udphdr
Definition: proto.h:168
openvpn_iphdr::daddr
uint32_t daddr
Definition: proto.h:128
openvpn_iphdr::protocol
uint8_t protocol
Definition: proto.h:124
openvpn_iphdr::saddr
uint32_t saddr
Definition: proto.h:127
BLEN
#define BLEN(buf)
Definition: buffer.h:127
DHCP_ROUTER
#define DHCP_ROUTER
Definition: dhcp.h:35
dhcp_extract_router_msg
in_addr_t dhcp_extract_router_msg(struct buffer *ipbuf)
Definition: dhcp.c:151
openvpn_udphdr::check
uint16_t check
Definition: proto.h:172
dhcp::op
uint8_t op
Definition: dhcp.h:56
buffer
Wrapper structure for dynamically allocated memory.
Definition: buffer.h:60
DHCPOFFER
#define DHCPOFFER
Definition: dhcp.h:41
BOOTPC_PORT
#define BOOTPC_PORT
Definition: dhcp.h:51
print_in_addr_t
const char * print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc)
Definition: socket.c:2905
syshead.h
BPTR
#define BPTR(buf)
Definition: buffer.h:124
dhcp.h
gc_arena
Garbage collection arena used to keep track of dynamically allocated memory.
Definition: buffer.h:116
DHCP_END
#define DHCP_END
Definition: dhcp.h:37
DHCPACK
#define DHCPACK
Definition: dhcp.h:44
BOOTPS_PORT
#define BOOTPS_PORT
Definition: dhcp.h:50
gc_free
static void gc_free(struct gc_arena *a)
Definition: buffer.h:1019
socket.h
config.h
dhcp_full::dhcp
struct dhcp dhcp
Definition: dhcp.h:77
openvpn_udphdr::dest
uint16_t dest
Definition: proto.h:170
openvpn_iphdr
Definition: proto.h:106
memdbg.h
msg
#define msg(flags,...)
Definition: error.h:150
dhcp_full
Definition: dhcp.h:74
dhcp
Definition: dhcp.h:53
ip_checksum
uint16_t ip_checksum(const sa_family_t af, const uint8_t *payload, const int len_payload, const uint8_t *src_addr, const uint8_t *dest_addr, const int proto)
Calculates an IP or IPv6 checksum with a pseudo header as required by TCP, UDP and ICMPv6.
Definition: proto.c:125