nfqws: udp protocol desync

This commit is contained in:
bol-van
2022-01-01 20:22:04 +03:00
parent 566e3d1536
commit 65830eb665
21 changed files with 1048 additions and 736 deletions

View File

@@ -11,6 +11,9 @@ static uint16_t from64to16(uint64_t x)
return (uint16_t)u + (uint16_t)(u>>16);
}
// this function preserves data alignment requirements (otherwise it will be damn slow on mips arch)
// and uses 64-bit arithmetics to improve speed
// taken from linux source code
static uint16_t do_csum(const uint8_t * buff, size_t len)
{
uint8_t odd;
@@ -122,12 +125,12 @@ uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8
void tcp4_fix_checksum(struct tcphdr *tcp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr)
{
tcp->th_sum = 0;
tcp->th_sum = csum_tcpudp_magic(src_addr->s_addr,dest_addr->s_addr,len,IPPROTO_TCP,csum_partial(tcp, len));
tcp->th_sum = csum_tcpudp_magic(src_addr->s_addr,dest_addr->s_addr,len,IPPROTO_TCP,csum_partial(tcp,len));
}
void tcp6_fix_checksum(struct tcphdr *tcp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr)
{
tcp->th_sum = 0;
tcp->th_sum = csum_ipv6_magic(src_addr,dest_addr,len,IPPROTO_TCP,csum_partial(tcp, len));
tcp->th_sum = csum_ipv6_magic(src_addr,dest_addr,len,IPPROTO_TCP,csum_partial(tcp,len));
}
void tcp_fix_checksum(struct tcphdr *tcp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr)
{
@@ -136,3 +139,21 @@ void tcp_fix_checksum(struct tcphdr *tcp,size_t len,const struct ip *ip,const st
else if (ip6hdr)
tcp6_fix_checksum(tcp, len, &ip6hdr->ip6_src, &ip6hdr->ip6_dst);
}
void udp4_fix_checksum(struct udphdr *udp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr)
{
udp->uh_sum = 0;
udp->uh_sum = csum_tcpudp_magic(src_addr->s_addr,dest_addr->s_addr,len,IPPROTO_UDP,csum_partial(udp,len));
}
void udp6_fix_checksum(struct udphdr *udp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr)
{
udp->uh_sum = 0;
udp->uh_sum = csum_ipv6_magic(src_addr,dest_addr,len,IPPROTO_UDP,csum_partial(udp,len));
}
void udp_fix_checksum(struct udphdr *udp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr)
{
if (ip)
udp4_fix_checksum(udp, len, &ip->ip_src, &ip->ip_dst);
else if (ip6hdr)
udp6_fix_checksum(udp, len, &ip6hdr->ip6_src, &ip6hdr->ip6_dst);
}

View File

@@ -7,13 +7,19 @@
#include <netinet/ip6.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.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 ip *ip);
void tcp4_fix_checksum(struct tcphdr *tcp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr);
void tcp6_fix_checksum(struct tcphdr *tcp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr);
void tcp_fix_checksum(struct tcphdr *tcp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr);
void udp4_fix_checksum(struct udphdr *udp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr);
void udp6_fix_checksum(struct udphdr *udp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr);
void udp_fix_checksum(struct udphdr *udp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr);

View File

@@ -12,88 +12,68 @@ static void ut_oom_recover(void *elem)
oom = true;
}
static const char *connstate_s[]={"SYN","ESTABLISHED","FIN"};
#define _connswap \
memset(c2,0,sizeof(*c2)); \
c2->e1 = c->e2; \
c2->e2 = c->e1;
static void connswap4(const t_conn4 *c, t_conn4 *c2)
static void connswap(const t_conn *c, t_conn *c2)
{
_connswap
}
static void connswap6(const t_conn6 *c, t_conn6 *c2)
{
_connswap
memset(c2,0,sizeof(*c2));
c2->l3proto = c->l3proto;
c2->l4proto = c->l4proto;
c2->src = c->dst;
c2->dst = c->src;
c2->sport = c->dport;
c2->dport = c->sport;
}
#define _ConntrackPoolDestroy(v) \
t_conntrack##v *elem, *tmp; \
static void ConntrackPoolDestroyPool(t_conntrack_pool **pp)
{
t_conntrack_pool *elem, *tmp;
HASH_ITER(hh, *pp, elem, tmp) { HASH_DEL(*pp, elem); free(elem); }
static void ConntrackPoolDestroy4(t_conntrack4 **pp)
{
_ConntrackPoolDestroy(4)
}
static void ConntrackPoolDestroy6(t_conntrack6 **pp)
{
_ConntrackPoolDestroy(6)
}
void ConntrackPoolDestroy(t_conntrack *p)
{
ConntrackPoolDestroy4(&p->pool4);
ConntrackPoolDestroy6(&p->pool6);
ConntrackPoolDestroyPool(&p->pool);
}
void ConntrackPoolInit(t_conntrack *p, time_t purge_interval, uint32_t timeout_syn, uint32_t timeout_established, uint32_t timeout_fin)
void ConntrackPoolInit(t_conntrack *p, time_t purge_interval, uint32_t timeout_syn, uint32_t timeout_established, uint32_t timeout_fin, uint32_t timeout_udp)
{
p->timeout_syn = timeout_syn;
p->timeout_established = timeout_established;
p->timeout_fin = timeout_fin;
p->timeout_udp= timeout_udp;
p->t_purge_interval = purge_interval;
time(&p->t_last_purge);
p->pool4 = NULL;
p->pool6 = NULL;
p->pool = NULL;
}
#define _ConntrackExtractConn(v) \
memset(c,0,sizeof(*c)); \
if (bReverse) { \
c->e1.adr = ip->ip##v##_dst; \
c->e2.adr = ip->ip##v##_src; \
c->e1.port = htons(tcphdr->th_dport); \
c->e2.port = htons(tcphdr->th_sport); \
} else { \
c->e1.adr = ip->ip##v##_src; \
c->e2.adr = ip->ip##v##_dst; \
c->e1.port = htons(tcphdr->th_sport); \
c->e2.port = htons(tcphdr->th_dport); \
void ConntrackExtractConn(t_conn *c, bool bReverse, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr)
{
memset(c,0,sizeof(*c));
if (ip)
{
c->l3proto = IPPROTO_IP;
c->dst.ip = bReverse ? ip->ip_src : ip->ip_dst;
c->src.ip = bReverse ? ip->ip_dst : ip->ip_src;
}
void ConntrackExtractConn4(t_conn4 *c, bool bReverse, const struct ip *ip, const struct tcphdr *tcphdr)
{
_ConntrackExtractConn()
}
void ConntrackExtractConn6(t_conn6 *c, bool bReverse, const struct ip6_hdr *ip, const struct tcphdr *tcphdr)
{
_ConntrackExtractConn(6)
else if (ip6)
{
c->l3proto = IPPROTO_IPV6;
c->dst.ip6 = bReverse ? ip6->ip6_src : ip6->ip6_dst;
c->src.ip6 = bReverse ? ip6->ip6_dst : ip6->ip6_src;
}
else
c->l3proto = -1;
extract_ports(tcphdr, udphdr, &c->l4proto, bReverse ? &c->dport : &c->sport, bReverse ? &c->sport : &c->dport);
}
#define _ConntrackPoolSearch(v) \
t_conntrack##v *t; \
HASH_FIND(hh, p, c, sizeof(*c), t); \
static t_conntrack_pool *ConntrackPoolSearch(t_conntrack_pool *p, const t_conn *c)
{
t_conntrack_pool *t;
HASH_FIND(hh, p, c, sizeof(*c), t);
return t;
t_conntrack4 *ConntrackPoolSearch4(t_conntrack4 *p, const t_conn4 *c)
{
_ConntrackPoolSearch(4)
}
t_conntrack6 *ConntrackPoolSearch6(t_conntrack6 *p, const t_conn6 *c)
{
_ConntrackPoolSearch(6)
}
static void ConntrackInitTrack(t_ctrack *t)
{
@@ -102,206 +82,218 @@ static void ConntrackInitTrack(t_ctrack *t)
time(&t->t_start);
}
#define _ConntrackNew(v) \
t_conntrack##v *new; \
if (!(new = calloc(1,sizeof(*new)))) return NULL; \
new->conn = *c; \
oom = false; \
HASH_ADD(hh, *pp, conn, sizeof(*c), new); \
if (oom) { free(new); return NULL; } \
ConntrackInitTrack(&new->track); \
static t_conntrack_pool *ConntrackNew(t_conntrack_pool **pp, const t_conn *c)
{
t_conntrack_pool *new;
if (!(new = malloc(sizeof(*new)))) return NULL;
new->conn = *c;
oom = false;
HASH_ADD(hh, *pp, conn, sizeof(*c), new);
if (oom) { free(new); return NULL; }
ConntrackInitTrack(&new->track);
return new;
static t_conntrack4 *ConntrackNew4(t_conntrack4 **pp, const t_conn4 *c)
{
_ConntrackNew(4)
}
static t_conntrack6 *ConntrackNew6(t_conntrack6 **pp, const t_conn6 *c)
{
_ConntrackNew(6)
}
// non-tcp packets are passed with tcphdr=NULL but len_payload filled
static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr *tcphdr, uint32_t len_payload)
{
uint8_t scale;
if (tcp_syn_segment(tcphdr))
{
if (t->state!=SYN) ConntrackInitTrack(t); // erase current entry
t->seq0 = htonl(tcphdr->th_seq);
}
else if (tcp_synack_segment(tcphdr))
{
if (t->state!=SYN) ConntrackInitTrack(t); // erase current entry
if (!t->seq0) t->seq0 = htonl(tcphdr->th_ack)-1;
t->ack0 = htonl(tcphdr->th_seq);
}
else if (tcphdr->th_flags & (TH_FIN|TH_RST))
{
t->state = FIN;
}
else
{
if (t->state==SYN)
{
t->state=ESTABLISHED;
if (!bReverse && !t->ack0) t->ack0 = htonl(tcphdr->th_ack)-1;
}
}
scale = tcp_find_scale_factor(tcphdr);
if (bReverse)
{
t->pos_orig = t->seq_last = htonl(tcphdr->th_ack);
t->ack_last = htonl(tcphdr->th_seq);
t->pos_reply = t->ack_last + len_payload;
t->pcounter_reply++;
t->pdcounter_reply+=!!len_payload;
t->winsize_reply = htons(tcphdr->th_win);
if (scale!=SCALE_NONE) t->scale_reply = scale;
}
else
{
t->seq_last = htonl(tcphdr->th_seq);
t->pos_orig = t->seq_last + len_payload;
t->pos_reply = t->ack_last = htonl(tcphdr->th_ack);
t->pcounter_orig++;
t->pdcounter_orig+=!!len_payload;
t->winsize_orig = htons(tcphdr->th_win);
if (scale!=SCALE_NONE) t->scale_orig = scale;
}
if (tcphdr)
{
if (tcp_syn_segment(tcphdr))
{
if (t->state!=SYN) ConntrackInitTrack(t); // erase current entry
t->seq0 = htonl(tcphdr->th_seq);
}
else if (tcp_synack_segment(tcphdr))
{
if (t->state!=SYN) ConntrackInitTrack(t); // erase current entry
if (!t->seq0) t->seq0 = htonl(tcphdr->th_ack)-1;
t->ack0 = htonl(tcphdr->th_seq);
}
else if (tcphdr->th_flags & (TH_FIN|TH_RST))
{
t->state = FIN;
}
else
{
if (t->state==SYN)
{
t->state=ESTABLISHED;
if (!bReverse && !t->ack0) t->ack0 = htonl(tcphdr->th_ack)-1;
}
}
scale = tcp_find_scale_factor(tcphdr);
if (bReverse)
{
t->pos_orig = t->seq_last = htonl(tcphdr->th_ack);
t->ack_last = htonl(tcphdr->th_seq);
t->pos_reply = t->ack_last + len_payload;
t->winsize_reply = htons(tcphdr->th_win);
if (scale!=SCALE_NONE) t->scale_reply = scale;
}
else
{
t->seq_last = htonl(tcphdr->th_seq);
t->pos_orig = t->seq_last + len_payload;
t->pos_reply = t->ack_last = htonl(tcphdr->th_ack);
t->winsize_orig = htons(tcphdr->th_win);
if (scale!=SCALE_NONE) t->scale_orig = scale;
}
}
else
{
if (bReverse)
{
t->ack_last=t->pos_reply;
t->pos_reply+=len_payload;
}
else
{
t->seq_last=t->pos_orig;
t->pos_orig+=len_payload;
}
}
time(&t->t_last);
}
#define _ConntrackPoolFeed(v) \
t_conn##v conn, connswap; \
t_conntrack##v *ctr; \
bool b_rev; \
ConntrackExtractConn##v(&conn,false,ip,tcphdr); \
if ((ctr=ConntrackPoolSearch##v(*pp,&conn))) \
{ \
ConntrackFeedPacket(&ctr->track, (b_rev=false), tcphdr, len_payload); \
goto ok; \
} \
else \
{ \
connswap##v(&conn,&connswap); \
if ((ctr=ConntrackPoolSearch##v(*pp,&connswap))) \
{ \
ConntrackFeedPacket(&ctr->track, (b_rev=true), tcphdr, len_payload); \
goto ok; \
} \
} \
b_rev = tcp_synack_segment(tcphdr); \
if (tcp_syn_segment(tcphdr) || b_rev) \
{ \
if ((ctr=ConntrackNew##v(pp, b_rev ? &connswap : &conn))) \
{ \
ConntrackFeedPacket(&ctr->track, b_rev, tcphdr, len_payload); \
goto ok; \
} \
} \
return false; \
ok: \
if (ctrack) *ctrack = &ctr->track; \
if (bReverse) *bReverse = b_rev; \
return true;
static bool ConntrackPoolFeed4(t_conntrack4 **pp, const struct ip *ip, const struct tcphdr *tcphdr, uint32_t len_payload, t_ctrack **ctrack, bool *bReverse)
static bool ConntrackPoolFeedPool(t_conntrack_pool **pp, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, size_t len_payload, t_ctrack **ctrack, bool *bReverse)
{
_ConntrackPoolFeed(4)
}
static bool ConntrackPoolFeed6(t_conntrack6 **pp, const struct ip6_hdr *ip, const struct tcphdr *tcphdr, uint32_t len_payload, t_ctrack **ctrack, bool *bReverse)
{
_ConntrackPoolFeed(6)
}
bool ConntrackPoolFeed(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, size_t len_payload, t_ctrack **ctrack, bool *bReverse)
{
return ip ? ConntrackPoolFeed4(&p->pool4,ip,tcphdr,(uint32_t)len_payload,ctrack,bReverse) : ip6 ? ConntrackPoolFeed6(&p->pool6,ip6,tcphdr,(uint32_t)len_payload,ctrack,bReverse) : false;
}
t_conn conn, connswp;
t_conntrack_pool *ctr;
bool b_rev;
#define _ConntrackPoolDrop(v) \
t_conn##v conn, connswap; \
t_conntrack##v *t; \
ConntrackExtractConn##v(&conn,false,ip,tcphdr); \
if (!(t=ConntrackPoolSearch##v(*pp,&conn))) \
{ \
connswap##v(&conn,&connswap); \
t=ConntrackPoolSearch##v(*pp,&connswap); \
} \
if (!t) return false; \
HASH_DEL(*pp, t); free(t); \
return true;
static bool ConntrackPoolDrop4(t_conntrack4 **pp, const struct ip *ip, const struct tcphdr *tcphdr)
{
_ConntrackPoolDrop(4)
}
static bool ConntrackPoolDrop6(t_conntrack6 **pp, const struct ip6_hdr *ip, const struct tcphdr *tcphdr)
{
_ConntrackPoolDrop(6)
}
bool ConntrackPoolDrop(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr)
{
return ip ? ConntrackPoolDrop4(&p->pool4,ip,tcphdr) : ip6 ? ConntrackPoolDrop6(&p->pool6,ip6,tcphdr) : false;
}
#define _ConntrackPoolPurge(v, pp) \
{ \
t_conntrack##v *t, *tmp; \
time_t tidle; \
HASH_ITER(hh, *pp , t, tmp) { \
tidle = tnow - t->track.t_last; \
if ( t->track.b_cutoff || \
t->track.state==SYN && tidle>=p->timeout_syn || \
t->track.state==ESTABLISHED && tidle>=p->timeout_established || \
t->track.state==FIN && tidle>=p->timeout_fin) \
{ \
HASH_DEL(*pp, t); free(t); \
} \
} \
ConntrackExtractConn(&conn,false,ip,ip6,tcphdr,udphdr);
if ((ctr=ConntrackPoolSearch(*pp,&conn)))
{
ConntrackFeedPacket(&ctr->track, (b_rev=false), tcphdr, len_payload);
goto ok;
}
else
{
connswap(&conn,&connswp);
if ((ctr=ConntrackPoolSearch(*pp,&connswp)))
{
ConntrackFeedPacket(&ctr->track, (b_rev=true), tcphdr, len_payload);
goto ok;
}
}
b_rev = tcphdr && tcp_synack_segment(tcphdr);
if (tcphdr && tcp_syn_segment(tcphdr) || b_rev || udphdr)
{
if ((ctr=ConntrackNew(pp, b_rev ? &connswp : &conn)))
{
ConntrackFeedPacket(&ctr->track, b_rev, tcphdr, len_payload);
goto ok;
}
}
return false;
ok:
if (ctrack) *ctrack = &ctr->track;
if (bReverse) *bReverse = b_rev;
return true;
}
bool ConntrackPoolFeed(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, size_t len_payload, t_ctrack **ctrack, bool *bReverse)
{
return ConntrackPoolFeedPool(&p->pool,ip,ip6,tcphdr,udphdr,len_payload,ctrack,bReverse);
}
static bool ConntrackPoolDropPool(t_conntrack_pool **pp, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr)
{
t_conn conn, connswp;
t_conntrack_pool *t;
ConntrackExtractConn(&conn,false,ip,ip6,tcphdr,udphdr);
if (!(t=ConntrackPoolSearch(*pp,&conn)))
{
connswap(&conn,&connswp);
t=ConntrackPoolSearch(*pp,&connswp);
}
if (!t) return false;
HASH_DEL(*pp, t); free(t);
return true;
}
bool ConntrackPoolDrop(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr)
{
return ConntrackPoolDropPool(&p->pool,ip,ip6,tcphdr,udphdr);
}
void ConntrackPoolPurge(t_conntrack *p)
{
time_t tnow = time(NULL); \
time_t tidle, tnow = time(NULL);
t_conntrack_pool *t, *tmp;
if ((tnow - p->t_last_purge)>=p->t_purge_interval)
{
_ConntrackPoolPurge(4, &p->pool4);
_ConntrackPoolPurge(6, &p->pool6);
HASH_ITER(hh, p->pool , t, tmp) {
tidle = tnow - t->track.t_last;
if ( t->track.b_cutoff ||
t->conn.l4proto==IPPROTO_TCP && (
t->track.state==SYN && tidle>=p->timeout_syn ||
t->track.state==ESTABLISHED && tidle>=p->timeout_established ||
t->track.state==FIN && tidle>=p->timeout_fin) ||
t->conn.l4proto==IPPROTO_UDP &&
tidle>=p->timeout_udp)
{
HASH_DEL(p->pool, t); free(t);
}
}
p->t_last_purge = tnow;
}
}
static void taddr2str(uint8_t l3proto, const t_addr *a, char *buf, size_t bufsize)
{
if (!inet_ntop(family_from_proto(l3proto), a, buf, bufsize) && bufsize) *buf=0;
}
#define _ConntrackPoolDump(v,f) \
t_conntrack##v *t, *tmp; \
char sa1[40],sa2[40]; \
time_t tnow = time(NULL); \
HASH_ITER(hh, p, t, tmp) { \
*sa1=0; inet_ntop(AF_INET##f, &t->conn.e1.adr, sa1, sizeof(sa1)); \
*sa2=0; inet_ntop(AF_INET##f, &t->conn.e2.adr, sa2, sizeof(sa2)); \
printf("[%s]:%u => [%s]:%u : %s : t0=%llu last=t0+%llu now=last+%llu packets_orig=d%llu/n%llu packets_reply=d%llu/n%llu seq0=%u rseq=%u pos_orig=%u ack0=%u rack=%u pos_reply=%u wsize_orig=%u:%d wsize_reply=%u:%d cutoff=%u wss_cutoff=%u d_cutoff=%u\n", \
sa1, t->conn.e1.port, sa2, t->conn.e2.port, \
connstate_s[t->track.state], \
(unsigned long long)t->track.t_start, (unsigned long long)(t->track.t_last - t->track.t_start), (unsigned long long)(tnow - t->track.t_last), \
(unsigned long long)t->track.pdcounter_orig, (unsigned long long)t->track.pcounter_orig, \
(unsigned long long)t->track.pdcounter_reply, (unsigned long long)t->track.pcounter_reply,\
t->track.seq0, t->track.seq_last - t->track.seq0, t->track.pos_orig - t->track.seq0, \
t->track.ack0, t->track.ack_last - t->track.ack0, t->track.pos_reply - t->track.ack0, \
t->track.winsize_orig, t->track.scale_orig==SCALE_NONE ? -1 : t->track.scale_orig, \
t->track.winsize_reply, t->track.scale_reply==SCALE_NONE ? -1 : t->track.scale_reply, \
t->track.b_cutoff, t->track.b_wssize_cutoff, t->track.b_desync_cutoff); \
void ConntrackPoolDump(const t_conntrack *p)
{
t_conntrack_pool *t, *tmp;
char sa1[40],sa2[40];
time_t tnow = time(NULL);
HASH_ITER(hh, p->pool, t, tmp) {
taddr2str(t->conn.l3proto, &t->conn.src, sa1, sizeof(sa1));
taddr2str(t->conn.l3proto, &t->conn.dst, sa2, sizeof(sa2));
if (t->conn.l4proto==IPPROTO_TCP)
printf("%s [%s]:%u => [%s]:%u : %s : t0=%llu last=t0+%llu now=last+%llu packets_orig=d%llu/n%llu packets_reply=d%llu/n%llu seq0=%u rseq=%u pos_orig=%u ack0=%u rack=%u pos_reply=%u wsize_orig=%u:%d wsize_reply=%u:%d",
proto_name(t->conn.l4proto),
sa1, t->conn.sport, sa2, t->conn.dport,
t->conn.l4proto==IPPROTO_TCP ? connstate_s[t->track.state] : "-",
(unsigned long long)t->track.t_start, (unsigned long long)(t->track.t_last - t->track.t_start), (unsigned long long)(tnow - t->track.t_last),
(unsigned long long)t->track.pdcounter_orig, (unsigned long long)t->track.pcounter_orig,
(unsigned long long)t->track.pdcounter_reply, (unsigned long long)t->track.pcounter_reply,
t->track.seq0, t->track.seq_last - t->track.seq0, t->track.pos_orig - t->track.seq0,
t->track.ack0, t->track.ack_last - t->track.ack0, t->track.pos_reply - t->track.ack0,
t->track.winsize_orig, t->track.scale_orig==SCALE_NONE ? -1 : t->track.scale_orig,
t->track.winsize_reply, t->track.scale_reply==SCALE_NONE ? -1 : t->track.scale_reply);
else
printf("%s [%s]:%u => [%s]:%u : %s : t0=%llu last=t0+%llu now=last+%llu packets_orig=d%llu/n%llu packets_reply=d%llu/n%llu rseq=%u pos_orig=%u rack=%u pos_reply=%u",
proto_name(t->conn.l4proto),
sa1, t->conn.sport, sa2, t->conn.dport,
t->conn.l4proto==IPPROTO_TCP ? connstate_s[t->track.state] : "-",
(unsigned long long)t->track.t_start, (unsigned long long)(t->track.t_last - t->track.t_start), (unsigned long long)(tnow - t->track.t_last),
(unsigned long long)t->track.pdcounter_orig, (unsigned long long)t->track.pcounter_orig,
(unsigned long long)t->track.pdcounter_reply, (unsigned long long)t->track.pcounter_reply,
t->track.seq_last, t->track.pos_orig,
t->track.ack_last, t->track.pos_reply);
printf(" cutoff=%u wss_cutoff=%u d_cutoff=%u\n",
t->track.b_cutoff, t->track.b_wssize_cutoff, t->track.b_desync_cutoff);
};
void ConntrackPoolDump4(t_conntrack4 *p)
{
_ConntrackPoolDump(4,)
}
void ConntrackPoolDump6(t_conntrack6 *p)
{
_ConntrackPoolDump(6,6)
}
void ConntrackPoolDump(t_conntrack *p)
{
ConntrackPoolDump4(p->pool4);
ConntrackPoolDump6(p->pool6);
}

View File

@@ -12,6 +12,7 @@
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
//#define HASH_BLOOM 20
#define HASH_NONFATAL_OOM 1
@@ -19,26 +20,18 @@
#define HASH_FUNCTION HASH_BER
#include "uthash.h"
typedef union {
struct in_addr ip;
struct in6_addr ip6;
} t_addr;
typedef struct
{
struct in_addr adr;
uint16_t port;
} t_endpoint4;
typedef struct
{
struct in6_addr adr;
uint16_t port;
} t_endpoint6;
// e1 - initiator. the one who have sent SYN
// e2 - acceptor
typedef struct
{
t_endpoint4 e1,e2;
} t_conn4;
typedef struct
{
t_endpoint6 e1,e2;
} t_conn6;
t_addr src, dst;
uint16_t sport,dport;
uint8_t l3proto; // IPPROTO_IP, IPPROTO_IPV6
uint8_t l4proto; // IPPROTO_TCP, IPPROTO_UDP
} t_conn;
// SYN - SYN or SYN/ACK received
// ESTABLISHED - any except SYN or SYN/ACK received
@@ -46,53 +39,41 @@ typedef struct
typedef enum {SYN=0, ESTABLISHED, FIN} t_connstate;
typedef struct
{
t_connstate state;
// common state
time_t t_start, t_last;
uint32_t seq0, ack0; // starting seq and ack
uint32_t seq_last, ack_last; // last seen seq and ack
uint32_t pos_orig, pos_reply; // seq_last+payload, ack_last+payload
uint64_t pcounter_orig, pcounter_reply; // packet counter
uint64_t pdcounter_orig, pdcounter_reply; // data packet counter (with payload)
uint32_t pos_orig, pos_reply; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current
uint32_t seq_last, ack_last; // TCP: last seen seq and ack UDP: sum of all seen payload lenghts NOT including current
// tcp only state, not used in udp
t_connstate state;
uint32_t seq0, ack0; // starting seq and ack
uint16_t winsize_orig, winsize_reply; // last seen window size
uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none
bool b_cutoff; // mark for deletion
bool b_wssize_cutoff, b_desync_cutoff;
} t_ctrack;
// use separate pools for ipv4 and ipv6 to save RAM. otherwise could use union key
typedef struct
{
t_ctrack track;
UT_hash_handle hh; // makes this structure hashable
t_conn4 conn; // key
} t_conntrack4;
typedef struct
{
t_ctrack track;
UT_hash_handle hh; // makes this structure hashable
t_conn6 conn; // key
} t_conntrack6;
t_conn conn; // key
} t_conntrack_pool;
typedef struct
{
// inactivity time to purge an entry in each connection state
uint32_t timeout_syn,timeout_established,timeout_fin;
uint32_t timeout_syn,timeout_established,timeout_fin,timeout_udp;
time_t t_purge_interval, t_last_purge;
t_conntrack4 *pool4;
t_conntrack6 *pool6;
t_conntrack_pool *pool;
} t_conntrack;
void ConntrackPoolInit(t_conntrack *p, time_t purge_interval, uint32_t timeout_syn, uint32_t timeout_established, uint32_t timeout_fin);
void ConntrackPoolInit(t_conntrack *p, time_t purge_interval, uint32_t timeout_syn, uint32_t timeout_established, uint32_t timeout_fin, uint32_t timeout_udp);
void ConntrackPoolDestroy(t_conntrack *p);
bool ConntrackPoolFeed(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, size_t len_payload, t_ctrack **ctrack, bool *bReverse);
bool ConntrackPoolDrop(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr);
void ConntrackExtractConn4(t_conn4 *c, bool bReverse, const struct ip *ip, const struct tcphdr *tcphdr);
void ConntrackExtractConn6(t_conn6 *c, bool bReverse, const struct ip6_hdr *ip, const struct tcphdr *tcphdr);
void ConntrackPoolDump4(t_conntrack4 *p);
void ConntrackPoolDump6(t_conntrack6 *p);
void ConntrackPoolDump(t_conntrack *p);
bool ConntrackPoolFeed(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, size_t len_payload, t_ctrack **ctrack, bool *bReverse);
bool ConntrackPoolDrop(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr);
void CaonntrackExtractConn(t_conn *c, bool bReverse, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr);
void ConntrackPoolDump(const t_conntrack *p);
void ConntrackPoolPurge(t_conntrack *p);

View File

@@ -67,9 +67,9 @@ static void fill_tcphdr(
uint8_t t=0;
memset(tcp,0,sizeof(*tcp));
tcp->th_sport = nsport;
tcp->th_dport = ndport;
if (fooling & TCP_FOOL_BADSEQ)
tcp->th_sport = nsport;
tcp->th_dport = ndport;
if (fooling & FOOL_BADSEQ)
{
tcp->th_seq = net32_add(nseq,badseq_increment);
tcp->th_ack = net32_add(nack_seq,badseq_ack_increment);
@@ -82,7 +82,7 @@ static void fill_tcphdr(
tcp->th_off = 5;
*((uint8_t*)tcp+13)= tcp_flags;
tcp->th_win = nwsize;
if (fooling & TCP_FOOL_MD5SIG)
if (fooling & FOOL_MD5SIG)
{
tcpopt[0] = 19; // kind
tcpopt[1] = 18; // len
@@ -92,13 +92,13 @@ static void fill_tcphdr(
*(uint32_t*)(tcpopt+14)=random();
t=18;
}
if (timestamps || (fooling & TCP_FOOL_TS))
if (timestamps || (fooling & FOOL_TS))
{
tcpopt[t] = 8; // kind
tcpopt[t+1] = 10; // len
// forge only TSecr if orig timestamp is present
*(uint32_t*)(tcpopt+t+2) = timestamps ? timestamps[0] : -1;
*(uint32_t*)(tcpopt+t+6) = (timestamps && !(fooling & TCP_FOOL_TS)) ? timestamps[1] : -1;
*(uint32_t*)(tcpopt+t+6) = (timestamps && !(fooling & FOOL_TS)) ? timestamps[1] : -1;
t+=10;
}
if (scale_factor!=SCALE_NONE)
@@ -109,16 +109,518 @@ static void fill_tcphdr(
}
while (t&3) tcpopt[t++]=1; // noop
tcp->th_off += t>>2;
tcp->th_sum = 0;
}
static uint16_t tcpopt_len(uint8_t fooling, const uint32_t *timestamps, uint8_t scale_factor)
{
uint16_t t=0;
if (fooling & TCP_FOOL_MD5SIG) t=18;
if ((fooling & TCP_FOOL_TS) || timestamps) t+=10;
if (fooling & FOOL_MD5SIG) t=18;
if ((fooling & FOOL_TS) || timestamps) t+=10;
if (scale_factor!=SCALE_NONE) t+=3;
return (t+3)&~3;
}
// n prefix (nsport, nwsize) means network byte order
static void fill_udphdr(struct udphdr *udp, uint16_t nsport, uint16_t ndport, uint16_t len_payload)
{
udp->uh_sport = nsport;
udp->uh_dport = ndport;
udp->uh_ulen = htons(len_payload+sizeof(struct udphdr));
udp->uh_sum = 0;
}
static void fill_iphdr(struct ip *ip, const struct in_addr *src, const struct in_addr *dst, uint16_t pktlen, uint8_t proto, uint8_t ttl)
{
ip->ip_off = 0;
ip->ip_v = 4;
ip->ip_hl = 5;
ip->ip_len = htons(pktlen);
ip->ip_id = 0;
ip->ip_ttl = ttl;
ip->ip_p = proto;
ip->ip_src = *src;
ip->ip_dst = *dst;
}
static void fill_ip6hdr(struct ip6_hdr *ip6, const struct in6_addr *src, const struct in6_addr *dst, uint16_t payloadlen, uint8_t proto, uint8_t ttl)
{
ip6->ip6_ctlun.ip6_un1.ip6_un1_flow = htonl(0x60000000);
ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(payloadlen);
ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt = proto;
ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = ttl;
ip6->ip6_src = *src;
ip6->ip6_dst = *dst;
}
bool prepare_tcp_segment4(
const struct sockaddr_in *src, const struct sockaddr_in *dst,
uint8_t tcp_flags,
uint32_t nseq, uint32_t nack_seq,
uint16_t nwsize,
uint8_t scale_factor,
uint32_t *timestamps,
uint8_t ttl,
uint8_t fooling,
uint32_t badseq_increment,
uint32_t badseq_ack_increment,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen)
{
uint16_t tcpoptlen = tcpopt_len(fooling,timestamps,scale_factor);
uint16_t ip_payload_len = sizeof(struct tcphdr) + tcpoptlen + len;
uint16_t pktlen = sizeof(struct ip) + ip_payload_len;
if (pktlen>*buflen) return false;
struct ip *ip = (struct ip*)buf;
struct tcphdr *tcp = (struct tcphdr*)(ip+1);
uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen;
fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_TCP, ttl);
fill_tcphdr(tcp,fooling,tcp_flags,nseq,nack_seq,src->sin_port,dst->sin_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment);
memcpy(payload,data,len);
tcp4_fix_checksum(tcp,ip_payload_len,&ip->ip_src,&ip->ip_dst);
if (fooling & FOOL_BADSUM) tcp->th_sum^=htons(0xBEAF);
*buflen = pktlen;
return true;
}
bool prepare_tcp_segment6(
const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst,
uint8_t tcp_flags,
uint32_t nseq, uint32_t nack_seq,
uint16_t nwsize,
uint8_t scale_factor,
uint32_t *timestamps,
uint8_t ttl,
uint8_t fooling,
uint32_t badseq_increment,
uint32_t badseq_ack_increment,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen)
{
uint16_t tcpoptlen = tcpopt_len(fooling,timestamps,scale_factor);
uint16_t ip_payload_len = sizeof(struct tcphdr) + tcpoptlen + len;
uint16_t pktlen = sizeof(struct ip6_hdr) + ip_payload_len;
if (pktlen>*buflen) return false;
struct ip6_hdr *ip6 = (struct ip6_hdr*)buf;
struct tcphdr *tcp = (struct tcphdr*)(ip6+1);
uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen;
fill_ip6hdr(ip6, &src->sin6_addr, &dst->sin6_addr, ip_payload_len, IPPROTO_TCP, ttl);
fill_tcphdr(tcp,fooling,tcp_flags,nseq,nack_seq,src->sin6_port,dst->sin6_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment);
memcpy(payload,data,len);
tcp6_fix_checksum(tcp,ip_payload_len,&ip6->ip6_src,&ip6->ip6_dst);
if (fooling & FOOL_BADSUM) tcp->th_sum^=htons(0xBEAF);
*buflen = pktlen;
return true;
}
bool prepare_tcp_segment(
const struct sockaddr *src, const struct sockaddr *dst,
uint8_t tcp_flags,
uint32_t nseq, uint32_t nack_seq,
uint16_t nwsize,
uint8_t scale_factor,
uint32_t *timestamps,
uint8_t ttl,
uint8_t fooling,
uint32_t badseq_increment,
uint32_t badseq_ack_increment,
const void *data, uint16_t len,
uint8_t *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,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,fooling,badseq_increment,badseq_ack_increment,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,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) :
false;
}
bool prepare_udp_segment4(
const struct sockaddr_in *src, const struct sockaddr_in *dst,
uint8_t ttl,
uint8_t fooling,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen)
{
uint16_t ip_payload_len = sizeof(struct udphdr) + len;
uint16_t pktlen = sizeof(struct ip) + ip_payload_len;
if (pktlen>*buflen) return false;
struct ip *ip = (struct ip*)buf;
struct udphdr *udp = (struct udphdr*)(ip+1);
uint8_t *payload = (uint8_t*)(udp+1);
fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_UDP, ttl);
fill_udphdr(udp, src->sin_port, dst->sin_port, len);
memcpy(payload,data,len);
udp4_fix_checksum(udp,ip_payload_len,&ip->ip_src,&ip->ip_dst);
if (fooling & FOOL_BADSUM) udp->uh_sum^=htons(0xBEAF);
*buflen = pktlen;
return true;
}
bool prepare_udp_segment6(
const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst,
uint8_t ttl,
uint8_t fooling,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen)
{
uint16_t ip_payload_len = sizeof(struct udphdr) + len;
uint16_t pktlen = sizeof(struct ip6_hdr) + ip_payload_len;
if (pktlen>*buflen) return false;
struct ip6_hdr *ip6 = (struct ip6_hdr*)buf;
struct udphdr *udp = (struct udphdr*)(ip6+1);
uint8_t *payload = (uint8_t*)(udp+1);
fill_ip6hdr(ip6, &src->sin6_addr, &dst->sin6_addr, ip_payload_len, IPPROTO_UDP, ttl);
fill_udphdr(udp, src->sin6_port, dst->sin6_port, len);
memcpy(payload,data,len);
udp6_fix_checksum(udp,ip_payload_len,&ip6->ip6_src,&ip6->ip6_dst);
if (fooling & FOOL_BADSUM) udp->uh_sum^=htons(0xBEAF);
*buflen = pktlen;
return true;
}
bool prepare_udp_segment(
const struct sockaddr *src, const struct sockaddr *dst,
uint8_t ttl,
uint8_t fooling,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen)
{
return (src->sa_family==AF_INET && dst->sa_family==AF_INET) ?
prepare_udp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,ttl,fooling,data,len,buf,buflen) :
(src->sa_family==AF_INET6 && dst->sa_family==AF_INET6) ?
prepare_udp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,ttl,fooling,data,len,buf,buflen) :
false;
}
void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport)
{
if (sport) *sport = htons(tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport : 0);
if (dport) *dport = htons(tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport : 0);
if (proto) *proto = tcphdr ? IPPROTO_TCP : udphdr ? IPPROTO_UDP : -1;
}
void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const struct tcphdr *tcphdr,const struct udphdr *udphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst)
{
if (ip)
{
struct sockaddr_in *si;
if (dst)
{
si = (struct sockaddr_in*)dst;
si->sin_family = AF_INET;
si->sin_port = tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport : 0;
si->sin_addr = ip->ip_dst;
}
if (src)
{
si = (struct sockaddr_in*)src;
si->sin_family = AF_INET;
si->sin_port = tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport : 0;
si->sin_addr = ip->ip_src;
}
}
else if (ip6hdr)
{
struct sockaddr_in6 *si;
if (dst)
{
si = (struct sockaddr_in6*)dst;
si->sin6_family = AF_INET6;
si->sin6_port = tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport : 0;
si->sin6_addr = ip6hdr->ip6_dst;
si->sin6_flowinfo = 0;
si->sin6_scope_id = 0;
}
if (src)
{
si = (struct sockaddr_in6*)src;
si->sin6_family = AF_INET6;
si->sin6_port = tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport : 0;
si->sin6_addr = ip6hdr->ip6_src;
si->sin6_flowinfo = 0;
si->sin6_scope_id = 0;
}
}
}
const char *proto_name(uint8_t proto)
{
switch(proto)
{
case IPPROTO_TCP:
return "tcp";
case IPPROTO_UDP:
return "udp";
case IPPROTO_ICMP:
return "icmp";
case IPPROTO_IGMP:
return "igmp";
case IPPROTO_ESP:
return "esp";
case IPPROTO_AH:
return "ah";
case IPPROTO_IPV6:
return "6in4";
case IPPROTO_IPIP:
return "4in4";
case IPPROTO_GRE:
return "gre";
#ifdef IPPROTO_SCTP
case IPPROTO_SCTP:
return "sctp";
#endif
default:
return NULL;
}
}
static void str_proto_name(char *s, size_t s_len, uint8_t proto)
{
const char *name = proto_name(proto);
if (name)
snprintf(s,s_len,"%s",name);
else
snprintf(s,s_len,"%u",proto);
}
uint16_t family_from_proto(uint8_t l3proto)
{
switch(l3proto)
{
case IPPROTO_IP: return AF_INET;
case IPPROTO_IPV6: return AF_INET6;
default: return -1;
}
}
static void str_srcdst_ip(char *s, size_t s_len, const void *saddr,const void *daddr)
{
char s_ip[16],d_ip[16];
*s_ip=*d_ip=0;
inet_ntop(AF_INET, saddr, s_ip, sizeof(s_ip));
inet_ntop(AF_INET, daddr, d_ip, sizeof(d_ip));
snprintf(s,s_len,"%s => %s",s_ip,d_ip);
}
static void str_ip(char *s, size_t s_len, const struct ip *ip)
{
char ss[35],s_proto[16];
str_srcdst_ip(ss,sizeof(ss),&ip->ip_src,&ip->ip_dst);
str_proto_name(s_proto,sizeof(s_proto),ip->ip_p);
snprintf(s,s_len,"%s proto=%s",ss,s_proto);
}
void print_ip(const struct ip *ip)
{
char s[64];
str_ip(s,sizeof(s),ip);
printf("%s",s);
}
static void str_srcdst_ip6(char *s, size_t s_len, const void *saddr,const void *daddr)
{
char s_ip[40],d_ip[40];
*s_ip=*d_ip=0;
inet_ntop(AF_INET6, saddr, s_ip, sizeof(s_ip));
inet_ntop(AF_INET6, daddr, d_ip, sizeof(d_ip));
snprintf(s,s_len,"%s => %s",s_ip,d_ip);
}
static void str_ip6hdr(char *s, size_t s_len, const struct ip6_hdr *ip6hdr, uint8_t proto)
{
char ss[83],s_proto[16];
str_srcdst_ip6(ss,sizeof(ss),&ip6hdr->ip6_src,&ip6hdr->ip6_dst);
str_proto_name(s_proto,sizeof(s_proto),proto);
snprintf(s,s_len,"%s proto=%s",ss,s_proto);
}
void print_ip6hdr(const struct ip6_hdr *ip6hdr, uint8_t proto)
{
char s[128];
str_ip6hdr(s,sizeof(s),ip6hdr,proto);
printf("%s",s);
}
static void str_tcphdr(char *s, size_t s_len, const struct tcphdr *tcphdr)
{
char flags[7],*f=flags;
if (tcphdr->th_flags & TH_SYN) *f++='S';
if (tcphdr->th_flags & TH_ACK) *f++='A';
if (tcphdr->th_flags & TH_RST) *f++='R';
if (tcphdr->th_flags & TH_FIN) *f++='F';
if (tcphdr->th_flags & TH_PUSH) *f++='P';
if (tcphdr->th_flags & TH_URG) *f++='U';
*f=0;
snprintf(s,s_len,"sport=%u dport=%u flags=%s seq=%u ack_seq=%u",htons(tcphdr->th_sport),htons(tcphdr->th_dport),flags,htonl(tcphdr->th_seq),htonl(tcphdr->th_ack));
}
void print_tcphdr(const struct tcphdr *tcphdr)
{
char s[80];
str_tcphdr(s,sizeof(s),tcphdr);
printf("%s",s);
}
static void str_udphdr(char *s, size_t s_len, const struct udphdr *udphdr)
{
snprintf(s,s_len,"sport=%u dport=%u",htons(udphdr->uh_sport),htons(udphdr->uh_dport));
}
void print_udphdr(const struct udphdr *udphdr)
{
char s[30];
str_udphdr(s,sizeof(s),udphdr);
printf("%s",s);
}
bool proto_check_ipv4(const uint8_t *data, size_t len)
{
return len >= 20 && (data[0] & 0xF0) == 0x40 &&
len >= ((data[0] & 0x0F) << 2);
}
// move to transport protocol
void proto_skip_ipv4(uint8_t **data, size_t *len)
{
size_t l;
l = (**data & 0x0F) << 2;
*data += l;
*len -= l;
}
bool proto_check_tcp(const uint8_t *data, size_t len)
{
return len >= 20 && len >= ((data[12] & 0xF0) >> 2);
}
void proto_skip_tcp(uint8_t **data, size_t *len)
{
size_t l;
l = ((*data)[12] & 0xF0) >> 2;
*data += l;
*len -= l;
}
bool proto_check_udp(const uint8_t *data, size_t len)
{
return len >= 8 && len>=(data[4]<<8 | data[5]);
}
void proto_skip_udp(uint8_t **data, size_t *len)
{
*data += 8;
*len -= 8;
}
bool proto_check_ipv6(const uint8_t *data, size_t len)
{
return len >= 40 && (data[0] & 0xF0) == 0x60 &&
(len - 40) >= htons(*(uint16_t*)(data + 4)); // payload length
}
// move to transport protocol
// proto_type = 0 => error
void proto_skip_ipv6(uint8_t **data, size_t *len, uint8_t *proto_type)
{
size_t hdrlen;
uint8_t HeaderType;
if (proto_type) *proto_type = 0; // put error in advance
HeaderType = (*data)[6]; // NextHeader field
*data += 40; *len -= 40; // skip ipv6 base header
while (*len > 0) // need at least one byte for NextHeader field
{
switch (HeaderType)
{
case 0: // Hop-by-Hop Options
case 43: // routing
case 51: // authentication
case 60: // Destination Options
case 135: // mobility
case 139: // Host Identity Protocol Version v2
case 140: // Shim6
if (*len < 2) return; // error
hdrlen = 8 + ((*data)[1] << 3);
break;
case 44: // fragment. length fixed to 8, hdrlen field defined as reserved
hdrlen = 8;
break;
case 59: // no next header
return; // error
default:
// we found some meaningful payload. it can be tcp, udp, icmp or some another exotic shit
if (proto_type) *proto_type = HeaderType;
return;
}
if (*len < hdrlen) return; // error
HeaderType = **data;
// advance to the next header location
*len -= hdrlen;
*data += hdrlen;
}
// we have garbage
}
bool tcp_synack_segment(const struct tcphdr *tcphdr)
{
/* check for set bits in TCP hdr */
return ((tcphdr->th_flags & (TH_URG|TH_ACK|TH_PUSH|TH_RST|TH_SYN|TH_FIN)) == (TH_ACK|TH_SYN));
}
bool tcp_syn_segment(const struct tcphdr *tcphdr)
{
/* check for set bits in TCP hdr */
return ((tcphdr->th_flags & (TH_URG|TH_ACK|TH_PUSH|TH_RST|TH_SYN|TH_FIN)) == TH_SYN);
}
bool tcp_ack_segment(const struct tcphdr *tcphdr)
{
/* check for set bits in TCP hdr */
return ((tcphdr->th_flags & (TH_URG|TH_ACK|TH_PUSH|TH_RST|TH_SYN|TH_FIN)) == TH_ACK);
}
void tcp_rewrite_wscale(struct tcphdr *tcp, uint8_t scale_factor)
{
uint8_t *scale,scale_factor_old;
if (scale_factor!=SCALE_NONE)
{
scale = tcp_find_option(tcp,3); // tcp option 3 - scale factor
if (scale && scale[1]==3) // length should be 3
{
scale_factor_old=scale[2];
// do not allow increasing scale factor
if (scale_factor>=scale_factor_old)
DLOG("Scale factor %u unchanged\n", scale_factor_old)
else
{
scale[2]=scale_factor;
DLOG("Scale factor change %u => %u\n", scale_factor_old, scale_factor)
}
}
}
}
// scale_factor=SCALE_NONE - do not change
void tcp_rewrite_winsize(struct tcphdr *tcp, uint16_t winsize, uint8_t scale_factor)
{
uint16_t winsize_old;
winsize_old = htons(tcp->th_win); // << scale_factor;
tcp->th_win = htons(winsize);
DLOG("Window size change %u => %u\n", winsize_old, winsize)
tcp_rewrite_wscale(tcp, scale_factor);
}
static int rawsend_sock4=-1, rawsend_sock6=-1;
static void rawsend_clean_sock(int *sock)
{
@@ -288,7 +790,7 @@ bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const void *data,size_t
// BSD ipv6 raw socks are limited. cannot pass the whole packet with ip6 header.
struct sockaddr_storage sa_src;
int v;
extract_endpoints(NULL,(struct ip6_hdr *)data,NULL, &sa_src, NULL);
extract_endpoints(NULL,(struct ip6_hdr *)data,NULL,NULL, &sa_src, NULL);
v = ((struct ip6_hdr *)data)->ip6_ctlun.ip6_un1.ip6_un1_hlim;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &v, sizeof(v)) == -1)
perror("rawsend: setsockopt(IPV6_HOPLIMIT)");
@@ -316,7 +818,7 @@ bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const void *data,size_t
#endif
#if defined(__FreeBSD__) && __FreeBSD__<=10
// old FreeBSD requires some fields in the host byte order
// old FreeBSD requires some fields in host byte order
if (dst->sa_family==AF_INET && len>=sizeof(struct ip))
{
((struct ip*)data)->ip_len = htons(((struct ip*)data)->ip_len);
@@ -340,385 +842,3 @@ bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const void *data,size_t
}
return true;
}
bool prepare_tcp_segment4(
const struct sockaddr_in *src, const struct sockaddr_in *dst,
uint8_t tcp_flags,
uint32_t nseq, uint32_t nack_seq,
uint16_t nwsize,
uint8_t scale_factor,
uint32_t *timestamps,
uint8_t ttl,
uint8_t fooling,
uint32_t badseq_increment,
uint32_t badseq_ack_increment,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen)
{
uint16_t tcpoptlen = tcpopt_len(fooling,timestamps, scale_factor);
uint16_t pktlen = sizeof(struct ip) + sizeof(struct tcphdr) + tcpoptlen + len;
if (pktlen>*buflen)
{
fprintf(stderr,"prepare_tcp_segment : packet len cannot exceed %zu\n",*buflen);
return false;
}
struct ip *ip = (struct ip*) buf;
struct tcphdr *tcp = (struct tcphdr*) (ip+1);
ip->ip_off = 0;
ip->ip_v = 4;
ip->ip_hl = 5;
ip->ip_len = htons(pktlen);
ip->ip_id = 0;
ip->ip_ttl = ttl;
ip->ip_p = IPPROTO_TCP;
ip->ip_src = src->sin_addr;
ip->ip_dst = dst->sin_addr;
fill_tcphdr(tcp,fooling,tcp_flags,nseq,nack_seq,src->sin_port,dst->sin_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment);
memcpy((char*)tcp+sizeof(struct tcphdr)+tcpoptlen,data,len);
tcp4_fix_checksum(tcp,sizeof(struct tcphdr)+tcpoptlen+len,&ip->ip_src,&ip->ip_dst);
if (fooling & TCP_FOOL_BADSUM) tcp->th_sum^=0xBEAF;
*buflen = pktlen;
return true;
}
bool prepare_tcp_segment6(
const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst,
uint8_t tcp_flags,
uint32_t nseq, uint32_t nack_seq,
uint16_t nwsize,
uint8_t scale_factor,
uint32_t *timestamps,
uint8_t ttl,
uint8_t fooling,
uint32_t badseq_increment,
uint32_t badseq_ack_increment,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen)
{
uint16_t tcpoptlen = tcpopt_len(fooling,timestamps, scale_factor);
uint16_t payloadlen = sizeof(struct tcphdr) + tcpoptlen + len;
uint16_t pktlen = sizeof(struct ip6_hdr) + payloadlen;
if (pktlen>*buflen)
{
fprintf(stderr,"prepare_tcp_segment : packet len cannot exceed %zu\n",*buflen);
return false;
}
struct ip6_hdr *ip6 = (struct ip6_hdr*) buf;
struct tcphdr *tcp = (struct tcphdr*) (ip6+1);
ip6->ip6_ctlun.ip6_un1.ip6_un1_flow = htonl(0x60000000);
ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(payloadlen);
ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_TCP;
ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = ttl;
ip6->ip6_src = src->sin6_addr;
ip6->ip6_dst = dst->sin6_addr;
fill_tcphdr(tcp,fooling,tcp_flags,nseq,nack_seq,src->sin6_port,dst->sin6_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment);
memcpy((char*)tcp+sizeof(struct tcphdr)+tcpoptlen,data,len);
tcp6_fix_checksum(tcp,sizeof(struct tcphdr)+tcpoptlen+len,&ip6->ip6_src,&ip6->ip6_dst);
if (fooling & TCP_FOOL_BADSUM) tcp->th_sum^=0xBEAF;
*buflen = pktlen;
return true;
}
bool prepare_tcp_segment(
const struct sockaddr *src, const struct sockaddr *dst,
uint8_t tcp_flags,
uint32_t nseq, uint32_t nack_seq,
uint16_t nwsize,
uint8_t scale_factor,
uint32_t *timestamps,
uint8_t ttl,
uint8_t fooling,
uint32_t badseq_increment,
uint32_t badseq_ack_increment,
const void *data, uint16_t len,
uint8_t *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,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,fooling,badseq_increment,badseq_ack_increment,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,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) :
false;
}
void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const struct tcphdr *tcphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst)
{
if (ip)
{
struct sockaddr_in *si;
if (dst)
{
si = (struct sockaddr_in*)dst;
si->sin_family = AF_INET;
si->sin_port = tcphdr ? tcphdr->th_dport : 0;
si->sin_addr = ip->ip_dst;
}
if (src)
{
si = (struct sockaddr_in*)src;
si->sin_family = AF_INET;
si->sin_port = tcphdr ? tcphdr->th_sport : 0;
si->sin_addr = ip->ip_src;
}
}
else if (ip6hdr)
{
struct sockaddr_in6 *si;
if (dst)
{
si = (struct sockaddr_in6*)dst;
si->sin6_family = AF_INET6;
si->sin6_port = tcphdr ? tcphdr->th_dport : 0;
si->sin6_addr = ip6hdr->ip6_dst;
si->sin6_flowinfo = 0;
si->sin6_scope_id = 0;
}
if (src)
{
si = (struct sockaddr_in6*)src;
si->sin6_family = AF_INET6;
si->sin6_port = tcphdr ? tcphdr->th_sport : 0;
si->sin6_addr = ip6hdr->ip6_src;
si->sin6_flowinfo = 0;
si->sin6_scope_id = 0;
}
}
}
static const char *proto_name(uint8_t proto)
{
switch(proto)
{
case IPPROTO_TCP:
return "tcp";
case IPPROTO_UDP:
return "udp";
case IPPROTO_ICMP:
return "icmp";
case IPPROTO_IGMP:
return "igmp";
case IPPROTO_ESP:
return "esp";
case IPPROTO_AH:
return "ah";
case IPPROTO_IPV6:
return "6in4";
#ifdef IPPROTO_SCTP
case IPPROTO_SCTP:
return "sctp";
#endif
default:
return NULL;
}
}
static void str_proto_name(char *s, size_t s_len, uint8_t proto)
{
const char *name = proto_name(proto);
if (name)
snprintf(s,s_len,"%s",name);
else
snprintf(s,s_len,"%u",proto);
}
static void str_srcdst_ip(char *s, size_t s_len, const void *saddr,const void *daddr)
{
char s_ip[16],d_ip[16];
*s_ip=*d_ip=0;
inet_ntop(AF_INET, saddr, s_ip, sizeof(s_ip));
inet_ntop(AF_INET, daddr, d_ip, sizeof(d_ip));
snprintf(s,s_len,"%s => %s",s_ip,d_ip);
}
static void str_ip(char *s, size_t s_len, const struct ip *ip)
{
char ss[35],s_proto[16];
str_srcdst_ip(ss,sizeof(ss),&ip->ip_src,&ip->ip_dst);
str_proto_name(s_proto,sizeof(s_proto),ip->ip_p);
snprintf(s,s_len,"%s proto=%s",ss,s_proto);
}
void print_ip(const struct ip *ip)
{
char s[64];
str_ip(s,sizeof(s),ip);
printf("%s",s);
}
static void str_srcdst_ip6(char *s, size_t s_len, const void *saddr,const void *daddr)
{
char s_ip[40],d_ip[40];
*s_ip=*d_ip=0;
inet_ntop(AF_INET6, saddr, s_ip, sizeof(s_ip));
inet_ntop(AF_INET6, daddr, d_ip, sizeof(d_ip));
snprintf(s,s_len,"%s => %s",s_ip,d_ip);
}
static void str_ip6hdr(char *s, size_t s_len, const struct ip6_hdr *ip6hdr, uint8_t proto)
{
char ss[83],s_proto[16];
str_srcdst_ip6(ss,sizeof(ss),&ip6hdr->ip6_src,&ip6hdr->ip6_dst);
str_proto_name(s_proto,sizeof(s_proto),proto);
snprintf(s,s_len,"%s proto=%s",ss,s_proto);
}
void print_ip6hdr(const struct ip6_hdr *ip6hdr, uint8_t proto)
{
char s[128];
str_ip6hdr(s,sizeof(s),ip6hdr,proto);
printf("%s",s);
}
static void str_tcphdr(char *s, size_t s_len, const struct tcphdr *tcphdr)
{
char flags[7],*f=flags;
if (tcphdr->th_flags & TH_SYN) *f++='S';
if (tcphdr->th_flags & TH_ACK) *f++='A';
if (tcphdr->th_flags & TH_RST) *f++='R';
if (tcphdr->th_flags & TH_FIN) *f++='F';
if (tcphdr->th_flags & TH_PUSH) *f++='P';
if (tcphdr->th_flags & TH_URG) *f++='U';
*f=0;
snprintf(s,s_len,"sport=%u dport=%u flags=%s seq=%u ack_seq=%u",htons(tcphdr->th_sport),htons(tcphdr->th_dport),flags,htonl(tcphdr->th_seq),htonl(tcphdr->th_ack));
}
void print_tcphdr(const struct tcphdr *tcphdr)
{
char s[80];
str_tcphdr(s,sizeof(s),tcphdr);
printf("%s",s);
}
bool proto_check_ipv4(const uint8_t *data, size_t len)
{
return len >= 20 && (data[0] & 0xF0) == 0x40 &&
len >= ((data[0] & 0x0F) << 2);
}
// move to transport protocol
void proto_skip_ipv4(uint8_t **data, size_t *len)
{
size_t l;
l = (**data & 0x0F) << 2;
*data += l;
*len -= l;
}
bool proto_check_tcp(const uint8_t *data, size_t len)
{
return len >= 20 && len >= ((data[12] & 0xF0) >> 2);
}
void proto_skip_tcp(uint8_t **data, size_t *len)
{
size_t l;
l = ((*data)[12] & 0xF0) >> 2;
*data += l;
*len -= l;
}
bool proto_check_ipv6(const uint8_t *data, size_t len)
{
return len >= 40 && (data[0] & 0xF0) == 0x60 &&
(len - 40) >= htons(*(uint16_t*)(data + 4)); // payload length
}
// move to transport protocol
// proto_type = 0 => error
void proto_skip_ipv6(uint8_t **data, size_t *len, uint8_t *proto_type)
{
size_t hdrlen;
uint8_t HeaderType;
if (proto_type) *proto_type = 0; // put error in advance
HeaderType = (*data)[6]; // NextHeader field
*data += 40; *len -= 40; // skip ipv6 base header
while (*len > 0) // need at least one byte for NextHeader field
{
switch (HeaderType)
{
case 0: // Hop-by-Hop Options
case 43: // routing
case 51: // authentication
case 60: // Destination Options
case 135: // mobility
case 139: // Host Identity Protocol Version v2
case 140: // Shim6
if (*len < 2) return; // error
hdrlen = 8 + ((*data)[1] << 3);
break;
case 44: // fragment. length fixed to 8, hdrlen field defined as reserved
hdrlen = 8;
break;
case 59: // no next header
return; // error
default:
// we found some meaningful payload. it can be tcp, udp, icmp or some another exotic shit
if (proto_type) *proto_type = HeaderType;
return;
}
if (*len < hdrlen) return; // error
HeaderType = **data;
// advance to the next header location
*len -= hdrlen;
*data += hdrlen;
}
// we have garbage
}
bool tcp_synack_segment(const struct tcphdr *tcphdr)
{
/* check for set bits in TCP hdr */
return ((tcphdr->th_flags & (TH_URG|TH_ACK|TH_PUSH|TH_RST|TH_SYN|TH_FIN)) == (TH_ACK|TH_SYN));
}
bool tcp_syn_segment(const struct tcphdr *tcphdr)
{
/* check for set bits in TCP hdr */
return ((tcphdr->th_flags & (TH_URG|TH_ACK|TH_PUSH|TH_RST|TH_SYN|TH_FIN)) == TH_SYN);
}
bool tcp_ack_segment(const struct tcphdr *tcphdr)
{
/* check for set bits in TCP hdr */
return ((tcphdr->th_flags & (TH_URG|TH_ACK|TH_PUSH|TH_RST|TH_SYN|TH_FIN)) == TH_ACK);
}
void tcp_rewrite_wscale(struct tcphdr *tcp, uint8_t scale_factor)
{
uint8_t *scale,scale_factor_old;
if (scale_factor!=SCALE_NONE)
{
scale = tcp_find_option(tcp,3); // tcp option 3 - scale factor
if (scale && scale[1]==3) // length should be 3
{
scale_factor_old=scale[2];
// do not allow increasing scale factor
if (scale_factor>=scale_factor_old)
DLOG("Scale factor %u unchanged\n", scale_factor_old)
else
{
scale[2]=scale_factor;
DLOG("Scale factor change %u => %u\n", scale_factor_old, scale_factor)
}
}
}
}
// scale_factor=SCALE_NONE - do not change
void tcp_rewrite_winsize(struct tcphdr *tcp, uint16_t winsize, uint8_t scale_factor)
{
uint16_t winsize_old;
winsize_old = htons(tcp->th_win); // << scale_factor;
tcp->th_win = htons(winsize);
DLOG("Window size change %u => %u\n", winsize_old, winsize)
tcp_rewrite_wscale(tcp, scale_factor);
}

View File

@@ -7,17 +7,18 @@
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/in.h>
#include <sys/socket.h>
// returns netorder value
uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment);
#define TCP_FOOL_NONE 0
#define TCP_FOOL_MD5SIG 1
#define TCP_FOOL_BADSUM 2
#define TCP_FOOL_TS 4
#define TCP_FOOL_BADSEQ 8
#define FOOL_NONE 0
#define FOOL_MD5SIG 1
#define FOOL_BADSUM 2
#define FOOL_TS 4
#define FOOL_BADSEQ 8
#define SCALE_NONE ((uint8_t)-1)
@@ -62,7 +63,29 @@ bool prepare_tcp_segment(
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen);
void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const struct tcphdr *tcphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst);
bool prepare_udp_segment4(
const struct sockaddr_in *src, const struct sockaddr_in *dst,
uint8_t ttl,
uint8_t fooling,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen);
bool prepare_udp_segment6(
const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst,
uint8_t ttl,
uint8_t fooling,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen);
bool prepare_udp_segment(
const struct sockaddr *src, const struct sockaddr *dst,
uint8_t ttl,
uint8_t fooling,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen);
void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport);
void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const struct tcphdr *tcphdr,const struct udphdr *udphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst);
uint8_t *tcp_find_option(struct tcphdr *tcp, uint8_t kind);
uint32_t *tcp_find_timestamps(struct tcphdr *tcp);
uint8_t tcp_find_scale_factor(const struct tcphdr *tcp);
@@ -74,17 +97,21 @@ bool rawsend_preinit(uint32_t fwmark);
// cleans up socket autocreated by rawsend
void rawsend_cleanup();
const char *proto_name(uint8_t proto);
uint16_t family_from_proto(uint8_t l3proto);
void print_ip(const struct ip *ip);
void print_ip6hdr(const struct ip6_hdr *ip6hdr, uint8_t proto);
void print_tcphdr(const struct tcphdr *tcphdr);
void print_udphdr(const struct udphdr *udphdr);
bool proto_check_ipv4(const uint8_t *data, size_t len);
void proto_skip_ipv4(uint8_t **data, size_t *len);
bool proto_check_tcp(const uint8_t *data, size_t len);
void proto_skip_tcp(uint8_t **data, size_t *len);
bool proto_check_ipv6(const uint8_t *data, size_t len);
void proto_skip_ipv6(uint8_t **data, size_t *len, uint8_t *proto_type);
bool proto_check_tcp(const uint8_t *data, size_t len);
void proto_skip_tcp(uint8_t **data, size_t *len);
bool proto_check_udp(const uint8_t *data, size_t len);
void proto_skip_udp(uint8_t **data, size_t *len);
bool tcp_synack_segment(const struct tcphdr *tcphdr);
bool tcp_syn_segment(const struct tcphdr *tcphdr);

View File

@@ -120,15 +120,18 @@ static bool cutoff_test(t_ctrack *ctrack, uint64_t cutoff, char mode)
{
return cutoff && cutoff_get_limit(ctrack, mode)>=cutoff;
}
static void maybe_cutoff(t_ctrack *ctrack)
static void maybe_cutoff(t_ctrack *ctrack, uint8_t proto)
{
if (ctrack)
{
ctrack->b_wssize_cutoff |= cutoff_test(ctrack, params.wssize_cutoff, params.wssize_cutoff_mode);
if (proto==IPPROTO_TCP)
ctrack->b_wssize_cutoff |= cutoff_test(ctrack, params.wssize_cutoff, params.wssize_cutoff_mode);
ctrack->b_desync_cutoff |= cutoff_test(ctrack, params.desync_cutoff, params.desync_cutoff_mode);
// we do not need conntrack entry anymore if all cutoff conditions are either not defined or reached
ctrack->b_cutoff |= (!params.wssize || ctrack->b_wssize_cutoff) && (!params.desync_cutoff || ctrack->b_desync_cutoff);
if (proto==IPPROTO_TCP)
// we do not need conntrack entry anymore if all cutoff conditions are either not defined or reached
// do not drop udp entry because it will be recreated when next packet arrives
ctrack->b_cutoff |= (!params.wssize || ctrack->b_wssize_cutoff) && (!params.desync_cutoff || ctrack->b_desync_cutoff);
}
}
static void wssize_cutoff(t_ctrack *ctrack)
@@ -136,12 +139,12 @@ static void wssize_cutoff(t_ctrack *ctrack)
if (ctrack)
{
ctrack->b_wssize_cutoff = true;
maybe_cutoff(ctrack);
maybe_cutoff(ctrack, IPPROTO_TCP);
}
}
#define CONNTRACK_REQUIRED (params.wssize || params.desync_cutoff)
// result : true - drop original packet, false = dont drop
packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, size_t len_tcp, uint8_t *data_payload, size_t len_payload)
packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, size_t len_tcp, uint8_t *data_payload, size_t len_payload)
{
packet_process_result res=pass;
t_ctrack *ctrack=NULL;
@@ -158,8 +161,8 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc
if (CONNTRACK_REQUIRED)
{
ConntrackPoolPurge(&params.conntrack);
if (ConntrackPoolFeed(&params.conntrack, ip, ip6hdr, tcphdr, len_payload, &ctrack, &bReverse))
maybe_cutoff(ctrack);
if (ConntrackPoolFeed(&params.conntrack, ip, ip6hdr, tcphdr, NULL, len_payload, &ctrack, &bReverse))
maybe_cutoff(ctrack, IPPROTO_TCP);
}
//ConntrackPoolDump(&params.conntrack);
@@ -202,14 +205,14 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc
scale_factor = tcp_find_scale_factor(tcphdr);
timestamps = tcp_find_timestamps(tcphdr);
extract_endpoints(ip, ip6hdr, tcphdr, &src, &dst);
extract_endpoints(ip, ip6hdr, tcphdr, NULL, &src, &dst);
}
if (params.desync_mode0==DESYNC_SYNACK && tcp_syn_segment(tcphdr))
{
newlen = sizeof(newdata);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_SYN|TH_ACK, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
ttl_fake,params.desync_tcp_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment,
ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment,
NULL, 0, newdata, &newlen))
{
return res;
@@ -352,7 +355,7 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc
{
case DESYNC_FAKE:
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
ttl_fake,params.desync_tcp_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment,
ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment,
fake, fake_size, newdata, &newlen))
{
return res;
@@ -364,7 +367,7 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc
case DESYNC_RST:
case DESYNC_RSTACK:
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (desync_mode==DESYNC_RSTACK ? TH_ACK:0), tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
ttl_fake,params.desync_tcp_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment,
ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment,
NULL, 0, newdata, &newlen))
{
return res;
@@ -416,7 +419,7 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc
if (split_pos<len_payload)
{
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(tcphdr->th_seq,split_pos), tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
ttl_orig,TCP_FOOL_NONE,params.desync_badseq_increment,params.desync_badseq_ack_increment,
ttl_orig,FOOL_NONE,params.desync_badseq_increment,params.desync_badseq_ack_increment,
data_payload+split_pos, len_payload-split_pos, newdata, &newlen))
return res;
DLOG("sending 2nd out-of-order tcp segment %zu-%zu len=%zu : ",split_pos,len_payload-1, len_payload-split_pos)
@@ -430,7 +433,7 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc
{
fakeseg_len = sizeof(fakeseg);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
ttl_fake,params.desync_tcp_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment,
ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment,
zeropkt, split_pos, fakeseg, &fakeseg_len))
return res;
DLOG("sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos)
@@ -442,7 +445,7 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc
newlen = sizeof(newdata);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
ttl_orig,TCP_FOOL_NONE,params.desync_badseq_increment,params.desync_badseq_ack_increment,
ttl_orig,FOOL_NONE,params.desync_badseq_increment,params.desync_badseq_ack_increment,
data_payload, split_pos, newdata, &newlen))
return res;
DLOG("sending 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos)
@@ -472,7 +475,7 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc
{
fakeseg_len = sizeof(fakeseg);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
ttl_fake,params.desync_tcp_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment,
ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment,
zeropkt, split_pos, fakeseg, &fakeseg_len))
return res;
DLOG("sending fake(1) 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos)
@@ -483,7 +486,7 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc
newlen = sizeof(newdata);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
ttl_orig,TCP_FOOL_NONE,params.desync_badseq_increment,params.desync_badseq_ack_increment,
ttl_orig,FOOL_NONE,params.desync_badseq_increment,params.desync_badseq_ack_increment,
data_payload, split_pos, newdata, &newlen))
return res;
DLOG("sending 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos)
@@ -503,7 +506,7 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc
{
newlen = sizeof(newdata);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(tcphdr->th_seq,split_pos), tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
ttl_orig,TCP_FOOL_NONE,params.desync_badseq_increment,params.desync_badseq_ack_increment,
ttl_orig,FOOL_NONE,params.desync_badseq_increment,params.desync_badseq_ack_increment,
data_payload+split_pos, len_payload-split_pos, newdata, &newlen))
return res;
DLOG("sending 2nd tcp segment %zu-%zu len=%zu : ",split_pos,len_payload-1, len_payload-split_pos)
@@ -516,8 +519,113 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc
}
break;
}
return res;
}
return res;
}
packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct udphdr *udphdr, uint8_t *data_payload, size_t len_payload)
{
packet_process_result res=pass;
t_ctrack *ctrack=NULL;
bool bReverse=false;
struct sockaddr_storage src, dst;
uint8_t newdata[DPI_DESYNC_MAX_FAKE_LEN+100];
size_t newlen;
uint8_t ttl_orig,ttl_fake;
if (!!ip == !!ip6hdr) return res; // one and only one must be present
if (CONNTRACK_REQUIRED)
{
ConntrackPoolPurge(&params.conntrack);
if (ConntrackPoolFeed(&params.conntrack, ip, ip6hdr, NULL, udphdr, len_payload, &ctrack, &bReverse))
maybe_cutoff(ctrack, IPPROTO_UDP);
}
//ConntrackPoolDump(&params.conntrack);
if (bReverse) return res; // nothing to do. do not waste cpu
if (params.desync_cutoff)
{
if (ctrack)
{
if (ctrack->b_desync_cutoff)
{
DLOG("not desyncing. desync-cutoff reached (mode %c): %llu/%u\n", params.desync_cutoff_mode, (unsigned long long)cutoff_get_limit(ctrack,params.desync_cutoff_mode), params.desync_cutoff);
return res;
}
DLOG("desync-cutoff not reached (mode %c): %llu/%u\n", params.desync_cutoff_mode, (unsigned long long)cutoff_get_limit(ctrack,params.desync_cutoff_mode), params.desync_cutoff);
}
else
{
DLOG("not desyncing. desync-cutoff is set but conntrack entry is missing\n");
return res;
}
}
if (params.desync_mode==DESYNC_NONE) return res;
ttl_orig = ip ? ip->ip_ttl : ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_hlim;
if (ip6hdr) ttl_fake = params.desync_ttl6 ? params.desync_ttl6 : ttl_orig;
else ttl_fake = params.desync_ttl ? params.desync_ttl : ttl_orig;
extract_endpoints(ip, ip6hdr, NULL, udphdr, &src, &dst);
if (len_payload)
{
const uint8_t *fake;
size_t fake_size;
bool b;
if (!params.desync_any_proto) return res;
DLOG("applying tampering to unknown protocol\n")
fake = params.fake_unknown_udp;
fake_size = params.fake_unknown_udp_size;
if (params.debug)
{
printf("dpi desync src=");
print_sockaddr((struct sockaddr *)&src);
printf(" dst=");
print_sockaddr((struct sockaddr *)&dst);
printf("\n");
}
newlen = sizeof(newdata);
b = false;
switch(params.desync_mode)
{
case DESYNC_FAKE:
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, params.desync_fooling_mode, fake, fake_size, newdata, &newlen))
return res;
DLOG("sending fake request : ");
hexdump_limited_dlog(fake,fake_size,PKT_MAXDUMP); DLOG("\n")
b = true;
break;
}
if (b)
{
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen))
return res;
DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", len_pkt, len_payload)
#ifdef __FreeBSD__
// FreeBSD tend to pass ipv6 frames with wrong checksum
if (res==modify || ip6hdr)
#else
// if original packet was tampered earlier it needs checksum fixed
if (res==modify)
#endif
udp_fix_checksum(udphdr,sizeof(struct udphdr)+len_payload,ip,ip6hdr);
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, data_pkt, len_pkt))
return res;
return drop;
}
}
return res;

