From 5cc888cd2ca5cc00fcd0a0fcff4f6e7835661247 Mon Sep 17 00:00:00 2001 From: bol-van Date: Sat, 3 May 2025 12:01:49 +0300 Subject: [PATCH] nfqws: autottl cache, --dup-autottl, --orig-autottl --- docs/changes.txt | 6 +- nfq/conntrack.h | 3 +- nfq/darkmagic.c | 25 +++--- nfq/darkmagic.h | 7 +- nfq/desync.c | 146 +++++++++++++++++++++----------- nfq/desync.h | 2 +- nfq/helpers.h | 2 + nfq/nfqws.c | 136 +++++++++++++++++++++-------- nfq/packet_queue.c | 16 ++-- nfq/packet_queue.h | 4 +- nfq/params.h | 18 ++++ nfq/pools.c | 207 +++++++++++++++++++++++++++++++++++++++++++++ nfq/pools.h | 40 +++++++++ 13 files changed, 501 insertions(+), 111 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 7eef2eba..1a198606 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -482,7 +482,11 @@ nfqws: multiple mods for multiple TLS fakes init.d: remove 50-discord blockcheck: use tpws --fix-seg on linux for multiple splits -v70.7 +v71 nfqws,tpws: debug tls version, alpn, ech nfqws: --dpi-desync-fake-tls=! means default tls fake +nfqws: --dup* +nfqws: --orig* +nfqws: autottl cache +nfqws: autottl disable path length check diff --git a/nfq/conntrack.h b/nfq/conntrack.h index 564d2cf1..ca9b4492 100644 --- a/nfq/conntrack.h +++ b/nfq/conntrack.h @@ -77,7 +77,8 @@ typedef struct bool req_seq_present,req_seq_finalized,req_seq_abandoned; uint32_t req_seq_start,req_seq_end; // sequence interval of the request (to track retransmissions) - uint8_t incoming_ttl, autottl; + uint8_t incoming_ttl, desync_autottl, orig_autottl, dup_autottl; + bool b_autottl_discovered; bool b_cutoff; // mark for deletion bool b_wssize_cutoff, b_desync_cutoff, b_dup_cutoff, b_orig_mod_cutoff; diff --git a/nfq/darkmagic.c b/nfq/darkmagic.c index 14534ca4..ad74c405 100644 --- a/nfq/darkmagic.c +++ b/nfq/darkmagic.c @@ -1832,17 +1832,15 @@ bool rawsend_queue(struct rawpacket_tailhead *q) } -// return guessed fake ttl value. 0 means unsuccessfull, should not perform autottl fooling -// ttl = TTL of incoming packet -uint8_t autottl_guess(uint8_t ttl, const autottl *attl) +uint8_t hop_count_guess(uint8_t ttl) { - uint8_t orig, path, fake; - int d; - // 18.65.168.125 ( cloudfront ) 255 // 157.254.246.178 128 // 1.1.1.1 64 // guess original ttl. consider path lengths less than 32 hops + + uint8_t orig; + if (ttl>223) orig=255; else if (ttl<128 && ttl>96) @@ -1852,15 +1850,22 @@ uint8_t autottl_guess(uint8_t ttl, const autottl *attl) else return 0; - path = orig - ttl; + return orig - ttl; +} +// return guessed fake ttl value. 0 means unsuccessfull, should not perform autottl fooling +uint8_t autottl_eval(uint8_t hop_count, const autottl *attl) +{ + uint8_t fake; + int d; - d = (int)path + attl->delta; + d = (int)hop_count + attl->delta; if (dmin) fake=attl->min; else if (d>attl->max) fake=attl->max; else fake=(uint8_t)d; - if (attl->delta<0 && fake>=path || attl->delta>=0 && fakedelta<0 && fake>=hop_count || attl->delta>=0 && fakereasm_offset && (split_pos-reasm_offset)incoming_ttl) - { - autottl *attl = bIpv6 ? &ctrack->dp->desync_autottl6 : &ctrack->dp->desync_autottl; if (AUTOTTL_ENABLED(*attl)) { - ctrack->autottl = autottl_guess(ctrack->incoming_ttl, attl); - if (ctrack->autottl) - DLOG("autottl: guessed %u\n",ctrack->autottl); + uint8_t autottl = autottl_eval(hop_count, attl); + if (autottl) + DLOG("%s autottl: guessed %u\n",attl_kind,autottl); else - DLOG("autottl: could not guess\n"); + DLOG("%s autottl: could not guess\n",attl_kind); + return autottl; } else - ctrack->autottl = 0; + return 0; +} +static void autottl_discover(t_ctrack *ctrack, const struct in_addr *a4, const struct in6_addr *a6, const char *iface) +{ + if (ctrack && params.autottl_present && !ctrack->b_autottl_discovered) + { + ip_cache_item *ipc = ipcacheTouch(¶ms.ipcache,a4,a6,iface); + if (!ipc) + { + DLOG_ERR("ipcache: out of memory\n"); + return; + } + if (ctrack->incoming_ttl) + { + uint8_t old_hops = ipc->hops; + ipc->hops = hop_count_guess(ctrack->incoming_ttl); + DLOG("incoming hops guessed %u\n", ipc->hops); + if (old_hops!=ipc->hops) + DLOG("updated autottl cache\n"); + } + else if (ipc->hops) + DLOG("using cached hops %u\n", ipc->hops); + else + DLOG("hop count unknown\n"); + if (ipc->hops) + { + ctrack->desync_autottl = autottl_guess(a6 ? &ctrack->dp->desync_autottl6 : &ctrack->dp->desync_autottl, ipc->hops, "desync"); + ctrack->orig_autottl = autottl_guess(a6 ? &ctrack->dp->orig_autottl6 : &ctrack->dp->orig_autottl, ipc->hops, "orig"); + ctrack->dup_autottl = autottl_guess(a6 ? &ctrack->dp->dup_autottl6 : &ctrack->dp->dup_autottl, ipc->hops, "dup"); + } + ctrack->b_autottl_discovered = true; + } +} +static void autottl_rediscover(t_ctrack *ctrack, const struct in_addr *a4, const struct in6_addr *a6, const char *iface) +{ + if (ctrack) + { + ctrack->b_autottl_discovered = false; + autottl_discover(ctrack,a4,a6,iface); } } @@ -837,8 +873,8 @@ static bool runtime_tls_mod(int fake_n,const struct fake_tls_mod_cache *modcache 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; + + 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)) { ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; @@ -893,14 +929,13 @@ static bool tcp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c bool sack,DF; extract_endpoints(dis->ip, dis->ip6, dis->tcp, NULL, &src, &dst); + ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; verdict_tcp_csum_fix(verdict, dis->tcp, dis->transport_len, dis->ip, dis->ip6); 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; + 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) { @@ -910,20 +945,19 @@ static bool tcp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c sack = tcp_has_sack(dis->tcp); nmss = tcp_find_mss(dis->tcp); ip_id = IP4_IP_ID_FIX(dis->ip); - DF = ip_has_df(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, - DF,ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), + ip_has_df(dis->ip),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); + DLOG("sending %u dups with packet reconstruct. ttl %u => %u\n", dp->dup_repeats, ttl_orig, ttl_fake); // send dups for (k=0;kdup_repeats;k++) @@ -941,7 +975,7 @@ static bool tcp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c DLOG("NOT sending original because of dup_replace\n"); else { - DLOG("sending original\n", dp->dup_repeats); + DLOG("sending original ttl %u\n", ttl_orig); if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , dis->data_pkt, dis->len_pkt)) return false; } @@ -949,7 +983,7 @@ static bool tcp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c } if (bForceSend) { - DLOG("sending original\n", dp->dup_repeats); + DLOG("sending original ttl %u\n", ttl_orig); if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , dis->data_pkt, dis->len_pkt)) return false; return true; @@ -968,18 +1002,15 @@ static bool udp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c uint16_t ip_id; struct sockaddr_storage src, dst; uint8_t ttl_orig,ttl_fake; - bool DF; extract_endpoints(dis->ip, dis->ip6, NULL, dis->udp, &src, &dst); + ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6); 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; - DF = ip_has_df(dis->ip); + 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) { @@ -987,7 +1018,7 @@ static bool udp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c len = sizeof(pkt); if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, - DF,ttl_fake, IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), + ip_has_df(dis->ip),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)) { @@ -995,7 +1026,7 @@ static bool udp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c return false; } - DLOG("sending %u dups with packet reconstruct\n", dp->dup_repeats); + DLOG("sending %u dups with packet reconstruct. ttl %u => %u\n", dp->dup_repeats, ttl_orig, ttl_fake); // send dups for (k=0;kdup_repeats;k++) @@ -1013,7 +1044,7 @@ static bool udp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c DLOG("NOT sending original because of dup_replace\n"); else { - DLOG("sending original\n", dp->dup_repeats); + DLOG("sending original ttl %u\n", ttl_orig); if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , dis->data_pkt, dis->len_pkt)) return false; } @@ -1021,7 +1052,7 @@ static bool udp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c } if (bForceSend) { - DLOG("sending original\n", dp->dup_repeats); + DLOG("sending original ttl %u\n", ttl_orig); if (!rawsend((struct sockaddr *)&dst, fwmark, ifout , dis->data_pkt, dis->len_pkt)) return false; return true; @@ -1030,7 +1061,7 @@ static bool udp_orig_send(uint8_t verdict, uint32_t fwmark, const char *ifout, c 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) +static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifin, const char *ifout, struct dissect *dis) { uint8_t verdict=VERDICT_PASS; @@ -1121,10 +1152,10 @@ 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; if (!ctrack->incoming_ttl) { - DLOG("incoming TTL %u\n",ttl_orig); ctrack->incoming_ttl = ttl_orig; + DLOG("incoming TTL %u\n",ttl_orig); + autottl_rediscover(ctrack,dis->ip ? &dis->ip->ip_src : NULL,dis->ip6 ? &dis->ip6->ip6_src : NULL , ifin); } - if (!ctrack->autottl) autottl_discover(ctrack,!!dis->ip6); } // process reply packets for auto hostlist mode @@ -1178,6 +1209,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint return verdict; // nothing to do. do not waste cpu } + autottl_discover(ctrack,dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , ifout); + if (orig_mod(dp,ctrack,dis)) // ttl can change ! verdict = VERDICT_MODIFY; @@ -1207,7 +1240,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } // !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)); + 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); scale_factor = tcp_find_scale_factor(dis->tcp); timestamps = tcp_find_timestamps(dis->tcp); @@ -1368,7 +1401,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (!ReasmIsEmpty(&ctrack->reasm_orig)) { verdict_tcp_csum_fix(verdict, dis->tcp, dis->transport_len, dis->ip, dis->ip6); - if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload)) + if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload)) { DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed)); } @@ -1455,10 +1488,14 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (dp!=dp_prev) { DLOG("desync profile changed by revealed l7 protocol or hostname !\n"); - // rediscover autottl - autottl_discover(ctrack_replay,!!dis->ip6); + autottl_rediscover(ctrack_replay,dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , ifout); // re-evaluate start/cutoff limiters - if (!replay) + if (replay) + { + if (orig_mod(dp,ctrack_replay,dis)) // ttl can change ! + verdict = VERDICT_MODIFY; + } + else { maybe_cutoff(ctrack, IPPROTO_TCP); if (orig_mod(dp,ctrack,dis)) // ttl can change ! @@ -1509,7 +1546,7 @@ 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->autottl) ? ctrack_replay->autottl : (dis->ip6 ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig)); + 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) @@ -2207,7 +2244,7 @@ static bool quic_reasm_cancel(t_ctrack *ctrack, const char *reason) } } -static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifout, struct dissect *dis) +static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifin, const char *ifout, struct dissect *dis) { uint8_t verdict=VERDICT_PASS; @@ -2294,12 +2331,14 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint { DLOG("incoming TTL %u\n",ttl_orig); ctrack->incoming_ttl = ttl_orig; + autottl_rediscover(ctrack,dis->ip ? &dis->ip->ip_src : NULL,dis->ip6 ? &dis->ip6->ip6_src : NULL , ifin); } - if (!ctrack->autottl) autottl_discover(ctrack,!!dis->ip6); } return verdict; // nothing to do. do not waste cpu } + autottl_discover(ctrack,dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , ifout); + if (orig_mod(dp,ctrack,dis)) // ttl can change ! verdict = VERDICT_MODIFY; @@ -2384,7 +2423,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint if (!ReasmIsEmpty(&ctrack->reasm_orig)) { verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6); - if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload)) + if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload)) { DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed)); } @@ -2433,7 +2472,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint } } verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6); - if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload)) + if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload)) { DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed)); } @@ -2554,10 +2593,14 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint if (dp!=dp_prev) { DLOG("desync profile changed by revealed l7 protocol or hostname !\n"); - // rediscover autottl - autottl_discover(ctrack_replay,!!dis->ip6); + autottl_rediscover(ctrack_replay,dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , ifout); // re-evaluate start/cutoff limiters - if (!replay) + if (replay) + { + if (orig_mod(dp,ctrack_replay,dis)) // ttl can change ! + verdict = VERDICT_MODIFY; + } + else { maybe_cutoff(ctrack, IPPROTO_UDP); if (orig_mod(dp,ctrack,dis)) // ttl can change ! @@ -2619,7 +2662,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint break; } - 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)); + 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; @@ -2832,7 +2875,7 @@ static void packet_debug(bool replay, const struct dissect *dis) } -static uint8_t dpi_desync_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt) +static uint8_t dpi_desync_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifin, const char *ifout, uint8_t *data_pkt, size_t *len_pkt) { struct dissect dis; uint8_t verdict = VERDICT_PASS; @@ -2846,14 +2889,14 @@ static uint8_t dpi_desync_packet_play(bool replay, size_t reasm_offset, uint32_t case IPPROTO_TCP: if (dis.tcp) { - verdict = dpi_desync_tcp_packet_play(replay, reasm_offset, fwmark, ifout, &dis); + verdict = dpi_desync_tcp_packet_play(replay, reasm_offset, fwmark, ifin, ifout, &dis); verdict_tcp_csum_fix(verdict, dis.tcp, dis.transport_len, dis.ip, dis.ip6); } break; case IPPROTO_UDP: if (dis.udp) { - verdict = dpi_desync_udp_packet_play(replay, reasm_offset, fwmark, ifout, &dis); + verdict = dpi_desync_udp_packet_play(replay, reasm_offset, fwmark, ifin, ifout, &dis); verdict_udp_csum_fix(verdict, dis.udp, dis.transport_len, dis.ip, dis.ip6); } break; @@ -2862,9 +2905,10 @@ static uint8_t dpi_desync_packet_play(bool replay, size_t reasm_offset, uint32_t } return verdict; } -uint8_t dpi_desync_packet(uint32_t fwmark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt) +uint8_t dpi_desync_packet(uint32_t fwmark, const char *ifin, const char *ifout, uint8_t *data_pkt, size_t *len_pkt) { - return dpi_desync_packet_play(false, 0, fwmark, ifout, data_pkt, len_pkt); + ipcachePurgeRateLimited(¶ms.ipcache, params.autottl_cache_lifetime); + return dpi_desync_packet_play(false, 0, fwmark, ifin, ifout, data_pkt, len_pkt); } @@ -2878,7 +2922,7 @@ static bool replay_queue(struct rawpacket_tailhead *q) for (i=1,offset=0 ; (rp=rawpacket_dequeue(q)) ; offset+=rp->len_payload, rawpacket_free(rp), i++) { DLOG("REPLAYING delayed packet #%u offset %zu\n",i,offset); - uint8_t verdict = dpi_desync_packet_play(true, offset, rp->fwmark, rp->ifout, rp->packet, &rp->len); + uint8_t verdict = dpi_desync_packet_play(true, offset, rp->fwmark, rp->ifin, rp->ifout, rp->packet, &rp->len); switch(verdict & VERDICT_MASK) { case VERDICT_MODIFY: diff --git a/nfq/desync.h b/nfq/desync.h index a9b4cf42..82f8f780 100644 --- a/nfq/desync.h +++ b/nfq/desync.h @@ -52,4 +52,4 @@ bool desync_valid_second_stage(enum dpi_desync_mode mode); bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode); bool desync_valid_second_stage_udp(enum dpi_desync_mode mode); -uint8_t dpi_desync_packet(uint32_t fwmark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt); +uint8_t dpi_desync_packet(uint32_t fwmark, const char *ifin, const char *ifout, uint8_t *data_pkt, size_t *len_pkt); diff --git a/nfq/helpers.h b/nfq/helpers.h index f6d7a990..9f4aa2dd 100644 --- a/nfq/helpers.h +++ b/nfq/helpers.h @@ -9,6 +9,8 @@ #include #include +#define UNARY_PLUS(v) (v>0 ? "+" : "") + // this saves memory. sockaddr_storage is larger than required. it can be 128 bytes. sockaddr_in6 is 28 bytes. typedef union { diff --git a/nfq/nfqws.c b/nfq/nfqws.c index 5fc35231..87667845 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -99,7 +99,11 @@ static void onusr2(int sig) printf("\nDESYNC PROFILE %d\n",dpl->dp.n); HostFailPoolDump(dpl->dp.hostlist_auto_fail_counters); } - + if (params.autottl_present) + { + printf("\nAUTOTTL IP CACHE\n"); + ipcachePrint(¶ms.ipcache); + } printf("\n"); } @@ -111,7 +115,7 @@ static void pre_desync(void) } -static uint8_t processPacketData(uint32_t *mark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt) +static uint8_t processPacketData(uint32_t *mark, const char *ifin, const char *ifout, uint8_t *data_pkt, size_t *len_pkt) { #ifdef __linux__ if (*mark & params.desync_fwmark) @@ -120,7 +124,7 @@ static uint8_t processPacketData(uint32_t *mark, const char *ifout, uint8_t *dat return VERDICT_PASS; } #endif - return dpi_desync_packet(*mark, ifout, data_pkt, len_pkt); + return dpi_desync_packet(*mark, ifin, ifout, data_pkt, len_pkt); } @@ -154,8 +158,8 @@ static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_da size_t len; struct nfqnl_msg_packet_hdr *ph; uint8_t *data; - uint32_t ifidx; - char ifout[IFNAMSIZ+1]; + uint32_t ifidx_out, ifidx_in; + char ifout[IFNAMSIZ], ifin[IFNAMSIZ]; ph = nfq_get_msg_packet_hdr(nfa); id = ph ? ntohl(ph->packet_id) : 0; @@ -163,27 +167,20 @@ static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_da uint32_t mark = nfq_get_nfmark(nfa); ilen = nfq_get_payload(nfa, &data); + ifidx_out = nfq_get_outdev(nfa); *ifout=0; - if (params.bind_fix4 || params.bind_fix6) - { - char ifin[IFNAMSIZ+1]; - uint32_t ifidx_in; + if (ifidx_out) if_indextoname(ifidx_out,ifout); - ifidx = nfq_get_outdev(nfa); - if (ifidx) if_indextoname(ifidx,ifout); - *ifin=0; - ifidx_in = nfq_get_indev(nfa); - if (ifidx_in) if_indextoname(ifidx_in,ifin); + ifidx_in = nfq_get_indev(nfa); + *ifin=0; + if (ifidx_in) if_indextoname(ifidx_in,ifin); + + DLOG("packet: id=%d len=%d mark=%08X ifin=%s(%u) ifout=%s(%u)\n", id, ilen, mark, ifin, ifidx_in, ifout, ifidx_out); - DLOG("packet: id=%d len=%d mark=%08X ifin=%s(%u) ifout=%s(%u)\n", id, ilen, mark, ifin, ifidx_in, ifout, ifidx); - } - else - // save some syscalls - DLOG("packet: id=%d len=%d mark=%08X\n", id, ilen, mark); if (ilen >= 0) { len = ilen; - uint8_t verdict = processPacketData(&mark, ifout, data, &len); + uint8_t verdict = processPacketData(&mark, ifin, ifout, data, &len); switch(verdict & VERDICT_MASK) { case VERDICT_MODIFY: @@ -437,7 +434,7 @@ static int dvt_main(void) ReloadCheck(); DLOG("packet: id=%u len=%zu\n", id, len); - verdict = processPacketData(&mark, NULL, buf, &len); + verdict = processPacketData(&mark, NULL, NULL, buf, &len); switch (verdict & VERDICT_MASK) { case VERDICT_PASS: @@ -484,7 +481,7 @@ static int win_main(const char *windivert_filter) uint8_t packet[16384]; uint32_t mark; WINDIVERT_ADDRESS wa; - char ifout[22]; + char ifname[IFNAMSIZ]; pre_desync(); @@ -550,8 +547,8 @@ static int win_main(const char *windivert_filter) ReloadCheck(); - *ifout=0; - if (wa.Outbound) snprintf(ifout,sizeof(ifout),"%u.%u", wa.Network.IfIdx, wa.Network.SubIfIdx); + *ifname=0; + snprintf(ifname,sizeof(ifname),"%u.%u", wa.Network.IfIdx, wa.Network.SubIfIdx); DLOG("packet: id=%u len=%zu %s IPv6=%u IPChecksum=%u TCPChecksum=%u UDPChecksum=%u IfIdx=%u.%u\n", id, len, wa.Outbound ? "outbound" : "inbound", wa.IPv6, wa.IPChecksum, wa.TCPChecksum, wa.UDPChecksum, wa.Network.IfIdx, wa.Network.SubIfIdx); if (wa.Impostor) { @@ -567,7 +564,7 @@ static int win_main(const char *windivert_filter) { mark=0; // pseudo interface id IfIdx.SubIfIdx - verdict = processPacketData(&mark, ifout, packet, &len); + verdict = processPacketData(&mark, ifname, ifname, packet, &len); } switch (verdict & VERDICT_MASK) { @@ -690,11 +687,14 @@ static void load_file_or_exit(const char *filename, void *buf, size_t *size) } } -static bool parse_autottl(const char *s, autottl *t) +static bool parse_autottl(const char *s, autottl *t, int8_t def_delta, uint8_t def_min, uint8_t def_max) { bool neg=true; unsigned int delta,min,max; - AUTOTTL_SET_DEFAULT(*t); + + t->delta = def_delta; + t->min = def_min; + t->max = def_max; if (s) { max = t->max; @@ -1416,6 +1416,7 @@ static void exithelp(void) " --bind-fix6\t\t\t\t\t; apply outgoing interface selection fix for generated ipv6 packets\n" #endif " --ctrack-timeouts=S:E:F[:U]\t\t\t; internal conntrack timeouts for TCP SYN, ESTABLISHED, FIN stages, UDP timeout. default %u:%u:%u:%u\n" + " --autottl-cache-lifetime=\t\t\t; time in seconds to keep cached hop count (default %u)\n" #ifdef __CYGWIN__ "\nWINDIVERT FILTER:\n" " --wf-iface=[.]\t\t\t; numeric network interface and subinterface indexes\n" @@ -1456,12 +1457,16 @@ static void exithelp(void) " --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-autottl=[[:[-]]]\t; auto ttl mode for both ipv4 and ipv6. default: +%d:%u-%u\n" + " --orig-autottl6=[[:[-]]]\t; overrides --orig-autottl for ipv6 only\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-replace=[0|1]\t\t\t\t; 1 or no argument means do not send original, only dups\n" " --dup-ttl=\t\t\t\t; set TTL for dups\n" " --dup-ttl6=\t\t\t\t; set ipv6 hop limit for dups. by default ttl value is used\n" + " --dup-autottl=[[:[-]]]\t; auto ttl mode for both ipv4 and ipv6. default: %d:%u-%u\n" + " --dup-autottl6=[[:[-]]]\t; overrides --dup-autottl for ipv6 only\n" " --dup-fooling=[,]\t\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack hopbyhop hopbyhop2\n" " --dup-badseq-increment=\t\t; badseq fooling seq signed increment for dup. default %d\n" " --dup-badack-increment=\t\t; badseq fooling ackseq signed increment for dup. default %d\n" @@ -1515,12 +1520,15 @@ static void exithelp(void) " --dpi-desync-start=[n|d|s]N\t\t\t; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n" " --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, + AUTOTTL_CACHE_LIFETIME, HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT, HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT, + AUTOTTL_DEFAULT_ORIG_DELTA,AUTOTTL_DEFAULT_ORIG_MIN,AUTOTTL_DEFAULT_ORIG_MAX, + AUTOTTL_DEFAULT_DUP_DELTA,AUTOTTL_DEFAULT_DUP_MIN,AUTOTTL_DEFAULT_DUP_MAX, BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT, #if defined(__linux__) || defined(SO_USER_COOKIE) DPI_DESYNC_FWMARK_DEFAULT,DPI_DESYNC_FWMARK_DEFAULT, #endif - AUTOTTL_DEFAULT_DELTA,AUTOTTL_DEFAULT_MIN,AUTOTTL_DEFAULT_MAX, + AUTOTTL_DEFAULT_DESYNC_DELTA,AUTOTTL_DEFAULT_DESYNC_MIN,AUTOTTL_DEFAULT_DESYNC_MAX, DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_UDP_DEFAULT, DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_TCP_DEFAULT, BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT, @@ -1610,6 +1618,7 @@ enum opt_indices { IDX_WSSIZE, IDX_WSSIZE_CUTOFF, IDX_CTRACK_TIMEOUTS, + IDX_AUTOTTL_CACHE_LIFETIME, IDX_HOSTCASE, IDX_HOSTSPELL, IDX_HOSTNOSPACE, @@ -1624,6 +1633,8 @@ enum opt_indices { IDX_DUP, IDX_DUP_TTL, IDX_DUP_TTL6, + IDX_DUP_AUTOTTL, + IDX_DUP_AUTOTTL6, IDX_DUP_FOOLING, IDX_DUP_BADSEQ_INCREMENT, IDX_DUP_BADACK_INCREMENT, @@ -1632,6 +1643,8 @@ enum opt_indices { IDX_DUP_CUTOFF, IDX_ORIG_TTL, IDX_ORIG_TTL6, + IDX_ORIG_AUTOTTL, + IDX_ORIG_AUTOTTL6, IDX_ORIG_MOD_START, IDX_ORIG_MOD_CUTOFF, IDX_DPI_DESYNC_TTL, @@ -1723,6 +1736,7 @@ static const struct option long_options[] = { [IDX_WSSIZE] = {"wssize", required_argument, 0, 0}, [IDX_WSSIZE_CUTOFF] = {"wssize-cutoff", required_argument, 0, 0}, [IDX_CTRACK_TIMEOUTS] = {"ctrack-timeouts", required_argument, 0, 0}, + [IDX_AUTOTTL_CACHE_LIFETIME] = {"autottl-cache-lifetime", required_argument, 0, 0}, [IDX_HOSTCASE] = {"hostcase", no_argument, 0, 0}, [IDX_HOSTSPELL] = {"hostspell", required_argument, 0, 0}, [IDX_HOSTNOSPACE] = {"hostnospace", no_argument, 0, 0}, @@ -1737,6 +1751,8 @@ static const struct option long_options[] = { [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_AUTOTTL] = {"dup-autottl", optional_argument, 0, 0}, + [IDX_DUP_AUTOTTL6] = {"dup-autottl6", optional_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}, @@ -1745,6 +1761,8 @@ static const struct option long_options[] = { [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_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}, @@ -1872,7 +1890,8 @@ int main(int argc, char **argv) params.ctrack_t_est = CTRACK_T_EST; params.ctrack_t_fin = CTRACK_T_FIN; params.ctrack_t_udp = CTRACK_T_UDP; - + params.autottl_cache_lifetime = AUTOTTL_CACHE_LIFETIME; + LIST_INIT(¶ms.hostlists); LIST_INIT(¶ms.ipsets); @@ -2025,6 +2044,13 @@ int main(int argc, char **argv) exit_clean(1); } break; + case IDX_AUTOTTL_CACHE_LIFETIME: + if (sscanf(optarg, "%u", ¶ms.autottl_cache_lifetime)!=1) + { + DLOG_ERR("invalid autottl-cache-lifetime value\n"); + exit_clean(1); + } + break; case IDX_HOSTCASE: dp->hostcase = true; break; @@ -2130,6 +2156,22 @@ int main(int argc, char **argv) case IDX_DUP_TTL6: dp->dup_ttl6 = (uint8_t)atoi(optarg); break; + case IDX_DUP_AUTOTTL: + if (!parse_autottl(optarg, &dp->dup_autottl, AUTOTTL_DEFAULT_DUP_DELTA, AUTOTTL_DEFAULT_DUP_MIN, AUTOTTL_DEFAULT_DUP_MAX)) + { + DLOG_ERR("dup-autottl value error\n"); + exit_clean(1); + } + params.autottl_present=true; + break; + case IDX_DUP_AUTOTTL6: + if (!parse_autottl(optarg, &dp->dup_autottl6, AUTOTTL_DEFAULT_DUP_DELTA, AUTOTTL_DEFAULT_DUP_MIN, AUTOTTL_DEFAULT_DUP_MAX)) + { + DLOG_ERR("dup-autottl6 value error\n"); + exit_clean(1); + } + params.autottl_present=true; + break; case IDX_DUP_REPLACE: dp->dup_replace = optarg ? !!atoi(optarg) : true; break; @@ -2175,6 +2217,22 @@ int main(int argc, char **argv) case IDX_ORIG_TTL6: dp->orig_mod_ttl6 = (uint8_t)atoi(optarg); break; + case IDX_ORIG_AUTOTTL: + if (!parse_autottl(optarg, &dp->orig_autottl, AUTOTTL_DEFAULT_ORIG_DELTA, AUTOTTL_DEFAULT_ORIG_MIN, AUTOTTL_DEFAULT_ORIG_MAX)) + { + DLOG_ERR("orig-autottl value error\n"); + exit_clean(1); + } + params.autottl_present=true; + break; + case IDX_ORIG_AUTOTTL6: + if (!parse_autottl(optarg, &dp->orig_autottl6, AUTOTTL_DEFAULT_ORIG_DELTA, AUTOTTL_DEFAULT_ORIG_MIN, AUTOTTL_DEFAULT_ORIG_MAX)) + { + DLOG_ERR("orig-autottl6 value error\n"); + exit_clean(1); + } + params.autottl_present=true; + break; case IDX_ORIG_MOD_CUTOFF: if (!parse_cutoff(optarg, &dp->orig_mod_cutoff, &dp->orig_mod_cutoff_mode)) { @@ -2197,18 +2255,20 @@ int main(int argc, char **argv) dp->desync_ttl6 = (uint8_t)atoi(optarg); break; case IDX_DPI_DESYNC_AUTOTTL: - if (!parse_autottl(optarg, &dp->desync_autottl)) + if (!parse_autottl(optarg, &dp->desync_autottl, AUTOTTL_DEFAULT_DESYNC_DELTA, AUTOTTL_DEFAULT_DESYNC_MIN, AUTOTTL_DEFAULT_DESYNC_MAX)) { DLOG_ERR("dpi-desync-autottl value error\n"); exit_clean(1); } + params.autottl_present=true; break; case IDX_DPI_DESYNC_AUTOTTL6: - if (!parse_autottl(optarg, &dp->desync_autottl6)) + if (!parse_autottl(optarg, &dp->desync_autottl6, AUTOTTL_DEFAULT_DESYNC_DELTA, AUTOTTL_DEFAULT_DESYNC_MIN, AUTOTTL_DEFAULT_DESYNC_MAX)) { DLOG_ERR("dpi-desync-autottl6 value error\n"); exit_clean(1); } + params.autottl_present=true; break; case IDX_DPI_DESYNC_FOOLING: if (!parse_fooling(optarg,&dp->desync_fooling_mode)) @@ -2789,10 +2849,20 @@ int main(int argc, char **argv) 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->orig_autottl6)) dp->orig_autottl6 = dp->orig_autottl; + if (!AUTOTTL_ENABLED(dp->dup_autottl6)) dp->dup_autottl6 = dp->dup_autottl; if (AUTOTTL_ENABLED(dp->desync_autottl)) - DLOG("profile %d autottl ipv4 %d:%u-%u\n",dp->n,dp->desync_autottl.delta,dp->desync_autottl.min,dp->desync_autottl.max); + DLOG("profile %d desync autottl ipv4 %s%d:%u-%u\n",dp->n,UNARY_PLUS(dp->desync_autottl.delta),dp->desync_autottl.delta,dp->desync_autottl.min,dp->desync_autottl.max); if (AUTOTTL_ENABLED(dp->desync_autottl6)) - DLOG("profile %d autottl ipv6 %d:%u-%u\n",dp->n,dp->desync_autottl6.delta,dp->desync_autottl6.min,dp->desync_autottl6.max); + DLOG("profile %d desync autottl ipv6 %s%d:%u-%u\n",dp->n,UNARY_PLUS(dp->desync_autottl6.delta),dp->desync_autottl6.delta,dp->desync_autottl6.min,dp->desync_autottl6.max); + if (AUTOTTL_ENABLED(dp->orig_autottl)) + DLOG("profile %d orig autottl ipv4 %s%d:%u-%u\n",dp->n,UNARY_PLUS(dp->orig_autottl.delta),dp->orig_autottl.delta,dp->orig_autottl.min,dp->orig_autottl.max); + if (AUTOTTL_ENABLED(dp->orig_autottl6)) + DLOG("profile %d orig autottl ipv6 %s%d:%u-%u\n",dp->n,UNARY_PLUS(dp->orig_autottl6.delta),dp->orig_autottl6.delta,dp->orig_autottl6.min,dp->orig_autottl6.max); + if (AUTOTTL_ENABLED(dp->dup_autottl)) + DLOG("profile %d dup autottl ipv4 %s%d:%u-%u\n",dp->n,UNARY_PLUS(dp->dup_autottl.delta),dp->dup_autottl.delta,dp->dup_autottl.min,dp->dup_autottl.max); + if (AUTOTTL_ENABLED(dp->dup_autottl6)) + DLOG("profile %d dup autottl ipv6 %s%d:%u-%u\n",dp->n,UNARY_PLUS(dp->dup_autottl6.delta),dp->dup_autottl6.delta,dp->dup_autottl6.min,dp->dup_autottl6.max); split_compat(dp); if (!dp_fake_defaults(dp)) { diff --git a/nfq/packet_queue.c b/nfq/packet_queue.c index ff5ee73b..3c63b1cd 100644 --- a/nfq/packet_queue.c +++ b/nfq/packet_queue.c @@ -1,5 +1,6 @@ #include #include +#include #include "packet_queue.h" @@ -25,7 +26,7 @@ void rawpacket_queue_destroy(struct rawpacket_tailhead *q) while((rp = rawpacket_dequeue(q))) rawpacket_free(rp); } -struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len,size_t len_payload) +struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload) { struct rawpacket *rp = malloc(sizeof(struct rawpacket)); if (!rp) return NULL; @@ -39,13 +40,14 @@ struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sock rp->dst = *dst; rp->fwmark = fwmark; - if (ifout) - { - strncpy(rp->ifout,ifout,sizeof(rp->ifout)); - rp->ifout[sizeof(rp->ifout)-1]=0; - } + if (ifin) + snprintf(rp->ifin,sizeof(rp->ifin),"%s",ifin); else - rp->ifout[0]=0; + *rp->ifin = 0; + if (ifout) + snprintf(rp->ifout,sizeof(rp->ifout),"%s",ifout); + else + *rp->ifout = 0; memcpy(rp->packet,data,len); rp->len=len; rp->len_payload=len_payload; diff --git a/nfq/packet_queue.h b/nfq/packet_queue.h index fb57798e..6d2c81c8 100644 --- a/nfq/packet_queue.h +++ b/nfq/packet_queue.h @@ -9,7 +9,7 @@ struct rawpacket { struct sockaddr_storage dst; - char ifout[IFNAMSIZ+1]; + char ifin[IFNAMSIZ], ifout[IFNAMSIZ]; uint32_t fwmark; size_t len, len_payload; uint8_t *packet; @@ -21,6 +21,6 @@ void rawpacket_queue_init(struct rawpacket_tailhead *q); void rawpacket_queue_destroy(struct rawpacket_tailhead *q); bool rawpacket_queue_empty(const struct rawpacket_tailhead *q); unsigned int rawpacket_queue_count(const struct rawpacket_tailhead *q); -struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len,size_t len_payload); +struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload); struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q); void rawpacket_free(struct rawpacket *rp); diff --git a/nfq/params.h b/nfq/params.h index 5c578800..0ce21e60 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -36,6 +36,18 @@ #define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60 #define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3 +#define AUTOTTL_CACHE_LIFETIME 86400 +#define AUTOTTL_DEFAULT_DESYNC_DELTA -1 +#define AUTOTTL_DEFAULT_DESYNC_MIN 3 +#define AUTOTTL_DEFAULT_DESYNC_MAX 20 +#define AUTOTTL_DEFAULT_ORIG_DELTA +5 +#define AUTOTTL_DEFAULT_ORIG_MIN 3 +#define AUTOTTL_DEFAULT_ORIG_MAX 64 +#define AUTOTTL_DEFAULT_DUP_DELTA -1 +#define AUTOTTL_DEFAULT_DUP_MIN 3 +#define AUTOTTL_DEFAULT_DUP_MAX 64 + + #define MAX_SPLITS 64 #define FAKE_TLS_MOD_SAVE_MASK 0x0F @@ -89,10 +101,12 @@ struct desync_profile uint8_t dup_ttl, dup_ttl6; uint32_t dup_fooling_mode; uint32_t dup_badseq_increment, dup_badseq_ack_increment; + autottl dup_autottl, dup_autottl6; 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; char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence unsigned int desync_start, desync_cutoff; @@ -182,6 +196,10 @@ struct params_s unsigned int ctrack_t_syn, ctrack_t_est, ctrack_t_fin, ctrack_t_udp; t_conntrack conntrack; + + unsigned int autottl_cache_lifetime; + bool autottl_present; + ip_cache ipcache; }; extern struct params_s params; diff --git a/nfq/pools.c b/nfq/pools.c index c4ac8fec..407e324e 100644 --- a/nfq/pools.c +++ b/nfq/pools.c @@ -579,3 +579,210 @@ bool blob_collection_empty(const struct blob_collection_head *head) { return !LIST_FIRST(head); } + + + +static void ipcache_item_touch(ip_cache_item *item) +{ + time(&item->last); +} +static void ipcache_item_init(ip_cache_item *item) +{ + ipcache_item_touch(item); + item->hops = 0; +} + +static void ipcache4Destroy(ip_cache4 **ipcache) +{ + ip_cache4 *elem, *tmp; + HASH_ITER(hh, *ipcache, elem, tmp) + { + HASH_DEL(*ipcache, elem); + free(elem); + } +} +static void ipcache4Key(ip4if *key, const struct in_addr *a, const char *iface) +{ + memset(key,0,sizeof(*key)); // make sure everything is zero + key->addr = *a; + if (iface) snprintf(key->iface,sizeof(key->iface),"%s",iface); +} +static ip_cache4 *ipcache4Find(ip_cache4 *ipcache, const struct in_addr *a, const char *iface) +{ + ip_cache4 *entry; + struct ip4if key; + + ipcache4Key(&key,a,iface); + HASH_FIND(hh, ipcache, &key, sizeof(key), entry); + return entry; +} +static ip_cache4 *ipcache4Add(ip_cache4 **ipcache, const struct in_addr *a, const char *iface) +{ + // avoid dups + ip_cache4 *entry = ipcache4Find(*ipcache,a,iface); + if (entry) return entry; // already included + + entry = malloc(sizeof(ip_cache4)); + if (!entry) return NULL; + ipcache4Key(&entry->key,a,iface); + + oom = false; + HASH_ADD(hh, *ipcache, key, sizeof(entry->key), entry); + if (oom) { free(entry); return NULL; } + + ipcache_item_init(&entry->data); + + return entry; +} +static void ipcache4Print(ip_cache4 *ipcache) +{ + char s_ip[16]; + time_t now; + ip_cache4 *ipc, *tmp; + + time(&now); + HASH_ITER(hh, ipcache , ipc, tmp) + { + *s_ip=0; + inet_ntop(AF_INET, &ipc->key.addr, s_ip, sizeof(s_ip)); + printf("%s iface=%s : hops %u now=last+%llu\n", s_ip, ipc->key.iface, ipc->data.hops, (unsigned long long)(now-ipc->data.last)); + } +} + +static void ipcache6Destroy(ip_cache6 **ipcache) +{ + ip_cache6 *elem, *tmp; + HASH_ITER(hh, *ipcache, elem, tmp) + { + HASH_DEL(*ipcache, elem); + free(elem); + } +} +static void ipcache6Key(ip6if *key, const struct in6_addr *a, const char *iface) +{ + memset(key,0,sizeof(*key)); // make sure everything is zero + key->addr = *a; + if (iface) snprintf(key->iface,sizeof(key->iface),"%s",iface); +} +static ip_cache6 *ipcache6Find(ip_cache6 *ipcache, const struct in6_addr *a, const char *iface) +{ + ip_cache6 *entry; + ip6if key; + + ipcache6Key(&key,a,iface); + HASH_FIND(hh, ipcache, &key, sizeof(key), entry); + return entry; +} +static ip_cache6 *ipcache6Add(ip_cache6 **ipcache, const struct in6_addr *a, const char *iface) +{ + // avoid dups + ip_cache6 *entry = ipcache6Find(*ipcache,a,iface); + if (entry) return entry; // already included + + entry = malloc(sizeof(ip_cache6)); + if (!entry) return NULL; + ipcache6Key(&entry->key,a,iface); + + oom = false; + HASH_ADD(hh, *ipcache, key, sizeof(entry->key), entry); + if (oom) { free(entry); return NULL; } + + ipcache_item_init(&entry->data); + + return entry; +} +static void ipcache6Print(ip_cache6 *ipcache) +{ + char s_ip[40]; + time_t now; + ip_cache6 *ipc, *tmp; + + time(&now); + HASH_ITER(hh, ipcache , ipc, tmp) + { + *s_ip=0; + inet_ntop(AF_INET6, &ipc->key.addr, s_ip, sizeof(s_ip)); + printf("%s iface=%s : hops %u now=last+%llu\n", s_ip, ipc->key.iface, ipc->data.hops, (unsigned long long)(now-ipc->data.last)); + } +} + +void ipcacheDestroy(ip_cache *ipcache) +{ + ipcache4Destroy(&ipcache->ipcache4); + ipcache6Destroy(&ipcache->ipcache6); +} +void ipcachePrint(ip_cache *ipcache) +{ + ipcache4Print(ipcache->ipcache4); + ipcache6Print(ipcache->ipcache6); +} + +ip_cache_item *ipcacheTouch(ip_cache *ipcache, const struct in_addr *a4, const struct in6_addr *a6, const char *iface) +{ + ip_cache4 *ipcache4; + ip_cache6 *ipcache6; + if (a4) + { + if ((ipcache4 = ipcache4Add(&ipcache->ipcache4,a4,iface))) + { + ipcache_item_touch(&ipcache4->data); + return &ipcache4->data; + } + } + else if (a6) + { + if ((ipcache6 = ipcache6Add(&ipcache->ipcache6,a6,iface))) + { + ipcache_item_touch(&ipcache6->data); + return &ipcache6->data; + } + } + return NULL; +} + +static void ipcache4_purge(ip_cache4 **ipcache, time_t lifetime) +{ + ip_cache4 *elem, *tmp; + time_t now = time(NULL); + HASH_ITER(hh, *ipcache, elem, tmp) + { + if (now >= (elem->data.last + lifetime)) + { + HASH_DEL(*ipcache, elem); + free(elem); + } + } +} +static void ipcache6_purge(ip_cache6 **ipcache, time_t lifetime) +{ + ip_cache6 *elem, *tmp; + time_t now = time(NULL); + HASH_ITER(hh, *ipcache, elem, tmp) + { + if (now >= (elem->data.last + lifetime)) + { + HASH_DEL(*ipcache, elem); + free(elem); + } + } +} +static void ipcache_purge(ip_cache *ipcache, time_t lifetime) +{ + if (lifetime) // 0 = no expire + { + ipcache4_purge(&ipcache->ipcache4, lifetime); + ipcache6_purge(&ipcache->ipcache6, lifetime); + } +} +static time_t ipcache_purge_prev=0; +void ipcachePurgeRateLimited(ip_cache *ipcache, time_t lifetime) +{ + time_t now = time(NULL); + // do not purge too often to save resources + if (ipcache_purge_prev != now) + { + ipcache_purge(ipcache, lifetime); + ipcache_purge_prev = now; + } +} + diff --git a/nfq/pools.h b/nfq/pools.h index 034ccb23..74a9fd84 100644 --- a/nfq/pools.h +++ b/nfq/pools.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "helpers.h" @@ -161,3 +162,42 @@ struct blob_item *blob_collection_add(struct blob_collection_head *head); struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve); void blob_collection_destroy(struct blob_collection_head *head); bool blob_collection_empty(const struct blob_collection_head *head); + + +typedef struct ip4if +{ + char iface[IFNAMSIZ]; + struct in_addr addr; +} ip4if; +typedef struct ip6if +{ + char iface[IFNAMSIZ]; + struct in6_addr addr; +} ip6if; +typedef struct ip_cache_item +{ + time_t last; + uint8_t hops; +} ip_cache_item; +typedef struct ip_cache4 +{ + ip4if key; + ip_cache_item data; + UT_hash_handle hh; /* makes this structure hashable */ +} ip_cache4; +typedef struct ip_cache6 +{ + ip6if key; + ip_cache_item data; + UT_hash_handle hh; /* makes this structure hashable */ +} ip_cache6; +typedef struct ip_cache +{ + ip_cache4 *ipcache4; + ip_cache6 *ipcache6; +} ip_cache; + +ip_cache_item *ipcacheTouch(ip_cache *ipcache, const struct in_addr *a4, const struct in6_addr *a6, const char *iface); +void ipcachePurgeRateLimited(ip_cache *ipcache, time_t lifetime); +void ipcacheDestroy(ip_cache *ipcache); +void ipcachePrint(ip_cache *ipcache);