diff --git a/nfq/conntrack.c b/nfq/conntrack.c index 594717f..b402b65 100644 --- a/nfq/conntrack.c +++ b/nfq/conntrack.c @@ -338,8 +338,8 @@ void ConntrackPoolDump(const t_conntrack *p) printf("rseq=%u pos_orig=%u rack=%u pos_reply=%u", t->track.seq_last, t->track.pos_orig, t->track.ack_last, t->track.pos_reply); - printf(" req_retrans=%u cutoff=%u wss_cutoff=%u d_cutoff=%u hostname=%s l7proto=%s\n", - t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_wssize_cutoff, t->track.b_desync_cutoff, t->track.hostname, l7proto_str(t->track.l7proto)); + printf(" req_retrans=%u cutoff=%u wss_cutoff=%u desync_cutoff=%u dup_cutoff=%u orig_cutoff=%u hostname=%s l7proto=%s\n", + t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_wssize_cutoff, t->track.b_desync_cutoff, t->track.b_dup_cutoff, t->track.b_orig_mod_cutoff, t->track.hostname, l7proto_str(t->track.l7proto)); }; } diff --git a/nfq/conntrack.h b/nfq/conntrack.h index ffe5270..564d2cf 100644 --- a/nfq/conntrack.h +++ b/nfq/conntrack.h @@ -80,7 +80,7 @@ typedef struct uint8_t incoming_ttl, autottl; bool b_cutoff; // mark for deletion - bool b_wssize_cutoff, b_desync_cutoff; + bool b_wssize_cutoff, b_desync_cutoff, b_dup_cutoff, b_orig_mod_cutoff; t_l7proto l7proto; bool l7proto_discovered; diff --git a/nfq/darkmagic.c b/nfq/darkmagic.c index be4f478..e016a71 100644 --- a/nfq/darkmagic.c +++ b/nfq/darkmagic.c @@ -83,10 +83,22 @@ bool tcp_has_fastopen(const struct tcphdr *tcp) opt = tcp_find_option((struct tcphdr*)tcp, 254); return opt && opt[1]>=4 && opt[2]==0xF9 && opt[3]==0x89; } +uint16_t tcp_find_mss(struct tcphdr *tcp) +{ + uint8_t *t = tcp_find_option(tcp,2); + return (t && t[1]==4) ? *(uint16_t*)(t+2) : 0; +} +bool tcp_has_sack(struct tcphdr *tcp) +{ + uint8_t *t = tcp_find_option(tcp,4); + return !!t; +} // n prefix (nsport, nwsize) means network byte order static void fill_tcphdr( struct tcphdr *tcp, uint32_t fooling, uint8_t tcp_flags, + bool sack, + uint16_t nmss, uint32_t nseq, uint32_t nack_seq, uint16_t nsport, uint16_t ndport, uint16_t nwsize, uint8_t scale_factor, @@ -111,20 +123,32 @@ static void fill_tcphdr( tcp->th_seq = nseq; tcp->th_ack = nack_seq; } - tcp->th_off = 5; + tcp->th_off = 5; if ((fooling & FOOL_DATANOACK) && !(tcp_flags & (TH_SYN|TH_RST)) && data_len) tcp_flags &= ~TH_ACK; *((uint8_t*)tcp+13)= tcp_flags; tcp->th_win = nwsize; + if (nmss) + { + tcpopt[t++] = 2; // kind + tcpopt[t++] = 4; // len + *(uint16_t*)(tcpopt+t) = nmss; + t+=2; + } + if (sack) + { + tcpopt[t++] = 4; // kind + tcpopt[t++] = 2; // len + } if (fooling & FOOL_MD5SIG) { - tcpopt[0] = 19; // kind - tcpopt[1] = 18; // len - *(uint32_t*)(tcpopt+2)=random(); - *(uint32_t*)(tcpopt+6)=random(); - *(uint32_t*)(tcpopt+10)=random(); - *(uint32_t*)(tcpopt+14)=random(); - t=18; + tcpopt[t] = 19; // kind + tcpopt[t+1] = 18; // len + *(uint32_t*)(tcpopt+t+2)=random(); + *(uint32_t*)(tcpopt+t+6)=random(); + *(uint32_t*)(tcpopt+t+10)=random(); + *(uint32_t*)(tcpopt+t+14)=random(); + t+=18; } if (timestamps || (fooling & FOOL_TS)) { @@ -145,10 +169,12 @@ static void fill_tcphdr( tcp->th_off += t>>2; tcp->th_sum = 0; } -static uint16_t tcpopt_len(uint32_t fooling, const uint32_t *timestamps, uint8_t scale_factor) +static uint16_t tcpopt_len(bool sack, bool mss, uint32_t fooling, const uint32_t *timestamps, uint8_t scale_factor) { uint16_t t=0; - if (fooling & FOOL_MD5SIG) t=18; + if (sack) t+=2; + if (mss) t+=4; + if (fooling & FOOL_MD5SIG) t+=18; if ((fooling & FOOL_TS) || timestamps) t+=10; if (scale_factor!=SCALE_NONE) t+=3; return (t+3)&~3; @@ -190,6 +216,8 @@ static void fill_ip6hdr(struct ip6_hdr *ip6, const struct in6_addr *src, const s bool prepare_tcp_segment4( const struct sockaddr_in *src, const struct sockaddr_in *dst, uint8_t tcp_flags, + bool sack, + uint16_t nmss, uint32_t nseq, uint32_t nack_seq, uint16_t nwsize, uint8_t scale_factor, @@ -203,7 +231,7 @@ bool prepare_tcp_segment4( const void *data, uint16_t len, uint8_t *buf, size_t *buflen) { - uint16_t tcpoptlen = tcpopt_len(fooling,timestamps,scale_factor); + uint16_t tcpoptlen = tcpopt_len(sack,!!nmss,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; @@ -213,11 +241,11 @@ bool prepare_tcp_segment4( uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen; fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_TCP, ttl, tos, ip_id); - fill_tcphdr(tcp,fooling,tcp_flags,nseq,nack_seq,src->sin_port,dst->sin_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment,len); + fill_tcphdr(tcp,fooling,tcp_flags,sack,nmss,nseq,nack_seq,src->sin_port,dst->sin_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment,len); 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); + if (fooling & FOOL_BADSUM) tcp->th_sum^=(uint16_t)(1+random()%0xFFFF); *buflen = pktlen; return true; @@ -226,6 +254,8 @@ bool prepare_tcp_segment4( bool prepare_tcp_segment6( const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst, uint8_t tcp_flags, + bool sack, + uint16_t nmss, uint32_t nseq, uint32_t nack_seq, uint16_t nwsize, uint8_t scale_factor, @@ -238,7 +268,7 @@ bool prepare_tcp_segment6( const void *data, uint16_t len, uint8_t *buf, size_t *buflen) { - uint16_t tcpoptlen = tcpopt_len(fooling,timestamps,scale_factor); + uint16_t tcpoptlen = tcpopt_len(sack,!!nmss,fooling,timestamps,scale_factor); uint16_t transport_payload_len = sizeof(struct tcphdr) + tcpoptlen + len; uint16_t ip_payload_len = transport_payload_len + 8*!!((fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2))==FOOL_HOPBYHOP) + @@ -297,11 +327,11 @@ bool prepare_tcp_segment6( uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen; fill_ip6hdr(ip6, &src->sin6_addr, &dst->sin6_addr, ip_payload_len, proto, ttl, flow_label); - fill_tcphdr(tcp,fooling,tcp_flags,nseq,nack_seq,src->sin6_port,dst->sin6_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment,len); + fill_tcphdr(tcp,fooling,tcp_flags,sack,nmss,nseq,nack_seq,src->sin6_port,dst->sin6_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment,len); memcpy(payload,data,len); tcp6_fix_checksum(tcp,transport_payload_len,&ip6->ip6_src,&ip6->ip6_dst); - if (fooling & FOOL_BADSUM) tcp->th_sum^=htons(0xBEAF); + if (fooling & FOOL_BADSUM) tcp->th_sum^=(1+random()%0xFFFF); *buflen = pktlen; return true; @@ -310,6 +340,8 @@ bool prepare_tcp_segment6( bool prepare_tcp_segment( const struct sockaddr *src, const struct sockaddr *dst, uint8_t tcp_flags, + bool sack, + uint16_t nmss, uint32_t nseq, uint32_t nack_seq, uint16_t nwsize, uint8_t scale_factor, @@ -325,9 +357,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,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,tos,ip_id,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) : + prepare_tcp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,tcp_flags,sack,nmss,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,tos,ip_id,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,flow_label,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) : + prepare_tcp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,tcp_flags,sack,nmss,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,flow_label,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) : false; } @@ -370,7 +402,7 @@ bool prepare_udp_segment4( else memset(payload+len,0,padlen); udp4_fix_checksum(udp,ip_payload_len,&ip->ip_src,&ip->ip_dst); - if (fooling & FOOL_BADSUM) udp->uh_sum^=htons(0xBEAF); + if (fooling & FOOL_BADSUM) udp->uh_sum^=(1+random()%0xFFFF); *buflen = pktlen; return true; @@ -459,7 +491,7 @@ bool prepare_udp_segment6( else memset(payload+len,0,padlen); udp6_fix_checksum(udp,transport_payload_len,&ip6->ip6_src,&ip6->ip6_dst); - if (fooling & FOOL_BADSUM) udp->uh_sum^=htons(0xBEAF); + if (fooling & FOOL_BADSUM) udp->uh_sum^=(1+random()%0xFFFF); *buflen = pktlen; return true; @@ -601,10 +633,29 @@ bool ip_frag( return false; } -void rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl) +bool rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl) { - if (ip) ip->ip_ttl = ttl; - if (ip6) ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = ttl; + if (ttl) + { + if (ip) + { + if (ip->ip_ttl!=ttl) + { + ip->ip_ttl = ttl; + ip4_fix_checksum(ip); + return true; + } + } + else if (ip6) + { + if (ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim!=ttl) + { + ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = ttl; + return true; + } + } + } + return false; } diff --git a/nfq/darkmagic.h b/nfq/darkmagic.h index 42f7902..9a11e1a 100644 --- a/nfq/darkmagic.h +++ b/nfq/darkmagic.h @@ -59,6 +59,7 @@ uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment); #define VERDICT_DROP 2 #define VERDICT_MASK 3 #define VERDICT_NOCSUM 4 +#define VERDICT_GARBAGE 8 #define IP4_TOS(ip_header) (ip_header ? ip_header->ip_tos : 0) #define IP4_IP_ID(ip_header) (ip_header ? ip_header->ip_id : 0) @@ -68,6 +69,8 @@ uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment); bool prepare_tcp_segment4( const struct sockaddr_in *src, const struct sockaddr_in *dst, uint8_t tcp_flags, + bool sack, + uint16_t nmss, uint32_t nseq, uint32_t nack_seq, uint16_t nwsize, uint8_t scale_factor, @@ -83,6 +86,8 @@ bool prepare_tcp_segment4( bool prepare_tcp_segment6( const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst, uint8_t tcp_flags, + bool sack, + uint16_t nmss, uint32_t nseq, uint32_t nack_seq, uint16_t nwsize, uint8_t scale_factor, @@ -97,6 +102,8 @@ bool prepare_tcp_segment6( bool prepare_tcp_segment( const struct sockaddr *src, const struct sockaddr *dst, uint8_t tcp_flags, + bool sack, + uint16_t nmss, uint32_t nseq, uint32_t nack_seq, uint16_t nwsize, uint8_t scale_factor, @@ -162,13 +169,16 @@ bool ip_frag( uint8_t *pkt1, size_t *pkt1_size, uint8_t *pkt2, size_t *pkt2_size); -void rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl); +bool rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl); 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); +uint16_t tcp_find_mss(struct tcphdr *tcp); +bool tcp_has_sack(struct tcphdr *tcp); + bool tcp_has_fastopen(const struct tcphdr *tcp); #ifdef __CYGWIN__ diff --git a/nfq/desync.c b/nfq/desync.c index 414e953..dc8afec 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -325,6 +325,8 @@ static void maybe_cutoff(t_ctrack *ctrack, uint8_t proto) if (proto==IPPROTO_TCP) ctrack->b_wssize_cutoff |= cutoff_test(ctrack, ctrack->dp->wssize_cutoff, ctrack->dp->wssize_cutoff_mode); ctrack->b_desync_cutoff |= cutoff_test(ctrack, ctrack->dp->desync_cutoff, ctrack->dp->desync_cutoff_mode); + ctrack->b_dup_cutoff |= cutoff_test(ctrack, ctrack->dp->dup_cutoff, ctrack->dp->dup_cutoff_mode); + ctrack->b_orig_mod_cutoff |= cutoff_test(ctrack, ctrack->dp->orig_mod_cutoff, ctrack->dp->orig_mod_cutoff_mode); // in MULTI STRATEGY concept conntrack entry holds desync profile // we do not want to remove conntrack entries ASAP anymore @@ -653,6 +655,88 @@ static bool process_desync_interval(const struct desync_profile *dp, t_ctrack *c return false; } } +static bool check_dup_interval(const struct desync_profile *dp, const t_ctrack *ctrack) +{ + if (dp) + { + if (dp->dup_start) + { + if (ctrack) + { + if (!cutoff_test(ctrack, dp->dup_start, dp->dup_start_mode)) + { + DLOG("dup-start not reached (mode %c): %llu/%u . not duping\n", dp->dup_start_mode, (unsigned long long)cutoff_get_limit(ctrack,dp->dup_start_mode), dp->dup_start); + return false; + } + DLOG("dup-start reached (mode %c): %llu/%u\n", dp->dup_start_mode, (unsigned long long)cutoff_get_limit(ctrack,dp->dup_start_mode), dp->dup_start); + } + else + { + DLOG("not duping. dup-start is set but conntrack entry is missing\n"); + return false; + } + } + if (dp->dup_cutoff) + { + if (ctrack) + { + if (ctrack->b_dup_cutoff) + { + DLOG("dup-cutoff reached (mode %c): %llu/%u . not duping\n", dp->dup_cutoff_mode, (unsigned long long)cutoff_get_limit(ctrack,dp->dup_cutoff_mode), dp->dup_cutoff); + return false; + } + DLOG("dup-cutoff not reached (mode %c): %llu/%u\n", dp->dup_cutoff_mode, (unsigned long long)cutoff_get_limit(ctrack,dp->dup_cutoff_mode), dp->dup_cutoff); + } + else + { + DLOG("not duping. dup-cutoff is set but conntrack entry is missing\n"); + return false; + } + } + } + return true; +} +static bool check_orig_mod_interval(const struct desync_profile *dp, const t_ctrack *ctrack) +{ + if (dp) + { + if (dp->orig_mod_start) + { + if (ctrack) + { + if (!cutoff_test(ctrack, dp->orig_mod_start, dp->orig_mod_start_mode)) + { + DLOG("orig-mod-start not reached (mode %c): %llu/%u . not modding original\n", dp->orig_mod_start_mode, (unsigned long long)cutoff_get_limit(ctrack,dp->orig_mod_start_mode), dp->orig_mod_start); + return false; + } + DLOG("orig-mod-start reached (mode %c): %llu/%u\n", dp->orig_mod_start_mode, (unsigned long long)cutoff_get_limit(ctrack,dp->orig_mod_start_mode), dp->orig_mod_start); + } + else + { + DLOG("not modding original. orig-mod-start is set but conntrack entry is missing\n"); + return false; + } + } + if (dp->orig_mod_cutoff) + { + if (ctrack) + { + if (ctrack->b_orig_mod_cutoff) + { + DLOG("orig-mod-cutoff reached (mode %c): %llu/%u . not modding original\n", dp->orig_mod_cutoff_mode, (unsigned long long)cutoff_get_limit(ctrack,dp->orig_mod_cutoff_mode), dp->orig_mod_cutoff); + return false; + } + DLOG("orig-mod-cutoff not reached (mode %c): %llu/%u\n", dp->orig_mod_cutoff_mode, (unsigned long long)cutoff_get_limit(ctrack,dp->orig_mod_cutoff_mode), dp->orig_mod_cutoff); + } + else + { + DLOG("not modding original. orig-mod-cutoff is set but conntrack entry is missing\n"); + return false; + } + } + } + return true; +} static bool replay_queue(struct rawpacket_tailhead *q); @@ -750,6 +834,196 @@ static bool runtime_tls_mod(int fake_n,const struct fake_tls_mod_cache *modcache return b; } +uint8_t orig_mod(const struct desync_profile *dp, const t_ctrack *ctrack, struct dissect *dis) +{ + uint8_t ttl,ttl_orig; + + ttl = dis->ip6 ? dp->orig_mod_ttl6 : dp->orig_mod_ttl; + if (ttl && check_orig_mod_interval(dp,ctrack)) + { + ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; + if (ttl_orig!=ttl) + { + DLOG("rewrite original packet ttl %u => %u\n",ttl_orig,ttl); + rewrite_ttl(dis->ip,dis->ip6,ttl); + return true; + } + } + return false; +} + +static bool orig_send_rewrite( + uint32_t fwmark, const char *ifout, const struct sockaddr *dst, + uint8_t ttl_orig, uint8_t ttl_fake, const struct desync_profile *dp, const struct dissect *dis) +{ + unsigned int k; + + // here we avoid heavy ops and preserve exact tcp options structure + + if (ttl_fake==ttl_orig) + DLOG("sending %u dups\n", dp->dup_repeats); + else + DLOG("sending %u dups with ttl rewrite %u => %u\n", dp->dup_repeats, ttl_orig, ttl_fake); + rewrite_ttl(dis->ip,dis->ip6,ttl_fake); + // send dups + for (k=0;kdup_repeats;k++) + { + if (!rawsend(dst, fwmark, ifout , dis->data_pkt, dis->len_pkt)) + { + rewrite_ttl(dis->ip,dis->ip6,ttl_orig); + return false; + } + } + rewrite_ttl(dis->ip,dis->ip6,ttl_orig); + return true; +} + +// return : true - orig was sent completely, false - should send orig another way +static bool tcp_orig_send(uint32_t fwmark, const char *ifout, const struct desync_profile *dp, const t_ctrack *ctrack, struct dissect *dis, bool bForceSend) +{ + if (dp->dup_repeats || bForceSend) + { + unsigned int k; + uint8_t pkt[DPI_DESYNC_MAX_FAKE_LEN+100]; + size_t len; + uint16_t ip_id, nmss; + struct sockaddr_storage src, dst; + uint8_t ttl_orig,ttl_fake,flags_orig,scale_factor; + uint32_t *timestamps; + bool sack; + + extract_endpoints(dis->ip, dis->ip6, dis->tcp, NULL, &src, &dst); + + if (dp->dup_repeats && check_dup_interval(dp,ctrack)) + { + ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; + ttl_fake = dis->ip6 ? dp->dup_ttl6 : dp->dup_ttl; + if (!ttl_fake) ttl_fake = ttl_orig; + + if (dp->dup_fooling_mode) + { + flags_orig = *((uint8_t*)dis->tcp+13); + scale_factor = tcp_find_scale_factor(dis->tcp); + timestamps = tcp_find_timestamps(dis->tcp); + sack = tcp_has_sack(dis->tcp); + nmss = tcp_find_mss(dis->tcp); + ip_id = IP4_IP_ID_FIX(dis->ip); + + len = sizeof(pkt); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, + flags_orig, sack, nmss, + dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), + dp->dup_fooling_mode,dp->dup_badseq_increment,dp->dup_badseq_ack_increment, + dis->data_payload, dis->len_payload, pkt, &len)) + { + DLOG_ERR("dup: packet reconstruct failed\n"); + return false; + } + + DLOG("sending %u dups with packet reconstruct\n", dp->dup_repeats); + + // send dups + for (k=0;kdup_repeats;k++) + { + if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , pkt, len)) + return false; + } + } + else + { + if (!orig_send_rewrite(fwmark,ifout,(struct sockaddr *)&dst,ttl_orig,ttl_fake,dp,dis)) + return false; + } + if (dp->dup_replace) + DLOG("NOT sending original because of dup_replace\n"); + else + { + DLOG("sending original\n", dp->dup_repeats); + if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , dis->data_pkt, dis->len_pkt)) + return false; + } + return true; + } + if (bForceSend) + { + DLOG("sending original\n", dp->dup_repeats); + if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , dis->data_pkt, dis->len_pkt)) + return false; + return true; + } + } + return false; +} +// return : true - orig was sent completely, false - should send orig another way +static bool udp_orig_send(uint32_t fwmark, const char *ifout, const struct desync_profile *dp, const t_ctrack *ctrack, struct dissect *dis, bool bForceSend) +{ + if (dp->dup_repeats || bForceSend) + { + unsigned int k; + uint8_t pkt[DPI_DESYNC_MAX_FAKE_LEN+100]; + size_t len; + uint16_t ip_id; + struct sockaddr_storage src, dst; + uint8_t ttl_orig,ttl_fake; + + extract_endpoints(dis->ip, dis->ip6, NULL, dis->udp, &src, &dst); + + if (dp->dup_repeats && check_dup_interval(dp,ctrack)) + { + ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; + ttl_fake = dis->ip6 ? dp->dup_ttl6 : dp->dup_ttl; + if (!ttl_fake) ttl_fake = ttl_orig; + + if (dp->dup_fooling_mode) + { + ip_id = IP4_IP_ID_FIX(dis->ip); + + len = sizeof(pkt); + if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, + ttl_fake, IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), + dp->dup_fooling_mode, NULL, 0, 0, + dis->data_payload, dis->len_payload, pkt, &len)) + { + DLOG_ERR("dup: packet reconstruct failed\n"); + return false; + } + + DLOG("sending %u dups with packet reconstruct\n", dp->dup_repeats); + + // send dups + for (k=0;kdup_repeats;k++) + { + if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , pkt, len)) + return false; + } + } + else + { + if (!orig_send_rewrite(fwmark,ifout,(struct sockaddr *)&dst,ttl_orig,ttl_fake,dp,dis)) + return false; + } + if (dp->dup_replace) + DLOG("NOT sending original because of dup_replace\n"); + else + { + DLOG("sending original\n", dp->dup_repeats); + if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , dis->data_pkt, dis->len_pkt)) + return false; + } + return true; + } + if (bForceSend) + { + DLOG("sending original\n", dp->dup_repeats); + if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , dis->data_pkt, dis->len_pkt)) + return false; + return true; + } + } + return false; +} + static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifout, struct dissect *dis) { uint8_t verdict=VERDICT_PASS; @@ -761,14 +1035,16 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint t_ctrack *ctrack=NULL, *ctrack_replay=NULL; bool bReverse=false; + bool bFake=false; struct sockaddr_storage src, dst; uint8_t pkt1[DPI_DESYNC_MAX_FAKE_LEN+100], pkt2[DPI_DESYNC_MAX_FAKE_LEN+100]; size_t pkt1_len, pkt2_len; uint8_t ttl_orig,ttl_fake,flags_orig,scale_factor; uint32_t *timestamps; + bool bSack; + uint16_t nmss; - ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; uint32_t desync_fwmark = fwmark | params.desync_fwmark; extract_endpoints(dis->ip, dis->ip6, dis->tcp, NULL, &src, &dst); @@ -836,6 +1112,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint { if (ctrack) { + ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; if (!ctrack->incoming_ttl) { DLOG("incoming TTL %u\n",ttl_orig); @@ -895,6 +1172,9 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint return verdict; // nothing to do. do not waste cpu } + if (orig_mod(dp,ctrack,dis)) // ttl can change ! + verdict = VERDICT_MODIFY; + if (dp->wssize) { if (ctrack) @@ -915,34 +1195,37 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint DLOG("not changing wssize. wssize is set but conntrack entry is missing\n"); } } + + // start and cutoff limiters + if (!process_desync_interval(dp, ctrack)) goto send_orig; } // !replay + ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; ttl_fake = (ctrack_replay && ctrack_replay->autottl) ? ctrack_replay->autottl : (dis->ip6 ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig)); flags_orig = *((uint8_t*)dis->tcp+13); scale_factor = tcp_find_scale_factor(dis->tcp); timestamps = tcp_find_timestamps(dis->tcp); + bSack = tcp_has_sack(dis->tcp); + nmss = tcp_find_mss(dis->tcp); if (!replay) { - // start and cutoff limiters - if (!process_desync_interval(dp, ctrack)) return verdict; - if (tcp_syn_segment(dis->tcp)) { switch (dp->desync_mode0) { case DESYNC_SYNACK: pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_SYN|TH_ACK, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_SYN|TH_ACK, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, NULL, 0, pkt1, &pkt1_len)) { - return verdict; + goto send_orig; } DLOG("sending fake SYNACK\n"); if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; + goto send_orig; break; case DESYNC_SYNDATA: // make sure we are not breaking TCP fast open @@ -957,23 +1240,23 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint break; } pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, bSack, nmss, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), 0,0,0, dp->fake_syndata,dp->fake_syndata_size, pkt1,&pkt1_len)) { - return verdict; + goto send_orig; } DLOG("sending SYN with fake data : "); hexdump_limited_dlog(dp->fake_syndata,dp->fake_syndata_size,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; - verdict = ct_new_postnat_fix_tcp(ctrack, dis->ip, dis->ip6, dis->tcp); + goto send_orig; + verdict = VERDICT_DROP; break; default: break; } // can do nothing else with SYN packet - return verdict; + goto send_orig; } } // !replay @@ -1021,7 +1304,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (!bHaveHost) { DLOG("not applying tampering to HTTP without Host:\n"); - return verdict; + goto send_orig; } if (ctrack) { @@ -1056,7 +1339,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (!reasm_orig_start(ctrack,IPPROTO_TCP,TLSRecordLen(dis->data_payload),TCP_MAX_REASM,dis->data_payload,dis->len_payload)) { reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } } if (!ctrack->req_seq_finalized) @@ -1086,7 +1369,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint { DLOG_ERR("rawpacket_queue failed !\n"); reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } if (ReasmIsFull(&ctrack->reasm_orig)) { @@ -1101,7 +1384,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint { DLOG("not applying tampering to TLS ClientHello without hostname in the SNI\n"); reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } } @@ -1135,7 +1418,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint { DLOG_ERR("hostname dup : out of memory"); reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } } } @@ -1160,7 +1443,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (!dp) { reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } if (dp!=dp_prev) { @@ -1174,7 +1457,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (!process_desync_interval(dp, ctrack)) { reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } } } @@ -1202,7 +1485,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } DLOG("not applying tampering to this request\n"); reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } } @@ -1212,7 +1495,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint { DLOG("not applying tampering to unknown protocol\n"); reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } DLOG("applying tampering to unknown protocol\n"); } @@ -1273,7 +1556,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (dp->desync_mode==DESYNC_NONE) { reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } if (params.debug) @@ -1375,7 +1658,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint seqovl_pos = 0; uint32_t fooling_orig = FOOL_NONE; - bool bFake = false; switch(dp->desync_mode) { case DESYNC_FAKE_KNOWN: @@ -1412,20 +1694,20 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint fake_data = fake_item->data; } pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, fake_data, fake_item->size, pkt1, &pkt1_len)) { reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } DLOG("sending fake[%d] : ", n); hexdump_limited_dlog(fake_data,fake_item->size,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) { reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } ip_id=IP4_IP_ID_NEXT(ip_id); } @@ -1436,19 +1718,19 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint case DESYNC_RSTACK: if (reasm_offset) break; pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (dp->desync_mode==DESYNC_RSTACK ? TH_ACK:0), dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (dp->desync_mode==DESYNC_RSTACK ? TH_ACK:0), false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, NULL, 0, pkt1, &pkt1_len)) { reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } DLOG("sending fake RST/RSTACK\n"); if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) { reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } bFake = true; break; @@ -1464,16 +1746,16 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint rdata_payload=NULL; pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_orig,0,0,IP6_FLOW(dis->ip6), fooling_orig,0,0, dis->data_payload, dis->len_payload, pkt1, &pkt1_len)) { - return verdict; + goto send_orig; } DLOG("resending original packet with extension header\n"); if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; + goto send_orig; // this mode is final, no other options available return VERDICT_DROP; } @@ -1517,7 +1799,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (seg_len>sizeof(ovlseg)) { DLOG("seqovl is too large"); - return verdict; + goto send_orig; } fill_pattern(ovlseg,seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern)); memcpy(ovlseg+seqovl,dis->data_payload+from,to-from); @@ -1531,12 +1813,12 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq,from-seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), fooling_orig,0,0, seg, seg_len, pkt1, &pkt1_len)) - return verdict; + goto send_orig; ip_id=IP4_IP_ID_NEXT(ip_id); DLOG("sending multisplit part %d %zu-%zu len=%zu seqovl=%u : ",i+1,from,to-1,to-from,seqovl); hexdump_limited_dlog(seg,seg_len,PKTDATA_MAXDUMP); DLOG("\n"); @@ -1549,7 +1831,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint continue; } #endif - return verdict; + goto send_orig; } #ifdef __linux__ break; @@ -1591,7 +1873,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (seg_len>sizeof(ovlseg)) { DLOG("seqovl is too large"); - return verdict; + goto send_orig; } fill_pattern(ovlseg,seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern)); memcpy(ovlseg+seqovl,dis->data_payload+from,to-from); @@ -1600,17 +1882,17 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq,from-seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), fooling_orig,0,0, seg, seg_len, pkt1, &pkt1_len)) - return verdict; + goto send_orig; ip_id=IP4_IP_ID_PREV(ip_id); DLOG("sending multisplit part %d %zu-%zu len=%zu seqovl=%u : ",i+2,from,to-1,to-from,seqovl); hexdump_limited_dlog(seg,seg_len,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; + goto send_orig; to = from; } @@ -1627,7 +1909,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (dis->len_payload > sizeof(pat)) { DLOG("packet is too large\n"); - return verdict; + goto send_orig; } fill_pattern(pat,dis->len_payload,dp->fsplit_pattern,sizeof(dp->fsplit_pattern)); @@ -1647,7 +1929,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (seg_len>sizeof(fakeseg)) { DLOG("seqovl is too large\n"); - return verdict; + goto send_orig; } fill_pattern(fakeseg,seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern)); memcpy(fakeseg+seqovl,dis->data_payload+split_pos,dis->len_payload-split_pos); @@ -1660,28 +1942,28 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } fakeseg2_len = sizeof(fakeseg2); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq,split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq,split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, pat+split_pos, dis->len_payload-split_pos, fakeseg2, &fakeseg2_len)) - return verdict; + goto send_orig; ip_id=IP4_IP_ID_PREV(ip_id); DLOG("sending fake(1) 2nd out-of-order tcp segment %zu-%zu len=%zu : ",split_pos,dis->len_payload-1, dis->len_payload-split_pos); hexdump_limited_dlog(pat+split_pos,dis->len_payload-split_pos,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg2, fakeseg2_len)) - return verdict; + goto send_orig; pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq , split_pos - seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq , split_pos - seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, seg, seg_len, pkt1, &pkt1_len)) - return verdict; + goto send_orig; ip_id=IP4_IP_ID_PREV(ip_id); DLOG("sending 2nd out-of-order tcp segment %zu-%zu len=%zu seqovl=%u : ",split_pos,dis->len_payload-1, dis->len_payload-split_pos, seqovl); hexdump_limited_dlog(seg,seg_len,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; + goto send_orig; if (dis->ip) ((struct ip*)fakeseg2)->ip_id = ip_id; ip_id=IP4_IP_ID_PREV(ip_id); @@ -1689,37 +1971,37 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint DLOG("sending fake(2) 2nd out-of-order tcp segment %zu-%zu len=%zu : ",split_pos,dis->len_payload-1, dis->len_payload-split_pos); hexdump_limited_dlog(pat+split_pos,dis->len_payload-split_pos,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg2, fakeseg2_len)) - return verdict; + goto send_orig; seg_len = sizeof(fakeseg); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, pat, split_pos, fakeseg, &seg_len)) - return verdict; + goto send_orig; ip_id=IP4_IP_ID_PREV(ip_id); DLOG("sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos); hexdump_limited_dlog(pat,split_pos,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, seg_len)) - return verdict; + goto send_orig; pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, dis->data_payload, split_pos, pkt1, &pkt1_len)) - return verdict; + goto send_orig; ip_id=IP4_IP_ID_PREV(ip_id); DLOG("sending 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos); hexdump_limited_dlog(dis->data_payload,split_pos,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; + goto send_orig; if (dis->ip) ((struct ip*)fakeseg)->ip_id = ip_id; DLOG("sending fake(2) 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos); hexdump_limited_dlog(pat,split_pos,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, seg_len)) - return verdict; + goto send_orig; return VERDICT_DROP; } @@ -1733,23 +2015,23 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (dis->len_payload > sizeof(pat)) { DLOG("packet is too large\n"); - return verdict; + goto send_orig; } fill_pattern(pat,dis->len_payload,dp->fsplit_pattern,sizeof(dp->fsplit_pattern)); ip_id = IP4_IP_ID_FIX(dis->ip); fakeseg_len = sizeof(fakeseg); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, pat, split_pos, fakeseg, &fakeseg_len)) - return verdict; + goto send_orig; ip_id=IP4_IP_ID_NEXT(ip_id); DLOG("sending fake(1) 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos); hexdump_limited_dlog(pat,split_pos,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len)) - return verdict; + goto send_orig; unsigned int seqovl = reasm_offset ? 0 : seqovl_pos; #ifdef __linux__ @@ -1763,7 +2045,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (seg_len>sizeof(ovlseg)) { DLOG("seqovl is too large"); - return verdict; + goto send_orig; } fill_pattern(ovlseg,seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern)); memcpy(ovlseg+seqovl,dis->data_payload,split_pos); @@ -1776,11 +2058,11 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq,-seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq,-seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, seg, seg_len, pkt1, &pkt1_len)) - return verdict; + goto send_orig; ip_id=IP4_IP_ID_NEXT(ip_id); DLOG("sending 1st tcp segment 0-%zu len=%zu seqovl=%u : ",split_pos-1, split_pos, seqovl); hexdump_limited_dlog(seg,seg_len,PKTDATA_MAXDUMP); DLOG("\n"); @@ -1793,7 +2075,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint continue; } #endif - return verdict; + goto send_orig; } #ifdef __linux__ break; @@ -1804,38 +2086,38 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint DLOG("sending fake(2) 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos); hexdump_limited_dlog(pat,split_pos,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len)) - return verdict; + goto send_orig; fakeseg_len = sizeof(fakeseg); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq,split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq,split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, pat+split_pos, dis->len_payload-split_pos, fakeseg, &fakeseg_len)) - return verdict; + goto send_orig; ip_id=IP4_IP_ID_NEXT(ip_id); DLOG("sending fake(1) 2nd tcp segment %zu-%zu len=%zu : ",split_pos,dis->len_payload-1, dis->len_payload-split_pos); hexdump_limited_dlog(pat+split_pos,dis->len_payload-split_pos,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len)) - return verdict; + goto send_orig; pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq,split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq,split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_orig,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, dis->data_payload+split_pos, dis->len_payload-split_pos, pkt1, &pkt1_len)) - return verdict; + goto send_orig; ip_id=IP4_IP_ID_NEXT(ip_id); DLOG("sending 2nd tcp segment %zu-%zu len=%zu : ",split_pos,dis->len_payload-1, dis->len_payload-split_pos); hexdump_limited_dlog(dis->data_payload+split_pos,dis->len_payload-split_pos,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; + goto send_orig; if (dis->ip) ((struct ip*)fakeseg)->ip_id = ip_id; DLOG("sending fake(2) 2nd tcp segment %zu-%zu len=%zu : ",split_pos,dis->len_payload-1, dis->len_payload-split_pos); hexdump_limited_dlog(pat+split_pos,dis->len_payload-split_pos,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len)) - return verdict; + goto send_orig; return VERDICT_DROP; } @@ -1859,7 +2141,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint { pkt_orig_len = sizeof(pkt3); if (!ip6_insert_simple_hdr(fooling_orig==FOOL_HOPBYHOP ? IPPROTO_HOPOPTS : IPPROTO_DSTOPTS, dis->data_pkt, dis->len_pkt, pkt3, &pkt_orig_len)) - return verdict; + goto send_orig; pkt_orig = pkt3; } else @@ -1869,17 +2151,17 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } if (!ip_frag(pkt_orig, pkt_orig_len, ipfrag_pos, ident, pkt1, &pkt1_len, pkt2, &pkt2_len)) - return verdict; + goto send_orig; DLOG("sending 1st ip fragment 0-%zu ip_payload_len=%zu : ", ipfrag_pos-1, ipfrag_pos); hexdump_limited_dlog(pkt1,pkt1_len,IP_MAXDUMP); DLOG("\n"); if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; + goto send_orig; DLOG("sending 2nd ip fragment %zu-%zu ip_payload_len=%zu : ", ipfrag_pos, dis->transport_len-1, dis->transport_len-ipfrag_pos); hexdump_limited_dlog(pkt2,pkt2_len,IP_MAXDUMP); DLOG("\n"); if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt2, pkt2_len)) - return verdict; + goto send_orig; return VERDICT_DROP; } @@ -1888,17 +2170,16 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } if (bFake) - { - // if we are here original message was not sent in any form - // allowing system to pass the message to queue can result in unpredicted send order - DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", dis->len_pkt, dis->len_payload); verdict_tcp_csum_fix(verdict, dis->tcp, dis->transport_len, dis->ip, dis->ip6); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , dis->data_pkt, dis->len_pkt)) - return verdict; - return VERDICT_DROP; - } } +send_orig: + + if ((verdict & VERDICT_MASK)==VERDICT_DROP) + verdict = ct_new_postnat_fix_tcp(ctrack, dis->ip, dis->ip6, dis->tcp); + else + if (tcp_orig_send(desync_fwmark,ifout,dp,ctrack_replay,dis,bFake)) + verdict = ct_new_postnat_fix_tcp(ctrack, dis->ip, dis->ip6, dis->tcp); return verdict; } @@ -1925,13 +2206,11 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint // additional safety check if (!!dis->ip == !!dis->ip6) return verdict; - // no need to desync middle packets in reasm session - if (reasm_offset) return verdict; - struct desync_profile *dp = NULL; t_ctrack *ctrack=NULL, *ctrack_replay=NULL; bool bReverse=false; + bool bFake = false; struct sockaddr_storage src, dst; uint8_t pkt1[DPI_DESYNC_MAX_FAKE_LEN+100], pkt2[DPI_DESYNC_MAX_FAKE_LEN+100]; @@ -1939,7 +2218,6 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint uint8_t ttl_orig,ttl_fake; t_l7proto l7proto = UNKNOWN; - ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; extract_endpoints(dis->ip, dis->ip6, NULL, dis->udp, &src, &dst); if (replay) @@ -1963,6 +2241,9 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint DLOG("matching desync profile not found\n"); return verdict; } + + // no need to desync middle packets in reasm session + if (reasm_offset) goto send_orig; } else { @@ -1994,23 +2275,31 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint HostFailPoolPurgeRateLimited(&dp->hostlist_auto_fail_counters); //ConntrackPoolDump(¶ms.conntrack); - } - - if (bReverse && ctrack) - { - if (!ctrack->incoming_ttl) + + if (bReverse) { - DLOG("incoming TTL %u\n",ttl_orig); - ctrack->incoming_ttl = ttl_orig; + if (ctrack) + { + ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; + if (!ctrack->incoming_ttl) + { + DLOG("incoming TTL %u\n",ttl_orig); + ctrack->incoming_ttl = ttl_orig; + } + if (!ctrack->autottl) autottl_discover(ctrack,!!dis->ip6); + } + return verdict; // nothing to do. do not waste cpu } - if (!ctrack->autottl) autottl_discover(ctrack,!!dis->ip6); - return verdict; // nothing to do. do not waste cpu - } - // start and cutoff limiters - if (!replay && !process_desync_interval(dp, ctrack)) return verdict; + if (orig_mod(dp,ctrack,dis)) // ttl can change ! + verdict = VERDICT_MODIFY; + + // start and cutoff limiters + if (!process_desync_interval(dp, ctrack)) goto send_orig; + } uint32_t desync_fwmark = fwmark | params.desync_fwmark; + ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; if (dis->len_payload) { @@ -2052,7 +2341,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint { DLOG("QUIC reasm is too long. cancelling.\n"); reasm_orig_cancel(ctrack); - return verdict; // cannot be first packet + goto send_orig; // cannot be first packet } } uint8_t defrag[UDP_MAX_REASM]; @@ -2079,7 +2368,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint if (!reasm_orig_start(ctrack,IPPROTO_UDP,UDP_MAX_REASM,UDP_MAX_REASM,clean,clean_len)) { reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } } if (!ReasmIsEmpty(&ctrack->reasm_orig)) @@ -2093,7 +2382,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint { DLOG_ERR("rawpacket_queue failed !\n"); reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } if (bReqFull) { @@ -2111,12 +2400,12 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint { reasm_orig_cancel(ctrack); DLOG("not applying tampering to QUIC ClientHello without hostname in the SNI\n"); - return verdict; + goto send_orig; } } else { - if (!quic_reasm_cancel(ctrack,"QUIC initial without ClientHello")) return verdict; + if (!quic_reasm_cancel(ctrack,"QUIC initial without ClientHello")) goto send_orig; } } else @@ -2130,7 +2419,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint if (!reasm_orig_start(ctrack,IPPROTO_UDP,UDP_MAX_REASM,UDP_MAX_REASM,clean,clean_len)) { reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } } verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6); @@ -2142,23 +2431,23 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint { DLOG_ERR("rawpacket_queue failed !\n"); reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt); } - if (!quic_reasm_cancel(ctrack,"QUIC initial fragmented CRYPTO")) return verdict; + if (!quic_reasm_cancel(ctrack,"QUIC initial fragmented CRYPTO")) goto send_orig; } } else { // defrag failed - if (!quic_reasm_cancel(ctrack,"QUIC initial defrag CRYPTO failed")) return verdict; + if (!quic_reasm_cancel(ctrack,"QUIC initial defrag CRYPTO failed")) goto send_orig; } } else { // decrypt failed - if (!quic_reasm_cancel(ctrack,"QUIC initial decryption failed")) return verdict; + if (!quic_reasm_cancel(ctrack,"QUIC initial decryption failed")) goto send_orig; } } else // not QUIC initial @@ -2197,7 +2486,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint if (!dp->desync_any_proto) { DLOG("not applying tampering to unknown protocol\n"); - return verdict; + goto send_orig; } DLOG("applying tampering to unknown protocol\n"); } @@ -2225,7 +2514,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint if (!ctrack_replay->hostname) { DLOG_ERR("hostname dup : out of memory"); - return verdict; + goto send_orig; } } } @@ -2250,7 +2539,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint if (!dp) { reasm_orig_cancel(ctrack); - return verdict; + goto send_orig; } if (dp!=dp_prev) { @@ -2261,7 +2550,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint if (!replay) { maybe_cutoff(ctrack, IPPROTO_UDP); - if (!process_desync_interval(dp, ctrack)) return verdict; + if (!process_desync_interval(dp, ctrack)) goto send_orig; } } } @@ -2291,7 +2580,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint } } DLOG("not applying tampering to this request\n"); - return verdict; + goto send_orig; } } @@ -2330,7 +2619,6 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint DLOG("dpi desync src=%s dst=%s\n",s1,s2); } - bool bFake = false; switch(dp->desync_mode) { case DESYNC_FAKE_KNOWN: @@ -2355,12 +2643,12 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint dp->desync_fooling_mode, NULL, 0, 0, fake_item->data, fake_item->size, pkt1, &pkt1_len)) { - return verdict; + goto send_orig; } DLOG("sending fake[%d] : ", n); hexdump_limited_dlog(fake_item->data,fake_item->size,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; + goto send_orig; ip_id=IP4_IP_ID_NEXT(ip_id); } } @@ -2377,11 +2665,11 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint ttl_orig,0,0,IP6_FLOW(dis->ip6),fooling_orig,NULL,0,0, dis->data_payload, dis->len_payload, pkt1, &pkt1_len)) { - return verdict; + goto send_orig; } DLOG("resending original packet with extension header\n"); if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; + goto send_orig; // this mode is final, no other options available return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt); } @@ -2403,7 +2691,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint } DLOG("resending original packet with increased by %d length\n", dp->udplen_increment); if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; + goto send_orig; return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt); case DESYNC_TAMPER: if (IsDhtD1(dis->data_payload,dis->len_payload)) @@ -2428,7 +2716,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint } DLOG("resending tampered DHT\n"); if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; + goto send_orig; return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt); } else @@ -2455,7 +2743,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint { pkt_orig_len = sizeof(pkt3); if (!ip6_insert_simple_hdr(fooling_orig==FOOL_HOPBYHOP ? IPPROTO_HOPOPTS : IPPROTO_DSTOPTS, dis->data_pkt, dis->len_pkt, pkt3, &pkt_orig_len)) - return verdict; + goto send_orig; pkt_orig = pkt3; } else @@ -2465,17 +2753,17 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint } if (!ip_frag(pkt_orig, pkt_orig_len, ipfrag_pos, ident, pkt1, &pkt1_len, pkt2, &pkt2_len)) - return verdict; + goto send_orig; DLOG("sending 1st ip fragment 0-%zu ip_payload_len=%zu : ", ipfrag_pos-1, ipfrag_pos); hexdump_limited_dlog(pkt1,pkt1_len,IP_MAXDUMP); DLOG("\n"); if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; + goto send_orig; DLOG("sending 2nd ip fragment %zu-%zu ip_payload_len=%zu : ", ipfrag_pos, dis->transport_len-1, dis->transport_len-ipfrag_pos); hexdump_limited_dlog(pkt2,pkt2_len,IP_MAXDUMP); DLOG("\n"); if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt2, pkt2_len)) - return verdict; + goto send_orig; return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt); } @@ -2484,17 +2772,15 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint } if (bFake) - { - // if we are here original message was not sent in any form - // allowing system to pass the message to queue can result in unpredicted send order - DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", dis->len_pkt, dis->len_payload); verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , dis->data_pkt, dis->len_pkt)) - return verdict; - return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt); - } } +send_orig: + if ((verdict & VERDICT_MASK)==VERDICT_DROP) + verdict = ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt); + else + if (udp_orig_send(desync_fwmark,ifout,dp,ctrack_replay,dis,bFake)) + verdict = ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt); return verdict; } diff --git a/nfq/nfqws.c b/nfq/nfqws.c index 311f505..10758c0 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -1003,6 +1003,33 @@ err: return false; } +static bool parse_fooling(char *opt, unsigned int *fooling_mode) +{ + char *e,*p = opt; + while (p) + { + e = strchr(p,','); + if (e) *e++=0; + if (!strcmp(p,"md5sig")) + *fooling_mode |= FOOL_MD5SIG; + else if (!strcmp(p,"ts")) + *fooling_mode |= FOOL_TS; + else if (!strcmp(p,"badsum")) + *fooling_mode |= FOOL_BADSUM; + else if (!strcmp(p,"badseq")) + *fooling_mode |= FOOL_BADSEQ; + else if (!strcmp(p,"datanoack")) + *fooling_mode |= FOOL_DATANOACK; + else if (!strcmp(p,"hopbyhop")) + *fooling_mode |= FOOL_HOPBYHOP; + else if (!strcmp(p,"hopbyhop2")) + *fooling_mode |= FOOL_HOPBYHOP2; + else if (strcmp(p,"none")) + return false; + p = e; + } + return true; +} static void split_compat(struct desync_profile *dp) { @@ -1421,6 +1448,19 @@ static void exithelp(void) " --wsize=[:]\t\t; set window size. 0 = do not modify. OBSOLETE !\n" " --wssize=[:]\t; set window size for server. 0 = do not modify. default scale_factor = 0.\n" " --wssize-cutoff=[n|d|s]N\t\t\t; apply server wsize only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n" + " --orig-ttl=\t\t\t\t; set TTL for original packets\n" + " --orig-ttl6=\t\t\t\t; set ipv6 hop limit for original packets. by default ttl value is used\n" + " --orig-mod-start=[n|d|s]N\t\t\t; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n" + " --orig-mod-cutoff=[n|d|s]N\t\t\t; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n" + " --dup=\t\t\t\t\t; duplicate original packets. send N dups before original.\n" + " --dup-ttl=\t\t\t\t; set TTL for dups\n" + " --dup-replace=[0|1]\t\t\t\t; 1 or no argument means do not send original, only dups\n" + " --dup-ttl6=\t\t\t\t; set ipv6 hop limit for dups. by default ttl value is used\n" + " --dup-fooling=[,]\t\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack hopbyhop hopbyhop2\n" + " --dup-start=[n|d|s]N\t\t\t\t; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n" + " --dup-cutoff=[n|d|s]N\t\t\t\t; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n" + " --dup-badseq-increment=\t\t; badseq fooling seq signed increment for dup. default %d\n" + " --dup-desync-badack-increment=\t; badseq fooling ackseq signed increment for dup. default %d\n" " --hostcase\t\t\t\t\t; change Host: => host:\n" " --hostspell\t\t\t\t\t; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n" " --hostnospace\t\t\t\t\t; remove space after Host: and add it to User-Agent: to preserve packet size\n" @@ -1434,11 +1474,11 @@ static void exithelp(void) #elif defined(SO_USER_COOKIE) " --dpi-desync-sockarg=\t\t; override sockarg (SO_USER_COOKIE) for desync packet. default = 0x%08X (%u)\n" #endif - " --dpi-desync-ttl=\t\t\t\t; set ttl for desync packet\n" - " --dpi-desync-ttl6=\t\t\t; set ipv6 hop limit for desync packet. by default ttl value is used.\n" + " --dpi-desync-ttl=\t\t\t\t; set ttl for fakes packets\n" + " --dpi-desync-ttl6=\t\t\t; set ipv6 hop limit for fake packet. by default --dpi-desync-ttl value is used.\n" " --dpi-desync-autottl=[[:[-]]]\t; auto ttl mode for both ipv4 and ipv6. default: %u:%u-%u\n" " --dpi-desync-autottl6=[[:[-]]] ; overrides --dpi-desync-autottl for ipv6 only\n" - " --dpi-desync-fooling=[,]\t\t; can use multiple comma separated values. modes : none md5sig ts badseq badsum datanoack hopbyhop hopbyhop2\n" + " --dpi-desync-fooling=[,]\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack hopbyhop hopbyhop2\n" " --dpi-desync-repeats=\t\t\t; send every desync packet N times\n" " --dpi-desync-skip-nosni=0|1\t\t\t; 1(default)=do not act on ClientHello without SNI\n" " --dpi-desync-split-pos=N|-N|marker+N|marker-N\t; comma separated list of split positions\n" @@ -1470,6 +1510,7 @@ static void exithelp(void) " --dpi-desync-cutoff=[n|d|s]N\t\t\t; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n", CTRACK_T_SYN, CTRACK_T_EST, CTRACK_T_FIN, CTRACK_T_UDP, HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT, HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT, + BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT, #if defined(__linux__) || defined(SO_USER_COOKIE) DPI_DESYNC_FWMARK_DEFAULT,DPI_DESYNC_FWMARK_DEFAULT, #endif @@ -1574,6 +1615,19 @@ enum opt_indices { #elif defined(SO_USER_COOKIE) IDX_DPI_DESYNC_SOCKARG, #endif + IDX_DUP, + IDX_DUP_TTL, + IDX_DUP_TTL6, + IDX_DUP_FOOLING, + IDX_DUP_BADSEQ_INCREMENT, + IDX_DUP_BADACK_INCREMENT, + IDX_DUP_REPLACE, + IDX_DUP_START, + IDX_DUP_CUTOFF, + IDX_ORIG_TTL, + IDX_ORIG_TTL6, + IDX_ORIG_MOD_START, + IDX_ORIG_MOD_CUTOFF, IDX_DPI_DESYNC_TTL, IDX_DPI_DESYNC_TTL6, IDX_DPI_DESYNC_AUTOTTL, @@ -1674,6 +1728,19 @@ static const struct option long_options[] = { #elif defined(SO_USER_COOKIE) [IDX_DPI_DESYNC_SOCKARG] = {"dpi-desync-sockarg", required_argument, 0, 0}, #endif + [IDX_DUP] = {"dup", required_argument, 0, 0}, + [IDX_DUP_TTL] = {"dup-ttl", required_argument, 0, 0}, + [IDX_DUP_TTL6] = {"dup-ttl6", required_argument, 0, 0}, + [IDX_DUP_FOOLING] = {"dup-fooling", required_argument, 0, 0}, + [IDX_DUP_BADSEQ_INCREMENT] = {"dup-badseq-increment", required_argument, 0, 0}, + [IDX_DUP_BADACK_INCREMENT] = {"dup-badack-increment", required_argument, 0, 0}, + [IDX_DUP_REPLACE] = {"dup-replace", optional_argument, 0, 0}, + [IDX_DUP_START] = {"dup-start", required_argument, 0, 0}, + [IDX_DUP_CUTOFF] = {"dup-cutoff", required_argument, 0, 0}, + [IDX_ORIG_TTL] = {"orig-ttl", required_argument, 0, 0}, + [IDX_ORIG_TTL6] = {"orig-ttl6", required_argument, 0, 0}, + [IDX_ORIG_MOD_START] = {"orig-mod-start", required_argument, 0, 0}, + [IDX_ORIG_MOD_CUTOFF] = {"orig-mod-cutoff", required_argument, 0, 0}, [IDX_DPI_DESYNC_TTL] = {"dpi-desync-ttl", required_argument, 0, 0}, [IDX_DPI_DESYNC_TTL6] = {"dpi-desync-ttl6", required_argument, 0, 0}, [IDX_DPI_DESYNC_AUTOTTL] = {"dpi-desync-autottl", optional_argument, 0, 0}, @@ -2043,6 +2110,80 @@ int main(int argc, char **argv) } break; #endif + + case IDX_DUP: + if (sscanf(optarg,"%u",&dp->dup_repeats)<1 || dp->dup_repeats>1024) + { + DLOG_ERR("dup-repeats must be within 0..1024\n"); + exit_clean(1); + } + break; + case IDX_DUP_TTL: + dp->dup_ttl = (uint8_t)atoi(optarg); + break; + case IDX_DUP_TTL6: + dp->dup_ttl6 = (uint8_t)atoi(optarg); + break; + case IDX_DUP_REPLACE: + dp->dup_replace = optarg ? !!atoi(optarg) : true; + break; + case IDX_DUP_FOOLING: + if (!parse_fooling(optarg,&dp->dup_fooling_mode)) + { + DLOG_ERR("fooling allowed values : none,md5sig,ts,badseq,badsum,datanoack,hopbyhop,hopbyhop2\n"); + exit_clean(1); + } + break; + case IDX_DUP_BADSEQ_INCREMENT: + if (!parse_badseq_increment(optarg,&dp->dup_badseq_increment)) + { + DLOG_ERR("dup-badseq-increment should be signed decimal or signed 0xHEX\n"); + exit_clean(1); + } + break; + case IDX_DUP_BADACK_INCREMENT: + if (!parse_badseq_increment(optarg,&dp->dup_badseq_ack_increment)) + { + DLOG_ERR("dup-badack-increment should be signed decimal or signed 0xHEX\n"); + exit_clean(1); + } + break; + case IDX_DUP_CUTOFF: + if (!parse_cutoff(optarg, &dp->dup_cutoff, &dp->dup_cutoff_mode)) + { + DLOG_ERR("invalid dup-cutoff value\n"); + exit_clean(1); + } + break; + case IDX_DUP_START: + if (!parse_cutoff(optarg, &dp->dup_start, &dp->dup_start_mode)) + { + DLOG_ERR("invalid dup-start value\n"); + exit_clean(1); + } + break; + + case IDX_ORIG_TTL: + dp->orig_mod_ttl = (uint8_t)atoi(optarg); + break; + case IDX_ORIG_TTL6: + dp->orig_mod_ttl6 = (uint8_t)atoi(optarg); + break; + case IDX_ORIG_MOD_CUTOFF: + if (!parse_cutoff(optarg, &dp->orig_mod_cutoff, &dp->orig_mod_cutoff_mode)) + { + DLOG_ERR("invalid orig-mod-cutoff value\n"); + exit_clean(1); + } + break; + case IDX_ORIG_MOD_START: + if (!parse_cutoff(optarg, &dp->orig_mod_start, &dp->orig_mod_start_mode)) + { + DLOG_ERR("invalid orig-mod-start value\n"); + exit_clean(1); + } + break; + case IDX_DPI_DESYNC_TTL: dp->desync_ttl = (uint8_t)atoi(optarg); break; @@ -2064,44 +2205,16 @@ int main(int argc, char **argv) } break; case IDX_DPI_DESYNC_FOOLING: + if (!parse_fooling(optarg,&dp->desync_fooling_mode)) { - char *e,*p = optarg; - while (p) - { - e = strchr(p,','); - if (e) *e++=0; - if (!strcmp(p,"md5sig")) - dp->desync_fooling_mode |= FOOL_MD5SIG; - else if (!strcmp(p,"ts")) - dp->desync_fooling_mode |= FOOL_TS; - else if (!strcmp(p,"badsum")) - { - #ifdef __OpenBSD__ - DLOG_CONDUP("\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 - dp->desync_fooling_mode |= FOOL_BADSUM; - } - else if (!strcmp(p,"badseq")) - dp->desync_fooling_mode |= FOOL_BADSEQ; - else if (!strcmp(p,"datanoack")) - dp->desync_fooling_mode |= FOOL_DATANOACK; - else if (!strcmp(p,"hopbyhop")) - dp->desync_fooling_mode |= FOOL_HOPBYHOP; - else if (!strcmp(p,"hopbyhop2")) - dp->desync_fooling_mode |= FOOL_HOPBYHOP2; - else if (strcmp(p,"none")) - { - DLOG_ERR("dpi-desync-fooling allowed values : none,md5sig,ts,badseq,badsum,datanoack,hopbyhop,hopbyhop2\n"); - exit_clean(1); - } - p = e; - } + DLOG_ERR("fooling allowed values : none,md5sig,ts,badseq,badsum,datanoack,hopbyhop,hopbyhop2\n"); + exit_clean(1); } break; case IDX_DPI_DESYNC_REPEATS: - if (sscanf(optarg,"%u",&dp->desync_repeats)<1 || !dp->desync_repeats || dp->desync_repeats>20) + if (sscanf(optarg,"%u",&dp->desync_repeats)<1 || !dp->desync_repeats || dp->desync_repeats>1024) { - DLOG_ERR("dpi-desync-repeats must be within 1..20\n"); + DLOG_ERR("dpi-desync-repeats must be within 1..1024\n"); exit_clean(1); } break; @@ -2709,6 +2822,8 @@ int main(int argc, char **argv) dp = &dpl->dp; // not specified - use desync_ttl value instead if (dp->desync_ttl6 == 0xFF) dp->desync_ttl6=dp->desync_ttl; + if (dp->dup_ttl6 == 0xFF) dp->dup_ttl6=dp->dup_ttl; + if (dp->orig_mod_ttl6 == 0xFF) dp->orig_mod_ttl6=dp->orig_mod_ttl; if (!AUTOTTL_ENABLED(dp->desync_autottl6)) dp->desync_autottl6 = dp->desync_autottl; if (AUTOTTL_ENABLED(dp->desync_autottl)) DLOG("profile %d autottl ipv4 %u:%u-%u\n",dp->n,dp->desync_autottl.delta,dp->desync_autottl.min,dp->desync_autottl.max); diff --git a/nfq/params.c b/nfq/params.c index d862b6e..e279ebf 100644 --- a/nfq/params.c +++ b/nfq/params.c @@ -187,10 +187,10 @@ void dp_init(struct desync_profile *dp) dp->desync_repeats = 1; dp->fake_syndata_size = 16; dp->wscale=-1; // default - dont change scale factor (client) - dp->desync_ttl6 = 0xFF; // unused - dp->desync_badseq_increment = BADSEQ_INCREMENT_DEFAULT; - dp->desync_badseq_ack_increment = BADSEQ_ACK_INCREMENT_DEFAULT; - dp->wssize_cutoff_mode = dp->desync_start_mode = dp->desync_cutoff_mode = 'n'; // packet number by default + dp->desync_ttl6 = dp->dup_ttl6 = dp->orig_mod_ttl6 = 0xFF; // unused + dp->desync_badseq_increment = dp->dup_badseq_increment = BADSEQ_INCREMENT_DEFAULT; + dp->desync_badseq_ack_increment = dp->dup_badseq_ack_increment = BADSEQ_ACK_INCREMENT_DEFAULT; + dp->wssize_cutoff_mode = dp->desync_start_mode = dp->desync_cutoff_mode = dp->dup_start_mode = dp->dup_cutoff_mode = dp->orig_mod_start_mode = dp->orig_mod_cutoff_mode = 'n'; // packet number by default dp->udplen_increment = UDPLEN_INCREMENT_DEFAULT; dp->hostlist_auto_fail_threshold = HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT; dp->hostlist_auto_fail_time = HOSTLIST_AUTO_FAIL_TIME_DEFAULT; diff --git a/nfq/params.h b/nfq/params.h index 015059a..7ae8bee 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -82,6 +82,18 @@ struct desync_profile int split_count; struct proto_pos seqovl; + char dup_start_mode, dup_cutoff_mode; // n - packets, d - data packets, s - relative sequence + bool dup_replace; + unsigned int dup_start, dup_cutoff; + unsigned int dup_repeats; + uint8_t dup_ttl, dup_ttl6; + uint32_t dup_fooling_mode; + uint32_t dup_badseq_increment, dup_badseq_ack_increment; + + char orig_mod_start_mode, orig_mod_cutoff_mode; // n - packets, d - data packets, s - relative sequence + unsigned int orig_mod_start, orig_mod_cutoff; + uint8_t orig_mod_ttl, orig_mod_ttl6; + char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence unsigned int desync_start, desync_cutoff; uint8_t desync_ttl, desync_ttl6; @@ -117,6 +129,7 @@ struct desync_profile #define PROFILE_IPSETS_ABSENT(dp) (!LIST_FIRST(&dp->ips_collection) && !LIST_FIRST(&dp->ips_collection_exclude)) #define PROFILE_IPSETS_EMPTY(dp) (ipset_collection_is_empty(&dp->ips_collection) && ipset_collection_is_empty(&dp->ips_collection_exclude)) #define PROFILE_HOSTLISTS_EMPTY(dp) (hostlist_collection_is_empty(&dp->hl_collection) && hostlist_collection_is_empty(&dp->hl_collection_exclude)) +#define PROFILE_HAS_ORIG_MOD(dp) (dp->orig_mod_ttl || dp->orig_mod_ttl6) struct desync_profile_list { struct desync_profile dp;