#include <array>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <stdexcept>
#include <type_traits>
#include <vector>
#include <arpa/inet.h>
// Convert between network and host encoding.
inline uint8_t NetworkToHost(uint8_t inValue) { return inValue; }
inline uint16_t NetworkToHost(uint16_t inValue) { return ntohs(inValue); }
inline uint32_t NetworkToHost(uint32_t inValue) { return ntohl(inValue); }
inline uint8_t HostToNetwork(uint8_t inValue) { return inValue; }
inline uint16_t HostToNetwork(uint16_t inValue) { return htons(inValue); }
inline uint32_t HostToNetwork(uint32_t inValue) { return htonl(inValue); }
/**
* @brief The NetEncoded class wraps a network-encoded value.
* Can be constructed from a host-encoded value using the "NetEncode" factory function.
* This class meets pod requirements and can be used to represent fields in packet headers.
*/
template<typename T>
class NetEncoded {
public:
NetEncoded() = default;
T hostValue() const {
return NetworkToHost(mValue);
}
private:
friend NetEncoded<uint16_t> NetEncode(uint16_t);
friend NetEncoded<uint32_t> NetEncode(uint32_t);
friend NetEncoded<uint64_t> NetEncode(uint64_t);
NetEncoded(const T & inValue) : mValue(inValue)
{
}
friend bool operator<(const NetEncoded & lhs, const NetEncoded & rhs) {
return lhs.mValue < rhs.mValue;
}
friend bool operator==(const NetEncoded & lhs, const NetEncoded & rhs) {
return lhs.mValue == rhs.mValue;
}
friend bool operator!=(const NetEncoded & lhs, const NetEncoded & rhs) {
return lhs.mValue != rhs.mValue;
}
T mValue;
};
/**
* @brief Net16 holds a 16-bit network-encoded value.
*/
typedef NetEncoded<uint16_t> Net16;
/**
* @brief Net32 holds a 32-bit network-encoded value.
*/
typedef NetEncoded<uint32_t> Net32;
/**
* @brief NetEncode overload for creating Net16 from uint16_t
*/
inline Net16 NetEncode(uint16_t value) {
return HostToNetwork(value);
}
/**
* @brief NetEncode overload for creating Net32 from uint32_t
*/
inline Net32 NetEncode(uint32_t value) {
return HostToNetwork(value);
}
/**
* @brief NetEncode overload for creating Net16 from a 2-byte object.
* @param An 16-bit object with host-encoding that is explictly convertible to uint16_t.
*/
template<typename T>
inline Net16 NetEncode(T inValue, typename std::enable_if<sizeof (T) == sizeof (uint16_t)>::type * = 0) {
return NetEncode(static_cast<uint16_t> (inValue));
}
/**
* @brief NetEncode overload for creating Net32 from a 4-byte object.
* @param An 32-bit object with host-encoding that is explictly convertible to uint32_t.
*/
template<typename T>
inline Net32 NetEncode(T inValue, typename std::enable_if<sizeof (T) == sizeof (uint32_t)>::type * = 0) {
return NetEncode(static_cast<uint32_t> (inValue));
}
//
// Usage example
//
enum class IPProtNum : uint8_t
{
ICMP = 1,
TCP = 6,
UDP = 17
};
typedef std::array<uint8_t, 4> IPv4Address;
struct IPv4Header
{
uint8_t VersionAndIHL; // 0
uint8_t TypeOfService; // 1
Net16 TotalLength; // 2
Net16 Identification; // 4
Net16 FlagsAndFragmentOffset; // 6
uint8_t TTL; // 8
IPProtNum Protocol; // 9
Net16 HeaderChecksum; // 10
IPv4Address SourceAddress; // 12
IPv4Address DestinationAddress; // 16
};
static_assert(std::is_pod<IPv4Header>::value, "IPv4Header is not a POD type!");
static_assert(sizeof(IPv4Header) == 20, "IPv4header must have size 20.");
IPv4Header ParseIPv4Packet(const std::vector<uint8_t> & data)
{
IPv4Header hdr;
if (data.size() < sizeof(hdr)) {
throw std::logic_error("Buffer too small");
}
std::memcpy(&hdr, data.data(), sizeof(hdr));
return hdr;
}
const uint8_t cIPv4Packet[] =
{
0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x21, 0xdd, 0x0a, 0x04, 0x01, 0x9e, 0x0a, 0x04, 0x03, 0x27, 0x08, 0x00, 0x2d, 0xa2, 0x59, 0x4e, 0x00, 0x01, 0x68, 0xda, 0xd1, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x11, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
};
int main()
{
std::vector<uint8_t> data(&cIPv4Packet[0], &cIPv4Packet[0] + sizeof(cIPv4Packet));
IPv4Header hdr = ParseIPv4Packet(data);
std::cout << "Length = " << hdr.TotalLength.hostValue();
assert(hdr.TotalLength.hostValue() == sizeof(cIPv4Packet));
}
I2luY2x1ZGUgPGFycmF5PgojaW5jbHVkZSA8Y2Fzc2VydD4KI2luY2x1ZGUgPGNzdGRpbnQ+CiNpbmNsdWRlIDxjc3RyaW5nPgojaW5jbHVkZSA8aW9zdHJlYW0+CiNpbmNsdWRlIDxzdGRleGNlcHQ+CiNpbmNsdWRlIDx0eXBlX3RyYWl0cz4KI2luY2x1ZGUgPHZlY3Rvcj4KI2luY2x1ZGUgPGFycGEvaW5ldC5oPgoKCi8vIENvbnZlcnQgYmV0d2VlbiBuZXR3b3JrIGFuZCBob3N0IGVuY29kaW5nLgppbmxpbmUgdWludDhfdCAgTmV0d29ya1RvSG9zdCh1aW50OF90ICBpblZhbHVlKSB7IHJldHVybiBpblZhbHVlOyAgICAgICAgfQppbmxpbmUgdWludDE2X3QgTmV0d29ya1RvSG9zdCh1aW50MTZfdCBpblZhbHVlKSB7IHJldHVybiBudG9ocyhpblZhbHVlKTsgfQppbmxpbmUgdWludDMyX3QgTmV0d29ya1RvSG9zdCh1aW50MzJfdCBpblZhbHVlKSB7IHJldHVybiBudG9obChpblZhbHVlKTsgfQppbmxpbmUgdWludDhfdCAgSG9zdFRvTmV0d29yayh1aW50OF90ICBpblZhbHVlKSB7IHJldHVybiBpblZhbHVlOyAgICAgICAgfQppbmxpbmUgdWludDE2X3QgSG9zdFRvTmV0d29yayh1aW50MTZfdCBpblZhbHVlKSB7IHJldHVybiBodG9ucyhpblZhbHVlKTsgfQppbmxpbmUgdWludDMyX3QgSG9zdFRvTmV0d29yayh1aW50MzJfdCBpblZhbHVlKSB7IHJldHVybiBodG9ubChpblZhbHVlKTsgfQoKCi8qKgogKiBAYnJpZWYgVGhlIE5ldEVuY29kZWQgY2xhc3Mgd3JhcHMgYSBuZXR3b3JrLWVuY29kZWQgdmFsdWUuCiAqIENhbiBiZSBjb25zdHJ1Y3RlZCBmcm9tIGEgaG9zdC1lbmNvZGVkIHZhbHVlIHVzaW5nIHRoZSAiTmV0RW5jb2RlIiBmYWN0b3J5IGZ1bmN0aW9uLgogKiBUaGlzIGNsYXNzIG1lZXRzIHBvZCByZXF1aXJlbWVudHMgYW5kIGNhbiBiZSB1c2VkIHRvIHJlcHJlc2VudCBmaWVsZHMgaW4gcGFja2V0IGhlYWRlcnMuCiAqLwp0ZW1wbGF0ZTx0eXBlbmFtZSBUPgpjbGFzcyBOZXRFbmNvZGVkIHsKcHVibGljOgogICAgTmV0RW5jb2RlZCgpID0gZGVmYXVsdDsKCiAgICBUIGhvc3RWYWx1ZSgpIGNvbnN0IHsKICAgICAgICByZXR1cm4gTmV0d29ya1RvSG9zdChtVmFsdWUpOwogICAgfQoKcHJpdmF0ZToKICAgIGZyaWVuZCBOZXRFbmNvZGVkPHVpbnQxNl90PiBOZXRFbmNvZGUodWludDE2X3QpOwogICAgZnJpZW5kIE5ldEVuY29kZWQ8dWludDMyX3Q+IE5ldEVuY29kZSh1aW50MzJfdCk7CiAgICBmcmllbmQgTmV0RW5jb2RlZDx1aW50NjRfdD4gTmV0RW5jb2RlKHVpbnQ2NF90KTsKCiAgICBOZXRFbmNvZGVkKGNvbnN0IFQgJiBpblZhbHVlKSA6IG1WYWx1ZShpblZhbHVlKQogICAgewogICAgfQoKICAgIGZyaWVuZCBib29sIG9wZXJhdG9yPChjb25zdCBOZXRFbmNvZGVkICYgbGhzLCBjb25zdCBOZXRFbmNvZGVkICYgcmhzKSB7CiAgICAgICAgcmV0dXJuIGxocy5tVmFsdWUgPCByaHMubVZhbHVlOwogICAgfQoKICAgIGZyaWVuZCBib29sIG9wZXJhdG9yPT0oY29uc3QgTmV0RW5jb2RlZCAmIGxocywgY29uc3QgTmV0RW5jb2RlZCAmIHJocykgewogICAgICAgIHJldHVybiBsaHMubVZhbHVlID09IHJocy5tVmFsdWU7CiAgICB9CgogICAgZnJpZW5kIGJvb2wgb3BlcmF0b3IhPShjb25zdCBOZXRFbmNvZGVkICYgbGhzLCBjb25zdCBOZXRFbmNvZGVkICYgcmhzKSB7CiAgICAgICAgcmV0dXJuIGxocy5tVmFsdWUgIT0gcmhzLm1WYWx1ZTsKICAgIH0KCiAgICBUIG1WYWx1ZTsKfTsKCgovKioKICogQGJyaWVmIE5ldDE2IGhvbGRzIGEgMTYtYml0IG5ldHdvcmstZW5jb2RlZCB2YWx1ZS4KICovCnR5cGVkZWYgTmV0RW5jb2RlZDx1aW50MTZfdD4gTmV0MTY7CgoKLyoqCiAqIEBicmllZiBOZXQzMiBob2xkcyBhIDMyLWJpdCBuZXR3b3JrLWVuY29kZWQgdmFsdWUuCiAqLwp0eXBlZGVmIE5ldEVuY29kZWQ8dWludDMyX3Q+IE5ldDMyOwoKCi8qKgogKiBAYnJpZWYgTmV0RW5jb2RlIG92ZXJsb2FkIGZvciBjcmVhdGluZyBOZXQxNiBmcm9tIHVpbnQxNl90CiAqLwppbmxpbmUgTmV0MTYgTmV0RW5jb2RlKHVpbnQxNl90IHZhbHVlKSB7CiAgICByZXR1cm4gSG9zdFRvTmV0d29yayh2YWx1ZSk7Cn0KCgovKioKICogQGJyaWVmIE5ldEVuY29kZSBvdmVybG9hZCBmb3IgY3JlYXRpbmcgTmV0MzIgZnJvbSB1aW50MzJfdAogKi8KaW5saW5lIE5ldDMyIE5ldEVuY29kZSh1aW50MzJfdCB2YWx1ZSkgewogICAgcmV0dXJuIEhvc3RUb05ldHdvcmsodmFsdWUpOwp9CgoKLyoqCiAqIEBicmllZiBOZXRFbmNvZGUgb3ZlcmxvYWQgZm9yIGNyZWF0aW5nIE5ldDE2IGZyb20gYSAyLWJ5dGUgb2JqZWN0LgogKiBAcGFyYW0gQW4gMTYtYml0IG9iamVjdCB3aXRoIGhvc3QtZW5jb2RpbmcgdGhhdCBpcyBleHBsaWN0bHkgY29udmVydGlibGUgdG8gdWludDE2X3QuCiAqLwp0ZW1wbGF0ZTx0eXBlbmFtZSBUPgppbmxpbmUgTmV0MTYgTmV0RW5jb2RlKFQgaW5WYWx1ZSwgdHlwZW5hbWUgc3RkOjplbmFibGVfaWY8c2l6ZW9mIChUKSA9PSBzaXplb2YgKHVpbnQxNl90KT46OnR5cGUgKiA9IDApIHsKICAgIHJldHVybiBOZXRFbmNvZGUoc3RhdGljX2Nhc3Q8dWludDE2X3Q+IChpblZhbHVlKSk7Cn0KCgovKioKICogQGJyaWVmIE5ldEVuY29kZSBvdmVybG9hZCBmb3IgY3JlYXRpbmcgTmV0MzIgZnJvbSBhIDQtYnl0ZSBvYmplY3QuCiAqIEBwYXJhbSBBbiAzMi1iaXQgb2JqZWN0IHdpdGggaG9zdC1lbmNvZGluZyB0aGF0IGlzIGV4cGxpY3RseSBjb252ZXJ0aWJsZSB0byB1aW50MzJfdC4KICovCnRlbXBsYXRlPHR5cGVuYW1lIFQ+CmlubGluZSBOZXQzMiBOZXRFbmNvZGUoVCBpblZhbHVlLCB0eXBlbmFtZSBzdGQ6OmVuYWJsZV9pZjxzaXplb2YgKFQpID09IHNpemVvZiAodWludDMyX3QpPjo6dHlwZSAqID0gMCkgewogICAgcmV0dXJuIE5ldEVuY29kZShzdGF0aWNfY2FzdDx1aW50MzJfdD4gKGluVmFsdWUpKTsKfQoKCi8vCi8vIFVzYWdlIGV4YW1wbGUKLy8KZW51bSBjbGFzcyBJUFByb3ROdW0gOiB1aW50OF90CnsKICAgIElDTVAgPSAxLAogICAgVENQICA9IDYsCiAgICBVRFAgID0gMTcKfTsKCnR5cGVkZWYgc3RkOjphcnJheTx1aW50OF90LCA0PiBJUHY0QWRkcmVzczsKCnN0cnVjdCBJUHY0SGVhZGVyCnsKICAgIHVpbnQ4X3QgICAgIFZlcnNpb25BbmRJSEw7IC8vIDAKICAgIHVpbnQ4X3QgICAgIFR5cGVPZlNlcnZpY2U7IC8vIDEKICAgIE5ldDE2ICAgICAgIFRvdGFsTGVuZ3RoOyAgIC8vIDIKICAgIE5ldDE2ICAgICAgIElkZW50aWZpY2F0aW9uOyAvLyA0CiAgICBOZXQxNiAgICAgICBGbGFnc0FuZEZyYWdtZW50T2Zmc2V0OyAvLyA2CiAgICB1aW50OF90ICAgICBUVEw7IC8vIDgKICAgIElQUHJvdE51bSAgIFByb3RvY29sOyAvLyA5CiAgICBOZXQxNiAgICAgICBIZWFkZXJDaGVja3N1bTsgLy8gMTAKICAgIElQdjRBZGRyZXNzIFNvdXJjZUFkZHJlc3M7IC8vIDEyCiAgICBJUHY0QWRkcmVzcyBEZXN0aW5hdGlvbkFkZHJlc3M7IC8vIDE2Cn07CgoKc3RhdGljX2Fzc2VydChzdGQ6OmlzX3BvZDxJUHY0SGVhZGVyPjo6dmFsdWUsICJJUHY0SGVhZGVyIGlzIG5vdCBhIFBPRCB0eXBlISIpOwpzdGF0aWNfYXNzZXJ0KHNpemVvZihJUHY0SGVhZGVyKSA9PSAyMCwgIklQdjRoZWFkZXIgbXVzdCBoYXZlIHNpemUgMjAuIik7CgoKSVB2NEhlYWRlciBQYXJzZUlQdjRQYWNrZXQoY29uc3Qgc3RkOjp2ZWN0b3I8dWludDhfdD4gJiBkYXRhKQp7CglJUHY0SGVhZGVyIGhkcjsJCglpZiAoZGF0YS5zaXplKCkgPCBzaXplb2YoaGRyKSkgewoJCXRocm93IHN0ZDo6bG9naWNfZXJyb3IoIkJ1ZmZlciB0b28gc21hbGwiKTsKCX0KCXN0ZDo6bWVtY3B5KCZoZHIsIGRhdGEuZGF0YSgpLCBzaXplb2YoaGRyKSk7CglyZXR1cm4gaGRyOwp9CgoKY29uc3QgdWludDhfdCBjSVB2NFBhY2tldFtdID0KewogICAgMHg0NSwgMHgwMCwgMHgwMCwgMHg1NCwgMHgwMCwgMHgwMCwgMHg0MCwgMHgwMCwgMHg0MCwgMHgwMSwgMHgyMSwgMHhkZCwgMHgwYSwgMHgwNCwgMHgwMSwgMHg5ZSwgMHgwYSwgMHgwNCwgMHgwMywgMHgyNywgMHgwOCwgMHgwMCwgMHgyZCwgMHhhMiwgMHg1OSwgMHg0ZSwgMHgwMCwgMHgwMSwgMHg2OCwgMHhkYSwgMHhkMSwgMHg0ZiwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCwgMHg2ZCwgMHgxMSwgMHgwYiwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCwgMHgxMCwgMHgxMSwgMHgxMiwgMHgxMywgMHgxNCwgMHgxNSwgMHgxNiwgMHgxNywgMHgxOCwgMHgxOSwgMHgxYSwgMHgxYiwgMHgxYywgMHgxZCwgMHgxZSwgMHgxZiwgMHgyMCwgMHgyMSwgMHgyMiwgMHgyMywgMHgyNCwgMHgyNSwgMHgyNiwgMHgyNywgMHgyOCwgMHgyOSwgMHgyYSwgMHgyYiwgMHgyYywgMHgyZCwgMHgyZSwgMHgyZiwgMHgzMCwgMHgzMSwgMHgzMiwgMHgzMywgMHgzNCwgMHgzNSwgMHgzNiwgMHgzNwp9OwoKaW50IG1haW4oKQp7CglzdGQ6OnZlY3Rvcjx1aW50OF90PiBkYXRhKCZjSVB2NFBhY2tldFswXSwgJmNJUHY0UGFja2V0WzBdICsgc2l6ZW9mKGNJUHY0UGFja2V0KSk7CglJUHY0SGVhZGVyIGhkciA9IFBhcnNlSVB2NFBhY2tldChkYXRhKTsKCXN0ZDo6Y291dCA8PCAiTGVuZ3RoID0gIiA8PCBoZHIuVG90YWxMZW5ndGguaG9zdFZhbHVlKCk7Cglhc3NlcnQoaGRyLlRvdGFsTGVuZ3RoLmhvc3RWYWx1ZSgpID09IHNpemVvZihjSVB2NFBhY2tldCkpOwp9