VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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