mirror of
https://github.com/bol-van/zapret.git
synced 2025-05-24 22:32:58 +03:00
nfqws: udp protocol desync
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
|
440
nfq/conntrack.c
440
nfq/conntrack.c
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
|
904
nfq/darkmagic.c
904
nfq/darkmagic.c
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
|
148
nfq/desync.c
148
nfq/desync.c
@@ -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(¶ms.conntrack);
|
||||
if (ConntrackPoolFeed(¶ms.conntrack, ip, ip6hdr, tcphdr, len_payload, &ctrack, &bReverse))
|
||||
maybe_cutoff(ctrack);
|
||||
if (ConntrackPoolFeed(¶ms.conntrack, ip, ip6hdr, tcphdr, NULL, len_payload, &ctrack, &bReverse))
|
||||
maybe_cutoff(ctrack, IPPROTO_TCP);
|
||||
}
|
||||
|
||||
//ConntrackPoolDump(¶ms.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(¶ms.conntrack);
|
||||
if (ConntrackPoolFeed(¶ms.conntrack, ip, ip6hdr, NULL, udphdr, len_payload, &ctrack, &bReverse))
|
||||
maybe_cutoff(ctrack, IPPROTO_UDP);
|
||||
}
|
||||
|
||||
//ConntrackPoolDump(¶ms.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;
|
||||
|
@@ -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);
|
||||
|
99
nfq/nfqws.c
99
nfq/nfqws.c
@@ -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", ¶ms.ctrack_t_syn, ¶ms.ctrack_t_est, ¶ms.ctrack_t_fin)!=3)
|
||||
if (sscanf(optarg, "%u:%u:%u:%u", ¶ms.ctrack_t_syn, ¶ms.ctrack_t_est, ¶ms.ctrack_t_fin, ¶ms.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,¶ms.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,¶ms.fake_http_size))
|
||||
{
|
||||
fprintf(stderr, "could not read %s\n",optarg);
|
||||
exit_clean(1);
|
||||
}
|
||||
load_file_or_exit(optarg,params.fake_http,¶ms.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,¶ms.fake_tls_size))
|
||||
{
|
||||
fprintf(stderr, "could not read %s\n",optarg);
|
||||
exit_clean(1);
|
||||
}
|
||||
load_file_or_exit(optarg,params.fake_tls,¶ms.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,¶ms.fake_unknown_size))
|
||||
{
|
||||
fprintf(stderr, "could not read %s\n",optarg);
|
||||
exit_clean(1);
|
||||
}
|
||||
load_file_or_exit(optarg,params.fake_unknown,¶ms.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,¶ms.fake_unknown_udp_size);
|
||||
break;
|
||||
case 30: /* desync-cutoff */
|
||||
if (!parse_cutoff(optarg, ¶ms.desync_cutoff, ¶ms.desync_cutoff_mode))
|
||||
{
|
||||
fprintf(stderr, "invalid desync-cutoff value\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case 30: /* hostlist */
|
||||
case 31: /* hostlist */
|
||||
if (!LoadHostList(¶ms.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(¶ms.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(¶ms.conntrack, 10, params.ctrack_t_syn, params.ctrack_t_est, params.ctrack_t_fin, params.ctrack_t_udp);
|
||||
|
||||
#ifdef __linux__
|
||||
result = nfq_main();
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user