#pragma once #include #include "net.hpp" #include #include #include #include #include namespace llarp::net { template struct ip_header_le { unsigned int ihl : 4; unsigned int version : 4; uint8_t tos; uint16_t tot_len; uint16_t id; uint16_t frag_off; uint8_t ttl; uint8_t protocol; uint16_t check; uint32_t saddr; uint32_t daddr; }; template <> struct ip_header_le { unsigned int version : 4; unsigned int ihl : 4; uint8_t tos; uint16_t tot_len; uint16_t id; uint16_t frag_off; uint8_t ttl; uint8_t protocol; uint16_t check; uint32_t saddr; uint32_t daddr; }; using ip_header = ip_header_le; template struct ipv6_header_preamble_le { unsigned char pad_small : 4; unsigned char version : 4; uint8_t pad[3]; }; template <> struct ipv6_header_preamble_le { unsigned char version : 4; unsigned char pad_small : 4; uint8_t pad[3]; }; struct ipv6_header { union { ipv6_header_preamble_le preamble; uint32_t flowlabel; } preamble; uint16_t payload_len; uint8_t proto; uint8_t hoplimit; in6_addr srcaddr; in6_addr dstaddr; llarp::nuint32_t FlowLabel() const; /// put 20 bit truncated flow label network order void FlowLabel(llarp::nuint32_t label); }; /// "well known" ip protocols /// TODO: extend this to non "well known values" enum class IPProtocol : uint8_t { ICMP = 0x01, IGMP = 0x02, IPIP = 0x04, TCP = 0x06, UDP = 0x11, GRE = 0x2F, ICMP6 = 0x3A, OSFP = 0x59, PGM = 0x71, }; /// get string representation of this protocol /// throws std::invalid_argument if we don't know the name of this ip protocol std::string IPProtocolName(IPProtocol proto); /// parse a string to an ip protocol /// throws std::invalid_argument if cannot be parsed IPProtocol ParseIPProtocol(std::string data); /// an Packet struct IPPacket { static constexpr size_t MaxSize = 1500; llarp_time_t timestamp; size_t sz; alignas(ip_header) byte_t buf[MaxSize]; static IPPacket UDP(nuint32_t srcaddr, nuint16_t srcport, nuint32_t dstaddr, nuint16_t dstport, const llarp_buffer_t& data); ManagedBuffer Buffer(); ManagedBuffer ConstBuffer() const; bool Load(const llarp_buffer_t& buf); struct CompareSize { bool operator()(const IPPacket& left, const IPPacket& right) { return left.sz < right.sz; } }; struct CompareOrder { bool operator()(const IPPacket& left, const IPPacket& right) { return left.timestamp < right.timestamp; } }; inline ip_header* Header() { return reinterpret_cast(&buf[0]); } inline const ip_header* Header() const { return reinterpret_cast(&buf[0]); } inline ipv6_header* HeaderV6() { return reinterpret_cast(&buf[0]); } inline const ipv6_header* HeaderV6() const { return reinterpret_cast(&buf[0]); } inline int Version() const { return Header()->version; } inline bool IsV4() const { return Version() == 4; } inline bool IsV6() const { return Version() == 6; } inline service::ProtocolType ServiceProtocol() const { if (IsV4()) return service::ProtocolType::TrafficV4; if (IsV6()) return service::ProtocolType::TrafficV6; return service::ProtocolType::Control; } huint128_t srcv6() const; huint128_t dstv6() const; huint32_t srcv4() const; huint32_t dstv4() const; huint128_t src4to6() const; huint128_t dst4to6() const; huint128_t src4to6Lan() const; huint128_t dst4to6Lan() const; /// get destination port if applicable std::optional DstPort() const; /// get source port if applicable std::optional SrcPort() const; /// get pointer and size of layer 4 data std::optional> L4Data() const; void UpdateIPv4Address(nuint32_t src, nuint32_t dst); void UpdateIPv6Address( huint128_t src, huint128_t dst, std::optional flowlabel = std::nullopt); /// set addresses to zero and recacluate checksums void ZeroAddresses(std::optional flowlabel = std::nullopt); /// zero out source address void ZeroSourceAddress(std::optional flowlabel = std::nullopt); /// make an icmp unreachable reply packet based of this ip packet std::optional MakeICMPUnreachable() const; }; /// generate ip checksum uint16_t ipchksum(const byte_t* buf, size_t sz, uint32_t sum = 0); } // namespace llarp::net