join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
dhcp_message.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_FABRIC_DHCP_MESSAGE_HPP
26#define JOIN_FABRIC_DHCP_MESSAGE_HPP
27
28// libjoin.
29#include <join/dhcp_option.hpp>
30
31// C++.
32#include <sstream>
33#include <memory>
34#include <vector>
35
36// C.
37#include <net/ethernet.h>
38#include <netinet/in.h>
39#include <cstring>
40
41namespace join
42{
47 {
49 using Ptr = std::unique_ptr<DhcpPacket>;
50
53
56
59
61 IpAddress client{AF_INET};
62
64 IpAddress your{AF_INET};
65
67 IpAddress server{AF_INET};
68
71
73 uint32_t id = 0;
74
76 uint16_t secs = 0;
77
79 uint16_t flags = 0;
80
82 uint8_t op = 0;
83
86 };
87
92 {
93 public:
97 enum MessageType : uint8_t
98 {
100 Offer = 2,
103 Ack = 5,
104 Nak = 6,
106 Inform = 8,
107 };
108
112 enum Operation : uint8_t
113 {
116 };
117
121 enum Flag : uint16_t
122 {
123 BroadcastFlag = 0x8000,
124 };
125
129 enum Overload : uint8_t
130 {
133 };
134
141 int serialize (const DhcpPacket& packet, std::stringstream& data) const
142 {
143 if ((packet.op != BootRequest) && (packet.op != BootReply))
144 {
146 return -1;
147 }
148
149 const std::streampos start = data.tellp ();
150
151 uint8_t head[4] = {packet.op, _ethernet, ETH_ALEN, 0};
152 data.write (reinterpret_cast<const char*> (head), sizeof (head));
153
154 uint32_t id = htonl (packet.id);
155 data.write (reinterpret_cast<const char*> (&id), sizeof (id));
156
157 uint16_t secs = htons (packet.secs);
158 data.write (reinterpret_cast<const char*> (&secs), sizeof (secs));
159
160 uint16_t flags = htons (packet.flags);
161 data.write (reinterpret_cast<const char*> (&flags), sizeof (flags));
162
163 writeAddress (data, packet.client);
164 writeAddress (data, packet.your);
165 writeAddress (data, packet.server);
166 writeAddress (data, packet.gateway);
167
168 char chaddr[_chaddrSize] = {};
169 ::memcpy (chaddr, packet.hardware.addr (), ETH_ALEN);
170 data.write (chaddr, sizeof (chaddr));
171
172 char padding[_snameSize + _fileSize] = {};
173 data.write (padding, sizeof (padding));
174
175 uint32_t cookie = htonl (magicCookie);
176 data.write (reinterpret_cast<const char*> (&cookie), sizeof (cookie));
177
178 if (serialize (packet.options, data) == -1)
179 {
180 return -1;
181 }
182
183 const std::streamoff written = data.tellp () - start;
184 if (written < static_cast<std::streamoff> (minMsgSize))
185 {
186 const std::string pad (static_cast<size_t> (minMsgSize - written), static_cast<char> (DhcpOption::Pad));
187 data.write (pad.data (), pad.size ());
188 }
189
190 return 0;
191 }
192
199 int deserialize (DhcpPacket& packet, std::stringstream& data) const
200 {
201 packet.options.clear ();
202
203 uint8_t head[4] = {};
204 if (!extract (data, head, sizeof (head)))
205 {
206 return -1;
207 }
208
209 packet.op = head[0];
210 if (((packet.op != BootRequest) && (packet.op != BootReply)) || (head[1] != _ethernet) ||
211 (head[2] != ETH_ALEN))
212 {
214 return -1;
215 }
216
217 uint32_t id = 0;
218 uint16_t secs = 0, flags = 0;
219
220 if (!extract (data, &id, sizeof (id)) || !extract (data, &secs, sizeof (secs)) ||
221 !extract (data, &flags, sizeof (flags)))
222 {
223 return -1;
224 }
225
226 packet.id = ntohl (id);
227 packet.secs = ntohs (secs);
228 packet.flags = ntohs (flags);
229
230 if (!readAddress (data, packet.client) || !readAddress (data, packet.your) ||
231 !readAddress (data, packet.server) || !readAddress (data, packet.gateway))
232 {
233 return -1;
234 }
235
236 uint8_t chaddr[_chaddrSize] = {};
237 if (!extract (data, chaddr, sizeof (chaddr)))
238 {
239 return -1;
240 }
241
242 packet.hardware = MacAddress (chaddr, ETH_ALEN);
243
244 char sname[_snameSize] = {}, file[_fileSize] = {};
245 uint32_t cookie = 0;
246
247 if (!extract (data, sname, sizeof (sname)) || !extract (data, file, sizeof (file)) ||
248 !extract (data, &cookie, sizeof (cookie)))
249 {
250 return -1;
251 }
252
253 if (ntohl (cookie) != magicCookie)
254 {
256 return -1;
257 }
258
259 if (deserialize (packet.options, data) == -1)
260 {
261 return -1;
262 }
263
264 const uint8_t* overload = packet.options.getIf<uint8_t> (DhcpOption::OptionOverload);
265 if (overload != nullptr)
266 {
267 if ((*overload & FileOverload) && !deserialize (packet.options, file, sizeof (file)))
268 {
269 return -1;
270 }
271
272 if ((*overload & SnameOverload) && !deserialize (packet.options, sname, sizeof (sname)))
273 {
274 return -1;
275 }
276 }
277
278 return 0;
279 }
280
282 static constexpr uint32_t magicCookie = 0x63825363;
283
285 static constexpr size_t headerSize = 240;
286
288 static constexpr size_t minMsgSize = 300;
289
291 static constexpr size_t maxOptionSize = 255;
292
293 protected:
300 int serialize (const DhcpOption& options, std::stringstream& data) const;
301
308 int deserialize (DhcpOption& options, std::stringstream& data) const;
309
317 bool deserialize (DhcpOption& options, const char* field, size_t size) const
318 {
319 std::stringstream data;
320 data.rdbuf ()->pubsetbuf (const_cast<char*> (field), size);
321 return (deserialize (options, data) != -1);
322 }
323
331 static bool writeHead (std::ostream& data, uint8_t code, size_t size);
332
338 static void writeAddress (std::ostream& data, const IpAddress& address)
339 {
340 struct in_addr addr = {};
341
342 if (address.family () == AF_INET)
343 {
344 ::memcpy (&addr, address.addr (), sizeof (addr));
345 }
346
347 data.write (reinterpret_cast<const char*> (&addr), sizeof (addr));
348 }
349
356 static bool readAddress (std::istream& data, IpAddress& address)
357 {
358 struct in_addr addr = {};
359
360 if (!extract (data, &addr, sizeof (addr)))
361 {
362 return false;
363 }
364
365 address = IpAddress (&addr, sizeof (addr));
366
367 return true;
368 }
369
377 static bool extract (std::istream& data, void* out, size_t size)
378 {
379 data.read (reinterpret_cast<char*> (out), size);
380
381 if (data.fail ())
382 {
384 return false;
385 }
386
387 return true;
388 }
389
391 static constexpr uint8_t _ethernet = 1;
392
394 static constexpr size_t _chaddrSize = 16;
395
397 static constexpr size_t _snameSize = 64;
398
400 static constexpr size_t _fileSize = 128;
401 };
402}
403
404#endif
DHCP message codec.
Definition dhcp_message.hpp:92
Operation
DHCP operation codes.
Definition dhcp_message.hpp:113
@ BootReply
Definition dhcp_message.hpp:115
@ BootRequest
Definition dhcp_message.hpp:114
static constexpr uint32_t magicCookie
magic cookie introducing the option field.
Definition dhcp_message.hpp:282
static bool readAddress(std::istream &data, IpAddress &address)
read an IPv4 address from a byte stream.
Definition dhcp_message.hpp:356
Overload
option overload values.
Definition dhcp_message.hpp:130
@ SnameOverload
Definition dhcp_message.hpp:132
@ FileOverload
Definition dhcp_message.hpp:131
MessageType
DHCP message types, RFC 2132 section 9.6.
Definition dhcp_message.hpp:98
@ Request
Definition dhcp_message.hpp:101
@ Nak
Definition dhcp_message.hpp:104
@ Discover
Definition dhcp_message.hpp:99
@ Ack
Definition dhcp_message.hpp:103
@ Decline
Definition dhcp_message.hpp:102
@ Offer
Definition dhcp_message.hpp:100
@ Inform
Definition dhcp_message.hpp:106
@ Release
Definition dhcp_message.hpp:105
static void writeAddress(std::ostream &data, const IpAddress &address)
write an IPv4 address into a byte stream.
Definition dhcp_message.hpp:338
static constexpr size_t _fileSize
size of the boot file name field.
Definition dhcp_message.hpp:400
int deserialize(DhcpPacket &packet, std::stringstream &data) const
deserialize a DHCP message from a byte stream.
Definition dhcp_message.hpp:199
bool deserialize(DhcpOption &options, const char *field, size_t size) const
deserialize an option list from an overloaded field.
Definition dhcp_message.hpp:317
Flag
message flags.
Definition dhcp_message.hpp:122
@ BroadcastFlag
Definition dhcp_message.hpp:123
static constexpr size_t _snameSize
size of the server name field.
Definition dhcp_message.hpp:397
static bool writeHead(std::ostream &data, uint8_t code, size_t size)
write an option header into a byte stream.
Definition dhcp_message.cpp:40
static bool extract(std::istream &data, void *out, size_t size)
read a fixed amount of bytes from a byte stream.
Definition dhcp_message.hpp:377
static constexpr size_t _chaddrSize
size of the client hardware address field.
Definition dhcp_message.hpp:394
static constexpr size_t minMsgSize
smallest message a BOOTP implementation accepts, RFC 951 and RFC 1542 section 2.1.
Definition dhcp_message.hpp:288
static constexpr size_t maxOptionSize
biggest payload a single option can carry, its length field is one octet.
Definition dhcp_message.hpp:291
static constexpr size_t headerSize
size of the fixed part of a DHCP message, magic cookie included.
Definition dhcp_message.hpp:285
static constexpr uint8_t _ethernet
hardware address type of an Ethernet link.
Definition dhcp_message.hpp:391
int serialize(const DhcpPacket &packet, std::stringstream &data) const
serialize a DHCP message into a byte stream.
Definition dhcp_message.hpp:141
DHCP option list.
Definition dhcp_option.hpp:61
@ OptionOverload
Definition dhcp_option.hpp:120
@ Pad
Definition dhcp_option.hpp:68
const T * getIf(uint8_t code) const
get the value identified by code if it is present and holds the requested type.
Definition dhcp_option.hpp:243
void clear()
remove all elements from the list.
Definition dhcp_option.hpp:336
IPv6, IPv4 address class.
Definition ip_address.hpp:51
MAC address class.
Definition mac_address.hpp:46
const uint8_t * addr() const
get the internal MAC address array address.
Definition mac_address.cpp:164
Definition acceptor.hpp:32
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:195
DHCP message.
Definition dhcp_message.hpp:47
uint16_t flags
message flags.
Definition dhcp_message.hpp:79
MacAddress hardware
client hardware address, carried by the message itself.
Definition dhcp_message.hpp:58
IpAddress client
client IP address, set when the client already owns a lease.
Definition dhcp_message.hpp:61
uint8_t op
operation code.
Definition dhcp_message.hpp:82
MacAddress src
link layer source address, set by the transport.
Definition dhcp_message.hpp:52
std::unique_ptr< DhcpPacket > Ptr
pointer to a DHCP message.
Definition dhcp_message.hpp:49
IpAddress your
IP address the server assigns to the client.
Definition dhcp_message.hpp:64
DhcpOption options
message options.
Definition dhcp_message.hpp:85
uint16_t secs
seconds elapsed since the client started the acquisition.
Definition dhcp_message.hpp:76
MacAddress dest
link layer destination address, set by the transport.
Definition dhcp_message.hpp:55
IpAddress gateway
IP address of the relay agent the message went through.
Definition dhcp_message.hpp:70
IpAddress server
IP address of the next server to use at boot time.
Definition dhcp_message.hpp:67
uint32_t id
transaction identifier.
Definition dhcp_message.hpp:73
overload resolution.
Definition traits.hpp:80
IpAddress address
Definition tcp_acceptor_test.cpp:35