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