Sponge
CS144's user-space TCP library
ipv4_header.cc
Go to the documentation of this file.
1 #include "ipv4_header.hh"
2 
3 #include "util.hh"
4 
5 #include <arpa/inet.h>
6 #include <iomanip>
7 #include <sstream>
8 
9 using namespace std;
10 
24  Buffer original_serialized_version = p.buffer();
25 
26  const size_t data_size = p.buffer().size();
27  if (data_size < IPv4Header::LENGTH) {
29  }
30 
31  const uint8_t first_byte = p.u8();
32  ver = first_byte >> 4; // version
33  hlen = first_byte & 0x0f; // header length
34  tos = p.u8(); // type of service
35  len = p.u16(); // length
36  id = p.u16(); // id
37 
38  const uint16_t fo_val = p.u16();
39  df = static_cast<bool>(fo_val & 0x4000); // don't fragment
40  mf = static_cast<bool>(fo_val & 0x2000); // more fragments
41  offset = fo_val & 0x1fff; // offset
42 
43  ttl = p.u8(); // ttl
44  proto = p.u8(); // proto
45  cksum = p.u16(); // checksum
46  src = p.u32(); // source address
47  dst = p.u32(); // destination address
48 
49  if (data_size < 4 * hlen) {
51  }
52  if (ver != 4) {
54  }
55  if (hlen < 5) {
57  }
58  if (data_size != len) {
60  }
61 
62  p.remove_prefix(hlen * 4 - IPv4Header::LENGTH);
63 
64  if (p.error()) {
65  return p.get_error();
66  }
67 
68  InternetChecksum check;
69  check.add({original_serialized_version.str().data(), size_t(4 * hlen)});
70  if (check.value()) {
72  }
73 
74  return ParseResult::NoError;
75 }
76 
78 string IPv4Header::serialize() const {
79  // sanity checks
80  if (ver != 4) {
81  throw runtime_error("wrong IP version");
82  }
83  if (4 * hlen < IPv4Header::LENGTH) {
84  throw runtime_error("IP header too short");
85  }
86 
87  string ret;
88  ret.reserve(4 * hlen);
89 
90  const uint8_t first_byte = (ver << 4) | (hlen & 0xf);
91  NetUnparser::u8(ret, first_byte); // version and header length
92  NetUnparser::u8(ret, tos); // type of service
93  NetUnparser::u16(ret, len); // length
94  NetUnparser::u16(ret, id); // id
95 
96  const uint16_t fo_val = (df ? 0x4000 : 0) | (mf ? 0x2000 : 0) | (offset & 0x1fff);
97  NetUnparser::u16(ret, fo_val); // flags and offset
98 
99  NetUnparser::u8(ret, ttl); // time to live
100  NetUnparser::u8(ret, proto); // protocol number
101 
102  NetUnparser::u16(ret, cksum); // checksum
103 
104  NetUnparser::u32(ret, src); // src address
105  NetUnparser::u32(ret, dst); // dst address
106 
107  ret.resize(4 * hlen); // expand header to advertised size
108 
109  return ret;
110 }
111 
112 uint16_t IPv4Header::payload_length() const { return len - 4 * hlen; }
113 
126  uint32_t pcksum = (src >> 16) + (src & 0xffff); // source addr
127  pcksum += (dst >> 16) + (dst & 0xffff); // dest addr
128  pcksum += proto; // protocol
129  pcksum += payload_length(); // payload length
130  return pcksum;
131 }
132 
135  stringstream ss{};
136  ss << hex << boolalpha << "IP version: " << +ver << '\n'
137  << "IP hdr len: " << +hlen << '\n'
138  << "IP tos: " << +tos << '\n'
139  << "IP dgram len: " << +len << '\n'
140  << "IP id: " << +id << '\n'
141  << "Flags: df: " << df << " mf: " << mf << '\n'
142  << "Offset: " << +offset << '\n'
143  << "TTL: " << +ttl << '\n'
144  << "Protocol: " << +proto << '\n'
145  << "Checksum: " << +cksum << '\n'
146  << "Src addr: " << +src << '\n'
147  << "Dst addr: " << +dst << '\n';
148  return ss.str();
149 }
150 
152  stringstream ss{};
153  ss << hex << boolalpha << "IPv" << +ver << ", "
154  << "len=" << +len << ", "
155  << "protocol=" << +proto << ", " << (ttl >= 10 ? "" : "ttl=" + ::to_string(ttl) + ", ")
156  << "src=" << inet_ntoa({htobe32(src)}) << ", "
157  << "dst=" << inet_ntoa({htobe32(dst)});
158  return ss.str();
159 }
NetParser::u16
uint16_t u16()
Parse a 16-bit integer in network byte order from the data stream.
Definition: parser.cc:64
ParseResult::NoError
@ NoError
Success.
IPv4Header::LENGTH
static constexpr size_t LENGTH
IPv4 header length, not including options
Definition: ipv4_header.hh:9
std::string::resize
T resize(T... args)
util.hh
NetUnparser::u8
static void u8(std::string &s, const uint8_t val)
Write an 8-bit integer into the data stream in network byte order.
Definition: parser.cc:72
NetParser::remove_prefix
void remove_prefix(const size_t n)
Remove n bytes from the buffer.
Definition: parser.cc:45
std::string
len
constexpr size_t len
Definition: tcp_benchmark.cc:12
std::string::reserve
T reserve(T... args)
InternetChecksum::add
void add(std::string_view data)
Definition: util.cc:89
IPv4Header::summary
std::string summary() const
Return a string containing a human-readable summary of the header.
Definition: ipv4_header.cc:151
std::stringstream
InternetChecksum::value
uint16_t value() const
Definition: util.cc:100
ipv4_header.hh
NetParser::buffer
Buffer buffer() const
Definition: parser.hh:40
NetParser::error
bool error() const
Returns true if there has been an error.
Definition: parser.hh:50
std::hex
T hex(T... args)
ParseResult::BadChecksum
@ BadChecksum
Bad checksum.
NetUnparser::u16
static void u16(std::string &s, const uint16_t val)
Write a 16-bit integer into the data stream in network byte order.
Definition: parser.cc:70
Buffer
A reference-counted read-only string that can discard bytes from the front.
Definition: buffer.hh:14
std::to_string
T to_string(T... args)
IPv4Header::to_string
std::string to_string() const
Return a string containing a header in human-readable format.
Definition: ipv4_header.cc:134
ParseResult
ParseResult
The result of parsing or unparsing an IP datagram, TCP segment, Ethernet frame, or ARP message.
Definition: parser.hh:12
std::runtime_error
std::uint8_t
IPv4Header::serialize
std::string serialize() const
Serialize the IP fields.
Definition: ipv4_header.cc:78
IPv4Header::pseudo_cksum
uint32_t pseudo_cksum() const
pseudo-header's contribution to the TCP checksum
Definition: ipv4_header.cc:125
ParseResult::TruncatedPacket
@ TruncatedPacket
Packet length is shorter than header claims.
NetParser
Definition: parser.hh:25
NetUnparser::u32
static void u32(std::string &s, const uint32_t val)
Write a 32-bit integer into the data stream in network byte order.
Definition: parser.cc:68
NetParser::u8
uint8_t u8()
Parse an 8-bit integer in network byte order from the data stream.
Definition: parser.cc:66
IPv4Header::parse
ParseResult parse(NetParser &p)
Parse the IP fields from the provided NetParser.
Definition: ipv4_header.cc:23
std::boolalpha
T boolalpha(T... args)
std
ParseResult::WrongIPVersion
@ WrongIPVersion
Got a version of IP other than 4.
ParseResult::HeaderTooShort
@ HeaderTooShort
Header length is shorter than minimum required.
InternetChecksum
The internet checksum algorithm.
Definition: util.hh:55
ParseResult::PacketTooShort
@ PacketTooShort
Not enough data to finish parsing.
NetParser::get_error
ParseResult get_error() const
Get the current value stored in BaseParser::_error.
Definition: parser.hh:43
Buffer::size
size_t size() const
Size of the string.
Definition: buffer.hh:41
std::size_t
Buffer::str
std::string_view str() const
Definition: buffer.hh:27
NetParser::u32
uint32_t u32()
Parse a 32-bit integer in network byte order from the data stream.
Definition: parser.cc:62
IPv4Header::payload_length
uint16_t payload_length() const
Length of the payload.
Definition: ipv4_header.cc:112