VirtualBox

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

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

Dhcpd: Eliminated use of std::string (probably my mistake in the original code). Various other cleanups. bugref:9288

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

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