OpenVPN 3 Core Library
Loading...
Searching...
No Matches
dhcp_capture.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12#ifndef OPENVPN_TUN_CLIENT_DHCP_CAPTURE_H
13#define OPENVPN_TUN_CLIENT_DHCP_CAPTURE_H
14
16#include <cstring>
17
21#include <openvpn/ip/dhcp.hpp>
23
24namespace openvpn {
26{
27 public:
28 // We take a TunBuilderCapture object with previously pushed
29 // options and augment it with additional options sniffed
30 // from the DHCP reply.
32 : props(props_arg)
33 {
34 if (props->vpn_ipv4() || props->vpn_ipv4())
35 OPENVPN_LOG("NOTE: pushed ifconfig directive is ignored in layer 2 mode");
36 if (!props->dns_options.servers.empty())
37 OPENVPN_LOG("NOTE: pushed DNS servers are ignored in layer 2 mode");
38 reset();
39 }
40
41 // returns true when router addr and DNS servers are captured
42 bool mod_reply(Buffer &buf)
43 {
44 if (buf.size() < sizeof(DHCPPacket))
45 return false;
46 if (!is_safe_conversion<unsigned int>(buf.size()))
47 return false;
48
49 DHCPPacket *dhcp = (DHCPPacket *)buf.data();
50 if (dhcp->ip.protocol == IPCommon::UDP
51 && dhcp->udp.source == htons(DHCP::BOOTPS_PORT)
52 && dhcp->udp.dest == htons(DHCP::BOOTPC_PORT)
53 && dhcp->dhcp.op == DHCP::BOOTREPLY)
54 {
55 const unsigned int optlen = static_cast<unsigned int>(buf.size() - sizeof(DHCPPacket));
56 const int message_type = dhcp_message_type(dhcp, optlen);
57 if (message_type == DHCP::DHCPACK || message_type == DHCP::DHCPOFFER)
58 {
59 /* get host IP address/netmask */
61 const IPv4::Addr netmask = get_netmask(dhcp, optlen);
62 const int prefix_len = netmask.prefix_len_nothrow();
63
64 /* get the router IP address while padding out all DHCP router options */
65 const IPv4::Addr router = extract_router(dhcp, optlen);
66
67 /* get DNS server addresses */
68 const std::vector<DnsAddress> dns_addresses = get_dns(dhcp, optlen);
69
70 /* recompute the UDP checksum */
71 dhcp->udp.check = 0;
72 dhcp->udp.check = htons(udp_checksum((uint8_t *)&dhcp->udp,
73 sizeof(UDPHeader) + sizeof(DHCP) + optlen,
74 (uint8_t *)&dhcp->ip.saddr,
75 (uint8_t *)&dhcp->ip.daddr));
76
77 /* only capture the extracted Router address if DHCPACK */
78 if (message_type == DHCP::DHCPACK && !configured)
79 {
80 bool complete = true;
81 if (host.unspecified())
82 {
83 OPENVPN_LOG("NOTE: failed to obtain host address via DHCP");
84 complete = false;
85 }
86 if (netmask.unspecified())
87 {
88 OPENVPN_LOG("NOTE: failed to obtain netmask via DHCP");
89 complete = false;
90 }
91 if (prefix_len < 0)
92 {
93 OPENVPN_LOG("NOTE: bad netmask obtained via DHCP: " << netmask);
94 complete = false;
95 }
96 if (router.unspecified())
97 {
98 OPENVPN_LOG("NOTE: failed to obtain router via DHCP");
99 complete = false;
100 }
101 if (complete)
102 {
103 reset();
104 props->tun_builder_add_address(host.to_string(), prefix_len, router.to_string(), false, false);
105 if (dns_addresses.empty())
106 OPENVPN_LOG("NOTE: failed to obtain DNS servers via DHCP");
107 else
108 {
109 DnsServer server;
110 server.addresses = dns_addresses;
112 dns_options.servers[0] = server;
114 }
115 }
116 return configured = complete;
117 }
118 }
119 }
120 return false;
121 }
122
124 {
125 return *props;
126 }
127
128 private:
129 void reset()
130 {
133 }
134
135 static int dhcp_message_type(const DHCPPacket *dhcp, const unsigned int optlen)
136 {
137 const std::uint8_t *p = dhcp->options;
138 for (unsigned int i = 0; i < optlen; ++i)
139 {
140 const std::uint8_t type = p[i];
141 const unsigned int room = optlen - i;
142
143 if (type == DHCP::DHCP_END) /* didn't find what we were looking for */
144 return -1;
145 else if (type == DHCP::DHCP_PAD) /* no-operation */
146 ;
147 else if (type == DHCP::DHCP_MSG_TYPE) /* what we are looking for */
148 {
149 if (room >= 3)
150 {
151 if (p[i + 1] == 1) /* option length should be 1 */
152 return p[i + 2]; /* return message type */
153 }
154 return -1;
155 }
156 else /* some other option */
157 {
158 if (room >= 2)
159 {
160 const unsigned int len = p[i + 1]; /* get option length */
161 i += (len + 1); /* advance to next option */
162 }
163 }
164 }
165 return -1;
166 }
167
168 static IPv4::Addr extract_router(DHCPPacket *dhcp, const unsigned int optlen)
169 {
170 std::uint8_t *p = dhcp->options;
172
173 for (unsigned int i = 0; i < optlen;)
174 {
175 const std::uint8_t type = p[i];
176 const unsigned int room = optlen - i;
177
178 if (type == DHCP::DHCP_END)
179 break;
180 else if (type == DHCP::DHCP_PAD)
181 ++i;
182 else if (type == DHCP::DHCP_ROUTER)
183 {
184 if (room >= 2)
185 {
186 const unsigned int len = p[i + 1]; /* get option length */
187 if (len <= (room - 2))
188 {
189 /* get router IP address */
190 if (ret.unspecified() && len >= 4 && (len & 3) == 0)
191 ret = IPv4::Addr::from_bytes_net(p + i + 2);
192
193 /* delete the router option */
194 std::uint8_t *dest = p + i;
195 const unsigned int owlen = len + 2; /* len of data to overwrite */
196 std::uint8_t *src = dest + owlen;
197 std::uint8_t *end = p + optlen;
198 const ssize_t movlen = end - src;
199 if (movlen > 0)
200 std::memmove(dest, src, static_cast<size_t>(movlen)); /* overwrite router option */
201 std::memset(end - owlen, DHCP::DHCP_PAD, owlen); /* pad tail */
202 }
203 else
204 break;
205 }
206 else
207 break;
208 }
209 else /* some other option */
210 {
211 if (room >= 2)
212 {
213 const unsigned int len = p[i + 1]; /* get option length */
214 i += (len + 2); /* advance to next option */
215 }
216 else
217 break;
218 }
219 }
220 return ret;
221 }
222
223 static IPv4::Addr get_netmask(const DHCPPacket *dhcp, const unsigned int optlen)
224 {
225 const std::uint8_t *p = dhcp->options;
227
228 for (unsigned int i = 0; i < optlen;)
229 {
230 const std::uint8_t type = p[i];
231 const unsigned int room = optlen - i;
232
233 if (type == DHCP::DHCP_END)
234 break;
235 else if (type == DHCP::DHCP_PAD)
236 ++i;
237 else if (type == DHCP::DHCP_NETMASK)
238 {
239 if (room >= 2)
240 {
241 const unsigned int len = p[i + 1]; /* get option length */
242 if (len <= (room - 2) && len == 4)
243 return IPv4::Addr::from_bytes_net(p + i + 2);
244 else
245 break;
246 }
247 else
248 break;
249 }
250 else /* some other option */
251 {
252 if (room >= 2)
253 {
254 const unsigned int len = p[i + 1]; /* get option length */
255 i += (len + 2); /* advance to next option */
256 }
257 else
258 break;
259 }
260 }
261 return ret;
262 }
263
264 static std::vector<DnsAddress> get_dns(const DHCPPacket *dhcp, const unsigned int optlen)
265 {
266 const std::uint8_t *p = dhcp->options;
267 std::vector<DnsAddress> ret;
268
269 for (unsigned int i = 0; i < optlen;)
270 {
271 const std::uint8_t type = p[i];
272 const unsigned int room = optlen - i;
273
274 if (type == DHCP::DHCP_END)
275 break;
276 else if (type == DHCP::DHCP_PAD)
277 ++i;
278 else if (type == DHCP::DHCP_DNS)
279 {
280 if (room >= 2)
281 {
282 const unsigned int len = p[i + 1]; /* get option length */
283 if (len <= (room - 2) && (len & 3) == 0)
284 {
285 /* get DNS addresses */
286 for (unsigned int j = 0; j < len; j += 4)
287 ret.push_back({IPv4::Addr::from_bytes_net(p + i + j + 2).to_string(), 0});
288
289 i += (len + 2); /* advance to next option */
290 }
291 else
292 break;
293 }
294 else
295 break;
296 }
297 else /* some other option */
298 {
299 if (room >= 2)
300 {
301 const unsigned int len = p[i + 1]; /* get option length */
302 i += (len + 2); /* advance to next option */
303 }
304 else
305 break;
306 }
307 }
308 return ret;
309 }
310
312 bool configured = false;
313};
314} // namespace openvpn
315
316#endif
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1242
T * data()
Get a mutable pointer to the start of the array.
Definition buffer.hpp:1450
static int dhcp_message_type(const DHCPPacket *dhcp, const unsigned int optlen)
static IPv4::Addr extract_router(DHCPPacket *dhcp, const unsigned int optlen)
TunBuilderCapture::Ptr props
const TunBuilderCapture & get_props() const
DHCPCapture(const TunBuilderCapture::Ptr &props_arg)
static std::vector< DnsAddress > get_dns(const DHCPPacket *dhcp, const unsigned int optlen)
static IPv4::Addr get_netmask(const DHCPPacket *dhcp, const unsigned int optlen)
bool mod_reply(Buffer &buf)
static Addr from_bytes_net(const unsigned char *bytes)
Definition ipv4.hpp:160
static Addr from_uint32_net(const base_type addr)
Definition ipv4.hpp:112
int prefix_len_nothrow() const
Definition ipv4.hpp:464
static Addr from_zero()
Definition ipv4.hpp:168
bool unspecified() const
Definition ipv4.hpp:429
std::string to_string() const
Definition ipv4.hpp:232
bool tun_builder_set_dns_options(const DnsOptions &dns) override
Set DNS options for use with tun builder.
Definition capture.hpp:737
void reset_dns_options()
Resets DNS options to default values.
Definition capture.hpp:892
bool tun_builder_add_address(const std::string &address, int prefix_length, const std::string &gateway, bool ipv6, bool net30) override
Adds a local address to the TUN interface.
Definition capture.hpp:644
const RouteAddress * vpn_ipv4() const
Gets the IPv4 tunnel address.
Definition capture.hpp:902
void reset_tunnel_addresses()
Resets all tunnel addresses.
Definition capture.hpp:881
#define OPENVPN_LOG(args)
std::uint16_t udp_checksum(const std::uint8_t *buf, const unsigned int len_udp, const std::uint8_t *src_addr, const std::uint8_t *dest_addr)
Definition udp.hpp:34
std::uint8_t options[]
Definition dhcp.hpp:77
IPv4Header ip
Definition dhcp.hpp:74
UDPHeader udp
Definition dhcp.hpp:75
std::uint32_t yiaddr
Definition dhcp.hpp:62
@ DHCP_MSG_TYPE
Definition dhcp.hpp:32
std::uint8_t op
Definition dhcp.hpp:54
All DNS options set with the –dns or –dhcp-option directive.
std::map< int, DnsServer > servers
DNS settings for a name server.
std::vector< DnsAddress > addresses
std::uint8_t protocol
Definition ip4.hpp:57
std::uint32_t daddr
Definition ip4.hpp:61
std::uint32_t saddr
Definition ip4.hpp:60
std::uint16_t source
Definition udp.hpp:26
std::uint16_t dest
Definition udp.hpp:27
std::uint16_t check
Definition udp.hpp:29
proxy_host_port host
DnsOptions dns_options
std::string ret
int prefix_len(const IPv4::Addr::base_type mask)