Merge pull request #1 from cathugger/ipv6-tun

do IPv6 checksum stuff or something
pull/686/head
Jeff 5 years ago committed by GitHub
commit 164d465057
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -613,7 +613,7 @@ namespace libuv
m_CloseFuncs.emplace_back(std::bind(&tun_glue ::Close, glue));
return true;
}
delete glue;
return false;
}

@ -127,7 +127,7 @@ namespace llarp
dst = net::IPPacket::TruncateV6(m_Parent->GetIfAddr());
else
dst = pkt.dstv4();
pkt.UpdateV4Address(net::IPPacket::TruncateV6(m_IP), dst);
pkt.UpdateIPV4Address(xhtonl(net::IPPacket::TruncateV6(m_IP)), xhtonl(dst));
}
else
{
@ -151,7 +151,7 @@ namespace llarp
src = m_Parent->GetIfAddr();
else
src = pkt.srcv6();
pkt.UpdateV6Address(src, m_IP);
pkt.UpdateIPv6Address(src, m_IP);
const llarp_buffer_t& pktbuf = pkt.Buffer(); // life time extension
const uint8_t queue_idx = pktbuf.sz / llarp::routing::ExitPadSize;
if(m_DownstreamQueues.find(queue_idx) == m_DownstreamQueues.end())

@ -451,7 +451,7 @@ namespace llarp
if(!pkt.Load(buf))
return false;
// rewrite ip
pkt.UpdateV6Address(from, m_IfAddr);
pkt.UpdateIPv6Address(from, m_IfAddr);
return llarp_ev_tun_async_write(&m_Tun, pkt.Buffer());
}

@ -714,7 +714,7 @@ namespace llarp
{
if(m_Exit && pkt.IsV4() && !llarp::IsIPv4Bogon(pkt.dstv4()))
{
pkt.UpdateV4Address({0}, pkt.dstv4());
pkt.UpdateIPv4Address({0}, xhtonl(pkt.dstv4()));
m_Exit->QueueUpstreamTraffic(std::move(pkt),
llarp::routing::ExitPadSize);
}
@ -746,9 +746,9 @@ namespace llarp
// prepare packet for insertion into network
// this includes clearing IP addresses, recalculating checksums, etc
if(pkt.IsV4())
pkt.UpdateV4Address({0}, {0});
pkt.UpdateIPv4Address({0}, {0});
else
pkt.UpdateV6Address({0}, {0});
pkt.UpdateIPv6Address({0}, {0});
if(sendFunc && sendFunc(pkt.Buffer()))
return;
@ -786,14 +786,14 @@ namespace llarp
{
return false;
}
pkt.UpdateV4Address(net::IPPacket::TruncateV6(themIP),
net::IPPacket::TruncateV6(usIP));
pkt.UpdateIPv4Address(xhtonl(net::IPPacket::TruncateV6(themIP)),
xhtonl(net::IPPacket::TruncateV6(usIP)));
}
else if(pkt.IsV6())
{
if(pkt.srcv6() != huint128_t{0} || pkt.dstv6() != huint128_t{0})
return false;
pkt.UpdateV6Address(themIP, usIP);
pkt.UpdateIPv6Address(themIP, usIP);
}
return true;
});

@ -209,19 +209,20 @@ namespace llarp
{
if(pkt.IsV4())
{
pkt.UpdateV6Address(net::IPPacket::ExpandV4(pkt.srcv4()),
m_OurIP);
pkt.UpdateIPv6Address(net::IPPacket::ExpandV4(pkt.srcv4()),
m_OurIP);
}
else
{
pkt.UpdateV6Address(pkt.srcv6(), m_OurIP);
pkt.UpdateIPv6Address(pkt.srcv6(), m_OurIP);
}
}
else
{
if(pkt.IsV4())
pkt.UpdateV4Address(pkt.srcv4(),
net::IPPacket::TruncateV6(m_OurIP));
pkt.UpdateIPv4Address(
xhtonl(pkt.srcv4()),
xhtonl(net::IPPacket::TruncateV6(m_OurIP)));
else
return false;
}

