diff --git a/binaries/aarch64/nfqws b/binaries/aarch64/nfqws index d5adfec..98e2fb1 100755 Binary files a/binaries/aarch64/nfqws and b/binaries/aarch64/nfqws differ diff --git a/binaries/arm/nfqws b/binaries/arm/nfqws index ba7d969..2782026 100755 Binary files a/binaries/arm/nfqws and b/binaries/arm/nfqws differ diff --git a/binaries/freebsd-x64/dvtws b/binaries/freebsd-x64/dvtws index df06ed1..2b05289 100755 Binary files a/binaries/freebsd-x64/dvtws and b/binaries/freebsd-x64/dvtws differ diff --git a/binaries/mips32r1-lsb/nfqws b/binaries/mips32r1-lsb/nfqws index 7bf5c92..0a43cc2 100755 Binary files a/binaries/mips32r1-lsb/nfqws and b/binaries/mips32r1-lsb/nfqws differ diff --git a/binaries/mips32r1-msb/nfqws b/binaries/mips32r1-msb/nfqws index 3706349..ba14948 100755 Binary files a/binaries/mips32r1-msb/nfqws and b/binaries/mips32r1-msb/nfqws differ diff --git a/binaries/mips64r2-msb/nfqws b/binaries/mips64r2-msb/nfqws index 345cc7f..b1cb63d 100755 Binary files a/binaries/mips64r2-msb/nfqws and b/binaries/mips64r2-msb/nfqws differ diff --git a/binaries/ppc/nfqws b/binaries/ppc/nfqws index 73de3d9..0fd1147 100755 Binary files a/binaries/ppc/nfqws and b/binaries/ppc/nfqws differ diff --git a/binaries/win64/WinDivert.dll b/binaries/win64/WinDivert.dll new file mode 100644 index 0000000..50ca874 Binary files /dev/null and b/binaries/win64/WinDivert.dll differ diff --git a/binaries/win64/WinDivert64.sys b/binaries/win64/WinDivert64.sys new file mode 100644 index 0000000..218ccaf Binary files /dev/null and b/binaries/win64/WinDivert64.sys differ diff --git a/binaries/win64/ip2net.exe b/binaries/win64/ip2net.exe new file mode 100644 index 0000000..5796e9c Binary files /dev/null and b/binaries/win64/ip2net.exe differ diff --git a/binaries/win64/mdig.exe b/binaries/win64/mdig.exe new file mode 100644 index 0000000..8006737 Binary files /dev/null and b/binaries/win64/mdig.exe differ diff --git a/binaries/win64/readme.txt b/binaries/win64/readme.txt new file mode 100644 index 0000000..3923bc6 --- /dev/null +++ b/binaries/win64/readme.txt @@ -0,0 +1,9 @@ +Standalone version in zapret-winws folder !! +From this folder winws can be started only from cygwin shell. + +Cygwin refuses to start winws if a copy of cygwin1.dll is present ! + +How to get win7 and winws compatible version of cygwin : + +curl -O https://www.cygwin.com/setup-x86_64.exe +setup-x86_64.exe --allow-unsupported-windows --no-verify --site http://ctm.crouchingtigerhiddenfruitbat.org/pub/cygwin/circa/64bit/2024/01/30/231215 diff --git a/binaries/win64/winws.exe b/binaries/win64/winws.exe new file mode 100644 index 0000000..1b3b2a1 Binary files /dev/null and b/binaries/win64/winws.exe differ diff --git a/binaries/win64/zapret-winws/WinDivert.dll b/binaries/win64/zapret-winws/WinDivert.dll new file mode 100644 index 0000000..50ca874 Binary files /dev/null and b/binaries/win64/zapret-winws/WinDivert.dll differ diff --git a/binaries/win64/zapret-winws/WinDivert64.sys b/binaries/win64/zapret-winws/WinDivert64.sys new file mode 100644 index 0000000..218ccaf Binary files /dev/null and b/binaries/win64/zapret-winws/WinDivert64.sys differ diff --git a/binaries/win64/zapret-winws/cygwin1.dll b/binaries/win64/zapret-winws/cygwin1.dll new file mode 100644 index 0000000..1bb2e05 Binary files /dev/null and b/binaries/win64/zapret-winws/cygwin1.dll differ diff --git a/binaries/win64/zapret-winws/task_create.cmd b/binaries/win64/zapret-winws/task_create.cmd new file mode 100644 index 0000000..57fcce9 --- /dev/null +++ b/binaries/win64/zapret-winws/task_create.cmd @@ -0,0 +1,2 @@ +set WINWS1=--wf-l3=ipv4,ipv6 --wf-tcp=80,443 --dpi-desync=fake,split --dpi-desync-ttl=7 --dpi-desync-fooling=md5sig +schtasks /Create /F /TN winws1 /NP /RU "" /SC onstart /TR "\"%~dp0winws.exe\" %WINWS1%" diff --git a/binaries/win64/zapret-winws/task_remove.cmd b/binaries/win64/zapret-winws/task_remove.cmd new file mode 100644 index 0000000..f4c94aa --- /dev/null +++ b/binaries/win64/zapret-winws/task_remove.cmd @@ -0,0 +1,2 @@ +schtasks /End /TN winws1 +schtasks /Delete /TN winws1 /F diff --git a/binaries/win64/zapret-winws/task_start.cmd b/binaries/win64/zapret-winws/task_start.cmd new file mode 100644 index 0000000..e1bfc96 --- /dev/null +++ b/binaries/win64/zapret-winws/task_start.cmd @@ -0,0 +1 @@ +schtasks /Run /TN winws1 diff --git a/binaries/win64/zapret-winws/task_stop.cmd b/binaries/win64/zapret-winws/task_stop.cmd new file mode 100644 index 0000000..2d98ce8 --- /dev/null +++ b/binaries/win64/zapret-winws/task_stop.cmd @@ -0,0 +1 @@ +schtasks /End /TN winws1 diff --git a/binaries/win64/zapret-winws/winws.exe b/binaries/win64/zapret-winws/winws.exe new file mode 100644 index 0000000..65b8868 Binary files /dev/null and b/binaries/win64/zapret-winws/winws.exe differ diff --git a/binaries/x86/nfqws b/binaries/x86/nfqws index 2a5efe8..22e6f12 100755 Binary files a/binaries/x86/nfqws and b/binaries/x86/nfqws differ diff --git a/binaries/x86_64/nfqws b/binaries/x86_64/nfqws index 7b8d338..6e97add 100755 Binary files a/binaries/x86_64/nfqws and b/binaries/x86_64/nfqws differ diff --git a/blockcheck.sh b/blockcheck.sh index ce2567d..f257033 100755 --- a/blockcheck.sh +++ b/blockcheck.sh @@ -17,6 +17,7 @@ TPWS_UID=${TPWS_UID:-1} TPWS_GID=${TPWS_GID:-3003} NFQWS=${NFQWS:-${ZAPRET_BASE}/nfq/nfqws} DVTWS=${DVTWS:-${ZAPRET_BASE}/nfq/dvtws} +WINWS=${WINWS:-${ZAPRET_BASE}/nfq/winws} TPWS=${TPWS:-${ZAPRET_BASE}/tpws/tpws} MDIG=${MDIG:-${ZAPRET_BASE}/mdig/mdig} DESYNC_MARK=0x10000000 @@ -191,7 +192,9 @@ mdig_resolve() { # $1 - ip version 4/6 # $2 - hostname - echo "$2" | "$MDIG" --family=$1 | head -n 1 + + # windows version of mdig outputs 0D0A line ending. remove 0D. + echo "$2" | "$MDIG" --family=$1 | head -n 1 | tr -d '\r' } check_system() @@ -229,6 +232,12 @@ check_system() PKTWSD=dvtws FWTYPE=mpf ;; + CYGWIN*) + UNAME=CYGWIN + PKTWS="$WINWS" + PKTWSD=winws + FWTYPE=windivert + ;; *) echo $UNAME not supported exitp 5 @@ -256,7 +265,7 @@ check_prerequisites() { echo \* checking prerequisites - [ "$UNAME" = Darwin -o -x "$PKTWS" ] && [ -x "$TPWS" ] && [ -x "$MDIG" ] || { + [ "$UNAME" = Darwin -o -x "$PKTWS" ] && [ "$UNAME" = CYGWIN -o -x "$TPWS" ] && [ -x "$MDIG" ] || { local target case $UNAME in Darwin) @@ -323,6 +332,9 @@ check_prerequisites() [ "$UNAME" = "Darwin" ] && SKIP_PKTWS=1 pf_save ;; + CYGWIN) + SKIP_TPWS=1 + ;; esac for prog in $progs; do @@ -446,6 +458,7 @@ curl_with_dig() return 6 } shift ; shift ; shift + ALL_PROXY="$ALL_PROXY" curl $connect_to "$@" } @@ -558,6 +571,10 @@ pktws_ipt_prepare() opf) opf_prepare_dvtws $1 $2 ;; + windivert) + WF="--wf-l3=ipv${IPV} --wf-${1}=$2" + ;; + esac } pktws_ipt_unprepare() @@ -578,6 +595,9 @@ pktws_ipt_unprepare() opf) pf_restore ;; + windivert) + unset WF + ;; esac } @@ -636,6 +656,9 @@ pktws_start() FreeBSD|OpenBSD) "$DVTWS" --port=$IPFW_DIVERT_PORT "$@" >/dev/null & ;; + CYGWIN) + "$WINWS" $WF "$@" >/dev/null & + ;; esac PID=$! # give some time to initialize @@ -711,7 +734,7 @@ pktws_curl_test() # $1 - test function # $2 - domain # $3,$4,$5, ... - nfqws/dvtws params - echo - checking $PKTWSD $3 $4 $5 $6 $7 $8 $9 + echo - checking $PKTWSD ${WF:+$WF }$3 $4 $5 $6 $7 $8 $9 ws_curl_test pktws_start "$@" } xxxws_curl_test_update() @@ -726,7 +749,7 @@ xxxws_curl_test_update() shift $xxxf $testf $dom "$@" code=$? - [ $code = 0 ] && strategy="${strategy:-$@}" + [ $code = 0 ] && strategy="${WF:+$WF }${strategy:-$@}" return $code } pktws_curl_test_update() @@ -1329,6 +1352,10 @@ pingtest() OpenBSD) ping -c 1 -w 1 $1 >/dev/null ;; + CYGWIN) + # cygwin does not have own PING by default. use windows PING. + ping -n 1 -w 1000 $1 >/dev/null + ;; *) ping -c 1 -W 1 $1 >/dev/null ;; @@ -1356,7 +1383,7 @@ lookup4() # $2 - DNS case "$LOOKUP" in nslookup) - nslookup $1 $2 | sed -n '/Name:/,$p' | grep ^Address | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' + nslookup $1 $2 2>/dev/null | sed -n '/Name:/,$p' | sed -nre 's/^.*(([0-9]{1,3}\.){3}[0-9]{1,3}).*$/\1/p' ;; host) host -t A $1 $2 | grep "has address" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' @@ -1367,7 +1394,9 @@ check_dns_spoof() { # $1 - domain # $2 - public DNS - echo $1 | "$MDIG" --family=4 >"$DNSCHECK_DIG1" + + # windows version of mdig outputs 0D0A line ending. remove 0D. + echo $1 | "$MDIG" --family=4 | tr -d '\r' >"$DNSCHECK_DIG1" lookup4 $1 $2 >"$DNSCHECK_DIG2" # check whether system resolver returns anything other than public DNS grep -qvFf "$DNSCHECK_DIG2" "$DNSCHECK_DIG1" @@ -1475,7 +1504,7 @@ sigpipe() fsleep_setup fix_sbin_path check_system -require_root +[ "$UNAME" = CYGWIN ] || require_root check_prerequisites trap sigint_cleanup INT check_dns @@ -1485,6 +1514,7 @@ trap - INT PID= NREPORT= +unset WF trap sigint INT trap sigpipe PIPE for dom in $DOMAINS; do diff --git a/docs/changes.txt b/docs/changes.txt index 0787f20..a569fb4 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -283,3 +283,7 @@ nfqws: --dpi-desync-start option nfqws: packet delay for kyber TLS and QUIC nfqws: --dpi-desync-retrans obsolete nfqws: --qnum is mandatory, no more default queue 0 + +v58 + +winws diff --git a/docs/iptables.txt b/docs/iptables.txt index 4e319e0..c3b8c6f 100644 --- a/docs/iptables.txt +++ b/docs/iptables.txt @@ -3,9 +3,14 @@ For window size changing : iptables -t mangle -I PREROUTING -p tcp --sport 80 --tcp-flags SYN,ACK SYN,ACK -j NFQUEUE --queue-num 200 --queue-bypass iptables -t mangle -I PREROUTING -p tcp --sport 80 --tcp-flags SYN,ACK SYN,ACK -m set --match-set zapret src -j NFQUEUE --queue-num 200 --queue-bypass +For outgoing data manipulation ("Host:" case changing) : + +iptables -t mangle -I POSTROUTING -p tcp --dport 80 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass +iptables -t mangle -I POSTROUTING -p tcp --dport 80 -m set --match-set zapret dst -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:5 -j NFQUEUE --queue-num 200 --queue-bypass + For dpi desync attack : -iptables -t mangle -I POSTROUTING -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 +iptables -t mangle -I POSTROUTING -p tcp -m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 2:4 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass iptables -t mangle -I POSTROUTING -p tcp --dport 443 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass iptables -t mangle -I POSTROUTING -p udp --dport 443 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass diff --git a/docs/quick_start.txt b/docs/quick_start.txt index 06ddc57..b15bba0 100644 --- a/docs/quick_start.txt +++ b/docs/quick_start.txt @@ -91,7 +91,7 @@ zapret не может пробить блокировку по IP адресу Сейчас блокираторы ставят на магистральных каналах. В сложных случаях у вас может быть несколько маршрутов с различной длиной по ХОПам, с DPI на разных хопах. Приходится преодолевать целый зоопарк DPI, которые еще и включаются в работу хаотичным образом или образом, зависящим от направления (IP сервера). -blockheck не всегда может выдать вам в итогах оптимальную стратегию, которую надо просто переписать в настройки. +blockcheck не всегда может выдать вам в итогах оптимальную стратегию, которую надо просто переписать в настройки. В некоторых случаях надо реально думать что происходит, анализируя результат на разных стратегиях. Если вы применяете большой TTL, чтобы достать до магистрала, то не лишним будет добавить дополнительный ограничитель --dpi-desync-fooling, чтобы не сломать сайты на более коротких дистанциях. diff --git a/docs/quick_start_windows.txt b/docs/quick_start_windows.txt new file mode 100644 index 0000000..732a6eb --- /dev/null +++ b/docs/quick_start_windows.txt @@ -0,0 +1,95 @@ +Специально для тех, кто хочет побыстрее начать, но не хочет слишком углубляться в простыню readme.txt. + +Как обычно, компьютерная грамотность ложится полностью на вас. +Вы должны уметь работать с консолью windows и иметь минимальные навыки обращения с командными файлами bat,cmd. +Если грамотность отсутствует и возникает куча "как" на базовых вещах - проходите мимо или ищите помощь в другом месте. + +Обход DPI является хакерской методикой. Под этим словом понимается метод, которому сопротивляется окружающая среда, +которому автоматически не гарантирована работоспособность в любых условиях и на любых ресурсах, +требуется настройка под специфические условия у вашего провайдера. Условия могут меняться со временем, +и методика может начинать или переставать работать, может потребоваться повторный анализ ситуации. +Могут обнаруживаться отдельные ресурсы, которые заблокированы иначе, и которые не работают или перестали работать. +Могут и сломаться отдельные незаблокированные ресурсы. +Поэтому очень желательно иметь знания в области сетей, чтобы иметь возможность проанализировать техническую ситуацию. +Не будет лишним иметь обходные каналы проксирования трафика на случай, если обход DPI не помогает. + +Будем считать, что у вас есть windows 7 или выше. Задача - обойти блокировки с самой системы. + +1) Если у вас windows 7, обновляйте систему. Годами не обновляемая 7-ка может не запускать драйвер windivert. +Поддержка 32-битных x86 windows возможна, но в готовом виде отсутствует. +Поддержка arm64 систем возможна при определенных условиях, но в готовом виде отсутствует. +Читайте docs/windows.txt + +Имейте в виду, что антивирусы могут плохо реагировать на windivert. Если это имеет место , используйте исключения. + +2) Скачайте zip архив проекта с github, распакуйте его куда-нибудь. + +3) Убедитесь, что у вас отключены все средства обхода блокировок, в том числе и сам zapret. + +4) Если вы работаете в виртуальной машине, необходимо использовать соединение с сетью в режиме bridge. nat не подходит + +5) Выполните установку cygwin. Желательно устанавливать windows 7 совместимую версию, под которой и был собран проект. +Скачайте https://www.cygwin.com/setup-x86_64.exe +Выполните его с параметрами : setup-x86_64.exe --allow-unsupported-windows --no-verify --site http://ctm.crouchingtigerhiddenfruitbat.org/pub/cygwin/circa/64bit/2024/01/30/231215 +Установите cygwin, выбрав в списке пакетов curl. + +cygwin нужен только для поиска стратегии обхода блокировки. После этого он не нужен. + +6) Запустите cygwin.bat из директории установки cygwin от имени администратора. +В нем нужно пройти в директорию с zapret. Буква диска windows X: отображается как /cygdrive/x. +Используейте команды как в *nix + +7) Однократно выполните ./install_bin.sh + +8) Запустите blockcheck.sh. blockcheck.sh в начале проверяет DNS. Если выводятся сообщения о подмене адресов, то +первым делом нужно решить эту проблему, иначе ничего не будет работать. +Решение проблемы DNS выходит за рамки проекта. Обычно она решается либо заменой DNS серверов +от провайдера на публичные (1.1.1.1, 8.8.8.8), либо в случае перехвата провайдером обращений +к сторонним серверам - через специальные средства шифрования DNS запросов, такие как dnscrypt, DoT, DoH. +В современных броузерах чаще всего DoH включен по умолчанию, но curl будет использовать обычный DNS. + +9) blockcheck позволяет выявить рабочую стратегию обхода блокировок. +Запомните найденные стратегии. + +Следует понимать, что blockcheck проверяет доступность только конкретного домена, который вы вводите в начале. +Вероятно, все остальные домены блокированы подобным образом, но не факт. +В большинстве случаев можно обьединить несколько стратегий в одну универсальную, но для этого необходимо понимать +"что там за буковки". Если вы в сетях слабо разбираетесь, это не для вас. В противном случае читайте readme.txt. +zapret не может пробить блокировку по IP адресу +Для проверки нескольких доменов вводите их через пробел. + +Сейчас блокираторы ставят на магистральных каналах. В сложных случаях у вас может быть несколько маршрутов +с различной длиной по ХОПам, с DPI на разных хопах. Приходится преодолевать целый зоопарк DPI, +которые еще и включаются в работу хаотичным образом или образом, зависящим от направления (IP сервера). +blockcheck не всегда может выдать вам в итогах оптимальную стратегию, которую надо просто переписать в настройки. +В некоторых случаях надо реально думать что происходит, анализируя результат на разных стратегиях. +Если вы применяете большой TTL, чтобы достать до магистрала, то не лишним будет добавить дополнительный ограничитель +--dpi-desync-fooling, чтобы не сломать сайты на более коротких дистанциях. +md5sig наиболее совместим, но работатет только на linux серверах. +badseq может работать только на https и не работать на http. +Чтобы выяснить какие дополнительные ограничители работают, смотрите результат теста аналогичных стратегий без TTL +с каждым из этих ограничителей. + +При использовании autottl следует протестировать как можно больше разных доменов. Эта техника +может на одних провайдерах работать стабильно, на других потребуется выяснить при каких параметрах +она стабильна, на третьих полный хаос, и проще отказаться. + +10) Протестируйте найденные стратегии на winws. winws следует брать из binaries/win64/zapret-winws. + +11) Обеспечьте удобную загрузку обхода блокировок. +В binaries/win64/zapret-winws есть командные файлы task_*, предназначенные для управления задачами планировщика. +Там следует поменять содержимое переменной WINWS1 на свою стратегию. +Если вы не можете обьединить несколько стратегий для разных протоколов в одну, дублируйте код в каждом из cmd +для поддержки нескольких задач : winws1,winws2,winws3. +После создания задач запустите их. Проверьте, что обход встает после перезагрузки windows. + +12) Если ломаются отдельные незаблокированные ресурсы, используйте хост-листы. +Где они будут находиться - решайте сами. Пути прописываются не в формате windows, а формате cygwin. +Например, /cygdrive/c/Users/vasya/zapret. +Если в путях присутствуют национальные символы, кодировку нужно использовать OEM. Для русского языка это 866. +Пути с пробелами нужно брать в кавычки. +Параметры управления хост-листами точно такие же, как в *nix. + +Это минимальная инструкция, чтобы соориентироваться с чего начать. Однако, это - не панацея. +В некоторых случаях вы не обойдетесь без знаний и основного "толмуда". +Подробности и полное техническое описание расписаны в readme.txt diff --git a/docs/readme.eng.md b/docs/readme.eng.md index ff7f17c..445b850 100644 --- a/docs/readme.eng.md +++ b/docs/readme.eng.md @@ -9,6 +9,8 @@ blocked by Roskomnadzor), but most others are common. Mainly OpenWRT targeted but also supports traditional Linux, FreeBSD, OpenBSD, partially MacOS. +Most features are also supported in Windows. + ## How it works In the simplest case you are dealing with passive DPI. Passive DPI can read passthrough traffic, @@ -1158,29 +1160,7 @@ see docs/bsd.eng.md ### Windows (WSL) -Using WSL (Windows subsystem for Linux) it's possible to run tpws in socks mode under rather new builds of -windows 10 and windows server. -Its not required to install any linux distributions as suggested in most articles. -tpws is static binary. It doesn't need a distribution. - -Install WSL : `dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all` - -Copy binaries/x86_64/tpws_wsl.tgz to the target system. -Run : `wsl --import tpws "%USERPROFILE%\tpws" tpws_wsl.tgz` - -Run tpws : `wsl -d tpws --exec /tpws --uid=1 --no-resolve --socks --bind-addr=127.0.0.1 --port=1080 ` - -Configure socks as 127.0.0.1:1080 in a browser or another program. - -Cleanup : `wsl --unregister tpws` - -Tested in windows 10 build 19041 (20.04). - -`--oob` , `--mss` and `--disorder` do not work. -RST detection in autohostlist scheme may not work. -WSL may glitch with pipes. `--nosplice` may be required. - -NOTICE. There is native windows solution GoodByeDPI. It works on packet level like nfqws. +see docs/windows.eng.md ### Other devices diff --git a/docs/readme.txt b/docs/readme.txt index 0ff95a5..a1fcb5c 100644 --- a/docs/readme.txt +++ b/docs/readme.txt @@ -1,4 +1,4 @@ -zapret v.57 +zapret v.58 English ------- @@ -16,10 +16,12 @@ For english version refer to docs/readme.eng.txt Поддерживаются традиционные Linux системы, FreeBSD, OpenBSD, частично MacOS. В некоторых случаях возможна самостоятельная прикрутка решения к различным прошивкам. +Большая часть функционала работает на windows. + Как побыстрее начать -------------------- -Читайте docs/quick_start.txt +Читайте docs/quick_start.txt для linux и openwrt, docs/quick_start_windows.txt для windows. Как это работает @@ -1559,29 +1561,10 @@ FreeBSD, OpenBSD, MacOS Описано в docs/bsd.txt -Windows (WSL) -------------- +Windows +------- -tpws в режиме socks можно запускать и под более-менее современными билдами windows 10 и windows server -с установленным WSL. Совсем не обязательно устанавливать дистрибутив убунту, как вам напишут почти в каждой -статье про WSL, которую вы найдете в сети. tpws - статический бинарик, ему дистрибутив не нужен. - -Установить WSL : dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all -Скопировать на целевую систему binaries/x86_64/tpws_wsl.tgz. -Выполнить : wsl --import tpws "%USERPROFILE%\tpws" tpws_wsl.tgz -Запустить : wsl -d tpws --exec /tpws --uid=1 --no-resolve --socks --bind-addr=127.0.0.1 --port=1080 <параметры_дурения> -Прописать socks 127.0.0.1:1080 в броузер или другую программу. - -Удаление : wsl --unregister tpws - -Проверено на windows 10 build 19041 (20.04). - -Не работают функции --oob и --mss из-за ограничений реализации WSL. ---disorder не работает из-за особенностей tcp/ip стека windows. -Может не срабатывать детект RST в autohostlist. -WSL может глючить с pipes, ломая тем самым splice и приводя к зацикливанию процесса. Может потребоваться --nosplice. - -ЗАМЕЧАНИЕ. Под Windows существует нативное решение GoodByeDPI, выполняющее дурение на пакетном уровне (по типу nfqws). +Описано в docs/windows.txt Другие прошивки diff --git a/docs/windows.eng.md b/docs/windows.eng.md new file mode 100644 index 0000000..69114a9 --- /dev/null +++ b/docs/windows.eng.md @@ -0,0 +1,95 @@ +### tpws + +Using `WSL` (Windows subsystem for Linux) it's possible to run `tpws` in socks mode under rather new builds of +windows 10 and windows server. +Its not required to install any linux distributions as suggested in most articles. +tpws is static binary. It doesn't need a distribution. + +Install `WSL` : `dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all` + +Copy `binaries/x86_64/tpws_wsl.tgz` to the target system. +Run : `wsl --import tpws "%USERPROFILE%\tpws" tpws_wsl.tgz` + +Run tpws : `wsl -d tpws --exec /tpws --uid=1 --no-resolve --socks --bind-addr=127.0.0.1 --port=1080 ` + +Configure socks as `127.0.0.1:1080` in a browser or another program. + +Cleanup : `wsl --unregister tpws` + +Tested in windows 10 build 19041 (20.04). + +`--oob` , `--mss` and `--disorder` do not work. +RST detection in autohostlist scheme may not work. +WSL may glitch with splice. `--nosplice` may be required. + + +### winws + +`winws` is `nfqws` version for windows. It's based on `windivert`. Most functions are working. +Large ip filters (ipsets) are not possible. Forwarded traffic and connection sharing are not supported. +Administrator rights are required. + +Working with packet filter consists of two parts + +1. In-kernel packet selection and passing selected packets to a packet filter in user mode. +In *nix it's done by `iptables`, `nftables`, `pf`, `ipfw`. +2. User mode packet filter processes packets and does DPI bypass magic. + +Windows does not have part 1. No `iptables` exist. That's why 3rd party packet redirector is used. +It's called `windivert`. It works starting from `windows 7`. Kernel driver is signed but it may require to disable secure boot +or update windows 7. + +Task of `iptables` is done inside `winws` through `windivert` filters. `Windivert` has it's own [filter language](https://reqrypt.org/windivert-doc.html#filter_language). +`winws` can automate filter construction using simple ip version and port filter. Raw filters are also supported. + +``` + --wf-l3=ipv4|ipv6 ; L3 protocol filter. multiple comma separated values allowed. + --wf-tcp=[~]port1[-port2] ; TCP port filter. ~ means negation. multiple comma separated values allowed. + --wf-udp=[~]port1[-port2] ; UDP port filter. ~ means negation. multiple comma separated values allowed. + --wf-raw=|@ ; raw windivert filter string or filename + --wf-save= ; save windivert filter string to a file and exit +``` + +`--wf-l3`, `--wf-tcp`, `--wf-udp` can take multiple comma separated arguments. + +Multiple `winws` processes are allowed. However, it's discouraged to intersect their filters. + +Paths are passed in `cygwin` format. Windows drives are mapped to `/cygdrive/x`. For example : `/cygdrive/c/Users/vasya/zapret`. + +`Cygwin` shell does not run binaries if their directory has it's own copy of `cygwin1.dll`. +That's why exists separate standalone version in `binaries/win64/zapret-tpws`. +`Cygwin` is required for `blockcheck.sh` support but `winws` itself can be run standalone without cygwin. + +How to get `windows 7` and `winws` compatible `cygwin` : +``` +curl -O https://www.cygwin.com/setup-x86_64.exe +setup-x86_64.exe --allow-unsupported-windows --no-verify --site http://ctm.crouchingtigerhiddenfruitbat.org/pub/cygwin/circa/64bit/2024/01/30/231215 +``` +You must choose to install `curl`. To compile from sources install `gcc-core`,`make`,`zlib-devel`. + +`winws` requires `cygwin1.dll`, `windivert.dll`, `windivert64.sys`. You can take them from `binaries/win64/zapret-winws`. + +It's possible to build x86 32-bit version but this version is not shipped. You have to build it yourself. +32-bit `windivert` can be downloaded from it's developer github. Required version is 2.2.2. +There's no `arm64` signed `windivert` driver. You can compile it yourself but it will run only with disabled driver signature checks. + + +### blockcheck + +`blockcheck.sh` is written in posix shell and uses some standard posix utilites. +Windows does not have them. To execute `blockcheck.sh` use `cygwin` command prompt run as administrator. +It's not possible to use `WSL`. It's not the same as `cygwin`. +First run once `install_bin.sh` then `blockcheck.sh`. + +`Cygwin` is required only for `blockcheck.sh`. Standalone `winws` can be run without it. + + +### auto start + +To start `winws` with windows use windows task scheduler. There are `task_*.cmd` batch files in `binaries/win64/zapret-winws`. +They create, remove, start and stop scheduled task `winws1`. They must be run as administrator. + +Edit `task_create.cmd` and write your `winws` parameters to `%WINWS1%` variable. If you need multiple `winws` instances +clone the code in all cmd files to support multiple tasks `winws1,winws2,winws3,...`. + +Tasks can also be controlled from GUI `taskschd.msc`. diff --git a/docs/windows.txt b/docs/windows.txt new file mode 100644 index 0000000..c35755d --- /dev/null +++ b/docs/windows.txt @@ -0,0 +1,117 @@ +tpws +---- + + tpws Linux WSL. + Windows , epoll, windows . + +tpws socks - windows 10 windows server + WSL. , + WSL, . tpws - , . + + WSL : dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all + binaries/x86_64/tpws_wsl.tgz. + : wsl --import tpws "%USERPROFILE%\tpws" tpws_wsl.tgz + : wsl -d tpws --exec /tpws --uid=1 --no-resolve --socks --bind-addr=127.0.0.1 --port=1080 <_> + socks 127.0.0.1:1080 . + + : wsl --unregister tpws + + windows 10 build 19041 (20.04). + + --oob --mss - WSL. +--disorder - tcp/ip windows. + RST autohostlist. +WSL splice, . --nosplice. + + +winws +----- + + nfqws Windows, windivert. + , ipset . IP . + , "" , . + windivert . + unix , --uid, --user , . nfqws dvtws. + + . + - user mode. + - . + + windows , iptables, nftables, pf ipfw. + windivert. , windows 7. +secure boot - . secureboot testsigning. + windows 7 . . + , GoodbyDPI. + + iptables winws windivert. + windivert , wireshark. + windivert : https://reqrypt.org/windivert-doc.html#filter_language + , . + + --wf-l3=ipv4|ipv6 ; L3 . ipv4 ipv6. + --wf-tcp=[~]port1[-port2] ; tcp. ~ + --wf-udp=[~]port1[-port2] ; udp. ~ + --wf-raw=|@ ; windivert . @. + --wf-save= ; windivert + + --wf-l3, --wf-tcp, --wf-udp . + + tcp tcp synack tcp rst +autottl autohostlist. autohostlist http redirect 302 307. + - ipv4 ipv6. + . , + --wf-save. --wf-raw. - 8 Kb. + + winws . , . + + , , windows, cygwin. +, /cygdrive/c/Users/vasya/zapret. + , winws cmd bat OEM. + 866. . + + , c winws cygwin . , nfqws, + cygwin1.dll, winws . binaries/win64 zapret-winws, + cygwin. . + cygwin, binaries/win64. blockcheck. + cygwin winws kill , *nix. + + windows 7 winws cygwin : +curl -O https://www.cygwin.com/setup-x86_64.exe +setup-x86_64.exe --allow-unsupported-windows --no-verify --site http://ctm.crouchingtigerhiddenfruitbat.org/pub/cygwin/circa/64bit/2024/01/30/231215 + curl. + + gcc-core,make,zlib-devel. +winws cygwin1.dll, windivert.dll, windivert64.sys. binaries/win64/zapret-winws. + 32- x86 windows , , - . +32- windivert . 2.2.2. + arm64 windivert. windivert, + . + + +blockcheck +---------- + +blockcheck.sh posix shell posix. windows, , . + blockcheck.sh . + cygwin , . + cygwin shell cygwin.bat. + zapret. windows X: /cygdrive/x. + *nix : 1 ./install_bin.sh , ./blockcheck.sh. +WSL , . + +cygwin winws . winws SIGHUP . + + + winws +---------------- + + winws windows windows. + schtasks. + binaries/win64/winws task_*.cmd . + , , winws %WINWS1%. + . , + winws1,winws2,winws3,... + + . + + taskschd.msc diff --git a/install_bin.sh b/install_bin.sh index ced96c2..3f2e361 100755 --- a/install_bin.sh +++ b/install_bin.sh @@ -18,9 +18,9 @@ check_dir() # ash and dash try to execute invalid executables as a script. they interpret binary garbage with possible negative consequences # bash and zsh do not do this if exists bash; then - out=$(echo 0.0.0.0 | bash -c "$exe" 2>/dev/null) + out=$(echo 0.0.0.0 | bash -c "\"$exe"\" 2>/dev/null) elif exists zsh; then - out=$(echo 0.0.0.0 | zsh -c "$exe" 2>/dev/null) + out=$(echo 0.0.0.0 | zsh -c "\"$exe\"" 2>/dev/null) else # find does not use its own shell exec # it uses execvp(). in musl libc it does not call shell, in glibc it DOES call /bin/sh @@ -49,15 +49,27 @@ ccp() } UNAME=$(uname) -if [ "$UNAME" = "Linux" ]; then - ARCHLIST="my x86_64 x86 aarch64 arm mips64r2-msb mips32r1-lsb mips32r1-msb ppc" -elif [ "$UNAME" = "Darwin" ]; then - ARCHLIST="my mac64" -elif [ "$UNAME" = "FreeBSD" ]; then - ARCHLIST="my freebsd-x64" -else - ARCHLIST="my" -fi +unset PKTWS +case $UNAME in + Linux) + ARCHLIST="my x86_64 x86 aarch64 arm mips64r2-msb mips32r1-lsb mips32r1-msb ppc" + PKTWS=nfqws + ;; + Darwin) + ARCHLIST="my mac64" + ;; + FreeBSD) + ARCHLIST="my freebsd-x64" + PKTWS=dvtws + ;; + CYGWIN*) + UNAME=CYGWIN + ARCHLIST="win64" + PKTWS=winws + ;; + *) + ARCHLIST="my" +esac if [ "$1" = "getarch" ]; then for arch in $ARCHLIST @@ -77,12 +89,8 @@ else echo installing binaries ... ccp $arch/ip2net ip2net ccp $arch/mdig mdig - if [ "$UNAME" = "Linux" ]; then - ccp $arch/nfqws nfq - else - ccp $arch/dvtws nfq - fi - ccp $arch/tpws tpws + [ -n "$PKTWS" ] && ccp $arch/$PKTWS nfq + [ "$UNAME" = CYGWIN ] || ccp $arch/tpws tpws exit 0 else echo $arch is NOT OK diff --git a/nfq/Makefile b/nfq/Makefile index 9cbc07f..60a8f61 100644 --- a/nfq/Makefile +++ b/nfq/Makefile @@ -2,9 +2,10 @@ CC ?= gcc CFLAGS += -std=gnu99 -Wno-logical-op-parentheses -O3 CFLAGS_BSD = -Wno-address-of-packed-member -Wno-switch CFLAGS_MAC = -mmacosx-version-min=10.8 +CFLAGS_CYGWIN = -Wno-address-of-packed-member -static LIBS_LINUX = -lnetfilter_queue -lnfnetlink -lz LIBS_BSD = -lz -LIBS_CYGWIN = -lz +LIBS_CYGWIN = -lz -Lwindivert -lwindivert SRC_FILES = *.c crypto/*.c all: nfqws @@ -23,7 +24,7 @@ mac: $(SRC_FILES) rm -f dvtwsx dvtwsa cygwin: - $(CC) -s $(CFLAGS) -o winws $(SRC_FILES) $(LDFLAGS) $(LIBS_CYGWIN) + $(CC) -s $(CFLAGS) $(CFLAGS_CYGWIN) -o winws $(SRC_FILES) $(LDFLAGS) $(LIBS_CYGWIN) clean: - rm -f nfqws dvtws *.o + rm -f nfqws dvtws winws.exe *.o diff --git a/nfq/darkmagic.c b/nfq/darkmagic.c index 6d5942c..37bb34b 100644 --- a/nfq/darkmagic.c +++ b/nfq/darkmagic.c @@ -1,6 +1,5 @@ #define _GNU_SOURCE -#include "darkmagic.h" #include #include #include @@ -8,10 +7,13 @@ #include #include #include +#include +#include "darkmagic.h" #include "helpers.h" #include "params.h" + uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment) { return htonl(ntohl(netorder_value)+cpuorder_increment); @@ -642,6 +644,8 @@ const char *proto_name(uint8_t proto) return "udp"; case IPPROTO_ICMP: return "icmp"; + case IPPROTO_ICMPV6: + return "icmp6"; case IPPROTO_IGMP: return "igmp"; case IPPROTO_ESP: @@ -950,8 +954,133 @@ void tcp_rewrite_winsize(struct tcphdr *tcp, uint16_t winsize, uint8_t scale_fac } +#ifdef __CYGWIN__ +static HANDLE w_filter = NULL, w_event = NULL; +static HANDLE windivert_init_filter(const char *filter, UINT64 flags) +{ + LPTSTR errormessage = NULL; + DWORD errorcode = 0; + HANDLE h; + + h = WinDivertOpen(filter, WINDIVERT_LAYER_NETWORK, 0, flags); + if (h != INVALID_HANDLE_VALUE) + { + return h; + } + errorcode = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errorcode, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPTSTR)&errormessage, 0, NULL); + fprintf(stderr, "windivert: error opening filter: %s", errormessage); + LocalFree(errormessage); + if (errorcode == 577) + fprintf(stderr,"windivert: try to disable secure boot and install OS patches\n"); + return NULL; +} +void rawsend_cleanup(void) +{ + if (w_filter) + { + WinDivertClose(w_filter); + w_filter=NULL; + } + if (w_event) + { + CloseHandle(w_event); + w_event=NULL; + } +} +bool windivert_init(const char *filter) +{ + rawsend_cleanup(); + w_filter = windivert_init_filter(filter, 0); + if (w_filter) + { + w_event = CreateEventW(NULL,FALSE,FALSE,NULL); + if (!w_event) + { + rawsend_cleanup(); + return false; + } + return true; + } + return false; +} + +static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa) +{ + UINT recv_len; + DWORD err; + OVERLAPPED ovl = { .hEvent = w_event }; + DWORD rd; + char c; + + if (WinDivertRecvEx(hFilter, packet, *len, &recv_len, 0, wa, NULL, &ovl)) + { + *len = recv_len; + return true; + } + for(;;) + { + err = GetLastError(); + switch(err) + { + case ERROR_IO_PENDING: + // make signals working + while(WaitForSingleObject(w_event,50)==WAIT_TIMEOUT) usleep(0); + if (!GetOverlappedResult(hFilter,&ovl,&rd,TRUE)) + continue; + *len = rd; + return true; + case ERROR_INSUFFICIENT_BUFFER: + errno = ENOBUFS; + break; + case ERROR_NO_DATA: + errno = ESHUTDOWN; + break; + default: + errno = EIO; + } + break; + } + return false; +} +bool windivert_recv(uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa) +{ + return windivert_recv_filter(w_filter,packet,len,wa); +} + +static bool windivert_send_filter(HANDLE hFilter, const uint8_t *packet, size_t len, const WINDIVERT_ADDRESS *wa) +{ + return WinDivertSend(hFilter,packet,(UINT)len,NULL,wa); +} +bool windivert_send(const uint8_t *packet, size_t len, const WINDIVERT_ADDRESS *wa) +{ + return windivert_send_filter(w_filter,packet,len,wa); +} + +bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len) +{ + WINDIVERT_ADDRESS wa; + + memset(&wa,0,sizeof(wa)); + // pseudo interface id IfIdx.SubIfIdx + if (sscanf(ifout,"%u.%u",&wa.Network.IfIdx,&wa.Network.SubIfIdx)!=2) + { + errno = EINVAL; + return false; + } + wa.Outbound=1; + wa.IPChecksum=1; + wa.TCPChecksum=1; + wa.UDPChecksum=1; + wa.IPv6 = (dst->sa_family==AF_INET6); + + return windivert_send(data,len,&wa); +} + +#else // *nix static int rawsend_sock4=-1, rawsend_sock6=-1; static bool b_bind_fix4=false, b_bind_fix6=false; @@ -1264,6 +1393,8 @@ nofix: return true; } +#endif // not CYGWIN + bool rawsend_rp(const struct rawpacket *rp) { return rawsend((struct sockaddr*)&rp->dst,rp->fwmark,rp->ifout,rp->packet,rp->len); @@ -1311,23 +1442,35 @@ uint8_t autottl_guess(uint8_t ttl, const autottl *attl) void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transport_len, struct ip *ip, struct ip6_hdr *ip6hdr) { - #ifdef __FreeBSD__ - // FreeBSD tend to pass ipv6 frames with wrong checksum - if ((verdict & VERDICT_MASK)==VERDICT_MODIFY || ip6hdr) - #else - // if original packet was tampered earlier it needs checksum fixed - if ((verdict & VERDICT_MASK)==VERDICT_MODIFY) - #endif - tcp_fix_checksum(tcphdr,transport_len,ip,ip6hdr); + if (!(verdict & VERDICT_NOCSUM)) + { + // always fix csum for windivert. original can be partial or bad + #ifndef __CYGWIN__ + #ifdef __FreeBSD__ + // FreeBSD tend to pass ipv6 frames with wrong checksum + if ((verdict & VERDICT_MASK)==VERDICT_MODIFY || ip6hdr) + #else + // if original packet was tampered earlier it needs checksum fixed + if ((verdict & VERDICT_MASK)==VERDICT_MODIFY) + #endif + #endif + tcp_fix_checksum(tcphdr,transport_len,ip,ip6hdr); + } } void verdict_udp_csum_fix(uint8_t verdict, struct udphdr *udphdr, size_t transport_len, struct ip *ip, struct ip6_hdr *ip6hdr) { - #ifdef __FreeBSD__ - // FreeBSD tend to pass ipv6 frames with wrong checksum - if ((verdict & VERDICT_MASK)==VERDICT_MODIFY || ip6hdr) - #else - // if original packet was tampered earlier it needs checksum fixed - if ((verdict & VERDICT_MASK)==VERDICT_MODIFY) - #endif - udp_fix_checksum(udphdr,transport_len,ip,ip6hdr); + if (!(verdict & VERDICT_NOCSUM)) + { + // always fix csum for windivert. original can be partial or bad + #ifndef __CYGWIN__ + #ifdef __FreeBSD__ + // FreeBSD tend to pass ipv6 frames with wrong checksum + if ((verdict & VERDICT_MASK)==VERDICT_MODIFY || ip6hdr) + #else + // if original packet was tampered earlier it needs checksum fixed + if ((verdict & VERDICT_MASK)==VERDICT_MODIFY) + #endif + #endif + udp_fix_checksum(udphdr,transport_len,ip,ip6hdr); + } } diff --git a/nfq/darkmagic.h b/nfq/darkmagic.h index 308fb06..b152d2b 100644 --- a/nfq/darkmagic.h +++ b/nfq/darkmagic.h @@ -1,15 +1,21 @@ #pragma once -#include "checksum.h" - #include #include +#include +#include #include #include #include #include -#include #include +#include + +#include "checksum.h" + +#ifdef __CYGWIN__ +#include "windivert/windivert.h" +#endif #include "packet_queue.h" @@ -142,17 +148,26 @@ uint32_t *tcp_find_timestamps(struct tcphdr *tcp); uint8_t tcp_find_scale_factor(const struct tcphdr *tcp); bool tcp_has_fastopen(const struct tcphdr *tcp); +#ifdef __CYGWIN__ +bool windivert_init(const char *filter); +bool windivert_recv(uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa); +bool windivert_send(const uint8_t *packet, size_t len, const WINDIVERT_ADDRESS *wa); +#else +// should pre-do it if dropping privileges. otherwise its not necessary +bool rawsend_preinit(bool bind_fix4, bool bind_fix6); +#endif + // auto creates internal socket and uses it for subsequent calls bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len); bool rawsend_rp(const struct rawpacket *rp); // return trues if all packets were send successfully bool rawsend_queue(struct rawpacket_tailhead *q); -// should pre-do it if dropping privileges. otherwise its not necessary -bool rawsend_preinit(bool bind_fix4, bool bind_fix6); // cleans up socket autocreated by rawsend void rawsend_cleanup(void); +#ifdef BSD int socket_divert(sa_family_t family); +#endif const char *proto_name(uint8_t proto); uint16_t family_from_proto(uint8_t l3proto); diff --git a/nfq/helpers.c b/nfq/helpers.c index 8045275..efabfd7 100644 --- a/nfq/helpers.c +++ b/nfq/helpers.c @@ -265,3 +265,35 @@ time_t file_mod_time(const char *filename) struct stat st; return stat(filename,&st)==-1 ? 0 : st.st_mtime; } + +bool pf_in_range(uint16_t port, const port_filter *pf) +{ + return port && ((!pf->from && !pf->to || port>=pf->from && port<=pf->to) ^ pf->neg); +} +bool pf_parse(const char *s, port_filter *pf) +{ + unsigned int v1,v2; + + if (!s) return false; + if (*s=='~') + { + pf->neg=true; + s++; + } + else + pf->neg=false; + if (sscanf(s,"%u-%u",&v1,&v2)==2) + { + if (!v1 || v1>65535 || v2>65535 || v1>v2) return false; + pf->from=(uint16_t)v1; + pf->to=(uint16_t)v2; + } + else if (sscanf(s,"%u",&v1)==1) + { + if (!v1 || v1>65535) return false; + pf->to=pf->from=(uint16_t)v1; + } + else + return false; + return true; +} diff --git a/nfq/helpers.h b/nfq/helpers.h index 66551bf..2f630b9 100644 --- a/nfq/helpers.h +++ b/nfq/helpers.h @@ -47,3 +47,11 @@ void fill_pattern(uint8_t *buf,size_t bufsize,const void *pattern,size_t patsize int fprint_localtime(FILE *F); time_t file_mod_time(const char *filename); + +typedef struct +{ + uint16_t from,to; + bool neg; +} port_filter; +bool pf_in_range(uint16_t port, const port_filter *pf); +bool pf_parse(const char *s, port_filter *pf); diff --git a/nfq/nfqws.c b/nfq/nfqws.c index 20de560..2465354 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -78,6 +78,15 @@ static void onusr2(int sig) printf("\n"); } +static void pre_desync(void) +{ + signal(SIGHUP, onhup); + signal(SIGUSR1, onusr1); + signal(SIGUSR2, onusr2); + + desync_init(); +} + static uint8_t processPacketData(uint32_t *mark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt) { @@ -189,17 +198,16 @@ static int nfq_main(void) if (!rawsend_preinit(params.bind_fix4,params.bind_fix6)) goto exiterr; +#ifndef __CYGWIN__ sec_harden(); if (params.droproot && !droproot(params.uid, params.gid)) goto exiterr; + print_id(); +#endif - signal(SIGHUP, onhup); - signal(SIGUSR1, onusr1); - signal(SIGUSR2, onusr2); - - desync_init(); + pre_desync(); fd = nfq_fd(h); @@ -311,10 +319,7 @@ static int dvt_main(void) goto exiterr; print_id(); - signal(SIGHUP, onhup); - signal(SIGUSR1, onusr1); - - desync_init(); + pre_desync(); for(;;) { @@ -385,7 +390,75 @@ exiterr: return res; } -#endif + +#elif defined (__CYGWIN__) + +static int win_main(const char *windivert_filter) +{ + size_t len; + unsigned int id; + uint8_t verdict; + bool bOutbound; + uint8_t packet[16384]; + uint32_t mark; + WINDIVERT_ADDRESS wa; + char ifout[22]; + + if (!windivert_init(windivert_filter)) + return 1; + + printf("windivert initialized. capture is started.\n"); + + pre_desync(); + + for (id=0;;id++) + { + len = sizeof(packet); + if (!windivert_recv(packet, &len, &wa)) + { + if (errno==ENOBUFS) + { + DLOG("windivert: ignoring too large packet\n") + continue; // too large packet + } + fprintf(stderr, "windivert: recv failed. errno %d\n", errno); + break; + } + *ifout=0; + snprintf(ifout,sizeof(ifout),"%u.%u",wa.Network.IfIdx, wa.Network.SubIfIdx); + DLOG("packet: id=%u len=%zu outbound=%u IPv6=%u IPChecksum=%u TCPChecksum=%u UDPChecksum=%u IfIdx=%s\n", id, len, wa.Outbound, wa.IPv6, wa.IPChecksum, wa.TCPChecksum, wa.UDPChecksum, ifout) + if (wa.Impostor) + { + DLOG("windivert: skipping impostor packet\n") + continue; + } + if (wa.Loopback) + { + DLOG("windivert: skipping loopback packet\n") + continue; + } + mark=0; + // pseudo interface id IfIdx.SubIfIdx + verdict = processPacketData(&mark, ifout, packet, &len); + switch (verdict & VERDICT_MASK) + { + case VERDICT_PASS: + case VERDICT_MODIFY: + if ((verdict & VERDICT_MASK)==VERDICT_PASS) + DLOG("packet: id=%u reinject unmodified\n", id) + else + DLOG("packet: id=%u reinject modified len=%zu\n", id, len) + if (!windivert_send(packet, len, &wa)) + fprintf(stderr,"windivert: reinject of packet id=%u failed\n", id); + break; + default: + DLOG("packet: id=%u drop\n", id); + } + } + return 0; +} + +#endif // multiple OS divert handlers @@ -427,16 +500,35 @@ static void exithelp(void) #endif " --daemon\t\t\t\t\t; daemonize\n" " --pidfile=\t\t\t\t; write pid to file\n" +#ifndef __CYGWIN__ " --user=\t\t\t\t; drop root privs\n" " --uid=uid[:gid]\t\t\t\t; drop root privs\n" +#endif #ifdef __linux__ " --bind-fix4\t\t\t\t\t; apply outgoing interface selection fix for generated ipv4 packets\n" " --bind-fix6\t\t\t\t\t; apply outgoing interface selection fix for generated ipv6 packets\n" #endif + " --ctrack-timeouts=S:E:F[:U]\t\t\t; internal conntrack timeouts for TCP SYN, ESTABLISHED, FIN stages, UDP timeout. default %u:%u:%u:%u\n" +#ifdef __CYGWIN__ + "\nWINDIVERT FILTER:\n" + " --wf-l3=ipv4|ipv6\t\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n" + " --wf-tcp=[~]port1[-port2]\t\t\t; TCP port filter. ~ means negation. multiple comma separated values allowed.\n" + " --wf-udp=[~]port1[-port2]\t\t\t; UDP port filter. ~ means negation. multiple comma separated values allowed.\n" + " --wf-raw=|@\t\t\t; raw windivert filter string or filename\n" + " --wf-save=\t\t\t\t; save windivert filter string to a file and exit\n" +#endif + "\nHOSTLIST FILTER:\n" + " --hostlist=\t\t\t\t; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n" + " --hostlist-exclude=\t\t\t; do not apply dpi desync to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n" + " --hostlist-auto=\t\t\t; detect DPI blocks and build hostlist automatically\n" + " --hostlist-auto-fail-threshold=\t\t; how many failed attempts cause hostname to be added to auto hostlist (default : %d)\n" + " --hostlist-auto-fail-time=\t\t; all failed attemps must be within these seconds (default : %d)\n" + " --hostlist-auto-retrans-threshold=\t; how many request retransmissions cause attempt to fail (default : %d)\n" + " --hostlist-auto-debug=\t\t; debug auto hostlist positives\n" + "\nTAMPER:\n" " --wsize=[:]\t\t; set window size. 0 = do not modify. OBSOLETE !\n" " --wssize=[:]\t; set window size for server. 0 = do not modify. default scale_factor = 0.\n" " --wssize-cutoff=[n|d|s]N\t\t\t; apply server wsize only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n" - " --ctrack-timeouts=S:E:F[:U]\t\t\t; internal conntrack timeouts for TCP SYN, ESTABLISHED, FIN stages, UDP timeout. default %u:%u:%u:%u\n" " --hostcase\t\t\t\t\t; change Host: => host:\n" " --hostspell\t\t\t\t\t; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n" " --hostnospace\t\t\t\t\t; remove space after Host: and add it to User-Agent: to preserve packet size\n" @@ -471,15 +563,9 @@ static void exithelp(void) " --dpi-desync-udplen-increment=\t\t; increase or decrease udp packet length by N bytes (default %u). negative values decrease length.\n" " --dpi-desync-udplen-pattern=|0xHEX\t; udp tail fill pattern\n" " --dpi-desync-start=[n|d|s]N\t\t\t; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n" - " --dpi-desync-cutoff=[n|d|s]N\t\t\t; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n" - " --hostlist=\t\t\t\t; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n" - " --hostlist-exclude=\t\t\t; do not apply dpi desync to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n" - " --hostlist-auto=\t\t\t; detect DPI blocks and build hostlist automatically\n" - " --hostlist-auto-fail-threshold=\t\t; how many failed attempts cause hostname to be added to auto hostlist (default : %d)\n" - " --hostlist-auto-fail-time=\t\t; all failed attemps must be within these seconds (default : %d)\n" - " --hostlist-auto-retrans-threshold=\t; how many request retransmissions cause attempt to fail (default : %d)\n" - " --hostlist-auto-debug=\t\t; debug auto hostlist positives\n", + " --dpi-desync-cutoff=[n|d|s]N\t\t\t; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n", CTRACK_T_SYN, CTRACK_T_EST, CTRACK_T_FIN, CTRACK_T_UDP, + HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT, HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT, #if defined(__linux__) || defined(SO_USER_COOKIE) DPI_DESYNC_FWMARK_DEFAULT,DPI_DESYNC_FWMARK_DEFAULT, #endif @@ -488,8 +574,7 @@ static void exithelp(void) DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_UDP_DEFAULT, DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_TCP_DEFAULT, BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT, - UDPLEN_INCREMENT_DEFAULT, - HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT, HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT + UDPLEN_INCREMENT_DEFAULT ); exit(1); } @@ -580,12 +665,151 @@ bool parse_autottl(const char *s, autottl *t) return true; } +#ifdef __CYGWIN__ +static bool wf_make_pf(char *opt, const char *l4, const char *portname, char *buf, size_t len) +{ + char *e,*p,c,s1[64]; + port_filter pf; + int n; + + if (len<3) return false; + + for (n=0,p=opt,*buf='(',buf[1]=0 ; p ; n++) + { + if ((e = strchr(p,','))) + { + c=*e; + *e=0; + } + if (!pf_parse(p,&pf)) return false; + + if (pf.from==pf.to) + snprintf(s1, sizeof(s1), "(%s.%s %s %u)", l4, portname, pf.neg ? "!=" : "==", pf.from); + else + snprintf(s1, sizeof(s1), "(%s.%s %s %u %s %s.%s %s %u)", l4, portname, pf.neg ? "<" : ">=", pf.from, pf.neg ? "or" : "and" , l4, portname, pf.neg ? ">" : "<=", pf.to); + if (n) strncat(buf," or ",len-strlen(buf)-1); + strncat(buf, s1, len-strlen(buf)-1); + + if (e) + { + *e++=c; + } + p = e; + } + strncat(buf, ")", len-strlen(buf)-1); + return true; +} +static bool wf_make_l3(char *opt, bool *ipv4, bool *ipv6) +{ + char *e,*p,c; + + for (p=opt,*ipv4=*ipv6=false ; p ; ) + { + if ((e = strchr(p,','))) + { + c=*e; + *e=0; + } + + if (!strcmp(p,"ipv4")) + *ipv4 = true; + else if (!strcmp(p,"ipv6")) + *ipv6 = true; + else return false; + + if (e) + { + *e++=c; + } + p = e; + } + return true; +} + +#define DIVERT_NO_LOCALNETSv4_DST "(" \ + "(ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and " \ + "(ip.DstAddr < 10.0.0.0 or ip.DstAddr > 10.255.255.255) and " \ + "(ip.DstAddr < 192.168.0.0 or ip.DstAddr > 192.168.255.255) and " \ + "(ip.DstAddr < 172.16.0.0 or ip.DstAddr > 172.31.255.255) and " \ + "(ip.DstAddr < 169.254.0.0 or ip.DstAddr > 169.254.255.255))" +#define DIVERT_NO_LOCALNETSv4_SRC "(" \ + "(ip.SrcAddr < 127.0.0.1 or ip.SrcAddr > 127.255.255.255) and " \ + "(ip.SrcAddr < 10.0.0.0 or ip.SrcAddr > 10.255.255.255) and " \ + "(ip.SrcAddr < 192.168.0.0 or ip.SrcAddr > 192.168.255.255) and " \ + "(ip.SrcAddr < 172.16.0.0 or ip.SrcAddr > 172.31.255.255) and " \ + "(ip.SrcAddr < 169.254.0.0 or ip.SrcAddr > 169.254.255.255))" + +#define DIVERT_NO_LOCALNETSv6_DST "(" \ + "(ipv6.DstAddr > ::1) and " \ + "(ipv6.DstAddr < 2001::0 or ipv6.DstAddr >= 2001:1::0) and " \ + "(ipv6.DstAddr < fc00::0 or ipv6.DstAddr >= fe00::0) and " \ + "(ipv6.DstAddr < fe80::0 or ipv6.DstAddr >= fec0::0) and " \ + "(ipv6.DstAddr < ff00::0 or ipv6.DstAddr >= ffff::0))" +#define DIVERT_NO_LOCALNETSv6_SRC "(" \ + "(ipv6.SrcAddr > ::1) and " \ + "(ipv6.SrcAddr < 2001::0 or ipv6.SrcAddr >= 2001:1::0) and " \ + "(ipv6.SrcAddr < fc00::0 or ipv6.SrcAddr >= fe00::0) and " \ + "(ipv6.SrcAddr < fe80::0 or ipv6.SrcAddr >= fec0::0) and " \ + "(ipv6.SrcAddr < ff00::0 or ipv6.SrcAddr >= ffff::0))" + +#define DIVERT_NO_LOCALNETS_SRC "(" DIVERT_NO_LOCALNETSv4_SRC " or " DIVERT_NO_LOCALNETSv6_SRC ")" +#define DIVERT_NO_LOCALNETS_DST "(" DIVERT_NO_LOCALNETSv4_DST " or " DIVERT_NO_LOCALNETSv6_DST ")" + +#define DIVERT_TCP_INBOUNDS "tcp.Ack and tcp.Syn or tcp.Rst or tcp.Fin" + +// HTTP/1.? 30(2|7) +#define DIVERT_HTTP_REDIRECT "tcp.PayloadLength>=12 and tcp.Payload32[0]==0x48545450 and tcp.Payload16[2]==0x2F31 and tcp.Payload[6]==0x2E and tcp.Payload16[4]==0x2033 and tcp.Payload[10]==0x30 and (tcp.Payload[11]==0x32 or tcp.Payload[11]==0x37)" + +#define DIVERT_PROLOG "!impostor and !loopback" + +static bool wf_make_filter( + char *wf, size_t len, + bool ipv4, bool ipv6, + const char *pf_tcp_src, const char *pf_tcp_dst, + const char *pf_udp_src, const char *pf_udp_dst) +{ + char pf_src_buf[512],pf_dst_buf[512]; + const char *pf_dst; + const char *f_tcpin = *pf_tcp_src ? *params.hostlist_auto_filename ? "(" DIVERT_TCP_INBOUNDS " or (" DIVERT_HTTP_REDIRECT "))" : DIVERT_TCP_INBOUNDS : ""; + + if (!*pf_tcp_src && !*pf_udp_src) return false; + if (*pf_tcp_src && *pf_udp_src) + { + snprintf(pf_dst_buf,sizeof(pf_dst_buf),"(%s or %s)",pf_tcp_dst,pf_udp_dst); + pf_dst = pf_dst_buf; + } + else + pf_dst = *pf_tcp_dst ? pf_tcp_dst : pf_udp_dst; + snprintf(wf,len, + DIVERT_PROLOG " and%s\n ((outbound and %s%s)\n or\n (inbound and tcp%s%s%s%s%s%s%s))", + ipv4 ? ipv6 ? "" : " ip and" : " ipv6 and", + pf_dst, + ipv4 ? ipv6 ? " and " DIVERT_NO_LOCALNETS_DST : " and " DIVERT_NO_LOCALNETSv4_DST : " and " DIVERT_NO_LOCALNETSv6_DST, + *pf_tcp_src ? "" : " and false", + *f_tcpin ? " and " : "", + *f_tcpin ? f_tcpin : "", + *pf_tcp_src ? " and " : "", + *pf_tcp_src ? pf_tcp_src : "", + *pf_tcp_src ? " and " : "", + *pf_tcp_src ? ipv4 ? ipv6 ? DIVERT_NO_LOCALNETS_SRC : DIVERT_NO_LOCALNETSv4_SRC : DIVERT_NO_LOCALNETSv6_SRC : "" + ); + + return true; +} + +#endif + int main(int argc, char **argv) { int result, v; int option_index = 0; bool daemon = false; char pidfile[256]; +#ifdef __CYGWIN__ + char windivert_filter[8192], wf_pf_tcp_src[256], wf_pf_tcp_dst[256], wf_pf_udp_src[256], wf_pf_udp_dst[256], wf_save_file[256]; + bool wf_ipv4=true, wf_ipv6=true; + *windivert_filter = *wf_pf_tcp_src = *wf_pf_tcp_dst = *wf_pf_udp_src = *wf_pf_udp_dst = *wf_save_file = 0; +#endif srandom(time(NULL)); @@ -629,12 +853,14 @@ int main(int argc, char **argv) LIST_INIT(¶ms.hostlist_files); LIST_INIT(¶ms.hostlist_exclude_files); - + +#ifndef __CYGWIN__ if (can_drop_root()) // are we root ? { params.uid = params.gid = 0x7FFFFFFF; // default uid:gid params.droproot = true; } +#endif const struct option long_options[] = { {"debug",optional_argument,0,0}, // optidx=0 @@ -647,8 +873,13 @@ int main(int argc, char **argv) #endif {"daemon",no_argument,0,0}, // optidx=2 {"pidfile",required_argument,0,0}, // optidx=3 +#ifndef __CYGWIN__ {"user",required_argument,0,0 }, // optidx=4 {"uid",required_argument,0,0 }, // optidx=5 +#else + {"disabled_argument_2",no_argument,0,0}, // optidx=4 + {"disabled_argument_3",no_argument,0,0}, // optidx=5 +#endif {"wsize",required_argument,0,0}, // optidx=6 {"wssize",required_argument,0,0}, // optidx=7 {"wssize-cutoff",required_argument,0,0},// optidx=8 @@ -663,7 +894,7 @@ int main(int argc, char **argv) #elif defined(SO_USER_COOKIE) {"dpi-desync-sockarg",required_argument,0,0}, // optidx=15 #else - {"disabled_argument_2",no_argument,0,0}, // optidx=15 + {"disabled_argument_4",no_argument,0,0}, // optidx=15 #endif {"dpi-desync-ttl",required_argument,0,0}, // optidx=16 {"dpi-desync-ttl6",required_argument,0,0}, // optidx=17 @@ -701,6 +932,12 @@ int main(int argc, char **argv) #ifdef __linux__ {"bind-fix4",no_argument,0,0}, // optidx=48 {"bind-fix6",no_argument,0,0}, // optidx=49 +#elif defined(__CYGWIN__) + {"wf-l3",required_argument,0,0}, // optidx=48 + {"wf-tcp",required_argument,0,0}, // optidx=49 + {"wf-udp",required_argument,0,0}, // optidx=50 + {"wf-raw",required_argument,0,0}, // optidx=51 + {"wf-save",required_argument,0,0}, // optidx=52 #endif {NULL,0,NULL,0} }; @@ -713,6 +950,7 @@ int main(int argc, char **argv) case 0: /* debug */ params.debug = !optarg || atoi(optarg); break; +#ifndef __CYGWIN__ case 1: /* qnum or port */ #ifdef __linux__ params.qnum = atoi(optarg); @@ -733,6 +971,7 @@ int main(int argc, char **argv) } #endif break; +#endif case 2: /* daemon */ daemon = true; break; @@ -740,6 +979,7 @@ int main(int argc, char **argv) strncpy(pidfile, optarg, sizeof(pidfile)); pidfile[sizeof(pidfile) - 1] = '\0'; break; +#ifndef __CYGWIN__ case 4: /* user */ { struct passwd *pwd = getpwnam(optarg); @@ -762,6 +1002,7 @@ int main(int argc, char **argv) exit_clean(1); } break; +#endif case 6: /* wsize */ if (!parse_ws_scale_factor(optarg,¶ms.wsize,¶ms.wscale)) exit_clean(1); @@ -847,6 +1088,7 @@ int main(int argc, char **argv) #endif } break; +#ifndef __CYGWIN__ case 15: /* dpi-desync-fwmark/dpi-desync-sockarg */ #if defined(__linux__) || defined(SO_USER_COOKIE) params.desync_fwmark = 0; @@ -861,6 +1103,7 @@ int main(int argc, char **argv) exit_clean(1); #endif break; +#endif case 16: /* dpi-desync-ttl */ params.desync_ttl = (uint8_t)atoi(optarg); break; @@ -1069,8 +1312,10 @@ int main(int argc, char **argv) fprintf(stderr, "gzipped auto hostlists are not supported\n"); exit_clean(1); } +#ifndef __CYGWIN__ if (params.droproot && chown(optarg, params.uid, -1)) fprintf(stderr, "could not chown %s. auto hostlist file may not be writable after privilege drop\n", optarg); +#endif } if (!strlist_add(¶ms.hostlist_files, optarg)) { @@ -1113,8 +1358,10 @@ int main(int argc, char **argv) exit_clean(1); } fclose(F); +#ifndef __CYGWIN__ if (params.droproot && chown(optarg, params.uid, -1)) fprintf(stderr, "could not chown %s. auto hostlist debug log may not be writable after privilege drop\n", optarg); +#endif strncpy(params.hostlist_auto_debuglog, optarg, sizeof(params.hostlist_auto_debuglog)); params.hostlist_auto_debuglog[sizeof(params.hostlist_auto_debuglog) - 1] = '\0'; } @@ -1126,6 +1373,48 @@ int main(int argc, char **argv) case 49: /* bind-fix6 */ params.bind_fix6 = true; break; +#elif defined(__CYGWIN__) + case 48: /* wf-l3 */ + if (!wf_make_l3(optarg,&wf_ipv4,&wf_ipv6)) + { + fprintf(stderr, "bad value for --wf-l3\n"); + exit_clean(1); + } + break; + case 49: /* wf-tcp */ + if (!wf_make_pf(optarg,"tcp","SrcPort",wf_pf_tcp_src,sizeof(wf_pf_tcp_src)) || + !wf_make_pf(optarg,"tcp","DstPort",wf_pf_tcp_dst,sizeof(wf_pf_tcp_dst))) + { + fprintf(stderr, "bad value for --wf-tcp\n"); + exit_clean(1); + } + break; + case 50: /* wf-udp */ + if (!wf_make_pf(optarg,"udp","SrcPort",wf_pf_udp_src,sizeof(wf_pf_udp_src)) || + !wf_make_pf(optarg,"udp","DstPort",wf_pf_udp_dst,sizeof(wf_pf_udp_dst))) + { + fprintf(stderr, "bad value for --wf-udp\n"); + exit_clean(1); + } + break; + case 51: /* wf-raw */ + if (optarg[0]=='@') + { + size_t sz = sizeof(windivert_filter)-1; + load_file_or_exit(optarg+1,windivert_filter,&sz); + windivert_filter[sz] = 0; + } + else + { + strncpy(windivert_filter, optarg, sizeof(windivert_filter)); + windivert_filter[sizeof(windivert_filter) - 1] = '\0'; + } + break; + case 52: /* wf-save */ + strncpy(wf_save_file, optarg, sizeof(wf_save_file)); + wf_save_file[sizeof(wf_save_file) - 1] = '\0'; + break; + #endif } } @@ -1142,6 +1431,34 @@ int main(int argc, char **argv) fprintf(stderr, "Need divert port (--port)\n"); exit_clean(1); } +#elif defined(__CYGWIN__) + if (!*windivert_filter) + { + if (!*wf_pf_tcp_src && !*wf_pf_udp_src) + { + fprintf(stderr, "windivert filter : must specify port filter\n"); + exit_clean(1); + } + if (!wf_make_filter(windivert_filter, sizeof(windivert_filter), wf_ipv4, wf_ipv6, wf_pf_tcp_src, wf_pf_tcp_dst, wf_pf_udp_src, wf_pf_udp_dst)) + { + fprintf(stderr, "windivert filter : could not make filter\n"); + exit_clean(1); + } + } + DLOG("windivert filter size: %zu\nwindivert filter:\n%s\n",strlen(windivert_filter),windivert_filter) + if (*wf_save_file) + { + if (save_file(wf_save_file,windivert_filter,strlen(windivert_filter))) + { + printf("windivert filter: raw filter saved to %s\n", wf_save_file); + exit_clean(0); + } + else + { + fprintf(stderr, "windivert filter: could not save raw filter to %s\n", wf_save_file); + exit_clean(0); + } + } #endif // not specified - use desync_ttl value instead @@ -1157,7 +1474,8 @@ int main(int argc, char **argv) fprintf(stderr, "Include hostlist load failed\n"); exit_clean(1); } - if (*params.hostlist_auto_filename) NonEmptyHostlist(¶ms.hostlist); + if (*params.hostlist_auto_filename) + NonEmptyHostlist(¶ms.hostlist); if (!LoadExcludeHostLists()) { fprintf(stderr, "Exclude hostlist load failed\n"); @@ -1179,6 +1497,8 @@ int main(int argc, char **argv) result = nfq_main(); #elif defined(BSD) result = dvt_main(); +#elif defined(__CYGWIN__) + result = win_main(windivert_filter); #else #error unsupported OS #endif diff --git a/nfq/params.h b/nfq/params.h index 458957b..a295563 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -61,9 +61,12 @@ struct params_s uint8_t fake_unknown_udp[1472],udplen_pattern[1472],fake_quic[1472],fake_wg[1472],fake_dht[1472]; size_t fake_http_size,fake_tls_size,fake_quic_size,fake_wg_size,fake_dht_size,fake_unknown_size,fake_syndata_size,fake_unknown_udp_size; int udplen_increment; + +#ifndef __CYGWIN__ bool droproot; uid_t uid; gid_t gid; +#endif strpool *hostlist, *hostlist_exclude; struct str_list_head hostlist_files, hostlist_exclude_files; diff --git a/nfq/sec.c b/nfq/sec.c index cf7656d..c8b95df 100644 --- a/nfq/sec.c +++ b/nfq/sec.c @@ -270,17 +270,18 @@ bool dropcaps(void) } return true; } -#else // __linux__ +#endif // __linux__ + +#ifndef __CYGWIN__ + +#ifndef __linux__ bool sec_harden(void) { // noop return true; } - -#endif // __linux__ - - +#endif bool can_drop_root(void) { @@ -329,6 +330,7 @@ void print_id(void) { int i,N; gid_t g[128]; + printf("Running as UID=%u GID=",getuid()); N=getgroups(sizeof(g)/sizeof(*g),g); if (N>0) @@ -341,6 +343,9 @@ void print_id(void) printf("%u\n",getgid()); } +#endif + + void daemonize(void) { int pid; diff --git a/nfq/sec.h b/nfq/sec.h index 3dc4343..afd6e8a 100644 --- a/nfq/sec.h +++ b/nfq/sec.h @@ -52,9 +52,12 @@ bool dropcaps(void); #endif +#ifndef __CYGWIN__ bool sec_harden(void); bool can_drop_root(void); bool droproot(uid_t uid, gid_t gid); void print_id(void); +#endif + void daemonize(void); bool writepid(const char *filename); diff --git a/nfq/windivert/libwindivert.a b/nfq/windivert/libwindivert.a new file mode 100644 index 0000000..99f3d35 Binary files /dev/null and b/nfq/windivert/libwindivert.a differ diff --git a/nfq/windivert/windivert.h b/nfq/windivert/windivert.h new file mode 100644 index 0000000..952f7ef --- /dev/null +++ b/nfq/windivert/windivert.h @@ -0,0 +1,635 @@ +// WinDivert 2.2.2. MODDED + +/* + * windivert.h + * (C) 2019, all rights reserved, + * + * This file is part of WinDivert. + * + * WinDivert is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * WinDivert is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __WINDIVERT_H +#define __WINDIVERT_H + +#ifndef WINDIVERT_KERNEL +#include +#endif /* WINDIVERT_KERNEL */ + +#ifndef WINDIVERTEXPORT +#define WINDIVERTEXPORT extern __declspec(dllimport) +#endif /* WINDIVERTEXPORT */ + +#ifdef __MINGW32__ +#define __in +#define __in_opt +#define __out +#define __out_opt +#define __inout +#define __inout_opt +#include +#define INT8 int8_t +#define UINT8 uint8_t +#define INT16 int16_t +#define UINT16 uint16_t +#define INT32 int32_t +#define UINT32 uint32_t +#define INT64 int64_t +#define UINT64 uint64_t +#endif /* __MINGW32__ */ + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************/ +/* WINDIVERT API */ +/****************************************************************************/ + +/* + * WinDivert layers. + */ +typedef enum +{ + WINDIVERT_LAYER_NETWORK = 0, /* Network layer. */ + WINDIVERT_LAYER_NETWORK_FORWARD = 1,/* Network layer (forwarded packets) */ + WINDIVERT_LAYER_FLOW = 2, /* Flow layer. */ + WINDIVERT_LAYER_SOCKET = 3, /* Socket layer. */ + WINDIVERT_LAYER_REFLECT = 4, /* Reflect layer. */ +} WINDIVERT_LAYER, *PWINDIVERT_LAYER; + +/* + * WinDivert NETWORK and NETWORK_FORWARD layer data. + */ +typedef struct +{ + UINT32 IfIdx; /* Packet's interface index. */ + UINT32 SubIfIdx; /* Packet's sub-interface index. */ +} WINDIVERT_DATA_NETWORK, *PWINDIVERT_DATA_NETWORK; + +/* + * WinDivert FLOW layer data. + */ +typedef struct +{ + UINT64 EndpointId; /* Endpoint ID. */ + UINT64 ParentEndpointId; /* Parent endpoint ID. */ + UINT32 ProcessId; /* Process ID. */ + UINT32 LocalAddr[4]; /* Local address. */ + UINT32 RemoteAddr[4]; /* Remote address. */ + UINT16 LocalPort; /* Local port. */ + UINT16 RemotePort; /* Remote port. */ + UINT8 Protocol; /* Protocol. */ +} WINDIVERT_DATA_FLOW, *PWINDIVERT_DATA_FLOW; + +/* + * WinDivert SOCKET layer data. + */ +typedef struct +{ + UINT64 EndpointId; /* Endpoint ID. */ + UINT64 ParentEndpointId; /* Parent Endpoint ID. */ + UINT32 ProcessId; /* Process ID. */ + UINT32 LocalAddr[4]; /* Local address. */ + UINT32 RemoteAddr[4]; /* Remote address. */ + UINT16 LocalPort; /* Local port. */ + UINT16 RemotePort; /* Remote port. */ + UINT8 Protocol; /* Protocol. */ +} WINDIVERT_DATA_SOCKET, *PWINDIVERT_DATA_SOCKET; + +/* + * WinDivert REFLECTION layer data. + */ +typedef struct +{ + INT64 Timestamp; /* Handle open time. */ + UINT32 ProcessId; /* Handle process ID. */ + WINDIVERT_LAYER Layer; /* Handle layer. */ + UINT64 Flags; /* Handle flags. */ + INT16 Priority; /* Handle priority. */ +} WINDIVERT_DATA_REFLECT, *PWINDIVERT_DATA_REFLECT; + +/* + * WinDivert address. + */ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4201) +#endif +typedef struct +{ + INT64 Timestamp; /* Packet's timestamp. */ + UINT32 Layer:8; /* Packet's layer. */ + UINT32 Event:8; /* Packet event. */ + UINT32 Sniffed:1; /* Packet was sniffed? */ + UINT32 Outbound:1; /* Packet is outound? */ + UINT32 Loopback:1; /* Packet is loopback? */ + UINT32 Impostor:1; /* Packet is impostor? */ + UINT32 IPv6:1; /* Packet is IPv6? */ + UINT32 IPChecksum:1; /* Packet has valid IPv4 checksum? */ + +// MODDED : UDPChecksum and TCPChecksum in original version are exchanged + UINT32 UDPChecksum:1; /* Packet has valid UDP checksum? */ + UINT32 TCPChecksum:1; /* Packet has valid TCP checksum? */ + + UINT32 Reserved1:8; + UINT32 Reserved2; + union + { + WINDIVERT_DATA_NETWORK Network; /* Network layer data. */ + WINDIVERT_DATA_FLOW Flow; /* Flow layer data. */ + WINDIVERT_DATA_SOCKET Socket; /* Socket layer data. */ + WINDIVERT_DATA_REFLECT Reflect; /* Reflect layer data. */ + UINT8 Reserved3[64]; + }; +} WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +/* + * WinDivert events. + */ +typedef enum +{ + WINDIVERT_EVENT_NETWORK_PACKET = 0, /* Network packet. */ + WINDIVERT_EVENT_FLOW_ESTABLISHED = 1, + /* Flow established. */ + WINDIVERT_EVENT_FLOW_DELETED = 2, /* Flow deleted. */ + WINDIVERT_EVENT_SOCKET_BIND = 3, /* Socket bind. */ + WINDIVERT_EVENT_SOCKET_CONNECT = 4, /* Socket connect. */ + WINDIVERT_EVENT_SOCKET_LISTEN = 5, /* Socket listen. */ + WINDIVERT_EVENT_SOCKET_ACCEPT = 6, /* Socket accept. */ + WINDIVERT_EVENT_SOCKET_CLOSE = 7, /* Socket close. */ + WINDIVERT_EVENT_REFLECT_OPEN = 8, /* WinDivert handle opened. */ + WINDIVERT_EVENT_REFLECT_CLOSE = 9, /* WinDivert handle closed. */ +} WINDIVERT_EVENT, *PWINDIVERT_EVENT; + +/* + * WinDivert flags. + */ +#define WINDIVERT_FLAG_SNIFF 0x0001 +#define WINDIVERT_FLAG_DROP 0x0002 +#define WINDIVERT_FLAG_RECV_ONLY 0x0004 +#define WINDIVERT_FLAG_READ_ONLY WINDIVERT_FLAG_RECV_ONLY +#define WINDIVERT_FLAG_SEND_ONLY 0x0008 +#define WINDIVERT_FLAG_WRITE_ONLY WINDIVERT_FLAG_SEND_ONLY +#define WINDIVERT_FLAG_NO_INSTALL 0x0010 +#define WINDIVERT_FLAG_FRAGMENTS 0x0020 + +/* + * WinDivert parameters. + */ +typedef enum +{ + WINDIVERT_PARAM_QUEUE_LENGTH = 0, /* Packet queue length. */ + WINDIVERT_PARAM_QUEUE_TIME = 1, /* Packet queue time. */ + WINDIVERT_PARAM_QUEUE_SIZE = 2, /* Packet queue size. */ + WINDIVERT_PARAM_VERSION_MAJOR = 3, /* Driver version (major). */ + WINDIVERT_PARAM_VERSION_MINOR = 4, /* Driver version (minor). */ +} WINDIVERT_PARAM, *PWINDIVERT_PARAM; +#define WINDIVERT_PARAM_MAX WINDIVERT_PARAM_VERSION_MINOR + +/* + * WinDivert shutdown parameter. + */ +typedef enum +{ + WINDIVERT_SHUTDOWN_RECV = 0x1, /* Shutdown recv. */ + WINDIVERT_SHUTDOWN_SEND = 0x2, /* Shutdown send. */ + WINDIVERT_SHUTDOWN_BOTH = 0x3, /* Shutdown recv and send. */ +} WINDIVERT_SHUTDOWN, *PWINDIVERT_SHUTDOWN; +#define WINDIVERT_SHUTDOWN_MAX WINDIVERT_SHUTDOWN_BOTH + +#ifndef WINDIVERT_KERNEL + +/* + * Open a WinDivert handle. + */ +WINDIVERTEXPORT HANDLE WinDivertOpen( + __in const char *filter, + __in WINDIVERT_LAYER layer, + __in INT16 priority, + __in UINT64 flags); + +/* + * Receive (read) a packet from a WinDivert handle. + */ +WINDIVERTEXPORT BOOL WinDivertRecv( + __in HANDLE handle, + __out_opt VOID *pPacket, + __in UINT packetLen, + __out_opt UINT *pRecvLen, + __out_opt WINDIVERT_ADDRESS *pAddr); + +/* + * Receive (read) a packet from a WinDivert handle. + */ +WINDIVERTEXPORT BOOL WinDivertRecvEx( + __in HANDLE handle, + __out_opt VOID *pPacket, + __in UINT packetLen, + __out_opt UINT *pRecvLen, + __in UINT64 flags, + __out WINDIVERT_ADDRESS *pAddr, + __inout_opt UINT *pAddrLen, + __inout_opt LPOVERLAPPED lpOverlapped); + +/* + * Send (write/inject) a packet to a WinDivert handle. + */ +WINDIVERTEXPORT BOOL WinDivertSend( + __in HANDLE handle, + __in const VOID *pPacket, + __in UINT packetLen, + __out_opt UINT *pSendLen, + __in const WINDIVERT_ADDRESS *pAddr); + +/* + * Send (write/inject) a packet to a WinDivert handle. + */ +WINDIVERTEXPORT BOOL WinDivertSendEx( + __in HANDLE handle, + __in const VOID *pPacket, + __in UINT packetLen, + __out_opt UINT *pSendLen, + __in UINT64 flags, + __in const WINDIVERT_ADDRESS *pAddr, + __in UINT addrLen, + __inout_opt LPOVERLAPPED lpOverlapped); + +/* + * Shutdown a WinDivert handle. + */ +WINDIVERTEXPORT BOOL WinDivertShutdown( + __in HANDLE handle, + __in WINDIVERT_SHUTDOWN how); + +/* + * Close a WinDivert handle. + */ +WINDIVERTEXPORT BOOL WinDivertClose( + __in HANDLE handle); + +/* + * Set a WinDivert handle parameter. + */ +WINDIVERTEXPORT BOOL WinDivertSetParam( + __in HANDLE handle, + __in WINDIVERT_PARAM param, + __in UINT64 value); + +/* + * Get a WinDivert handle parameter. + */ +WINDIVERTEXPORT BOOL WinDivertGetParam( + __in HANDLE handle, + __in WINDIVERT_PARAM param, + __out UINT64 *pValue); + +#endif /* WINDIVERT_KERNEL */ + +/* + * WinDivert constants. + */ +#define WINDIVERT_PRIORITY_HIGHEST 30000 +#define WINDIVERT_PRIORITY_LOWEST (-WINDIVERT_PRIORITY_HIGHEST) +#define WINDIVERT_PARAM_QUEUE_LENGTH_DEFAULT 4096 +#define WINDIVERT_PARAM_QUEUE_LENGTH_MIN 32 +#define WINDIVERT_PARAM_QUEUE_LENGTH_MAX 16384 +#define WINDIVERT_PARAM_QUEUE_TIME_DEFAULT 2000 /* 2s */ +#define WINDIVERT_PARAM_QUEUE_TIME_MIN 100 /* 100ms */ +#define WINDIVERT_PARAM_QUEUE_TIME_MAX 16000 /* 16s */ +#define WINDIVERT_PARAM_QUEUE_SIZE_DEFAULT 4194304 /* 4MB */ +#define WINDIVERT_PARAM_QUEUE_SIZE_MIN 65535 /* 64KB */ +#define WINDIVERT_PARAM_QUEUE_SIZE_MAX 33554432 /* 32MB */ +#define WINDIVERT_BATCH_MAX 0xFF /* 255 */ +#define WINDIVERT_MTU_MAX (40 + 0xFFFF) + +/****************************************************************************/ +/* WINDIVERT HELPER API */ +/****************************************************************************/ + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4214) +#endif + +/* + * IPv4/IPv6/ICMP/ICMPv6/TCP/UDP header definitions. + */ +typedef struct +{ + UINT8 HdrLength:4; + UINT8 Version:4; + UINT8 TOS; + UINT16 Length; + UINT16 Id; + UINT16 FragOff0; + UINT8 TTL; + UINT8 Protocol; + UINT16 Checksum; + UINT32 SrcAddr; + UINT32 DstAddr; +} WINDIVERT_IPHDR, *PWINDIVERT_IPHDR; + +#define WINDIVERT_IPHDR_GET_FRAGOFF(hdr) \ + (((hdr)->FragOff0) & 0xFF1F) +#define WINDIVERT_IPHDR_GET_MF(hdr) \ + ((((hdr)->FragOff0) & 0x0020) != 0) +#define WINDIVERT_IPHDR_GET_DF(hdr) \ + ((((hdr)->FragOff0) & 0x0040) != 0) +#define WINDIVERT_IPHDR_GET_RESERVED(hdr) \ + ((((hdr)->FragOff0) & 0x0080) != 0) + +#define WINDIVERT_IPHDR_SET_FRAGOFF(hdr, val) \ + do \ + { \ + (hdr)->FragOff0 = (((hdr)->FragOff0) & 0x00E0) | \ + ((val) & 0xFF1F); \ + } \ + while (FALSE) +#define WINDIVERT_IPHDR_SET_MF(hdr, val) \ + do \ + { \ + (hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFDF) | \ + (((val) & 0x0001) << 5); \ + } \ + while (FALSE) +#define WINDIVERT_IPHDR_SET_DF(hdr, val) \ + do \ + { \ + (hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFBF) | \ + (((val) & 0x0001) << 6); \ + } \ + while (FALSE) +#define WINDIVERT_IPHDR_SET_RESERVED(hdr, val) \ + do \ + { \ + (hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFF7F) | \ + (((val) & 0x0001) << 7); \ + } \ + while (FALSE) + +typedef struct +{ + UINT8 TrafficClass0:4; + UINT8 Version:4; + UINT8 FlowLabel0:4; + UINT8 TrafficClass1:4; + UINT16 FlowLabel1; + UINT16 Length; + UINT8 NextHdr; + UINT8 HopLimit; + UINT32 SrcAddr[4]; + UINT32 DstAddr[4]; +} WINDIVERT_IPV6HDR, *PWINDIVERT_IPV6HDR; + +#define WINDIVERT_IPV6HDR_GET_TRAFFICCLASS(hdr) \ + ((((hdr)->TrafficClass0) << 4) | ((hdr)->TrafficClass1)) +#define WINDIVERT_IPV6HDR_GET_FLOWLABEL(hdr) \ + ((((UINT32)(hdr)->FlowLabel0) << 16) | ((UINT32)(hdr)->FlowLabel1)) + +#define WINDIVERT_IPV6HDR_SET_TRAFFICCLASS(hdr, val) \ + do \ + { \ + (hdr)->TrafficClass0 = ((UINT8)(val) >> 4); \ + (hdr)->TrafficClass1 = (UINT8)(val); \ + } \ + while (FALSE) +#define WINDIVERT_IPV6HDR_SET_FLOWLABEL(hdr, val) \ + do \ + { \ + (hdr)->FlowLabel0 = (UINT8)((val) >> 16); \ + (hdr)->FlowLabel1 = (UINT16)(val); \ + } \ + while (FALSE) + +typedef struct +{ + UINT8 Type; + UINT8 Code; + UINT16 Checksum; + UINT32 Body; +} WINDIVERT_ICMPHDR, *PWINDIVERT_ICMPHDR; + +typedef struct +{ + UINT8 Type; + UINT8 Code; + UINT16 Checksum; + UINT32 Body; +} WINDIVERT_ICMPV6HDR, *PWINDIVERT_ICMPV6HDR; + +typedef struct +{ + UINT16 SrcPort; + UINT16 DstPort; + UINT32 SeqNum; + UINT32 AckNum; + UINT16 Reserved1:4; + UINT16 HdrLength:4; + UINT16 Fin:1; + UINT16 Syn:1; + UINT16 Rst:1; + UINT16 Psh:1; + UINT16 Ack:1; + UINT16 Urg:1; + UINT16 Reserved2:2; + UINT16 Window; + UINT16 Checksum; + UINT16 UrgPtr; +} WINDIVERT_TCPHDR, *PWINDIVERT_TCPHDR; + +typedef struct +{ + UINT16 SrcPort; + UINT16 DstPort; + UINT16 Length; + UINT16 Checksum; +} WINDIVERT_UDPHDR, *PWINDIVERT_UDPHDR; + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +/* + * Flags for WinDivertHelperCalcChecksums() + */ +#define WINDIVERT_HELPER_NO_IP_CHECKSUM 1 +#define WINDIVERT_HELPER_NO_ICMP_CHECKSUM 2 +#define WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM 4 +#define WINDIVERT_HELPER_NO_TCP_CHECKSUM 8 +#define WINDIVERT_HELPER_NO_UDP_CHECKSUM 16 + +#ifndef WINDIVERT_KERNEL + +/* + * Hash a packet. + */ +WINDIVERTEXPORT UINT64 WinDivertHelperHashPacket( + __in const VOID *pPacket, + __in UINT packetLen, + __in UINT64 seed +#ifdef __cplusplus + = 0 +#endif +); + +/* + * Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet. + */ +WINDIVERTEXPORT BOOL WinDivertHelperParsePacket( + __in const VOID *pPacket, + __in UINT packetLen, + __out_opt PWINDIVERT_IPHDR *ppIpHdr, + __out_opt PWINDIVERT_IPV6HDR *ppIpv6Hdr, + __out_opt UINT8 *pProtocol, + __out_opt PWINDIVERT_ICMPHDR *ppIcmpHdr, + __out_opt PWINDIVERT_ICMPV6HDR *ppIcmpv6Hdr, + __out_opt PWINDIVERT_TCPHDR *ppTcpHdr, + __out_opt PWINDIVERT_UDPHDR *ppUdpHdr, + __out_opt PVOID *ppData, + __out_opt UINT *pDataLen, + __out_opt PVOID *ppNext, + __out_opt UINT *pNextLen); + +/* + * Parse an IPv4 address. + */ +WINDIVERTEXPORT BOOL WinDivertHelperParseIPv4Address( + __in const char *addrStr, + __out_opt UINT32 *pAddr); + +/* + * Parse an IPv6 address. + */ +WINDIVERTEXPORT BOOL WinDivertHelperParseIPv6Address( + __in const char *addrStr, + __out_opt UINT32 *pAddr); + +/* + * Format an IPv4 address. + */ +WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv4Address( + __in UINT32 addr, + __out char *buffer, + __in UINT bufLen); + +/* + * Format an IPv6 address. + */ +WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv6Address( + __in const UINT32 *pAddr, + __out char *buffer, + __in UINT bufLen); + +/* + * Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums. + */ +WINDIVERTEXPORT BOOL WinDivertHelperCalcChecksums( + __inout VOID *pPacket, + __in UINT packetLen, + __out_opt WINDIVERT_ADDRESS *pAddr, + __in UINT64 flags); + +/* + * Decrement the TTL/HopLimit. + */ +WINDIVERTEXPORT BOOL WinDivertHelperDecrementTTL( + __inout VOID *pPacket, + __in UINT packetLen); + +/* + * Compile the given filter string. + */ +WINDIVERTEXPORT BOOL WinDivertHelperCompileFilter( + __in const char *filter, + __in WINDIVERT_LAYER layer, + __out_opt char *object, + __in UINT objLen, + __out_opt const char **errorStr, + __out_opt UINT *errorPos); + +/* + * Evaluate the given filter string. + */ +WINDIVERTEXPORT BOOL WinDivertHelperEvalFilter( + __in const char *filter, + __in const VOID *pPacket, + __in UINT packetLen, + __in const WINDIVERT_ADDRESS *pAddr); + +/* + * Format the given filter string. + */ +WINDIVERTEXPORT BOOL WinDivertHelperFormatFilter( + __in const char *filter, + __in WINDIVERT_LAYER layer, + __out char *buffer, + __in UINT bufLen); + +/* + * Byte ordering. + */ +WINDIVERTEXPORT UINT16 WinDivertHelperNtohs( + __in UINT16 x); +WINDIVERTEXPORT UINT16 WinDivertHelperHtons( + __in UINT16 x); +WINDIVERTEXPORT UINT32 WinDivertHelperNtohl( + __in UINT32 x); +WINDIVERTEXPORT UINT32 WinDivertHelperHtonl( + __in UINT32 x); +WINDIVERTEXPORT UINT64 WinDivertHelperNtohll( + __in UINT64 x); +WINDIVERTEXPORT UINT64 WinDivertHelperHtonll( + __in UINT64 x); +WINDIVERTEXPORT void WinDivertHelperNtohIPv6Address( + __in const UINT *inAddr, + __out UINT *outAddr); +WINDIVERTEXPORT void WinDivertHelperHtonIPv6Address( + __in const UINT *inAddr, + __out UINT *outAddr); + +/* + * Old names to be removed in the next version. + */ +WINDIVERTEXPORT void WinDivertHelperNtohIpv6Address( + __in const UINT *inAddr, + __out UINT *outAddr); +WINDIVERTEXPORT void WinDivertHelperHtonIpv6Address( + __in const UINT *inAddr, + __out UINT *outAddr); + +#endif /* WINDIVERT_KERNEL */ + +#ifdef __cplusplus +} +#endif + +#endif /* __WINDIVERT_H */