diff --git a/docs/changes.txt b/docs/changes.txt index 7b74e9c4..ad95d80b 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -561,3 +561,10 @@ v72.1 nfqws: --ip-id=seq|seqgroup|rnd|zero blockcheck: MIN_AUTOTTL_DELTA,MAX_AUTOTTL_DELTA init.d: 50-quic4all custom + +72.2 + +nfqws: --wssize-forced-cutoff +nfqws: --orig-tcp-flags, --dup-tcp-flags, --dpi-desync-tcp-flags +nfqws: --dup-ip-id + diff --git a/nfq/darkmagic.c b/nfq/darkmagic.c index 1e85a7cb..b760d0a2 100644 --- a/nfq/darkmagic.c +++ b/nfq/darkmagic.c @@ -111,7 +111,7 @@ bool tcp_has_sack(struct tcphdr *tcp) // n prefix (nsport, nwsize) means network byte order static void fill_tcphdr( - struct tcphdr *tcp, uint32_t fooling, uint8_t tcp_flags, + struct tcphdr *tcp, uint32_t fooling, uint16_t tcp_flags, bool sack, uint16_t nmss, uint32_t nseq, uint32_t nack_seq, @@ -142,7 +142,8 @@ static void fill_tcphdr( 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_flags = (uint8_t)tcp_flags; + tcp->th_x2 = (tcp_flags>>8) & 0xF; tcp->th_win = nwsize; if (nmss) { @@ -231,7 +232,7 @@ 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, + uint16_t tcp_flags, bool sack, uint16_t nmss, uint32_t nseq, uint32_t nack_seq, @@ -271,7 +272,7 @@ bool prepare_tcp_segment4( bool prepare_tcp_segment6( const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst, - uint8_t tcp_flags, + uint16_t tcp_flags, bool sack, uint16_t nmss, uint32_t nseq, uint32_t nack_seq, @@ -358,7 +359,7 @@ bool prepare_tcp_segment6( bool prepare_tcp_segment( const struct sockaddr *src, const struct sockaddr *dst, - uint8_t tcp_flags, + uint16_t tcp_flags, bool sack, uint16_t nmss, uint32_t nseq, uint32_t nack_seq, @@ -681,6 +682,20 @@ bool rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl) return false; } +void apply_tcp_flags(struct tcphdr *tcp, uint16_t fl) +{ + if (tcp) + { + tcp->th_flags = (uint8_t)fl; + tcp->th_x2 = (fl>>8) & 0xF; + } +} +uint16_t get_tcp_flags(const struct tcphdr *tcp) +{ + return tcp->th_flags | (tcp->th_x2<<8); +} + + void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport) { diff --git a/nfq/darkmagic.h b/nfq/darkmagic.h index 77515a55..49b0ee65 100644 --- a/nfq/darkmagic.h +++ b/nfq/darkmagic.h @@ -69,7 +69,7 @@ uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment); // 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, + uint16_t tcp_flags, bool sack, uint16_t nmss, uint32_t nseq, uint32_t nack_seq, @@ -88,7 +88,7 @@ bool prepare_tcp_segment4( uint8_t *buf, size_t *buflen); bool prepare_tcp_segment6( const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst, - uint8_t tcp_flags, + uint16_t tcp_flags, bool sack, uint16_t nmss, uint32_t nseq, uint32_t nack_seq, @@ -105,7 +105,7 @@ bool prepare_tcp_segment6( uint8_t *buf, size_t *buflen); bool prepare_tcp_segment( const struct sockaddr *src, const struct sockaddr *dst, - uint8_t tcp_flags, + uint16_t tcp_flags, bool sack, uint16_t nmss, uint32_t nseq, uint32_t nack_seq, @@ -178,6 +178,8 @@ bool ip_frag( uint8_t *pkt2, size_t *pkt2_size); bool rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl); +uint16_t get_tcp_flags(const struct tcphdr *tcp); +void apply_tcp_flags(struct tcphdr *tcp, uint16_t fl); 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); diff --git a/nfq/desync.c b/nfq/desync.c index 1f62a01a..cf65595a 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -841,11 +841,13 @@ static uint16_t IP4_IP_ID_FIX(const struct ip *ip, t_ip_id_mode mode) { switch(mode) { - case IPID_RND: - return (uint16_t)(random()%0xFFFF + 1); case IPID_SEQ: case IPID_SEQ_GROUP: return ip->ip_id ? ip->ip_id : (uint16_t)random(); + case IPID_SAME: + return ip->ip_id; + case IPID_RND: + return (uint16_t)(random()%0xFFFF + 1); default: break; } @@ -856,8 +858,6 @@ static uint16_t IP4_IP_ID_ADD(uint16_t ip_id, uint16_t inc, t_ip_id_mode mode) { switch(mode) { - case IPID_RND: - return (uint16_t)(random()%0xFFFF + 1);; case IPID_SEQ_GROUP: case IPID_SEQ: if (ip_id) @@ -865,7 +865,10 @@ static uint16_t IP4_IP_ID_ADD(uint16_t ip_id, uint16_t inc, t_ip_id_mode mode) ip_id = net16_add(ip_id, inc); if (!ip_id) ip_id = net16_add(ip_id, ((int16_t)inc) < 0 ? -1 : 1); // do not allow zero } + case IPID_SAME: return ip_id; + case IPID_RND: + return (uint16_t)(random()%0xFFFF + 1);; default: return 0; } @@ -929,22 +932,42 @@ static bool runtime_tls_mod(int fake_n, const struct fake_tls_mod_cache *modcach return b; } -uint8_t orig_mod(const struct desync_profile *dp, const t_ctrack *ctrack, struct dissect *dis) +static void rewrite_tcp_flags(uint16_t *flags, uint16_t unset, uint16_t set, const char *what) +{ + if (set || unset) + { + uint16_t fl_new = *flags & ~unset | set; + DLOG("rewrite %s tcp flags 0x%03X => 0x%03X\n", what, *flags, fl_new); + *flags = fl_new; + } +} + +static uint8_t orig_mod(const struct desync_profile *dp, const t_ctrack *ctrack, struct dissect *dis) { uint8_t ttl, ttl_orig; + bool bModded = false; - ttl = (ctrack && ctrack->orig_autottl) ? ctrack->orig_autottl : dis->ip6 ? dp->orig_mod_ttl6 : dp->orig_mod_ttl; - if (ttl && check_orig_mod_interval(dp, ctrack)) + if (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) + ttl = (ctrack && ctrack->orig_autottl) ? ctrack->orig_autottl : dis->ip6 ? dp->orig_mod_ttl6 : dp->orig_mod_ttl; + if (ttl) { - DLOG("rewrite original packet ttl %u => %u\n", ttl_orig, ttl); - rewrite_ttl(dis->ip, dis->ip6, ttl); - return true; + 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); + bModded = true; + } + } + if (dis->tcp) + { + uint16_t flags = get_tcp_flags(dis->tcp); + rewrite_tcp_flags(&flags, dp->orig_tcp_flags_unset, dp->orig_tcp_flags_set, "original"); + apply_tcp_flags(dis->tcp,flags); } } - return false; + return bModded; } static bool orig_send_rewrite( @@ -960,6 +983,7 @@ static bool orig_send_rewrite( 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; k < dp->dup_repeats; k++) { @@ -983,7 +1007,8 @@ static bool tcp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c size_t len; uint16_t ip_id, nmss; struct sockaddr_storage src, dst; - uint8_t ttl_orig, ttl_fake, flags_orig, scale_factor; + uint8_t ttl_orig, ttl_dup, scale_factor; + uint16_t flags_dup; uint32_t *timestamps; bool sack, DF; @@ -994,11 +1019,13 @@ static bool tcp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c if (dp->dup_repeats && check_dup_interval(dp, ctrack)) { - ttl_fake = (ctrack && ctrack->dup_autottl) ? ctrack->dup_autottl : (dis->ip6 ? (dp->dup_ttl6 ? dp->dup_ttl6 : ttl_orig) : (dp->dup_ttl ? dp->dup_ttl : ttl_orig)); + ttl_dup = (ctrack && ctrack->dup_autottl) ? ctrack->dup_autottl : (dis->ip6 ? (dp->dup_ttl6 ? dp->dup_ttl6 : ttl_orig) : (dp->dup_ttl ? dp->dup_ttl : ttl_orig)); - if (dp->dup_fooling_mode) + if (dp->dup_fooling_mode || dp->dup_tcp_flags_set || dp->dup_tcp_flags_unset || (dis->ip && dp->dup_ip_id_mode!=IPID_SAME)) { - flags_orig = *((uint8_t*)dis->tcp + 13); + flags_dup = dis->tcp->th_flags; + rewrite_tcp_flags(&flags_dup, dp->dup_tcp_flags_unset, dp->dup_tcp_flags_set, "dup"); + scale_factor = tcp_find_scale_factor(dis->tcp); timestamps = tcp_find_timestamps(dis->tcp); sack = tcp_has_sack(dis->tcp); @@ -1007,27 +1034,29 @@ static bool tcp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c len = sizeof(pkt); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, - flags_orig, sack, nmss, + flags_dup, sack, nmss, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, - ip_has_df(dis->ip), ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), + ip_has_df(dis->ip), ttl_dup, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), dp->dup_fooling_mode, dp->dup_ts_increment, 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. ttl %u => %u\n", dp->dup_repeats, ttl_orig, ttl_fake); + DLOG("sending %u dups with packet reconstruct. ttl %u => %u\n", dp->dup_repeats, ttl_orig, ttl_dup); // send dups for (k = 0; k < dp->dup_repeats; k++) { if (!rawsend((struct sockaddr *)&dst, fwmark, ifout, pkt, len)) return false; + ip_id = IP4_IP_ID_NEXT(ip_id,dp->dup_ip_id_mode); + if (dis->ip) ((struct ip*)pkt)->ip_id = ip_id; } } else { - if (!orig_send_rewrite(fwmark, ifout, (struct sockaddr *)&dst, ttl_orig, ttl_fake, dp, dis)) + if (!orig_send_rewrite(fwmark, ifout, (struct sockaddr *)&dst, ttl_orig, ttl_dup, dp, dis)) return false; } if (dp->dup_replace) @@ -1071,7 +1100,7 @@ static bool udp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c { ttl_fake = (ctrack && ctrack->dup_autottl) ? ctrack->dup_autottl : (dis->ip6 ? (dp->dup_ttl6 ? dp->dup_ttl6 : ttl_orig) : (dp->dup_ttl ? dp->dup_ttl : ttl_orig)); - if (dp->dup_fooling_mode) + if (dp->dup_fooling_mode || (dis->ip && dp->dup_ip_id_mode!=IPID_SAME)) { ip_id = IP4_IP_ID_FIX(dis->ip,dp->ip_id_mode); @@ -1092,6 +1121,8 @@ static bool udp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c { if (!rawsend((struct sockaddr *)&dst, fwmark, ifout, pkt, len)) return false; + ip_id = IP4_IP_ID_NEXT(ip_id,dp->dup_ip_id_mode); + if (dis->ip) ((struct ip*)pkt)->ip_id = ip_id; } } else @@ -1136,7 +1167,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint struct sockaddr_storage src, dst; uint8_t pkt1[DPI_DESYNC_MAX_FAKE_LEN + 100], pkt2[DPI_DESYNC_MAX_FAKE_LEN + 100], pkt3[DPI_DESYNC_MAX_FAKE_LEN + 100]; size_t pkt1_len, pkt2_len, pkt3_len; - uint8_t ttl_orig, ttl_fake, flags_orig, scale_factor; + uint8_t ttl_orig, ttl_fake, scale_factor; uint32_t *timestamps; bool bSack, DF; uint16_t nmss; @@ -1387,7 +1418,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; ttl_fake = (ctrack_replay && ctrack_replay->desync_autottl) ? ctrack_replay->desync_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); + uint16_t flags_orig = get_tcp_flags(dis->tcp); scale_factor = tcp_find_scale_factor(dis->tcp); bSack = tcp_has_sack(dis->tcp); nmss = tcp_find_mss(dis->tcp); @@ -1486,7 +1517,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint // we do not reassemble http reasm_orig_cancel(ctrack); - forced_wssize_cutoff(ctrack); + if (!dp->wssize_no_forced_cutoff) forced_wssize_cutoff(ctrack); bHaveHost = HttpExtractHost(rdata_payload, rlen_payload, host, sizeof(host)); if (!bHaveHost) @@ -1544,7 +1575,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint DLOG("req retrans : seq interval %u-%u\n", ctrack->req_seq_start, ctrack->req_seq_end); ctrack->req_seq_finalized |= bReqFull; } - if (bReqFull || ReasmIsEmpty(&ctrack->reasm_orig)) forced_wssize_cutoff(ctrack); + if (!dp->wssize_no_forced_cutoff && (bReqFull || ReasmIsEmpty(&ctrack->reasm_orig))) forced_wssize_cutoff(ctrack); if (!ReasmIsEmpty(&ctrack->reasm_orig)) { @@ -1669,6 +1700,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint goto send_orig; } } + ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; + ttl_fake = (ctrack_replay && ctrack_replay->desync_autottl) ? ctrack_replay->desync_autottl : (dis->ip6 ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig)); } } else if (ctrack_replay) @@ -1709,7 +1742,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint DLOG("applying tampering to unknown protocol\n"); } - ttl_fake = (ctrack_replay && ctrack_replay->desync_autottl) ? ctrack_replay->desync_autottl : (dis->ip6 ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig)); if ((l7proto == HTTP) && (dp->hostcase || dp->hostnospace || dp->domcase || dp->methodeol) && HttpFindHost(&phost, dis->data_payload, dis->len_payload)) { if (dp->hostcase) @@ -1912,6 +1944,10 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint seqovl_pos = 0; uint32_t fooling_orig = FOOL_NONE; + + uint16_t flags_fake = flags_orig; + rewrite_tcp_flags(&flags_fake, dp->desync_tcp_flags_unset, dp->desync_tcp_flags_set, "desync"); + switch (dp->desync_mode) { case DESYNC_FAKE_KNOWN: @@ -1952,7 +1988,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint fake_size = fake_item->size - fake_item->offset; pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, htonl(sequence), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_fake, false, 0, htonl(sequence), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, fake_data, fake_size, pkt1, &pkt1_len)) @@ -2110,7 +2146,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint // pkt2: fake_host segment pkt2_len = sizeof(pkt2); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_fake, false, 0, net32_add(dis->tcp->th_seq, pos_host), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, @@ -2405,7 +2441,7 @@ 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, false, 0, 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_fake, false, 0, net32_add(dis->tcp->th_seq, split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, pat + split_pos, dis->len_payload - split_pos, fakeseg2, &fakeseg2_len)) @@ -2448,7 +2484,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (split_pos) { seg_len = sizeof(fakeseg); - 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, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_fake, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, pat, split_pos, fakeseg, &seg_len)) @@ -2517,7 +2553,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } fakeseg_len = sizeof(fakeseg); - 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, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_fake, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, pat, split_pos, fakeseg, &fakeseg_len)) @@ -2596,7 +2632,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (split_pos < dis->len_payload) { fakeseg_len = sizeof(fakeseg); - 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, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_fake, false, 0, net32_add(dis->tcp->th_seq, split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, pat + split_pos, dis->len_payload - split_pos, fakeseg, &fakeseg_len)) @@ -2860,7 +2896,6 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint } 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; DF = ip_has_df(dis->ip); if (dis->len_payload) @@ -3188,6 +3223,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint break; } + ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; ttl_fake = (ctrack_replay && ctrack_replay->desync_autottl) ? ctrack_replay->desync_autottl : (dis->ip6 ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig)); uint32_t fooling_orig = FOOL_NONE; diff --git a/nfq/nfqws.c b/nfq/nfqws.c index 2373f390..1b1bba44 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -1303,6 +1303,63 @@ static bool parse_strlist(char *opt, struct str_list_head *list) return true; } +static bool parse_tcpflags(char *opt, uint16_t *fl) +{ + unsigned int u; + char *e, *p, c; + + if (sscanf(optarg, "0x%X", &u)<=0 && sscanf(optarg, "%u", &u)<=0) + { + *fl=0; + for (p = opt; p; ) + { + if ((e = strchr(p, ','))) + { + c = *e; + *e = 0; + } + + if (!strcasecmp(p, "FIN")) + *fl |= TH_FIN; + else if (!strcasecmp(p, "SYN")) + *fl |= TH_SYN; + else if (!strcasecmp(p, "RST")) + *fl |= TH_RST; + else if (!strcasecmp(p, "PSH") || !strcasecmp(p, "PUSH")) + *fl |= TH_PUSH; + else if (!strcasecmp(p, "ACK")) + *fl |= TH_ACK; + else if (!strcasecmp(p, "URG")) + *fl |= TH_URG; + else if (!strcasecmp(p, "ECE")) + *fl |= 0x40; + else if (!strcasecmp(p, "CWR")) + *fl |= 0x80; + else if (!strcasecmp(p, "AE") || !strcasecmp(p, "AECN") || !strcasecmp(p, "ACCECN")) + *fl |= 0x100; + else if (!strcasecmp(p, "R1")) + *fl |= 0x200; + else if (!strcasecmp(p, "R2")) + *fl |= 0x400; + else if (!strcasecmp(p, "R3")) + *fl |= 0x800; + else + return false; + if (e) *e++ = c; + p = e; + } + + return true; + } + else + { + *fl = u & 0xFFF; + return *fl==u; + } +} + + + static void split_compat(struct desync_profile *dp) { if (!dp->split_count) @@ -1768,11 +1825,14 @@ static void exithelp(void) " --wsize=[:]\t\t\t; set window size. 0 = do not modify. OBSOLETE !\n" " --wssize=[:]\t\t; set window size for server. 0 = do not modify. default scale_factor = 0.\n" " --wssize-cutoff=[n|d|s]N\t\t\t\t; apply server wsize only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n" + " --wssize-forced-cutoff=0|1\t\t\t\t; 1(default)=auto cutoff wssize on known protocol\n" " --synack-split=[syn|synack|acksyn]\t\t\t; perform TCP split handshake : send SYN only, SYN+ACK or ACK+SYN\n" " --orig-ttl=\t\t\t\t\t; set TTL for original packets\n" " --orig-ttl6=\t\t\t\t\t; set ipv6 hop limit for original packets. by default ttl value is used\n" " --orig-autottl=[[:[-]]|-]\t\t; auto ttl mode for both ipv4 and ipv6. default: +%d:%u-%u\n" " --orig-autottl6=[[:[-]]|-]\t\t; overrides --orig-autottl for ipv6 only\n" + " --orig-tcp-flags-set=\t\t; set these tcp flags (flags |= value). value can be int, hex or comma separated list : FIN,SYN,RST,PSH,ACK,URG,ECE,CWR,AE,R1,R2,R3\n" + " --orig-tcp-flags-unset=\t\t; unset these tcp flags (flags &= ~value)\n" " --orig-mod-start=[n|d|s]N\t\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\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\t; duplicate original packets. send N dups before original.\n" @@ -1781,10 +1841,13 @@ static void exithelp(void) " --dup-ttl6=\t\t\t\t\t; set ipv6 hop limit for dups. by default ttl value is used\n" " --dup-autottl=[[:[-]]|-]\t\t; auto ttl mode for both ipv4 and ipv6. default: %d:%u-%u\n" " --dup-autottl6=[[:[-]]|-]\t\t; overrides --dup-autottl for ipv6 only\n" + " --dup-tcp-flags-set=\t\t; set these tcp flags (flags |= value). value can be int, hex or comma separated list : FIN,SYN,RST,PSH,ACK,URG,ECE,CWR,AE,R1,R2,R3\n" + " --dup-tcp-flags-unset=\t\t; unset these tcp flags (flags &= ~value)\n" " --dup-fooling=[,]\t\t\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2\n" " --dup-ts-increment=\t\t\t\t; ts fooling TSval signed increment for dup. default %d\n" " --dup-badseq-increment=\t\t\t; badseq fooling seq signed increment for dup. default %d\n" " --dup-badack-increment=\t\t\t; badseq fooling ackseq signed increment for dup. default %d\n" + " --dup-ip-id=same|zero|seq|rnd\t\t\t\t; ipv4 ip_id mode for dupped packets\n" " --dup-start=[n|d|s]N\t\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\t; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n" " --hostcase\t\t\t\t\t\t; change Host: => host:\n" @@ -1805,6 +1868,8 @@ static void exithelp(void) " --dpi-desync-ttl6=\t\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: %d:%u-%u\n" " --dpi-desync-autottl6=[[:[-]]|-]\t; overrides --dpi-desync-autottl for ipv6 only\n" + " --dpi-desync-tcp-flags-set=\t; set these tcp flags (flags |= value). value can be int, hex or comma separated list : FIN,SYN,RST,PSH,ACK,URG,ECE,CWR,AE,R1,R2,R3\n" + " --dpi-desync-tcp-flags-unset=\t; unset these tcp flags (flags &= ~value)\n" " --dpi-desync-fooling=[,]\t\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2\n" " --dpi-desync-repeats=\t\t\t\t; send every desync packet N times\n" " --dpi-desync-skip-nosni=0|1\t\t\t\t; 1(default)=do not act on ClientHello without SNI\n" @@ -1816,7 +1881,7 @@ static void exithelp(void) " --dpi-desync-split-seqovl-pattern=[+ofs]@|0xHEX ; pattern for the fake part of overlap\n" " --dpi-desync-fakedsplit-pattern=[+ofs]@|0xHEX ; fake pattern for fakedsplit/fakeddisorder\n" " --dpi-desync-fakedsplit-mod=mod[,mod]\t\t\t; mods can be none,altorder=0|1|2|3 + 0|8|16\n" - " --dpi-desync-hostfakesplit-midhost=marker+N|marker-N ; additionally split real hostname at specified marker. must be within host..endhost or won't be splitted.\n" + " --dpi-desync-hostfakesplit-midhost=marker+N|marker-N\t; additionally split real hostname at specified marker. must be within host..endhost or won't be splitted.\n" " --dpi-desync-hostfakesplit-mod=mod[,mod]\t\t; mods can be none,host=,altorder=0|1\n" " --dpi-desync-ipfrag-pos-tcp=<8..%u>\t\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n" " --dpi-desync-ipfrag-pos-udp=<8..%u>\t\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n" @@ -1950,6 +2015,7 @@ enum opt_indices { IDX_WSIZE, IDX_WSSIZE, IDX_WSSIZE_CUTOFF, + IDX_WSSIZE_FORCED_CUTOFF, IDX_SYNACK_SPLIT, IDX_CTRACK_TIMEOUTS, IDX_CTRACK_DISABLE, @@ -1972,23 +2038,30 @@ enum opt_indices { IDX_DUP_TTL6, IDX_DUP_AUTOTTL, IDX_DUP_AUTOTTL6, + IDX_DUP_TCP_FLAGS_SET, + IDX_DUP_TCP_FLAGS_UNSET, IDX_DUP_FOOLING, IDX_DUP_TS_INCREMENT, IDX_DUP_BADSEQ_INCREMENT, IDX_DUP_BADACK_INCREMENT, IDX_DUP_REPLACE, + IDX_DUP_IP_ID, IDX_DUP_START, IDX_DUP_CUTOFF, IDX_ORIG_TTL, IDX_ORIG_TTL6, IDX_ORIG_AUTOTTL, IDX_ORIG_AUTOTTL6, + IDX_ORIG_TCP_FLAGS_SET, + IDX_ORIG_TCP_FLAGS_UNSET, IDX_ORIG_MOD_START, IDX_ORIG_MOD_CUTOFF, IDX_DPI_DESYNC_TTL, IDX_DPI_DESYNC_TTL6, IDX_DPI_DESYNC_AUTOTTL, IDX_DPI_DESYNC_AUTOTTL6, + IDX_DPI_DESYNC_TCP_FLAGS_SET, + IDX_DPI_DESYNC_TCP_FLAGS_UNSET, IDX_DPI_DESYNC_FOOLING, IDX_DPI_DESYNC_REPEATS, IDX_DPI_DESYNC_SKIP_NOSNI, @@ -2083,6 +2156,7 @@ static const struct option long_options[] = { [IDX_WSIZE] = {"wsize", required_argument, 0, 0}, [IDX_WSSIZE] = {"wssize", required_argument, 0, 0}, [IDX_WSSIZE_CUTOFF] = {"wssize-cutoff", required_argument, 0, 0}, + [IDX_WSSIZE_FORCED_CUTOFF] = {"wssize-forced-cutoff", required_argument, 0, 0}, [IDX_SYNACK_SPLIT] = {"synack-split", optional_argument, 0, 0}, [IDX_CTRACK_TIMEOUTS] = {"ctrack-timeouts", required_argument, 0, 0}, [IDX_CTRACK_DISABLE] = {"ctrack-disable", optional_argument, 0, 0}, @@ -2105,23 +2179,30 @@ static const struct option long_options[] = { [IDX_DUP_TTL6] = {"dup-ttl6", required_argument, 0, 0}, [IDX_DUP_AUTOTTL] = {"dup-autottl", optional_argument, 0, 0}, [IDX_DUP_AUTOTTL6] = {"dup-autottl6", optional_argument, 0, 0}, + [IDX_DUP_TCP_FLAGS_SET] = {"dup-tcp-flags-set", optional_argument, 0, 0}, + [IDX_DUP_TCP_FLAGS_UNSET] = {"dup-tcp-flags-unset", optional_argument, 0, 0}, [IDX_DUP_FOOLING] = {"dup-fooling", required_argument, 0, 0}, [IDX_DUP_TS_INCREMENT] = {"dup-ts-increment", 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_IP_ID] = {"dup-ip-id", required_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_AUTOTTL] = {"orig-autottl", optional_argument, 0, 0}, [IDX_ORIG_AUTOTTL6] = {"orig-autottl6", optional_argument, 0, 0}, + [IDX_ORIG_TCP_FLAGS_SET] = {"orig-tcp-flags-set", optional_argument, 0, 0}, + [IDX_ORIG_TCP_FLAGS_UNSET] = {"orig-tcp-flags-unset", optional_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}, [IDX_DPI_DESYNC_AUTOTTL6] = {"dpi-desync-autottl6", optional_argument, 0, 0}, + [IDX_DPI_DESYNC_TCP_FLAGS_SET] = {"dpi-desync-tcp-flags-set", optional_argument, 0, 0}, + [IDX_DPI_DESYNC_TCP_FLAGS_UNSET] = {"dpi-desync-tcp-flags-unset", optional_argument, 0, 0}, [IDX_DPI_DESYNC_FOOLING] = {"dpi-desync-fooling", required_argument, 0, 0}, [IDX_DPI_DESYNC_REPEATS] = {"dpi-desync-repeats", required_argument, 0, 0}, [IDX_DPI_DESYNC_SKIP_NOSNI] = {"dpi-desync-skip-nosni", optional_argument, 0, 0}, @@ -2423,6 +2504,9 @@ int main(int argc, char **argv) exit_clean(1); } break; + case IDX_WSSIZE_FORCED_CUTOFF: + dp->wssize_no_forced_cutoff = !atoi(optarg); + break; case IDX_SYNACK_SPLIT: dp->synack_split = SS_SYN; if (optarg) @@ -2594,6 +2678,20 @@ int main(int argc, char **argv) } params.autottl_present = true; break; + case IDX_DUP_TCP_FLAGS_SET: + if (!parse_tcpflags(optarg, &dp->dup_tcp_flags_set)) + { + DLOG_ERR("invalid tcp flags\n"); + exit_clean(1); + } + break; + case IDX_DUP_TCP_FLAGS_UNSET: + if (!parse_tcpflags(optarg, &dp->dup_tcp_flags_unset)) + { + DLOG_ERR("invalid tcp flags\n"); + exit_clean(1); + } + break; case IDX_DUP_REPLACE: dp->dup_replace = !optarg || atoi(optarg); break; @@ -2639,6 +2737,21 @@ int main(int argc, char **argv) exit_clean(1); } break; + case IDX_DUP_IP_ID: + if (!strcmp(optarg,"zero")) + dp->dup_ip_id_mode = IPID_ZERO; + else if (!strcmp(optarg,"same")) + dp->dup_ip_id_mode = IPID_SAME; + else if (!strcmp(optarg,"seq")) + dp->dup_ip_id_mode = IPID_SEQ; + else if (!strcmp(optarg,"rnd")) + dp->dup_ip_id_mode = IPID_RND; + else + { + DLOG_ERR("invalid dup ip_id mode : %s\n",optarg); + exit_clean(1); + } + break; case IDX_ORIG_TTL: dp->orig_mod_ttl = (uint8_t)atoi(optarg); @@ -2662,6 +2775,20 @@ int main(int argc, char **argv) } params.autottl_present = true; break; + case IDX_ORIG_TCP_FLAGS_SET: + if (!parse_tcpflags(optarg, &dp->orig_tcp_flags_set)) + { + DLOG_ERR("invalid tcp flags\n"); + exit_clean(1); + } + break; + case IDX_ORIG_TCP_FLAGS_UNSET: + if (!parse_tcpflags(optarg, &dp->orig_tcp_flags_unset)) + { + DLOG_ERR("invalid tcp flags\n"); + exit_clean(1); + } + break; case IDX_ORIG_MOD_CUTOFF: if (!parse_cutoff(optarg, &dp->orig_mod_cutoff, &dp->orig_mod_cutoff_mode)) { @@ -2699,6 +2826,20 @@ int main(int argc, char **argv) } params.autottl_present = true; break; + case IDX_DPI_DESYNC_TCP_FLAGS_SET: + if (!parse_tcpflags(optarg, &dp->desync_tcp_flags_set)) + { + DLOG_ERR("invalid tcp flags\n"); + exit_clean(1); + } + break; + case IDX_DPI_DESYNC_TCP_FLAGS_UNSET: + if (!parse_tcpflags(optarg, &dp->desync_tcp_flags_unset)) + { + DLOG_ERR("invalid tcp flags\n"); + exit_clean(1); + } + break; case IDX_DPI_DESYNC_FOOLING: if (!parse_fooling(optarg, &dp->desync_fooling_mode)) { @@ -2776,8 +2917,8 @@ int main(int argc, char **argv) size_t sz = sizeof(buf); load_file_or_exit(optarg, buf, &sz, NULL); fill_pattern(dp->seqovl_pattern, sizeof(dp->seqovl_pattern), buf, sz, 0); + break; } - break; case IDX_DPI_DESYNC_FAKEDSPLIT_PATTERN: { free(dp->fsplit_pattern); @@ -2788,8 +2929,8 @@ int main(int argc, char **argv) } load_file_or_exit(optarg, dp->fsplit_pattern, &dp->fsplit_pattern_size, NULL); dp->fsplit_pattern = realloc(dp->fsplit_pattern, dp->fsplit_pattern_size); + break; } - break; case IDX_DPI_DESYNC_FAKEDSPLIT_MOD: if (!parse_fakedsplit_mod(optarg, &dp->fs_mod)) { diff --git a/nfq/params.c b/nfq/params.c index b5bbede9..5addbe66 100644 --- a/nfq/params.c +++ b/nfq/params.c @@ -237,6 +237,7 @@ void dp_init(struct desync_profile *dp) dp->hostlist_auto_fail_time = HOSTLIST_AUTO_FAIL_TIME_DEFAULT; dp->hostlist_auto_retrans_threshold = HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT; dp->filter_ipv4 = dp->filter_ipv6 = true; + dp->dup_ip_id_mode = IPID_SAME; } bool dp_fake_defaults(struct desync_profile *dp) { diff --git a/nfq/params.h b/nfq/params.h index 26717628..0d30055c 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -97,7 +97,7 @@ struct tcp_mod }; typedef enum {SS_NONE=0,SS_SYN,SS_SYNACK,SS_ACKSYN} t_synack_split; -typedef enum {IPID_SEQ=0,IPID_SEQ_GROUP,IPID_RND,IPID_ZERO} t_ip_id_mode; +typedef enum {IPID_SEQ=0,IPID_SEQ_GROUP,IPID_RND,IPID_ZERO,IPID_SAME} t_ip_id_mode; struct desync_profile { @@ -106,6 +106,7 @@ struct desync_profile uint16_t wsize,wssize; uint8_t wscale,wsscale; char wssize_cutoff_mode; // n - packets, d - data packets, s - relative sequence + bool wssize_no_forced_cutoff; unsigned int wssize_cutoff; t_synack_split synack_split; @@ -131,11 +132,14 @@ struct desync_profile uint32_t dup_fooling_mode; uint32_t dup_ts_increment, dup_badseq_increment, dup_badseq_ack_increment; autottl dup_autottl, dup_autottl6; + uint16_t dup_tcp_flags_set, dup_tcp_flags_unset; + t_ip_id_mode dup_ip_id_mode; 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; autottl orig_autottl, orig_autottl6; + uint16_t orig_tcp_flags_set, orig_tcp_flags_unset; char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence unsigned int desync_start, desync_cutoff; @@ -143,6 +147,7 @@ struct desync_profile autottl desync_autottl, desync_autottl6; uint32_t desync_fooling_mode; uint32_t desync_ts_increment, desync_badseq_increment, desync_badseq_ack_increment; + uint16_t desync_tcp_flags_set, desync_tcp_flags_unset; struct blob_collection_head fake_http,fake_tls,fake_unknown,fake_unknown_udp,fake_quic,fake_wg,fake_dht,fake_discord,fake_stun; uint8_t fake_syndata[FAKE_MAX_TCP],seqovl_pattern[FAKE_MAX_TCP],udplen_pattern[FAKE_MAX_UDP]; @@ -184,7 +189,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) +#define PROFILE_HAS_ORIG_MOD(dp) ((dp)->orig_mod_ttl || (dp)->orig_mod_ttl6 || (dp)->orig_tcp_flags_set || (dp)->orig_tcp_flags_unset) struct desync_profile_list { struct desync_profile dp;