-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathipv4.cpp
More file actions
81 lines (68 loc) · 2.97 KB
/
ipv4.cpp
File metadata and controls
81 lines (68 loc) · 2.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <ctime>
#include <iterator>
#include <span>
#include <unistd.h>
#include "include/ipv4.hpp"
#include "include/parsing.hpp"
constexpr IPv4Addr::IPv4Addr(uint8_t a, uint8_t b, uint8_t c, uint8_t d) : addr(a, b, c, d) {}
IPv4Packet::IPv4Packet(std::span<const uint8_t> packet)
: version_ihl(packet[4]), tos(packet[5]), total_length(read_u16(packet, 6)),
identification(read_u16(packet, 8)), flags_fragoffset(read_u16(packet, 10)),
time_to_live(packet[12]), protocol(packet[13]), header_cksum(read_u16(packet, 14)),
source_address(IPv4Addr(packet[16], packet[17], packet[18], packet[19])),
destination_address(IPv4Addr(packet[20], packet[21], packet[22], packet[23])) {
assert((packet[0] << 24) | (packet[1] << 16) | (packet[2] << 8) | packet[3] == 2 &&
"not ipv4 protocol");
// ihl == length of header in 32 bit words (so each word is 4 bytes so 4 places)
size_t header_len = (version_ihl & 0x0f) * 4;
body = packet.subspan(header_len + 4, (total_length - header_len));
}
IPv4Packet::IPv4Packet(size_t size, IPv4Addr source, IPv4Addr destination, uint8_t time_to_live,
uint8_t protocol)
: total_length(20 + size), time_to_live(time_to_live), protocol(protocol),
source_address(source), destination_address(destination) {
version_ihl = (4 << 4) | 5;
set_checksum();
}
void IPv4Packet::set_body(std::span<const uint8_t> body) {
this->body = body;
total_length = (version_ihl & 0x0f) * 4 + body.size();
}
std::vector<uint8_t> IPv4Packet::to_bytes() const {
BufWriter w = BufWriter();
w.write(this->version_ihl);
w.write(this->tos);
w.write(this->total_length);
w.write(this->identification);
w.write(this->flags_fragoffset);
w.write(this->time_to_live);
w.write(this->protocol);
w.write(this->header_cksum);
w.write(this->source_address.to_bytes());
w.write(this->destination_address.to_bytes());
w.write(this->body);
return std::move(w).finish();
}
void IPv4Packet::set_checksum() {
std::vector<uint8_t> packet = to_bytes();
assert(packet.size() % 2 == 0); // ihl measures 32 bit words so ihl * 4 should be packet.size()
uint32_t sum{};
for (int i{}; i < std::ssize(packet); i += 2) {
uint16_t word = packet[i] << 8 | packet[i + 1];
sum += word;
}
int carry = sum >> 16; // get the number of carryovers done
sum = sum & 0xffff + carry; // add it to the LSB of the sum
this->header_cksum = static_cast<uint16_t>(sum);
}
IPv4Addr IPv4Packet::source() const { return source_address; }
IPv4Addr IPv4Packet::destination() const { return destination_address; }
uint8_t IPv4Packet::get_protocol() const { return protocol; }
std::span<const uint8_t> IPv4Packet::get_body() const { return body; }
uint32_t IPv4Addr::to_bytes() const {
return (std::get<3>(addr) << 24) | (std::get<2>(addr) << 16) | (std::get<1>(addr) << 8) |
(std::get<0>(addr));
}