VirtualBox

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

最後變更 在這個檔案從79761是 79568,由 vboxsync 提交於 6 年 前

Dhcpd: Went over the DhcpMessage a little as well as revisiting the lease reading code in the database. Logging is LogRel() or similar, no cout, RTPrintf or similar. The debug & release loggers can both output to stderr/out/whatever as needed. bugref:9288

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 12.3 KB
 
1/* $Id: DhcpMessage.cpp 79568 2019-07-06 23:42:51Z vboxsync $ */
2/** @file
3 * DHCP Message and its de/serialization.
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.alldomusa.eu.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 "DhcpMessage.h"
24#include "DhcpOptions.h"
25
26#include <iprt/string.h>
27
28
29
30DhcpMessage::DhcpMessage()
31 : m_xid(0)
32 , m_flags(0)
33 , m_ciaddr()
34 , m_yiaddr()
35 , m_siaddr()
36 , m_giaddr()
37#if 0 /* not currently unused */
38 , m_sname()
39 , m_file()
40#endif
41 , m_optMessageType()
42{
43}
44
45
46/*********************************************************************************************************************************
47* DhcpClientMessage Implementation *
48*********************************************************************************************************************************/
49
50/* static */
51DhcpClientMessage *DhcpClientMessage::parse(bool broadcasted, const void *buf, size_t buflen)
52{
53 /*
54 * Validate the request.
55 */
56 if (buflen < RT_OFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts))
57 DHCP_LOG2_RET_NULL(("DhcpClientMessage::parse: %zu bytes datagram is too short\n", buflen));
58
59 PCRTNETBOOTP bp = (PCRTNETBOOTP)buf;
60
61 if (bp->bp_op != RTNETBOOTP_OP_REQUEST)
62 DHCP_LOG2_RET_NULL(("DhcpClientMessage::parse: bad opcode: %d\n", bp->bp_op));
63
64 if (bp->bp_htype != RTNET_ARP_ETHER)
65 DHCP_LOG2_RET_NULL(("DhcpClientMessage::parse: unsupported htype %d\n", bp->bp_htype));
66
67 if (bp->bp_hlen != sizeof(RTMAC))
68 DHCP_LOG2_RET_NULL(("DhcpClientMessage::parse: unexpected hlen %d\n", bp->bp_hlen));
69
70 if ( (bp->bp_chaddr.Mac.au8[0] & 0x01) != 0
71 && (bp->bp_flags & RTNET_DHCP_FLAG_BROADCAST) == 0)
72 LogRel2(("DhcpClientMessage::parse: multicast chaddr %RTmac without broadcast flag\n", &bp->bp_chaddr.Mac));
73
74 /* we don't want to deal with forwarding */
75 if (bp->bp_giaddr.u != 0)
76 DHCP_LOG2_RET_NULL(("DhcpClientMessage::parse: giaddr %RTnaipv4\n", bp->bp_giaddr.u));
77
78 if (bp->bp_hops != 0)
79 DHCP_LOG2_RET_NULL(("DhcpClientMessage::parse: non-zero hops %d\n", bp->bp_hops));
80
81 if (bp->bp_vend.Dhcp.dhcp_cookie != RT_H2N_U32_C(RTNET_DHCP_COOKIE))
82 DHCP_LOG2_RET_NULL(("DhcpClientMessage::parse: bad cookie %#RX32\n", bp->bp_vend.Dhcp.dhcp_cookie));
83
84 /*
85 * Convert it into a DhcpClientMessage instance.
86 */
87 std::unique_ptr<DhcpClientMessage> msg(new DhcpClientMessage());
88
89 msg->m_broadcasted = broadcasted;
90 msg->m_xid = bp->bp_xid;
91 msg->m_flags = bp->bp_flags;
92 msg->m_mac = bp->bp_chaddr.Mac;
93 msg->m_ciaddr = bp->bp_ciaddr;
94 msg->m_yiaddr = bp->bp_yiaddr;
95 msg->m_siaddr = bp->bp_siaddr;
96 msg->m_giaddr = bp->bp_giaddr;
97
98 int fOptOverload = msg->i_parseOptions(&bp->bp_vend.Dhcp.dhcp_opts[0],
99 buflen - RT_OFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts));
100 if (fOptOverload < 0)
101 return NULL;
102
103 /* "The 'file' field MUST be interpreted next ..." */
104 if (fOptOverload & RTNET_DHCP_OPTION_OVERLOAD_FILE)
105 {
106 int status = msg->i_parseOptions(bp->bp_file, sizeof(bp->bp_file));
107 if (status != 0)
108 return NULL;
109 }
110#if 0 /* not currently unused */
111 else if (bp->bp_file[0] != '\0')
112 {
113 /* must be zero terminated, ignore if not */
114 const char *pszFile = (const char *)bp->bp_file;
115 size_t len = RTStrNLen(pszFile, sizeof(bp->bp_file));
116 if (len < sizeof(bp->bp_file))
117 msg->m_file.assign(pszFile, len);
118 }
119#endif
120
121 /* "... followed by the 'sname' field." */
122 if (fOptOverload & RTNET_DHCP_OPTION_OVERLOAD_SNAME)
123 {
124 int status = msg->i_parseOptions(bp->bp_sname, sizeof(bp->bp_sname));
125 if (status != 0) /* NB: this includes "nested" Option Overload */
126 return NULL;
127 }
128#if 0 /* not currently unused */
129 else if (bp->bp_sname[0] != '\0')
130 {
131 /* must be zero terminated, ignore if not */
132 const char *pszSName = (const char *)bp->bp_sname;
133 size_t len = RTStrNLen(pszSName, sizeof(bp->bp_sname));
134 if (len < sizeof(bp->bp_sname))
135 msg->m_sname.assign(pszSName, len);
136 }
137#endif
138
139 msg->m_optMessageType = OptMessageType(*msg);
140 if (!msg->m_optMessageType.present())
141 return NULL;
142
143 msg->m_id = ClientId(msg->m_mac, OptClientId(*msg));
144
145 return msg.release();
146}
147
148
149int DhcpClientMessage::i_parseOptions(const uint8_t *pbBuf, size_t cbBuf) RT_NOEXCEPT
150{
151 int fOptOverload = 0;
152 while (cbBuf > 0)
153 {
154 uint8_t const bOpt = *pbBuf++;
155 --cbBuf;
156
157 if (bOpt == RTNET_DHCP_OPT_PAD)
158 continue;
159
160 if (bOpt == RTNET_DHCP_OPT_END)
161 break;
162
163 if (cbBuf == 0)
164 DHCP_LOG_RET(-1, ("option %d has no length field\n", bOpt));
165
166 uint8_t const cbOpt = *pbBuf++;
167 --cbBuf;
168
169 if (cbOpt > cbBuf)
170 DHCP_LOG_RET(-1, ("option %d truncated (length %d, but only %zu bytes left)\n", bOpt, cbOpt, cbBuf));
171
172#if 0
173 rawopts_t::const_iterator it(m_optmap.find(bOpt));
174 if (it != m_optmap.cend())
175 return -1;
176#endif
177 if (bOpt == RTNET_DHCP_OPT_OPTION_OVERLOAD)
178 {
179 if (cbOpt != 1)
180 DHCP_LOG_RET(-1, ("Overload Option (option %d) has invalid length %d\n", bOpt, cbOpt));
181
182 fOptOverload = *pbBuf;
183
184 if ((fOptOverload & ~RTNET_DHCP_OPTION_OVERLOAD_MASK) != 0)
185 DHCP_LOG_RET(-1, ("Overload Option (option %d) has invalid value 0x%x\n", bOpt, fOptOverload));
186 }
187 else
188 m_rawopts.insert(std::make_pair(bOpt, octets_t(pbBuf, pbBuf + cbOpt)));
189
190 pbBuf += cbOpt;
191 cbBuf -= cbOpt;
192 }
193
194 return fOptOverload;
195}
196
197
198void DhcpClientMessage::dump() const RT_NOEXCEPT
199{
200 switch (m_optMessageType.value())
201 {
202 case RTNET_DHCP_MT_DISCOVER:
203 LogRel(("DISCOVER"));
204 break;
205
206 case RTNET_DHCP_MT_REQUEST:
207 LogRel(("REQUEST"));
208 break;
209
210 case RTNET_DHCP_MT_INFORM:
211 LogRel(("INFORM"));
212 break;
213
214 case RTNET_DHCP_MT_DECLINE:
215 LogRel(("DECLINE"));
216 break;
217
218 case RTNET_DHCP_MT_RELEASE:
219 LogRel(("RELEASE"));
220 break;
221
222 default:
223 LogRel(("<Unknown Mesage Type %d>", m_optMessageType.value()));
224 break;
225 }
226
227 if (OptRapidCommit(*this).present())
228 LogRel((" (rapid commit)"));
229
230 try
231 {
232 const OptServerId sid(*this);
233 if (sid.present())
234 LogRel((" for server %RTnaipv4", sid.value().u));
235
236 LogRel((" xid 0x%08x", m_xid));
237 LogRel((" chaddr %RTmac\n", &m_mac));
238
239 const OptClientId cid(*this);
240 if (cid.present()) {
241 if (cid.value().size() > 0)
242 LogRel((" client id: %.*Rhxs\n", cid.value().size(), &cid.value().front()));
243 else
244 LogRel((" client id: <empty>\n"));
245 }
246
247 LogRel((" ciaddr %RTnaipv4", m_ciaddr.u));
248 if (m_yiaddr.u != 0)
249 LogRel((" yiaddr %RTnaipv4", m_yiaddr.u));
250 if (m_siaddr.u != 0)
251 LogRel((" siaddr %RTnaipv4", m_siaddr.u));
252 if (m_giaddr.u != 0)
253 LogRel((" giaddr %RTnaipv4", m_giaddr.u));
254 LogRel(("%s\n", broadcast() ? "broadcast" : ""));
255
256
257 const OptRequestedAddress reqAddr(*this);
258 if (reqAddr.present())
259 LogRel((" requested address %RTnaipv4", reqAddr.value().u));
260 const OptLeaseTime reqLeaseTime(*this);
261 if (reqLeaseTime.present())
262 LogRel((" requested lease time %d", reqAddr.value()));
263 if (reqAddr.present() || reqLeaseTime.present())
264 LogRel(("\n"));
265
266 const OptParameterRequest params(*this);
267 if (params.present())
268 {
269 LogRel((" params {"));
270 typedef OptParameterRequest::value_t::const_iterator it_t;
271 for (it_t it = params.value().begin(); it != params.value().end(); ++it)
272 LogRel((" %d", *it));
273 LogRel((" }\n"));
274 }
275 }
276 catch (std::bad_alloc &)
277 {
278 LogRel(("bad_alloc during dumping\n"));
279 }
280
281 bool fHeader = true;
282 for (rawopts_t::const_iterator it = m_rawopts.begin(); it != m_rawopts.end(); ++it)
283 {
284 const uint8_t optcode = (*it).first;
285 switch (optcode)
286 {
287 case OptMessageType::optcode: /* FALLTHROUGH */
288 case OptClientId::optcode: /* FALLTHROUGH */
289 case OptRequestedAddress::optcode: /* FALLTHROUGH */
290 case OptLeaseTime::optcode: /* FALLTHROUGH */
291 case OptParameterRequest::optcode: /* FALLTHROUGH */
292 case OptRapidCommit::optcode:
293 break;
294
295 default:
296 if (fHeader)
297 {
298 LogRel((" other options:"));
299 fHeader = false;
300 }
301 LogRel((" %d", optcode));
302 break;
303 }
304 }
305 if (!fHeader)
306 LogRel(("\n"));
307}
308
309
310
311/*********************************************************************************************************************************
312* DhcpServerMessage Implementation *
313*********************************************************************************************************************************/
314
315DhcpServerMessage::DhcpServerMessage(const DhcpClientMessage &req, uint8_t messageTypeParam, RTNETADDRIPV4 serverAddr)
316 : DhcpMessage()
317 , m_optServerId(serverAddr)
318{
319 m_dst.u = 0xffffffff; /* broadcast */
320
321 m_optMessageType = OptMessageType(messageTypeParam);
322
323 /* copy values from the request (cf. RFC2131 Table 3) */
324 m_xid = req.xid();
325 m_flags = req.flags();
326 m_giaddr = req.giaddr();
327 m_mac = req.mac();
328
329 if (req.messageType() == RTNET_DHCP_MT_REQUEST)
330 m_ciaddr = req.ciaddr();
331}
332
333
334void DhcpServerMessage::maybeUnicast(const DhcpClientMessage &req) RT_NOEXCEPT
335{
336 if (!req.broadcast() && req.ciaddr().u != 0)
337 setDst(req.ciaddr());
338}
339
340
341/**
342 * @throws std::bad_alloc
343 */
344void DhcpServerMessage::addOption(DhcpOption *opt)
345{
346 m_optmap << opt;
347}
348
349
350/**
351 * @throws std::bad_alloc
352 */
353void DhcpServerMessage::addOptions(const optmap_t &optmap)
354{
355 for (optmap_t::const_iterator it( optmap.begin() ); it != optmap.end(); ++it)
356 m_optmap << it->second;
357}
358
359
360/**
361 * @throws std::bad_alloc
362 */
363int DhcpServerMessage::encode(octets_t &data)
364{
365 /*
366 * Header, including DHCP cookie.
367 */
368 RTNETBOOTP bp;
369 RT_ZERO(bp);
370
371 bp.bp_op = RTNETBOOTP_OP_REPLY;
372 bp.bp_htype = RTNET_ARP_ETHER;
373 bp.bp_hlen = sizeof(RTMAC);
374
375 bp.bp_xid = m_xid;
376
377 bp.bp_ciaddr = m_ciaddr;
378 bp.bp_yiaddr = m_yiaddr;
379 bp.bp_siaddr = m_siaddr;
380 bp.bp_giaddr = m_giaddr;
381
382 bp.bp_chaddr.Mac = m_mac;
383
384 bp.bp_vend.Dhcp.dhcp_cookie = RT_H2N_U32_C(RTNET_DHCP_COOKIE);
385
386 data.insert(data.end(), (uint8_t *)&bp, (uint8_t *)&bp.bp_vend.Dhcp.dhcp_opts);
387
388 /*
389 * Options
390 */
391 data << m_optServerId
392 << m_optMessageType;
393
394 for (optmap_t::const_iterator it ( m_optmap.begin() );
395 it != m_optmap.end(); ++it)
396 {
397 LogRel3(("encoding option %d\n", it->first));
398 DhcpOption &opt = *it->second;
399 data << opt;
400 }
401
402 data << OptEnd();
403
404 AssertCompile(RTNET_DHCP_NORMAL_SIZE == 548);
405 if (data.size() < RTNET_DHCP_NORMAL_SIZE) /* XXX */
406 data.resize(RTNET_DHCP_NORMAL_SIZE);
407
408 return VINF_SUCCESS;
409}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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