diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 84cacb6..25ba16e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -87,15 +87,14 @@ jobs: export LDFLAGS="-Os" # netfilter libs - git clone --depth 1 -b libmnl-1.0.5 git://git.netfilter.org/libmnl - git clone --depth 1 -b libnfnetlink-1.0.2 git://git.netfilter.org/libnfnetlink - git clone --depth 1 -b libnetfilter_queue-1.0.5 git://git.netfilter.org/libnetfilter_queue + wget -qO- https://www.netfilter.org/pub/libnfnetlink/libnfnetlink-1.0.2.tar.bz2 | tar -xj + wget -qO- https://www.netfilter.org/pub/libmnl/libmnl-1.0.5.tar.bz2 | tar -xj + wget -qO- https://www.netfilter.org/pub/libnetfilter_queue/libnetfilter_queue-1.0.5.tar.bz2 | tar -xj for i in libmnl libnfnetlink libnetfilter_queue ; do ( - cd $i - ./autogen.sh && \ - ./configure --prefix= --host=$TARGET --enable-static --disable-shared && \ + cd $i-* + ./configure --prefix= --host=$TARGET --enable-static --disable-shared --disable-dependency-tracking make install -j$(nproc) DESTDIR=$DEPS_DIR ) sed -i "s|^prefix=.*|prefix=$DEPS_DIR|g" $DEPS_DIR/lib/pkgconfig/$i.pc @@ -106,7 +105,7 @@ jobs: xargs -I{} wget -qO- https://github.com/madler/zlib/archive/refs/tags/{}.tar.gz | tar -xz ( cd zlib-* - ./configure --prefix= --static && \ + ./configure --prefix= --static make install -j$(nproc) DESTDIR=$DEPS_DIR ) @@ -282,9 +281,77 @@ jobs: path: zapret-*.zip if-no-files-found: error + build-android: + name: Android ${{ matrix.abi }} + runs-on: ubuntu-latest + strategy: + matrix: + include: + - abi: armeabi-v7a + target: armv7a-linux-androideabi + - abi: arm64-v8a + target: aarch64-linux-android + - abi: x86 + target: i686-linux-android + - abi: x86_64 + target: x86_64-linux-android + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + path: zapret + + - name: Build + env: + ABI: ${{ matrix.abi }} + TARGET: ${{ matrix.target }} + run: | + DEPS_DIR=$GITHUB_WORKSPACE/deps + export TOOLCHAIN=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64 + export API=21 + export CC="$TOOLCHAIN/bin/clang --target=$TARGET$API" + export AR=$TOOLCHAIN/bin/llvm-ar + export AS=$CC + export LD=$TOOLCHAIN/bin/ld + export RANLIB=$TOOLCHAIN/bin/llvm-ranlib + export STRIP=$TOOLCHAIN/bin/llvm-strip + export PKG_CONFIG_PATH=$DEPS_DIR/lib/pkgconfig + + # optimize for size + export CFLAGS="-Os -flto=auto" + export LDFLAGS="-Os" + + # netfilter libs + wget -qO- https://www.netfilter.org/pub/libnfnetlink/libnfnetlink-1.0.2.tar.bz2 | tar -xj + wget -qO- https://www.netfilter.org/pub/libmnl/libmnl-1.0.5.tar.bz2 | tar -xj + wget -qO- https://www.netfilter.org/pub/libnetfilter_queue/libnetfilter_queue-1.0.5.tar.bz2 | tar -xj + patch -p1 -d libnetfilter_queue-* -i ../zapret/.github/workflows/libnetfilter_queue-android.patch + + for i in libmnl libnfnetlink libnetfilter_queue ; do + ( + cd $i-* + CFLAGS="$CFLAGS -Wno-implicit-function-declaration" \ + ./configure --prefix= --host=$TARGET --enable-static --disable-shared --disable-dependency-tracking + make install -j$(nproc) DESTDIR=$DEPS_DIR + ) + sed -i "s|^prefix=.*|prefix=$DEPS_DIR|g" $DEPS_DIR/lib/pkgconfig/$i.pc + done + + # zapret + CFLAGS="$CFLAGS -I$DEPS_DIR/include" LDFLAGS="$LDFLAGS -L$DEPS_DIR/lib" \ + make -C zapret android -j$(nproc) + zip zapret-android-$ABI.zip -j zapret/binaries/my/* + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: zapret-android-${{ matrix.abi }} + path: zapret-*.zip + if-no-files-found: error + release: if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') - needs: [ build-linux, build-windows, build-macos, build-freebsd ] + needs: [ build-linux, build-windows, build-macos, build-freebsd, build-android ] permissions: contents: write runs-on: ubuntu-latest @@ -343,18 +410,22 @@ jobs: if [ -d $dir ]; then echo "Processing $dir" case $dir in - *-freebsd-x86_64 ) run_dir freebsd-x64 ;; - *-linux-arm ) run_dir arm ;; - *-linux-arm64 ) run_dir aarch64 ;; - *-linux-mips64 ) run_dir mips64r2-msb ;; - *-linux-mipselsf ) run_dir mips32r1-lsb ;; - *-linux-mipssf ) run_dir mips32r1-msb ;; - *-linux-ppc ) run_dir ppc ;; - *-linux-x86 ) run_dir x86 ;; - *-linux-x86_64 ) run_dir x86_64 ;; - *-mac-x64 ) run_dir mac64 ;; - *-win-x86 ) run_dir win32 ;; - *-win-x86_64 ) run_dir win64 ;; + *-android-arm64-v8a ) run_dir android-aarch64 ;; + *-android-armeabi-v7a ) run_dir android-arm ;; + *-android-x86 ) run_dir android-x86 ;; + *-android-x86_64 ) run_dir android-x86_64 ;; + *-freebsd-x86_64 ) run_dir freebsd-x64 ;; + *-linux-arm ) run_dir arm ;; + *-linux-arm64 ) run_dir aarch64 ;; + *-linux-mips64 ) run_dir mips64r2-msb ;; + *-linux-mipselsf ) run_dir mips32r1-lsb ;; + *-linux-mipssf ) run_dir mips32r1-msb ;; + *-linux-ppc ) run_dir ppc ;; + *-linux-x86 ) run_dir x86 ;; + *-linux-x86_64 ) run_dir x86_64 ;; + *-mac-x64 ) run_dir mac64 ;; + *-win-x86 ) run_dir win32 ;; + *-win-x86_64 ) run_dir win64 ;; esac fi done diff --git a/.github/workflows/libnetfilter_queue-android.patch b/.github/workflows/libnetfilter_queue-android.patch new file mode 100644 index 0000000..a0ce64b --- /dev/null +++ b/.github/workflows/libnetfilter_queue-android.patch @@ -0,0 +1,41 @@ +--- a/src/extra/pktbuff.c ++++ b/src/extra/pktbuff.c +@@ -14,7 +14,7 @@ + #include /* for memcpy */ + #include + +-#include ++#include + #include + #include + +--- a/src/nlmsg.c ++++ b/src/nlmsg.c +@@ -21,7 +21,7 @@ + + #include + +-#include ++// #include + + #include "internal.h" + +--- a/src/extra/tcp.c ++++ b/src/extra/tcp.c +@@ -139,12 +139,16 @@ void nfq_tcp_compute_checksum_ipv6(struc + * (union is compatible to any of its members) + * This means this part of the code is -fstrict-aliasing safe now. + */ ++#ifndef __ANDROID__ + union tcp_word_hdr { + struct tcphdr hdr; + uint32_t words[5]; + }; ++#endif + ++#ifndef tcp_flag_word + #define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words[3]) ++#endif + + /** + * nfq_pkt_snprintf_tcp_hdr - print tcp header into one buffer in a humnan diff --git a/Makefile b/Makefile index 68145e0..00e6c20 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,19 @@ all: clean done \ done +android: clean + @mkdir -p "$(TGT)"; \ + for dir in $(DIRS); do \ + find "$$dir" -type f \( -name "*.c" -o -name "*.h" -o -name "*akefile" \) -exec chmod -x {} \; ; \ + $(MAKE) -C "$$dir" android || exit; \ + for exe in "$$dir/"*; do \ + if [ -f "$$exe" ] && [ -x "$$exe" ]; then \ + mv -f "$$exe" "${TGT}" ; \ + ln -fs "../${TGT}/$$(basename "$$exe")" "$$exe" ; \ + fi \ + done \ + done + bsd: clean @mkdir -p "$(TGT)"; \ for dir in $(DIRS); do \ diff --git a/blockcheck.sh b/blockcheck.sh index dca4bad..ebed7a4 100755 --- a/blockcheck.sh +++ b/blockcheck.sh @@ -1011,6 +1011,15 @@ tpws_curl_test() echo - checking tpws $3 $4 $5 $6 $7 $8 $9${TPWS_EXTRA:+ $TPWS_EXTRA}${TPWS_EXTRA_1:+ "$TPWS_EXTRA_1"}${TPWS_EXTRA_2:+ "$TPWS_EXTRA_2"}${TPWS_EXTRA_3:+ "$TPWS_EXTRA_3"}${TPWS_EXTRA_4:+ "$TPWS_EXTRA_4"}${TPWS_EXTRA_5:+ "$TPWS_EXTRA_5"}${TPWS_EXTRA_6:+ "$TPWS_EXTRA_6"}${TPWS_EXTRA_7:+ "$TPWS_EXTRA_7"}${TPWS_EXTRA_8:+ "$TPWS_EXTRA_8"}${TPWS_EXTRA_9:+ "$TPWS_EXTRA_9"} local ALL_PROXY="socks5://127.0.0.1:$SOCKS_PORT" ws_curl_test tpws_start "$@"${TPWS_EXTRA:+ $TPWS_EXTRA}${TPWS_EXTRA_1:+ "$TPWS_EXTRA_1"}${TPWS_EXTRA_2:+ "$TPWS_EXTRA_2"}${TPWS_EXTRA_3:+ "$TPWS_EXTRA_3"}${TPWS_EXTRA_4:+ "$TPWS_EXTRA_4"}${TPWS_EXTRA_5:+ "$TPWS_EXTRA_5"}${TPWS_EXTRA_6:+ "$TPWS_EXTRA_6"}${TPWS_EXTRA_7:+ "$TPWS_EXTRA_7"}${TPWS_EXTRA_8:+ "$TPWS_EXTRA_8"}${TPWS_EXTRA_9:+ "$TPWS_EXTRA_9"} + local code=$? + [ "$code" = 0 ] && { + local testf=$1 dom=$2 + shift; shift; + local strategy="$@" + strategy_append_extra_tpws + report_append "ipv${IPV} $dom $testf : tpws ${WF:+$WF }$strategy" + } + return $code } pktws_curl_test() { @@ -1019,7 +1028,26 @@ pktws_curl_test() # $3,$4,$5, ... - nfqws/dvtws params echo - checking $PKTWSD ${WF:+$WF }$3 $4 $5 $6 $7 $8 $9${PKTWS_EXTRA:+ $PKTWS_EXTRA}${PKTWS_EXTRA_1:+ "$PKTWS_EXTRA_1"}${PKTWS_EXTRA_2:+ "$PKTWS_EXTRA_2"}${PKTWS_EXTRA_3:+ "$PKTWS_EXTRA_3"}${PKTWS_EXTRA_4:+ "$PKTWS_EXTRA_4"}${PKTWS_EXTRA_5:+ "$PKTWS_EXTRA_5"}${PKTWS_EXTRA_6:+ "$PKTWS_EXTRA_6"}${PKTWS_EXTRA_7:+ "$PKTWS_EXTRA_7"}${PKTWS_EXTRA_8:+ "$PKTWS_EXTRA_8"}${PKTWS_EXTRA_9:+ "$PKTWS_EXTRA_9"} ws_curl_test pktws_start "$@"${PKTWS_EXTRA:+ $PKTWS_EXTRA}${PKTWS_EXTRA_1:+ "$PKTWS_EXTRA_1"}${PKTWS_EXTRA_2:+ "$PKTWS_EXTRA_2"}${PKTWS_EXTRA_3:+ "$PKTWS_EXTRA_3"}${PKTWS_EXTRA_4:+ "$PKTWS_EXTRA_4"}${PKTWS_EXTRA_5:+ "$PKTWS_EXTRA_5"}${PKTWS_EXTRA_6:+ "$PKTWS_EXTRA_6"}${PKTWS_EXTRA_7:+ "$PKTWS_EXTRA_7"}${PKTWS_EXTRA_8:+ "$PKTWS_EXTRA_8"}${PKTWS_EXTRA_9:+ "$PKTWS_EXTRA_9"} + local code=$? + [ "$code" = 0 ] && { + local testf=$1 dom=$2 + shift; shift; + local strategy="$@" + strategy_append_extra_pktws + report_append "ipv${IPV} $dom $testf : $PKTWSD ${WF:+$WF }$strategy" + } + return $code } + +strategy_append_extra_pktws() +{ + strategy="${strategy:+$strategy${PKTWS_EXTRA:+ $PKTWS_EXTRA}${PKTWS_EXTRA_1:+ "$PKTWS_EXTRA_1"}${PKTWS_EXTRA_2:+ "$PKTWS_EXTRA_2"}${PKTWS_EXTRA_3:+ "$PKTWS_EXTRA_3"}${PKTWS_EXTRA_4:+ "$PKTWS_EXTRA_4"}${PKTWS_EXTRA_5:+ "$PKTWS_EXTRA_5"}${PKTWS_EXTRA_6:+ "$PKTWS_EXTRA_6"}${PKTWS_EXTRA_7:+ "$PKTWS_EXTRA_7"}${PKTWS_EXTRA_8:+ "$PKTWS_EXTRA_8"}${PKTWS_EXTRA_9:+ "$PKTWS_EXTRA_9"}}" +} +strategy_append_extra_tpws() +{ + strategy="${strategy:+$strategy${TPWS_EXTRA:+ $TPWS_EXTRA}${TPWS_EXTRA_1:+ "$TPWS_EXTRA_1"}${TPWS_EXTRA_2:+ "$TPWS_EXTRA_2"}${TPWS_EXTRA_3:+ "$TPWS_EXTRA_3"}${TPWS_EXTRA_4:+ "$TPWS_EXTRA_4"}${TPWS_EXTRA_5:+ "$TPWS_EXTRA_5"}${TPWS_EXTRA_6:+ "$TPWS_EXTRA_6"}${TPWS_EXTRA_7:+ "$TPWS_EXTRA_7"}${TPWS_EXTRA_8:+ "$TPWS_EXTRA_8"}${TPWS_EXTRA_9:+ "$TPWS_EXTRA_9"}}" +} + xxxws_curl_test_update() { # $1 - xxx_curl_test function @@ -1071,7 +1099,7 @@ report_strategy() strategy="$(echo "$strategy" | xargs)" echo "!!!!! $1: working strategy found for ipv${IPV} $2 : $3 $strategy !!!!!" echo - report_append "ipv${IPV} $2 $1 : $3 ${WF:+$WF }$strategy" +# report_append "ipv${IPV} $2 $1 : $3 ${WF:+$WF }$strategy" return 0 else echo "$1: $3 strategy for ipv${IPV} $2 not found" @@ -1314,7 +1342,7 @@ pktws_check_domain_http_bypass() local strategy pktws_check_domain_http_bypass_ "$@" - strategy="${strategy:+$strategy${PKTWS_EXTRA:+ $PKTWS_EXTRA}${PKTWS_EXTRA_1:+ "$PKTWS_EXTRA_1"}${PKTWS_EXTRA_2:+ "$PKTWS_EXTRA_2"}${PKTWS_EXTRA_3:+ "$PKTWS_EXTRA_3"}${PKTWS_EXTRA_4:+ "$PKTWS_EXTRA_4"}${PKTWS_EXTRA_5:+ "$PKTWS_EXTRA_5"}${PKTWS_EXTRA_6:+ "$PKTWS_EXTRA_6"}${PKTWS_EXTRA_7:+ "$PKTWS_EXTRA_7"}${PKTWS_EXTRA_8:+ "$PKTWS_EXTRA_8"}${PKTWS_EXTRA_9:+ "$PKTWS_EXTRA_9"}}" + strategy_append_extra_pktws report_strategy $1 $3 $PKTWSD } @@ -1359,7 +1387,7 @@ pktws_check_domain_http3_bypass() local strategy pktws_check_domain_http3_bypass_ "$@" - strategy="${strategy:+$strategy $PKTWS_EXTRA $PKTWS_EXTRA_1 $PKTWS_EXTRA_2 $PKTWS_EXTRA_3 $PKTWS_EXTRA_4 $PKTWS_EXTRA_5 $PKTWS_EXTRA_6 $PKTWS_EXTRA_7 $PKTWS_EXTRA_8 $PKTWS_EXTRA_9}" + strategy_append_extra_pktws report_strategy $1 $2 $PKTWSD } warn_mss() @@ -1402,12 +1430,14 @@ tpws_check_domain_http_bypass_() tpws_curl_test_update $1 $3 $s && [ "$SCANLEVEL" = quick ] && return done else + local need_mss=1 for mss in '' 88; do s3=${mss:+--mss=$mss} for s2 in '' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do for pos in $splits_tls; do tpws_curl_test_update $1 $3 --split-pos=$pos $s2 $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && { [ "$SCANLEVEL" = quick ] && return + need_mss=0 break } done @@ -1416,12 +1446,14 @@ tpws_check_domain_http_bypass_() for s2 in '--tlsrec=midsld' '--tlsrec=sniext+1 --split-pos=midsld' '--tlsrec=sniext+4 --split-pos=midsld' '--tlsrec=sniext+1 --split-pos=1,midsld' '--tlsrec=sniext+4 --split-pos=1,midsld' ; do tpws_curl_test_update $1 $3 $s2 $s $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && { [ "$SCANLEVEL" = quick ] && return + need_mss=0 break } done done # only linux supports mss [ "$UNAME" = Linux -a "$sec" = 1 ] || break + [ "$SCANLEVEL" = force -o "$need_mss" = 1 ] || break done fi } @@ -1433,7 +1465,7 @@ tpws_check_domain_http_bypass() local strategy tpws_check_domain_http_bypass_ "$@" - strategy="${strategy:+$strategy${TPWS_EXTRA:+ $TPWS_EXTRA}${TPWS_EXTRA_1:+ "$TPWS_EXTRA_1"}${TPWS_EXTRA_2:+ "$TPWS_EXTRA_2"}${TPWS_EXTRA_3:+ "$TPWS_EXTRA_3"}${TPWS_EXTRA_4:+ "$TPWS_EXTRA_4"}${TPWS_EXTRA_5:+ "$TPWS_EXTRA_5"}${TPWS_EXTRA_6:+ "$TPWS_EXTRA_6"}${TPWS_EXTRA_7:+ "$TPWS_EXTRA_7"}${TPWS_EXTRA_8:+ "$TPWS_EXTRA_8"}${TPWS_EXTRA_9:+ "$TPWS_EXTRA_9"}}" + strategy_append_extra_tpws report_strategy $1 $3 tpws } diff --git a/docs/compile/build_howto_openwrt.txt b/docs/compile/build_howto_openwrt.txt index 9ff5f1a..3a61c85 100644 --- a/docs/compile/build_howto_openwrt.txt +++ b/docs/compile/build_howto_openwrt.txt @@ -3,19 +3,33 @@ How to compile native programs for use in openwrt 1) Download latest SDK for your platform from https://downloads.openwrt.org - curl -o - https://downloads.openwrt.org/releases/23.05.5/targets/x86/64/openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64.tar.xz | tar -Jxvf - - cd openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64 +examples : -2) ./scripts/feeds update -a - ./scripts/feeds install -a +curl -o - https://downloads.openwrt.org/releases/23.05.5/targets/x86/64/openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64.tar.xz | tar -Jxvf - +cd openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64 -3) cp -R /opt/zapret/docs/compile/openwrt/. . - cp -R /opt/zapret/tpws package/zapret/tpws - cp -R /opt/zapret/nfq package/zapret/nfqws - cp -R /opt/zapret/mdig package/zapret/mdig - cp -R /opt/zapret/ip2net package/zapret/ip2net +curl -o - https://downloads.openwrt.org/snapshots/targets/x86/64/openwrt-sdk-x86-64_gcc-13.3.0_musl.Linux-x86_64.tar.zst | tar --zstd -xvf - +cd openwrt-sdk-x86-64_gcc-13.3.0_musl.Linux-x86_64 -4) make package/{tpws,nfqws,mdig,ip2net}/compile +2) Install required libs -5) find bin -name tpws*.ipk - #take your tpws*.ipk , nfqws*.ipk , ip2net*.ipk, mdig*.ipk from there +./scripts/feeds update base packages +./scripts/feeds install libnetfilter-queue zlib libcap + +3) Prepare openwrt package definitions + +cp -R /opt/zapret/docs/compile/openwrt/. . +cp -R /opt/zapret/tpws package/zapret/tpws +cp -R /opt/zapret/nfq package/zapret/nfqws +cp -R /opt/zapret/mdig package/zapret/mdig +cp -R /opt/zapret/ip2net package/zapret/ip2net +rm -f package/zapret/tpws/tpws/tpws package/zapret/nfqws/nfq/nfqws package/zapret/mdig/mdig/mdig package/zapret/ip2net/ip2net/ip2net + +4) Compile + +make package/{tpws,nfqws,mdig,ip2net}/compile + +5) Get result + +ls -l bin/packages/*/base +# take your ipk or apk from there diff --git a/docs/readme.md b/docs/readme.md index e93b529..0edd17c 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -1326,9 +1326,12 @@ linux, но через раз приобретает статус INVALID в con переменные. ``` -DOMAINS - список тестируемых доменов через пробел +CURL - замена программы curl CURL_MAX_TIME - время таймаута curl в секундах CURL_MAX_TIME_QUIC - время таймаута curl для quic. если не задано, используется значение CURL_MAX_TIME +CURL_CMD=1 - показывать команды curl +CURL_OPT - дополнительные параметры curl. `-k` - игнор сертификатов. `-v` - подробный вывод протокола +DOMAINS - список тестируемых доменов через пробел HTTP_PORT, HTTPS_PORT, QUIC_PORT - номера портов для соответствующих протоколов SKIP_DNSCHECK=1 - отказ от проверки DNS SKIP_TPWS=1 - отказ от тестов tpws @@ -1338,7 +1341,6 @@ PKTWS_EXTRA_1 .. PKTWS_EXTRA_9, TPWS_EXTRA_1 .. TPWS_EXTRA_9 - отдельно SECURE_DNS=0|1 - принудительно выключить или включить DoH DOH_SERVERS - список URL DoH через пробел для автоматического выбора работающего сервера DOH_SERVER - конкретный DoH URL, отказ от поиска -CURL - замена программы curl ``` Пример запуска с переменными:\ @@ -1471,7 +1473,7 @@ nfqws начнет получать адреса пакетов из локал Таким образом, все 3 режима вполне могут задействоваться вместе. Так же безусловно и независимо, в добавок к стандартным опциям, применяются все custom скрипты в `init.d/{sysv,openwrt,macos}/custom.d`. -Однако, при комбинировании tpws и nfqws не все так просто , как может показаться на первый взгляд. +Однако, при комбинировании tpws и nfqws с пересечением по L3/L4 протоколам не все так просто , как может показаться на первый взгляд. Первым всегда работает tpws, за ним - nfqws. На nfqws попадает уже "задуренный" трафик от tpws. Получается, что дурилка дурит дурилку, и дурилка не срабатывает, потому что ее задурили. Вот такой веселый момент. nfqws перестает распознавать протоколы и применять методы. @@ -1480,6 +1482,8 @@ nfqws начнет получать адреса пакетов из локал Комбинирование tpws и nfqws является продвинутым вариантом, требующим глубокого понимания происходящего. Очень желательно проанализировать действия nfqws по `--debug` логу. Все ли так, как вы задумали. +Одновременное использование tpws и nfqws без пересечения по L3/L4 (то есть nfqws - udp, tpws - tcp или nfqws - port 443, tpws - port 80 или nfqws - ipv4, tpws - ipv6) проблем не представляет. + `tpws-socks` требует настройки параметров `tpws`, но не требует перехвата трафика. Остальные опции требуют раздельно настройки перехвата трафика и опции самих демонов. Каждая опция предполагает запуск одного инстанса соответствующего демона. Все различия методов дурения @@ -2143,7 +2147,7 @@ Openwrt является одной из немногих относительн Если не работает автономный обход, приходится перенаправлять трафик через сторонний хост. Предлагается использовать прозрачный редирект через socks5 посредством `iptables+redsocks`, либо `iptables+iproute+vpn`. Настройка варианта с redsocks на openwrt описана в [redsocks.txt](./redsocks.txt). -Настройка варианта с `iproute+wireguard` - в [wireguard_iproute_openwrt.txt](./wireguard/wireguard_iproute_openwrt.txt). +Настройка варианта с `iproute+wireguard` - в [wireguard_iproute_openwrt.txt](./wireguard_iproute_openwrt.txt). ## Почему стоит вложиться в покупку VPS diff --git a/docs/wireguard/010-wg-mod.patch b/docs/wireguard/010-wg-mod.patch deleted file mode 100644 index 1577da6..0000000 --- a/docs/wireguard/010-wg-mod.patch +++ /dev/null @@ -1,133 +0,0 @@ -Index: WireGuard-0.0.20190123/src/cookie.c -=================================================================== ---- WireGuard-0.0.20190123.orig/src/cookie.c -+++ WireGuard-0.0.20190123/src/cookie.c -@@ -193,6 +193,8 @@ void wg_cookie_message_create(struct mes - xchacha20poly1305_encrypt(dst->encrypted_cookie, cookie, COOKIE_LEN, - macs->mac1, COOKIE_LEN, dst->nonce, - checker->cookie_encryption_key); -+ // MOD : randomize trash -+ dst->header.trash = gen_trash(); - } - - void wg_cookie_message_consume(struct message_handshake_cookie *src, -Index: WireGuard-0.0.20190123/src/messages.h -=================================================================== ---- WireGuard-0.0.20190123.orig/src/messages.h -+++ WireGuard-0.0.20190123/src/messages.h -@@ -53,23 +53,41 @@ enum limits { - MAX_QUEUED_PACKETS = 1024 /* TODO: replace this with DQL */ - }; - -+/* - enum message_type { -- MESSAGE_INVALID = 0, -- MESSAGE_HANDSHAKE_INITIATION = 1, -- MESSAGE_HANDSHAKE_RESPONSE = 2, -- MESSAGE_HANDSHAKE_COOKIE = 3, -- MESSAGE_DATA = 4 -+ MESSAGE_INVALID = 0, -+ MESSAGE_HANDSHAKE_INITIATION = 1, -+ MESSAGE_HANDSHAKE_RESPONSE = 2, -+ MESSAGE_HANDSHAKE_COOKIE = 3, -+ MESSAGE_DATA = 4 - }; -+*/ -+ -+// MOD : message type -+enum message_type { -+ MESSAGE_INVALID = 0xE319CCD0, -+ MESSAGE_HANDSHAKE_INITIATION = 0x48ADE198, -+ MESSAGE_HANDSHAKE_RESPONSE = 0xFCA6A8F3, -+ MESSAGE_HANDSHAKE_COOKIE = 0x64A3BB18, -+ MESSAGE_DATA = 0x391820AA -+}; -+ -+// MOD : generate fast trash without true RNG -+__le32 gen_trash(void); - - struct message_header { -- /* The actual layout of this that we want is: -- * u8 type -- * u8 reserved_zero[3] -- * -- * But it turns out that by encoding this as little endian, -- * we achieve the same thing, and it makes checking faster. -- */ -- __le32 type; -+ /* The actual layout of this that we want is: -+ * u8 type -+ * u8 reserved_zero[3] -+ * -+ * But it turns out that by encoding this as little endian, -+ * we achieve the same thing, and it makes checking faster. -+ */ -+ -+ // MOD : trash field to change message size and add 4 byte offset to all fields -+ __le32 trash; -+ -+ __le32 type; - }; - - struct message_macs { -Index: WireGuard-0.0.20190123/src/noise.c -=================================================================== ---- WireGuard-0.0.20190123.orig/src/noise.c -+++ WireGuard-0.0.20190123/src/noise.c -@@ -17,6 +17,24 @@ - #include - #include - -+ -+// MOD : trash generator -+__le32 gtrash = 0; -+__le32 gen_trash(void) -+{ -+ if (gtrash) -+ gtrash = gtrash*1103515243 + 12345; -+ else -+ // first value is true random -+ get_random_bytes_wait(>rash, sizeof(gtrash)); -+ return gtrash; -+} -+ - /* This implements Noise_IKpsk2: - * - * <- s -@@ -515,6 +533,10 @@ wg_noise_handshake_create_initiation(str - &handshake->entry); - - handshake->state = HANDSHAKE_CREATED_INITIATION; -+ -+ // MOD : randomize trash -+ dst->header.trash = gen_trash(); -+ - ret = true; - - out: -@@ -655,6 +677,10 @@ bool wg_noise_handshake_create_response( - &handshake->entry); - - handshake->state = HANDSHAKE_CREATED_RESPONSE; -+ -+ // MOD : randomize trash -+ dst->header.trash = gen_trash(); -+ - ret = true; - - out: -Index: WireGuard-0.0.20190123/src/send.c -=================================================================== ---- WireGuard-0.0.20190123.orig/src/send.c -+++ WireGuard-0.0.20190123/src/send.c -@@ -200,6 +200,10 @@ static bool encrypt_packet(struct sk_buf - header->header.type = cpu_to_le32(MESSAGE_DATA); - header->key_idx = keypair->remote_index; - header->counter = cpu_to_le64(PACKET_CB(skb)->nonce); -+ -+ // MOD : randomize trash -+ header->header.trash = gen_trash(); -+ - pskb_put(skb, trailer, trailer_len); - - /* Now we can encrypt the scattergather segments */ diff --git a/docs/wireguard/wireguard-mod.txt b/docs/wireguard/wireguard-mod.txt deleted file mode 100644 index 878aa44..0000000 --- a/docs/wireguard/wireguard-mod.txt +++ /dev/null @@ -1,250 +0,0 @@ -!!! Эта инструкция написана еще до включения wireguard в ядро linux. -!!! Процесс сборки для in-tree модулей отличается. -!!! Цель данного чтива - дать идею для программистов как можно исправить исходники wireguard -!!! для преодоления DPI. Автор не преследует цели поддерживать готовые патчи для актуальных версий. -!!! Вместо патчинга гораздо проще использовать навесное решение ipobfs. - -Посвящено возможной блокировке в РФ VPN протоколов через DPI. -Предпосылками являются последние законодательные акты и во всю сочащиеся "секретные" записки. -В РФ разрабатываются и готовятся к применению более продвинутые решения по блокировке трафика. -Вполне вероятно будут резать стандартные VPN протоколы. Нам надо быть к этому готовыми. - -Один из возможных и перспективных путей решения данного вопроса - кустомная модификация -исходников VPN с целью незначительного изменения протокола, ломающего стандартные модули обнаружения в DPI. -Это относительно сложно, доступно только для гиков. -Никто не будет разрабатывать специальные модули обнаружения в DPI, если только кто-то не сделает простое и -удобное решение для всех, и его станут широко применять. Но это маловероятно, и даже если и так, -то всегда можно модифицировать протокол чуток по другому. Делать моды для DPI несравненно дольше -и дороже, чем клепать на коленке изменения протокола для wireguard. - - -ЗАМЕЧЕНИЕ : альтернативой модификации конечного софта для VPN является использование "навесных" -обфускаторов. см : https://github.com/bol-van/ipobfs - - -Рассмотрю что нам надо пропатчить в wireguard. Модифицированный wireguard проверен на виртуалках -с десктопным linux, он работает, сообщения в wireshark действительно не вписываются в стандартный -протокол и не опознаются. - -Wireguard протокол очень простой. Все сообщения описаны в messages.h -Поставим себе целью сделать 2 простые модификации : -1) Добавим в начало всех сообщений немного мусора, чтобы изменить размер сообщений и смещения полей -2) Изменим коды типов сообщений -Этого может быть вполне достаточно для обмана DPI - ---messages.h-------------------------- -/* -enum message_type { - MESSAGE_INVALID = 0, - MESSAGE_HANDSHAKE_INITIATION = 1, - MESSAGE_HANDSHAKE_RESPONSE = 2, - MESSAGE_HANDSHAKE_COOKIE = 3, - MESSAGE_DATA = 4 -}; -*/ - -// MOD : message type -enum message_type { - MESSAGE_INVALID = 0xE319CCD0, - MESSAGE_HANDSHAKE_INITIATION = 0x48ADE198, - MESSAGE_HANDSHAKE_RESPONSE = 0xFCA6A8F3, - MESSAGE_HANDSHAKE_COOKIE = 0x64A3BB18, - MESSAGE_DATA = 0x391820AA -}; - -// MOD : generate fast trash without true RNG -__le32 gen_trash(void); - -struct message_header { - /* The actual layout of this that we want is: - * u8 type - * u8 reserved_zero[3] - * - * But it turns out that by encoding this as little endian, - * we achieve the same thing, and it makes checking faster. - */ - - // MOD : trash field to change message size and add 4 byte offset to all fields - __le32 trash; - - __le32 type; -}; --------------------------------------- - -Напишем функцию для генерации trash. Функция должна быть быстрая, важно не замедлить скорость. -Мы не расчитываем, что нас будут специально ловить, иначе бы пришлось делать полноценный обфускатор. -Задача лишь сломать стандартный модуль обнаружения протокола wireguard. Потому истинная рандомность -trash не важна. -Но все же немного "трэша" не повредит. Гонки между тредами так же пофигистичны. Это же трэш. - ---noise.c----------------------------- -// MOD : trash generator -__le32 gtrash = 0; -__le32 gen_trash(void) -{ - if (gtrash) - gtrash = gtrash*1103515243 + 12345; - else - // first value is true random - get_random_bytes_wait(>rash, sizeof(gtrash)); - return gtrash; -} --------------------------------------- - -Теперь осталось найти все места, где создаются сообщения и внести туда заполнение поля trash. -Сообщений всего 4. Их можно найти по присваиванию полю type одного из значений enum message_type. - -2 места в noise.c в функциях wg_noise_handshake_create_initiation и wg_noise_handshake_create_response, -1 место в cookie.c в функции wg_cookie_message_create -Дописываем в конец инициализации структуры сообщения : - --------------------------------------- - // MOD : randomize trash - dst->header.trash = gen_trash(); --------------------------------------- - -и 1 место в send.c в функции encrypt_packet - --------------------------------------- - // MOD : randomize trash - header->header.trash = gen_trash(); --------------------------------------- - - -Вот и весь патчинг. Полный patch (версия wireguard 0.0.20190123) лежит в 010-wg-mod.patch. -Патчинг кода - самое простое. Для десктопного linux дальше все просто. -Пересобираем через make, устанавливаем через make install, перегружаем -модуль wireguard, перезапускаем интерфейсы, и все готово. - -Настоящий геморой начнется когда вы это попытаетесь засунуть на роутер под openwrt. -Одна из больших проблем linux - отсутствие совместимости драйверов на уровне бинариков. -Поэтому собирать необходимо в точности под вашу версию ядра и в точности под его .config. -Вам придется либо полностью самостоятельно собирать всю прошивку, либо найти SDK в точности -от вашей версии прошивки для вашей архитектуры и собрать модуль с помощью этого SDK. -Последний вариант более легкий. -Для сборки вам понадобится система на linux x86_64. Ее можно установить в виртуалке. -Теоретически можно пользоваться WSL из win10, но на практике там очень медленное I/O, -по крайней мере на старых версиях win10. Безумно медленное. Будете собирать вечность. -Может в новых win10 что-то и улучшили, но я бы сразу расчитывал на полноценный linux. - -Находим здесь вашу версию : https://downloads.openwrt.org/ -Скачиваем файл openwrt-sdk-*.tar.xz или lede-sdk-*.tar.xz -Например : https://downloads.openwrt.org/releases/18.06.2/targets/ar71xx/generic/openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64.tar.xz -Если ваша версия непонятна или стара, то проще будет найти последнюю прошивку и перешить роутер. -Распаковываем SDK. Следующими командами можно собрать оригинальный вариант wireguard : - -# scripts/feeds update -a -# scripts/feeds install -a -# make defconfig -# make -j 4 package/wireguard/compile - -Сборка будет довольно долгой. Ведь придется подтащить ядро, собрать его, собрать зависимости. -"-j 4" означает использовать 4 потока. Впишите вместо 4 количество доступных cpu cores. - -Получим следующие файлы : - -openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/bin/targets/ar71xx/generic/packages/kmod-wireguard_4.9.152+0.0.20190123-1_mips_24kc.ipk -openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/bin/packages/mips_24kc/base/wireguard-tools_0.0.20190123-1_mips_24kc.ipk - -Но это будет оригинальный wireguard. Нам нужен патченый. -Установим quilt и mc для нормального редактора вместо vim : - -# sudo apt-get update -# sudo apt-get install quilt mc - -# make package/wireguard/clean -# make package/wireguard/prepare V=s QUILT=1 - - -Сорцы приготовлены для сборки в : - openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/build_dir/target-mips_24kc_musl/linux-ar71xx_generic/WireGuard-0.0.20190123/src - -# cd build_dir/target-mips_24kc_musl/linux-ar71xx_generic/WireGuard-0.0.20190123/src -# quilt push -a -# quilt new 010-wg-mod.patch -# export EDITOR=mcedit - -Далее будет открываться редактор mcedit, в который нужно вносить изменения в каждый файл : - -# quilt edit messages.h -# quilt edit cookie.c -# quilt edit noise.c -# quilt edit send.c -# quilt diff -# quilt refresh - -Получили файл патча в : -openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/build_dir/target-mips_24kc_musl/linux-ar71xx_generic/WireGuard-0.0.20190123/patches/010-wg-mod.patch - -Выходим в корень SDK. - -# make package/wireguard/compile V=99 - -Если не было ошибок, то получили измененные ipk. -Патч можно зафиксировать в описании пакета : - -# make package/wireguard/update - -Получим : -openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/feeds/base/package/network/services/wireguard/patches/010-wg-mod.patch -При последующей очистке и пересборке он будет автоматом применяться. - - -АЛЬТЕРНАТИВА : можно не возиться с quilt. -сделайте -# make package/wireguard/clean -# make package/wireguard/prepare -и напрямую модифицируйте или копируйте файлы в - openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/build_dir/target-mips_24kc_musl/linux-ar71xx_generic/WireGuard-0.0.20190123/src -затем -# make package/wireguard/compile - -Если нужно поменять версию wireguard, то идите в -openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/feeds/base/package/network/services/wireguard/Makefile -поменяйте там версию в PKG_VERSION на последнюю из : https://git.zx2c4.com/WireGuard -скачайте tar.xz с этой версией , вычислите его sha256sum, впишите в PKG_HASH - -1 раз где-нибудь пропатчите файлы последней версии wireguard в текстовом редакторе, скопируйте в build_dir, -сделайте версию для openwrt. эти же файлы скопируйте на ваш сервер с десктопным linux, сделайте там make / make install - -Но имейте в виду, что build_dir - локация для временных файлов. -make clean оттуда все снесет, включая ваши модификации. Модифицированные файлы лучше сохранить отдельно, -чтобы потом было легко скопировать обратно. - -Полученные ipk копируем на роутер в /tmp, устанавливаем через -# cd /tmp -# rm -r /tmp/opkg-lists -# opkg install *.ipk -Если требует зависимостей, то -# opkg update -# opkg install .... <зависимости> -# rm -r /tmp/opkg-lists -# opkg install *.ipk - -В /tmp/opkg-lists opkg хранит кэш списка пакетов. Если попытаться установить файл ipk, и такой же пакет -найдется в репозитории, opkg будет устанавливать из репозитория. А нам это не надо. - -# rmmod wireguard -# kmodloader -# dmesg | tail -должны увидеть что-то вроде : -[8985.415490] wireguard: WireGuard 0.0.20190123 loaded. See www.wireguard.com for information. -[8985.424178] wireguard: Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. -значит модуль загрузился - -Могут понадобиться ключи opkg --force-reinstall, --force-depends. ---force-depends поможет при несоответствии hash версии ядра. То есть версия x.x.x та же самая, но hash конфигурации разный. -При несоответствии x.x.x вы что-то делаете не так, работать это не будет. -Например : 4.14.56-1-b1186491495127cc6ff81d29c00a91fc, 4.14.56-1-3f8a21a63974cfb7ee67e41f2d4b805d -Это свидетельствует о несоответствии .config ядра при сборке прошивки и в SDK. -Если несоответствие легкое, то может все прокатить, но при более серьезной разнице в .config модуль может не загрузиться -или вызвать стабильные или хаотические падения ядра и перезагрузки (включая вариант беcконечной перезагрузки - bootloop). -Так что перед --force-depends убедитесь, что знаете как лечится такая ситуация, и не стоит это делать при отсутствии физического -доступа к девайсу. - -Когда поднимите линк, и вдруг ничего не будет работать, то посмотрите в wireshark udp пакеты -на порт endpoint. Они не должны начинаться с 0,1,2,3,4. В первых 4 байтах должен быть рандом, -в следующих 4 байтах - значения из измененного enum message_type. Если пакет все еще начинается с 0..4, -значит модуль wireguard оригинальный, что-то не собралось, не скопировалось, не перезапустилось. -В противном случае должен подняться линк, пинги ходить. Значит вы победили, поздравляю. -Регулятору будет намного сложнее поймать ваш VPN. diff --git a/docs/wireguard/wireguard_iproute_openwrt.txt b/docs/wireguard_iproute_openwrt.txt similarity index 98% rename from docs/wireguard/wireguard_iproute_openwrt.txt rename to docs/wireguard_iproute_openwrt.txt index 8258b44..f9d610a 100644 --- a/docs/wireguard/wireguard_iproute_openwrt.txt +++ b/docs/wireguard_iproute_openwrt.txt @@ -236,7 +236,7 @@ config rule --- Подготовка zapret --- -Выполните install_easy.sh. Он настроит режим обхода DPI. Если обход DPI не нужен - выберите MODE=filter. +Выполните install_easy.sh. Он настроит режим обхода DPI. Если обход DPI не нужен - не включайте tpws и nfqws. Так же инсталятор заресолвит домены из ipset/zapret-hosts-user-ipban.txt и внесет крон-джоб для периодического обновления ip. Если вы используете в своих правилах ipset zapret, то он ресолвится и обновляется только, если выбран режим фильтрации обхода DPI по ipset. diff --git a/ip2net/Makefile b/ip2net/Makefile index 56f6b17..b144893 100644 --- a/ip2net/Makefile +++ b/ip2net/Makefile @@ -9,7 +9,9 @@ SRC_FILES = ip2net.c qsort.c all: ip2net ip2net: $(SRC_FILES) - $(CC) -s $(CFLAGS) -o $@ $(SRC_FILES) $(LDFLAGS) $(LIBS) + $(CC) -s $(CFLAGS) -o ip2net $(SRC_FILES) $(LDFLAGS) $(LIBS) + +android: ip2net bsd: $(SRC_FILES) $(CC) -s $(CFLAGS) $(CFLAGS_BSD) -o ip2net $(SRC_FILES) $(LDFLAGS) $(LIBS) diff --git a/mdig/Makefile b/mdig/Makefile index 0100b5b..ae2137a 100644 --- a/mdig/Makefile +++ b/mdig/Makefile @@ -3,13 +3,17 @@ CFLAGS += -std=gnu99 -Os CFLAGS_BSD = -Wno-address-of-packed-member CFLAGS_WIN = -static LIBS = -lpthread +LIBS_ANDROID = LIBS_WIN = -lws2_32 SRC_FILES = *.c all: mdig mdig: $(SRC_FILES) - $(CC) -s $(CFLAGS) -o $@ $(SRC_FILES) $(LDFLAGS) $(LIBS) + $(CC) -s $(CFLAGS) -o mdig $(SRC_FILES) $(LDFLAGS) $(LIBS) + +android: $(SRC_FILES) + $(CC) -s $(CFLAGS) -o mdig $(SRC_FILES) $(LDFLAGS) $(LIBS_ANDROID) bsd: $(SRC_FILES) $(CC) -s $(CFLAGS) $(CFLAGS_BSD) -o mdig $(SRC_FILES) $(LDFLAGS) $(LIBS) diff --git a/nfq/BSDmakefile b/nfq/BSDmakefile index ff5475e..e782a07 100644 --- a/nfq/BSDmakefile +++ b/nfq/BSDmakefile @@ -6,7 +6,7 @@ SRC_FILES = *.c crypto/*.c all: dvtws dvtws: $(SRC_FILES) - $(CC) $(CFLAGS) -o $@ $(SRC_FILES) $(LDFLAGS) $(LIBS) + $(CC) $(CFLAGS) -o dvtws $(SRC_FILES) $(LDFLAGS) $(LIBS) clean: rm -f dvtws diff --git a/nfq/Makefile b/nfq/Makefile index 8e4c058..92adf99 100644 --- a/nfq/Makefile +++ b/nfq/Makefile @@ -15,7 +15,9 @@ SRC_FILES = *.c crypto/*.c all: nfqws nfqws: $(SRC_FILES) - $(CC) -s $(CFLAGS) -o $@ $(SRC_FILES) $(LDFLAGS) $(LIBS_LINUX) + $(CC) -s $(CFLAGS) -o nfqws $(SRC_FILES) $(LDFLAGS) $(LIBS_LINUX) + +android: nfqws bsd: $(SRC_FILES) $(CC) -s $(CFLAGS) $(CFLAGS_BSD) -o dvtws $(SRC_FILES) $(LDFLAGS) $(LIBS_BSD) diff --git a/nfq/dvtws b/nfq/dvtws new file mode 100644 index 0000000..2d9d47e Binary files /dev/null and b/nfq/dvtws differ diff --git a/nfq/nfqws.c b/nfq/nfqws.c index da81369..5da3750 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -552,7 +552,7 @@ static bool parse_ws_scale_factor(char *s, uint16_t *wsize, uint8_t *wscale) -#ifndef __OpenBSD__ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) static void cleanup_args() { wordfree(¶ms.wexp); @@ -561,7 +561,7 @@ static void cleanup_args() static void cleanup_params(void) { -#ifndef __OpenBSD__ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) cleanup_args(); #endif @@ -985,7 +985,7 @@ static unsigned int hash_jen(const void *data,unsigned int len) static void exithelp(void) { printf( -#ifndef __OpenBSD__ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) " @|$\t\t\t; read file for options. must be the only argument. other options are ignored.\n\n" #endif " --debug=0|1|syslog|@\n" @@ -1099,7 +1099,7 @@ static void exithelp_clean(void) exithelp(); } -#ifndef __OpenBSD__ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) // no static to not allow optimizer to inline this func (save stack) void config_from_file(const char *filename) { @@ -1192,7 +1192,7 @@ int main(int argc, char **argv) } #endif -#ifndef __OpenBSD__ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) if (argc>=2 && (argv[1][0]=='@' || argv[1][0]=='$')) { config_from_file(argv[1]+1); @@ -1963,7 +1963,7 @@ int main(int argc, char **argv) } // do not need args from file anymore -#ifndef __OpenBSD__ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) cleanup_args(); #endif argv=NULL; argc=0; diff --git a/nfq/params.h b/nfq/params.h index 630d20d..3b59f36 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -14,7 +14,7 @@ #include #include #include -#ifndef __OpenBSD__ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) #include #endif @@ -104,7 +104,7 @@ bool dp_list_have_autohostlist(struct desync_profile_list_head *head); struct params_s { -#ifndef __OpenBSD__ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) wordexp_t wexp; // for file based config #endif diff --git a/tpws/BSDmakefile b/tpws/BSDmakefile index e9ad901..c86e4bd 100644 --- a/tpws/BSDmakefile +++ b/tpws/BSDmakefile @@ -6,7 +6,7 @@ SRC_FILES = *.c all: tpws tpws: $(SRC_FILES) - $(CC) $(CFLAGS) -Iepoll-shim/include -o $@ $(SRC_FILES) epoll-shim/src/*.c $(LDFLAGS) $(LIBS) + $(CC) $(CFLAGS) -Iepoll-shim/include -o tpws $(SRC_FILES) epoll-shim/src/*.c $(LDFLAGS) $(LIBS) clean: rm -f tpws *.o diff --git a/tpws/Makefile b/tpws/Makefile index b2b00ea..00814c4 100644 --- a/tpws/Makefile +++ b/tpws/Makefile @@ -2,12 +2,17 @@ CC ?= gcc CFLAGS += -std=gnu99 -Os CFLAGS_BSD = -Wno-address-of-packed-member LIBS = -lz -lpthread +LIBS_ANDROID = -lz SRC_FILES = *.c +SRC_FILES_ANDROID = $(SRC_FILES) andr/*.c all: tpws tpws: $(SRC_FILES) - $(CC) -s $(CFLAGS) -o $@ $(SRC_FILES) $(LDFLAGS) $(LIBS) + $(CC) -s $(CFLAGS) -o tpws $(SRC_FILES) $(LDFLAGS) $(LIBS) + +android: $(SRC_FILES) + $(CC) -s $(CFLAGS) -o tpws $(SRC_FILES_ANDROID) $(LDFLAGS) $(LIBS_ANDROID) bsd: $(SRC_FILES) $(CC) -s $(CFLAGS) $(CFLAGS_BSD) -Iepoll-shim/include -o tpws $(SRC_FILES) epoll-shim/src/*.c $(LDFLAGS) $(LIBS) diff --git a/tpws/andr/_musl_license.txt b/tpws/andr/_musl_license.txt new file mode 100644 index 0000000..5ae13c6 --- /dev/null +++ b/tpws/andr/_musl_license.txt @@ -0,0 +1,26 @@ +Code in this dir is taken from musl libc to support old android versions <7.0 + +musl as a whole is licensed under the following standard MIT license: + +---------------------------------------------------------------------- +Copyright 2005-2020 Rich Felker, et al. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------- diff --git a/tpws/andr/getifaddrs.c b/tpws/andr/getifaddrs.c new file mode 100644 index 0000000..74df4d6 --- /dev/null +++ b/tpws/andr/getifaddrs.c @@ -0,0 +1,216 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include "netlink.h" + +#define IFADDRS_HASH_SIZE 64 + +/* getifaddrs() reports hardware addresses with PF_PACKET that implies + * struct sockaddr_ll. But e.g. Infiniband socket address length is + * longer than sockaddr_ll.ssl_addr[8] can hold. Use this hack struct + * to extend ssl_addr - callers should be able to still use it. */ +struct sockaddr_ll_hack { + unsigned short sll_family, sll_protocol; + int sll_ifindex; + unsigned short sll_hatype; + unsigned char sll_pkttype, sll_halen; + unsigned char sll_addr[24]; +}; + +union sockany { + struct sockaddr sa; + struct sockaddr_ll_hack ll; + struct sockaddr_in v4; + struct sockaddr_in6 v6; +}; + +struct ifaddrs_storage { + struct ifaddrs ifa; + struct ifaddrs_storage *hash_next; + union sockany addr, netmask, ifu; + unsigned int index; + char name[IFNAMSIZ+1]; +}; + +struct ifaddrs_ctx { + struct ifaddrs *first; + struct ifaddrs *last; + struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE]; +}; + +void freeifaddrs(struct ifaddrs *ifp) +{ + struct ifaddrs *n; + while (ifp) { + n = ifp->ifa_next; + free(ifp); + ifp = n; + } +} + +static void copy_addr(struct sockaddr **r, int af, union sockany *sa, void *addr, size_t addrlen, int ifindex) +{ + uint8_t *dst; + int len; + + switch (af) { + case AF_INET: + dst = (uint8_t*) &sa->v4.sin_addr; + len = 4; + break; + case AF_INET6: + dst = (uint8_t*) &sa->v6.sin6_addr; + len = 16; + if (IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_MC_LINKLOCAL(addr)) + sa->v6.sin6_scope_id = ifindex; + break; + default: + return; + } + if (addrlen < len) return; + sa->sa.sa_family = af; + memcpy(dst, addr, len); + *r = &sa->sa; +} + +static void gen_netmask(struct sockaddr **r, int af, union sockany *sa, int prefixlen) +{ + uint8_t addr[16] = {0}; + int i; + + if (prefixlen > 8*sizeof(addr)) prefixlen = 8*sizeof(addr); + i = prefixlen / 8; + memset(addr, 0xff, i); + if (i < sizeof(addr)) addr[i++] = 0xff << (8 - (prefixlen % 8)); + copy_addr(r, af, sa, addr, sizeof(addr), 0); +} + +static void copy_lladdr(struct sockaddr **r, union sockany *sa, void *addr, size_t addrlen, int ifindex, unsigned short hatype) +{ + if (addrlen > sizeof(sa->ll.sll_addr)) return; + sa->ll.sll_family = AF_PACKET; + sa->ll.sll_ifindex = ifindex; + sa->ll.sll_hatype = hatype; + sa->ll.sll_halen = addrlen; + memcpy(sa->ll.sll_addr, addr, addrlen); + *r = &sa->sa; +} + +static int netlink_msg_to_ifaddr(void *pctx, struct nlmsghdr *h) +{ + struct ifaddrs_ctx *ctx = pctx; + struct ifaddrs_storage *ifs, *ifs0; + struct ifinfomsg *ifi = NLMSG_DATA(h); + struct ifaddrmsg *ifa = NLMSG_DATA(h); + struct rtattr *rta; + int stats_len = 0; + + if (h->nlmsg_type == RTM_NEWLINK) { + for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + if (rta->rta_type != IFLA_STATS) continue; + stats_len = RTA_DATALEN(rta); + break; + } + } else { + for (ifs0 = ctx->hash[ifa->ifa_index % IFADDRS_HASH_SIZE]; ifs0; ifs0 = ifs0->hash_next) + if (ifs0->index == ifa->ifa_index) + break; + if (!ifs0) return 0; + } + + ifs = calloc(1, sizeof(struct ifaddrs_storage) + stats_len); + if (ifs == 0) return -1; + + if (h->nlmsg_type == RTM_NEWLINK) { + ifs->index = ifi->ifi_index; + ifs->ifa.ifa_flags = ifi->ifi_flags; + + for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + switch (rta->rta_type) { + case IFLA_IFNAME: + if (RTA_DATALEN(rta) < sizeof(ifs->name)) { + memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta)); + ifs->ifa.ifa_name = ifs->name; + } + break; + case IFLA_ADDRESS: + copy_lladdr(&ifs->ifa.ifa_addr, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifi->ifi_index, ifi->ifi_type); + break; + case IFLA_BROADCAST: + copy_lladdr(&ifs->ifa.ifa_broadaddr, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifi->ifi_index, ifi->ifi_type); + break; + case IFLA_STATS: + ifs->ifa.ifa_data = (void*)(ifs+1); + memcpy(ifs->ifa.ifa_data, RTA_DATA(rta), RTA_DATALEN(rta)); + break; + } + } + if (ifs->ifa.ifa_name) { + unsigned int bucket = ifs->index % IFADDRS_HASH_SIZE; + ifs->hash_next = ctx->hash[bucket]; + ctx->hash[bucket] = ifs; + } + } else { + ifs->ifa.ifa_name = ifs0->ifa.ifa_name; + ifs->ifa.ifa_flags = ifs0->ifa.ifa_flags; + for (rta = NLMSG_RTA(h, sizeof(*ifa)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + switch (rta->rta_type) { + case IFA_ADDRESS: + /* If ifa_addr is already set we, received an IFA_LOCAL before + * so treat this as destination address */ + if (ifs->ifa.ifa_addr) + copy_addr(&ifs->ifa.ifa_dstaddr, ifa->ifa_family, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index); + else + copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index); + break; + case IFA_BROADCAST: + copy_addr(&ifs->ifa.ifa_broadaddr, ifa->ifa_family, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index); + break; + case IFA_LOCAL: + /* If ifa_addr is set and we get IFA_LOCAL, assume we have + * a point-to-point network. Move address to correct field. */ + if (ifs->ifa.ifa_addr) { + ifs->ifu = ifs->addr; + ifs->ifa.ifa_dstaddr = &ifs->ifu.sa; + memset(&ifs->addr, 0, sizeof(ifs->addr)); + } + copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index); + break; + case IFA_LABEL: + if (RTA_DATALEN(rta) < sizeof(ifs->name)) { + memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta)); + ifs->ifa.ifa_name = ifs->name; + } + break; + } + } + if (ifs->ifa.ifa_addr) + gen_netmask(&ifs->ifa.ifa_netmask, ifa->ifa_family, &ifs->netmask, ifa->ifa_prefixlen); + } + + if (ifs->ifa.ifa_name) { + if (!ctx->first) ctx->first = &ifs->ifa; + if (ctx->last) ctx->last->ifa_next = &ifs->ifa; + ctx->last = &ifs->ifa; + } else { + free(ifs); + } + return 0; +} + +int getifaddrs(struct ifaddrs **ifap) +{ + struct ifaddrs_ctx _ctx, *ctx = &_ctx; + int r; + memset(ctx, 0, sizeof *ctx); + r = __rtnetlink_enumerate(AF_UNSPEC, AF_UNSPEC, netlink_msg_to_ifaddr, ctx); + if (r == 0) *ifap = ctx->first; + else freeifaddrs(ctx->first); + return r; +} diff --git a/tpws/andr/ifaddrs.h b/tpws/andr/ifaddrs.h new file mode 100644 index 0000000..a729809 --- /dev/null +++ b/tpws/andr/ifaddrs.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +#if __ANDROID_API__ < 24 +void freeifaddrs(struct ifaddrs *); +int getifaddrs(struct ifaddrs **); +#endif diff --git a/tpws/andr/netlink.c b/tpws/andr/netlink.c new file mode 100644 index 0000000..ad61a2d --- /dev/null +++ b/tpws/andr/netlink.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include + +#include "netlink.h" + +static int __netlink_enumerate(int fd, unsigned int seq, int type, int af, + int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx) +{ + struct nlmsghdr *h; + union { + uint8_t buf[8192]; + struct { + struct nlmsghdr nlh; + struct rtgenmsg g; + } req; + struct nlmsghdr reply; + } u; + int r, ret; + + memset(&u.req, 0, sizeof(u.req)); + u.req.nlh.nlmsg_len = sizeof(u.req); + u.req.nlh.nlmsg_type = type; + u.req.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; + u.req.nlh.nlmsg_seq = seq; + u.req.g.rtgen_family = af; + r = send(fd, &u.req, sizeof(u.req), 0); + if (r < 0) return r; + + while (1) { + r = recv(fd, u.buf, sizeof(u.buf), MSG_DONTWAIT); + if (r <= 0) return -1; + for (h = &u.reply; NLMSG_OK(h, (void*)&u.buf[r]); h = NLMSG_NEXT(h)) { + if (h->nlmsg_type == NLMSG_DONE) return 0; + if (h->nlmsg_type == NLMSG_ERROR) return -1; + ret = cb(ctx, h); + if (ret) return ret; + } + } +} + +int __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx) +{ + int fd, r; + + fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE); + if (fd < 0) return -1; + r = __netlink_enumerate(fd, 1, RTM_GETLINK, link_af, cb, ctx); + if (!r) r = __netlink_enumerate(fd, 2, RTM_GETADDR, addr_af, cb, ctx); + close(fd); + return r; +} diff --git a/tpws/andr/netlink.h b/tpws/andr/netlink.h new file mode 100644 index 0000000..939c56c --- /dev/null +++ b/tpws/andr/netlink.h @@ -0,0 +1,94 @@ +#include + +/* linux/netlink.h */ + +#define NETLINK_ROUTE 0 + +struct nlmsghdr { + uint32_t nlmsg_len; + uint16_t nlmsg_type; + uint16_t nlmsg_flags; + uint32_t nlmsg_seq; + uint32_t nlmsg_pid; +}; + +#define NLM_F_REQUEST 1 +#define NLM_F_MULTI 2 +#define NLM_F_ACK 4 + +#define NLM_F_ROOT 0x100 +#define NLM_F_MATCH 0x200 +#define NLM_F_ATOMIC 0x400 +#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH) + +#define NLMSG_NOOP 0x1 +#define NLMSG_ERROR 0x2 +#define NLMSG_DONE 0x3 +#define NLMSG_OVERRUN 0x4 + +/* linux/rtnetlink.h */ + +#define RTM_NEWLINK 16 +#define RTM_GETLINK 18 +#define RTM_NEWADDR 20 +#define RTM_GETADDR 22 + +struct rtattr { + unsigned short rta_len; + unsigned short rta_type; +}; + +struct rtgenmsg { + unsigned char rtgen_family; +}; + +struct ifinfomsg { + unsigned char ifi_family; + unsigned char __ifi_pad; + unsigned short ifi_type; + int ifi_index; + unsigned ifi_flags; + unsigned ifi_change; +}; + +/* linux/if_link.h */ + +#define IFLA_ADDRESS 1 +#define IFLA_BROADCAST 2 +#define IFLA_IFNAME 3 +#define IFLA_STATS 7 + +/* linux/if_addr.h */ + +struct ifaddrmsg { + uint8_t ifa_family; + uint8_t ifa_prefixlen; + uint8_t ifa_flags; + uint8_t ifa_scope; + uint32_t ifa_index; +}; + +#define IFA_ADDRESS 1 +#define IFA_LOCAL 2 +#define IFA_LABEL 3 +#define IFA_BROADCAST 4 + +/* musl */ + +#define NETLINK_ALIGN(len) (((len)+3) & ~3) +#define NLMSG_DATA(nlh) ((void*)((char*)(nlh)+sizeof(struct nlmsghdr))) +#define NLMSG_DATALEN(nlh) ((nlh)->nlmsg_len-sizeof(struct nlmsghdr)) +#define NLMSG_DATAEND(nlh) ((char*)(nlh)+(nlh)->nlmsg_len) +#define NLMSG_NEXT(nlh) (struct nlmsghdr*)((char*)(nlh)+NETLINK_ALIGN((nlh)->nlmsg_len)) +#define NLMSG_OK(nlh,end) ((char*)(end)-(char*)(nlh) >= sizeof(struct nlmsghdr)) + +#define RTA_DATA(rta) ((void*)((char*)(rta)+sizeof(struct rtattr))) +#define RTA_DATALEN(rta) ((rta)->rta_len-sizeof(struct rtattr)) +#define RTA_DATAEND(rta) ((char*)(rta)+(rta)->rta_len) +#define RTA_NEXT(rta) (struct rtattr*)((char*)(rta)+NETLINK_ALIGN((rta)->rta_len)) +#define RTA_OK(rta,end) ((char*)(end)-(char*)(rta) >= sizeof(struct rtattr)) + +#define NLMSG_RTA(nlh,len) ((void*)((char*)(nlh)+sizeof(struct nlmsghdr)+NETLINK_ALIGN(len))) +#define NLMSG_RTAOK(rta,nlh) RTA_OK(rta,NLMSG_DATAEND(nlh)) + +int __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx); diff --git a/tpws/helpers.c b/tpws/helpers.c index 94cff17..c25fd4f 100644 --- a/tpws/helpers.c +++ b/tpws/helpers.c @@ -7,11 +7,16 @@ #include #include #include -#include #include #include #include +#ifdef __ANDROID__ +#include "andr/ifaddrs.h" +#else +#include +#endif + #include "helpers.h" int unique_size_t(size_t *pu, int ct) diff --git a/tpws/params.h b/tpws/params.h index 3afa694..acf9f4a 100644 --- a/tpws/params.h +++ b/tpws/params.h @@ -6,7 +6,7 @@ #include #include #include -#ifndef __OpenBSD__ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) #include #endif @@ -85,7 +85,7 @@ void dp_list_destroy(struct desync_profile_list_head *head); struct params_s { -#ifndef __OpenBSD__ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) wordexp_t wexp; // for file based config #endif diff --git a/tpws/tpws.c b/tpws/tpws.c index 8136da3..8d30561 100644 --- a/tpws/tpws.c +++ b/tpws/tpws.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -25,6 +24,12 @@ #include #include +#ifdef __ANDROID__ +#include "andr/ifaddrs.h" +#else +#include +#endif + #include "tpws.h" #ifdef BSD @@ -122,7 +127,7 @@ static int get_default_ttl(void) static void exithelp(void) { printf( -#ifndef __OpenBSD__ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) " @|$\t\t; read file for options. must be the only argument. other options are ignored.\n\n" #endif " --bind-addr=|\t; for v6 link locals append %%interface_name\n" @@ -215,7 +220,7 @@ static void exithelp(void) ); exit(1); } -#ifndef __OpenBSD__ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) static void cleanup_args() { wordfree(¶ms.wexp); @@ -223,7 +228,7 @@ static void cleanup_args() #endif static void cleanup_params(void) { -#ifndef __OpenBSD__ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) cleanup_args(); #endif @@ -472,7 +477,7 @@ static bool parse_pf_list(char *opt, struct port_filters_head *pfl) return true; } -#ifndef __OpenBSD__ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) // no static to not allow optimizer to inline this func (save stack) void config_from_file(const char *filename) { @@ -547,7 +552,7 @@ void parse_params(int argc, char *argv[]) dp = &dpl->dp; dp->n = ++desync_profile_count; -#ifndef __OpenBSD__ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) if (argc>=2 && (argv[1][0]=='@' || argv[1][0]=='$')) { config_from_file(argv[1]+1); @@ -1288,7 +1293,7 @@ void parse_params(int argc, char *argv[]) SplitDebug(); VPRINT("\n"); -#ifndef __OpenBSD__ +#if !defined( __OpenBSD__) && !defined(__ANDROID__) // do not need args from file anymore cleanup_args(); #endif