@ -102,27 +102,6 @@ namespace llarp
return huint32_t{ntohl(Header()->daddr)};
}
void
IPPacket::UpdateV6Address(huint128_t src, huint128_t dst)
{
if(sz <= 40)
return;
auto hdr = HeaderV6();
auto oldSrc = hdr->srcaddr;
auto oldDst = hdr->dstaddr;
hdr->srcaddr = HUIntToIn6(src);
hdr->dstaddr = HUIntToIn6(dst);
const size_t ihs = 40;
auto pld = buf + ihs;
auto psz = sz - ihs;
switch(hdr->proto)
{
//tcp
case 6:
return;
}
}
#if 0
static uint32_t
ipchksum_pseudoIPv4(nuint32_t src_ip, nuint32_t dst_ip, uint8_t proto,
@ -161,19 +140,49 @@ namespace llarp
}
#endif
#define ADD32CS(x) ((uint32_t)(x & 0xFFff) + (uint32_t)(x >> 16))
#define SUB32CS(x) ((uint32_t)((~x) & 0xFFff) + (uint32_t)((~x) >> 16))
static nuint16_t
deltaIPv4Checksum(nuint16_t old_sum, nuint32_t old_src_ip,
nuint32_t old_dst_ip, nuint32_t new_src_ip,
nuint32_t new_dst_ip)
{
#define ADDIPCS(x) ((uint32_t)(x.n & 0xFFff) + (uint32_t)(x.n >> 16))
#define SUBIPCS(x) ((uint32_t)((~x.n) & 0xFFff) + (uint32_t)((~x.n) >> 16))
uint32_t sum = uint32_t(old_sum.n) + ADD32CS(old_src_ip.n)
+ ADD32CS(old_dst_ip.n) + SUB32CS(new_src_ip.n)
+ SUB32CS(new_dst_ip.n);
// only need to do it 2 times to be sure
// proof: 0xFFff + 0xFFff = 0x1FFfe -> 0xFFff
sum = (sum & 0xFFff) + (sum >> 16);
sum += sum >> 16;
uint32_t sum = uint32_t(old_sum.n) + ADDIPCS(old_src_ip)
+ ADDIPCS(old_dst_ip) + SUBIPCS(new_src_ip) + SUBIPCS(new_dst_ip);
return nuint16_t{uint16_t(sum & 0xFFff)};
}
#undef ADDIPCS
#undef SUBIPCS
static nuint16_t
deltaIPv6Checksum(nuint16_t old_sum, const uint32_t old_src_ip[4],
const uint32_t old_dst_ip[4],
const uint32_t new_src_ip[4],
const uint32_t new_dst_ip[4])
{
/* we don't actually care in what way integers are arranged in memory
* internally */
/* as long as uint16 pairs are swapped in correct direction, result will
* be correct (assuming there are no gaps in structure) */
/* we represent 128bit stuff there as 4 32bit ints, that should be more or
* less correct */
/* we could do 64bit ints too but then we couldn't reuse 32bit macros and
* that'd suck for 32bit cpus */
#define ADDN128CS(x) \
(ADD32CS(x[0]) + ADD32CS(x[1]) + ADD32CS(x[2]) + ADD32CS(x[3]))
#define SUBN128CS(x) \
(SUB32CS(x[0]) + SUB32CS(x[1]) + SUB32CS(x[2]) + SUB32CS(x[3]))
uint32_t sum = uint32_t(old_sum.n) + ADDN128CS(old_src_ip)
+ ADDN128CS(old_dst_ip) + SUBN128CS(new_src_ip)
+ SUBN128CS(new_dst_ip);
#undef ADDN128CS
#undef SUBN128CS
// only need to do it 2 times to be sure
// proof: 0xFFff + 0xFFff = 0x1FFfe -> 0xFFff
@ -183,10 +192,13 @@ namespace llarp
return nuint16_t{uint16_t(sum & 0xFFff)};
}
#undef ADD32CS
#undef SUB32CS
static void
checksumDstIPv4TCP(byte_t *pld, ABSL_ATTRIBUTE_UNUSED size_t psz,
size_t fragoff, size_t chksumoff, nuint32_t oSrcIP,
nuint32_t oDstIP, nuint32_t nSrcIP, nuint32_t nDstIP)
deltaChecksumIPv4TCP(byte_t *pld, ABSL_ATTRIBUTE_UNUSED size_t psz,
size_t fragoff, size_t chksumoff, nuint32_t oSrcIP,
nuint32_t oDstIP, nuint32_t nSrcIP, nuint32_t nDstIP)
{
if(fragoff > chksumoff)
return;
@ -203,9 +215,29 @@ namespace llarp
}
static void
checksumDstIPv4UDP(byte_t *pld, ABSL_ATTRIBUTE_UNUSED size_t psz,
size_t fragoff, nuint32_t oSrcIP, nuint32_t oDstIP,
nuint32_t nSrcIP, nuint32_t nDstIP)
deltaChecksumIPv6TCP(byte_t *pld, ABSL_ATTRIBUTE_UNUSED size_t psz,
size_t fragoff, size_t chksumoff,
const uint32_t oSrcIP[4], const uint32_t oDstIP[4],
const uint32_t nSrcIP[4], const uint32_t nDstIP[4])
{
if(fragoff > chksumoff)
return;
auto check = (nuint16_t *)(pld + chksumoff - fragoff);
*check = deltaIPv6Checksum(*check, oSrcIP, oDstIP, nSrcIP, nDstIP);
// usually, TCP checksum field cannot be 0xFFff,
// because one's complement addition cannot result in 0x0000,
// and there's inversion in the end;
// emulate that.
if(check->n == 0xFFff)
check->n = 0x0000;
}
static void
deltaChecksumIPv4UDP(byte_t *pld, ABSL_ATTRIBUTE_UNUSED size_t psz,
size_t fragoff, nuint32_t oSrcIP, nuint32_t oDstIP,
nuint32_t nSrcIP, nuint32_t nDstIP)
{
if(fragoff > 6)
return;
@ -225,86 +257,27 @@ namespace llarp
// check->n = 0xFFff;
}
void
IPPacket::UpdateV4Address(huint32_t newSrcIP, huint32_t newDstIP)
{
llarp::LogDebug("set src=", newSrcIP, " dst=", newDstIP);
auto hdr = Header();
auto oSrcIP = nuint32_t{hdr->saddr};
auto oDstIP = nuint32_t{hdr->daddr};
auto nSrcIP = xhtonl(newSrcIP);
auto nDstIP = xhtonl(newDstIP);
// IPv4 checksum
auto v4chk = (nuint16_t *)&(hdr->check);
*v4chk = deltaIPv4Checksum(*v4chk, oSrcIP, oDstIP, nSrcIP, nDstIP);
// L4 checksum
auto ihs = size_t(hdr->ihl * 4);
if(ihs <= sz)
{
auto pld = buf + ihs;
auto psz = sz - ihs;
auto fragoff = size_t((ntohs(hdr->frag_off) & 0x1Fff) * 8);
switch(hdr->protocol)
{
case 6: // TCP
checksumDstIPv4TCP(pld, psz, fragoff, 16, oSrcIP, oDstIP, nSrcIP,
nDstIP);
break;
case 17: // UDP
case 136: // UDP-Lite - same checksum place, same 0->0xFFff condition
checksumDstIPv4UDP(pld, psz, fragoff, oSrcIP, oDstIP, nSrcIP,
nDstIP);
break;
case 33: // DCCP
checksumDstIPv4TCP(pld, psz, fragoff, 6, oSrcIP, oDstIP, nSrcIP,
nDstIP);
break;
}
}
// write new IP addresses
hdr->saddr = nSrcIP.n;
hdr->daddr = nDstIP.n;
}
static void
checksumSrcIPv4TCP(byte_t *pld, ABSL_ATTRIBUTE_UNUSED size_t psz,
size_t fragoff, size_t chksumoff, nuint32_t oSrcIP,
nuint32_t oDstIP)
{
if(fragoff > chksumoff)
return;
auto check = (nuint16_t *)(pld + chksumoff - fragoff);
*check =
deltaIPv4Checksum(*check, oSrcIP, oDstIP, nuint32_t{0}, nuint32_t{0});
// usually, TCP checksum field cannot be 0xFFff,
// because one's complement addition cannot result in 0x0000,
// and there's inversion in the end;
// emulate that.
if(check->n == 0xFFff)
check->n = 0x0000;
}
static void
checksumSrcIPv4UDP(byte_t *pld, ABSL_ATTRIBUTE_UNUSED size_t psz,
size_t fragoff, nuint32_t oSrcIP, nuint32_t oDstIP)
deltaChecksumIPv6UDP(byte_t *pld, ABSL_ATTRIBUTE_UNUSED size_t psz,
size_t fragoff, const uint32_t oSrcIP[4],
const uint32_t oDstIP[4], const uint32_t nSrcIP[4],
const uint32_t nDstIP[4])
{
if(fragoff > 6)
return;
auto check = (nuint16_t *)(pld + 6);
// 0 is used to indicate "no checksum", don't change
// even tho this shouldn't happen for IPv6, handle it properly
// we actually should drop/log 0-checksum packets per spec
// but that should be done at upper level than this function
// it's better to do correct thing there regardless
// XXX or maybe we should change this function to be able to return error?
// either way that's not a priority
if(check->n == 0x0000)
return; // 0 is used to indicate "no checksum", don't change
return;
*check =
deltaIPv4Checksum(*check, oSrcIP, oDstIP, nuint32_t{0}, nuint32_t{0});
*check = deltaIPv6Checksum(*check, oSrcIP, oDstIP, nSrcIP, nDstIP);
// 0 is used to indicate "no checksum"
// 0xFFff and 0 are equivalent in one's complement math
// 0xFFff + 1 = 0x10000 -> 0x0001 (same as 0 + 1)
@ -314,16 +287,18 @@ namespace llarp
// if(check->n == 0x0000)
// check->n = 0xFFff;
}
/*
void
IPacket::UpdateIPv4PacketOnSrc()
IPPacket::UpdateIPv4Address(nuint32_t nSrcIP, nuint32_t nDstIP)
{
llarp::LogDebug("set src=", nSrcIP, " dst=", nDstIP);
auto hdr = Header();
auto oSrcIP = nuint32_t{hdr->saddr};
auto oDstIP = nuint32_t{hdr->daddr};
// L4
// L4 checksum
auto ihs = size_t(hdr->ihl * 4);
if(ihs <= sz)
{
@ -335,27 +310,73 @@ namespace llarp
switch(hdr->protocol)
{
case 6: // TCP
checksumSrcIPv4TCP(pld, psz, fragoff, 16, oSrcIP, oDstIP);
deltaChecksumIPv4TCP(pld, psz, fragoff, 16, oSrcIP, oDstIP, nSrcIP,
nDstIP);
break;
case 17: // UDP
case 136: // UDP-Lite
checksumSrcIPv4UDP(pld, psz, fragoff, oSrcIP, oDstIP);
case 136: // UDP-Lite - same checksum place, same 0->0xFFff condition
deltaChecksumIPv4UDP(pld, psz, fragoff, oSrcIP, oDstIP, nSrcIP,
nDstIP);
break;
case 33: // DCCP
checksumSrcIPv4TCP(pld, psz, fragoff, 6, oSrcIP, oDstIP);
deltaChecksumIPv4TCP(pld, psz, fragoff, 6, oSrcIP, oDstIP, nSrcIP,
nDstIP);
break;
}
}
// IPv4
// IPv4 checksum
auto v4chk = (nuint16_t *)&(hdr->check);
*v4chk =
deltaIPv4Checksum(*v4chk, oSrcIP, oDstIP, nuint32_t{0}, nuint32_t{0});
*v4chk = deltaIPv4Checksum(*v4chk, oSrcIP, oDstIP, nSrcIP, nDstIP);
// clear addresses
hdr->saddr = 0;
hdr->daddr = 0;
// write new IP addresses
hdr->saddr = nSrcIP.n;
hdr->daddr = nDstIP.n;
}
void
IPPacket::UpdateIPv6Address(huint128_t src, huint128_t dst)
{
const size_t ihs = 40;
// XXX should've been checked at upper level?
if(sz <= ihs)
return;
auto hdr = HeaderV6();
const auto oldSrcIP = hdr->srcaddr;
const auto oldDstIP = hdr->dstaddr;
const uint32_t *oSrcIP = oldSrcIP.s6_addr32;
const uint32_t *oDstIP = oldDstIP.s6_addr32;
// IPv6 address
hdr->srcaddr = HUIntToIn6(src);
hdr->dstaddr = HUIntToIn6(dst);
const uint32_t *nSrcIP = hdr->srcaddr.s6_addr32;
const uint32_t *nDstIP = hdr->dstaddr.s6_addr32;
// TODO IPv6 header options
auto pld = buf + ihs;
auto psz = sz - ihs;
const size_t fragoff = 0;
switch(hdr->proto)
{
case 6: // TCP
deltaChecksumIPv6TCP(pld, psz, fragoff, 16, oSrcIP, oDstIP, nSrcIP,
nDstIP);
break;
case 17: // UDP
case 136: // UDP-Lite - same checksum place, same 0->0xFFff condition
deltaChecksumIPv6UDP(pld, psz, fragoff, oSrcIP, oDstIP, nSrcIP,
nDstIP);
break;
case 33: // DCCP
deltaChecksumIPv6TCP(pld, psz, fragoff, 6, oSrcIP, oDstIP, nSrcIP,
nDstIP);
break;
}
}
*/
} // namespace net
} // namespace llarp

@ -78,7 +78,7 @@ struct ipv6_header
{
unsigned char version : 4;
unsigned char pad_small : 4;
uint8_t pad [3];
uint8_t pad[3];
uint16_t payload_len;
uint8_t proto;
uint8_t hoplimit;
@ -249,10 +249,10 @@ namespace llarp
dst4to6() const;
void
UpdateV4Address(huint32_t src, huint32_t dst);
UpdateIPv4Address(nuint32_t src, nuint32_t dst);
void
UpdateV6Address(huint128_t src, huint128_t dst);
UpdateIPv6Address(huint128_t src, huint128_t dst);
};
} // namespace net

Loading…
Cancel
Save