ip: make things fragmentation-aware, cleanup UDP handling; also format

one's complement math is pretty fun
pull/31/head
cathugger 6 years ago
parent bf9512dfaf
commit 4d5f5fecfa
No known key found for this signature in database
GPG Key ID: 9BADDA2DAF6F01A8

@ -60,7 +60,7 @@ main(int argc, char *argv[])
multiThreaded = false;
}
//SetLogLevel(llarp::eLogDebug);
// SetLogLevel(llarp::eLogDebug);
#ifdef _WIN32
if(startWinsock())

@ -84,7 +84,6 @@ writesend_dnss_revresponse(std::string reverse, const struct sockaddr *from,
dnsd_question_request *request);
// FIXME: llarp::Addr
//
// setup/teardown functions/structure:
//

@ -289,7 +289,7 @@ namespace llarp
_addr.sin6_family = res->ai_family;
_addr4.sin_family = res->ai_family;
_addr4.sin_port = 0; // save a call, 0 is 0 no matter how u arrange it
_addr4.sin_port = 0; // save a call, 0 is 0 no matter how u arrange it
#if((__APPLE__ && __MACH__) || __FreeBSD__)
_addr4.sin_len = sizeof(in_addr);
#endif
@ -478,7 +478,7 @@ namespace llarp
else
return (sockaddr*)&_addr;
}
void
CopyInto(sockaddr* other) const
{

@ -334,7 +334,7 @@ namespace llarp
std::string host = bindaddr.substr(0, idx);
uint16_t port = std::stoi(bindaddr.substr(idx + 1));
addr = llarp::Addr(host, port);
saddr = (sockaddr *)addr;
saddr = (sockaddr*)addr;
}
return llarp_tcp_serve(&m_acceptor, saddr);
}

