diff --git a/nfq/conntrack.c b/nfq/conntrack.c index d348d8f..622f7da 100644 --- a/nfq/conntrack.c +++ b/nfq/conntrack.c @@ -98,6 +98,7 @@ t_conntrack6 *ConntrackPoolSearch6(t_conntrack6 *p, const t_conn6 *c) static void ConntrackInitTrack(t_ctrack *t) { memset(t,0,sizeof(*t)); + t->scale_orig = t->scale_reply = SCALE_NONE; time(&t->t_start); } @@ -122,6 +123,7 @@ static t_conntrack6 *ConntrackNew6(t_conntrack6 **pp, const t_conn6 *c) 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==FIN) ConntrackInitTrack(t); // erase current entry @@ -148,17 +150,23 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr if (!bReverse && !t->ack0) t->ack0 = htonl(tcphdr->th_ack)-1; } } + scale = tcp_find_scale_factor(tcphdr); if (bReverse) { t->seq_last = htonl(tcphdr->th_ack); t->ack_last = htonl(tcphdr->th_seq) + len_payload; t->pcounter_reply++; + t->winsize_reply = htons(tcphdr->th_win); + if (scale!=SCALE_NONE) t->scale_reply = scale; + } else { t->seq_last = htonl(tcphdr->th_seq) + len_payload; t->ack_last = htonl(tcphdr->th_ack); t->pcounter_orig++; + t->winsize_orig = htons(tcphdr->th_win); + if (scale!=SCALE_NONE) t->scale_orig = scale; } time(&t->t_last); } @@ -271,13 +279,15 @@ void ConntrackPoolPurge(t_conntrack *p) 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=%lld last=t0+%lld now=last+%lld cutoff=%u packets_orig=%llu packets_reply=%llu seq0=%u rseq=%u ack0=%u rack=%u\n", \ + printf("[%s]:%u => [%s]:%u : %s : t0=%lld last=t0+%lld now=last+%lld cutoff=%u packets_orig=%llu packets_reply=%llu seq0=%u rseq=%u ack0=%u rack=%u wsize_orig=%u:%d wsize_reply=%u:%d\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), \ t->track.b_cutoff, \ (unsigned long long)t->track.pcounter_orig, (unsigned long long)t->track.pcounter_reply, \ - t->track.seq0, t->track.seq_last - t->track.seq0, t->track.ack0, t->track.ack_last - t->track.ack0); \ + t->track.seq0, t->track.seq_last - t->track.seq0, t->track.ack0, t->track.ack_last - 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 ); \ }; void ConntrackPoolDump4(t_conntrack4 *p) { diff --git a/nfq/conntrack.h b/nfq/conntrack.h index 19e4e36..efeb9b8 100644 --- a/nfq/conntrack.h +++ b/nfq/conntrack.h @@ -51,6 +51,8 @@ typedef struct uint32_t seq0, ack0; // starting seq and ack uint32_t seq_last, ack_last; // current seq and ack uint64_t pcounter_orig, pcounter_reply; // packet counter + 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 } t_ctrack; diff --git a/nfq/darkmagic.c b/nfq/darkmagic.c index 00fe480..3bfe572 100644 --- a/nfq/darkmagic.c +++ b/nfq/darkmagic.c @@ -46,8 +46,14 @@ uint32_t *tcp_find_timestamps(struct tcphdr *tcp) uint8_t *t = tcp_find_option(tcp,8); return (t && t[1]==10) ? (uint32_t*)(t+2) : NULL; } +uint8_t tcp_find_scale_factor(const struct tcphdr *tcp) +{ + uint8_t *scale = tcp_find_option((struct tcphdr*)tcp,3); // tcp option 3 - scale factor + if (scale && scale[1]==3) return scale[2]; + return SCALE_NONE; +} -static void fill_tcphdr(struct tcphdr *tcp, uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, uint8_t fooling, uint16_t nsport, uint16_t ndport, uint16_t nwsize, uint32_t *timestamps) +static void fill_tcphdr(struct tcphdr *tcp, uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, uint8_t fooling, uint16_t nsport, uint16_t ndport, uint16_t nwsize, uint8_t scale_factor, uint32_t *timestamps) { char *tcpopt = (char*)(tcp+1); uint8_t t=0; @@ -87,14 +93,21 @@ static void fill_tcphdr(struct tcphdr *tcp, uint8_t tcp_flags, uint32_t seq, uin *(uint32_t*)(tcpopt+t+6) = (timestamps && !(fooling & TCP_FOOL_TS)) ? timestamps[1] : -1; t+=10; } + if (scale_factor!=SCALE_NONE) + { + tcpopt[t++]=3; + tcpopt[t++]=3; + tcpopt[t++]=scale_factor; + } while (t&3) tcpopt[t++]=1; // noop tcp->th_off += t>>2; } -static uint16_t tcpopt_len(uint8_t fooling, uint32_t *timestamps) +static uint16_t tcpopt_len(uint8_t fooling, 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 (scale_factor!=SCALE_NONE) t+=3; return (t+3)&~3; } @@ -253,6 +266,7 @@ bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const void *data,size_t { int sock=rawsend_socket(dst->sa_family,fwmark); if (sock==-1) return false; + int salen = dst->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); struct sockaddr_storage dst2; memcpy(&dst2,dst,salen); @@ -323,13 +337,14 @@ bool prepare_tcp_segment4( uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, uint16_t wsize, + uint8_t scale_factor, uint32_t *timestamps, uint8_t ttl, uint8_t fooling, const void *data, uint16_t len, uint8_t *buf, size_t *buflen) { - uint16_t tcpoptlen = tcpopt_len(fooling,timestamps); + uint16_t tcpoptlen = tcpopt_len(fooling,timestamps, scale_factor); uint16_t pktlen = sizeof(struct ip) + sizeof(struct tcphdr) + tcpoptlen + len; if (pktlen>*buflen) { @@ -350,7 +365,7 @@ bool prepare_tcp_segment4( ip->ip_src = src->sin_addr; ip->ip_dst = dst->sin_addr; - fill_tcphdr(tcp,tcp_flags,seq,ack_seq,fooling,src->sin_port,dst->sin_port,wsize,timestamps); + fill_tcphdr(tcp,tcp_flags,seq,ack_seq,fooling,src->sin_port,dst->sin_port,wsize,scale_factor,timestamps); memcpy((char*)tcp+sizeof(struct tcphdr)+tcpoptlen,data,len); tcp4_fix_checksum(tcp,sizeof(struct tcphdr)+tcpoptlen+len,&ip->ip_src,&ip->ip_dst); @@ -366,13 +381,14 @@ bool prepare_tcp_segment6( uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, uint16_t wsize, + uint8_t scale_factor, uint32_t *timestamps, uint8_t ttl, uint8_t fooling, const void *data, uint16_t len, uint8_t *buf, size_t *buflen) { - uint16_t tcpoptlen = tcpopt_len(fooling,timestamps); + 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) @@ -391,7 +407,7 @@ bool prepare_tcp_segment6( ip6->ip6_src = src->sin6_addr; ip6->ip6_dst = dst->sin6_addr; - fill_tcphdr(tcp,tcp_flags,seq,ack_seq,fooling,src->sin6_port,dst->sin6_port,wsize,timestamps); + fill_tcphdr(tcp,tcp_flags,seq,ack_seq,fooling,src->sin6_port,dst->sin6_port,wsize,scale_factor,timestamps); memcpy((char*)tcp+sizeof(struct tcphdr)+tcpoptlen,data,len); tcp6_fix_checksum(tcp,sizeof(struct tcphdr)+tcpoptlen+len,&ip6->ip6_src,&ip6->ip6_dst); @@ -406,6 +422,7 @@ bool prepare_tcp_segment( uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, uint16_t wsize, + uint8_t scale_factor, uint32_t *timestamps, uint8_t ttl, uint8_t fooling, @@ -413,9 +430,9 @@ bool prepare_tcp_segment( 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,seq,ack_seq,wsize,timestamps,ttl,fooling,data,len,buf,buflen) : + prepare_tcp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,tcp_flags,seq,ack_seq,wsize,scale_factor,timestamps,ttl,fooling,data,len,buf,buflen) : (src->sa_family==AF_INET6 && dst->sa_family==AF_INET6) ? - prepare_tcp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,tcp_flags,seq,ack_seq,wsize,timestamps,ttl,fooling,data,len,buf,buflen) : + prepare_tcp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,tcp_flags,seq,ack_seq,wsize,scale_factor,timestamps,ttl,fooling,data,len,buf,buflen) : false; } @@ -663,7 +680,7 @@ void tcp_rewrite_wscale(struct tcphdr *tcp, uint8_t scale_factor) { uint8_t *scale,scale_factor_old; - if (scale_factor!=(uint8_t)-1) + 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 @@ -680,7 +697,7 @@ void tcp_rewrite_wscale(struct tcphdr *tcp, uint8_t scale_factor) } } } -// scale_factor=-1 - do not change +// 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; diff --git a/nfq/darkmagic.h b/nfq/darkmagic.h index 1f0338e..e10797f 100644 --- a/nfq/darkmagic.h +++ b/nfq/darkmagic.h @@ -19,12 +19,15 @@ uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment); #define TCP_FOOL_TS 4 #define TCP_FOOL_BADSEQ 8 +#define SCALE_NONE ((uint8_t)-1) + // seq and wsize have network byte order bool prepare_tcp_segment4( const struct sockaddr_in *src, const struct sockaddr_in *dst, uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, uint16_t wsize, + uint8_t scale_factor, uint32_t *timestamps, uint8_t ttl, uint8_t fooling, @@ -35,6 +38,7 @@ bool prepare_tcp_segment6( uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, uint16_t wsize, + uint8_t scale_factor, uint32_t *timestamps, uint8_t ttl, uint8_t fooling, @@ -45,6 +49,7 @@ bool prepare_tcp_segment( uint8_t tcp_flags, uint32_t seq, uint32_t ack_seq, uint16_t wsize, + uint8_t scale_factor, uint32_t *timestamps, uint8_t ttl, uint8_t fooling, @@ -54,6 +59,7 @@ bool prepare_tcp_segment( void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const struct tcphdr *tcphdr, 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); // auto creates internal socket and uses it for subsequent calls bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const void *data,size_t len); @@ -77,6 +83,6 @@ void proto_skip_ipv6(uint8_t **data, size_t *len, uint8_t *proto_type); bool tcp_synack_segment(const struct tcphdr *tcphdr); bool tcp_syn_segment(const struct tcphdr *tcphdr); bool tcp_ack_segment(const struct tcphdr *tcphdr); -// scale_factor=-1 - do not change +// scale_factor=SCALE_NONE - do not change void tcp_rewrite_wscale(struct tcphdr *tcp, uint8_t scale_factor); void tcp_rewrite_winsize(struct tcphdr *tcp, uint16_t winsize, uint8_t scale_factor); diff --git a/nfq/desync.c b/nfq/desync.c index 20ce0bc..a22b982 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -240,6 +240,7 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc uint8_t flags_orig = *((uint8_t*)tcphdr+13); uint32_t *timestamps = tcp_find_timestamps(tcphdr); enum dpi_desync_mode desync_mode = params.desync_mode; + uint8_t scale_factor = tcp_find_scale_factor(tcphdr); bool b; newlen = sizeof(newdata); @@ -247,7 +248,7 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc switch(desync_mode) { case DESYNC_FAKE: - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, timestamps, + 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, fake, fake_size, newdata, &newlen)) { @@ -259,7 +260,7 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc break; 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, timestamps, + 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, NULL, 0, newdata, &newlen)) { @@ -311,7 +312,7 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc if (split_posth_seq,split_pos), tcphdr->th_ack, tcphdr->th_win, timestamps, + 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, data_payload+split_pos, len_payload-split_pos, newdata, &newlen)) return res; @@ -325,7 +326,7 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc if (desync_mode==DESYNC_DISORDER) { 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, timestamps, + 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, zeropkt, split_pos, fakeseg, &fakeseg_len)) return res; @@ -337,7 +338,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, timestamps, + 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, data_payload, split_pos, newdata, &newlen)) return res; @@ -367,7 +368,7 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc if (desync_mode==DESYNC_SPLIT) { 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, timestamps, + 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, zeropkt, split_pos, fakeseg, &fakeseg_len)) return res; @@ -378,7 +379,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, timestamps, + 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, data_payload, split_pos, newdata, &newlen)) return res; @@ -398,7 +399,7 @@ packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struc if (split_posth_seq,split_pos), tcphdr->th_ack, tcphdr->th_win, timestamps, + 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, data_payload+split_pos, len_payload-split_pos, newdata, &newlen)) return res;