{"id":13546962,"url":"https://github.com/bol-van/zapret","last_synced_at":"2026-02-24T09:24:18.524Z","repository":{"id":37385138,"uuid":"51757458","full_name":"bol-van/zapret","owner":"bol-van","description":"DPI bypass multi platform","archived":false,"fork":false,"pushed_at":"2026-02-22T14:33:14.000Z","size":20424,"stargazers_count":14424,"open_issues_count":9,"forks_count":995,"subscribers_count":181,"default_branch":"master","last_synced_at":"2026-02-22T19:33:26.485Z","etag":null,"topics":["anti-dpi","censorship-circumvention","freebsd","linux","macos","openbsd","openwrt","russian","windows"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bol-van.png","metadata":{"files":{"readme":"docs/readme.en.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2016-02-15T13:30:50.000Z","updated_at":"2026-02-22T18:26:41.000Z","dependencies_parsed_at":"2023-10-14T16:03:39.517Z","dependency_job_id":"337fb6ee-ed9b-4d6a-bf06-eb221f54a0b9","html_url":"https://github.com/bol-van/zapret","commit_stats":{"total_commits":1195,"total_committers":22,"mean_commits":54.31818181818182,"dds":"0.22677824267782432","last_synced_commit":"e42e0513c5143a58886517c13ab89a64acae0422"},"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"purl":"pkg:github/bol-van/zapret","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bol-van%2Fzapret","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bol-van%2Fzapret/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bol-van%2Fzapret/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bol-van%2Fzapret/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bol-van","download_url":"https://codeload.github.com/bol-van/zapret/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bol-van%2Fzapret/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29777833,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-24T04:54:30.205Z","status":"ssl_error","status_checked_at":"2026-02-24T04:53:58.628Z","response_time":75,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anti-dpi","censorship-circumvention","freebsd","linux","macos","openbsd","openwrt","russian","windows"],"created_at":"2024-08-01T12:00:48.796Z","updated_at":"2026-02-24T09:24:18.501Z","avatar_url":"https://github.com/bol-van.png","language":"C","funding_links":[],"categories":["C","Repos"],"sub_categories":[],"readme":"# SCAMMER WARNING\n\nThis software is free and open source under [MIT license](./LICENSE.txt).\nIf anyone demands you to download this software only from their webpage, telegram channel, forces you to delete links, videos, makes copyright claims, you are dealing with scammers.\nHowever, [donations](#donations) are welcome.\n\n# Multilanguage/Мультиязычный README\n___\n[![en](https://img.shields.io/badge/lang-en-red.svg)](https://github.com/bol-van/zapret/tree/master/docs/readme.en.md)\n[![ru](https://img.shields.io/badge/lang-ru-green.svg)](https://github.com/bol-van/zapret/tree/master/docs/readme.md)\n\n***\n\n- [What is it for](#what-is-it-for)\n- [How it works](#how-it-works)\n- [How to put this into practice in the linux system](#how-to-put-this-into-practice-in-the-linux-system)\n- [When it will not work](#when-it-will-not-work)\n- [nfqws](#nfqws)\n  - [DPI desync attack](#dpi-desync-attack)\n  - [Fakes](#fakes)\n  - [Fake mods](#fake-mods)\n  - [TCP segmentation](#tcp-segmentation)\n  - [Sequence numbers overlap](#sequence-numbers-overlap)\n  - [IP_ID assignment](#ip_id-assignment)\n  - [ipv6 specific modes](#ipv6-specific-modes)\n  - [Original modding](#original-modding)\n  - [Duplicates](#duplicates)\n  - [Server reply reaction](#server-reply-reaction)\n  - [SYNDATA mode](#syndata-mode)\n  - [DPI desync combos](#dpi-desync-combos)\n  - [IP cache](#ip-cache)\n  - [CONNTRACK](#conntrack)\n  - [Reassemble](#reassemble)\n  - [UDP support](#udp-support)\n  - [IP fragmentation](#ip-fragmentation)\n  - [Multiple strategies](#multiple-strategies)\n  - [WIFI filtering](#wifi-filtering)\n  - [Virtual machines](#virtual-machines)\n  - [IPTABLES for nfqws](#iptables-for-nfqws)\n  - [NFTABLES for nfqws](#nftables-for-nfqws)\n  - [Flow offloading](#flow-offloading)\n  - [Server side fooling](#server-side-fooling)\n- [tpws](#tpws)\n  - [TCP segmentation in tpws](#tcp-segmentation-in-tpws)\n  - [TLSREC](#tlsrec)\n  - [MSS](#mss)\n  - [Other tamper options](#other-tamper-options)\n  - [Supplementary options](#supplementary-options)\n  - [Multiple strategies](#multiple-strategies-1)\n  - [IPTABLES for tpws](#iptables-for-tpws)\n  - [NFTABLES for tpws](#nftables-for-tpws)\n- [Ways to get a list of blocked IP](#ways-to-get-a-list-of-blocked-ip)\n- [Domain name filtering](#domain-name-filtering)\n- [**autohostlist** mode](#autohostlist-mode)\n- [Choosing parameters](#choosing-parameters)\n- [Screwing to the firewall control system or your launch system](#screwing-to-the-firewall-control-system-or-your-launch-system)\n- [Installation](#installation)\n  - [Checking ISP](#checking-isp)\n  - [desktop linux system](#desktop-linux-system)\n  - [OpenWRT](#openwrt)\n  - [Android](#android)\n  - [FreeBSD, OpenBSD, MacOS](#freebsd-openbsd-macos)\n  - [Windows (WSL)](#windows-wsl)\n  - [Other devices](#other-devices)\n- [Donations](#donations)\n***\n\n## What is it for\n\nA stand-alone (without 3rd party servers) DPI circumvention tool.\nMay allow to bypass http(s) website blocking or speed shaping, resist signature tcp/udp protocol discovery.\n\nThe project is mainly aimed at the Russian audience.\nSome features of the project are russian reality specific (such as getting list of sites\nblocked by Roskomnadzor), but most others are common.\n\nMainly OpenWRT targeted but also supports traditional Linux, FreeBSD, OpenBSD, Windows, partially MacOS.\n\nMost features are also supported in Windows.\n\n## How it works\n\nIn the simplest case you are dealing with passive DPI. Passive DPI can read passthrough traffic,\ninject its own packets, but cannot drop packets.\n\nIf the request is prohibited the passive DPI will inject its own RST packet and optionally http redirect packet.\n\nIf fake packets from DPI are only sent to client, you can use iptables commands to drop them if you can write\ncorrect filter rules. This requires manual in-deep traffic analysis and tuning for specific ISP.\n\nThis is how we bypass the consequences of a ban trigger.\n\nIf the passive DPI sends an RST packet also to the server, there is nothing you can do about it.\nYour task is to prevent ban trigger from firing up. Iptables alone will not work.\nThis project is aimed at preventing the ban rather than eliminating its consequences.\n\nTo do that send what DPI does not expect and what breaks its algorithm of recognizing requests and blocking them.\n\nSome DPIs cannot recognize the http request if it is divided into TCP segments.\nFor example, a request of the form `GET / HTTP / 1.1 \\ r \\ nHost: kinozal.tv ......`\nwe send in 2 parts: first go `GET`, then `/ HTTP / 1.1 \\ r \\ nHost: kinozal.tv .....`.\n\nOther DPIs stumble when the `Host:` header is written in another case: for example, `host:`.\n\nSometimes work adding extra space after the method: `GET /` =\u003e `GET  /`\nor adding a dot at the end of the host name: `Host: kinozal.tv.`\n\nThere is also more advanced magic for bypassing DPI at the packet level.\n\n## How to put this into practice in the linux system\n\nIn short, the options can be classified according to the following scheme:\n\n1. Passive DPI not sending RST to the server. ISP tuned iptables commands can help.\nThis option is out of the scope of the project. If you do not allow ban trigger to fire, then you won’t have to\ndeal with its consequences.\n2. Modification of the TCP connection at the stream level. Implemented through a proxy or transparent proxy.\n3. Modification of TCP connection at the packet level. Implemented through the NFQUEUE handler and raw sockets.\n\nFor options 2 and 3, **tpws** and **nfqws** programs are implemented, respectively.\nYou need to run them with the necessary parameters and redirect certain traffic with iptables or nftables.\n\n## When it will not work\n\n* If DNS server returns false responses. ISP can return false IP addresses or not return anything\nwhen blocked domains are queried. If this is the case change DNS to public ones, such as 8.8.8.8 or 1.1.1.1.Sometimes ISP hijacks queries to any DNS server. Dnscrypt or dns-over-tls help.\n* If blocking is done by IP.\n* If a connection passes through a filter capable of reconstructing a TCP connection, and which\nfollows all standards. For example, we are routed to squid. Connection goes through the full OS tcpip stack. This project targets DPI only, not full OS stack and not server applications.\n\n## nfqws\n\nThis program is a packet modifier and a NFQUEUE queue handler.\nFor BSD systems there is dvtws. Its built from the same source and has almost the same parameters (see [bsd.en.md](./bsd.en.md)).\nnfqws takes the following parameters:\n\n```\n @\u003cconfig_file\u003e                                            ; read file for options. must be the only argument. other options are ignored.\n\n --debug=0|1\n --dry-run                                                 ; verify parameters and exit with code 0 if successful\n --version                                                 ; print version and exit\n --comment                                                 ; any text (ignored)\n --qnum=\u003cnfqueue_number\u003e\n --daemon                                                  ; daemonize\n --pidfile=\u003cfilename\u003e                                      ; write pid to file\n --user=\u003cusername\u003e                                         ; drop root privs\n --uid=uid[:gid1,gid2,...]                                 ; drop root privs\n --bind-fix4                                               ; apply outgoing interface selection fix for generated ipv4 packets\n --bind-fix6                                               ; apply outgoing interface selection fix for generated ipv6 packets\n --wsize=\u003cwindow_size\u003e[:\u003cscale_factor\u003e]                    ; set window size. 0 = do not modify. OBSOLETE !\n --wssize=\u003cwindow_size\u003e[:\u003cscale_factor\u003e]                   ; set window size for server. 0 = do not modify. default scale_factor = 0.\n --wssize-cutoff=[n|d|s]N                                  ; 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                                ; 1(default)=auto cutoff wssize on known protocol\n --ctrack-timeouts=S:E:F[:U]                               ; internal conntrack timeouts for TCP SYN, ESTABLISHED, FIN stages, UDP timeout. default 60:300:60:60\n --ctrack-disable=[0|1]                                    ; 1 or no argument disables conntrack\n --ipcache-lifetime=\u003cint\u003e                                  ; time in seconds to keep cached hop count and domain name (default 7200). 0 = no expiration\n --ipcache-hostname=[0|1]                                  ; 1 or no argument enables ip-\u003ehostname caching\n --hostcase                                                ; change Host: =\u003e host:\n --hostspell                                               ; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n --hostnospace                                             ; remove space after Host: and add it to User-Agent: to preserve packet size\n --domcase                                                 ; mix domain case : Host: TeSt.cOm\n --methodeol                                               ; add '\\n' before method and remove space after Host:\n --synack-split=[syn|synack|acksyn]                        ; perform TCP split handshake : send SYN only, SYN+ACK or ACK+SYN\n --orig-ttl=\u003cint\u003e                                          ; set TTL for original packets\n --orig-ttl6=\u003cint\u003e                                         ; set ipv6 hop limit for original packets. by default ttl value is used\n --orig-autottl=[\u003cdelta\u003e[:\u003cmin\u003e[-\u003cmax\u003e]]|-]                ; auto ttl mode for both ipv4 and ipv6. default: +5:3-64. \"0:0-0\" or \"-\" disables autottl.\n --orig-autottl6=[\u003cdelta\u003e[:\u003cmin\u003e[-\u003cmax\u003e]]|-]               ; overrides --orig-autottl for ipv6 only\n --orig-tcp-flags-set=\u003cint|0xHEX|flaglist\u003e                 ; 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=\u003cint|0xHEX|flaglist\u003e               ; unset these tcp flags (flags \u0026= ~value)\n --orig-mod-start=[n|d|s]N                                 ; 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                                ; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n --dup=\u003cint\u003e                                               ; duplicate original packets. send N dups before original.\n --dup-replace=[0|1]                                       ; 1 or no argument means do not send original, only dups\n --dup-ttl=\u003cint\u003e                                           ; set TTL for dups\n --dup-ttl6=\u003cint\u003e                                          ; set ipv6 hop limit for dups. by default ttl value is used\n --dup-autottl=[\u003cdelta\u003e[:\u003cmin\u003e[-\u003cmax\u003e]]|-]                 ; auto ttl mode for both ipv4 and ipv6. default: -1:3-64. \"0:0-0\" or \"-\" disables autottl.\n --dup-autottl6=[\u003cdelta\u003e[:\u003cmin\u003e[-\u003cmax\u003e]]|-]                ; overrides --dup-autottl for ipv6 only\n --dup-tcp-flags-set=\u003cint|0xHEX|flaglist\u003e                  ; 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=\u003cint|0xHEX|flaglist\u003e                ; unset these tcp flags (flags \u0026= ~value)\n --dup-fooling=\u003cmode\u003e[,\u003cmode\u003e]                             ; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack hopbyhop hopbyhop2\n --dup-ts-increment=\u003cint|0xHEX\u003e                            ; ts fooling TSval signed increment for dup. default -600000\n --dup-badseq-increment=\u003cint|0xHEX\u003e                        ; badseq fooling seq signed increment for dup. default -10000\n --dup-badack-increment=\u003cint|0xHEX\u003e                        ; badseq fooling ackseq signed increment for dup. default -66000\n --dup-ip-id=same|zero|seq|rnd                             ; ipv4 ip_id mode for dupped packets\n --dup-start=[n|d|s]N                                      ; 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                                     ; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n --ip-id=zero|seq|seqgroup|rnd                             ; ipv4 ip_id assignment scheme\n --dpi-desync=[\u003cmode0\u003e,]\u003cmode\u003e[,\u003cmode2\u003e]                   ; try to desync dpi state. modes : synack fake fakeknown rst rstack hopbyhop destopt ipfrag1 multisplit multidisorder fakedsplit hostfakesplit fakeddisorder ipfrag2 udplen tamper\n --dpi-desync-fwmark=\u003cint|0xHEX\u003e                           ; override fwmark for desync packet. default = 0x40000000 (1073741824)\n --dpi-desync-ttl=\u003cint\u003e                                    ; set ttl for desync packet\n --dpi-desync-ttl6=\u003cint\u003e                                   ; set ipv6 hop limit for desync packet. by default ttl value is used.\n --dpi-desync-autottl=[\u003cdelta\u003e[:\u003cmin\u003e[-\u003cmax\u003e]]|-]          ; auto ttl mode for both ipv4 and ipv6. default: -1:3-20. \"0:0-0\" or \"-\" disables autottl.\n --dpi-desync-autottl6=[\u003cdelta\u003e[:\u003cmin\u003e[-\u003cmax\u003e]]|-]         ; overrides --dpi-desync-autottl for ipv6 only\n --dpi-desync-tcp-flags-set=\u003cint|0xHEX|flaglist\u003e           ; 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=\u003cint|0xHEX|flaglist\u003e         ; unset these tcp flags (flags \u0026= ~value)\n --dpi-desync-fooling=\u003cmode\u003e[,\u003cmode\u003e]                      ; can use multiple comma separated values. modes : none md5sig ts badseq badsum datanoack hopbyhop hopbyhop2\n --dpi-desync-repeats=\u003cN\u003e                                  ; send every desync packet N times\n --dpi-desync-skip-nosni=0|1                               ; 1(default)=do not act on ClientHello without SNI (ESNI ?)\n --dpi-desync-split-pos=N|-N|marker+N|marker-N             ; comma separated list of split positions\n                                                           ; markers: method,host,endhost,sld,endsld,midsld,sniext\n                                                           ; full list is only used by multisplit and multidisorder\n                                                           ; fakedsplit/fakeddisorder use first l7-protocol-compatible parameter if present, first abs value otherwise\n --dpi-desync-split-seqovl=N|-N|marker+N|marker-N          ; use sequence overlap before first sent original split segment\n --dpi-desync-split-seqovl-pattern=[+ofs]@\u003cfilename\u003e|0xHEX ; pattern for the fake part of overlap\n --dpi-desync-fakedsplit-pattern=[+ofs]@\u003cfilename\u003e|0xHEX   ; fake pattern for fakedsplit/fakeddisorder\n --dpi-desync-fakedsplit-mod=mod[,mod]                     ; 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-mod=mod[,mod]                  ; can be none, host=\u003chostname\u003e, altorder=0|1\n --dpi-desync-ipfrag-pos-tcp=\u003c8..9216\u003e                     ; ip frag position starting from the transport header. multiple of 8, default 32.\n --dpi-desync-ipfrag-pos-udp=\u003c8..9216\u003e                     ; ip frag position starting from the transport header. multiple of 8, default 8.\n --dpi-desync-ts-increment=\u003cint|0xHEX\u003e                     ; ts fooling TSval signed increment. default -600000\n --dpi-desync-badseq-increment=\u003cint|0xHEX\u003e                 ; badseq fooling seq signed increment. default -10000\n --dpi-desync-badack-increment=\u003cint|0xHEX\u003e                 ; badseq fooling ackseq signed increment. default -66000\n --dpi-desync-any-protocol=0|1                             ; 0(default)=desync only http and tls  1=desync any nonempty data packet\n --dpi-desync-fake-tcp-mod=mod[,mod]                       ; comma separated list of tcp fake mods. available mods : none,seq\n --dpi-desync-fake-http=[+ofs]@\u003cfilename\u003e|0xHEX            ; file containing fake http request\n --dpi-desync-fake-tls=[+ofs]@\u003cfilename\u003e|0xHEX|![+offset]  ; file containing fake TLS ClientHello (for https). '!' = standard fake\n --dpi-desync-fake-tls-mod=mod[,mod]                       ; comma separated list of TLS fake mods. available mods : none,rnd,rndsni,sni=\u003csni\u003e,dupsid,padencap\n --dpi-desync-fake-unknown=[+ofs]@\u003cfilename\u003e|0xHEX         ; file containing unknown protocol fake payload\n --dpi-desync-fake-syndata=[+ofs]@\u003cfilename\u003e|0xHEX         ; file containing SYN data payload\n --dpi-desync-fake-quic=[+ofs]@\u003cfilename\u003e|0xHEX            ; file containing fake QUIC Initial\n --dpi-desync-fake-wireguard=[+ofs]@\u003cfilename\u003e|0xHEX       ; file containing fake wireguard handshake initiation\n --dpi-desync-fake-dht=[+ofs]@\u003cfilename\u003e|0xHEX             ; file containing fake DHT (d1..e)\n --dpi-desync-fake-discord=[+ofs]@\u003cfilename\u003e|0xHEX         ; file containing fake Discord voice connection initiation packet (IP Discovery)\n --dpi-desync-fake-stun=[+ofs]@\u003cfilename\u003e|0xHEX            ; file containing fake STUN message\n --dpi-desync-fake-unknown-udp=[+ofs]@\u003cfilename\u003e|0xHEX     ; file containing unknown udp protocol fake payload\n --dpi-desync-udplen-increment=\u003cint\u003e                       ; increase or decrease udp packet length by N bytes (default 2). negative values decrease length.\n --dpi-desync-udplen-pattern=[+ofs]@\u003cfilename\u003e|0xHEX       ; udp tail fill pattern\n --dpi-desync-start=[n|d|s]N                               ; 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                              ; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n --hostlist=\u003cfilename\u003e                                     ; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply if not prefixed with `^`, gzip supported, multiple hostlists allowed)\n --hostlist-domains=\u003cdomain_list\u003e                          ; comma separated fixed domain list\n --hostlist-exclude=\u003cfilename\u003e                             ; do not apply dpi desync to the listed hosts (one host per line, subdomains auto apply if not prefixed with `^`, gzip supported, multiple hostlists allowed)\n --hostlist-exclude-domains=\u003cdomain_list\u003e                  ; comma separated fixed domain list\n --hostlist-auto=\u003cfilename\u003e                                ; detect DPI blocks and build hostlist automatically\n --hostlist-auto-fail-threshold=\u003cint\u003e                      ; how many failed attempts cause hostname to be added to auto hostlist (default : 3)\n --hostlist-auto-fail-time=\u003cint\u003e                           ; all failed attemps must be within these seconds (default : 60)\n --hostlist-auto-retrans-threshold=\u003cint\u003e                   ; how many request retransmissions cause attempt to fail (default : 3)\n --hostlist-auto-debug=\u003clogfile\u003e                           ; debug auto hostlist positives\n --new                                                     ; begin new strategy (new profile)\n --skip                                                    ; do not use this profile\n --filter-l3=ipv4|ipv6                                     ; L3 protocol filter. multiple comma separated values allowed.\n --filter-tcp=[~]port1[-port2]|*                           ; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list supported.\n --filter-udp=[~]port1[-port2]|*                           ; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list supported.\n --filter-l7=\u003cproto\u003e                                       ; L6-L7 protocol filter. multiple comma separated values allowed. proto: http tls quic wireguard dht discord stun unknown\n --filter-ssid=ssid1[,ssid2,ssid3,...]                     ; per profile wifi SSID filter\n --ipset=\u003cfilename\u003e                                        ; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n --ipset-ip=\u003cip_list\u003e                                      ; comma separated fixed subnet list\n --ipset-exclude=\u003cfilename\u003e                                ; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n --ipset-exclude-ip=\u003cip_list\u003e                              ; comma separated fixed subnet list\n```\n\nMany parameters dealing with binary data support loading from hex string prefixed by \"0x\" or from a file.\nFilename can be \"as is\" or prefixed with \"@\". If there's \"+number\" prefix before \"@\" it means offset of data inside the file.\nOffset must be less that data size.\n\n### DPI desync attack\n\nThe idea is to take original message, modify it, add additional fake information in such a way that the server OS accepts original data only\nbut DPI cannot recostruct original message or sees what it cannot identify as a prohibited request.\n\nThere's a set of instruments to achieve that goal.\nIt can be fake packets that reach DPI but do not reach server or get rejected by server, TCP segmentation or IP fragmentation.\nThere're attacks based on TCP sequence numbers. Methods can be combined in many ways.\n\n### Fakes\n\nFakes are separate generated by nfqws packets carrying false information for DPI. They must either not reach the server or be rejected by it. Otherwise TCP connection or data stream would be broken. There're multiple ways to solve this task.\n\n* **md5sig** does not work on all servers. It typically works only on Linux servers. MD5 tcp option requires additional space in TCP header\n  and can cause MTU overflow during fakedsplit/fakeddisorder on low positions when multisegment query (TLS kyber) is transmitted.\n  `nfqws` cannot redistribute data between original TCP segments. The error displayed is 'message too long'.\n* **badsum** doesn't work if your device is behind NAT which does not pass invalid packets.\n  The most common Linux NAT router configuration does not pass them. Most home routers are Linux based.\n  The default sysctl configuration `net.netfilter.nf_conntrack_checksum=1` causes conntrack to verify tcp and udp checksums\n  and set INVALID state for packets with invalid checksum.\n  Typically, iptables rules include a rule for dropping packets with INVALID state in the FORWARD chain.\n  The combination of these factors does not allow badsum packets to pass through the router.\n  In openwrt mentioned sysctl is set to 0 from the box, in other routers its often left in the default \"1\" state.\n  For nfqws to work properly through the router set `net.netfilter.nf_conntrack_checksum=0` on the router.\n  System never verifies checksums of locally generated packets so nfqws will always work on the router itself.\n  If you are behind another NAT, such as a ISP, and it does not pass invalid packages, there is nothing you can do about it.\n  But usually ISPs pass badsum.\n  Some adapters/switches/drivers enable hardware filtering of rx badsum not allowing it to pass to the OS.\n  This behavior was observed on a Mediatek MT7621 based device.\n  Tried to modify mediatek ethernet driver with no luck, likely hardware enforced limitation.\n  However the device allowed to send badsum packets, problem only existed for passthrough traffic from clients.\n* **badseq** packets will be dropped by server, but DPI also can ignore them.\n  default badseq increment is set to -10000 because some DPIs drop packets outside of the small tcp window.\n  But this also can cause troubles when `--dpi-desync-any-protocol` is enabled.\n  To be 100% sure fake packet cannot fit to server tcp window consider setting badseq increment to 0x80000000\n* **TTL** looks like the best option, but it requires special tuning for each ISP. If DPI is further than local ISP websites\n  you can cut access to them. Manual IP exclude list is required. Its possible to use md5sig with ttl.\n  This way you cant hurt anything, but good chances it will help to open local ISP websites.\n  If automatic solution cannot be found then use `zapret-hosts-user-exclude.txt`.\n  Some router stock firmwares fix outgoing TTL. Without switching this option off TTL fooling will not work.\n* **hopbyhop** is ipv6 only. This fooling adds empty extension header `hop-by-hop options` or two headers in case of `hopbyhop2`.\n  Packets with two hop-by-hop headers violate RFC and discarded by all operating systems.\n  All OS accept packets with one hop-by-hop header.\n  Some ISPs/operators drop ipv6 packets with hop-by-hop options. Fakes will not be processed by the server either because\n  ISP drops them or because there are two same headers.\n  DPIs may still anaylize packets with one or two hop-by-hop headers.\n* **datanoack** sends tcp fakes without ACK flag. Servers do not accept this but DPI may accept.\n  This mode may break NAT and may not work with iptables if masquerade is used, even from the router itself.\n  Works with nftables properly. Likely requires external IP address (some ISPs pass these packets through their NAT).\n* Manipulate **tcp flags** with `--dpi-desync-tcp-flags-set` and `--dpi-desync-tcp-flags-unset`.\n  Invalid tcp flags combination may cause server to drop the packet but DPI can accept it.\n  For example, set SYN in fakes. This may not work with all servers.\n  `datanoack` can be replaced to `--dpi-desync-tcp-flags-unset=ACK`.\n* **ts** adds to TSval ts increment value (-600000 by default). Servers discard packets with TSval in some range.\n  Practical tests suggest increment between -100 and -0x80000000.\n  Timestamps are generated by client OS. In linux timestamps are enabled by default. In windows by default timestamps are disabled.\n  They can be enabled with this command : `netsh interface tcp set global timestamps=enabled` .\n  ts fooling requires that timestamps are enabled. They must be enabled on every client OS.\n  TSecr is left unmodified.\n* **autottl** tries to automatically guess hop count to the server and compute TTL by adding some delta value that can be positive or negative.\n  Positive deltas must be preceeded by unary `+` sign. Deltas without any unary sign are treated negative for old versions compatibility reasons.\n  This tech relies on well known TTL default values used by OS : 64,128,255.\n  nfqws needs first incoming packet to see it's TTL. You must redirect it too.\n  If resulting value TTL is outside the range (min,max) then its normalized to min or max.\n  If delta is negative and TTL is longer than guessed hop count or delta is positive and TTL is shorter than guessed hop count\n  then autottl fails and falls back to the fixed value.\n  This can help if multiple DPIs exists on backbone channels, not just near the ISP.\n  Can fail if inbound and outbound paths are not symmetric.\n\n\n`--dpi-desync-fooling` takes multiple comma separated values.\n\n\nMultiple parameters `--dpi-desync-fake-???` are supported except for the `--dpi-desync-fake-syndata`.\nFakes are sent in the specified order. `--dpi-desync-repeats` resends each fake.\nResulting order would be : `fake1 fake1 fake1 fake2 fake2 fake2 fake3 fake3 fake3 .....`\n\n\n### FAKE mods\n\nBy default all tcp fakes are sent with the same sequence as original packet.\nThis can be changed by `--dpi-desync-fake-tcp-mod=seq`. In the latter case all fakes are sent as if they would be tcp segments of a single fake.\n\n**nfqws** has built-in TLS fake. It can be customized with `--dpi-desync-fake-tls` option.\nCustomized fake data can be anything - valid TLS Client Hello or arbitrary data.\nIt's possible to use TLS Client Hello with any fingerprint and any SNI.\n\n**nfqws** can do some modifications of valid TLS Client Hello fakes in runtime with `--dpi-desync-fake-tls-mod` option.\n\n * `none`. Do not do any mods.\n * `rnd`. Randomize `random` and `session id` fields. Applied on every request.\n * `rndsni`. Randomize SNI. If SNI \u003e=7 symbols random SLD is applied with known TLD. Otherwise filled with random symbols. Applied only once at startup.\n * `dupsid`. Copy `session ID` from original TLS Client Hello. Takes precedence over `rnd`. Applied on every request.\n * `sni=\u003csni\u003e`. Set specified SNI value. Changes TLS fake length, fixes lengths in TLS structure. Applied once at startup before `rndsni`.\n * `padencap`. Padding extension is extended by original TLS Client Hello size (including multi packet variation with kyber). Padding extension is added to the end if not present, otherwise it must be the last extension. All lengths are increased. Fake size is not changed. Can be useful if DPI does not analyze sequence numbers properly. Applied on every request.\n\nBy default if custom fake is not defined `rnd,rndsni,dupsid` mods are applied. If defined - `none`.\nThis behaviour is compatible with previous versions with addition of `dupsid`.\n\nIf multiple TLS fakes are present each one takes the last mod.\nIf a mod is specified after fake it replaces previous mod.\nThis way it's possible to use different mods for every TLS fake.\n\nIf a mod is set to non-TLS fake it causes error. Use `--dpi-desync-fake-tls-mod=none'.\n\nExample : `--dpi-desync-fake-tls=iana_org.bin --dpi-desync-fake-tls-mod=rndsni --dpi-desync-fake-tls=0xaabbccdd --dpi-desync-fake-tls-mod=none'\n\n### TCP segmentation\n\n * `multisplit`. split request at specified in `--dpi-desync-split-pos` positions\n * `multidisorder`. same as `multisplit` but send in reverse order\n * `fakedsplit`. sequental one position split with fake mix\n * `hostfakesplit` (altorder=0). fake host part of the request : before host, random fake host, real host (optionally split this part), random fake host repeat, after host\n * `hostfakesplit` (altorder=1). fake host part of the request : before host, random fake host, after host, real host (optionally split this part)\n * `fakedsplit`. reverse one position split with fake mix\n\n`--dpi-desync-fakedsplit-mod=altorder=N` specifies number which influence to the presence of individual fakes in `fakedsplit`/`fakeddisorder`.\n\n`fakedsplit` TCP segments of multi-packet messages with split pos :\n\n * `altorder=0`. fake 1st segment, 1st segment, fake 1st segment, fake 2nd segment, 2nd segment, fake 2nd segment\n * `altorder=1`. 1st segment, fake 1st segment, fake 2nd segment, 2nd segment, fake 2nd segment\n * `altorder=2`. 1st segment, fake 2nd segment, 2nd segment, fake 2nd segment\n * `altorder=3`. 1st segment, fake 2nd segment, 2nd segment\n\n`fakeddisorder` TCP segments of multi-packet messages with split pos :\n\n * `altorder=0`. fake 2nd segment, 2nd segment, fake 2nd segment, fake 1st segment, 1st segment, fake 1st segment\n * `altorder=1`. 2nd segment, fake 2nd segment, fake 1st segment, 1st segment, fake 1st segment\n * `altorder=2`. 2nd segment, fake 1st segment, 1st segment, fake 1st segment\n * `altorder=3`. 1st segment, fake 1st segment, 1st segment\n\n`fakedsplit`/`fakeddisorder` TCP segments of multi-packet messages without split pos :\n\n * `altorder=0`. fake, original, fake\n * `altorder=8`. original, fake\n * `altorder=16`. original\n\nResulting `altorder=N` is the sum of two `altorder` parts mentioned above.\n\n`--dpi-desync-fakedsplit-pattern` defines data payload of fakes in `fakedsplit`/`fakeddisorder`. By default pattern is simple `0x00`.\nOffset of split part + offset of current packet in multi-packet message define offset in the pattern.\n\nPositions are defined by markers.\n\n* **Absolute positive marker** - numeric offset inside one packet or group of packets starting from the start\n* **Absolute negative marker** - numeric offset inside one packet or group of packets starting from the next byte after the end\n* **Relative marker** - positive or negative offset relative to a logical position within a packet or group of packets\n\nRelative positions :\n\n* **method** - HTTP method start ('GET', 'POST', 'HEAD', ...). Method is usually always at position 0 but can shift because of `--methodeol` fooling. If fooled position can become 1 or 2.\n* **host** - hostname start in a known protocol (http, TLS)\n* **endhost** - the byte next to the last hostname's byte\n* **sld** - second level domain start in the hostname\n* **endsld** - the byte next to the last SLD byte\n* **midsld** - middle of SLD\n* **sniext** - start of the data field in the SNI TLS extension. Any extension has 2-byte type and length fields followed by data field.\n\nMarker list example : `100,midsld,sniext+1,endhost-2,-10`.\n\nWhen splitting all markers are resolved to absolute offsets. If a relative position is absent in the current protocol its dropped. Then all resolved offsets are normalized to the current packet offset in multi packet group (multi-packet TLS with kyber, for example). Positions outside of the current packet are dropped. Remaining positions are sorted and deduplicated.\n\nIn `multisplit`or `multidisorder` case split is cancelled if no position remained.\n\n`fakedsplit` и `fakeddisorder` use only one split position. It's searched from the  `--dpi-desync-split-pos` list by a special alorightm.\nFirst relative markers are searched. If no suitable found absolute markers are searched. If nothing found position 1 is used.\n\nFor example, `--dpi-desync-split-pos=method+2,midsld,5` means `method+2` for http, `midsld` for TLS and 5 for others.\n\n`--dpi-desync-fakedsplit-mod=altorder=N` switches `fakedsplit` to alternate segment ordering.\n\n`hostfakesplit` only fakes hostname part of the request making it hard to destinguish between real and fake host names.\nIt works for tcp protocols with host : TLS and HTTP. Real hostname can be additionally split using `--dpi-desync-hostfakesplit-midhost` marker.\nFor example, `--dpi-desync-hostfakesplit-midhost=midsld`. Position must be within host range or split won't happen.\nMulti-packet queries are supported if hostname part is not already split. If it is fooling is cancelled.\n\nBy default fake host names are generated randomly on the fly using `[0-9a-z]` pattern. If host length is \u003e= 7 dot is placed to simulate 3-char TLD and last 3 chars are replaces with a random known 3-char TLD.\nIt's possible to set fake host template : `--dpi-desync-hostfakesplit-mod=host=\u003chostname\u003e`.\nTemplate hostname will be expanded to the left to original hostname size with random characters from `[0-9a-z]` pattern : \"www.networksolutions.com\" -\u003e \"h8xmdba4tv7a8.google.com\".\nIf original hostname size is less than template size it will be cut : \"habr.com\" -\u003e \"ogle.com\".\nIf original hostname size is larger than template size by one, dot will be appended to the left : \"www.xxx.com\" =\u003e \".google.com\"..\nThat's why it's a good idea to use short hostnames in template : \"ya.ru\", \"vk.com\", \"x.com\".\n\n`--dpi-desync-hostfakesplit-mod=altorder=1` switches `hostfakesplit` to alternate segment ordering. `altorder=1` sends the whole request with faked host sequentally, then real host segment.\n\n### Sequence numbers overlap\n\n`seqovl` adds to one of the original segment `seqovl` bytes to the beginning and decreases sequence number. For `split` - to the first segment, for `disorder` - to the beginning of the penultimate segment sent (second in the original sequence).\n\nIn `split` mode this creates partially in-window packet. OS receives only in-window part.\nIn `disorder` mode OS receives fake and real part of the second segment but does not pass received data to the socket until first segment is received. First segment overwrites fake part of the second segment. Then OS passes original data to the socket.\nAll unix OS except Solaris preserve last received data. This is not the case for Windows servers and `disorder` with `seqovl` will not work.\nDisorder requires `seqovl` to be less than split position. Otherwise `seqovl` is not possible and will be cancelled.\nMethod allows to avoid separate fakes. Fakes and real data are mixed.\n\n### IP_ID assignment\n\nSome DPIs check ipv4 ip_id value. OS normally increment ip_id value every packet. Some anti-DPI software may send fakes or tcp segments with the same ip_id as original causing block trigger.\n\nSequental ip_id will be broken in case of sending fakes or additional tcp segments because OS knows nothing about them. But still there are options how to assignt ip_id to generated packets.\n\n`ip-id` parameter sets ip_id assignment scheme for a desync profile :\n\n * `seq` (default) : increment ip_id for every next packet. in `multidisorder` case increase ip_id for the number of tcp segments then decrease by 1 every packet.\n * `seqgroup` : same as `seq` but send fake replacements with the same ip_id as original parts. related only to fake tcp segments with the same size and same sequence as originals.\n * `rnd` : assign random ip_id\n * `zero` : always set zero. Linux and BSD will send zero, Windows will replace zero with it's own counter.\n\nipv6 header lacks ip_id field, `ip-id` parameter ignored for ipv6.\n\n### ipv6 specific modes\n\n`hopbyhop`, `destopt` and `ipfrag1` desync modes (they're not the same as `hopbyhop` fooling !) are ipv6 only. One `hop-by-hop`,\n`destination options` or `fragment` header is added to all desynced packets.\nExtra header increases packet size and can't be applied to the maximum size packets.\nIf it's not possible to send modified packet original one will be sent.\nThe idea here is that DPI sees 0 in the next header field of the main ipv6 header and does not\nwalk through the extension header chain until transport header is found.\n`hopbyhop`, `destopt`, `ipfrag1` modes can be used with any second phase mode except `ipfrag1+ipfrag2`.\nFor example, `hopbyhop,multisplit` means split original tcp packet into several pieces and add hop-by-hop header to each.\nWith `hopbyhop,ipfrag2` header sequence will be : `ipv6,hop-by-hop,fragment,tcp/udp`.\n`ipfrag1` mode may not always work without special preparations. See \"IP Fragmentation\" notices.\n\n### Original modding\n\nParameters `--orig-ttl` and `--orig-ttl6` allow to set TTL on original packets.\nAll further packet manipulations, e.g. segmentation, take modded original as data source and inherit modded TTL.\n\n`--orig-autottl` and `--orig-autottl6` work the same way as `dpi-desync-autottl`, but on original packets.\nDelta should have unary `+` sign to produce TTL longer than guessed hop count. Otherwise nothing will reach the server.\nExample : `--orig-autottl=+5:3-64`.\n\n`--orig-mod-start` and `--orig-mod-cutoff` specify start and end conditions for original modding. The work the same way as\n`--dpi-desync-start` and `--dpi-desync-cutoff`.\n\nThis function can be useful when DPI hunts for fakes and blocks suspicious connections.\nDPI can compute TTL difference between packets and fire block trigger if it exceedes some threshold.\n\n### Duplicates\n\nDuplicates are copies of original packets which are sent before them. Duplicates are enabled by `--dup=N`, where N is dup count.\n`--dup-replace` disables sending of original.\n\nDups are sent only when original would also be sent without reconstruction.\nFor example, if TCP segmentation happens, original is actually dropped and is being replaced by artificially constructed new packets.\nDups are not sent in this case.\n\nAll dup fooling modes are available : `--dup-ttl`. `--dup-ttl6`, `--dup-fooling`.\nYou decide whether these packets need to reach the server and in what form, according to the intended strategy.\n\n`--dup-autottl` and `--dup-autottl6` work the same way as `dpi-desync-autottl`.\nDelta can be preceeded by unary `+` or `-` sign.\nExample : `--dup-autottl=-2:3-64`.\n\n`--dup-start` and `--dup-cutoff` specify start and end conditions for dupping. The work the same way as\n`--dpi-desync-start` and `--dpi-desync-cutoff`.\n\nThis function can help if DPI compares some characteristics of fake and original packets and block connection if they differ some way.\nFooled duplicates can convince DPI that the whole session has an anomaly.\nFor example, all connection is protected by MD5 signature, not individual packets.\n\n### Server reply reaction\n\nThere are DPIs that analyze responses from the server, particularly the certificate from the ServerHello that contain domain name(s). The ClientHello delivery confirmation is an ACK packet from the server with ACK sequence number corresponding to the length of the ClientHello+1.\nIn the disorder variant, a selective acknowledgement (SACK) usually arrives first, then a full ACK.\nIf, instead of ACK or SACK, there is an RST packet with minimal delay, DPI cuts you off at the request stage.\nIf the RST is after a full ACK after a delay of about ping to the server, then probably DPI acts on the server response. The DPI may be satisfied with good ClientHello and stop monitoring the TCP session without checking ServerHello. Then you were lucky. 'fake' option could work.\nIf it does not stop monitoring and persistently checks the ServerHello, `--wssize` parameter may help (see [CONNTRACK](#conntrack)).\nOtherwise it is hardly possible to overcome this without the help of the server.\nThe best solution is to enable TLS 1.3 support on the server. TLS 1.3 sends the server certificate in encrypted form.\nThis is recommendation to all admins of blocked sites. Enable TLS 1.3. You will give more opportunities to overcome DPI.\n\n### SYNDATA mode\n\nNormally SYNs come without data payload. If it's present it's ignored by all major OS if TCP fast open (TFO) is not involved, but may not be ignored by DPI.\nOriginal connections with TFO are not touched because otherwise they would be definitely broken.\nWithout extra parameter payload is 16 zero bytes.\n\n### DPI desync combos\n\n`--dpi-desync` takes up to 3 comma separated modes.\n\n* 0 phase modes work during the connection establishement : `synack`, `syndata` `--wsize`, `--wssize`. [hostlist](#multiple-strategies) filters are applicable only if [`--ipcache-hostname`](#ip-cache) is enabled.\n* In the 1st phase fakes are sent before original data  : `fake`, `rst`, `rstack`.\n* In the 2nd phase original data is sent in a modified way (for example `fakedsplit` or `ipfrag2`).\n\nModes must be specified in phase ascending order.\n\n### IP cache\n\n`ipcache` is the structure in the process memory that stores some information by IP address and interface name key.\nThis information can be used as missing data. Currently it's used in the following cases :\n\n1. IP,interface =\u003e hop count . This is used to apply autottl at 0 phase since the first session packet. If the record is absent autottl will not be applied immediately. Second time it will be applied immediately using cached hop count.\n\n2. IP =\u003e hostname . Hostname is cached to be used in 0 phase strategies. Mode is disabled by default and can be enabled by `ipcache-hostname` parameter.\nThis tech is experimental. There's no one-to-one correspondence between IP and domain name. Multiple domains can resolve to the same IP.\nIf collision happens hostname is replaced. On CDNs a domain can resolve to different IPs over time. `--ipcache-lifetime` limits how long cached record is valid. It's 2 hours by default.\nBe prepared for unexpected results that can be explained only by reading debug logs.\n\nSIGUSR2 forces process to output it's ipcache to stdout.\n\n### CONNTRACK\n\nnfqws is equipped with minimalistic connection tracking system (conntrack)\nIt's used if some specific DPI circumvention methods are involved and helps to reassemble multi-packet requests.\n\nConntrack can track connection phase : SYN,ESTABLISHED,FIN , packet counts in both directions , sequence numbers.\n\nIt can be fed with unidirectional or bidirectional packets.\n\nA SYN or SYN,ACK packet creates an entry in the conntrack table.\n\nThat's why iptables redirection must start with the first packet although can be cut later using connbytes filter.\n\nFirst seen UDP packet creates UDP stream. It defines the stream direction. Then all packets with the same\n`src_ip,src_port,dst_ip,dst_port` are considered to belong to the same UDP stream. UDP stream exists till inactivity timeout.\n\nA connection is deleted from the table as soon as it's no more required to satisfy nfqws needs or when a timeout happens.\n\nThere're 3 timeouts for each connection state. They can be changed in `--ctrack-timeouts` parameter.\n\n`--wssize` changes tcp window size for the server to force it to send split replies.\nIn order for this to affect all server operating systems, it is necessary to change the window size in each outgoing packet\nbefore sending the message, the answer to which must be split (for example, TLS ClientHello).\nThat's why conntrack is required to know when to stop applying low window size.\n\nIf you do not stop and set the low wssize all the time, the speed will drop catastrophically.\nLinux can overcome this using connbytes filter but other OS may not include similar filter.\n\nIn http(s) case wssize stops after the first http request or TLS ClientHello unless `--wssize-forced-cutoff=0` is specified.\n\nIf you deal with a non-http(s) protocol you need `--wssize-cutoff`. It sets the threshold where wssize stops.\n\nThreshold can be prefixed with 'n' (packet number starting from 1), 'd' (data packet number starting from 1), \n's' (relative sequence number - sent by client bytes + 1).\n\nIf a http request or TLS ClientHello packet is detected wssize stops immediately ignoring wssize-cutoff option.\nThis action is called \"forced wssize cutoff\" and can disabled using `--wssize-forced-cutoff=0`.\n\nIf your protocol is prone to long inactivity, you should increase ESTABLISHED phase timeout using `--ctrack-timeouts`.\n\nDefault timeout is low - only 5 mins.\n\nDon't forget that nfqws feeds with redirected packets. If you have limited redirection with connbytes\nESTABLISHED entries can remain in the table until dropped by timeout.\n\nTo diagnose conntrack state send SIGUSR1 signal to nfqws : `killall -SIGUSR1 nfqws`.\n\nnfqws will dump current conntrack table to stdout.\n\nTypically, in a SYN packet, client sends TCP extension **scaling factor** in addition to window size.\nscaling factor is the power of two by which the window size is multiplied : 0=\u003e1, 1=\u003e2, 2=\u003e4, ..., 8=\u003e256, ...\n\nThe wssize parameter specifies the scaling factor after a colon.\n\nScaling factor can only decrease, increase is blocked to prevent the server from exceeding client's window size.\n\nTo force a TLS server to fragment ServerHello message to avoid hostname detection on DPI use `--wssize=1:6`\n\nThe main rule is to set scale_factor as much as possible so that after recovery the final window size\nbecomes the possible maximum. If you set `scale_factor` 64:0, it will be very slow.\n\nOn the other hand, the server response must not be large enough for the DPI to find what it is looking for.\n\n`--wssize` is not applied in desync profiles with hostlist filter because it works since the connection initiation when it's not yet possible\nto extract the host name. But it works with auto hostlist profiles.\n\n`--wssize` may slow down sites and/or increase response time. It's desired to use another methods if possible.\n\n`--dpi-desync-cutoff` allows you to set the threshold at which it stops applying dpi-desync.\nCan be prefixed with 'n', 'd', 's' symbol the same way as `--wssize-cutoff`.\nUseful with `--dpi-desync-any-protocol=1`.\nIf the connection falls out of the conntrack and `--dpi-desync-cutoff` is set, `dpi desync` will not be applied.\n\nSet conntrack timeouts appropriately.\n\n### Reassemble\n\nnfqws supports reassemble of TLS and QUIC ClientHello.\nThey can consist of multiple packets if kyber crypto is used (default starting from chromium 124).\nChromium randomizes TLS fingerprint. SNI can be in any packet or in-between.\nStateful DPIs usually reassemble all packets in the request then apply block decision.\nIf nfqws receives a partial ClientHello it begins reassemble session. Packets are delayed until it's finished.\nThen they go through desync using fully reassembled message.\nOn any error reassemble is cancelled and all delayed packets are sent immediately without desync.\n\nThere is special support for all tcp split options for multi segment TLS. Split position is treated as message-oriented, not packet oriented. For example, if your client sends TLS ClientHello with size 2000 and SNI is at 1700, desync mode is `fake,multisplit`, then fake is sent first, then original first segment and the last splitted segment. 3 segments total.\n\n### UDP support\n\nUDP attacks are limited. Its not possible to fragment UDP on transport level, only on network (ip) level.\nOnly desync modes `fake`,`fakeknown`,`hopbyhop`,`destopt`,`ipfrag1`,`ipfrag2`,`udplen` and `tamper` are applicable.\n`fake`,`fakeknown`,`hopbyhop`,`destopt`,`ipfrag1` are 1st phase modes, others - 2nd phase.\nAs always it's possible to combine one mode from 1st phase with one mode from 2nd phase but not possible to mix same phase modes.\n\n`udplen` increases udp payload size by `--dpi-desync-udplen-increment` bytes. Padding is filled with zeroes by default but can be overriden with a pattern.\nThis option can resist DPIs that track outgoing UDP packet sizes.\nRequires that application protocol does not depend on udp payload size.\n\nQUIC initial packets are recognized. Decryption and hostname extraction is supported so `--hostlist` parameter will work.\nWireguard handshake initiation, DHT, STUN and [Discord Voice IP Discovery](https://discord.com/developers/docs/topics/voice-connections#ip-discovery) packets are also recognized.\nFor other protocols desync use `--dpi-desync-any-protocol`.\n\nConntrack supports udp. `--dpi-desync-cutoff` will work. UDP conntrack timeout can be set in the 4th parameter of `--ctrack-timeouts`.\n\nFake attack is useful only for stateful DPI and useless for stateless dealing with each packet independently.\nBy default fake payload is 64 zeroes. Can be overriden using `--dpi-desync-fake-unknown-udp`.\n\n### IP fragmentation\n\nModern network can be very hostile to IP fragmentation. Fragmented packets are often not delivered or refragmented/reassembled on the way. \nFrag position is set independently for tcp and udp. By default 24 and 8, must be multiple of 8.\nOffset starts from the transport header.\n\ntcp fragments are almost always filtered. It's absolutely not suitable for arbitrary websites.\nudp fragments have good chances to survive but not everywhere. It's good to assume success rate on QUIC between 50..75%.\nLikely more with your VPS. Sometimes filtered by DDoS protection.\n\nThere are important nuances when working with fragments in Linux.\n\nipv4 : Linux allows to send ipv4 fragments but standard firewall rules in OUTPUT chain can cause raw send to fail.\n\nipv6 : There's no way for an application to reliably send fragments without defragmentation by conntrack.\nSometimes it works, sometimes system defragments packets.\nLooks like kernels \u003c4.16 have no simple way to solve this problem. Unloading of `nf_conntrack` module\nand its dependency `nf_defrag_ipv6` helps but this severely impacts functionality.\nKernels 4.16+ exclude from defragmentation untracked packets.\nSee `blockcheck.sh` code for example.\n\nSometimes it's required to load `ip6table_raw` kernel module with parameter `raw_before_defrag=1`.\nIn openwrt module parameters are specified after module names separated by space in files located in `/etc/modules.d`.\n\nIn traditional linux check whether `iptables-legacy` or `iptables-nft` is used. If legacy create the file\n`/etc/modprobe.d/ip6table_raw.conf` with the following content :\n```\noptions ip6table_raw raw_before_defrag=1\n```\nIn some linux distros its possible to change current ip6tables using this command: `update-alternatives --config ip6tables`.\nIf you want to stay with `nftables-nft` you need to patch and recompile your version.\nIn `nft.c` find :\n```\n\t\t\t{\n\t\t\t\t.name\t= \"PREROUTING\",\n\t\t\t\t.type\t= \"filter\",\n\t\t\t\t.prio\t= -300,\t/* NF_IP_PRI_RAW */\n\t\t\t\t.hook\t= NF_INET_PRE_ROUTING,\n\t\t\t},\n\t\t\t{\n\t\t\t\t.name\t= \"OUTPUT\",\n\t\t\t\t.type\t= \"filter\",\n\t\t\t\t.prio\t= -300,\t/* NF_IP_PRI_RAW */\n\t\t\t\t.hook\t= NF_INET_LOCAL_OUT,\n\t\t\t},\n```\nand replace -300 to -450.\n\nIt must be done manually, `blockcheck.sh` cannot auto fix this for you.\n\nOr just move to `nftables`. You can create hooks with any priority there.\n\nLooks like there's no way to do ipfrag using iptables for forwarded traffic if NAT is present.\n`MASQUERADE` is terminating target, after it `NFQUEUE` does not work.\nnfqws sees packets with internal network source address. If fragmented NAT does not process them.\nThis results in attempt to send packets to internet with internal IP address.\nYou need to use nftables instead with hook priority 101 or higher.\n\n### Multiple strategies\n\n**nfqws** can apply different strategies to different requests. It's done with multiple desync profiles.\nProfiles are delimited by the `--new` parameter. First profile is created automatically and does not require `--new`.\nEach profile has a filter. By default it's empty and profile matches any packet.\nFilter can have hard parameters : ip version, ipset and tcp/udp port range.\nHard parameters are always identified unambiguously even on zero-phase when hostname and L7 are unknown yet.\nHostlists can also act as a filter. They can be combined with hard parameters.\nWhen a packet comes profiles are matched from the first to the last until first filter condition match.\nHard filter is matched first. If it does not match verification goes to the next profile.\nIf a profile matches hard filter , L7 filter and has autohostlist it's selected immediately.\nIf a profile matches hard filter , L7 filter and has normal hostlist(s) and hostname is unknown yet verification goes to the next profile.\nOtherwise profile hostlist(s) are checked for the hostname. If it matches profile is selected.\nOtherwise verification goes to the next profile.\n\nIt's possible that before knowing L7 and hostname connection is served by one profile and after\nthis information is revealed it's switched to another profile.\nIf you use 0-phase desync methods think carefully what can happen during strategy switch.\nUse `--debug` logging to understand better what **nfqws** does.\n\nProfiles are numbered from 1 to N. There's last empty profile in the chain numbered 0.\nIt's used when no filter matched.\n\nIMPORTANT : multiple strategies exist only for the case when it's not possible to combine all to one strategy.\nCopy-pasting blockcheck results of different websites to multiple strategies lead to the mess.\nThis way you may never unblock all resources and only confuse yourself.\n\nIMPORTANT : user-mode ipset implementation was not designed as a kernel version replacement. Kernel version is much more effective.\nIt's for the systems that lack ipset support : Windows and Linux without nftables and ipset kernel modules (Android, for example).\n\n### WIFI filtering\n\nWifi interface name is not related to connected SSID.\nIt's possible to connect interface to different SSIDs.\nThey may require different strategies. How to solve this problem ?\n\nYou can run and stop nfqws instances manually. But you can also automate this.\nWindows version `winws` has global filter `--ssid-filter`.\nIt connects or disconnects `winws` depending on connected SSIDs.\nRouting is not take into account. This approach is possible because windivert can have multiple handlers with intersecting filter.\nIf SSID changes one `winws` connects and others disconnect.\n\n`winws` solution is hard to implement in Linux because one nfqueue can have only one handler and it's impossible to pass same traffic to multiple queues.\nOne must connect when others have already disconnected.\nInstead, `nfqws` has per-profile `--filter-ssid` parameter. Like `--ssid-filter` it takes comma separated SSID list.\n`nfqws` maintains ifname-\u003eSSID list which is updated not faster than once a second.\nWhen a packet comes incoming or outgoing interface name is matched to the SSID and then used in profile selection algorithm.\n\nSSID info is taken the same way as `iw dev \u003cifname\u003e info` does (nl80211).\nUnfortunately it's broken since kernel 5.19 and still unfixed in 6.14.\nIn the latter case `iwgetid` way is used (wireless extensions).\nWireless extensions are deprecated. Some kernels can be built without wext support.\nBefore using `--filter-ssid` check that any of the mentioned commands can return SSID.\n\n### Virtual machines\n\nMost of nfqws packet magic does not work from VMs powered by virtualbox and vmware when network is NATed.\nHypervisor forcibly changes TTL and does not forward fake packets.\nSet up bridge networking.\n\n### IPTABLES for nfqws\n\n\u003e [!CAUTION]\n\u003e Starting from Linux kernel 6.17 there's CONFIG_NETFILTER_XTABLES_LEGACY parameter which is not set by default. Many distributions will likely not turn it on making iptables-legacy non working. This is part of iptables deprecation. However iptables-nft still works because their backend is based on nftables.\n\nThis is the common way to redirect some traffic to nfqws :\n\n```\niptables -t mangle -I POSTROUTING -o \u003cwan_interface\u003e -p tcp -m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass\n```\n\nThis variant works if DPI is stateful and does not track all packets separately in search for \"bad requests\". If it's stateless you have to redirect all outgoing plain http packets.\n\n```\niptables -t mangle -I POSTROUTING -o \u003cwan_interface\u003e -p tcp --dport 443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass\niptables -t mangle -I POSTROUTING -o \u003cwan_interface\u003e -p tcp --dport 80 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass\n```\n\nmark bit is used to prevent loops. **nfqws** sets this mark in each injected packet.\nIt's also necessary for correct injected packet ordering and for deadlock prevention.\n\n`autottl` requires incoming `SYN,ACK` packet or first reply packet (it's usually the same). \n\n`autohostlist` needs incoming `RST` and `http redirect`.\n\nIt's possible to build tcp flags and u32 based filter but connbytes is easier.\n\n`\niptables -t mangle -I PREROUTING -i \u003cwan_interface\u003e -p tcp -m multiport --sports 80,443 -m connbytes --connbytes-dir=reply --connbytes-mode=packets --connbytes 1:3 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass\n`\n\nFor QUIC :\n\n```\niptables -t mangle -I POSTROUTING -o \u003cwan_interface\u003e -p udp --dport 443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass\n```\n\n6 packets cover possible retransmissions of quic initials and feed `autohostlist` mode.\n\n### NFTABLES for nfqws\n\nThis is the start configuration :\n\n```\nIFACE_WAN=wan\n\nnft create table inet ztest\n\nnft add chain inet ztest post \"{type filter hook postrouting priority mangle;}\"\nnft add rule inet ztest post oifname $IFACE_WAN meta mark and 0x40000000 == 0 tcp dport \"{80,443}\" ct original packets 1-6 queue num 200 bypass\nnft add rule inet ztest post oifname $IFACE_WAN meta mark and 0x40000000 == 0 udp dport 443 ct original packets 1-6 queue num 200 bypass\n\n# auto hostlist with avoiding wrong ACK numbers in RST,ACK packets sent by russian DPI\nsysctl net.netfilter.nf_conntrack_tcp_be_liberal=1 \nnft add chain inet ztest pre \"{type filter hook prerouting priority filter;}\"\nnft add rule inet ztest pre iifname $IFACE_WAN tcp sport \"{80,443}\" ct reply packets 1-3 queue num 200 bypass\n```\n\nTo engage `datanoack` or `ipfrag` for passthrough traffic special POSTNAT configuration is required. Generated packets must be marked as **notrack** in the early stage to avoid being invalidated by linux conntrack.\n\n```\nIFACE_WAN=wan\n\nnft create table inet ztest\n\nnft add chain inet ztest postnat \"{type filter hook postrouting priority srcnat+1;}\"\nnft add rule inet ztest postnat oifname $IFACE_WAN meta mark and 0x40000000 == 0 tcp dport \"{80,443}\" ct original packets 1-6 queue num 200 bypass\nnft add rule inet ztest postnat oifname $IFACE_WAN meta mark and 0x40000000 == 0 udp dport 443 ct original packets 1-6 queue num 200 bypass\n\nnft add chain inet ztest predefrag \"{type filter hook output priority -401;}\"\nnft add rule inet ztest predefrag \"mark \u0026 0x40000000 != 0x00000000 notrack\"\n```\n\nDelete nftable :\n\n```\nnft delete table inet ztest\n```\n\n### Flow offloading\n\nIf your device supports flow offloading (hardware acceleration) iptables and nftables may not work. With offloading enabled packets bypass standard netfilter flow. It must be either disabled or selectively controlled.\n\nNewer linux kernels have software flow offloading (SFO). The story is the same with SFO.\n\nIn `iptables` flow offloading is controlled by openwrt proprietary extension `FLOWOFFLOAD`. Newer `nftables` implement built-in offloading support.\n\nFlow offloading does not interfere with **tpws** and `OUTPUT` traffic. It only breaks nfqws that fools `FORWARD` traffic.\n\n### Server side fooling\n\nIt's also possible.\nnfqws is intended for client side attacks. That's why it recognizes direct and reply traffic based on role in connection establishement.\nIf it sees SYN then source IP is client IP. If it sees SYN,ACK then source ip is server IP.\nFor UDP client address is considered as source IP of the first seen packet of src_ip,src_port,dst_ip,dst_port tuple.\n\nThis does not work correctly on the server side. Client traffic is reply traffic, server traffic is direct traffic.\n\n`--wsize` works in any case. It can be used on both client and server.\nOther techs work only if nfqws treats traffic as direct traffic.\nTo apply them to server originated traffic disable conntrack by `--ctrack-disable` parameter.\nIf a packet is not found in conntrack it's treated as direct and techs like `multidisorder` will be applied.\n\nMost of the protocols will not be recognized because protocol recognition system only reacts to client packets.\nTo make things working use `--dpi-desync-any-protocol` with connbytes or packet payload limiter.\nstart/cutoff are unavailable because they are conntrack based.\n\n`--synack-split` removes standard SYN,ACK packet and replaces it with one SYN packet, SYN then ACK separate packets or ACK then SYN separate packets.\nClient sends SYN,ACK in reply which usually only server does.\nThis makes some DPI's to treat connection establishement roles wrong. They stop to block.\nSee [split handshake](https://nmap.org/misc/split-handshake.pdf).\n\nOn server side traffic should be redirected to nfqws using source port numbers and original connbytes direction.\n\n\n## tpws\n\ntpws is transparent proxy.\n\n```\n @\u003cconfig_file\u003e                          ; read file for options. must be the only argument. other options are ignored.\n\n --debug=0|1|2|syslog|@\u003cfilename\u003e        ; 1 and 2 means log to console and set debug level. for other targets use --debug-level.\n --debug-level=0|1|2                     ; specify debug level for syslog and @\u003cfilename\u003e\n --dry-run                               ; verify parameters and exit with code 0 if successful\n --version                                      ; print version and exit\n --bind-addr=\u003cv4_addr\u003e|\u003cv6_addr\u003e         ; for v6 link locals append %interface_name : fe80::1%br-lan\n --bind-iface4=\u003cinterface_name\u003e          ; bind to the first ipv4 addr of interface\n --bind-iface6=\u003cinterface_name\u003e          ; bind to the first ipv6 addr of interface\n --bind-linklocal=no|unwanted|prefer|force\n                                         ; no : bind only to global ipv6\n                                         ; unwanted (default) : prefer global address, then LL\n                                         ; prefer : prefer LL, then global\n                                         ; force : LL only\n --bind-wait-ifup=\u003csec\u003e                  ; wait for interface to appear and up\n --bind-wait-ip=\u003csec\u003e                    ; after ifup wait for ip address to appear up to N seconds\n --bind-wait-ip-linklocal=\u003csec\u003e          ; accept only link locals first N seconds then any\n --bind-wait-only                        ; wait for bind conditions satisfaction then exit. return code 0 if success.\n --connect-bind-addr=\u003cv4_addr\u003e|\u003cv6_addr\u003e ; address for outbound connections. for v6 link locals append %%interface_name\n --port=\u003cport\u003e                           ; port number to listen on\n --socks                                 ; implement socks4/5 proxy instead of transparent proxy\n --local-rcvbuf=\u003cbytes\u003e                  ; SO_RCVBUF for local legs\n --local-sndbuf=\u003cbytes\u003e                  ; SO_SNDBUF for local legs\n --remote-rcvbuf=\u003cbytes\u003e                 ; SO_RCVBUF for remote legs\n --remote-sndbuf=\u003cbytes\u003e                 ; SO_SNDBUF for remote legs\n --nosplice                              ; do not use splice to transfer data between sockets\n --skip-nodelay                          ; do not set TCP_NODELAY for outgoing connections. incompatible with split.\n --local-tcp-user-timeout=\u003cseconds\u003e      ; set tcp user timeout for local leg (default : 10, 0 = system default)\n --remote-tcp-user-timeout=\u003cseconds\u003e     ; set tcp user timeout for remote leg (default : 20, 0 = system default)\n --fix-seg=\u003cint\u003e                         ; recover failed TCP segmentation at the cost of slowdown. wait up to N msec.\n --ipcache-lifetime=\u003cint\u003e                ; time in seconds to keep cached domain name (default 7200). 0 = no expiration\n --ipcache-hostname=[0|1]                ; 1 or no argument enables ip-\u003ehostname caching\n --no-resolve                            ; disable socks5 remote dns\n --resolver-threads=\u003cint\u003e                ; number of resolver worker threads\n --maxconn=\u003cmax_connections\u003e             ; max number of local legs\n --maxfiles=\u003cmax_open_files\u003e             ; max file descriptors (setrlimit). min requirement is (X*connections+16), where X=6 in tcp proxy mode, X=4 in tampering mode.\n                                         ; its worth to make a reserve with 1.5 multiplier. by default maxfiles is (X*connections)*1.5+16\n --max-orphan-time=\u003csec\u003e                 ; if local leg sends something and closes and remote leg is still connecting then cancel connection attempt after N seconds\n\n --new                                   ; begin new strategy (new profile)\n --skip                                  ; do not use this profile\n --filter-l3=ipv4|ipv6                   ; L3 protocol filter. multiple comma separated values allowed.\n --filter-tcp=[~]port1[-port2]|*         ; TCP port filter. ~ means negation. comma separated list supported.\n --filter-l7=[http|tls|unknown]          ; L6-L7 protocol filter. multiple comma separated values allowed.\n --ipset=\u003cfilename\u003e                      ; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n --ipset-ip=\u003cip_list\u003e                    ; comma separated fixed subnet list\n --ipset-exclude=\u003cfilename\u003e              ; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n --ipset-exclude-ip=\u003cip_list\u003e            ; comma separated fixed subnet list\n\n --hostlist=\u003cfilename\u003e                   ; only act on hosts in the list (one host per line, subdomains auto apply if not prefixed with '^', gzip supported, multiple hostlists allowed)\n --hostlist-domains=\u003cdomain_list\u003e        ; comma separated fixed domain list\n --hostlist-exclude=\u003cfilename\u003e           ; do not act on hosts in the list (one host per line, subdomains auto apply if not prefixed with '^', gzip supported, multiple hostlists allowed)\n --hostlist-exclude-domains=\u003cdomain_list\u003e ; comma separated fixed domain list\n --hostlist-auto=\u003cfilename\u003e              ; detect DPI blocks and build hostlist automatically\n --hostlist-auto-fail-threshold=\u003cint\u003e    ; how many failed attempts cause hostname to be added to auto hostlist (default : 3)\n --hostlist-auto-fail-time=\u003cint\u003e         ; all failed attemps must be within these seconds (default : 60)\n --hostlist-auto-debug=\u003clogfile\u003e         ; debug auto hostlist positives\n\n --split-pos=N|-N|marker+N|marker-N      ; comma separated list of split positions\n                                         ; markers: method,host,endhost,sld,endsld,midsld,sniext  \n --split-any-protocol                    ; split not only http and TLS\n --disorder[=http|tls]                   ; when splitting simulate sending second fragment first\n --oob[=http|tls]                        ; when splitting send out of band byte. default is HEX 0x00.\n --oob-data=\u003cchar\u003e|0xHEX                 ; override default 0x00 OOB byte.\n --hostcase                              ; change Host: =\u003e host:\n --hostspell                             ; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n --hostdot                               ; add \".\" after Host: name\n --hosttab                               ; add tab after Host: name\n --hostnospace                           ; remove space after Host:\n --hostpad=\u003cbytes\u003e                       ; add dummy padding headers before Host:\n --domcase                               ; mix domain case after Host: like this : TeSt.cOm\n --methodspace                           ; add extra space after method\n --methodeol                             ; add end-of-line before method\n --unixeol                               ; replace 0D0A to 0A\n --tlsrec=N|-N|marker+N|marker-N         ; make 2 TLS records. split at specified logical part. don't split if SNI is not present.\n --tlsrec-pos=\u003cpos\u003e                      ; make 2 TLS records. split at specified pos\n --mss=\u003cint\u003e                             ; set client MSS. forces server to split messages but significantly decreases speed !\n --tamper-start=[n]\u003cpos\u003e                 ; start tampering only from specified outbound stream position. byte pos or block number ('n'). default is 0.\n --tamper-cutoff=[n]\u003cpos\u003e                ; do not tamper anymore after specified outbound stream position. byte pos or block number ('n'). default is unlimited.\n --daemon                                ; daemonize\n --pidfile=\u003cfilename\u003e                    ; write pid to file\n --user=\u003cusername\u003e                       ; drop root privs\n --uid=uid[:gid1,gid2,...]               ; drop root privs\n```\n\n### TCP segmentation in tpws\n\n**tpws** like **nfqws** supports multiple splits. Split [markers](#tcp-segmentation) are specified in `--split-pos` parameter.\n\nOn the socket level there's no guaranteed way to force OS to send pieces of data in separate packets. OS has a send buffer for each socket. If `TCP_NODELAY` socket option is enabled and send buffer is empty OS will likely send data immediately. If send buffer is not empty OS will coalesce it with new data and send in one packet if possible.\n\nIn practice outside of massive transmissions it's usually enough to enable `TCP_NODELAY` and use separate `send()` calls to force custom TCP segmentation. But if there're too many split segments Linux can combined some pieces and break desired behaviour. BSD and Windows are more predictable in this case. That's why it's not recommended to use too many splits. Tests revealed that 8+ can become problematic.\n\nSince linux kernel 4.6 **tpws** can recognize TCP segmentation failures and warn about them. `--fix-seg` can fix segmentation failures at the cost of some slowdown. It waits for several msec until all previous data is sent. This breaks async processing model and slows down every other connection going through **tpws**. Thus it's not recommended on highly loaded systems. But can be compromise for home systems.\n\nIf you're attempting to split massive transmission with `--split-any-protocol` option it will definitely cause massive segmentation failures. Do not do that without `--tamper-start` and `--tamper-cutoff` limiters.\n\n**tpws** works on socket level and receives in one shot long requests (TLS with kyber) that should normally require several TCP packets. It tampers entire received block without knowing how much packets it will take. OS will do additional segmenation to meet MTU.\n\n`--disorder` sends every odd packet with TTL=1. Server receives even packets fastly. Then client OS retransmits odd packets with normal TTL and server receives them. In case of 6 segments server and DPI will see them in this order : `2 4 6 1 3 5`. This way of disorder causes some delays. Default retransmission timeout in Linux is 200 ms.\n\n`--oob` sends one out-of-band byte in the end of the first split segment.\n\n`--oob` and `--disorder` can be combined only in Linux. Others OS do not handle this correctly.\n\n### TLSREC\n\n`--tlsrec` allow to split TLS ClientHello into 2 TLS records in one TCP segment. It accepts single pos marker.\n\n`--tlsrec` breaks significant number of sites. Crypto libraries on servers usually accept fine modified ClientHello but middleboxes such as CDNs and ddos guards - not always. Use of `--tlsrec` without filters is discouraged.\n\n### MSS\n\n`--mss` sets TCP_MAXSEG socket option. Client sets this value in MSS TCP option in the SYN packet.\nServer replies with it's own MSS in SYN,ACK packet. Usually servers lower their packet sizes but they still don't fit to supplied MSS. The greater MSS client sets the bigger server's packets will be.\nIf it's enough to split TLS 1.2 ServerHello, it may fool DPI that checks certificate domain name.\nThis scheme may significantly lower speed. Hostlist filter is possible only in socks mode if client uses remote resolving (firefox `network.proxy.socks_remote_dns`) or if `ipcache-hostname` is enabled.\n`--mss` is not required for TLS1.3. If TLS1.3 is negotiable then MSS make things only worse. Use only if nothing better is available. Works only in Linux, not BSD or MacOS.\n\n### Other tamper options\n\n`--hostpad=\u003cbytes\u003e` adds padding headers before `Host:` with specified number of bytes. If `\u003cbytes\u003e` is too large headers are split by 2K. Padding more that 64K is not supported and not accepted by http servers.\n\nIt's useful against stateful DPI's that reassemble only limited amount of data. Increase padding `\u003cbytes\u003e` until website works. If minimum working `\u003cbytes\u003e` is close to MTU then it's likely DPI is not reassembling packets. Then it's better to use regular split instead of `--hostpad`.\n\n### Supplementary options\n\n**tpws** can bind to multiple interfaces and IP addresses (up to 32).\n\nPort number is always the same.\n\nParameters `--bind-iface*` and `--bind-addr` create new bind.\n\nOther parameters `--bind-*` are related to the last bind.\n\nlink local ipv6 (`fe80::/8`) mode selection :\n\n```\n--bind-iface6 --bind-linklocal=no : first selects private address fc00::/7, then global address\n--bind-iface6 --bind-linklocal=unwanted : first selects private address fc00::/7, then global address, then LL\n--bind-iface6 --bind-linklocal=prefer : first selects LL, then private address fc00::/7, then global address\n--bind-iface6 --bind-linklocal=force : select only LL\n```\n\nTo bind to all ipv4 specify `--bind-addr \"0.0.0.0\"`, all ipv6 - `::`. \n\n`--bind-addr=\"\"` - mean bind to all ipv4 and ipv6.\n\nIf no binds are specified default bind to all ipv4 and ipv6 addresses is created.\n\nTo bind to a specific link local address do : `--bind-iface6=fe80::aaaa:bbbb:cccc:dddd%iface-name`\n\nThe `--bind-wait*` parameters can help in situations where you need to get IP from the interface, but it is not there yet, it is not raised\nor not configured.\n\nIn different systems, ifup events are caught in different ways and do not guarantee that the interface has already received an IP address of a certain type.\n\nIn the general case, there is no single mechanism to hang oneself on an event of the type \"link local address appeared on the X interface.\"\n\nTo bind to a specific ip when its interface may not be configured yet do : `--bind-addr=192.168.5.3 --bind-wait-ip=20`\n\nIt's possible to bind to any nonexistent address in transparent mode but in socks mode address must exist.\n\nIn socks proxy mode no additional system privileges are required. Connections to local IPs of the system where **tpws** runs are prohibited.\ntpws supports remote dns resolving (curl : `--socks5-hostname`  firefox : `socks_remote_dns=true`) , but does it in blocking mode.\n\n**tpws** uses async sockets for all activities. Domain names are resolved in multi threaded pool.\nResolving does not freeze other connections. But if there're too many requests resolving delays may increase.\nNumber of resolver threads is choosen automatically proportinally to `--maxconn` and can be overriden using `--resolver-threads`.\nTo disable hostname resolve use `--no-resolve` option.\n\n### Multiple strategies\n\n**tpws** like **nfqws** supports multiple strategies. They work mostly like with **nfqws** with minimal differences.\n`filter-udp` is absent because **tpws** does not support udp. 0-phase desync methods (`--mss`) can work with hostlist in socks modes with remote hostname resolve.\nThis is the point where you have to plan profiles carefully. If you use `--mss` and hostlist filters, behaviour can be different depending on remote resolve feature enabled or not.\nUse `--mss` both in hostlist profile and profile without hostlist.\nUse `curl --socks5` and `curl --socks5-hostname` to issue two kinds of proxy queries.\nSee `--debug` output to test your setup.\n\n### IPTABLES for tpws\n\nUse the following rules to redirect TCP connections to 'tpws' :\n```\niptables -t nat -I OUTPUT -o \u003cwan_interface\u003e -p tcp --dport 80 -m owner ! --uid-owner tpws -j DNAT --to 127.0.0.127:988\niptables -t nat -I PREROUTING -i \u003clan_interface\u003e -p tcp --dport 80 -j DNAT --to 127.0.0.127:988\n```\n\nFirst rule redirects outgoing from the same system traffic, second redirects passthrough traffic.\n\nDNAT to localhost works only in the **OUTPUT** chain and does not work in the **PREROUTING** chain without setting this sysctl :\n\n`sysctl -w net.ipv4.conf.\u003clan_interface\u003e.route_localnet=1`\n\nIt's also possible to use `-j REDIRECT --to-port 988` instead of DNAT but in the latter case transparent proxy must listen on all IP addresses or on a LAN interface address. It's not too good to listen on all IP and it's not trivial to get specific IP in a shell script. `route_localnet` has it's own security impact if not protected by additional rules. You open `127.0.0.0/8` subnet to the net.\n\nThis is how to open only single `127.0.0.127` address :\n```\niptables -A INPUT ! -i lo -d 127.0.0.127 -j ACCEPT\niptables -A INPUT ! -i lo -d 127.0.0.0/8 -j DROP\n```\n\nOwner filter is required to avoid redirection loops. **tpws** must be run with `--user tpws` parameter.\n\nip6tables work almost the same with minor differences. ipv6 addresses should be enclosed in square brackets :\n```\nip6tables -t nat -I OUTPUT -o \u003cwan_interface\u003e -p tcp --dport 80 -m owner ! --uid-owner tpws -j DNAT --to [::1]:988\n```\n\nThere's no `route_localnet` for ipv6. DNAT to localhost (`::1`) is possible only in **OUTPUT** chain. In **PREROUTING** chain DNAT is possible to any global address or link local address of the interface where packet came from.\n\n### NFTABLES for tpws\n\nBase nftables scheme :\n```\nIFACE_WAN=wan\nIFACE_LAN=br-lan\n\nsysctl -w net.ipv4.conf.$IFACE_LAN.route_localnet=1\n\nnft create table inet ztest\n\nnft create chain inet ztest localnet_protect\nnft add rule inet ztest localnet_protect ip daddr 127.0.0.127 return\nnft add rule inet ztest localnet_protect ip daddr 127.0.0.0/8 drop\nnft create chain inet ztest input \"{type filter hook input priority filter - 1;}\"\nnft add rule inet ztest input iif != \"lo\" jump localnet_protect\n\nnft create chain inet ztest dnat_output \"{type nat hook output priority dstnat;}\"\nnft add rule inet ztest dnat_output meta skuid != tpws oifname $IFACE_WAN tcp dport { 80, 443 } dnat ip to 127.0.0.127:988\nnft create chain inet ztest dnat_pre \"{type nat hook prerouting priority dstnat;}\"\nnft add rule inet ztest dnat_pre meta iifname $IFACE_LAN tcp dport { 80, 443 } dnat ip to 127.0.0.127:988\n```\n\nDelete nftable :\n```\nnft delete table inet ztest\n```\n\n\n## Ways to get a list of blocked IP\n\nnftables can't work with ipsets. Native nf sets require lots of RAM to load large ip lists with subnets and intervals.\nIn case you're on a low RAM system and need large lists it may be required to fall back to iptables+ipset.\n\n1. Enter the blocked domains to `ipset/zapret-hosts-user.txt` and run `ipset/get_user.sh`\nAt the output, you get `ipset/zapret-ip-user.txt` with IP addresses.\n\n2. `ipset/get_reestr_*.sh`. Russian specific\n\n3. `ipset/get_antifilter_*.sh`. Russian specific\n\n4. `ipset/get_config.sh`. This script calls what is written into the GETLIST variable from the config file.\n\nIf the variable is not defined, then only lists for ipsets nozapret/nozapret6 are resolved.\n\nSo, if you're not russian, the only way for you is to manually add blocked domains.\nOr write your own `ipset/get_iran_blocklist.sh` , if you know where to download this one.\n\nOn routers, it is not recommended to call these scripts more than once in 2 days to minimize flash memory writes.\n\n`ipset/create_ipset.sh` executes forced ipset update.\nWith `no-update` parameter `create_ipset.sh` creates ipset but populate it only if it was actually created.\n\nIt's useful when multiple subsequent calls are possible to avoid wasting of cpu time redoing the same job.\n\nIpset loading is resource consuming. Its a good idea to call create_ipset without `no-update` parameter\n\nonly once a several days. Use it with `no-update` option in other cases.\n\nipset scripts automatically call ip2net utility.\nip2net helps to reduce ip list size by combining IPs to subnets. Also it cuts invalid IPs from the list.\nStored lists are already processed by ip2net. They are error free and ready for loading.\n\n`create_ipset.sh` supports loading ip lists from gzip files. First it looks for the filename with the \".gz\" extension,\nsuch as `zapret-ip.txt.gz`, if not found it falls back to the original name `zapret-ip.txt`.\n\nSo your own get_iran_blockslist.sh can use \"zz\" function to produce gz. Study how other russian `get_XXX.sh` work.\n\nGzipping helps saving a lot of precious flash space on embedded systems.\n\nUser lists are not gzipped because they are not expected to be very large.\n\nYou can add a list of domains to `ipset/zapret-hosts-user-ipban.txt`. Their ip addresses will be placed\nin a separate ipset \"ipban\". It can be used to route connections to transparent proxy \"redsocks\" or VPN.\n\nIPV6: if ipv6 is enabled, then additional txt's are created with the same name, but with a \"6\" at the end before the extension.\n\n`zapret-ip.txt` =\u003e `zapret-ip6.txt`\n\nThe ipsets zapret6 and ipban6 are created.\n\nIP EXCLUSION SYSTEM. All scripts resolve `zapret-hosts-user-exclude.txt` file, creating `zapret-ip-exclude.txt` and `zapret-ip-exclude6.txt`.\n\nThey are the source for ipsets nozapret/nozapret6. All rules created by init scripts are created with these ipsets in mind.\nThe IPs placed in them are not involved in the process.\nzapret-hosts-user-exclude.txt can contain domains, ipv4 and ipv6 addresses or subnets.\n\nFreeBSD. `ipset/*.sh` scripts also work in FreeBSD. Instead of ipset they create ipfw lookup tables with the same names as in Linux.\nipfw tables can store both ipv4 and ipv6 addresses and subnets. There's no 4 and 6 separation.\n\nLISTS_RELOAD config parameter defines a custom lists reloading command.\nIts useful on BSD systems with PF.\nLISTS_RELOAD=-  disables reloading ip list backend.\n\n## Domain name filtering\n\nAn alternative to ipset is to use **tpws** or **nfqws** with a list(s) of domains.\nBoth **tpws** and **nfqws** take any number of include (`--hostlist`) and exclude (`--hostlist-exclude`) domain lists.\nAll lists of the same type are combined internally leaving only 2 lists : include and exclude.\n\nExclude list is checked first. Fooling is cancelled if domain belongs to exclude list.\nIf include list is present and domain does not belong to that list fooling is also cancelled.\nEmpty list means absent list. Otherwise fooling goes on.\n\nLaunch system looks for 2 include lists :\n\n`ipset/zapret-hosts-users.txt.gz` or `ipset/zapret-hosts-users.txt`\n\n`ipset/zapret-hosts.txt.gz` or `ipset/zapret-hosts.txt`\n\nand 1 exclude list\n\n`ipset/zapret-hosts-users-exclude.txt.gz` or `ipset/zapret-hosts-users-exclude.txt`\n\nIf `MODE_FILTER=hostlist` all present lists are passed to **nfqws** or **tpws**.\nIf all include lists are empty it works like no include lists exist at all.\nIf you need \"all except\" mode you dont have to delete zapret-hosts-users.txt. Just make it empty.\n\nSubdomains auto apply. For example, \"ru\" in the list affects \"\\*.ru\" .\n`^` prefix symbol disables subdomain match.\n\n**tpws** and **nfqws** automatically reload lists if their modification time or file size is changed.\nHUP signal forcibly reloads all lists.\n\nWhen filtering by domain name, daemons should run without filtering by ipset.\nWhen using large regulator lists estimate the amount of RAM on the router !\n\n## **autohostlist** mode\n\nThis mode analyzes both client requests and server replies.\nIf a host is not in any list and a situation similar to block occurs host is automatically added to the special list both in memory and file.\nUse exclude hostlist to prevent autohostlist triggering.\nIf it did happen - delete the undesired record from the file.\n\nIn case of nfqws it's required to redirect both incoming and outgoing traffic to the queue.\nIt's strongly recommended to use connbytes filter or nfqws will process gigabytes of incoming traffic.\nFor the same reason it's not recommended to use autohostlist mode in BSDs. BSDs do not support connbytes or similar mechanism.\n\n**nfqws** и **tpws** detect the folowing situations :\n1) [nfqws] Multiple retransmissions of the first request inside a TCP session having host.\n2) [nfqws,tpws] RST in response to the first request.\n3) [nfqws,tpws] HTTP redirect in response to the first http request with 2nd level domain diferent from the original.\n4) [tpws] Client closes connection after first request without having server reply (no reponse from server, timeout).\n\nTo minimize false positives there's fail counter. If in specific time occurs more than specified number of fails\nthe host is added to the list. Then DPI bypass strategy start to apply immediately.\n\nFor the user autohostlist mode looks like this.\nWhen for the first time user visits a blocked website it sees block page, connection reset\nor browser hangs until timeout, then display a error.\nUser presses multiple times F5 causing browser to retry attempts.\nAfter some retries a website opens and next time works as expected.\n\nWith autohostlist mode it's possible to use bypass strategies that break lots of sites.\nIf a site does not behave like blocked no fooling applies.\nOtherwise it's nothing to lose.\n\nHowever false positives still can occur in case target website is behaving abnormally\n(may be due to DDoS attack or server malfunction). If it happens bypass strategy\nmay start to break the website. This situation can only be controlled manually.\nRemove undesired domain from the autohostlist file.\nUse exclude hostlist to prevent further auto additions.\n\nIt's possible to use one auto hostlist with multiple processes. All processes check for file modification time.\nIf a process modified autohostlist, all others will reread it automatically.\nAll processes must run with the same uid.\n\nIf zapret scripts are used then autohostlist is `ipset/zapret-hosts-auto.txt`\nand exlude list is `ipset/zapret-hosts-user-exclude.txt`. autohostlist mode\nincludes hostlist mode. You can use `ipset/zapret-hosts-user.txt`.\n\n\n## Choosing parameters\n\nThe file `/opt/zapret/config` is used by various components of the system and contains basic settings.\nIt needs to be viewed and edited if necessary.\n\nWhich firewall type use on linux systems : `nftables` or `iptables`.\nOn traditional systems `nftables` is selected by default if `nft` is installed.\nOn openwrt by default `nftables` is selected on `firewall4` based systems.\n\n`FWTYPE=iptables`\n\nWith `nftables` post-NAT scheme is used by default. It allows more DPI attacks on forwarded traffic.\nIt's possible to use `iptables`-like pre-NAT scheme. **nfqws** will see client source IPs and display them in logs.\n\n`#POSTNAT=0`\n\nThere'are 3 standard options configured separately and independently : `tpws-socks`, **tpws**, **nfqws**.\nThey can be used alone or combined. Custom scripts in `init.d/{sysv,openwrt,macos}/custom.d` are always applied.\n\n`tpws-socks` requires daemon parameter configuration but does not require traffic interception.\nOther standard options require also traffic interception.\nEach standard option launches single daemon instance. Strategy differiences are managed using multi-profile scheme.\nMain rule for interception is \"intercept required minumum\". Everything else only wastes CPU resources and slows down connection.\n\n`--ipset` option is prohibited intentionally to disallow easy to use but ineffective user-mode filtering.\nUse kernel ipsets instead. It may require custom scripts.\n\nTo use standard updatable hostlists from the `ipset` dir use `\u003cHOSTLIST\u003e` placeholder. It's automatically replaced\nwith hostlist parameters if `MODE_FILTER` variable enables hostlists and is removed otherwise.\nStandard hostlists are expected in final (fallback) strategies closing groups of filter parameters.\nDon't use `\u003cHOSTLIST\u003e` in highly specialized profiles. Use your own filter or hostlist(s).\n`\u003cHOSTLIST_NOAUTO\u003e` marker uses standard autohostlist as usual hostlist thus disabling auto additions in this profile.\nIf any other profile adds something this profile accepts the change automatically.\n\nChange loop prevention mark bit\n\n`DESYNC_MARK=0x40000000`\n\nChange postnat scheme mark bit\n\n`DESYNC_MARK_POSTNAT=0x20000000`\n\nIf uncommented pass to zapret only packets marked with this bit\n\n`#FILTER_MARK=0x10000000`\n\nBit must be set in your own rules.\n* iptables - in mangle PREROUTING and mangle OUTPUT before zapret rules (iptables -I _after_ zapret rules application).\n* nftables - in output and prerouting hooks with priority -102 or lower.\n\nMark criterias can be any. For example, source IP or source interface name.\n\n**tpws** socks proxy mode switch\n\n`TPWS_SOCKS_ENABLE=0`\n\nListening tcp port for **tpws** proxy mode.\n\n`TPPORT_SOCKS=987`\n\n**tpws** socks mode parameters\n\n```\nTPWS_SOCKS_OPT=\"\n--filter-tcp=80 --methodeol \u003cHOSTLIST\u003e --new\n--filter-tcp=443 --split-pos=1,midsld --disorder \u003cHOSTLIST\u003e\"\n\"\n```\n\n**tpws** transparent mode switch\n\n`TPWS_ENABLE=0`\n\n**tpws** transparent mode target ports\n\n`TPWS_PORTS=80,443`\n\n**tpws** transparent mode parameters\n\n```\nTPWS_OPT=\"\n--filter-tcp=80 --methodeol \u003cHOSTLIST\u003e --new\n--filter-tcp=443 --split-pos=1,midsld --disorder \u003cHOSTLIST\u003e\"\n\"\n```\n\n**nfqws** enable switch\n\n`NFQWS_ENABLE=0`\n\n**nfqws** port targets for `connbytes`-limited interception. `connbytes` allows to intercept only starting packets from connections.\nThis is more effective kernel-mode alternative to `nfqws --dpi-desync-cutoff=nX`.\n\n```\nNFQWS_PORTS_TCP=80,443\nNFQWS_PORTS_UDP=443\n```\n\nHow many starting packets should be intercepted to nfqws in each direction\n\n```\nNFQWS_TCP_PKT_OUT=$((6+$AUTOHOSTLIST_RETRANS_THRESHOLD))\nNFQWS_TCP_PKT_IN=3\nNFQWS_UDP_PKT_OUT=$((6+$AUTOHOSTLIST_RETRANS_THRESHOLD))\nNFQWS_UDP_PKT_IN=0\n```\n\nThere's kind of traffic that requires interception of entire outgoing stream.\nTypically it's support for plain http keepalives and stateless DPI.\nThis mode of interception significantly increases CPU utilization. Use with care and only if required.\nHere you specify port numbers for unlimited interception.\nIt's advised also to remove these ports from `connbytes`-limited interception list.\n\n```\n#NFQWS_PORTS_TCP_KEEPALIVE=80\n#NFQWS_PORTS_UDP_KEEPALIVE=\n```\n\n**nfqws** parameters\n\n```\nNFQWS_OPT=\"\n--filter-tcp=80 --dpi-desync=fake,multisplit --dpi-desync-split-pos=method+2 --dpi-desync-fooling=md5sig \u003cHOSTLIST\u003e --new\n--filter-tcp=443 --dpi-desync=fake,multidisorder --dpi-desync-split-pos=1,midsld --dpi-desync-fooling=badseq,md5sig \u003cHOSTLIST\u003e --new\n--filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=6 \u003cHOSTLIST_NOAUTO\u003e\n\"\n```\n\n\nHost filtering mode :\n```\nnone - apply fooling to all hosts\nipset - limit fooling to hosts from ipset zapret/zapret6\nhostlist - limit fooling to hosts from hostlist\nautohostlist - hostlist mode + blocks auto detection\n```\n\n`MODE_FILTER=none`\n\n\nflow offloading control (if supported)\n\n```\ndonttouch : disable system flow offloading setting if selected mode is incompatible with it, dont touch it otherwise and dont configure selective flow offloading\nnone : always disable system flow offloading setting and dont configure selective flow offloading\nsoftware : always disable system flow offloading setting and configure selective software flow offloading\nhardware : always disable system flow offloading setting and configure selective hardware flow offloading\n```\n\n`FLOWOFFLOAD=donttouch`\n\nThe GETLIST parameter tells the install_easy.sh installer which script to call\nto update the list of blocked ip or hosts.\nIts called via `get_config.sh` from scheduled tasks (crontab or systemd timer).\nPut here the name of the script that you will use to update the lists.\nIf not, then the parameter should be commented out.\n\nYou can individually disable ipv4 or ipv6. If the parameter is commented out or not equal to \"1\",\nuse of the protocol is permitted.\n\n```\n#DISABLE_IPV4=1\nDISABLE_IPV6=1\n```\n\nThe number of threads for mdig multithreaded DNS resolver (1..100).\nThe more of them, the faster, but will your DNS server be offended by hammering ?\n\n`MDIG_THREADS=30`\n\ntemp directory. Used by ipset/*.sh scripts for large lists processing.\n/tmp by default. Can be reassigned if /tmp is tmpfs and RAM is low.\nTMPDIR=/opt/zapret/tmp\n\nipset and nfset options :\n\n```\nSET_MAXELEM=262144\nIPSET_OPT=\"hashsize 262144 maxelem 2097152\n```\n\nKernel automatically increases hashsize if ipset is too large for the current hashsize.\nThis procedure requires internal reallocation and may require additional memory.\nOn low RAM systems it can cause errors.\nDo not use too high hashsize. This way you waste your RAM. And dont use too low hashsize to avoid reallocs.\n\nip2net options. separate for ipv4 and ipv6.\n\n```\nIP2NET_OPT4=\"--prefix-length=22-30 --v4-threshold=3/4\"\nIP2NET_OPT6=\"--prefix-length=56-64 --v6-threshold=5\"\n```\n\nautohostlist mode tuning.\n\n```\nAUTOHOSTLIST_RETRANS_THRESHOLD=3\nAUTOHOSTLIST_FAIL_THRESHOLD=2\nAUTOHOSTLIST_FAIL_TIME=60\nAUTOHOSTLIST_DEBUG=0\n```\n\nEnable gzip compression for large lists. Used by ipset/*.sh scripts.\n\n`GZIP_LISTS=1`\n\nCommand to reload ip/host lists after update.\nComment or leave empty for auto backend selection : ipset or ipfw if present.\nOn BSD systems with PF no auto reloading happens. You must provide your own command.\nNewer FreeBSD versions support table only reloading : `pfctl -Tl -f /etc/pf.conf`\nSet to \"-\" to disable reload.\n\n`LISTS_RELOAD=\"pfctl -f /etc/pf.conf\"`\n\nIn openwrt there's default network `lan`. Only traffic coming from this network is redirected to tpws by default.\nTo override this behaviour set the following variable :\n\n`OPENWRT_LAN=\"lan lan2 lan3\"`\n\nIn openwrt wan interfaces are those having default route. Separately for ipv4 and ipv6.\nThis can be redefined :\n```\nOPENWRT_WAN4=\"wan4 vpn\"\nOPENWRT_WAN6=\"wan6 vpn6\"\n```\n\nThe `INIT_APPLY_FW=1` parameter enables the init script to independently apply iptables rules.\nWith other values or if the parameter is commented out, the rules will not be applied.\nThis is useful if you have a firewall management system, in the settings of which you should tie the rules.\nNot applicable to `OpenWRT` if used with `firewall3+iptables`.\n\n`FILTER_TTL_EXPIRED_ICMP=1` blocks icmp time exceeded messages in response to connections handled by nfqws.\nLinux closes socket if it receives this icmp in response to SYN packet. Similar mechanism exists for datagram sockets.\nIt's better to disable this if you do not expect problems caused by icmp.\n\nThe following settings are not relevant for openwrt :\n\nIf your system works as a router, then you need to enter the names of the internal and external interfaces:\n```\nIFACE_LAN=eth0\nIFACE_WAN=eth1\nIFACE_WAN6=\"henet ipsec0\"\n```\nMultiple interfaces are space separated. IF IFACE_WAN6 is omitted then IFACE_WAN value is taken.\n\nIMPORTANT: configuring routing, masquerade, etc. not a zapret task.\nOnly modes that intercept transit traffic are enabled.\nIt's possible to specify multiple interfaces like this : `IFACE_LAN=\"eth0 eth1 eth2\"`\n\n\n## Screwing to the firewall control system or your launch system\n\nIf you use some kind of firewall management system, then it may conflict with an existing startup script.\nWhen re-applying the rules, it could break the iptables settings from the zapret.\nIn this case, the rules for iptables should be screwed to your firewall separately from running tpws or nfqws.\n\nThe following calls allow you to apply or remove iptables rules separately:\n\n```\n /opt/zapret/init.d/sysv/zapret start_fw\n /opt/zapret/init.d/sysv/zapret stop_fw\n /opt/zapret/init.d/sysv/zapret restart_fw\n```\n\nAnd you can start or stop the demons separately from the firewall:\n\n```\n /opt/zapret/init.d/sysv/zapret start_daemons\n /opt/zapret/init.d/sysv/zapret stop_daemons\n /opt/zapret/init.d/sysv/zapret restart_daemons\n```\n\nnftables nearly eliminate conflicts betweeen firewall control systems because they allow\nseparate tables and netfilter hooks. `zapret` nf table is used for zapret purposes.\nIf your system does not touch it everything will likely be OK.\n\nSome additional nftables-only calls exist :\n\nLookup `lanif`, `wanif`, `wanif6` and `flow table` interface sets.\n```\n /opt/zapret/init.d/sysv/zapret list_ifsets\n```\n\nRenew `lanif`, `wanif`, `wanif6` and `flow table` interface sets.\nTaken from `IFACE_LAN`, `IFACE_WAN` config variables on traditional Linux systems.\nAutoselected on `OpenWRT`. `lanif` can be extended using `OPENWRT_LAN` config variable.\n```\n /opt/zapret/init.d/sysv/zapret reload_ifsets\n```\n\nCalls `nft -t list table inet zapret`.\n```\n /opt/zapret/init.d/sysv/zapret list_table\n```\n\nIt's also possible to hook with your script to any stage of zapret firewall processing.\nThe following settings are available in the zapret config file :\n\n```\nINIT_FW_PRE_UP_HOOK=\"/etc/firewall.zapret.hook.pre_up\"\nINIT_FW_POST_UP_HOOK=\"/etc/firewall.zapret.hook.post_up\"\nINIT_FW_PRE_DOWN_HOOK=\"/etc/firewall.zapret.hook.pre_down\"\nINIT_FW_POST_DOWN_HOOK=\"/etc/firewall.zapret.hook.post_down\"\n```\n\nHooks are extremely useful if you need nftables sets populated by zapret scripts.\nnfsets can only belong to one table. You have to write rule there and synchorize them with zapret scripts.\n\n## Installation\n\n### Checking ISP\n\nBefore running zapret you must discover working bypass strategy.\n`blockcheck.sh` automates this process. It first checks DNS then tries many strategies finding the working ones.\nNote that DNS check is mostly Russia targeted. It checks several pre-defined blocked in Russia domains and\nverifies system DNS answers with public DNS answers. Because ISP can block public DNS or redirect any DNS queries\nto their servers `blockcheck.sh` also checks that all returned answers are unique. Usually if DNS is blocked\nISP returns single ip for all blocked domains to redirect you to their \"access denied\" page.\nDoH servers are used automatically for checks if DNS spoof is detected.\n`blockcheck.sh` works on all systems supported by `zapret`.\n\n### desktop linux system\n\nSimple install works on most modern linux distributions with systemd or openrc, OpenWRT and MacOS.\nRun `install_easy.sh` and answer its questions.\n\n### OpenWRT\n\n`install_easy.sh` works on openwrt but there're additional challenges.\nThey are mainly about possibly low flash free space.\nSimple install will not work if it has no space to install itself and required packages from the repo.\n\nAnother challenge would be to bring zapret to the router. You can download zip from github and use it.\nInstall openssh-sftp-server and unzip to openwrt and use sftp to transfer the file.\nIt's also not too hard to use 'nc' (netcat) for file transfer.\n\nThe best way to start is to put zapret dir to `/tmp` and run `/tmp/zapret/install_easy.sh` from there.\nAfter installation remove `/tmp/zapret` to free RAM.\n\nThe absolute minimum for openwrt is 64/8 system, 64/16 is comfortable, 128/extroot is recommended.\n\nFor low storage openwrt see `init.d/openwrt-minimal`.\n\n### Android\n\nIts not possible to use **nfqws** and **tpws** in transparent proxy mode without root privileges. Wi","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbol-van%2Fzapret","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbol-van%2Fzapret","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbol-van%2Fzapret/lists"}