VirtualBox

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

Last change on this file since 94991 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.1 KB
Line 
1/* $Id: DhcpOptions.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * DHCP server - DHCP options
4 */
5
6/*
7 * Copyright (C) 2017-2022 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#ifndef IN_VBOXSVC
25# include "DhcpMessage.h"
26#endif
27
28#include <iprt/cidr.h>
29
30
31#ifndef IN_VBOXSVC
32
33optmap_t &operator<<(optmap_t &optmap, DhcpOption *option)
34{
35 if (option == NULL)
36 return optmap;
37
38 if (option->present())
39 optmap[option->optcode()] = std::shared_ptr<DhcpOption>(option);
40 else
41 optmap.erase(option->optcode());
42
43 return optmap;
44}
45
46
47optmap_t &operator<<(optmap_t &optmap, const std::shared_ptr<DhcpOption> &option)
48{
49 if (!option)
50 return optmap;
51
52 if (option->present())
53 optmap[option->optcode()] = option;
54 else
55 optmap.erase(option->optcode());
56
57 return optmap;
58}
59
60#endif /* !IN_VBOXSVC */
61
62
63int DhcpOption::encode(octets_t &dst) const
64{
65 if (!m_fPresent)
66 return VERR_INVALID_STATE;
67
68 size_t cbOrig = dst.size();
69
70 append(dst, m_OptCode);
71 appendLength(dst, 0); /* placeholder */
72
73 ssize_t cbValue = encodeValue(dst);
74 if (cbValue < 0 || UINT8_MAX <= cbValue)
75 {
76 dst.resize(cbOrig); /* undo */
77 return VERR_INVALID_PARAMETER;
78 }
79
80 dst[cbOrig+1] = (uint8_t)cbValue;
81 return VINF_SUCCESS;
82}
83
84
85/* static */
86const octets_t *DhcpOption::findOption(const rawopts_t &aOptMap, uint8_t aOptCode)
87{
88 rawopts_t::const_iterator it(aOptMap.find(aOptCode));
89 if (it == aOptMap.end())
90 return NULL;
91
92 return &it->second;
93}
94
95
96int DhcpOption::decode(const rawopts_t &map)
97{
98 const octets_t *rawopt = DhcpOption::findOption(map, m_OptCode);
99 if (rawopt == NULL)
100 return VERR_NOT_FOUND;
101
102 int rc = decodeValue(*rawopt, rawopt->size());
103 if (RT_FAILURE(rc))
104 return VERR_INVALID_PARAMETER;
105
106 return VINF_SUCCESS;
107}
108
109
110#ifndef IN_VBOXSVC
111int DhcpOption::decode(const DhcpClientMessage &req)
112{
113 return decode(req.rawopts());
114}
115#endif
116
117
118int DhcpOption::parse1(bool &aValue, const char *pcszValue)
119{
120 pcszValue = RTStrStripL(pcszValue);
121 if ( strcmp(pcszValue, "true") == 0
122 || strcmp(pcszValue, "1") == 0
123 || strcmp(pcszValue, "yes") == 0
124 || strcmp(pcszValue, "on") == 0 )
125 {
126 aValue = true;
127 return VINF_SUCCESS;
128 }
129
130 if ( strcmp(pcszValue, "false") == 0
131 || strcmp(pcszValue, "0") == 0
132 || strcmp(pcszValue, "no") == 0
133 || strcmp(pcszValue, "off") == 0 )
134 {
135 aValue = false;
136 return VINF_SUCCESS;
137 }
138
139 uint8_t bTmp;
140 int rc = RTStrToUInt8Full(RTStrStripL(pcszValue), 10, &bTmp);
141 if (rc == VERR_TRAILING_SPACES)
142 rc = VINF_SUCCESS;
143 if (RT_SUCCESS(rc))
144 aValue = bTmp != 0;
145
146 return rc;
147}
148
149
150int DhcpOption::parse1(uint8_t &aValue, const char *pcszValue)
151{
152 int rc = RTStrToUInt8Full(RTStrStripL(pcszValue), 10, &aValue);
153 if (rc == VERR_TRAILING_SPACES)
154 rc = VINF_SUCCESS;
155 return rc;
156}
157
158
159int DhcpOption::parse1(uint16_t &aValue, const char *pcszValue)
160{
161 int rc = RTStrToUInt16Full(RTStrStripL(pcszValue), 10, &aValue);
162
163 if (rc == VERR_TRAILING_SPACES)
164 rc = VINF_SUCCESS;
165 return rc;
166}
167
168
169int DhcpOption::parse1(uint32_t &aValue, const char *pcszValue)
170{
171 int rc = RTStrToUInt32Full(RTStrStripL(pcszValue), 10, &aValue);
172
173 if (rc == VERR_TRAILING_SPACES)
174 rc = VINF_SUCCESS;
175 return rc;
176}
177
178
179int DhcpOption::parse1(RTNETADDRIPV4 &aValue, const char *pcszValue)
180{
181 return RTNetStrToIPv4Addr(pcszValue, &aValue);
182}
183
184
185int DhcpOption::parse1(DhcpIpv4AddrAndMask &aValue, const char *pcszValue)
186{
187 return RTCidrStrToIPv4(pcszValue, &aValue.Ipv4, &aValue.Mask);
188}
189
190
191template <typename a_Type>
192/*static*/ int DhcpOption::parseList(std::vector<a_Type> &aList, const char *pcszValue)
193{
194 std::vector<a_Type> vecTmp;
195
196 pcszValue = RTStrStripL(pcszValue);
197 for (;;)
198 {
199 /* Assume space, tab, comma or semicolon is used as separator (superset of RTStrStrip): */
200 const char *pszNext = strpbrk(pcszValue, " ,;:\t\n\r");
201 char szTmp[256];
202 if (pszNext)
203 {
204 size_t cchToCopy = (size_t)(pszNext - pcszValue);
205 if (cchToCopy >= sizeof(szTmp))
206 return VERR_INVALID_PARAMETER;
207 memcpy(szTmp, pcszValue, cchToCopy);
208 szTmp[cchToCopy] = '\0';
209 pcszValue = szTmp;
210
211 /* Advance pszNext past the separator character and fluff: */
212 char ch;
213 do
214 pszNext++;
215 while ((ch = *pszNext) == ' ' || ch == ':' || ch == ';' || ch == '\t' || ch == '\n' || ch == '\r');
216 if (ch == '\0')
217 pszNext = NULL;
218 }
219
220 /* Try convert it: */
221 a_Type Value;
222 int rc = DhcpOption::parse1(Value, pcszValue);
223 if (RT_SUCCESS(rc))
224 vecTmp.push_back(Value);
225 else
226 return VERR_INVALID_PARAMETER;
227
228 if (pszNext)
229 pcszValue = pszNext;
230 else
231 break;
232 }
233
234 aList.swap(vecTmp);
235 return VINF_SUCCESS;
236
237}
238
239/** ASSUME that uint8_t means hex byte strings. */
240template <>
241/*static*/ int DhcpOption::parseList(std::vector<uint8_t> &aList, const char *pcszValue)
242{
243 uint8_t abBuf[255];
244 size_t cbReturned = 0;
245 int rc = RTStrConvertHexBytesEx(RTStrStripL(pcszValue), abBuf, sizeof(abBuf), RTSTRCONVERTHEXBYTES_F_SEP_COLON,
246 NULL, &cbReturned);
247 if (RT_SUCCESS(rc))
248 {
249 if (rc != VWRN_TRAILING_CHARS)
250 {
251 for (size_t i = 0; i < cbReturned; i++)
252 aList.push_back(abBuf[i]);
253 rc = VINF_SUCCESS;
254 }
255 else
256 rc = VERR_TRAILING_CHARS;
257 }
258 return rc;
259}
260
261
262
263/*
264 * XXX: See DHCPServer::encodeOption()
265 */
266int DhcpOption::parseHex(octets_t &aRawValue, const char *pcszValue)
267{
268 uint8_t abBuf[255];
269 size_t cbReturned = 0;
270 int rc = RTStrConvertHexBytesEx(RTStrStripL(pcszValue), abBuf, sizeof(abBuf), RTSTRCONVERTHEXBYTES_F_SEP_COLON,
271 NULL, &cbReturned);
272 if (RT_SUCCESS(rc))
273 {
274 if (rc != VWRN_TRAILING_CHARS)
275 {
276 for (size_t i = 0; i < cbReturned; i++)
277 aRawValue.push_back(abBuf[i]);
278 rc = VINF_SUCCESS;
279 }
280 else
281 rc = VERR_TRAILING_CHARS;
282 }
283 return rc;
284}
285
286
287/*static*/ DhcpOption *DhcpOption::parse(uint8_t aOptCode, int aEnc, const char *pcszValue, int *prc /*= NULL*/)
288{
289 int rcIgn;
290 if (!prc)
291 prc = &rcIgn;
292
293 switch (aEnc)
294 {
295 case 0: /* DHCPOptionEncoding_Normal */
296 switch (aOptCode)
297 {
298#define HANDLE(a_OptClass) \
299 case a_OptClass::optcode: \
300 return a_OptClass::parse(pcszValue, prc)
301
302 HANDLE(OptSubnetMask); // 1
303 HANDLE(OptTimeOffset); // 2
304 HANDLE(OptRouters); // 3
305 HANDLE(OptTimeServers); // 4
306 HANDLE(OptNameServers); // 5
307 HANDLE(OptDNSes); // 6
308 HANDLE(OptLogServers); // 7
309 HANDLE(OptCookieServers); // 8
310 HANDLE(OptLPRServers); // 9
311 HANDLE(OptImpressServers); // 10
312 HANDLE(OptResourceLocationServers); // 11
313 HANDLE(OptHostName); // 12
314 HANDLE(OptBootFileSize); // 13
315 HANDLE(OptMeritDumpFile); // 14
316 HANDLE(OptDomainName); // 15
317 HANDLE(OptSwapServer); // 16
318 HANDLE(OptRootPath); // 17
319 HANDLE(OptExtensionPath); // 18
320 HANDLE(OptIPForwarding); // 19
321 HANDLE(OptNonLocalSourceRouting); // 20
322 HANDLE(OptPolicyFilter); // 21
323 HANDLE(OptMaxDgramReassemblySize); // 22
324 HANDLE(OptDefaultIPTTL); // 23
325 HANDLE(OptPathMTUAgingTimeout); // 24
326 HANDLE(OptPathMTUPlateauTable); // 25
327 HANDLE(OptInterfaceMTU); // 26
328 HANDLE(OptAllSubnetsAreLocal); // 27
329 HANDLE(OptBroadcastAddress); // 28
330 HANDLE(OptPerformMaskDiscovery); // 29
331 HANDLE(OptMaskSupplier); // 30
332 HANDLE(OptPerformRouterDiscovery); // 31
333 HANDLE(OptRouterSolicitationAddress); // 32
334 HANDLE(OptStaticRoute); // 33
335 HANDLE(OptTrailerEncapsulation); // 34
336 HANDLE(OptARPCacheTimeout); // 35
337 HANDLE(OptEthernetEncapsulation); // 36
338 HANDLE(OptTCPDefaultTTL); // 37
339 HANDLE(OptTCPKeepaliveInterval); // 38
340 HANDLE(OptTCPKeepaliveGarbage); // 39
341 HANDLE(OptNISDomain); // 40
342 HANDLE(OptNISServers); // 41
343 HANDLE(OptNTPServers); // 42
344 //HANDLE(OptVendorSpecificInfo); // 43 - Only DHCPOptionEncoding_hex
345 HANDLE(OptNetBIOSNameServers); // 44
346 HANDLE(OptNetBIOSDatagramServers); // 45
347 HANDLE(OptNetBIOSNodeType); // 46
348 //HANDLE(OptNetBIOSScope); // 47 - Only DHCPOptionEncoding_hex
349 HANDLE(OptXWindowsFontServers); // 48
350 HANDLE(OptXWindowsDisplayManager); // 49
351#ifndef IN_VBOXSVC /* Don't allow these in new configs */
352 // OptRequestedAddress (50) is client only and not configurable.
353 HANDLE(OptLeaseTime); // 51 - for historical reasons? Configuable elsewhere now.
354 // OptOptionOverload (52) is part of the protocol and not configurable.
355 // OptMessageType (53) is part of the protocol and not configurable.
356 // OptServerId (54) is the IP address of the server and configurable elsewhere.
357 // OptParameterRequest (55) is client only and not configurable.
358 // OptMessage (56) is server failure message and not configurable.
359 // OptMaxDHCPMessageSize (57) is client only (?) and not configurable.
360 HANDLE(OptRenewalTime); // 58 - for historical reasons?
361 HANDLE(OptRebindingTime); // 59 - for historical reasons?
362 // OptVendorClassId (60) is client only and not configurable.
363 // OptClientId (61) is client only and not configurable.
364#endif
365 HANDLE(OptNetWareIPDomainName); // 62
366 //HANDLE(OptNetWareIPInformation); // 63 - Only DHCPOptionEncoding_hex
367 HANDLE(OptNISPlusDomain); // 64
368 HANDLE(OptNISPlusServers); // 65
369 HANDLE(OptTFTPServerName); // 66 - perhaps we should use an alternative way to configure these.
370 HANDLE(OptBootfileName); // 67 - perhaps we should use an alternative way to configure these.
371 HANDLE(OptMobileIPHomeAgents); // 68
372 HANDLE(OptSMTPServers); // 69
373 HANDLE(OptPOP3Servers); // 70
374 HANDLE(OptNNTPServers); // 71
375 HANDLE(OptWWWServers); // 72
376 HANDLE(OptFingerServers); // 73
377 HANDLE(OptIRCServers); // 74
378 HANDLE(OptStreetTalkServers); // 75
379 HANDLE(OptSTDAServers); // 76
380 // OptUserClassId (77) is client only and not configurable.
381 //HANDLE(OptSLPDirectoryAgent); // 78 - Only DHCPOptionEncoding_hex
382 //HANDLE(OptSLPServiceScope); // 79 - Only DHCPOptionEncoding_hex
383 // OptRapidCommit (80) is not configurable.
384
385 //HANDLE(OptDomainSearch); // 119 - Only DHCPOptionEncoding_hex
386
387#undef HANDLE
388 default:
389 if (prc)
390 *prc = VERR_NOT_IMPLEMENTED;
391 return NULL;
392 }
393 break;
394
395 case 1:
396 return RawOption::parse(aOptCode, pcszValue, prc);
397
398 default:
399 if (prc)
400 *prc = VERR_WRONG_TYPE;
401 return NULL;
402 }
403}
404
405
406/**
407 * Gets the option name (simply "unknown" if not known) for logging purposes.
408 */
409/*static*/ const char *DhcpOption::name(uint8_t aOptCode)
410{
411 switch (aOptCode)
412 {
413#define HANDLE(a_OptClass) \
414 case a_OptClass::optcode: \
415 return &#a_OptClass[3]
416
417 HANDLE(OptSubnetMask); // 1
418 HANDLE(OptTimeOffset); // 2
419 HANDLE(OptRouters); // 3
420 HANDLE(OptTimeServers); // 4
421 HANDLE(OptNameServers); // 5
422 HANDLE(OptDNSes); // 6
423 HANDLE(OptLogServers); // 7
424 HANDLE(OptCookieServers); // 8
425 HANDLE(OptLPRServers); // 9
426 HANDLE(OptImpressServers); // 10
427 HANDLE(OptResourceLocationServers); // 11
428 HANDLE(OptHostName); // 12
429 HANDLE(OptBootFileSize); // 13
430 HANDLE(OptMeritDumpFile); // 14
431 HANDLE(OptDomainName); // 15
432 HANDLE(OptSwapServer); // 16
433 HANDLE(OptRootPath); // 17
434 HANDLE(OptExtensionPath); // 18
435 HANDLE(OptIPForwarding); // 19
436 HANDLE(OptNonLocalSourceRouting); // 20
437 HANDLE(OptPolicyFilter); // 21
438 HANDLE(OptMaxDgramReassemblySize); // 22
439 HANDLE(OptDefaultIPTTL); // 23
440 HANDLE(OptPathMTUAgingTimeout); // 24
441 HANDLE(OptPathMTUPlateauTable); // 25
442 HANDLE(OptInterfaceMTU); // 26
443 HANDLE(OptAllSubnetsAreLocal); // 27
444 HANDLE(OptBroadcastAddress); // 28
445 HANDLE(OptPerformMaskDiscovery); // 29
446 HANDLE(OptMaskSupplier); // 30
447 HANDLE(OptPerformRouterDiscovery); // 31
448 HANDLE(OptRouterSolicitationAddress); // 32
449 HANDLE(OptStaticRoute); // 33
450 HANDLE(OptTrailerEncapsulation); // 34
451 HANDLE(OptARPCacheTimeout); // 35
452 HANDLE(OptEthernetEncapsulation); // 36
453 HANDLE(OptTCPDefaultTTL); // 37
454 HANDLE(OptTCPKeepaliveInterval); // 38
455 HANDLE(OptTCPKeepaliveGarbage); // 39
456 HANDLE(OptNISDomain); // 40
457 HANDLE(OptNISServers); // 41
458 HANDLE(OptNTPServers); // 42
459 HANDLE(OptVendorSpecificInfo); // 43
460 HANDLE(OptNetBIOSNameServers); // 44
461 HANDLE(OptNetBIOSDatagramServers); // 45
462 HANDLE(OptNetBIOSNodeType); // 46
463 HANDLE(OptNetBIOSScope); // 47
464 HANDLE(OptXWindowsFontServers); // 48
465 HANDLE(OptXWindowsDisplayManager); // 49
466 HANDLE(OptRequestedAddress); // 50
467 HANDLE(OptLeaseTime); // 51
468 //HANDLE(OptOptionOverload); // 52
469 HANDLE(OptMessageType); // 53
470 HANDLE(OptServerId); // 54
471 HANDLE(OptParameterRequest); // 55
472 HANDLE(OptMessage); // 56
473 HANDLE(OptMaxDHCPMessageSize); // 57
474 HANDLE(OptRenewalTime); // 58
475 HANDLE(OptRebindingTime); // 59
476 HANDLE(OptVendorClassId); // 60
477 HANDLE(OptClientId); // 61
478 HANDLE(OptNetWareIPDomainName); // 62
479 HANDLE(OptNetWareIPInformation); // 63
480 HANDLE(OptNISPlusDomain); // 64
481 HANDLE(OptNISPlusServers); // 65
482 HANDLE(OptTFTPServerName); // 66
483 HANDLE(OptBootfileName); // 67
484 HANDLE(OptMobileIPHomeAgents); // 68
485 HANDLE(OptSMTPServers); // 69
486 HANDLE(OptPOP3Servers); // 70
487 HANDLE(OptNNTPServers); // 71
488 HANDLE(OptWWWServers); // 72
489 HANDLE(OptFingerServers); // 73
490 HANDLE(OptIRCServers); // 74
491 HANDLE(OptStreetTalkServers); // 75
492 HANDLE(OptSTDAServers); // 76
493 HANDLE(OptUserClassId); // 77
494 HANDLE(OptSLPDirectoryAgent); // 78 - Only DHCPOptionEncoding_hex
495 HANDLE(OptSLPServiceScope); // 79 - Only DHCPOptionEncoding_hex
496 HANDLE(OptRapidCommit); // 80
497
498 HANDLE(OptDomainSearch); // 119 - Only DHCPOptionEncoding_hex
499
500#undef HANDLE
501 default:
502 return "unknown";
503 }
504}
505
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