@ -99,10 +99,10 @@ extern "C"
hdr->tc = fields & 0x0200;
hdr->rd = fields & 0x0100;
hdr->ra = (lFields >> 7) & 0x1;
hdr->z = (lFields >> 6) & 0x1;
hdr->ad = (lFields >> 5) & 0x1;
hdr->cd = (lFields >> 4) & 0x1;
hdr->ra = (lFields >> 7) & 0x1;
hdr->z = (lFields >> 6) & 0x1;
hdr->ad = (lFields >> 5) & 0x1;
hdr->cd = (lFields >> 4) & 0x1;
hdr->rcode = lFields & 0xf;
hdr->qdCount = get16bits(buffer);
@ -115,11 +115,11 @@ extern "C"
dns_msg_question *
decode_question(const char *buffer)
{
//char *start = (char *)buffer;
// char *start = (char *)buffer;
dns_msg_question *question = new dns_msg_question;
std::string m_qName = getDNSstring(buffer);
buffer += m_qName.length() + 2; // + length byte & ending terminator
//printf("Now0 at [%d]\n", buffer - start);
buffer += m_qName.length() + 2; // + length byte & ending terminator
// printf("Now0 at [%d]\n", buffer - start);
// buffer += m_qName.size() + 1;
/*
std::string m_qName = "";
@ -137,11 +137,11 @@ extern "C"
m_qName.append(1, '.');
}
*/
question->name = m_qName;
question->type = get16bits(buffer);
//printf("Now1 at [%d]\n", buffer - start);
question->name = m_qName;
question->type = get16bits(buffer);
// printf("Now1 at [%d]\n", buffer - start);
question->qClass = get16bits(buffer);
//printf("Now2 at [%d]\n", buffer - start);
// printf("Now2 at [%d]\n", buffer - start);
return question;
}
@ -203,7 +203,7 @@ extern "C"
{
// 2 names, then 4x 32bit
// why risk any crashes
if (answer->rdLen < 24)
if(answer->rdLen < 24)
{
llarp::LogWarn("Weird SOA is less than 24 bytes: ", answer->rdLen);
}

@ -23,7 +23,6 @@
dns_tracker dns_udp_tracker;
/*
#define DNC_BUF_SIZE 512
/// a question to be asked remotely (the actual bytes to send on the wire)

@ -269,7 +269,7 @@ handle_dnsc_result(dnsc_answer_request *client_request)
else
{
struct sockaddr *useHostRes = nullptr;
if (client_request->found)
if(client_request->found)
useHostRes = client_request->result;
writesend_dnss_response(useHostRes, server_request->from, server_request);
}

@ -28,11 +28,12 @@ namespace llarp
return llarp::InitBuffer(buf, sz);
}
#if 0
static uint32_t
ipchksum_pseudoIPv4(nuint32_t src_ip, nuint32_t dst_ip, uint8_t proto,
uint16_t innerlen)
{
#define IPCS(x) ((uint32_t)(x & 0xFFFF) + (uint32_t)(x >> 16))
#define IPCS(x) ((uint32_t)(x & 0xFFff) + (uint32_t)(x >> 16))
uint32_t sum = IPCS(src_ip.n) + IPCS(dst_ip.n) + (uint32_t)proto
+ (uint32_t)htons(innerlen);
#undef IPCS
@ -48,21 +49,26 @@ namespace llarp
sz -= sizeof(uint16_t);
buf += sizeof(uint16_t);
}
if(sz > 0)
sum += *(const byte_t *)buf;
if(sz != 0)
{
uint16_t x = 0;
*(byte_t *)&x = *(const byte_t *)buf;
sum += x;
}
while(sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
sum = (sum & 0xFFff) + (sum >> 16);
return ~sum;
}
#endif
static uint16_t
deltachksum(uint16_t old_sum, huint32_t old_src_ip, huint32_t old_dst_ip,
huint32_t new_src_ip, huint32_t new_dst_ip)
{
#define ADDIPCS(x) ((uint32_t)(x.h & 0xFFFF) + (uint32_t)(x.h >> 16))
#define SUBIPCS(x) ((uint32_t)((~x.h) & 0xFFFF) + (uint32_t)((~x.h) >> 16))
#define ADDIPCS(x) ((uint32_t)(x.h & 0xFFff) + (uint32_t)(x.h >> 16))
#define SUBIPCS(x) ((uint32_t)((~x.h) & 0xFFff) + (uint32_t)((~x.h) >> 16))
uint32_t sum = ntohs(old_sum) + ADDIPCS(old_src_ip) + ADDIPCS(old_dst_ip)
+ SUBIPCS(new_src_ip) + SUBIPCS(new_dst_ip);
@ -71,62 +77,46 @@ namespace llarp
#undef SUBIPCS
while(sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
sum = (sum & 0xFFff) + (sum >> 16);
return htons(sum);
}
static void
checksumDstTCP(byte_t *pld, size_t psz, huint32_t oSrcIP, huint32_t oDstIP,
huint32_t nSrcIP, huint32_t nDstIP)
checksumDstTCP(byte_t *pld, size_t psz, size_t fragoff, huint32_t oSrcIP,
huint32_t oDstIP, huint32_t nSrcIP, huint32_t nDstIP)
{
uint16_t *check = (uint16_t *)(pld + 16);
if(fragoff > 16)
return;
uint16_t *check = (uint16_t *)(pld + 16 - fragoff);
*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)
size_t fragoff, 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
if(fragoff > 6)
return;
auto cs =
ipchksum(pld, psz,
ipchksum_pseudoIPv4(nuint32_t{ohdr->saddr},
nuint32_t{ohdr->daddr}, 17, psz));
uint16_t *check = (uint16_t *)(pld + 6);
if(*check == 0x0000)
return; // 0 is used to indicate "no checksum", don't change
auto new_cs = deltachksum(cs, oSrcIP, oDstIP, nSrcIP, nDstIP);
*check = deltachksum(*check, 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;
}
// 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)
// infact it's impossible to get 0 with such addition
// when starting from non-0 value
// but it's possible to get 0xFFff and we invert after that
// so we still need this fixup check
if(*check == 0x0000)
*check = 0xFFff;
}
void
@ -141,18 +131,24 @@ namespace llarp
hdr->check = deltachksum(hdr->check, oSrcIP, oDstIP, nSrcIP, nDstIP);
// L4 checksum
auto proto = hdr->protocol;
auto ihs = size_t(hdr->ihl * 4);
auto pld = buf + ihs;
auto psz = sz - ihs;
switch(proto)
auto ihs = size_t(hdr->ihl * 4);
if(ihs <= sz)
{
case 6:
checksumDstTCP(pld, psz, oSrcIP, oDstIP, nSrcIP, nDstIP);
break;
case 17:
checksumDstUDP(hdr, pld, psz, oSrcIP, oDstIP, nSrcIP, nDstIP);
break;
auto pld = buf + ihs;
auto psz = sz - ihs;
auto fragoff = size_t((ntohs(hdr->frag_off) & 0x1Fff) * 8);
switch(hdr->protocol)
{
case 6:
checksumDstTCP(pld, psz, fragoff, oSrcIP, oDstIP, nSrcIP, nDstIP);
break;
case 17:
checksumDstUDP(hdr, pld, psz, fragoff, oSrcIP, oDstIP, nSrcIP,
nDstIP);
break;
}
}
// write new IP addresses
@ -161,56 +157,39 @@ namespace llarp
}
static void
checksumSrcTCP(byte_t *pld, size_t psz, huint32_t oSrcIP, huint32_t oDstIP)
checksumSrcTCP(byte_t *pld, size_t psz, size_t fragoff, huint32_t oSrcIP,
huint32_t oDstIP)
{
uint16_t *check = (uint16_t *)(pld + 16);
if(fragoff > 16)
return;
uint16_t *check = (uint16_t *)(pld + 16 - fragoff);
*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)
size_t fragoff, 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
if(fragoff > 6)
return;
auto cs =
ipchksum(pld, psz,
ipchksum_pseudoIPv4(nuint32_t{ohdr->saddr},
nuint32_t{ohdr->daddr}, 17, psz));
uint16_t *check = (uint16_t *)(pld + 6);
if(*check == 0x0000)
return; // 0 is used to indicate "no checksum", don't change
auto new_cs =
deltachksum(cs, oSrcIP, oDstIP, huint32_t{0}, huint32_t{0});
*check = deltachksum(*check, 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;
}
// 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)
// infact it's impossible to get 0 with such addition
// when starting from non-0 value
// but it's possible to get 0xFFff and we invert after that
// so we still need this fixup check
if(*check == 0x0000)
*check = 0xFFff;
}
void
@ -222,18 +201,23 @@ namespace llarp
auto oDstIP = xntohl(nuint32_t{hdr->daddr});
// L4
auto proto = hdr->protocol;
auto ihs = size_t(hdr->ihl * 4);
auto pld = buf + ihs;
auto psz = sz - ihs;
switch(proto)
auto ihs = size_t(hdr->ihl * 4);
if(ihs <= sz)
{
case 6:
checksumSrcTCP(pld, psz, oSrcIP, oDstIP);
break;
case 17:
checksumSrcUDP(hdr, pld, psz, oSrcIP, oDstIP);
break;
auto pld = buf + ihs;
auto psz = sz - ihs;
auto fragoff = size_t((ntohs(hdr->frag_off) & 0x1Fff) * 8);
switch(hdr->protocol)
{
case 6:
checksumSrcTCP(pld, psz, fragoff, oSrcIP, oDstIP);
break;
case 17:
checksumSrcUDP(hdr, pld, psz, fragoff, oSrcIP, oDstIP);
break;
}
}
// IPv4

Loading…
Cancel
Save