diff --git a/docs/changes.txt b/docs/changes.txt index 2d179db4..8e4076e5 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -490,6 +490,7 @@ nfqws: --dup* nfqws: --orig* nfqws: ipcache of hop count and host names nfqws: --ctrack-disable +nfqws: --synack-split tpws: ipcache of host names nfqws,tpws: set 1024 repeat limit to fakes and dups nfqws,tpws: do more before daemonize diff --git a/docs/readme.md b/docs/readme.md index e9976f3f..925f243f 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -41,6 +41,7 @@ zapret является свободным и open source. - [IPTABLES ДЛЯ NFQWS](#iptables-для-nfqws) - [NFTABLES ДЛЯ NFQWS](#nftables-для-nfqws) - [FLOW OFFLOADING](#flow-offloading) + - [ДУРЕНИЕ СО СТОРОНЫ СЕРВЕРА](#дурение-со-стороны-сервера) - [tpws](#tpws) - [TCP СЕГМЕНТАЦИЯ В TPWS](#tcp-сегментация-в-tpws) - [TLSREC](#tlsrec) @@ -179,6 +180,7 @@ dvtws, собираемый из тех же исходников (см. [док --wsize=[:] ; менять tcp window size на указанный размер в SYN,ACK. если не задан scale_factor, то он не меняется (устарело !) --wssize=[:] ; менять tcp window size на указанный размер в исходящих пакетах. scale_factor по умолчанию 0. (см. conntrack !) --wssize-cutoff=[n|d|s]N ; изменять server window size в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N +--synack-split=[0|1] ; 1 или отсутствие аргумента отсылает SYN,ACK tcp сегмент как раздельные SYN и ACK сегменты (техника для сервера !) --orig-ttl= ; модифицировать TTL оригинального пакета --orig-ttl6= ; модифицировать ipv6 hop limit оригинальных пакетов. если не указано, используется значение --orig-ttl --orig-autottl=[[:[-]]] ; режим auto ttl для ipv4 и ipv6. по умолчанию: +5:3-64. delta=0 отключает функцию @@ -884,6 +886,29 @@ iptables target `FLOWOFFLOAD` - это проприетарное изобрет Управление offload в nftables реализовано в базовом ядре linux без патчей. nftables - единственный способ включения offload на классическом Linux. +### ДУРЕНИЕ СО СТОРОНЫ СЕРВЕРА + +Это тоже возможно. +nfqws рассчитан на атаку со стороны клиента, поэтому он распознает прямой и обратный трафик на основании роли в установлении tcp соединения. +Если проходит SYN, то source IP - это клиент. Если проходит SYN,ACK , то source IP - это сервер. +Для UDP клиентом считается source IP первого прошедшего пакета по двум связкам ip-port. +На сервере трафиком клиента будет считаться принятый трафик, а трафиком сервера - исходящий. + +`--wssize` работает в любом случае, он может использоваться как на клиенте, так и на сервере. +Остальные техники работают только если nfqws считает трафик трафиком клиента. +Поэтому для их применения по исходящему с сервера трафику conntrack нужно выключить параметром `--ctrack-disable`. +Если пакет не найден в conntrack, по нему идет работа как по пакету клиента. + +Большинство протоколов опознаваться не будет, потому что система их опознавания рассчитана содержание пакетов от клиента. +Нужно использовать `--dpi-desync-any-protocol` с ограничителями connbytes или start/cutoff. + +Техника `synack-split` позволяет разбить tcp сегмент SYN,ACK на отдельные части с SYN и с ACK. +В ответ на это клиент шлет SYN,ACK , что обычно характеризует сервер. +У некоторых DPI от этого может ломаться алгоритм, и они перестают блокировать запрещенный контент. + +Перенаправление трафика обычно идет по номеру source портов и направлению original. +original - это исходящий с системы трафик, reply - входящий. + ## tpws diff --git a/nfq/desync.c b/nfq/desync.c index e5efc003..c0c602ab 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -1110,6 +1110,9 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint uint32_t desync_fwmark = fwmark | params.desync_fwmark; extract_endpoints(dis->ip, dis->ip6, dis->tcp, NULL, &src, &dst); + timestamps = tcp_find_timestamps(dis->tcp); + DF = ip_has_df(dis->ip); + ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; if (replay) { @@ -1193,15 +1196,11 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (bReverse) { - if (ctrack) + if (ctrack && !ctrack->incoming_ttl) { - ttl_orig = dis->ip ? dis->ip->ip_ttl : dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim; - if (!ctrack->incoming_ttl) - { - 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); - } + 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); } // process reply packets for auto hostlist mode @@ -1281,6 +1280,29 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } } + if (dp->synack_split && tcp_synack_segment(dis->tcp)) + { + dis->tcp->th_flags &= ~TH_ACK; + tcp_fix_checksum(dis->tcp,dis->transport_len, dis->ip, dis->ip6); + + DLOG("sending split SYNACK : SYN\n"); + if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , dis->data_pkt, dis->len_pkt)) + goto send_orig; + + pkt1_len = sizeof(pkt1); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_ACK, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, SCALE_NONE, timestamps, + DF,ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), + FOOL_NONE,0,0,NULL, 0, pkt1, &pkt1_len)) + { + DLOG_ERR("cannot prepare split SYNACK ACK part\n"); + goto send_orig; + } + DLOG("sending split SYNACK : ACK\n"); + if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + goto send_orig; + return VERDICT_DROP; + } + // start and cutoff limiters if (!process_desync_interval(dp, ctrack)) goto send_orig; } // !replay @@ -1289,10 +1311,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint 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); bSack = tcp_has_sack(dis->tcp); nmss = tcp_find_mss(dis->tcp); - DF = ip_has_df(dis->ip); if (!replay) { diff --git a/nfq/nfqws.c b/nfq/nfqws.c index 94552011..e640275e 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -1516,6 +1516,7 @@ 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" + " --synack-split=[0|1]\t\t\t\t; 1 or no arguments sends SYN,ACK tcp segment as separate SYN and ACK segments\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" @@ -1678,6 +1679,7 @@ enum opt_indices { IDX_WSIZE, IDX_WSSIZE, IDX_WSSIZE_CUTOFF, + IDX_SYNACK_SPLIT, IDX_CTRACK_TIMEOUTS, IDX_CTRACK_DISABLE, IDX_IPCACHE_LIFETIME, @@ -1798,6 +1800,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_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}, [IDX_IPCACHE_LIFETIME] = {"ipcache-lifetime", required_argument, 0, 0}, @@ -2099,6 +2102,9 @@ int main(int argc, char **argv) exit_clean(1); } break; + case IDX_SYNACK_SPLIT: + dp->synack_split = !optarg || atoi(optarg); + break; case IDX_CTRACK_TIMEOUTS: if (sscanf(optarg, "%u:%u:%u:%u", ¶ms.ctrack_t_syn, ¶ms.ctrack_t_est, ¶ms.ctrack_t_fin, ¶ms.ctrack_t_udp)<3) { diff --git a/nfq/params.h b/nfq/params.h index d57c07a9..305f5feb 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -84,6 +84,8 @@ struct desync_profile char wssize_cutoff_mode; // n - packets, d - data packets, s - relative sequence unsigned int wssize_cutoff; + bool synack_split; + bool hostcase, hostnospace, domcase, methodeol; char hostspell[4]; enum dpi_desync_mode desync_mode0,desync_mode,desync_mode2;