add {h,n}uint16_t types, optimize TCP/UDP checksuming

use static functions + switch instead of lambda functions + map.
pull/26/head
cathugger 6 years ago
parent 252b2ee3fb
commit 18c20396b6
No known key found for this signature in database
GPG Key ID: 9BADDA2DAF6F01A8

@ -57,18 +57,23 @@ namespace llarp
{
uint32_t h;
constexpr huint32_t operator &(huint32_t x) const { return huint32_t{h & x.h}; }
constexpr huint32_t operator |(huint32_t x) const { return huint32_t{h | x.h}; }
constexpr huint32_t operator ~() const { return huint32_t{~h}; }
constexpr huint32_t
operator &(huint32_t x) const { return huint32_t{uint32_t(h & x.h)}; }
constexpr huint32_t
operator |(huint32_t x) const { return huint32_t{uint32_t(h | x.h)}; }
constexpr huint32_t
operator ~() const { return huint32_t{uint32_t(~h)}; }
inline huint32_t operator ++() { ++h; return *this; }
inline huint32_t operator --() { --h; return *this; }
constexpr bool operator <(huint32_t x) const { return h < x.h; }
constexpr bool operator ==(huint32_t x) const { return h == x.h; }
struct Hash
{
inline size_t
operator()(huint32_t x) const
operator ()(huint32_t x) const
{
return std::hash< uint32_t >{}(x.h);
}
@ -79,36 +84,107 @@ namespace llarp
{
uint32_t n;
constexpr nuint32_t operator &(nuint32_t x) const { return nuint32_t{n & x.n}; }
constexpr nuint32_t operator |(nuint32_t x) const { return nuint32_t{n | x.n}; }
constexpr nuint32_t operator ~() const { return nuint32_t{~n}; }
constexpr nuint32_t
operator &(nuint32_t x) const { return nuint32_t{uint32_t(n & x.n)}; }
constexpr nuint32_t
operator |(nuint32_t x) const { return nuint32_t{uint32_t(n | x.n)}; }
constexpr nuint32_t
operator ~() const { return nuint32_t{uint32_t(~n)}; }
inline nuint32_t operator ++() { ++n; return *this; }
inline nuint32_t operator --() { --n; return *this; }
constexpr bool operator <(nuint32_t x) const { return n < x.n; }
constexpr bool operator ==(nuint32_t x) const { return n == x.n; }
struct Hash
{
inline size_t
operator()(nuint32_t x) const
operator ()(nuint32_t x) const
{
return std::hash< uint32_t >{}(x.n);
}
};
};
struct huint16_t
{
uint16_t h;
constexpr huint16_t
operator &(huint16_t x) const { return huint16_t{uint16_t(h & x.h)}; }
constexpr huint16_t
operator |(huint16_t x) const { return huint16_t{uint16_t(h | x.h)}; }
constexpr huint16_t
operator ~() const { return huint16_t{uint16_t(~h)}; }
inline huint16_t operator ++() { ++h; return *this; }
inline huint16_t operator --() { --h; return *this; }
constexpr bool operator <(huint16_t x) const { return h < x.h; }
constexpr bool operator ==(huint16_t x) const { return h == x.h; }
struct Hash
{
inline size_t
operator ()(huint16_t x) const
{
return std::hash< uint16_t >{}(x.h);
}
};
};
struct nuint16_t
{
uint16_t n;
constexpr nuint16_t
operator &(nuint16_t x) const { return nuint16_t{uint16_t(n & x.n)}; }
constexpr nuint16_t
operator |(nuint16_t x) const { return nuint16_t{uint16_t(n | x.n)}; }
constexpr nuint16_t
operator ~() const { return nuint16_t{uint16_t(~n)}; }
inline nuint16_t operator ++() { ++n; return *this; }
inline nuint16_t operator --() { --n; return *this; }
constexpr bool operator <(nuint16_t x) const { return n < x.n; }
constexpr bool operator ==(nuint16_t x) const { return n == x.n; }
struct Hash
{
inline size_t
operator ()(nuint16_t x) const
{
return std::hash< uint16_t >{}(x.n);
}
};
};
// clang-format on
static inline nuint32_t
xhtonl(huint32_t x)
{
return nuint32_t{htonl(x.h)};
}
static inline huint32_t
xntohl(nuint32_t x)
{
return huint32_t{ntohl(x.n)};
}
static inline nuint32_t
xhtonl(huint32_t x)
static inline nuint16_t
xhtons(huint16_t x)
{
return nuint32_t{htonl(x.h)};
return nuint16_t{htons(x.h)};
}
static inline huint16_t
xntohs(nuint16_t x)
{
return huint16_t{ntohs(x.n)};
}
struct Addr

@ -76,68 +76,59 @@ namespace llarp
return htons(sum);
}
static std::map<
byte_t,
std::function< void(const ip_header *ohdr, byte_t *pld, size_t psz,
huint32_t oSrcIP, huint32_t oDstIP,
huint32_t nSrcIP, huint32_t nDstIP) > >
protoDstCheckSummer = {
// {RFC3022} says that IPv4 hdr isn't included in ICMP checksum calc
// and that we don't need to modify it
{// TCP
6,
[](const ip_header *ohdr, byte_t *pld, size_t psz,
huint32_t oSrcIP, huint32_t oDstIP, huint32_t nSrcIP,
huint32_t nDstIP) {
uint16_t *check = (uint16_t *)(pld + 16);
*check = deltachksum(*check, oSrcIP, oDstIP, nSrcIP, nDstIP);
}},
{// UDP
17,
[](const ip_header *ohdr, byte_t *pld, size_t psz,
huint32_t oSrcIP, huint32_t oDstIP, huint32_t nSrcIP,
huint32_t nDstIP) {
uint16_t *check = (uint16_t *)(pld + 6);
if(*check != 0xFFff)
{
if(*check == 0x0000)
return; // don't change zero
*check = deltachksum(*check, oSrcIP, oDstIP, nSrcIP, nDstIP);
if(*check == 0x0000)
*check = 0xFFff;
}
else
{
// such checksum can mean 2 things: 0x0000 or 0xFFff
// we can only know by looking at data :<
auto pakcs = *check; // save
*check = 0; // zero checksum before calculation
auto cs = ipchksum(
pld, psz,
static void
checksumDstTCP(byte_t *pld, size_t psz, huint32_t oSrcIP, huint32_t oDstIP,
huint32_t nSrcIP, huint32_t nDstIP)
{
uint16_t *check = (uint16_t *)(pld + 16);
*check = deltachksum(*check, oSrcIP, oDstIP, nSrcIP, nDstIP);
}
static void
checksumDstUDP(const ip_header *ohdr, byte_t *pld, size_t psz,
huint32_t oSrcIP, huint32_t oDstIP, huint32_t nSrcIP,
huint32_t nDstIP)
{
uint16_t *check = (uint16_t *)(pld + 6);
if(*check != 0xFFff)
{
if(*check == 0x0000)
return; // don't change zero
*check = deltachksum(*check, oSrcIP, oDstIP, nSrcIP, nDstIP);
if(*check == 0x0000)
*check = 0xFFff;
}
else
{
// such checksum can mean 2 things: 0x0000 or 0xFFff
// we can only know by looking at data :<
auto pakcs = *check; // save
*check = 0; // zero checksum before calculation
auto cs =
ipchksum(pld, psz,
ipchksum_pseudoIPv4(nuint32_t{ohdr->saddr},
nuint32_t{ohdr->daddr}, 17, psz));
auto new_cs = deltachksum(cs, oSrcIP, oDstIP, nSrcIP, nDstIP);
if(cs != 0x0000 && cs != 0xFFff)
{
// packet was bad - sabotage new checksum
new_cs += pakcs - cs;
}
// 0x0000 is reserved for no checksum
if(new_cs == 0x0000)
new_cs = 0xFFff;
// put it in
*check = new_cs;
}
}},
};
auto new_cs = deltachksum(cs, oSrcIP, oDstIP, nSrcIP, nDstIP);
if(cs != 0x0000 && cs != 0xFFff)
{
// packet was bad - sabotage new checksum
new_cs += pakcs - cs;
}
// 0x0000 is reserved for no checksum
if(new_cs == 0x0000)
new_cs = 0xFFff;
// put it in
*check = new_cs;
}
}
void
IPv4Packet::UpdatePacketOnDst(huint32_t nSrcIP, huint32_t nDstIP)
{
@ -151,11 +142,17 @@ namespace llarp
// L4 checksum
auto proto = hdr->protocol;
auto itr = protoDstCheckSummer.find(proto);
size_t ihs;
if(itr != protoDstCheckSummer.end() && (ihs = size_t(hdr->ihl * 4)) <= sz)
auto ihs = size_t(hdr->ihl * 4);
auto pld = buf + ihs;
auto psz = sz - ihs;
switch(proto)
{
itr->second(hdr, buf + ihs, sz - ihs, oSrcIP, oDstIP, nSrcIP, nDstIP);
case 6:
checksumDstTCP(pld, psz, oSrcIP, oDstIP, nSrcIP, nDstIP);
break;
case 17:
checksumDstUDP(hdr, pld, psz, oSrcIP, oDstIP, nSrcIP, nDstIP);
break;
}
// write new IP addresses
@ -163,65 +160,59 @@ namespace llarp
hdr->daddr = xhtonl(nDstIP).n;
}
static std::map<
byte_t,
std::function< void(const ip_header *ohdr, byte_t *pld, size_t psz,
huint32_t oSrcIP, huint32_t oDstIP) > >
protoSrcCheckSummer = {
{// TCP
6,
[](const ip_header *ohdr, byte_t *pld, size_t psz,
huint32_t oSrcIP, huint32_t oDstIP) {
uint16_t *check = (uint16_t *)(pld + 16);
*check = deltachksum(*check, oSrcIP, oDstIP, huint32_t{0},
huint32_t{0});
}},
{// UDP
17,
[](const ip_header *ohdr, byte_t *pld, size_t psz,
huint32_t oSrcIP, huint32_t oDstIP) {
uint16_t *check = (uint16_t *)(pld + 6);
if(*check != 0xFFff)
{
if(*check == 0x0000)
return; // don't change zero
*check = deltachksum(*check, oSrcIP, oDstIP, huint32_t{0},
huint32_t{0});
if(*check == 0x0000)
*check = 0xFFff;
}
else
{
// such checksum can mean 2 things: 0x0000 or 0xFFff
// we can only know by looking at data :<
auto pakcs = *check; // save
*check = 0; // zero checksum before calculation
auto cs = ipchksum(
pld, psz,
static void
checksumSrcTCP(byte_t *pld, size_t psz, huint32_t oSrcIP, huint32_t oDstIP)
{
uint16_t *check = (uint16_t *)(pld + 16);
*check = deltachksum(*check, oSrcIP, oDstIP, huint32_t{0}, huint32_t{0});
}
static void
checksumSrcUDP(const ip_header *ohdr, byte_t *pld, size_t psz,
huint32_t oSrcIP, huint32_t oDstIP)
{
uint16_t *check = (uint16_t *)(pld + 6);
if(*check != 0xFFff)
{
if(*check == 0x0000)
return; // don't change zero
*check =
deltachksum(*check, oSrcIP, oDstIP, huint32_t{0}, huint32_t{0});
if(*check == 0x0000)
*check = 0xFFff;
}
else
{
// such checksum can mean 2 things: 0x0000 or 0xFFff
// we can only know by looking at data :<
auto pakcs = *check; // save
*check = 0; // zero checksum before calculation
auto cs =
ipchksum(pld, psz,
ipchksum_pseudoIPv4(nuint32_t{ohdr->saddr},
nuint32_t{ohdr->daddr}, 17, psz));
auto new_cs = deltachksum(cs, oSrcIP, oDstIP, huint32_t{0},
huint32_t{0});
if(cs != 0x0000 && cs != 0xFFff)
{
// packet was bad - sabotage new checksum
new_cs += pakcs - cs;
}
// 0x0000 is reserved for no checksum
if(new_cs == 0x0000)
new_cs = 0xFFff;
// put it in
*check = new_cs;
}
}},
};
auto new_cs =
deltachksum(cs, oSrcIP, oDstIP, huint32_t{0}, huint32_t{0});
if(cs != 0x0000 && cs != 0xFFff)
{
// packet was bad - sabotage new checksum
new_cs += pakcs - cs;
}
// 0x0000 is reserved for no checksum
if(new_cs == 0x0000)
new_cs = 0xFFff;
// put it in
*check = new_cs;
}
}
void
IPv4Packet::UpdatePacketOnSrc()
{
@ -232,11 +223,17 @@ namespace llarp
// L4
auto proto = hdr->protocol;
auto itr = protoSrcCheckSummer.find(proto);
size_t ihs;
if(itr != protoSrcCheckSummer.end() && (ihs = size_t(hdr->ihl * 4)) <= sz)
auto ihs = size_t(hdr->ihl * 4);
auto pld = buf + ihs;
auto psz = sz - ihs;
switch(proto)
{
itr->second(hdr, buf + ihs, sz - ihs, oSrcIP, oDstIP);
case 6:
checksumSrcTCP(pld, psz, oSrcIP, oDstIP);
break;
case 17:
checksumSrcUDP(hdr, pld, psz, oSrcIP, oDstIP);
break;
}
// IPv4

Loading…
Cancel
Save