View File

@@ -40,4 +40,5 @@ bool desync_valid_first_stage(enum dpi_desync_mode mode);
bool desync_valid_second_stage(enum dpi_desync_mode mode);
void desync_init();
packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, size_t len_tcp, uint8_t *data_payload, size_t len_payload);
packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, size_t len_tcp, uint8_t *data_payload, size_t len_payload);
packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct udphdr *udphdr, uint8_t *data_payload, size_t len_payload);

View File

@@ -39,6 +39,7 @@
#define CTRACK_T_SYN 60
#define CTRACK_T_FIN 60
#define CTRACK_T_EST 300
#define CTRACK_T_UDP 60
struct params_s params;
@@ -86,7 +87,8 @@ static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt
struct ip *ip = NULL;
struct ip6_hdr *ip6hdr = NULL;
struct tcphdr *tcphdr = NULL;
size_t len = len_pkt, len_tcp;
struct udphdr *udphdr = NULL;
size_t len = len_pkt, len_with_th;
uint8_t *data = data_pkt;
packet_process_result res = pass;
uint8_t proto;
@@ -129,7 +131,7 @@ static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt
if (proto==IPPROTO_TCP && proto_check_tcp(data, len))
{
tcphdr = (struct tcphdr *) data;
len_tcp = len;
len_with_th = len;
proto_skip_tcp(&data, &len);
if (params.debug)
@@ -141,7 +143,7 @@ static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt
if (len) { DLOG("TCP: ") hexdump_limited_dlog(data, len, 32); DLOG("\n") }
res = dpi_desync_packet(data_pkt, len_pkt, ip, ip6hdr, tcphdr, len_tcp, data, len);
res = dpi_desync_tcp_packet(data_pkt, len_pkt, ip, ip6hdr, tcphdr, len_with_th, data, len);
// in my FreeBSD divert tests only ipv4 packets were reinjected with correct checksum
// ipv6 packets were with incorrect checksum
#ifdef __FreeBSD__
@@ -150,7 +152,30 @@ static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt
#else
if (res==modify)
#endif
tcp_fix_checksum(tcphdr,len_tcp,ip,ip6hdr);
tcp_fix_checksum(tcphdr,len_with_th,ip,ip6hdr);
}
else if (proto==IPPROTO_UDP && proto_check_udp(data, len))
{
udphdr = (struct udphdr *) data;
len_with_th = len;
proto_skip_udp(&data, &len);
if (params.debug)
{
printf(" ");
print_udphdr(udphdr);
printf("\n");
}
if (len) { DLOG("UDP: ") hexdump_limited_dlog(data, len, 32); DLOG("\n") }
res = dpi_desync_udp_packet(data_pkt, len_pkt, ip, ip6hdr, udphdr, data, len);
#ifdef __FreeBSD__
// FreeBSD tend to pass ipv6 frames with wrong checksum
if (res==modify || ip6hdr)
#else
if (res==modify)
#endif
udp_fix_checksum(udphdr,len_with_th,ip,ip6hdr);
}
else
{
@@ -474,7 +499,7 @@ static void exithelp()
" --wsize=<window_size>[:<scale_factor>]\t; set window size. 0 = do not modify. OBSOLETE !\n"
" --wssize=<window_size>[:<scale_factor>]; set window size for server. 0 = do not modify. default scale_factor = 0.\n"
" --wssize-cutoff=[n|d|s]N\t\t; apply server wsize only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n"
" --ctrack-timeouts=S:E:F\t\t; internal conntrack timeouts for SYN, ESTABLISHED and FIN stage. default %u:%u:%u\n"
" --ctrack-timeouts=S:E:F[:U]\t\t; internal conntrack timeouts for TCP SYN, ESTABLISHED, FIN stages, UDP timeout. default %u:%u:%u:%u\n"
" --hostcase\t\t\t\t; change Host: => host:\n"
" --hostspell\t\t\t\t; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n"
" --hostnospace\t\t\t\t; remove space after Host: and add it to User-Agent: to preserve packet size\n"
@@ -500,9 +525,10 @@ static void exithelp()
" --dpi-desync-fake-http=<filename>\t; file containing fake http request\n"
" --dpi-desync-fake-tls=<filename>\t; file containing fake TLS ClientHello (for https)\n"
" --dpi-desync-fake-unknown=<filename>\t; file containing unknown protocol fake payload\n"
" --dpi-desync-fake-unknown-udp=<filename> ; file containing unknown udp protocol fake payload\n"
" --dpi-desync-cutoff=[n|d|s]N\t\t; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n"
" --hostlist=<filename>\t\t\t; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply)\n",
CTRACK_T_SYN, CTRACK_T_EST, CTRACK_T_FIN,
CTRACK_T_SYN, CTRACK_T_EST, CTRACK_T_FIN, CTRACK_T_UDP,
#if defined(__linux__) || defined(SO_USER_COOKIE)
DPI_DESYNC_FWMARK_DEFAULT,DPI_DESYNC_FWMARK_DEFAULT,
#endif
@@ -549,6 +575,17 @@ static bool parse_badseq_increment(const char *opt, uint32_t *value)
return sscanf(opt, "%d", (int32_t*)value)>0;
}
}
static void load_file_or_exit(const char *filename, void *buf, size_t *size)
{
if (!load_file_nonempty(filename,buf,size))
{
fprintf(stderr, "could not read %s\n",filename);
exit_clean(1);
}
DLOG("read %zu bytes from %s\n",*size,filename)
}
int main(int argc, char **argv)
{
int result, v;
@@ -571,10 +608,12 @@ int main(int argc, char **argv)
params.fake_http_size = strlen(fake_http_request_default);
memcpy(params.fake_http,fake_http_request_default,params.fake_http_size);
params.fake_unknown_size = 256;
params.fake_unknown_udp_size = 64;
params.wscale=-1; // default - dont change scale factor (client)
params.ctrack_t_syn = CTRACK_T_SYN;
params.ctrack_t_est = CTRACK_T_EST;
params.ctrack_t_fin = CTRACK_T_FIN;
params.ctrack_t_udp = CTRACK_T_UDP;
params.desync_ttl6 = 0xFF; // unused
params.desync_badseq_increment = BADSEQ_INCREMENT_DEFAULT;
params.desync_badseq_ack_increment = BADSEQ_ACK_INCREMENT_DEFAULT;
@@ -628,8 +667,9 @@ int main(int argc, char **argv)
{"dpi-desync-fake-http",required_argument,0,0},// optidx=26
{"dpi-desync-fake-tls",required_argument,0,0},// optidx=27
{"dpi-desync-fake-unknown",required_argument,0,0},// optidx=28
{"dpi-desync-cutoff",required_argument,0,0},// optidx=29
{"hostlist",required_argument,0,0}, // optidx=30
{"dpi-desync-fake-unknown-udp",required_argument,0,0},// optidx=29
{"dpi-desync-cutoff",required_argument,0,0},// optidx=30
{"hostlist",required_argument,0,0}, // optidx=31
{NULL,0,NULL,0}
};
if (argc < 2) exithelp();
@@ -706,7 +746,7 @@ int main(int argc, char **argv)
}
break;
case 9: /* ctrack-timeouts */
if (sscanf(optarg, "%u:%u:%u", &params.ctrack_t_syn, &params.ctrack_t_est, &params.ctrack_t_fin)!=3)
if (sscanf(optarg, "%u:%u:%u:%u", &params.ctrack_t_syn, &params.ctrack_t_est, &params.ctrack_t_fin, &params.ctrack_t_udp)<3)
{
fprintf(stderr, "invalid ctrack-timeouts value\n");
exit_clean(1);
@@ -796,18 +836,18 @@ int main(int argc, char **argv)
e = strchr(p,',');
if (e) *e++=0;
if (!strcmp(p,"md5sig"))
params.desync_tcp_fooling_mode |= TCP_FOOL_MD5SIG;
params.desync_fooling_mode |= FOOL_MD5SIG;
else if (!strcmp(p,"ts"))
params.desync_tcp_fooling_mode |= TCP_FOOL_TS;
params.desync_fooling_mode |= FOOL_TS;
else if (!strcmp(p,"badsum"))
{
#ifdef __OpenBSD__
printf("\nWARNING !!! OpenBSD may forcibly recompute tcp checksums !!! In this case badsum fooling will not work.\nYou should check tcp checksum correctness in tcpdump manually before using badsum.\n\n");
printf("\nWARNING !!! OpenBSD may forcibly recompute tcp/udp checksums !!! In this case badsum fooling will not work.\nYou should check tcp checksum correctness in tcpdump manually before using badsum.\n\n");
#endif
params.desync_tcp_fooling_mode |= TCP_FOOL_BADSUM;
params.desync_fooling_mode |= FOOL_BADSUM;
}
else if (!strcmp(p,"badseq"))
params.desync_tcp_fooling_mode |= TCP_FOOL_BADSEQ;
params.desync_fooling_mode |= FOOL_BADSEQ;
else if (strcmp(p,"none"))
{
fprintf(stderr, "dpi-desync-fooling allowed values : none,md5sig,ts,badseq,badsum\n");
@@ -850,7 +890,6 @@ int main(int argc, char **argv)
fprintf(stderr, "dpi-desync-badseq-increment should be signed decimal or signed 0xHEX\n");
exit_clean(1);
}
printf("FFF %08X\n", params.desync_badseq_increment);
break;
case 24: /* dpi-desync-badack-increment */
if (!parse_badseq_increment(optarg,&params.desync_badseq_ack_increment))
@@ -864,36 +903,28 @@ printf("FFF %08X\n", params.desync_badseq_increment);
break;
case 26: /* dpi-desync-fake-http */
params.fake_http_size = sizeof(params.fake_http);
if (!load_file_nonempty(optarg,params.fake_http,&params.fake_http_size))
{
fprintf(stderr, "could not read %s\n",optarg);
exit_clean(1);
}
load_file_or_exit(optarg,params.fake_http,&params.fake_http_size);
break;
case 27: /* dpi-desync-fake-tls */
params.fake_tls_size = sizeof(params.fake_tls);
if (!load_file_nonempty(optarg,params.fake_tls,&params.fake_tls_size))
{
fprintf(stderr, "could not read %s\n",optarg);
exit_clean(1);
}
load_file_or_exit(optarg,params.fake_tls,&params.fake_tls_size);
break;
case 28: /* dpi-desync-fake-unknown */
params.fake_unknown_size = sizeof(params.fake_unknown);
if (!load_file_nonempty(optarg,params.fake_unknown,&params.fake_unknown_size))
{
fprintf(stderr, "could not read %s\n",optarg);
exit_clean(1);
}
load_file_or_exit(optarg,params.fake_unknown,&params.fake_unknown_size);
break;
case 29: /* desync-cutoff */
case 29: /* dpi-desync-fake-unknown-udp */
params.fake_unknown_udp_size = sizeof(params.fake_unknown_udp);
load_file_or_exit(optarg,params.fake_unknown_udp,&params.fake_unknown_udp_size);
break;
case 30: /* desync-cutoff */
if (!parse_cutoff(optarg, &params.desync_cutoff, &params.desync_cutoff_mode))
{
fprintf(stderr, "invalid desync-cutoff value\n");
exit_clean(1);
}
break;
case 30: /* hostlist */
case 31: /* hostlist */
if (!LoadHostList(&params.hostlist, optarg))
exit_clean(1);
strncpy(params.hostfile,optarg,sizeof(params.hostfile));
@@ -919,8 +950,8 @@ printf("FFF %08X\n", params.desync_badseq_increment);
goto exiterr;
}
DLOG("initializing conntrack with timeouts %u:%u:%u\n", params.ctrack_t_syn, params.ctrack_t_est, params.ctrack_t_fin)
ConntrackPoolInit(&params.conntrack, 10, params.ctrack_t_syn, params.ctrack_t_est, params.ctrack_t_fin);
DLOG("initializing conntrack with timeouts tcp=%u:%u:%u udp=%u\n", params.ctrack_t_syn, params.ctrack_t_est, params.ctrack_t_fin, params.ctrack_t_udp)
ConntrackPoolInit(&params.conntrack, 10, params.ctrack_t_syn, params.ctrack_t_est, params.ctrack_t_fin, params.ctrack_t_udp);
#ifdef __linux__
result = nfq_main();

View File

@@ -40,18 +40,18 @@ struct params_s
char desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence
unsigned int desync_cutoff;
uint8_t desync_ttl, desync_ttl6;
uint8_t desync_tcp_fooling_mode;
uint8_t desync_fooling_mode;
uint32_t desync_fwmark; // unused in BSD
uint32_t desync_badseq_increment, desync_badseq_ack_increment;
char hostfile[256];
strpool *hostlist;
uint8_t fake_http[1432],fake_tls[1432],fake_unknown[1432];
size_t fake_http_size,fake_tls_size,fake_unknown_size;
uint8_t fake_http[1432],fake_tls[1432],fake_unknown[1432],fake_unknown_udp[1472];
size_t fake_http_size,fake_tls_size,fake_unknown_size,fake_unknown_udp_size;
bool droproot;
uid_t uid;
gid_t gid;
unsigned int ctrack_t_syn, ctrack_t_est, ctrack_t_fin;
unsigned int ctrack_t_syn, ctrack_t_est, ctrack_t_fin, ctrack_t_udp;
t_conntrack conntrack;
};