1 | /* $Id: Config.h 106061 2024-09-16 14:03:52Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * DHCP server - server configuration
|
---|
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 | #ifndef VBOX_INCLUDED_SRC_Dhcpd_Config_h
|
---|
29 | #define VBOX_INCLUDED_SRC_Dhcpd_Config_h
|
---|
30 | #ifndef RT_WITHOUT_PRAGMA_ONCE
|
---|
31 | # pragma once
|
---|
32 | #endif
|
---|
33 |
|
---|
34 | #include "DhcpdInternal.h"
|
---|
35 | #include <iprt/types.h>
|
---|
36 | #include <iprt/net.h>
|
---|
37 | #include <iprt/cpp/xml.h>
|
---|
38 | #include <iprt/cpp/ministring.h>
|
---|
39 |
|
---|
40 | #include <VBox/intnet.h>
|
---|
41 |
|
---|
42 | #include "DhcpOptions.h"
|
---|
43 | #include "ClientId.h"
|
---|
44 |
|
---|
45 |
|
---|
46 | class Config;
|
---|
47 |
|
---|
48 | /**
|
---|
49 | * Base configuration
|
---|
50 | *
|
---|
51 | * @author bird (2019-07-15)
|
---|
52 | */
|
---|
53 | class ConfigLevelBase
|
---|
54 | {
|
---|
55 | private:
|
---|
56 | /** DHCP options. */
|
---|
57 | optmap_t m_Options;
|
---|
58 | protected:
|
---|
59 | /** Minimum lease time, zero means try next level up. */
|
---|
60 | uint32_t m_secMinLeaseTime;
|
---|
61 | /** Default lease time, zero means try next level up. */
|
---|
62 | uint32_t m_secDefaultLeaseTime;
|
---|
63 | /** Maximum lease time, zero means try next level up. */
|
---|
64 | uint32_t m_secMaxLeaseTime;
|
---|
65 |
|
---|
66 | /** Options forced unsolicited upon the client. */
|
---|
67 | octets_t m_vecForcedOptions;
|
---|
68 | /** Options (typcially from higher up) that should be hidden from the client. */
|
---|
69 | octets_t m_vecSuppressedOptions;
|
---|
70 |
|
---|
71 | public:
|
---|
72 | ConfigLevelBase()
|
---|
73 | : m_Options()
|
---|
74 | , m_secMinLeaseTime(0)
|
---|
75 | , m_secDefaultLeaseTime(0)
|
---|
76 | , m_secMaxLeaseTime(0)
|
---|
77 | , m_vecForcedOptions()
|
---|
78 | , m_vecSuppressedOptions()
|
---|
79 | { }
|
---|
80 |
|
---|
81 | virtual ~ConfigLevelBase()
|
---|
82 | { }
|
---|
83 |
|
---|
84 | virtual void initFromXml(xml::ElementNode const *pElmConfig, bool fStrict, Config const *pConfig);
|
---|
85 | virtual const char *getType() const RT_NOEXCEPT = 0;
|
---|
86 | virtual const char *getName() const RT_NOEXCEPT = 0;
|
---|
87 |
|
---|
88 | /**
|
---|
89 | * Tries to find DHCP option @a bOpt, returning an success indicator and
|
---|
90 | * iterator to the result.
|
---|
91 | */
|
---|
92 | bool findOption(uint8_t bOpt, optmap_t::const_iterator &a_rItRet) const RT_NOEXCEPT
|
---|
93 | {
|
---|
94 | a_rItRet = m_Options.find(bOpt);
|
---|
95 | return a_rItRet != m_Options.end();
|
---|
96 | }
|
---|
97 |
|
---|
98 | /** Checks if @a bOpt is suppressed or not. */
|
---|
99 | bool isOptionSuppressed(uint8_t bOpt) const RT_NOEXCEPT
|
---|
100 | {
|
---|
101 | return m_vecSuppressedOptions.size() > 0
|
---|
102 | && memchr(&m_vecSuppressedOptions.front(), bOpt, m_vecSuppressedOptions.size()) != NULL;
|
---|
103 | }
|
---|
104 |
|
---|
105 | /** @name Accessors
|
---|
106 | * @{ */
|
---|
107 | uint32_t getMinLeaseTime() const RT_NOEXCEPT { return m_secMinLeaseTime; }
|
---|
108 | uint32_t getDefaultLeaseTime() const RT_NOEXCEPT { return m_secDefaultLeaseTime; }
|
---|
109 | uint32_t getMaxLeaseTime() const RT_NOEXCEPT { return m_secMaxLeaseTime; }
|
---|
110 | octets_t const &getForcedOptions() const RT_NOEXCEPT { return m_vecForcedOptions; }
|
---|
111 | octets_t const &getSuppressedOptions() const RT_NOEXCEPT { return m_vecSuppressedOptions; }
|
---|
112 | optmap_t const &getOptions() const RT_NOEXCEPT { return m_Options; }
|
---|
113 | /** @} */
|
---|
114 |
|
---|
115 | protected:
|
---|
116 | void i_parseOption(const xml::ElementNode *pElmOption);
|
---|
117 | void i_parseForcedOrSuppressedOption(const xml::ElementNode *pElmOption, bool fForced);
|
---|
118 | virtual void i_parseChild(const xml::ElementNode *pElmChild, bool fStrict, Config const *pConfig);
|
---|
119 | };
|
---|
120 |
|
---|
121 |
|
---|
122 | /**
|
---|
123 | * Global config
|
---|
124 | */
|
---|
125 | class GlobalConfig : public ConfigLevelBase
|
---|
126 | {
|
---|
127 | public:
|
---|
128 | GlobalConfig()
|
---|
129 | : ConfigLevelBase()
|
---|
130 | { }
|
---|
131 | void initFromXml(xml::ElementNode const *pElmOptions, bool fStrict, Config const *pConfig) RT_OVERRIDE;
|
---|
132 | const char *getType() const RT_NOEXCEPT RT_OVERRIDE { return "global"; }
|
---|
133 | const char *getName() const RT_NOEXCEPT RT_OVERRIDE { return "GlobalConfig"; }
|
---|
134 | };
|
---|
135 |
|
---|
136 |
|
---|
137 | /**
|
---|
138 | * Group membership condition.
|
---|
139 | */
|
---|
140 | class GroupCondition
|
---|
141 | {
|
---|
142 | protected:
|
---|
143 | /** The value. */
|
---|
144 | RTCString m_strValue;
|
---|
145 | /** Inclusive (true) or exclusive (false), latter takes precedency. */
|
---|
146 | bool m_fInclusive;
|
---|
147 |
|
---|
148 | public:
|
---|
149 | virtual ~GroupCondition()
|
---|
150 | {}
|
---|
151 |
|
---|
152 | virtual int initCondition(const char *a_pszValue, bool a_fInclusive);
|
---|
153 | virtual bool match(const ClientId &a_ridClient, const OptVendorClassId &a_ridVendorClass,
|
---|
154 | const OptUserClassId &a_ridUserClass) const RT_NOEXCEPT = 0;
|
---|
155 |
|
---|
156 | /** @name accessors
|
---|
157 | * @{ */
|
---|
158 | RTCString const &getValue() const RT_NOEXCEPT { return m_strValue; }
|
---|
159 | bool getInclusive() const RT_NOEXCEPT { return m_fInclusive; }
|
---|
160 | /** @} */
|
---|
161 |
|
---|
162 | protected:
|
---|
163 | bool matchClassId(bool a_fPresent, std::vector<uint8_t> const &a_rBytes, bool fWildcard = false) const RT_NOEXCEPT;
|
---|
164 | };
|
---|
165 |
|
---|
166 | /** MAC condition. */
|
---|
167 | class GroupConditionMAC : public GroupCondition
|
---|
168 | {
|
---|
169 | private:
|
---|
170 | RTMAC m_MACAddress;
|
---|
171 | public:
|
---|
172 | int initCondition(const char *a_pszValue, bool a_fInclusive) RT_OVERRIDE;
|
---|
173 | bool match(const ClientId &a_ridClient, const OptVendorClassId &a_ridVendorClass,
|
---|
174 | const OptUserClassId &a_ridUserClass) const RT_NOEXCEPT RT_OVERRIDE;
|
---|
175 | };
|
---|
176 |
|
---|
177 | /** MAC wildcard condition. */
|
---|
178 | class GroupConditionMACWildcard : public GroupCondition
|
---|
179 | {
|
---|
180 | public:
|
---|
181 | bool match(const ClientId &a_ridClient, const OptVendorClassId &a_ridVendorClass,
|
---|
182 | const OptUserClassId &a_ridUserClass) const RT_NOEXCEPT RT_OVERRIDE;
|
---|
183 | };
|
---|
184 |
|
---|
185 | /** Vendor class ID condition. */
|
---|
186 | class GroupConditionVendorClassID : public GroupCondition
|
---|
187 | {
|
---|
188 | public:
|
---|
189 | bool match(const ClientId &a_ridClient, const OptVendorClassId &a_ridVendorClass,
|
---|
190 | const OptUserClassId &a_ridUserClass) const RT_NOEXCEPT RT_OVERRIDE;
|
---|
191 | };
|
---|
192 |
|
---|
193 | /** Vendor class ID wildcard condition. */
|
---|
194 | class GroupConditionVendorClassIDWildcard : public GroupCondition
|
---|
195 | {
|
---|
196 | public:
|
---|
197 | bool match(const ClientId &a_ridClient, const OptVendorClassId &a_ridVendorClass,
|
---|
198 | const OptUserClassId &a_ridUserClass) const RT_NOEXCEPT RT_OVERRIDE;
|
---|
199 | };
|
---|
200 |
|
---|
201 | /** User class ID condition. */
|
---|
202 | class GroupConditionUserClassID : public GroupCondition
|
---|
203 | {
|
---|
204 | public:
|
---|
205 | bool match(const ClientId &a_ridClient, const OptVendorClassId &a_ridVendorClass,
|
---|
206 | const OptUserClassId &a_ridUserClass) const RT_NOEXCEPT RT_OVERRIDE;
|
---|
207 | };
|
---|
208 |
|
---|
209 | /** User class ID wildcard condition. */
|
---|
210 | class GroupConditionUserClassIDWildcard : public GroupCondition
|
---|
211 | {
|
---|
212 | public:
|
---|
213 | bool match(const ClientId &a_ridClient, const OptVendorClassId &a_ridVendorClass,
|
---|
214 | const OptUserClassId &a_ridUserClass) const RT_NOEXCEPT RT_OVERRIDE;
|
---|
215 | };
|
---|
216 |
|
---|
217 |
|
---|
218 | /**
|
---|
219 | * Group config
|
---|
220 | */
|
---|
221 | class GroupConfig : public ConfigLevelBase
|
---|
222 | {
|
---|
223 | private:
|
---|
224 | typedef std::vector<GroupCondition *> GroupConditionVec;
|
---|
225 |
|
---|
226 | /** The group name. */
|
---|
227 | RTCString m_strName;
|
---|
228 | /** Vector containing the inclusive membership conditions (must match one). */
|
---|
229 | GroupConditionVec m_Inclusive;
|
---|
230 | /** Vector containing the exclusive membership conditions (must match none). */
|
---|
231 | GroupConditionVec m_Exclusive;
|
---|
232 |
|
---|
233 | public:
|
---|
234 | GroupConfig()
|
---|
235 | : ConfigLevelBase()
|
---|
236 | {
|
---|
237 | }
|
---|
238 |
|
---|
239 | void initFromXml(xml::ElementNode const *pElmGroup, bool fStrict, Config const *pConfig) RT_OVERRIDE;
|
---|
240 | bool match(const ClientId &a_ridClient, const OptVendorClassId &a_ridVendorClass, const OptUserClassId &a_ridUserClass) const;
|
---|
241 |
|
---|
242 | /** @name Accessors
|
---|
243 | * @{ */
|
---|
244 | const char *getType() const RT_NOEXCEPT RT_OVERRIDE { return "group"; }
|
---|
245 | const char *getName() const RT_NOEXCEPT RT_OVERRIDE { return m_strName.c_str(); }
|
---|
246 | RTCString const &getGroupName() const RT_NOEXCEPT { return m_strName; }
|
---|
247 | /** @} */
|
---|
248 |
|
---|
249 | protected:
|
---|
250 | void i_parseChild(const xml::ElementNode *pElmChild, bool fStrict, Config const *pConfig) RT_OVERRIDE;
|
---|
251 | /** Used to name unnamed groups. */
|
---|
252 | static uint32_t s_uGroupNo;
|
---|
253 | };
|
---|
254 |
|
---|
255 |
|
---|
256 | /**
|
---|
257 | * Host (MAC address) specific configuration.
|
---|
258 | */
|
---|
259 | class HostConfig : public ConfigLevelBase
|
---|
260 | {
|
---|
261 | protected:
|
---|
262 | /** The MAC address. */
|
---|
263 | RTMAC m_MACAddress;
|
---|
264 | /** Name annotating the entry. */
|
---|
265 | RTCString m_strName;
|
---|
266 | /** Fixed address assignment when m_fHaveFixedAddress is true. */
|
---|
267 | RTNETADDRIPV4 m_FixedAddress;
|
---|
268 | /** Set if we have a fixed address asignment. */
|
---|
269 | bool m_fHaveFixedAddress;
|
---|
270 |
|
---|
271 | public:
|
---|
272 | HostConfig()
|
---|
273 | : ConfigLevelBase()
|
---|
274 | , m_fHaveFixedAddress(false)
|
---|
275 | {
|
---|
276 | RT_ZERO(m_MACAddress);
|
---|
277 | RT_ZERO(m_FixedAddress);
|
---|
278 | }
|
---|
279 |
|
---|
280 | void initFromXml(xml::ElementNode const *pElmConfig, bool fStrict, Config const *pConfig) RT_OVERRIDE;
|
---|
281 | const char *getType() const RT_NOEXCEPT RT_OVERRIDE { return "host"; }
|
---|
282 | const char *getName() const RT_NOEXCEPT RT_OVERRIDE { return m_strName.c_str(); }
|
---|
283 |
|
---|
284 | /** @name Accessors
|
---|
285 | * @{ */
|
---|
286 | RTMAC const &getMACAddress() const RT_NOEXCEPT { return m_MACAddress; }
|
---|
287 | bool haveFixedAddress() const RT_NOEXCEPT { return m_fHaveFixedAddress; }
|
---|
288 | RTNETADDRIPV4 const & getFixedAddress() const RT_NOEXCEPT { return m_FixedAddress; }
|
---|
289 | /** @} */
|
---|
290 | };
|
---|
291 |
|
---|
292 |
|
---|
293 | /**
|
---|
294 | * DHCP server configuration.
|
---|
295 | */
|
---|
296 | class Config
|
---|
297 | {
|
---|
298 | /** Group configuration map. */
|
---|
299 | typedef std::map<RTCString, GroupConfig const * > GroupConfigMap;
|
---|
300 | /** Host configuration map. */
|
---|
301 | typedef std::map<RTMAC, HostConfig const * > HostConfigMap;
|
---|
302 |
|
---|
303 |
|
---|
304 | RTCString m_strHome; /**< path of ~/.VirtualBox or equivalent, */
|
---|
305 |
|
---|
306 | RTCString m_strNetwork; /**< The name of the internal network the DHCP server is connected to. */
|
---|
307 | RTCString m_strLeasesFilename;/**< The lease DB filename. */
|
---|
308 |
|
---|
309 | RTCString m_strTrunk; /**< The trunk name of the internal network. */
|
---|
310 | INTNETTRUNKTYPE m_enmTrunkType; /**< The trunk type of the internal network. */
|
---|
311 |
|
---|
312 | RTMAC m_MacAddress; /**< The MAC address for the DHCP server. */
|
---|
313 |
|
---|
314 | RTNETADDRIPV4 m_IPv4Address; /**< The IPv4 address of the DHCP server. */
|
---|
315 | RTNETADDRIPV4 m_IPv4Netmask; /**< The IPv4 netmask for the DHCP server. */
|
---|
316 |
|
---|
317 | RTNETADDRIPV4 m_IPv4PoolFirst; /**< The first IPv4 address in the pool. */
|
---|
318 | RTNETADDRIPV4 m_IPv4PoolLast; /**< The last IPV4 address in the pool (inclusive like all other 'last' variables). */
|
---|
319 |
|
---|
320 |
|
---|
321 | /** The global configuration. */
|
---|
322 | GlobalConfig m_GlobalConfig;
|
---|
323 | /** The group configurations, indexed by group name. */
|
---|
324 | GroupConfigMap m_GroupConfigs;
|
---|
325 | /** The host configurations, indexed by MAC address. */
|
---|
326 | HostConfigMap m_HostConfigs;
|
---|
327 |
|
---|
328 | /** Set if we've initialized the log already (via command line). */
|
---|
329 | static bool g_fInitializedLog;
|
---|
330 |
|
---|
331 | private:
|
---|
332 | Config();
|
---|
333 |
|
---|
334 | int i_init() RT_NOEXCEPT;
|
---|
335 | int i_homeInit() RT_NOEXCEPT;
|
---|
336 | static Config *i_createInstanceAndCallInit() RT_NOEXCEPT;
|
---|
337 | int i_logInit() RT_NOEXCEPT;
|
---|
338 | static int i_logInitWithFilename(const char *pszFilename) RT_NOEXCEPT;
|
---|
339 | int i_complete() RT_NOEXCEPT;
|
---|
340 |
|
---|
341 | public:
|
---|
342 | /** @name Factory methods
|
---|
343 | * @{ */
|
---|
344 | static Config *hardcoded() RT_NOEXCEPT; /**< For testing. */
|
---|
345 | static Config *create(int argc, char **argv) RT_NOEXCEPT; /**< --config */
|
---|
346 | static Config *compat(int argc, char **argv);
|
---|
347 | /** @} */
|
---|
348 |
|
---|
349 | /** @name Accessors
|
---|
350 | * @{ */
|
---|
351 | const RTCString &getHome() const RT_NOEXCEPT { return m_strHome; }
|
---|
352 |
|
---|
353 | const RTCString &getNetwork() const RT_NOEXCEPT { return m_strNetwork; }
|
---|
354 | const RTCString &getLeasesFilename() const RT_NOEXCEPT { return m_strLeasesFilename; }
|
---|
355 |
|
---|
356 | const RTCString &getTrunk() const RT_NOEXCEPT { return m_strTrunk; }
|
---|
357 | INTNETTRUNKTYPE getTrunkType() const RT_NOEXCEPT { return m_enmTrunkType; }
|
---|
358 |
|
---|
359 | const RTMAC &getMacAddress() const RT_NOEXCEPT { return m_MacAddress; }
|
---|
360 |
|
---|
361 | RTNETADDRIPV4 getIPv4Address() const RT_NOEXCEPT { return m_IPv4Address; }
|
---|
362 | RTNETADDRIPV4 getIPv4Netmask() const RT_NOEXCEPT { return m_IPv4Netmask; }
|
---|
363 | RTNETADDRIPV4 getIPv4PoolFirst() const RT_NOEXCEPT { return m_IPv4PoolFirst; }
|
---|
364 | RTNETADDRIPV4 getIPv4PoolLast() const RT_NOEXCEPT { return m_IPv4PoolLast; }
|
---|
365 | /** @} */
|
---|
366 |
|
---|
367 | /** Gets the network (IP masked by network mask). */
|
---|
368 | RTNETADDRIPV4 getIPv4Network() const RT_NOEXCEPT
|
---|
369 | {
|
---|
370 | RTNETADDRIPV4 Network;
|
---|
371 | Network.u = m_IPv4Netmask.u & m_IPv4Address.u;
|
---|
372 | return Network;
|
---|
373 | }
|
---|
374 | /** Checks if the given IPv4 address is in the DHCP server network. */
|
---|
375 | bool isInIPv4Network(RTNETADDRIPV4 a_rAddress) const RT_NOEXCEPT
|
---|
376 | {
|
---|
377 | return (a_rAddress.u & getIPv4Netmask().u) == getIPv4Network().u;
|
---|
378 | }
|
---|
379 |
|
---|
380 | /** Host configuration vector. */
|
---|
381 | typedef std::vector<HostConfig const *> HostConfigVec;
|
---|
382 | int getFixedAddressConfigs(HostConfigVec &a_rRetConfigs) const;
|
---|
383 |
|
---|
384 | /** Configuration vector. */
|
---|
385 | typedef std::vector<ConfigLevelBase const *> ConfigVec;
|
---|
386 | ConfigVec &getConfigsForClient(ConfigVec &a_rRetConfigs, const ClientId &a_ridClient,
|
---|
387 | const OptVendorClassId &a_ridVendorClass,
|
---|
388 | const OptUserClassId &a_ridUserClass) const;
|
---|
389 | optmap_t &getOptionsForClient(optmap_t &a_rRetOpts, const OptParameterRequest &a_rReqOpts,
|
---|
390 | ConfigVec &a_rConfigs) const;
|
---|
391 |
|
---|
392 | private:
|
---|
393 | /** @name Configuration file reading and parsing
|
---|
394 | * @{ */
|
---|
395 | static Config *i_read(const char *pszFilename, bool fStrict) RT_NOEXCEPT;
|
---|
396 | void i_parseConfig(const xml::ElementNode *pElmRoot, bool fStrict);
|
---|
397 | void i_parseServer(const xml::ElementNode *pElmServer, bool fStrict);
|
---|
398 | /** @} */
|
---|
399 | };
|
---|
400 |
|
---|
401 | #endif /* !VBOX_INCLUDED_SRC_Dhcpd_Config_h */
|
---|