ip: code cleanups and compatibility improvements

do not assume that packets come with address zero-ed, older clients don't do that.
they don't modify checksum either, therefore we should be able to get correct checksum if we use deltachksum with old and new addresses.
pull/25/head
cathugger 6 years ago
parent e0c6404830
commit 71c9965471
No known key found for this signature in database
GPG Key ID: 9BADDA2DAF6F01A8

@ -153,13 +153,13 @@ namespace llarp
Header()->daddr = htonl(ip.h);
}
// update ip packet checksum (after packet gets out of network)
// update ip packet (after packet gets out of network)
void
UpdateChecksumsOnDst();
UpdatePacketOnDst(huint32_t nsrcIP, huint32_t ndstIP);
// update ip packet checksum (before packet gets inserted into network)
// update ip packet (before packet gets inserted into network)
void
UpdateChecksumsOnSrc();
UpdatePacketOnSrc();
};
} // namespace net

@ -313,10 +313,8 @@ namespace llarp
}
// prepare packet for insertion into network
pkt.UpdateChecksumsOnSrc();
// clear addresses
pkt.src(huint32_t{0});
pkt.dst(huint32_t{0});
// this includes clearing IP addresses, recalculating checksums, etc
pkt.UpdatePacketOnSrc();
if(!SendToOrQueue(itr->second, pkt.Buffer(), service::eProtocolTraffic))
{
@ -338,9 +336,8 @@ namespace llarp
// TODO: don't truncate packet here
pkt.sz = std::min(buf.sz, sizeof(pkt.buf));
memcpy(pkt.buf, buf.base, pkt.sz);
pkt.src(themIP);
pkt.dst(usIP);
pkt.UpdateChecksumsOnDst();
// update packet to use proper addresses, recalc checksums
pkt.UpdatePacketOnDst(themIP, usIP);
return true;
}))

