From 71c99654718e53cdaf0900be2b1555b7ec7e6daf Mon Sep 17 00:00:00 2001 From: cathugger Date: Wed, 10 Oct 2018 21:29:49 +0000 Subject: [PATCH] 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. --- include/llarp/ip.hpp | 8 +-- llarp/handlers/tun.cpp | 11 ++-- llarp/ip.cpp | 139 +++++++++++++++++++++-------------------- 3 files changed, 79 insertions(+), 79 deletions(-) diff --git a/include/llarp/ip.hpp b/include/llarp/ip.hpp index ade2471a0..fa43934d7 100644 --- a/include/llarp/ip.hpp +++ b/include/llarp/ip.hpp @@ -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 diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 1fdf0ef62..8826cde56 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -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; })) diff --git a/llarp/ip.cpp b/llarp/ip.cpp index 0278c825b..167e96a28 100644 --- a/llarp/ip.cpp +++ b/llarp/ip.cpp @@ -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