mirror of
https://github.com/bol-van/zapret.git
synced 2025-05-24 22:32:58 +03:00
nfqws: endian-correct seq increment, preserve window size
This commit is contained in:
131
nfq/checksum.c
Normal file
131
nfq/checksum.c
Normal file
@@ -0,0 +1,131 @@
|
||||
#define _GNU_SOURCE
|
||||
#include "checksum.h"
|
||||
#include <netinet/in.h>
|
||||
|
||||
//#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
|
||||
//#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
|
||||
|
||||
static uint16_t from64to16(uint64_t x)
|
||||
{
|
||||
uint32_t u = (uint32_t)(uint16_t)x + (uint16_t)(x>>16) + (uint16_t)(x>>32) + (uint16_t)(x>>48);
|
||||
return (uint16_t)u + (uint16_t)(u>>16);
|
||||
}
|
||||
|
||||
static uint16_t do_csum(const uint8_t * buff, size_t len)
|
||||
{
|
||||
uint8_t odd;
|
||||
size_t count;
|
||||
uint64_t result,w,carry=0;
|
||||
uint16_t u16;
|
||||
|
||||
if (len <= 0) return 0;
|
||||
odd = (uint8_t)(1 & (size_t)buff);
|
||||
if (odd)
|
||||
{
|
||||
// any endian compatible
|
||||
u16 = 0;
|
||||
*((uint8_t*)&u16+1) = *buff;
|
||||
result = u16;
|
||||
len--;
|
||||
buff++;
|
||||
}
|
||||
else
|
||||
result = 0;
|
||||
count = len >> 1; /* nr of 16-bit words.. */
|
||||
if (count)
|
||||
{
|
||||
if (2 & (size_t) buff)
|
||||
{
|
||||
result += *(uint16_t *) buff;
|
||||
count--;
|
||||
len -= 2;
|
||||
buff += 2;
|
||||
}
|
||||
count >>= 1; /* nr of 32-bit words.. */
|
||||
if (count)
|
||||
{
|
||||
if (4 & (size_t) buff)
|
||||
{
|
||||
result += *(uint32_t *) buff;
|
||||
count--;
|
||||
len -= 4;
|
||||
buff += 4;
|
||||
}
|
||||
count >>= 1; /* nr of 64-bit words.. */
|
||||
if (count)
|
||||
{
|
||||
do
|
||||
{
|
||||
w = *(uint64_t *) buff;
|
||||
count--;
|
||||
buff += 8;
|
||||
result += carry;
|
||||
result += w;
|
||||
carry = (w > result);
|
||||
} while (count);
|
||||
result += carry;
|
||||
result = (result & 0xffffffff) + (result >> 32);
|
||||
}
|
||||
if (len & 4)
|
||||
{
|
||||
result += *(uint32_t *) buff;
|
||||
buff += 4;
|
||||
}
|
||||
}
|
||||
if (len & 2)
|
||||
{
|
||||
result += *(uint16_t *) buff;
|
||||
buff += 2;
|
||||
}
|
||||
}
|
||||
if (len & 1)
|
||||
{
|
||||
// any endian compatible
|
||||
u16 = 0;
|
||||
*(uint8_t*)&u16 = *buff;
|
||||
result += u16;
|
||||
}
|
||||
u16 = from64to16(result);
|
||||
if (odd) u16 = ((u16 >> 8) & 0xff) | ((u16 & 0xff) << 8);
|
||||
return u16;
|
||||
}
|
||||
|
||||
uint16_t csum_partial(const void *buff, size_t len)
|
||||
{
|
||||
return do_csum(buff,len);
|
||||
}
|
||||
|
||||
uint16_t csum_tcpudp_magic(uint32_t saddr, uint32_t daddr, size_t len, uint8_t proto, uint16_t sum)
|
||||
{
|
||||
return ~from64to16((uint64_t)saddr + daddr + sum + htonl(len+proto));
|
||||
}
|
||||
|
||||
uint16_t ip4_compute_csum(const void *buff, size_t len)
|
||||
{
|
||||
return ~from64to16(do_csum(buff,len));
|
||||
}
|
||||
void ip4_fix_checksum(struct iphdr *ip)
|
||||
{
|
||||
ip->check = 0;
|
||||
ip->check = ip4_compute_csum(ip, ip->ihl<<2);
|
||||
}
|
||||
|
||||
uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8_t proto, uint16_t sum)
|
||||
{
|
||||
uint64_t a = (uint64_t)sum + htonl(len+proto) +
|
||||
*(uint32_t*)saddr + *((uint32_t*)saddr+1) + *((uint32_t*)saddr+2) + *((uint32_t*)saddr+3) +
|
||||
*(uint32_t*)daddr + *((uint32_t*)daddr+1) + *((uint32_t*)daddr+2) + *((uint32_t*)daddr+3);
|
||||
return ~from64to16(a);
|
||||
}
|
||||
|
||||
|
||||
void tcp_fix_checksum(struct tcphdr *tcp,int len, in_addr_t src_addr, in_addr_t dest_addr)
|
||||
{
|
||||
tcp->check = 0;
|
||||
tcp->check = csum_tcpudp_magic(src_addr,dest_addr,len,IPPROTO_TCP,csum_partial(tcp, len));
|
||||
}
|
||||
void tcp6_fix_checksum(struct tcphdr *tcp,int len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr)
|
||||
{
|
||||
tcp->check = 0;
|
||||
tcp->check = csum_ipv6_magic(src_addr,dest_addr,len,IPPROTO_TCP,csum_partial(tcp, len));
|
||||
}
|
16
nfq/checksum.h
Normal file
16
nfq/checksum.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
uint16_t csum_partial(const void *buff, size_t len);
|
||||
uint16_t csum_tcpudp_magic(uint32_t saddr, uint32_t daddr, size_t len, uint8_t proto, uint16_t sum);
|
||||
uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8_t proto, uint16_t sum);
|
||||
uint16_t ip4_compute_csum(const void *buff, size_t len);
|
||||
void ip4_fix_checksum(struct iphdr *ip);
|
||||
|
||||
void tcp_fix_checksum(struct tcphdr *tcp,int len, in_addr_t src_addr, in_addr_t dest_addr);
|
||||
void tcp6_fix_checksum(struct tcphdr *tcp,int len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr);
|
118
nfq/darkmagic.c
118
nfq/darkmagic.c
@@ -1,114 +1,17 @@
|
||||
#define _GNU_SOURCE
|
||||
#include "darkmagic.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "darkmagic.h"
|
||||
|
||||
uint16_t tcp_checksum(const void *buff, int len, in_addr_t src_addr, in_addr_t dest_addr)
|
||||
uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment)
|
||||
{
|
||||
const uint16_t *buf=buff;
|
||||
uint16_t *ip_src=(uint16_t *)&src_addr, *ip_dst=(uint16_t *)&dest_addr;
|
||||
uint32_t sum;
|
||||
int length=len;
|
||||
|
||||
// Calculate the sum
|
||||
sum = 0;
|
||||
while (len > 1)
|
||||
{
|
||||
sum += *buf++;
|
||||
if (sum & 0x80000000)
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
len -= 2;
|
||||
}
|
||||
if ( len & 1 )
|
||||
{
|
||||
// Add the padding if the packet lenght is odd
|
||||
uint16_t v=0;
|
||||
*(uint8_t *)&v = *((uint8_t *)buf);
|
||||
sum += v;
|
||||
}
|
||||
|
||||
// Add the pseudo-header
|
||||
sum += *(ip_src++);
|
||||
sum += *ip_src;
|
||||
sum += *(ip_dst++);
|
||||
sum += *ip_dst;
|
||||
sum += htons(IPPROTO_TCP);
|
||||
sum += htons(length);
|
||||
|
||||
// Add the carries
|
||||
while (sum >> 16)
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
|
||||
// Return the one's complement of sum
|
||||
return (uint16_t)(~sum);
|
||||
}
|
||||
void tcp_fix_checksum(struct tcphdr *tcp,int len, in_addr_t src_addr, in_addr_t dest_addr)
|
||||
{
|
||||
tcp->check = 0;
|
||||
tcp->check = tcp_checksum(tcp,len,src_addr,dest_addr);
|
||||
}
|
||||
uint16_t tcp6_checksum(const void *buff, int len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr)
|
||||
{
|
||||
const uint16_t *buf=buff;
|
||||
const uint16_t *ip_src=(uint16_t *)src_addr, *ip_dst=(uint16_t *)dest_addr;
|
||||
uint32_t sum;
|
||||
int length=len;
|
||||
|
||||
// Calculate the sum
|
||||
sum = 0;
|
||||
while (len > 1)
|
||||
{
|
||||
sum += *buf++;
|
||||
if (sum & 0x80000000)
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
len -= 2;
|
||||
}
|
||||
if ( len & 1 )
|
||||
{
|
||||
// Add the padding if the packet lenght is odd
|
||||
uint16_t v=0;
|
||||
*(uint8_t *)&v = *((uint8_t *)buf);
|
||||
sum += v;
|
||||
}
|
||||
|
||||
// Add the pseudo-header
|
||||
sum += *(ip_src++);
|
||||
sum += *(ip_src++);
|
||||
sum += *(ip_src++);
|
||||
sum += *(ip_src++);
|
||||
sum += *(ip_src++);
|
||||
sum += *(ip_src++);
|
||||
sum += *(ip_src++);
|
||||
sum += *ip_src;
|
||||
sum += *(ip_dst++);
|
||||
sum += *(ip_dst++);
|
||||
sum += *(ip_dst++);
|
||||
sum += *(ip_dst++);
|
||||
sum += *(ip_dst++);
|
||||
sum += *(ip_dst++);
|
||||
sum += *(ip_dst++);
|
||||
sum += *ip_dst;
|
||||
sum += htons(IPPROTO_TCP);
|
||||
sum += htons(length);
|
||||
|
||||
// Add the carries
|
||||
while (sum >> 16)
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
|
||||
// Return the one's complement of sum
|
||||
return (uint16_t)(~sum);
|
||||
}
|
||||
void tcp6_fix_checksum(struct tcphdr *tcp,int len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr)
|
||||
{
|
||||
tcp->check = 0;
|
||||
tcp->check = tcp6_checksum(tcp,len,src_addr,dest_addr);
|
||||
return htonl(ntohl(netorder_value)+cpuorder_increment);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void fill_tcphdr(struct tcphdr *tcp, uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, enum tcp_fooling_mode fooling, uint16_t nsport, uint16_t ndport)
|
||||
static void fill_tcphdr(struct tcphdr *tcp, uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, enum tcp_fooling_mode fooling, uint16_t nsport, uint16_t ndport, uint16_t nwsize)
|
||||
{
|
||||
char *tcpopt = (char*)(tcp+1);
|
||||
memset(tcp,0,sizeof(*tcp));
|
||||
@@ -118,7 +21,7 @@ static void fill_tcphdr(struct tcphdr *tcp, uint8_t tcp_flags, uint32_t seq, uin
|
||||
tcp->ack_seq = ack_seq;
|
||||
tcp->doff = 5;
|
||||
*((uint8_t*)tcp+13)= tcp_flags;
|
||||
tcp->window = htons(65535);
|
||||
tcp->window = nwsize;
|
||||
if (fooling==TCP_FOOL_MD5SIG)
|
||||
{
|
||||
tcp->doff += 5; // +20 bytes
|
||||
@@ -185,6 +88,7 @@ bool prepare_tcp_segment4(
|
||||
const struct sockaddr_in *src, const struct sockaddr_in *dst,
|
||||
uint8_t tcp_flags,
|
||||
uint32_t seq, uint32_t ack_seq,
|
||||
uint16_t wsize,
|
||||
uint8_t ttl,
|
||||
enum tcp_fooling_mode fooling,
|
||||
const void *data, uint16_t len,
|
||||
@@ -212,7 +116,7 @@ bool prepare_tcp_segment4(
|
||||
ip->saddr = src->sin_addr.s_addr;
|
||||
ip->daddr = dst->sin_addr.s_addr;
|
||||
|
||||
fill_tcphdr(tcp,tcp_flags,seq,ack_seq,fooling,src->sin_port,dst->sin_port);
|
||||
fill_tcphdr(tcp,tcp_flags,seq,ack_seq,fooling,src->sin_port,dst->sin_port,wsize);
|
||||
|
||||
memcpy((char*)tcp+sizeof(struct tcphdr)+tcpoptlen,data,len);
|
||||
tcp_fix_checksum(tcp,sizeof(struct tcphdr)+tcpoptlen+len,ip->saddr,ip->daddr);
|
||||
@@ -227,6 +131,7 @@ bool prepare_tcp_segment6(
|
||||
const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst,
|
||||
uint8_t tcp_flags,
|
||||
uint32_t seq, uint32_t ack_seq,
|
||||
uint16_t wsize,
|
||||
uint8_t ttl,
|
||||
enum tcp_fooling_mode fooling,
|
||||
const void *data, uint16_t len,
|
||||
@@ -252,7 +157,7 @@ bool prepare_tcp_segment6(
|
||||
ip6->ip6_src = src->sin6_addr;
|
||||
ip6->ip6_dst = dst->sin6_addr;
|
||||
|
||||
fill_tcphdr(tcp,tcp_flags,seq,ack_seq,fooling,src->sin6_port,dst->sin6_port);
|
||||
fill_tcphdr(tcp,tcp_flags,seq,ack_seq,fooling,src->sin6_port,dst->sin6_port,wsize);
|
||||
|
||||
memcpy((char*)tcp+sizeof(struct tcphdr)+tcpoptlen,data,len);
|
||||
tcp6_fix_checksum(tcp,sizeof(struct tcphdr)+tcpoptlen+len,&ip6->ip6_src,&ip6->ip6_dst);
|
||||
@@ -266,15 +171,16 @@ bool prepare_tcp_segment(
|
||||
const struct sockaddr *src, const struct sockaddr *dst,
|
||||
uint8_t tcp_flags,
|
||||
uint32_t seq, uint32_t ack_seq,
|
||||
uint16_t wsize,
|
||||
uint8_t ttl,
|
||||
enum tcp_fooling_mode fooling,
|
||||
const void *data, uint16_t len,
|
||||
char *buf, size_t *buflen)
|
||||
{
|
||||
return (src->sa_family==AF_INET && dst->sa_family==AF_INET) ?
|
||||
prepare_tcp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,tcp_flags,seq,ack_seq,ttl,fooling,data,len,buf,buflen) :
|
||||
prepare_tcp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,tcp_flags,seq,ack_seq,wsize,ttl,fooling,data,len,buf,buflen) :
|
||||
(src->sa_family==AF_INET6 && dst->sa_family==AF_INET6) ?
|
||||
prepare_tcp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,tcp_flags,seq,ack_seq,ttl,fooling,data,len,buf,buflen) :
|
||||
prepare_tcp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,tcp_flags,seq,ack_seq,wsize,ttl,fooling,data,len,buf,buflen) :
|
||||
false;
|
||||
}
|
||||
|
||||
|
@@ -7,21 +7,22 @@
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include "checksum.h"
|
||||
|
||||
uint16_t tcp_checksum(const void *buff, int len, in_addr_t src_addr, in_addr_t dest_addr);
|
||||
void tcp_fix_checksum(struct tcphdr *tcp,int len, in_addr_t src_addr, in_addr_t dest_addr);
|
||||
uint16_t tcp6_checksum(const void *buff, int len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr);
|
||||
void tcp6_fix_checksum(struct tcphdr *tcp,int len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr);
|
||||
// returns netorder value
|
||||
uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment);
|
||||
|
||||
enum tcp_fooling_mode {
|
||||
TCP_FOOL_NONE=0,
|
||||
TCP_FOOL_MD5SIG=1,
|
||||
TCP_FOOL_BADSUM=2
|
||||
};
|
||||
// seq and wsize have network byte order
|
||||
bool prepare_tcp_segment4(
|
||||
const struct sockaddr_in *src, const struct sockaddr_in *dst,
|
||||
uint8_t tcp_flags,
|
||||
uint32_t seq, uint32_t ack_seq,
|
||||
uint16_t wsize,
|
||||
uint8_t ttl,
|
||||
enum tcp_fooling_mode fooling,
|
||||
const void *data, uint16_t len,
|
||||
@@ -30,6 +31,7 @@ bool prepare_tcp_segment6(
|
||||
const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst,
|
||||
uint8_t tcp_flags,
|
||||
uint32_t seq, uint32_t ack_seq,
|
||||
uint16_t wsize,
|
||||
uint8_t ttl,
|
||||
enum tcp_fooling_mode fooling,
|
||||
const void *data, uint16_t len,
|
||||
@@ -38,6 +40,7 @@ bool prepare_tcp_segment(
|
||||
const struct sockaddr *src, const struct sockaddr *dst,
|
||||
uint8_t tcp_flags,
|
||||
uint32_t seq, uint32_t ack_seq,
|
||||
uint16_t wsize,
|
||||
uint8_t ttl,
|
||||
enum tcp_fooling_mode fooling,
|
||||
const void *data, uint16_t len,
|
||||
|
10
nfq/nfqws.c
10
nfq/nfqws.c
@@ -534,7 +534,7 @@ static bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, const str
|
||||
switch(params.desync_mode)
|
||||
{
|
||||
case DESYNC_FAKE:
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->seq, tcphdr->ack_seq,
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->seq, tcphdr->ack_seq, tcphdr->window,
|
||||
ttl_fake,params.desync_tcp_fooling_mode,
|
||||
fake, fake_size, newdata, &newlen))
|
||||
{
|
||||
@@ -543,7 +543,7 @@ static bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, const str
|
||||
break;
|
||||
case DESYNC_RST:
|
||||
case DESYNC_RSTACK:
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (params.desync_mode==DESYNC_RSTACK ? TH_ACK:0), tcphdr->seq, tcphdr->ack_seq,
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (params.desync_mode==DESYNC_RSTACK ? TH_ACK:0), tcphdr->seq, tcphdr->ack_seq, tcphdr->window,
|
||||
ttl_fake,params.desync_tcp_fooling_mode,
|
||||
NULL, 0, newdata, &newlen))
|
||||
{
|
||||
@@ -560,7 +560,7 @@ static bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, const str
|
||||
if (split_pos<len_payload)
|
||||
{
|
||||
DLOG("sending 2nd out-of-order tcp segment %zu-%zu len=%zu\n",split_pos,len_payload-1, len_payload-split_pos)
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->seq+split_pos, tcphdr->ack_seq,
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(tcphdr->seq,split_pos), tcphdr->ack_seq, tcphdr->window,
|
||||
ttl_orig,TCP_FOOL_NONE,
|
||||
data_payload+split_pos, len_payload-split_pos, newdata, &newlen) ||
|
||||
!rawsend((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen))
|
||||
@@ -574,7 +574,7 @@ static bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, const str
|
||||
{
|
||||
DLOG("sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu\n",split_pos-1, split_pos)
|
||||
fakeseg_len = sizeof(fakeseg);
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->seq, tcphdr->ack_seq,
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->seq, tcphdr->ack_seq, tcphdr->window,
|
||||
ttl_fake,params.desync_tcp_fooling_mode,
|
||||
zeropkt, split_pos, fakeseg, &fakeseg_len) ||
|
||||
!rawsend((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len))
|
||||
@@ -586,7 +586,7 @@ static bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, const str
|
||||
|
||||
DLOG("sending 1st out-of-order tcp segment 0-%zu len=%zu\n",split_pos-1, split_pos)
|
||||
newlen = sizeof(newdata);
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->seq, tcphdr->ack_seq,
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->seq, tcphdr->ack_seq, tcphdr->window,
|
||||
ttl_orig,TCP_FOOL_NONE,
|
||||
data_payload, split_pos, newdata, &newlen) ||
|
||||
!rawsend((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen))
|
||||
|
Reference in New Issue
Block a user