@ -77,35 +77,34 @@ namespace llarp
}
static std::map<
byte_t, std::function< void(const ip_header *, byte_t *, size_t) > >
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 *hdr, byte_t *pkt, size_t sz) {
auto hlen = size_t(hdr->ihl * 4);
[](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);
uint16_t *check = (uint16_t *)(pkt + hlen + 16);
*check = deltachksum(*check, huint32_t{0}, huint32_t{0},
xntohl(nuint32_t{hdr->saddr}),
xntohl(nuint32_t{hdr->daddr}));
*check = deltachksum(*check, oSrcIP, oDstIP, nSrcIP, nDstIP);
}},
{// UDP
17,
[](const ip_header *hdr, byte_t *pkt, size_t sz) {
auto hlen = size_t(hdr->ihl * 4);
uint16_t *check = (uint16_t *)(pkt + hlen + 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 + 6);
if(*check != 0xFFff)
{
if(*check == 0x0000)
return; // don't change zero
*check = deltachksum(*check, huint32_t{0}, huint32_t{0},
xntohl(nuint32_t{hdr->saddr}),
xntohl(nuint32_t{hdr->daddr}));
*check = deltachksum(*check, oSrcIP, oDstIP, nSrcIP, nDstIP);
if(*check == 0x0000)
*check = 0xFFff;
}
@ -113,83 +112,83 @@ namespace llarp
{
// such checksum can mean 2 things: 0x0000 or 0xFFff
// we can only know by looking at data :<
if(hlen > sz)
return; // malformed, bail out
auto oldcs = *check;
auto pakcs = *check; // save
*check = 0; // zero checksum before calculation
auto cs =
ipchksum(pkt + hlen, sz - hlen,
ipchksum_pseudoIPv4(nuint32_t{0}, nuint32_t{0},
17, sz - hlen));
auto cs = ipchksum(
pld, psz,
ipchksum_pseudoIPv4(nuint32_t{ohdr->saddr},
nuint32_t{ohdr->daddr}, 17, psz));
auto mod_cs = deltachksum(cs, huint32_t{0}, huint32_t{0},
xntohl(nuint32_t{hdr->saddr}),
xntohl(nuint32_t{hdr->daddr}));
auto new_cs = deltachksum(cs, oSrcIP, oDstIP, nSrcIP, nDstIP);
if(cs != 0x0000 && cs != 0xFFff)
{
// packet was bad - sabotage new checksum
mod_cs += cs - oldcs;
new_cs += pakcs - cs;
}
// 0x0000 is reserved for no checksum
if(mod_cs == 0x0000)
mod_cs = 0xFFff;
if(new_cs == 0x0000)
new_cs = 0xFFff;
// put it in
*check = mod_cs;
*check = new_cs;
}
}},
};
void
IPv4Packet::UpdateChecksumsOnDst()
IPv4Packet::UpdatePacketOnDst(huint32_t nSrcIP, huint32_t nDstIP)
{
auto hdr = Header();
auto oSrcIP = xntohl(nuint32_t{hdr->saddr});
auto oDstIP = xntohl(nuint32_t{hdr->daddr});
// IPv4 checksum
hdr->check = deltachksum(hdr->check, huint32_t{0}, huint32_t{0},
xntohl(nuint32_t{hdr->saddr}),
xntohl(nuint32_t{hdr->daddr}));
hdr->check = deltachksum(hdr->check, oSrcIP, oDstIP, nSrcIP, nDstIP);
// L4 checksum
auto proto = hdr->protocol;
auto itr = protoDstCheckSummer.find(proto);
if(itr != protoDstCheckSummer.end())
size_t ihs;
if(itr != protoDstCheckSummer.end() && (ihs = size_t(hdr->ihl * 4)) <= sz)
{
itr->second(hdr, buf, sz);
itr->second(hdr, buf + ihs, sz - ihs, oSrcIP, oDstIP, nSrcIP, nDstIP);
}
// write new IP addresses
hdr->saddr = xhtonl(nSrcIP).n;
hdr->daddr = xhtonl(nDstIP).n;
}
static std::map<
byte_t, std::function< void(const ip_header *, byte_t *, size_t) > >
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 *hdr, byte_t *pkt, size_t sz) {
auto hlen = size_t(hdr->ihl * 4);
[](const ip_header *ohdr, byte_t *pld, size_t psz,
huint32_t oSrcIP, huint32_t oDstIP) {
uint16_t *check = (uint16_t *)(pld + 16);
uint16_t *check = (uint16_t *)(pkt + hlen + 16);
*check = deltachksum(*check, xntohl(nuint32_t{hdr->saddr}),
xntohl(nuint32_t{hdr->daddr}), huint32_t{0},
*check = deltachksum(*check, oSrcIP, oDstIP, huint32_t{0},
huint32_t{0});
}},
{// UDP
17,
[](const ip_header *hdr, byte_t *pkt, size_t sz) {
auto hlen = size_t(hdr->ihl * 4);
uint16_t *check = (uint16_t *)(pkt + hlen + 6);
[](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, xntohl(nuint32_t{hdr->saddr}),
xntohl(nuint32_t{hdr->daddr}),
huint32_t{0}, huint32_t{0});
*check = deltachksum(*check, oSrcIP, oDstIP, huint32_t{0},
huint32_t{0});
if(*check == 0x0000)
*check = 0xFFff;
}
@ -197,52 +196,56 @@ namespace llarp
{
// such checksum can mean 2 things: 0x0000 or 0xFFff
// we can only know by looking at data :<
if(hlen > sz)
return; // malformed, bail out
auto oldcs = *check;
auto pakcs = *check; // save
*check = 0; // zero checksum before calculation
auto cs = ipchksum(
pkt + hlen, sz - hlen,
ipchksum_pseudoIPv4(nuint32_t{hdr->saddr},
nuint32_t{hdr->daddr}, 17, sz - hlen));
pld, psz,
ipchksum_pseudoIPv4(nuint32_t{ohdr->saddr},
nuint32_t{ohdr->daddr}, 17, psz));
auto mod_cs = deltachksum(cs, xntohl(nuint32_t{hdr->saddr}),
xntohl(nuint32_t{hdr->daddr}),
huint32_t{0}, huint32_t{0});
auto new_cs = deltachksum(cs, oSrcIP, oDstIP, huint32_t{0},
huint32_t{0});
if(cs != 0x0000 && cs != 0xFFff)
{
// packet was bad - sabotage new checksum
mod_cs += cs - oldcs;
new_cs += pakcs - cs;
}
// 0x0000 is reserved for no checksum
if(mod_cs == 0x0000)
mod_cs = 0xFFff;
if(new_cs == 0x0000)
new_cs = 0xFFff;
// put it in
*check = mod_cs;
*check = new_cs;
}
}},
};
void
IPv4Packet::UpdateChecksumsOnSrc()
IPv4Packet::UpdatePacketOnSrc()
{
auto hdr = Header();
auto oSrcIP = xntohl(nuint32_t{hdr->saddr});
auto oDstIP = xntohl(nuint32_t{hdr->daddr});
// L4
auto proto = hdr->protocol;
auto itr = protoSrcCheckSummer.find(proto);
if(itr != protoSrcCheckSummer.end())
size_t ihs;
if(itr != protoSrcCheckSummer.end() && (ihs = size_t(hdr->ihl * 4)) <= sz)
{
itr->second(hdr, buf, sz);
itr->second(hdr, buf + ihs, sz - ihs, oSrcIP, oDstIP);
}
// IPv4
hdr->check = deltachksum(hdr->check, xntohl(nuint32_t{hdr->saddr}),
xntohl(nuint32_t{hdr->daddr}), huint32_t{0},
huint32_t{0});
hdr->check =
deltachksum(hdr->check, oSrcIP, oDstIP, huint32_t{0}, huint32_t{0});
// clear addresses
hdr->saddr = 0;
hdr->daddr = 0;
}
} // namespace net
} // namespace llarp

Loading…
Cancel
Save