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-2024 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#endif
27
28#include "syshead.h"
29
30#include "dhcp.h"
31#include "socket.h"
32#include "error.h"
33
34#include "memdbg.h"
35
36static int
37get_dhcp_message_type(const struct dhcp *dhcp, const int optlen)
38{
39 const uint8_t *p = (uint8_t *) (dhcp + 1);
40 int i;
41
42 for (i = 0; i < optlen; ++i)
43 {
44 const uint8_t type = p[i];
45 const int room = optlen - i;
46 if (type == DHCP_END) /* didn't find what we were looking for */
47 {
48 return -1;
49 }
50 else if (type == DHCP_PAD) /* no-operation */
51 {
52 }
53 else if (type == DHCP_MSG_TYPE) /* what we are looking for */
54 {
55 if (room >= 3)
56 {
57 if (p[i+1] == 1) /* option length should be 1 */
58 {
59 return p[i+2]; /* return message type */
60 }
61 }
62 return -1;
63 }
64 else /* some other option */
65 {
66 if (room >= 2)
67 {
68 const int len = p[i+1]; /* get option length */
69 i += (len + 1); /* advance to next option */
70 }
71 }
72 }
73 return -1;
74}
75
76static in_addr_t
77do_extract(struct dhcp *dhcp, int optlen)
78{
79 uint8_t *p = (uint8_t *) (dhcp + 1);
80 int i;
81 in_addr_t ret = 0;
82
83 for (i = 0; i < optlen; )
84 {
85 const uint8_t type = p[i];
86 const int room = optlen - i;
87 if (type == DHCP_END)
88 {
89 break;
90 }
91 else if (type == DHCP_PAD)
92 {
93 ++i;
94 }
95 else if (type == DHCP_ROUTER)
96 {
97 if (room >= 2)
98 {
99 const int len = p[i+1]; /* get option length */
100 if (len <= (room-2))
101 {
102 /* get router IP address */
103 if (!ret && len >= 4 && (len & 3) == 0)
104 {
105 memcpy(&ret, p+i+2, 4);
106 ret = ntohl(ret);
107 }
108 {
109 /* delete the router option */
110 uint8_t *dest = p + i;
111 const int owlen = len + 2; /* len of data to overwrite */
112 uint8_t *src = dest + owlen;
113 uint8_t *end = p + optlen;
114 const int movlen = end - src;
115 if (movlen > 0)
116 {
117 memmove(dest, src, movlen); /* overwrite router option */
118 }
119 memset(end - owlen, DHCP_PAD, owlen); /* pad tail */
120 }
121 }
122 else
123 {
124 break;
125 }
126 }
127 else
128 {
129 break;
130 }
131 }
132 else /* some other option */
133 {
134 if (room >= 2)
135 {
136 const int len = p[i+1]; /* get option length */
137 i += (len + 2); /* advance to next option */
138 }
139 else
140 {
141 break;
142 }
143 }
144 }
145 return ret;
146}
147
148in_addr_t
150{
151 struct dhcp_full *df = (struct dhcp_full *) BPTR(ipbuf);
152 const int optlen = BLEN(ipbuf) - (sizeof(struct openvpn_iphdr) + sizeof(struct openvpn_udphdr) + sizeof(struct dhcp));
153
154 if (optlen >= 0
156 && df->udp.source == htons(BOOTPS_PORT)
157 && df->udp.dest == htons(BOOTPC_PORT)
158 && df->dhcp.op == BOOTREPLY)
159 {
160 const int message_type = get_dhcp_message_type(&df->dhcp, optlen);
161 if (message_type == DHCPACK || message_type == DHCPOFFER)
162 {
163 /* get the router IP address while padding out all DHCP router options */
164 const in_addr_t ret = do_extract(&df->dhcp, optlen);
165
166 /* recompute the UDP checksum */
167 df->udp.check = 0;
168 df->udp.check = htons(ip_checksum(AF_INET, (uint8_t *)&df->udp,
169 sizeof(struct openvpn_udphdr) + sizeof(struct dhcp) + optlen,
170 (uint8_t *)&df->ip.saddr, (uint8_t *)&df->ip.daddr,
172
173 /* only return the extracted Router address if DHCPACK */
174 if (message_type == DHCPACK)
175 {
176 if (ret)
177 {
178 struct gc_arena gc = gc_new();
179 msg(D_ROUTE, "Extracted DHCP router address: %s", print_in_addr_t(ret, 0, &gc));
180 gc_free(&gc);
181 }
182
183 return ret;
184 }
185 }
186 }
187 return 0;
188}
#define BPTR(buf)
Definition buffer.h:124
#define BLEN(buf)
Definition buffer.h:127
static void gc_free(struct gc_arena *a)
Definition buffer.h:1033
static struct gc_arena gc_new(void)
Definition buffer.h:1025
in_addr_t dhcp_extract_router_msg(struct buffer *ipbuf)
Definition dhcp.c:149
static in_addr_t do_extract(struct dhcp *dhcp, int optlen)
Definition dhcp.c:77
static int get_dhcp_message_type(const struct dhcp *dhcp, const int optlen)
Definition dhcp.c:37
#define DHCP_PAD
Definition dhcp.h:34
#define DHCP_ROUTER
Definition dhcp.h:35
#define DHCP_MSG_TYPE
Definition dhcp.h:36
#define DHCPACK
Definition dhcp.h:44
#define BOOTPS_PORT
Definition dhcp.h:50
#define BOOTPC_PORT
Definition dhcp.h:51
#define BOOTREPLY
Definition dhcp.h:55
#define DHCPOFFER
Definition dhcp.h:41
#define DHCP_END
Definition dhcp.h:37
#define D_ROUTE
Definition errlevel.h:80
#define msg(flags,...)
Definition error.h:144
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:123
#define OPENVPN_IPPROTO_UDP
Definition proto.h:108
const char * print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc)
Definition socket.c:2974
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
struct openvpn_udphdr udp
Definition dhcp.h:76
struct dhcp dhcp
Definition dhcp.h:77
struct openvpn_iphdr ip
Definition dhcp.h:75
Definition dhcp.h:53
uint8_t op
Definition dhcp.h:56
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:117
uint32_t saddr
Definition proto.h:113
uint32_t daddr
Definition proto.h:114
uint8_t protocol
Definition proto.h:110
uint16_t check
Definition proto.h:158
uint16_t source
Definition proto.h:155
uint16_t dest
Definition proto.h:156
struct gc_arena gc
Definition test_ssl.c:155