Branch data Line data Source code
1 : : /*
2 : : ** Copyright (C) 2023 Sylvain Fargier
3 : : **
4 : : ** This software is provided 'as-is', without any express or implied
5 : : ** warranty. In no event will the authors be held liable for any damages
6 : : ** arising from the use of this software.
7 : : **
8 : : ** Permission is granted to anyone to use this software for any purpose,
9 : : ** including commercial applications, and to alter it and redistribute it
10 : : ** freely, subject to the following restrictions:
11 : : **
12 : : ** 1. The origin of this software must not be misrepresented; you must not
13 : : ** claim that you wrote the original software. If you use this software
14 : : ** in a product, an acknowledgment in the product documentation would be
15 : : ** appreciated but is not required.
16 : : ** 2. Altered source versions must be plainly marked as such, and must not be
17 : : ** misrepresented as being the original software.
18 : : ** 3. This notice may not be removed or altered from any source distribution.
19 : : **
20 : : ** Created on: 2023-12-21T18:12:24
21 : : ** Author: Sylvain Fargier <fargier.sylvain@gmail.com>
22 : : */
23 : :
24 : : #include "RawIPMessage.hpp"
25 : :
26 : : #include <cstdint>
27 : : #include <cstring>
28 : :
29 : : #include <netinet/in.h>
30 : :
31 : : #include "../../Exception.hpp"
32 : :
33 : : namespace ccut {
34 : : namespace net {
35 : :
36 : : #define IPVERS_OFFSET 0
37 : : #define IPV4_TOTAL_LENGTH_OFFSET 2
38 : : #define IPV4_TTL_OFFSET 8
39 : : #define IPV4_PROTO_OFFSET 9
40 : : #define IPV4_CKSUM_OFFSET 10
41 : : #define IPV4_SRC_OFFSET 12
42 : : #define IPV4_DEST_OFFSET 16
43 : :
44 : : #define IPV6_PAYLOAD_LENGTH_OFFSET 4
45 : : #define IPV6_NEXT_HEADER_OFFSET 6
46 : : #define IPV6_HOP_LIMIT_OFFSET 7
47 : : #define IPV6_SRC_OFFSET 8
48 : : #define IPV6_DEST_OFFSET 24
49 : :
50 : : static const std::string s_logCat{"ccut:net:raw"};
51 : : constexpr size_t RawIPv4Message::MinDataSize;
52 : :
53 : 12 : std::string to_string(Protocol proto)
54 : : {
55 : 12 : switch (proto)
56 : : {
57 : 2 : case Protocol::ICMP: return "ICMP";
58 : 1 : case Protocol::IGMP: return "IGMP";
59 : 1 : case Protocol::IPinIP: return "IPinIP";
60 : 1 : case Protocol::TCP: return "TCP";
61 : 1 : case Protocol::IGP: return "IGP";
62 : 1 : case Protocol::UDP: return "UDP";
63 : 1 : case Protocol::RDP: return "RDP";
64 : 1 : case Protocol::IPv6: return "IPv6";
65 : 1 : case Protocol::ICMPv6: return "ICMPv6";
66 : 1 : case Protocol::RAW: return "RAW";
67 : 1 : default: return std::string();
68 : : }
69 : : }
70 : :
71 : 12 : const logger::Logger &operator<<(const logger::Logger &logger, Protocol proto)
72 : : {
73 : 12 : if (!logger.isEnabled())
74 : 0 : return logger;
75 : 12 : const std::string &value{to_string(proto)};
76 : 12 : if (value.empty())
77 : 2 : return (logger << "Protocol{" << logger::hex(enum_cast(proto), true)
78 : 1 : << "}");
79 : : else
80 : 11 : return (logger << value);
81 : 12 : }
82 : :
83 : 5 : std::string to_string(RawIPv6Message::ECN ecn)
84 : : {
85 : 5 : switch (ecn)
86 : : {
87 : 1 : case RawIPv6Message::ECN::NoECT: return "NoECT";
88 : 1 : case RawIPv6Message::ECN::ECNCapableTransport1:
89 : 1 : return "ECNCapableTransport1";
90 : 1 : case RawIPv6Message::ECN::ECNCapableTransport2:
91 : 1 : return "ECNCapableTransport2";
92 : 1 : case RawIPv6Message::ECN::CongestionExperienced:
93 : 1 : return "CongestionExperienced";
94 : 1 : default: return std::string();
95 : : }
96 : : }
97 : :
98 : 5 : const logger::Logger &operator<<(const logger::Logger &logger,
99 : : RawIPv6Message::ECN ecn)
100 : : {
101 : 5 : if (!logger.isEnabled())
102 : 0 : return logger;
103 : 5 : const std::string &value{to_string(ecn)};
104 : 5 : if (value.empty())
105 : 1 : return (logger << "ECN{" << logger::hex(enum_cast(ecn), true) << "}");
106 : : else
107 : 4 : return (logger << value);
108 : 5 : }
109 : :
110 : 23 : std::string to_string(RawIPv6Message::DSCP dscp)
111 : : {
112 : 23 : switch (dscp)
113 : : {
114 : 2 : case RawIPv6Message::DSCP::DefaultForwarding: return "DefaultForwarding";
115 : 1 : case RawIPv6Message::DSCP::ExpeditedForwarding:
116 : 1 : return "ExpeditedForwarding";
117 : 1 : case RawIPv6Message::DSCP::CS1: return "CS1";
118 : 1 : case RawIPv6Message::DSCP::CS2: return "CS2";
119 : 1 : case RawIPv6Message::DSCP::CS3: return "CS3";
120 : 1 : case RawIPv6Message::DSCP::CS4: return "CS4";
121 : 1 : case RawIPv6Message::DSCP::CS5: return "CS5";
122 : 1 : case RawIPv6Message::DSCP::CS6: return "CS6";
123 : 1 : case RawIPv6Message::DSCP::CS7: return "CS7";
124 : 1 : case RawIPv6Message::DSCP::AF11: return "AF11";
125 : 1 : case RawIPv6Message::DSCP::AF12: return "AF12";
126 : 1 : case RawIPv6Message::DSCP::AF13: return "AF13";
127 : 1 : case RawIPv6Message::DSCP::AF21: return "AF21";
128 : 1 : case RawIPv6Message::DSCP::AF22: return "AF22";
129 : 1 : case RawIPv6Message::DSCP::AF23: return "AF23";
130 : 1 : case RawIPv6Message::DSCP::AF31: return "AF31";
131 : 1 : case RawIPv6Message::DSCP::AF32: return "AF32";
132 : 1 : case RawIPv6Message::DSCP::AF33: return "AF33";
133 : 1 : case RawIPv6Message::DSCP::AF41: return "AF41";
134 : 1 : case RawIPv6Message::DSCP::AF42: return "AF42";
135 : 1 : case RawIPv6Message::DSCP::AF43: return "AF43";
136 : 1 : default: return std::string();
137 : : }
138 : : }
139 : :
140 : 23 : const logger::Logger &operator<<(const logger::Logger &logger,
141 : : RawIPv6Message::DSCP dscp)
142 : : {
143 : 23 : if (!logger.isEnabled())
144 : 0 : return logger;
145 : 23 : const std::string &value{to_string(dscp)};
146 : 23 : if (value.empty())
147 : 1 : return (logger << "DSCP{" << logger::hex(enum_cast(dscp), true) << "}");
148 : : else
149 : 22 : return (logger << value);
150 : 23 : }
151 : :
152 : 1 : RawIPv4Message::RawIPv4Message(const Addr &from,
153 : : const Addr &to,
154 : : Protocol proto,
155 : 1 : size_t payloadSize) :
156 : 1 : Message(from, to)
157 : : {
158 : 1 : init(payloadSize);
159 : 1 : setProtocol(proto);
160 : 1 : }
161 : :
162 : 0 : RawIPv4Message::RawIPv4Message(const Addr &to,
163 : : Protocol proto,
164 : 0 : size_t payloadSize) :
165 : 0 : RawIPv4Message(Addr(), to, proto, payloadSize)
166 : 0 : {}
167 : :
168 : 0 : RawIPv4Message::RawIPv4Message(Protocol proto, size_t payloadSize) :
169 : 0 : RawIPv4Message(Addr(), Addr(), proto, payloadSize)
170 : 0 : {}
171 : :
172 : 1 : RawIPv4Message RawIPv4Message::load(const data_t &buffer)
173 : : {
174 : 1 : RawIPv4Message ret;
175 : 1 : ret.data = buffer;
176 : 1 : if (ret)
177 : : {
178 : 1 : ret.from = ret.ipSrc();
179 : 1 : ret.to = ret.ipDest();
180 : : }
181 : 1 : return ret;
182 : 0 : }
183 : :
184 : 2 : size_t getRawIPVersion(const Message::data_t &buffer)
185 : : {
186 : 2 : if (buffer && buffer.size() > 1)
187 : 2 : return (buffer.read(0) >> 4) & 0xF;
188 : : else
189 : 0 : return 0;
190 : : }
191 : :
192 : 4 : void RawIPv4Message::prepare()
193 : : {
194 : 4 : if (data && data.size() >= MinDataSize)
195 : : {
196 : 4 : setTotalLength(data.size());
197 : 4 : setIpSrc(from);
198 : 4 : setIpDest(to);
199 : 4 : data.write<uint16_t>(IPV4_CKSUM_OFFSET, 0);
200 : 4 : uint16_t sum = net::cksum(make_const(data).data(),
201 : 4 : ipHeaderLength() * sizeof(uint32_t));
202 : 4 : data.write<uint16_t>(IPV4_CKSUM_OFFSET, sum,
203 : : (BYTE_ORDER == LITTLE_ENDIAN) ? false : true);
204 : : }
205 : 4 : }
206 : :
207 : 8 : uint8_t RawIPv4Message::ipVersion() const
208 : : {
209 : 8 : if (!data || data.size() < MinDataSize)
210 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv4 message");
211 : 7 : return (data.read(IPVERS_OFFSET) >> 4) & 0xF;
212 : : }
213 : :
214 : 11 : uint8_t RawIPv4Message::ipHeaderLength() const
215 : : {
216 : 11 : if (!data || data.size() < MinDataSize)
217 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv4 message");
218 : 10 : return data.read(IPVERS_OFFSET) & 0xF;
219 : : }
220 : 2 : uint8_t RawIPv4Message::differentiatedServicesCodePoint() const
221 : : {
222 : 2 : if (!data || data.size() < MinDataSize)
223 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv4 message");
224 : 1 : return (data.read(1) >> 2) & 0x3F;
225 : : }
226 : :
227 : 2 : uint8_t RawIPv4Message::explicitCongestionNotification() const
228 : : {
229 : 2 : if (!data || data.size() < MinDataSize)
230 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv4 message");
231 : 1 : return (data.read(1)) & 0x3;
232 : : }
233 : :
234 : 2 : uint16_t RawIPv4Message::totalLength() const
235 : : {
236 : 2 : if (!data || data.size() < MinDataSize)
237 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv4 message");
238 : 1 : return data.read<uint16_t>(IPV4_TOTAL_LENGTH_OFFSET, true);
239 : : }
240 : :
241 : 4 : RawIPv4Message &RawIPv4Message::setTotalLength(uint16_t totalLength)
242 : : {
243 : 4 : init();
244 : :
245 : 4 : data.write<uint16_t>(IPV4_TOTAL_LENGTH_OFFSET, totalLength, true);
246 : 4 : return *this;
247 : : }
248 : :
249 : 2 : uint16_t RawIPv4Message::ipIdentification() const
250 : : {
251 : 2 : if (!data || data.size() < MinDataSize)
252 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv4 message");
253 : 1 : return data.read<uint16_t>(4, true);
254 : : }
255 : :
256 : 1 : RawIPv4Message &RawIPv4Message::setIpIdentification(uint16_t identification)
257 : : {
258 : 1 : init();
259 : :
260 : 1 : data.write<uint16_t>(4, identification, true);
261 : 1 : return *this;
262 : : }
263 : :
264 : 2 : RawIPv4Message::IPFlags RawIPv4Message::ipFlags() const
265 : : {
266 : 2 : if (!data || data.size() < MinDataSize)
267 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv4 message");
268 : 1 : return IPFlags((data.read(6) >> 5) & 0x7);
269 : : }
270 : :
271 : 1 : RawIPv4Message &RawIPv4Message::setIpFlags(IPFlags flags)
272 : : {
273 : 1 : init();
274 : :
275 : 1 : uint8_t value = ((flags.bits() << 5) & 0xE0) |
276 : 1 : (data.read<uint8_t>(6) & 0x1F);
277 : 1 : data.write<uint8_t>(6, value);
278 : 1 : return *this;
279 : : }
280 : :
281 : 2 : uint16_t RawIPv4Message::ipFragmentOffset() const
282 : : {
283 : 2 : if (!data || data.size() < MinDataSize)
284 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv4 message");
285 : 1 : return data.read<uint16_t>(6, true) & 0x1FFF;
286 : : }
287 : :
288 : 1 : RawIPv4Message &RawIPv4Message::setIpFragmentOffset(uint16_t offset)
289 : : {
290 : 1 : init();
291 : :
292 : 1 : uint16_t value = (offset & 0x1FFF) | (data.read<uint16_t>(6, true) & 0xE000);
293 : 1 : data.write<uint16_t>(6, value, true);
294 : 1 : return *this;
295 : : }
296 : :
297 : 2 : uint8_t RawIPv4Message::timeToLive() const
298 : : {
299 : 2 : if (!data || data.size() < MinDataSize)
300 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv4 message");
301 : 1 : return data.read(IPV4_TTL_OFFSET);
302 : : }
303 : :
304 : 1 : RawIPv4Message &RawIPv4Message::setTimeToLive(uint8_t ttl)
305 : : {
306 : 1 : init();
307 : :
308 : 1 : data.write<uint8_t>(IPV4_TTL_OFFSET, ttl);
309 : 1 : return *this;
310 : : }
311 : :
312 : 3 : RawIPv4Message::Protocol RawIPv4Message::protocol() const
313 : : {
314 : 3 : if (!data || data.size() < MinDataSize)
315 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv4 message");
316 : 2 : return static_cast<Protocol>(data.read(IPV4_PROTO_OFFSET));
317 : : }
318 : :
319 : 2 : RawIPv4Message &RawIPv4Message::setProtocol(Protocol proto)
320 : : {
321 : 2 : init();
322 : :
323 : 2 : data.write<uint8_t>(IPV4_PROTO_OFFSET, enum_cast(proto));
324 : 2 : return *this;
325 : : }
326 : :
327 : 3 : uint16_t RawIPv4Message::ipHeaderChecksum() const
328 : : {
329 : 3 : if (!data || data.size() < MinDataSize)
330 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv4 message");
331 : 2 : return data.read<uint16_t>(IPV4_CKSUM_OFFSET, true);
332 : : }
333 : :
334 : 4 : Addr RawIPv4Message::ipSrc() const
335 : : {
336 : 4 : if (!data || data.size() < MinDataSize)
337 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv4 message");
338 : 6 : return Addr::fromBuffer(data.sub(IPV4_SRC_OFFSET, 4));
339 : : }
340 : :
341 : 4 : RawIPv4Message &RawIPv4Message::setIpSrc(const Addr &from)
342 : : {
343 : 4 : init();
344 : :
345 : 4 : if (!from.isValid())
346 : 0 : data.write<uint32_t>(IPV4_SRC_OFFSET, 0, true);
347 : 4 : else if (from.isV6())
348 : 0 : throw ccut::Exception(ccut::ErrorCode::Runtime,
349 : 0 : "Can't set an IPv6 address in IPv4 message");
350 : : else
351 : : {
352 : 4 : memcpy(
353 : 4 : &data[IPV4_SRC_OFFSET],
354 : 4 : &reinterpret_cast<const sockaddr_in *>(from.addr())->sin_addr.s_addr,
355 : : 4);
356 : : }
357 : 4 : return *this;
358 : : }
359 : :
360 : 4 : Addr RawIPv4Message::ipDest() const
361 : : {
362 : 4 : if (!data || data.size() < MinDataSize)
363 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv4 message");
364 : 6 : return Addr::fromBuffer(data.sub(IPV4_DEST_OFFSET, 4));
365 : : }
366 : :
367 : 4 : RawIPv4Message &RawIPv4Message::setIpDest(const Addr &from)
368 : : {
369 : 4 : init();
370 : :
371 : 4 : if (!from.isValid())
372 : 0 : data.write<uint32_t>(IPV4_DEST_OFFSET, 0, true);
373 : 4 : else if (from.isV6())
374 : 0 : throw ccut::Exception(ccut::ErrorCode::Runtime,
375 : 0 : "Can't set an IPv6 address in IPv4 message");
376 : : else
377 : : {
378 : 4 : memcpy(
379 : 4 : &data[IPV4_DEST_OFFSET],
380 : 4 : &reinterpret_cast<const sockaddr_in *>(from.addr())->sin_addr.s_addr,
381 : : 4);
382 : : }
383 : 4 : return *this;
384 : : }
385 : :
386 : 10 : bool RawIPv4Message::isValid() const
387 : : {
388 : 10 : if (!Message::isValid())
389 : 1 : return false;
390 : 9 : else if (!data || data.size() < MinDataSize || ipVersion() != 4)
391 : 4 : return false;
392 : : else
393 : : {
394 : 5 : uint16_t ret = cksum(data.data(), ipHeaderLength() * 4);
395 : 5 : if (ret != 0)
396 : : {
397 : 1 : logger::warning(s_logCat) << "invalid IPv4 checksum: " << ret;
398 : 1 : return false;
399 : : }
400 : : }
401 : 4 : return true;
402 : : }
403 : :
404 : 0 : Message::data_t RawIPv4Message::payload() const
405 : : {
406 : 0 : return data.sub(ipHeaderLength() * 4);
407 : : }
408 : :
409 : 19 : void RawIPv4Message::init(size_t payloadSize)
410 : : {
411 : 19 : if (!data)
412 : 2 : data = make_cow<buffer_t>(MinDataSize + payloadSize);
413 : 17 : else if (data.size() < MinDataSize + payloadSize)
414 : : {
415 : 0 : data.buffer()->resize(MinDataSize + payloadSize);
416 : 0 : data.reset(data.buffer());
417 : : }
418 : : else
419 : 17 : return;
420 : :
421 : 2 : data.write<uint8_t>(IPVERS_OFFSET, 0x45); // VERS=4 IHL=5
422 : 2 : data.write<uint8_t>(IPV4_TTL_OFFSET, 0xFF);
423 : : }
424 : :
425 : 1 : RawIPv6Message::RawIPv6Message(const Addr &from,
426 : : const Addr &to,
427 : : Protocol proto,
428 : 1 : size_t payloadSize) :
429 : 1 : Message(from, to)
430 : : {
431 : 1 : init(payloadSize);
432 : 1 : setNextHeader(proto);
433 : 1 : }
434 : :
435 : 0 : RawIPv6Message::RawIPv6Message(const Addr &to,
436 : : Protocol proto,
437 : 0 : size_t payloadSize) :
438 : 0 : RawIPv6Message(Addr(), to, proto, payloadSize)
439 : 0 : {}
440 : :
441 : 0 : RawIPv6Message::RawIPv6Message(Protocol proto, size_t payloadSize) :
442 : 0 : RawIPv6Message(Addr(), Addr(), proto, payloadSize)
443 : 0 : {}
444 : :
445 : 1 : RawIPv6Message RawIPv6Message::load(const data_t &buffer)
446 : : {
447 : 1 : RawIPv6Message ret;
448 : 1 : ret.data = buffer;
449 : 1 : if (ret)
450 : : {
451 : 1 : ret.from = ret.ipSrc();
452 : 1 : ret.to = ret.ipDest();
453 : : }
454 : 1 : return ret;
455 : 0 : }
456 : :
457 : 3 : void RawIPv6Message::prepare()
458 : : {
459 : 3 : if (data && data.size() >= MinDataSize)
460 : : {
461 : 3 : setPayloadLength(data.size() - MinDataSize);
462 : 3 : setIpSrc(from);
463 : 3 : setIpDest(to);
464 : : }
465 : 3 : }
466 : :
467 : 6 : uint8_t RawIPv6Message::ipVersion() const
468 : : {
469 : 6 : if (!data || data.size() < MinDataSize)
470 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv6 message");
471 : 5 : return (data.read(IPVERS_OFFSET) >> 4) & 0xF;
472 : : }
473 : :
474 : 3 : RawIPv6Message::ECN RawIPv6Message::explicitCongestionNotification() const
475 : : {
476 : 3 : if (!data || data.size() < MinDataSize)
477 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv6 message");
478 : 2 : return static_cast<ECN>((data.read(1) >> 4) & 0x3);
479 : : }
480 : :
481 : 2 : RawIPv6Message &RawIPv6Message::setExplicitCongestionNotification(ECN ecn)
482 : : {
483 : 2 : init();
484 : :
485 : 2 : uint8_t value = data.read(1);
486 : 2 : value = ((enum_cast(ecn) << 4) & 0x30) | (value & ~0x30);
487 : :
488 : 2 : data.write<uint8_t>(1, value);
489 : 2 : return *this;
490 : : }
491 : :
492 : 3 : RawIPv6Message::DSCP RawIPv6Message::differentiatedServicesCodePoint() const
493 : : {
494 : 3 : if (!data || data.size() < MinDataSize)
495 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv6 message");
496 : 2 : return static_cast<DSCP>((data.read<uint16_t>(0, true) >> 6) & 0x3F);
497 : : }
498 : :
499 : 2 : RawIPv6Message &RawIPv6Message::setDifferentiatedServicesCodePoint(DSCP dscp)
500 : : {
501 : 2 : init();
502 : :
503 : 2 : uint16_t value = data.read<uint16_t>(0, true);
504 : 2 : value = ((enum_cast(dscp) << 6) & 0x0FC0) | (value & ~0x0FC0);
505 : :
506 : 2 : data.write<uint16_t>(0, value, true);
507 : 2 : return *this;
508 : : }
509 : :
510 : 2 : uint8_t RawIPv6Message::trafficClass() const
511 : : {
512 : 2 : if (!data || data.size() < MinDataSize)
513 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv6 message");
514 : 1 : return (data.read<uint16_t>(IPVERS_OFFSET, true) >> 4) & 0xFF;
515 : : }
516 : :
517 : 3 : uint32_t RawIPv6Message::flowLabel() const
518 : : {
519 : 3 : if (!data || data.size() < MinDataSize)
520 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv6 message");
521 : 2 : return data.read<uint32_t>(IPVERS_OFFSET, true) & 0xFFFFF;
522 : : }
523 : :
524 : 2 : RawIPv6Message &RawIPv6Message::setFlowLabel(uint32_t flowLabel)
525 : : {
526 : 2 : init();
527 : 2 : uint32_t value = data.read<uint32_t>(0, true);
528 : 2 : value = (value & 0xFFF00000) | (flowLabel & 0xFFFFF);
529 : :
530 : 2 : data.write<uint32_t>(0, value, true);
531 : 2 : return *this;
532 : : }
533 : :
534 : 2 : uint16_t RawIPv6Message::payloadLength() const
535 : : {
536 : 2 : if (!data || data.size() < MinDataSize)
537 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv6 message");
538 : 1 : return data.read<uint16_t>(IPV6_PAYLOAD_LENGTH_OFFSET, true);
539 : : }
540 : :
541 : 3 : RawIPv6Message &RawIPv6Message::setPayloadLength(uint16_t value)
542 : : {
543 : 3 : init();
544 : :
545 : 3 : data.write<uint16_t>(4, value, true);
546 : 3 : return *this;
547 : : }
548 : :
549 : 3 : Protocol RawIPv6Message::nextHeader() const
550 : : {
551 : 3 : if (!data || data.size() < MinDataSize)
552 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv6 message");
553 : 2 : return static_cast<Protocol>(data.read(IPV6_NEXT_HEADER_OFFSET));
554 : : }
555 : :
556 : 3 : RawIPv6Message &RawIPv6Message::setNextHeader(Protocol proto)
557 : : {
558 : 3 : init();
559 : :
560 : 3 : data.write<uint8_t>(IPV6_NEXT_HEADER_OFFSET, enum_cast(proto));
561 : 3 : return *this;
562 : : }
563 : :
564 : 3 : uint8_t RawIPv6Message::hopLimit() const
565 : : {
566 : 3 : if (!data || data.size() < MinDataSize)
567 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv6 message");
568 : 2 : return data.read(IPV6_HOP_LIMIT_OFFSET);
569 : : }
570 : :
571 : 2 : RawIPv6Message &RawIPv6Message::setHopLimit(uint8_t limit)
572 : : {
573 : 2 : init();
574 : :
575 : 2 : data.write<uint8_t>(IPV6_HOP_LIMIT_OFFSET, limit);
576 : 2 : return *this;
577 : : }
578 : :
579 : 4 : Addr RawIPv6Message::ipSrc() const
580 : : {
581 : 4 : if (!data || data.size() < MinDataSize)
582 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv6 message");
583 : 6 : return Addr::fromBuffer(data.sub(IPV6_SRC_OFFSET, 16));
584 : : }
585 : :
586 : 6 : RawIPv6Message &RawIPv6Message::setIpSrc(const Addr &from)
587 : : {
588 : 6 : init();
589 : :
590 : 6 : if (!from.isValid())
591 : 1 : memset(&data[IPV6_SRC_OFFSET], 0, 16);
592 : 5 : else if (!from.isV6())
593 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime,
594 : 2 : "Can't set an IPv4 address in IPv6 message");
595 : : else
596 : : {
597 : 4 : memcpy(&data[IPV6_SRC_OFFSET],
598 : 4 : &reinterpret_cast<const sockaddr_in6 *>(from.addr())->sin6_addr,
599 : : 16);
600 : : }
601 : 5 : return *this;
602 : : }
603 : :
604 : 4 : Addr RawIPv6Message::ipDest() const
605 : : {
606 : 4 : if (!data || data.size() < MinDataSize)
607 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime, "Invalid IPv6 message");
608 : 6 : return Addr::fromBuffer(data.sub(IPV6_DEST_OFFSET, 16));
609 : : }
610 : :
611 : 6 : RawIPv6Message &RawIPv6Message::setIpDest(const Addr &from)
612 : : {
613 : 6 : init();
614 : :
615 : 6 : if (!from.isValid())
616 : 1 : memset(&data[IPV6_DEST_OFFSET], 0, 16);
617 : 5 : else if (!from.isV6())
618 : 1 : throw ccut::Exception(ccut::ErrorCode::Runtime,
619 : 2 : "Can't set an IPv4 address in IPv6 message");
620 : : else
621 : : {
622 : 4 : memcpy(&data[IPV6_DEST_OFFSET],
623 : 4 : &reinterpret_cast<const sockaddr_in6 *>(from.addr())->sin6_addr,
624 : : 16);
625 : : }
626 : 5 : return *this;
627 : : }
628 : :
629 : 8 : bool RawIPv6Message::isValid() const
630 : : {
631 : 8 : if (!Message::isValid())
632 : 1 : return false;
633 : 7 : else if (!data || data.size() < MinDataSize || ipVersion() != 6)
634 : 4 : return false;
635 : :
636 : 3 : return true;
637 : : }
638 : :
639 : 2 : Message::data_t RawIPv6Message::payload() const
640 : : {
641 : 2 : return data.sub(MinDataSize);
642 : : }
643 : :
644 : 27 : void RawIPv6Message::init(size_t payloadSize)
645 : : {
646 : 27 : if (!data)
647 : 2 : data = make_cow<buffer_t>(MinDataSize + payloadSize);
648 : 25 : else if (data.size() < MinDataSize + payloadSize)
649 : : {
650 : 0 : data.buffer()->resize(MinDataSize + payloadSize);
651 : 0 : data.reset(data.buffer());
652 : : }
653 : : else
654 : 25 : return;
655 : :
656 : 2 : data.write<uint8_t>(IPVERS_OFFSET, 0x60); // VERS=6
657 : 2 : data.write<uint8_t>(IPV6_HOP_LIMIT_OFFSET, 0xFF);
658 : : }
659 : :
660 : : } // namespace net
661 : : } // namespace ccut
|