From 483658485ec218d9845c519b16cb21c79f284cfb Mon Sep 17 00:00:00 2001 From: bol-van Date: Mon, 22 Mar 2021 12:02:55 +0300 Subject: [PATCH] openbsd: discovered how to apply divert-packet to outgoing only --- docs/bsd.eng.txt | 29 ++++++++++++++++------------- docs/bsd.txt | 27 ++++++++++++++------------- nfq/conntrack.h | 2 ++ nfq/desync.c | 8 -------- nfq/nfqws.c | 6 ------ nfq/params.h | 8 +------- 6 files changed, 33 insertions(+), 47 deletions(-) diff --git a/docs/bsd.eng.txt b/docs/bsd.eng.txt index def5fdd..3e012fc 100644 --- a/docs/bsd.eng.txt +++ b/docs/bsd.eng.txt @@ -170,7 +170,8 @@ dvtws for all traffic: /etc/pf.conf ------------ -pass out quick on em0 proto tcp to port {80,443} divert-packet port 989 +pass in quick on em0 proto tcp from port {80,443} no state +pass out quick on em0 proto tcp to port {80,443} divert-packet port 989 ------------ pfctl -f /etc/pf.conf ./dvtws --port=989 --dpi-desync=split2 @@ -179,32 +180,34 @@ dwtws only for table zapret with the exception of table nozapret : /etc/pf.conf ------------ +set limit table-entries 2000000 table file "/opt/zapret/ipset/zapret-ip.txt" table file "/opt/zapret/ipset/zapret-ip-user.txt" table file "/opt/zapret/ipset/zapret-ip-exclude.txt" -pass out quick on em0 inet proto tcp to port {80,443} -pass out quick on em0 inet proto tcp to port {80,443} divert-packet port 989 -pass out quick on em0 inet proto tcp to port {80,443} divert-packet port 989 +pass out quick on em0 inet proto tcp to port {80,443} +pass in quick on em0 inet proto tcp from port {80,443} no state +pass out quick on em0 inet proto tcp to port {80,443} divert-packet port 989 no state +pass in quick on em0 inet proto tcp from port {80,443} no state +pass out quick on em0 inet proto tcp to port {80,443} divert-packet port 989 no state table file "/opt/zapret/ipset/zapret-ip6.txt" table file "/opt/zapret/ipset/zapret-ip-user6.txt" table file "/opt/zapret/ipset/zapret-ip-exclude6.txt" -pass out quick on em0 inet6 proto tcp to port {80,443} -pass out quick on em0 inet6 proto tcp to port {80,443} divert-packet port 989 -pass out quick on em0 inet6 proto tcp to port {80,443} divert-packet port 989 +pass out quick on em0 inet6 proto tcp to port {80,443} +pass in quick on em0 inet6 proto tcp from port {80,443} no state +pass out quick on em0 inet6 proto tcp to port {80,443} divert-packet port 989 no state +pass in quick on em0 inet6 proto tcp from port {80,443} no state +pass out quick on em0 inet6 proto tcp to port {80,443} divert-packet port 989 no state ------------ pfctl -f /etc/pf.conf ./dvtws --port=989 --dpi-desync=split2 +divert-packet automatically adds the reverse rule. By default also incoming traffic will be passwed to dvtws. +This is highly undesired because it is waste of cpu resources and speed limiter. +The trick with "no state" and "in" rules allows to bypass auto reverse rule. dvtws in OpenBSD sends all fakes through a divert socket because raw sockets have critical artificial limitations. Looks like pf automatically prevent reinsertion of diverted frames. Loop problem does not exist. -Sadly PF auto applies return rule to divert-packet. -Not only outgoing packets go through dvtws but also incoming. -This adds great unneeded overhead that will be the most noticable on http/https downloads. -I could not figure out how to disable this feature. -Thats why you are encouraged to use table filters with your personal blocked site lists. - OpenBSD forcibly recomputes tcp checksum after divert. Thats why most likely dpi-desync-fooling=badsum will not work. dvtws will warn if you specify this parameter. diff --git a/docs/bsd.txt b/docs/bsd.txt index ed66eac..3ab4019 100644 --- a/docs/bsd.txt +++ b/docs/bsd.txt @@ -188,7 +188,8 @@ dvtws для всего трафика : /etc/pf.conf ------------ -pass out quick on em0 proto tcp to port {80,443} divert-packet port 989 +pass in quick on em0 proto tcp from port {80,443} no state +pass out quick on em0 proto tcp to port {80,443} divert-packet port 989 no state ------------ pfctl -f /etc/pf.conf ./dvtws --port=989 --dpi-desync=split2 @@ -201,29 +202,29 @@ set limit table-entries 2000000 table file "/opt/zapret/ipset/zapret-ip.txt" table file "/opt/zapret/ipset/zapret-ip-user.txt" table file "/opt/zapret/ipset/zapret-ip-exclude.txt" -pass out quick on em0 inet proto tcp to port {80,443} -pass out quick on em0 inet proto tcp to port {80,443} divert-packet port 989 -pass out quick on em0 inet proto tcp to port {80,443} divert-packet port 989 +pass out quick on em0 inet proto tcp to port {80,443} +pass in quick on em0 inet proto tcp from port {80,443} no state +pass out quick on em0 inet proto tcp to port {80,443} divert-packet port 989 no state +pass in quick on em0 inet proto tcp from port {80,443} no state +pass out quick on em0 inet proto tcp to port {80,443} divert-packet port 989 no state table file "/opt/zapret/ipset/zapret-ip6.txt" table file "/opt/zapret/ipset/zapret-ip-user6.txt" table file "/opt/zapret/ipset/zapret-ip-exclude6.txt" -pass out quick on em0 inet6 proto tcp to port {80,443} -pass out quick on em0 inet6 proto tcp to port {80,443} divert-packet port 989 -pass out quick on em0 inet6 proto tcp to port {80,443} divert-packet port 989 +pass out quick on em0 inet6 proto tcp to port {80,443} +pass in quick on em0 inet6 proto tcp from port {80,443} no state +pass out quick on em0 inet6 proto tcp to port {80,443} divert-packet port 989 no state +pass in quick on em0 inet6 proto tcp from port {80,443} no state +pass out quick on em0 inet6 proto tcp to port {80,443} divert-packet port 989 no state ------------ pfctl -f /etc/pf.conf ./dvtws --port=989 --dpi-desync=split2 +divert-packet автоматически вносит обратное правило для перенаправления. +Трюк с no state и in правилом позволяет обойти эту проблему, чтобы напрасно не гнать массивный трафик через dvtws. В OpenBSD dvtws все фейки отсылает через divert socket, поскольку эта возможность через raw sockets заблокирована. Видимо pf автоматически предотвращает повторный заворот diverted фреймов, поэтому проблемы зацикливания нет. -К сожалению, в PF присутствует "удобная" функция, которая автоматически применяет к правилу divert-packet -обратный трафик. Через divert пойдет все соединение, а не только исходящие пакеты. -Это добавит огромный ненужный overhead по процессингу входящих пакетов в dvtws, который будет наиболее заметен -на скачивании по http/https. Мне не удалось понять как этого избежать. -Поэтому использование фильтр-таблиц крайне рекомендовано ! - OpenBSD принудительно пересчитывает tcp checksum после divert, поэтому скорее всего dpi-desync-fooling=badsum у вас не заработает. При использовании этого параметра dvtws предупредит о возможной проблеме. diff --git a/nfq/conntrack.h b/nfq/conntrack.h index efeb9b8..d062a77 100644 --- a/nfq/conntrack.h +++ b/nfq/conntrack.h @@ -55,6 +55,8 @@ typedef struct uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none bool b_cutoff; // mark for deletion + + bool b_wssize_cutoff, b_desync_cutoff; } t_ctrack; // use separate pools for ipv4 and ipv6 to save RAM. otherwise could use union key diff --git a/nfq/desync.c b/nfq/desync.c index 69cea4e..2f1180e 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -107,11 +107,7 @@ static void maybe_cutoff(t_ctrack *ctrack) ctrack->b_wssize_cutoff |= params.wssize_cutoff && ctrack->pcounter_orig>=params.wssize_cutoff; ctrack->b_desync_cutoff |= params.desync_cutoff && ctrack->pcounter_orig>=params.desync_cutoff; - // do not cut off in OpenBSD. It looks like it's not possible to divert-packet only outgoing part of the connection - // It's better to destinguish outgoings using conntrack -#ifndef __OpenBSD__ ctrack->b_cutoff |= (!params.wssize || ctrack->b_wssize_cutoff) && !params.desync_cutoff; -#endif } } static void wssize_cutoff(t_ctrack *ctrack) @@ -122,11 +118,7 @@ static void wssize_cutoff(t_ctrack *ctrack) maybe_cutoff(ctrack); } } -#ifdef __OpenBSD__ -#define CONNTRACK_REQUIRED true -#else #define CONNTRACK_REQUIRED (params.wssize || params.desync_cutoff) -#endif // result : true - drop original packet, false = dont drop packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, size_t len_tcp, uint8_t *data_payload, size_t len_payload) { diff --git a/nfq/nfqws.c b/nfq/nfqws.c index e12499a..ef281bc 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -38,13 +38,7 @@ #define CTRACK_T_SYN 60 #define CTRACK_T_FIN 60 -#ifdef __OpenBSD__ -// It looks like it's not possible to divert-packet only outgoing part of the connection -// It's better to destinguish outgoings using conntrack. Do not purge conntrack entry too early -#define CTRACK_T_EST 7200 -#else #define CTRACK_T_EST 300 -#endif struct params_s params; diff --git a/nfq/params.h b/nfq/params.h index e38f753..0f7bb8d 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -11,16 +11,9 @@ #include #include -#if defined(__OpenBSD__) || defined (__APPLE__) -// divert-packet also diverts return traffic. sockets will experience high load -#define Q_RCVBUF (256*1024) // in bytes -#define Q_SNDBUF (256*1024) // in bytes -#define RAW_SNDBUF (64*1024) // in bytes -#else #define Q_RCVBUF (128*1024) // in bytes #define Q_SNDBUF (64*1024) // in bytes #define RAW_SNDBUF (64*1024) // in bytes -#endif #define Q_MAXLEN 1024 // in packets @@ -40,6 +33,7 @@ struct params_s enum dpi_desync_mode desync_mode,desync_mode2; bool desync_retrans,desync_skip_nosni,desync_any_proto; int desync_repeats,desync_split_pos; + unsigned int desync_cutoff; uint8_t desync_ttl; uint8_t desync_tcp_fooling_mode; uint32_t desync_fwmark; // unused in BSD