VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/Dhcpd/DhcpOptions.cpp@ 79761

Last change on this file since 79761 was 79761, checked in by vboxsync, 5 years ago

Main/DHCPServer,Dhcpd,VBoxManage: Added --log option to the DHCP server so we can start logging early. Added log rotation and limits. Put the config file next to the log and leases file. Validate DHCP options by reusing the parser code from the server, adding a bunch more DHCP options to the parser. Removed legacy and hardcoded configuration options from the dhcp server, it's all config file now. Fixed a bug in the option parsing of the VBoxManage dhcpserver add/modify commands. bugref:9288

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.3 KB
Line 
1/* $Id: DhcpOptions.cpp 79761 2019-07-14 03:18:41Z vboxsync $ */
2/** @file
3 * DHCP server - DHCP options
4 */
5
6/*
7 * Copyright (C) 2017-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include "DhcpdInternal.h"
23#include "DhcpOptions.h"
24#include "DhcpMessage.h"
25
26#include <iprt/cidr.h>
27
28
29optmap_t &operator<<(optmap_t &optmap, DhcpOption *option)
30{
31 if (option == NULL)
32 return optmap;
33
34 if (option->present())
35 optmap[option->optcode()] = std::shared_ptr<DhcpOption>(option);
36 else
37 optmap.erase(option->optcode());
38
39 return optmap;
40}
41
42
43optmap_t &operator<<(optmap_t &optmap, const std::shared_ptr<DhcpOption> &option)
44{
45 if (!option)
46 return optmap;
47
48 if (option->present())
49 optmap[option->optcode()] = option;
50 else
51 optmap.erase(option->optcode());
52
53 return optmap;
54}
55
56
57int DhcpOption::encode(octets_t &dst) const
58{
59 if (!m_fPresent)
60 return VERR_INVALID_STATE;
61
62 size_t cbOrig = dst.size();
63
64 append(dst, m_OptCode);
65 appendLength(dst, 0); /* placeholder */
66
67 ssize_t cbValue = encodeValue(dst);
68 if (cbValue < 0 || UINT8_MAX <= cbValue)
69 {
70 dst.resize(cbOrig); /* undo */
71 return VERR_INVALID_PARAMETER;
72 }
73
74 dst[cbOrig+1] = cbValue;
75 return VINF_SUCCESS;
76}
77
78
79/* static */
80const octets_t *DhcpOption::findOption(const rawopts_t &aOptMap, uint8_t aOptCode)
81{
82 rawopts_t::const_iterator it(aOptMap.find(aOptCode));
83 if (it == aOptMap.end())
84 return NULL;
85
86 return &it->second;
87}
88
89
90int DhcpOption::decode(const rawopts_t &map)
91{
92 const octets_t *rawopt = DhcpOption::findOption(map, m_OptCode);
93 if (rawopt == NULL)
94 return VERR_NOT_FOUND;
95
96 int rc = decodeValue(*rawopt, rawopt->size());
97 if (RT_FAILURE(rc))
98 return VERR_INVALID_PARAMETER;
99
100 return VINF_SUCCESS;
101}
102
103
104int DhcpOption::decode(const DhcpClientMessage &req)
105{
106 return decode(req.rawopts());
107}
108
109
110int DhcpOption::parse1(bool &aValue, const char *pcszValue)
111{
112 pcszValue = RTStrStripL(pcszValue);
113 if ( strcmp(pcszValue, "true") == 0
114 || strcmp(pcszValue, "1") == 0
115 || strcmp(pcszValue, "yes") == 0
116 || strcmp(pcszValue, "on") == 0 )
117 {
118 aValue = true;
119 return VINF_SUCCESS;
120 }
121
122 if ( strcmp(pcszValue, "false") == 0
123 || strcmp(pcszValue, "0") == 0
124 || strcmp(pcszValue, "no") == 0
125 || strcmp(pcszValue, "off") == 0 )
126 {
127 aValue = false;
128 return VINF_SUCCESS;
129 }
130
131 uint8_t bTmp;
132 int rc = RTStrToUInt8Full(RTStrStripL(pcszValue), 10, &bTmp);
133 if (rc == VERR_TRAILING_SPACES)
134 rc = VINF_SUCCESS;
135 if (RT_SUCCESS(rc))
136 aValue = bTmp != 0;
137
138 return rc;
139}
140
141
142int DhcpOption::parse1(uint8_t &aValue, const char *pcszValue)
143{
144 int rc = RTStrToUInt8Full(RTStrStripL(pcszValue), 10, &aValue);
145 if (rc == VERR_TRAILING_SPACES)
146 rc = VINF_SUCCESS;
147 return rc;
148}
149
150
151int DhcpOption::parse1(uint16_t &aValue, const char *pcszValue)
152{
153 int rc = RTStrToUInt16Full(RTStrStripL(pcszValue), 10, &aValue);
154
155 if (rc == VERR_TRAILING_SPACES)
156 rc = VINF_SUCCESS;
157 return rc;
158}
159
160
161int DhcpOption::parse1(uint32_t &aValue, const char *pcszValue)
162{
163 int rc = RTStrToUInt32Full(RTStrStripL(pcszValue), 10, &aValue);
164
165 if (rc == VERR_TRAILING_SPACES)
166 rc = VINF_SUCCESS;
167 return rc;
168}
169
170
171int DhcpOption::parse1(RTNETADDRIPV4 &aValue, const char *pcszValue)
172{
173 return RTNetStrToIPv4Addr(pcszValue, &aValue);
174}
175
176
177int DhcpOption::parse1(DhcpIpv4AddrAndMask &aValue, const char *pcszValue)
178{
179 return RTCidrStrToIPv4(pcszValue, &aValue.Ipv4, &aValue.Mask);
180}
181
182
183template <typename a_Type>
184static int DhcpOption::parseList(std::vector<a_Type> &aList, const char *pcszValue)
185{
186 std::vector<a_Type> vecTmp;
187
188 pcszValue = RTStrStripL(pcszValue);
189 for (;;)
190 {
191 /* Assume space, tab, comma or semicolon is used as separator (superset of RTStrStrip): */
192 const char *pszNext = strpbrk(pcszValue, " ,;:\t\n\r");
193 char szTmp[256];
194 if (pszNext)
195 {
196 size_t cchToCopy = pszNext - pcszValue;
197 if (cchToCopy >= sizeof(szTmp))
198 return VERR_INVALID_PARAMETER;
199 memcpy(szTmp, pcszValue, cchToCopy);
200 szTmp[cchToCopy] = '\0';
201 pcszValue = szTmp;
202
203 /* Advance pszNext past the separator character and fluff: */
204 char ch;
205 do
206 pszNext++;
207 while ((ch = *pszNext) == ' ' || ch == ':' || ch == ';' || ch == '\t' || ch == '\n' || ch == '\r');
208 if (ch == '\0')
209 pszNext = NULL;
210 }
211
212 /* Try convert it: */
213 a_Type Value;
214 int rc = DhcpOption::parse1(Value, pcszValue);
215 if (RT_SUCCESS(rc))
216 vecTmp.push_back(Value);
217 else
218 return VERR_INVALID_PARAMETER;
219
220 if (pszNext)
221 pcszValue = pszNext;
222 else
223 break;
224 }
225
226 aList.swap(vecTmp);
227 return VINF_SUCCESS;
228
229}
230
231/** ASSUME that uint8_t means hex byte strings. */
232template <>
233static int DhcpOption::parseList(std::vector<uint8_t> &aList, const char *pcszValue)
234{
235 uint8_t abBuf[256];
236 const char *pszNext = NULL;
237 size_t cbReturned = 0;
238 int rc = RTStrConvertHexBytesEx(RTStrStripL(pcszValue), abBuf, sizeof(abBuf), RTSTRCONVERTHEXBYTES_F_SEP_COLON,
239 &pszNext, &cbReturned);
240 if (RT_SUCCESS(rc))
241 {
242 if (pszNext)
243 pszNext = RTStrStripL(pszNext);
244 if (*pszNext)
245 {
246 for (size_t i = 0; i < cbReturned; i++)
247 aList.push_back(abBuf[i]);
248 return VINF_SUCCESS;
249 }
250 rc = VERR_TRAILING_CHARS;
251 }
252 return rc;
253}
254
255
256
257/*
258 * XXX: See DHCPServer::encodeOption()
259 */
260int DhcpOption::parseHex(octets_t &aRawValue, const char *pcszValue)
261{
262 octets_t data;
263 char *pszNext;
264 int rc;
265
266 if (pcszValue == NULL || *pcszValue == '\0')
267 return VERR_INVALID_PARAMETER;
268
269 while (*pcszValue != '\0')
270 {
271 if (data.size() > UINT8_MAX)
272 return VERR_INVALID_PARAMETER;
273
274 uint8_t u8Byte;
275 rc = RTStrToUInt8Ex(pcszValue, &pszNext, 16, &u8Byte);
276 if (!RT_SUCCESS(rc))
277 return rc;
278
279 if (*pszNext == ':')
280 ++pszNext;
281 else if (*pszNext != '\0')
282 return VERR_PARSE_ERROR;
283
284 data.push_back(u8Byte);
285 pcszValue = pszNext;
286 }
287
288 aRawValue.swap(data);
289 return VINF_SUCCESS;
290}
291
292
293DhcpOption *DhcpOption::parse(uint8_t aOptCode, int aEnc, const char *pcszValue, int *prc /*= NULL*/)
294{
295 int rcIgn;
296 if (!prc)
297 prc = &rcIgn;
298
299 switch (aEnc)
300 {
301 case 0: /* DhcpOptEncoding_Legacy */
302 switch (aOptCode)
303 {
304#define HANDLE(a_OptClass) \
305 case a_OptClass::optcode: \
306 return a_OptClass::parse(pcszValue, prc)
307
308 HANDLE(OptSubnetMask); // 1
309 HANDLE(OptTimeOffset); // 2
310 HANDLE(OptRouters); // 3
311 HANDLE(OptTimeServers); // 4
312 HANDLE(OptNameServers); // 5
313 HANDLE(OptDNSes); // 6
314 HANDLE(OptLogServers); // 7
315 HANDLE(OptCookieServers); // 8
316 HANDLE(OptLPRServers); // 9
317 HANDLE(OptImpressServers); // 10
318 HANDLE(OptResourceLocationServers); // 11
319 HANDLE(OptHostName); // 12
320 HANDLE(OptBootFileSize); // 13
321 HANDLE(OptMeritDumpFile); // 14
322 HANDLE(OptDomainName); // 15
323 HANDLE(OptSwapServer); // 16
324 HANDLE(OptRootPath); // 17
325 HANDLE(OptExtensionPath); // 18
326 HANDLE(OptIPForwarding); // 19
327 HANDLE(OptNonLocalSourceRouting); // 20
328 HANDLE(OptPolicyFilter); // 21
329 HANDLE(OptMaxDatagramReassemblySize); // 22
330 HANDLE(OptDefaultIPTTL); // 23
331 HANDLE(OptDefaultPathMTUAgingTimeout); // 24
332 HANDLE(OptPathMTUPlateauTable); // 25
333 HANDLE(OptInterfaceMTU); // 26
334 HANDLE(OptAllSubnetsAreLocal); // 27
335 HANDLE(OptBroadcastAddress); // 28
336 HANDLE(OptPerformMaskDiscovery); // 29
337 HANDLE(OptMaskSupplier); // 30
338 HANDLE(OptPerformRouterDiscovery); // 31
339 HANDLE(OptRouterSolicitationAddress); // 32
340 HANDLE(OptStaticRoute); // 33
341 HANDLE(OptTrailerEncapsulation); // 34
342 HANDLE(OptARPCacheTimeout); // 35
343 HANDLE(OptEthernetEncapsulation); // 36
344 HANDLE(OptTCPDefaultTTL); // 37
345 HANDLE(OptTCPKeepaliveInterval); // 38
346 HANDLE(OptTCPKeepaliveGarbage); // 39
347 HANDLE(OptNISDomain); // 40
348 HANDLE(OptNISServers); // 41
349 HANDLE(OptNTPServers); // 42
350 HANDLE(OptVendorSpecificInfo); // 43
351 HANDLE(OptNetBIOSNameServers); // 44
352 HANDLE(OptNetBIOSDatagramServers); // 45
353 HANDLE(OptNetBIOSNodeType); // 46
354 HANDLE(OptNetBIOSScope); // 47
355 HANDLE(OptXWindowsFontServers); // 48
356 HANDLE(OptXWindowsDisplayManager); // 49
357#ifndef IN_VBOXSVC /* Don't allow these in new configs */
358 // OptRequestedAddress (50) is client only and not configurable.
359 HANDLE(OptLeaseTime); // 51 - for historical reasons? Configuable elsewhere now.
360 // OptOptionOverload (52) is part of the protocol and not configurable.
361 // OptMessageType (53) is part of the protocol and not configurable.
362 // OptServerId (54) is the IP address of the server and configurable elsewhere.
363 // OptParameterRequest (55) is client only and not configurable.
364 // OptMessage (56) is server failure message and not configurable.
365 // OptMaxDHCPMessageSize (57) is client only (?) and not configurable.
366 HANDLE(OptRenewalTime); // 58 - for historical reasons?
367 HANDLE(OptRebindingTime); // 59 - for historical reasons?
368 // OptVendorClassId (60) is client only and not configurable.
369 // OptClientId (61) is client only and not configurable.
370#endif
371 HANDLE(OptNetWareIPDomainName); // 62
372 HANDLE(OptNetWareIPInformation); // 63
373 HANDLE(OptNISPlusDomain); // 64
374 HANDLE(OptNISPlusServers); // 65
375 HANDLE(OptTFTPServer); // 66 - perhaps we should use an alternative way to configure these.
376 HANDLE(OptBootFileName); // 67 - perhaps we should use an alternative way to configure these.
377 HANDLE(OptMobileIPHomeAgents); // 68
378 HANDLE(OptSMTPServers); // 69
379 HANDLE(OptPOP3Servers); // 70
380 HANDLE(OptNNTPServers); // 71
381 HANDLE(OptWWWServers); // 72
382 HANDLE(OptFingerServers); // 73
383 HANDLE(OptIRCServers); // 74
384 HANDLE(OptStreetTalkServers); // 75
385 HANDLE(OptSTDAServers); // 76
386 // OptUserClassId (77) is client only and not configurable.
387 HANDLE(OptSLPDirectoryAgent); // 78
388 HANDLE(OptSLPServiceScope); // 79
389 // OptRapidCommit (80) is not configurable.
390
391#undef HANDLE
392 default:
393 if (prc)
394 *prc = VERR_NOT_IMPLEMENTED;
395 return NULL;
396 }
397 break;
398
399 case 1:
400 return RawOption::parse(aOptCode, pcszValue, prc);
401
402 default:
403 if (prc)
404 *prc = VERR_WRONG_TYPE;
405 return NULL;
406 }
407}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette