From 6eb463a6758fb48cd101bc55dfd057e6e9d98af1 Mon Sep 17 00:00:00 2001 From: bol-van Date: Fri, 18 Sep 2026 11:43:31 +0300 Subject: [PATCH] bundle --- .gitattributes | 4 + .github/lockdown.yml | 2 + arm64/WinDivert64.sys | Bin 0 -> 79808 bytes arm64/install_arm64.cmd | 47 + arm64/ip2net.exe | Bin 0 -> 23552 bytes arm64/mdig.exe | Bin 0 -> 122368 bytes blockcheck/blockcheck-kyber.cmd | 8 + blockcheck/blockcheck.cmd | 8 + blockcheck/blockcheck2-kyber.cmd | 8 + blockcheck/blockcheck2.cmd | 8 + blockcheck/zapret/blockcheck.sh | 2349 ++++ blockcheck/zapret/blog.sh | 8 + blockcheck/zapret/blog_kyber.sh | 6 + blockcheck/zapret/common/base.sh | 460 + blockcheck/zapret/common/dialog.sh | 57 + blockcheck/zapret/common/elevate.sh | 28 + blockcheck/zapret/common/fwtype.sh | 64 + blockcheck/zapret/common/virt.sh | 39 + .../zapret/files/fake/dht_find_node.bin | Bin 0 -> 98 bytes .../zapret/files/fake/dht_get_peers.bin | 2 + .../fake/discord-ip-discovery-with-port.bin | Bin 0 -> 74 bytes .../discord-ip-discovery-without-port.bin | Bin 0 -> 74 bytes .../files/fake/dtls_clienthello_w3_org.bin | Bin 0 -> 226 bytes .../zapret/files/fake/http_iana_org.bin | 9 + .../files/fake/isakmp_initiator_request.bin | Bin 0 -> 584 bytes .../files/fake/quic_initial_facebook_com.bin | Bin 0 -> 1200 bytes .../fake/quic_initial_facebook_com_quiche.bin | Bin 0 -> 1200 bytes ...xguxaxjvh-n8me_googlevideo_com_kyber_1.bin | Bin 0 -> 1230 bytes ...xguxaxjvh-n8me_googlevideo_com_kyber_2.bin | Bin 0 -> 1230 bytes ...2---sn-gvnuxaxjvh-o8ge_googlevideo_com.bin | Bin 0 -> 1200 bytes .../files/fake/quic_initial_rutracker_org.bin | Bin 0 -> 1200 bytes .../quic_initial_rutracker_org_kyber_1.bin | Bin 0 -> 1230 bytes .../quic_initial_rutracker_org_kyber_2.bin | Bin 0 -> 1230 bytes .../zapret/files/fake/quic_initial_vk_com.bin | Bin 0 -> 1357 bytes .../fake/quic_initial_www_google_com.bin | Bin 0 -> 1200 bytes .../zapret/files/fake/quic_short_header.bin | Bin 0 -> 620 bytes blockcheck/zapret/files/fake/stun.bin | Bin 0 -> 100 bytes .../fake/tls_clienthello_gosuslugi_ru.bin | Bin 0 -> 517 bytes .../files/fake/tls_clienthello_iana_org.bin | Bin 0 -> 517 bytes .../tls_clienthello_rutracker_org_kyber.bin | Bin 0 -> 1787 bytes .../fake/tls_clienthello_sberbank_ru.bin | Bin 0 -> 517 bytes .../files/fake/tls_clienthello_vk_com.bin | Bin 0 -> 517 bytes .../fake/tls_clienthello_vk_com_kyber.bin | Bin 0 -> 1812 bytes .../fake/tls_clienthello_www_google_com.bin | Bin 0 -> 681 bytes .../files/fake/wireguard_initiation.bin | Bin 0 -> 148 bytes .../zapret/files/fake/wireguard_response.bin | Bin 0 -> 92 bytes blockcheck/zapret/files/fake/zero_1024.bin | Bin 0 -> 1024 bytes blockcheck/zapret/files/fake/zero_256.bin | Bin 0 -> 256 bytes blockcheck/zapret/files/fake/zero_512.bin | Bin 0 -> 512 bytes blockcheck/zapret/ip2net/ip2net.exe | Bin 0 -> 92672 bytes blockcheck/zapret/mdig/mdig.exe | Bin 0 -> 130560 bytes blockcheck/zapret/nfq/WinDivert.dll | Bin 0 -> 47616 bytes blockcheck/zapret/nfq/WinDivert64.sys | Bin 0 -> 94144 bytes blockcheck/zapret/nfq/winws.exe | Bin 0 -> 223232 bytes .../zapret2/blockcheck2.d/custom/10-list.sh | 79 + .../zapret2/blockcheck2.d/custom/README.txt | 12 + .../blockcheck2.d/custom/list_http.txt | 5 + .../blockcheck2.d/custom/list_https_tls12.txt | 4 + .../blockcheck2.d/custom/list_https_tls13.txt | 5 + .../blockcheck2.d/custom/list_quic.txt | 4 + .../blockcheck2.d/standard/10-http-basic.sh | 12 + .../zapret2/blockcheck2.d/standard/15-misc.sh | 42 + .../zapret2/blockcheck2.d/standard/17-oob.sh | 39 + .../blockcheck2.d/standard/20-multi.sh | 74 + .../blockcheck2.d/standard/23-seqovl.sh | 92 + .../blockcheck2.d/standard/24-syndata.sh | 55 + .../zapret2/blockcheck2.d/standard/25-fake.sh | 153 + .../blockcheck2.d/standard/30-faked.sh | 108 + .../blockcheck2.d/standard/35-hostfake.sh | 104 + .../blockcheck2.d/standard/50-fake-multi.sh | 164 + .../blockcheck2.d/standard/55-fake-faked.sh | 165 + .../standard/60-fake-hostfake.sh | 117 + .../zapret2/blockcheck2.d/standard/90-quic.sh | 36 + .../zapret2/blockcheck2.d/standard/def.inc | 21 + blockcheck/zapret2/blockcheck2.sh | 2020 +++ blockcheck/zapret2/blog.sh | 8 + blockcheck/zapret2/blog_kyber.sh | 6 + blockcheck/zapret2/common/base.sh | 466 + blockcheck/zapret2/common/dialog.sh | 57 + blockcheck/zapret2/common/elevate.sh | 28 + blockcheck/zapret2/common/fwtype.sh | 64 + blockcheck/zapret2/common/virt.sh | 39 + blockcheck/zapret2/ip2net/ip2net.exe | Bin 0 -> 92672 bytes blockcheck/zapret2/lua/zapret-antidpi.lua | 1250 ++ blockcheck/zapret2/lua/zapret-auto.lua | 576 + blockcheck/zapret2/lua/zapret-lib.lua | 2730 ++++ blockcheck/zapret2/lua/zapret-obfs.lua | 487 + blockcheck/zapret2/lua/zapret-pcap.lua | 40 + blockcheck/zapret2/lua/zapret-tests.lua | 1157 ++ blockcheck/zapret2/mdig/mdig.exe | Bin 0 -> 130560 bytes blockcheck/zapret2/nfq2/WinDivert.dll | Bin 0 -> 47616 bytes blockcheck/zapret2/nfq2/WinDivert64.sys | Bin 0 -> 94144 bytes blockcheck/zapret2/nfq2/winws2.exe | Bin 0 -> 656384 bytes cygwin/bin/[.exe | Bin 0 -> 73747 bytes cygwin/bin/arch.exe | Bin 0 -> 36883 bytes cygwin/bin/awk | 3 + cygwin/bin/basename.exe | Bin 0 -> 36371 bytes cygwin/bin/bash.exe | Bin 0 -> 854035 bytes cygwin/bin/bunzip2.exe | Bin 0 -> 33299 bytes cygwin/bin/bzcat.exe | Bin 0 -> 33299 bytes cygwin/bin/bzgrep | 85 + cygwin/bin/bzip2.exe | Bin 0 -> 33299 bytes cygwin/bin/cat.exe | Bin 0 -> 39955 bytes cygwin/bin/chattr.exe | Bin 0 -> 15379 bytes cygwin/bin/chgrp.exe | Bin 0 -> 64019 bytes cygwin/bin/chmod.exe | Bin 0 -> 59411 bytes cygwin/bin/chown.exe | Bin 0 -> 66067 bytes cygwin/bin/chrt.exe | Bin 0 -> 28179 bytes cygwin/bin/clear.exe | Bin 0 -> 10752 bytes cygwin/bin/cmp.exe | Bin 0 -> 46611 bytes cygwin/bin/cp.exe | Bin 0 -> 132115 bytes cygwin/bin/cut.exe | Bin 0 -> 45075 bytes cygwin/bin/cygattr-1.dll | Bin 0 -> 16915 bytes cygwin/bin/cygbsd-0.dll | Bin 0 -> 69892 bytes cygwin/bin/cygbz2-1.dll | Bin 0 -> 67603 bytes cygwin/bin/cygcrypto-1.1.dll | Bin 0 -> 2546707 bytes cygwin/bin/cyggcc_s-seh-1.dll | Bin 0 -> 75283 bytes cygwin/bin/cyggmp-10.dll | Bin 0 -> 604691 bytes cygwin/bin/cygiconv-2.dll | Bin 0 -> 1088019 bytes cygwin/bin/cygintl-8.dll | Bin 0 -> 107027 bytes cygwin/bin/cyglz4-1.dll | Bin 0 -> 138771 bytes cygwin/bin/cyglzma-5.dll | Bin 0 -> 178195 bytes cygwin/bin/cygmagic-1.dll | Bin 0 -> 163859 bytes cygwin/bin/cygmd-0.dll | Bin 0 -> 40979 bytes cygwin/bin/cygmpfr-6.dll | Bin 0 -> 665619 bytes cygwin/bin/cygncursesw-10.dll | Bin 0 -> 344595 bytes cygwin/bin/cygpath.exe | Bin 0 -> 26131 bytes cygwin/bin/cygpcre-1.dll | Bin 0 -> 508947 bytes cygwin/bin/cygpcre2-8-0.dll | Bin 0 -> 634387 bytes cygwin/bin/cygpopt-0.dll | Bin 0 -> 43027 bytes cygwin/bin/cygproc2-0.dll | Bin 0 -> 140819 bytes cygwin/bin/cygreadline7.dll | Bin 0 -> 262675 bytes cygwin/bin/cygssl-1.1.dll | Bin 0 -> 523795 bytes cygwin/bin/cygstart.exe | Bin 0 -> 22035 bytes cygwin/bin/cygtls-26.dll | Bin 0 -> 59923 bytes cygwin/bin/cygwin-console-helper.exe | Bin 0 -> 41491 bytes cygwin/bin/cygwin1.dll | Bin 0 -> 2954293 bytes cygwin/bin/cygz.dll | Bin 0 -> 89619 bytes cygwin/bin/cygzstd-1.dll | Bin 0 -> 665107 bytes cygwin/bin/date.exe | Bin 0 -> 120851 bytes cygwin/bin/dircolors.exe | Bin 0 -> 59923 bytes cygwin/bin/dirname.exe | Bin 0 -> 35347 bytes cygwin/bin/dos2unix.exe | Bin 0 -> 53267 bytes cygwin/bin/echo.exe | Bin 0 -> 36883 bytes cygwin/bin/egrep | 4 + cygwin/bin/env.exe | Bin 0 -> 44563 bytes cygwin/bin/expr.exe | Bin 0 -> 112659 bytes cygwin/bin/false.exe | Bin 0 -> 34323 bytes cygwin/bin/fgrep | 4 + cygwin/bin/find.exe | Bin 0 -> 269331 bytes cygwin/bin/fmt.exe | Bin 0 -> 44563 bytes cygwin/bin/fold.exe | Bin 0 -> 39443 bytes cygwin/bin/gawk.exe | Bin 0 -> 689683 bytes cygwin/bin/getconf.exe | Bin 0 -> 27155 bytes cygwin/bin/getopt.exe | Bin 0 -> 15891 bytes cygwin/bin/grep.exe | Bin 0 -> 227859 bytes cygwin/bin/gunzip | 57 + cygwin/bin/gzip.exe | Bin 0 -> 106515 bytes cygwin/bin/head.exe | Bin 0 -> 45587 bytes cygwin/bin/hexdump.exe | Bin 0 -> 49171 bytes cygwin/bin/hostname.exe | Bin 0 -> 13843 bytes cygwin/bin/id.exe | Bin 0 -> 44051 bytes cygwin/bin/install.exe | Bin 0 -> 139283 bytes cygwin/bin/kill.exe | Bin 0 -> 13843 bytes cygwin/bin/killall.exe | Bin 0 -> 24083 bytes cygwin/bin/ldd.exe | Bin 0 -> 17427 bytes cygwin/bin/ldh.exe | Bin 0 -> 17427 bytes cygwin/bin/link.exe | Bin 0 -> 34835 bytes cygwin/bin/ln.exe | Bin 0 -> 66067 bytes cygwin/bin/look.exe | Bin 0 -> 14355 bytes cygwin/bin/ls.exe | Bin 0 -> 150547 bytes cygwin/bin/md5sum.exe | Bin 0 -> 47635 bytes cygwin/bin/mkdir.exe | Bin 0 -> 72723 bytes cygwin/bin/more.exe | Bin 0 -> 36371 bytes cygwin/bin/mount.exe | Bin 0 -> 17939 bytes cygwin/bin/mv.exe | Bin 0 -> 140819 bytes cygwin/bin/nano.exe | Bin 0 -> 323603 bytes cygwin/bin/nc.exe | Bin 0 -> 42003 bytes cygwin/bin/nice.exe | Bin 0 -> 38419 bytes cygwin/bin/nl.exe | Bin 0 -> 107027 bytes cygwin/bin/pgrep.exe | Bin 0 -> 29715 bytes cygwin/bin/pidof.exe | Bin 0 -> 15891 bytes cygwin/bin/pkill.exe | Bin 0 -> 29715 bytes cygwin/bin/printenv.exe | Bin 0 -> 34835 bytes cygwin/bin/printf.exe | Bin 0 -> 75795 bytes cygwin/bin/ps.exe | Bin 0 -> 14867 bytes cygwin/bin/pwd.exe | Bin 0 -> 37395 bytes cygwin/bin/readlink.exe | Bin 0 -> 47123 bytes cygwin/bin/realpath.exe | Bin 0 -> 48147 bytes cygwin/bin/renice.exe | Bin 0 -> 12819 bytes cygwin/bin/rm.exe | Bin 0 -> 65555 bytes cygwin/bin/rmdir.exe | Bin 0 -> 65043 bytes cygwin/bin/sed.exe | Bin 0 -> 176659 bytes cygwin/bin/seq.exe | Bin 0 -> 73747 bytes cygwin/bin/sh.exe | Bin 0 -> 105472 bytes cygwin/bin/sha1sum.exe | Bin 0 -> 50707 bytes cygwin/bin/sha224sum.exe | Bin 0 -> 57363 bytes cygwin/bin/sha256sum.exe | Bin 0 -> 57363 bytes cygwin/bin/sha384sum.exe | Bin 0 -> 63507 bytes cygwin/bin/sha512sum.exe | Bin 0 -> 63507 bytes cygwin/bin/sleep.exe | Bin 0 -> 39955 bytes cygwin/bin/sort.exe | Bin 0 -> 109075 bytes cygwin/bin/stat.exe | Bin 0 -> 98323 bytes cygwin/bin/sync.exe | Bin 0 -> 35347 bytes cygwin/bin/tac.exe | Bin 0 -> 103955 bytes cygwin/bin/tail.exe | Bin 0 -> 61459 bytes cygwin/bin/tar.exe | Bin 0 -> 501267 bytes cygwin/bin/tee.exe | Bin 0 -> 38931 bytes cygwin/bin/test.exe | Bin 0 -> 71187 bytes cygwin/bin/timeout.exe | Bin 0 -> 44563 bytes cygwin/bin/touch.exe | Bin 0 -> 108051 bytes cygwin/bin/tr.exe | Bin 0 -> 51219 bytes cygwin/bin/true.exe | Bin 0 -> 34323 bytes cygwin/bin/truncate.exe | Bin 0 -> 40979 bytes cygwin/bin/tset.exe | Bin 0 -> 21504 bytes cygwin/bin/tty.exe | Bin 0 -> 34323 bytes cygwin/bin/ul.exe | Bin 0 -> 17939 bytes cygwin/bin/umount.exe | Bin 0 -> 11283 bytes cygwin/bin/uname.exe | Bin 0 -> 36883 bytes cygwin/bin/uniq.exe | Bin 0 -> 45587 bytes cygwin/bin/unix2dos.exe | Bin 0 -> 53267 bytes cygwin/bin/unzip.exe | Bin 0 -> 177171 bytes cygwin/bin/wc.exe | Bin 0 -> 48659 bytes cygwin/bin/which.exe | Bin 0 -> 25619 bytes cygwin/bin/xargs.exe | Bin 0 -> 68115 bytes cygwin/bin/xz.exe | Bin 0 -> 75283 bytes cygwin/bin/yes.exe | Bin 0 -> 35347 bytes cygwin/bin/zcat | 51 + cygwin/bin/zgrep | 285 + cygwin/bin/zip.exe | Bin 0 -> 204819 bytes cygwin/bin/zstd.exe | Bin 0 -> 828435 bytes cygwin/cygwin-admin.cmd | 3 + cygwin/cygwin.cmd | 3 + cygwin/dev/mqueue/.gitkeep | 0 cygwin/dev/shm/.gitkeep | 0 cygwin/etc/DIR_COLORS | 223 + cygwin/etc/bash.bash_logout | 23 + cygwin/etc/bash.bashrc | 63 + cygwin/etc/defaults/etc/DIR_COLORS | 223 + cygwin/etc/defaults/etc/bash.bash_logout | 23 + cygwin/etc/defaults/etc/bash.bashrc | 33 + cygwin/etc/defaults/etc/cygserver.conf | 147 + cygwin/etc/defaults/etc/man_db.conf | 132 + .../defaults/etc/pki/ca-trust/ca-legacy.conf | 24 + .../etc/defaults/etc/pki/tls/ct_log_list.cnf | 9 + cygwin/etc/defaults/etc/pki/tls/openssl.cnf | 368 + cygwin/etc/defaults/etc/profile | 163 + cygwin/etc/defaults/etc/shells | 18 + cygwin/etc/defaults/etc/skel/.bash_profile | 44 + cygwin/etc/defaults/etc/skel/.bashrc | 186 + cygwin/etc/defaults/etc/skel/.inputrc | 74 + cygwin/etc/defaults/etc/skel/.profile | 37 + cygwin/etc/fstab | 0 cygwin/etc/pki/tls/certs/ca-bundle.crt | 10918 ++++++++++++++++ cygwin/etc/pki/tls/openssl.cnf | 368 + cygwin/etc/profile | 163 + cygwin/etc/profile.d/gawk.csh | 11 + cygwin/etc/profile.d/gawk.sh | 31 + cygwin/etc/shells | 18 + cygwin/etc/skel/.bash_profile | 44 + cygwin/etc/skel/.bashrc | 186 + cygwin/etc/skel/.inputrc | 74 + cygwin/etc/skel/.profile | 37 + cygwin/home/.gitkeep | 0 cygwin/lib/charset.alias | 4 + cygwin/lib/gawk/.gitkeep | 0 cygwin/sbin/.gitkeep | 0 cygwin/tmp/.gitkeep | 0 cygwin/usr/libexec/awk/grcat.exe | Bin 0 -> 9235 bytes cygwin/usr/libexec/awk/pwcat.exe | Bin 0 -> 9235 bytes cygwin/usr/libexec/coreutils/libstdbuf.so | Bin 0 -> 9235 bytes cygwin/usr/local/bin/curl-kyber.exe | Bin 0 -> 7211008 bytes cygwin/usr/local/bin/curl.exe | Bin 0 -> 261632 bytes cygwin/usr/local/bin/cygcrypto-3.dll | Bin 0 -> 5220864 bytes cygwin/usr/local/bin/cygcurl-4.dll | Bin 0 -> 698880 bytes cygwin/usr/local/bin/cygidn2-0.dll | Bin 0 -> 339456 bytes cygwin/usr/local/bin/cygnghttp2-14.dll | Bin 0 -> 173056 bytes cygwin/usr/local/bin/cygnghttp3-9.dll | Bin 0 -> 151040 bytes cygwin/usr/local/bin/cygssl-3.dll | Bin 0 -> 1001472 bytes cygwin/usr/local/bin/idn2.exe | Bin 0 -> 190005 bytes cygwin/usr/local/etc/.gitkeep | 0 cygwin/usr/local/lib/.gitkeep | 0 cygwin/usr/sbin/.gitkeep | 0 cygwin/usr/share/awk/.gitkeep | 0 .../share/bash-completion/completions/getopt | 37 + .../share/bash-completion/completions/more | 30 + .../share/bash-completion/completions/renice | 41 + .../usr/share/bash-completion/completions/ul | 33 + cygwin/usr/share/cygwin/cygwin.ldif | 253 + cygwin/usr/share/locale/.gitkeep | 0 cygwin/usr/share/tabset/std | 1 + cygwin/usr/share/tabset/stdcrt | 1 + cygwin/usr/share/tabset/vt100 | 3 + cygwin/usr/share/tabset/vt300 | 3 + cygwin/usr/share/terminfo/45/Eterm | Bin 0 -> 2224 bytes cygwin/usr/share/terminfo/45/Eterm-256color | Bin 0 -> 2464 bytes cygwin/usr/share/terminfo/45/Eterm-88color | Bin 0 -> 2394 bytes cygwin/usr/share/terminfo/45/Eterm-color | Bin 0 -> 22 bytes cygwin/usr/share/terminfo/61/ansi | Bin 0 -> 1481 bytes cygwin/usr/share/terminfo/61/aterm | Bin 0 -> 2192 bytes cygwin/usr/share/terminfo/62/bracketed+paste | Bin 0 -> 120 bytes cygwin/usr/share/terminfo/62/bterm | Bin 0 -> 1155 bytes cygwin/usr/share/terminfo/63/cons25 | Bin 0 -> 1502 bytes cygwin/usr/share/terminfo/63/cygwin | Bin 0 -> 1518 bytes cygwin/usr/share/terminfo/63/cygwinB19 | Bin 0 -> 1625 bytes cygwin/usr/share/terminfo/63/cygwinDBG | Bin 0 -> 1530 bytes cygwin/usr/share/terminfo/64/dumb | Bin 0 -> 308 bytes cygwin/usr/share/terminfo/64/dumb-emacs-ansi | Bin 0 -> 898 bytes cygwin/usr/share/terminfo/65/eterm | Bin 0 -> 908 bytes cygwin/usr/share/terminfo/65/eterm-color | Bin 0 -> 1271 bytes cygwin/usr/share/terminfo/67/gnome | Bin 0 -> 3029 bytes cygwin/usr/share/terminfo/67/gnome-256color | Bin 0 -> 3299 bytes cygwin/usr/share/terminfo/68/hurd | Bin 0 -> 1587 bytes cygwin/usr/share/terminfo/6a/jfbterm | Bin 0 -> 1620 bytes cygwin/usr/share/terminfo/6b/konsole | Bin 0 -> 3339 bytes cygwin/usr/share/terminfo/6b/konsole-16color | Bin 0 -> 3625 bytes cygwin/usr/share/terminfo/6b/konsole-256color | Bin 0 -> 3507 bytes cygwin/usr/share/terminfo/6c/linux | Bin 0 -> 1740 bytes cygwin/usr/share/terminfo/6d/mach | Bin 0 -> 635 bytes cygwin/usr/share/terminfo/6d/mach-bold | Bin 0 -> 669 bytes cygwin/usr/share/terminfo/6d/mach-color | Bin 0 -> 1113 bytes cygwin/usr/share/terminfo/6d/mach-gnu | Bin 0 -> 1073 bytes cygwin/usr/share/terminfo/6d/mach-gnu-color | Bin 0 -> 1339 bytes cygwin/usr/share/terminfo/6d/mintty | Bin 0 -> 4022 bytes cygwin/usr/share/terminfo/6d/mintty+common | Bin 0 -> 3926 bytes cygwin/usr/share/terminfo/6d/mintty-direct | Bin 0 -> 4048 bytes cygwin/usr/share/terminfo/6d/mlterm | Bin 0 -> 3265 bytes cygwin/usr/share/terminfo/6d/mrxvt | Bin 0 -> 3044 bytes cygwin/usr/share/terminfo/6d/mrxvt-256color | Bin 0 -> 3306 bytes cygwin/usr/share/terminfo/6e/nsterm | Bin 0 -> 1988 bytes cygwin/usr/share/terminfo/70/pcansi | Bin 0 -> 1198 bytes cygwin/usr/share/terminfo/70/putty | Bin 0 -> 2530 bytes cygwin/usr/share/terminfo/70/putty-256color | Bin 0 -> 2608 bytes cygwin/usr/share/terminfo/70/putty-m1 | Bin 0 -> 1895 bytes cygwin/usr/share/terminfo/70/putty-m1b | Bin 0 -> 1837 bytes cygwin/usr/share/terminfo/70/putty-m2 | Bin 0 -> 1955 bytes cygwin/usr/share/terminfo/70/putty-noapp | Bin 0 -> 2548 bytes cygwin/usr/share/terminfo/70/putty-sco | Bin 0 -> 2606 bytes cygwin/usr/share/terminfo/70/putty-screen | Bin 0 -> 2600 bytes cygwin/usr/share/terminfo/70/putty-vt100 | Bin 0 -> 2510 bytes cygwin/usr/share/terminfo/72/rxvt | Bin 0 -> 2234 bytes cygwin/usr/share/terminfo/72/rxvt+pcfkeys | Bin 0 -> 1194 bytes cygwin/usr/share/terminfo/72/rxvt-16color | Bin 0 -> 2494 bytes cygwin/usr/share/terminfo/72/rxvt-256color | Bin 0 -> 2460 bytes cygwin/usr/share/terminfo/72/rxvt-88color | Bin 0 -> 2428 bytes cygwin/usr/share/terminfo/72/rxvt-basic | Bin 0 -> 2137 bytes cygwin/usr/share/terminfo/72/rxvt-color | Bin 0 -> 21 bytes cygwin/usr/share/terminfo/72/rxvt-cygwin | Bin 0 -> 2248 bytes .../usr/share/terminfo/72/rxvt-cygwin-native | Bin 0 -> 2266 bytes cygwin/usr/share/terminfo/72/rxvt-unicode | Bin 0 -> 2208 bytes .../share/terminfo/72/rxvt-unicode-256color | Bin 0 -> 2234 bytes cygwin/usr/share/terminfo/72/rxvt-xpm | Bin 0 -> 2234 bytes cygwin/usr/share/terminfo/73/screen | Bin 0 -> 1607 bytes cygwin/usr/share/terminfo/73/screen-16color | Bin 0 -> 1877 bytes cygwin/usr/share/terminfo/73/screen-256color | Bin 0 -> 1747 bytes cygwin/usr/share/terminfo/73/screen.Eterm | Bin 0 -> 2255 bytes cygwin/usr/share/terminfo/73/screen.gnome | Bin 0 -> 3146 bytes cygwin/usr/share/terminfo/73/screen.konsole | Bin 0 -> 3319 bytes .../share/terminfo/73/screen.konsole-256color | Bin 0 -> 3477 bytes cygwin/usr/share/terminfo/73/screen.linux | Bin 0 -> 1754 bytes cygwin/usr/share/terminfo/73/screen.linux-m1 | Bin 0 -> 1971 bytes cygwin/usr/share/terminfo/73/screen.linux-m1b | Bin 0 -> 1941 bytes cygwin/usr/share/terminfo/73/screen.linux-m2 | Bin 0 -> 1913 bytes cygwin/usr/share/terminfo/73/screen.linux-s | Bin 0 -> 29 bytes cygwin/usr/share/terminfo/73/screen.minitel1 | Bin 0 -> 1674 bytes .../usr/share/terminfo/73/screen.minitel1-nb | Bin 0 -> 1656 bytes .../usr/share/terminfo/73/screen.minitel12-80 | Bin 0 -> 36 bytes cygwin/usr/share/terminfo/73/screen.minitel1b | Bin 0 -> 1736 bytes .../usr/share/terminfo/73/screen.minitel1b-80 | Bin 0 -> 1758 bytes .../usr/share/terminfo/73/screen.minitel1b-nb | Bin 0 -> 1720 bytes .../usr/share/terminfo/73/screen.minitel2-80 | Bin 0 -> 36 bytes cygwin/usr/share/terminfo/73/screen.mlterm | Bin 0 -> 3221 bytes .../share/terminfo/73/screen.mlterm-256color | Bin 0 -> 3391 bytes cygwin/usr/share/terminfo/73/screen.mrxvt | Bin 0 -> 3125 bytes cygwin/usr/share/terminfo/73/screen.putty | Bin 0 -> 2498 bytes .../share/terminfo/73/screen.putty-256color | Bin 0 -> 2590 bytes cygwin/usr/share/terminfo/73/screen.putty-m1 | Bin 0 -> 1765 bytes cygwin/usr/share/terminfo/73/screen.putty-m1b | Bin 0 -> 1737 bytes cygwin/usr/share/terminfo/73/screen.putty-m2 | Bin 0 -> 1709 bytes cygwin/usr/share/terminfo/73/screen.rxvt | Bin 0 -> 2251 bytes cygwin/usr/share/terminfo/73/screen.teraterm | Bin 0 -> 1700 bytes cygwin/usr/share/terminfo/73/screen.vte | Bin 0 -> 3508 bytes .../usr/share/terminfo/73/screen.vte-256color | Bin 0 -> 3660 bytes .../share/terminfo/73/screen.xterm-256color | Bin 0 -> 3681 bytes cygwin/usr/share/terminfo/73/screen.xterm-new | Bin 0 -> 37 bytes cygwin/usr/share/terminfo/73/screen.xterm-r6 | Bin 0 -> 1607 bytes .../share/terminfo/73/screen.xterm-xfree86 | Bin 0 -> 3783 bytes cygwin/usr/share/terminfo/73/st | Bin 0 -> 2639 bytes cygwin/usr/share/terminfo/73/st-0.6 | Bin 0 -> 2412 bytes cygwin/usr/share/terminfo/73/st-0.7 | Bin 0 -> 2731 bytes cygwin/usr/share/terminfo/73/st-0.8 | Bin 0 -> 2637 bytes cygwin/usr/share/terminfo/73/st-16color | Bin 0 -> 2799 bytes cygwin/usr/share/terminfo/73/st-256color | Bin 0 -> 2759 bytes cygwin/usr/share/terminfo/73/st-direct | Bin 0 -> 2705 bytes cygwin/usr/share/terminfo/73/sun | Bin 0 -> 1004 bytes cygwin/usr/share/terminfo/74/tek4014 | Bin 0 -> 212 bytes cygwin/usr/share/terminfo/74/tek4014-sm | Bin 0 -> 228 bytes cygwin/usr/share/terminfo/74/teraterm | Bin 0 -> 1683 bytes .../usr/share/terminfo/74/teraterm-256color | Bin 0 -> 1853 bytes cygwin/usr/share/terminfo/74/teraterm2.3 | Bin 0 -> 1596 bytes cygwin/usr/share/terminfo/74/teraterm4.59 | Bin 0 -> 1588 bytes cygwin/usr/share/terminfo/74/teraterm4.97 | Bin 0 -> 1695 bytes cygwin/usr/share/terminfo/74/tmux | Bin 0 -> 3316 bytes cygwin/usr/share/terminfo/74/tmux-256color | Bin 0 -> 3458 bytes cygwin/usr/share/terminfo/74/tmux-direct | Bin 0 -> 3596 bytes cygwin/usr/share/terminfo/76/vt100 | Bin 0 -> 1282 bytes cygwin/usr/share/terminfo/76/vt100-nav | Bin 0 -> 1147 bytes cygwin/usr/share/terminfo/76/vt102 | Bin 0 -> 1276 bytes cygwin/usr/share/terminfo/76/vt220 | Bin 0 -> 1391 bytes cygwin/usr/share/terminfo/76/vt320 | Bin 0 -> 1538 bytes cygwin/usr/share/terminfo/76/vt420 | Bin 0 -> 1689 bytes cygwin/usr/share/terminfo/76/vt52 | Bin 0 -> 839 bytes cygwin/usr/share/terminfo/76/vt520 | Bin 0 -> 1723 bytes cygwin/usr/share/terminfo/76/vte | Bin 0 -> 3534 bytes cygwin/usr/share/terminfo/76/vte-256color | Bin 0 -> 3784 bytes cygwin/usr/share/terminfo/76/vwmterm | Bin 0 -> 1304 bytes cygwin/usr/share/terminfo/77/wsvt25 | Bin 0 -> 1597 bytes cygwin/usr/share/terminfo/77/wsvt25m | Bin 0 -> 1607 bytes cygwin/usr/share/terminfo/78/xfce | Bin 0 -> 2995 bytes cygwin/usr/share/terminfo/78/xterm | Bin 0 -> 3977 bytes cygwin/usr/share/terminfo/78/xterm-1002 | Bin 0 -> 3980 bytes cygwin/usr/share/terminfo/78/xterm-1003 | Bin 0 -> 3978 bytes cygwin/usr/share/terminfo/78/xterm-1005 | Bin 0 -> 3971 bytes cygwin/usr/share/terminfo/78/xterm-1006 | Bin 0 -> 3957 bytes cygwin/usr/share/terminfo/78/xterm-16color | Bin 0 -> 4217 bytes cygwin/usr/share/terminfo/78/xterm-24 | Bin 0 -> 1533 bytes cygwin/usr/share/terminfo/78/xterm-256color | Bin 0 -> 4071 bytes cygwin/usr/share/terminfo/78/xterm-88color | Bin 0 -> 4039 bytes cygwin/usr/share/terminfo/78/xterm-8bit | Bin 0 -> 1913 bytes cygwin/usr/share/terminfo/78/xterm-basic | Bin 0 -> 1828 bytes cygwin/usr/share/terminfo/78/xterm-bold | Bin 0 -> 1592 bytes cygwin/usr/share/terminfo/78/xterm-color | Bin 0 -> 1551 bytes cygwin/usr/share/terminfo/78/xterm-direct | Bin 0 -> 4028 bytes cygwin/usr/share/terminfo/78/xterm-direct16 | Bin 0 -> 4104 bytes cygwin/usr/share/terminfo/78/xterm-direct2 | Bin 0 -> 4018 bytes cygwin/usr/share/terminfo/78/xterm-direct256 | Bin 0 -> 4158 bytes cygwin/usr/share/terminfo/78/xterm-hp | Bin 0 -> 2652 bytes cygwin/usr/share/terminfo/78/xterm-mono | Bin 0 -> 1489 bytes cygwin/usr/share/terminfo/78/xterm-new | Bin 0 -> 3971 bytes cygwin/usr/share/terminfo/78/xterm-nic | Bin 0 -> 3987 bytes cygwin/usr/share/terminfo/78/xterm-noapp | Bin 0 -> 3933 bytes cygwin/usr/share/terminfo/78/xterm-old | Bin 0 -> 1493 bytes cygwin/usr/share/terminfo/78/xterm-p370 | Bin 0 -> 3957 bytes cygwin/usr/share/terminfo/78/xterm-p371 | Bin 0 -> 3991 bytes cygwin/usr/share/terminfo/78/xterm-pcolor | Bin 0 -> 1658 bytes cygwin/usr/share/terminfo/78/xterm-r5 | Bin 0 -> 1301 bytes cygwin/usr/share/terminfo/78/xterm-r6 | Bin 0 -> 1491 bytes cygwin/usr/share/terminfo/78/xterm-sco | Bin 0 -> 2620 bytes cygwin/usr/share/terminfo/78/xterm-sun | Bin 0 -> 2784 bytes cygwin/usr/share/terminfo/78/xterm-utf8 | Bin 0 -> 3994 bytes cygwin/usr/share/terminfo/78/xterm-vt220 | Bin 0 -> 2476 bytes cygwin/usr/share/terminfo/78/xterm-vt52 | Bin 0 -> 537 bytes cygwin/usr/share/terminfo/78/xterm-x10mouse | Bin 0 -> 3953 bytes cygwin/usr/share/terminfo/78/xterm-x11hilite | Bin 0 -> 3981 bytes cygwin/usr/share/terminfo/78/xterm-x11mouse | Bin 0 -> 3965 bytes cygwin/usr/share/terminfo/78/xterm-xf86-v32 | Bin 0 -> 2006 bytes cygwin/usr/share/terminfo/78/xterm-xf86-v33 | Bin 0 -> 1996 bytes cygwin/usr/share/terminfo/78/xterm-xf86-v333 | Bin 0 -> 2006 bytes cygwin/usr/share/terminfo/78/xterm-xf86-v40 | Bin 0 -> 2212 bytes cygwin/usr/share/terminfo/78/xterm-xf86-v43 | Bin 0 -> 2226 bytes cygwin/usr/share/terminfo/78/xterm-xf86-v44 | Bin 0 -> 2260 bytes cygwin/usr/share/terminfo/78/xterm-xfree86 | Bin 0 -> 2240 bytes cygwin/usr/share/terminfo/78/xterm-xi | Bin 0 -> 1986 bytes cygwin/var/cache/.gitkeep | 0 cygwin/var/lib/.gitkeep | 0 cygwin/var/log/.gitkeep | 0 cygwin/var/run/.gitkeep | 0 cygwin/var/tmp/.gitkeep | 0 readme.md | 94 + tools/elevator.exe | Bin 0 -> 4096 bytes win7/WinDivert.dll | Bin 0 -> 47104 bytes win7/WinDivert64.sys | Bin 0 -> 90456 bytes win7/install_win7.cmd | 41 + windivert-hide/Monkey64.sys | Bin 0 -> 94144 bytes windivert-hide/README.txt | 19 + windivert-hide/WinDivert.dll | Bin 0 -> 45568 bytes windivert-hide/monkey_delete.cmd | 21 + zapret-winws/WinDivert.dll | Bin 0 -> 47616 bytes zapret-winws/WinDivert64.sys | Bin 0 -> 94144 bytes zapret-winws/_CMD_ADMIN.cmd | 3 + zapret-winws/cygwin1.dll | Bin 0 -> 2954293 bytes zapret-winws/elevator.exe | Bin 0 -> 4096 bytes zapret-winws/enable_timestamps.cmd | 14 + zapret-winws/files/list-youtube.txt | 14 + .../files/quic_initial_www_google_com.bin | Bin 0 -> 1200 bytes zapret-winws/killall.exe | Bin 0 -> 20992 bytes zapret-winws/lua/zapret-antidpi.lua | 1250 ++ zapret-winws/lua/zapret-auto.lua | 576 + zapret-winws/lua/zapret-lib.lua | 2730 ++++ zapret-winws/lua/zapret-obfs.lua | 487 + zapret-winws/lua/zapret-pcap.lua | 40 + zapret-winws/lua/zapret-tests.lua | 1157 ++ zapret-winws/preset1_example.cmd | 11 + zapret-winws/preset2_example.cmd | 38 + zapret-winws/preset2_wireguard.cmd | 10 + zapret-winws/service1_create.cmd | 30 + zapret-winws/service2_create.cmd | 58 + zapret-winws/service_create.cmd | 30 + zapret-winws/service_del.cmd | 7 + zapret-winws/service_start.cmd | 2 + zapret-winws/service_stop.cmd | 2 + zapret-winws/windivert.filter/README.txt | 14 + .../windivert.filter/windivert_part.dht.txt | 1 + .../windivert_part.discord_media.txt | 20 + .../windivert_part.quic_initial_ietf.txt | 4 + .../windivert.filter/windivert_part.stun.txt | 3 + .../windivert_part.wireguard.txt | 3 + zapret-winws/windivert_delete.cmd | 21 + zapret-winws/winws.exe | Bin 0 -> 223232 bytes zapret-winws/winws2.exe | Bin 0 -> 656384 bytes 510 files changed, 34567 insertions(+) create mode 100644 .gitattributes create mode 100644 .github/lockdown.yml create mode 100644 arm64/WinDivert64.sys create mode 100644 arm64/install_arm64.cmd create mode 100644 arm64/ip2net.exe create mode 100644 arm64/mdig.exe create mode 100644 blockcheck/blockcheck-kyber.cmd create mode 100644 blockcheck/blockcheck.cmd create mode 100644 blockcheck/blockcheck2-kyber.cmd create mode 100644 blockcheck/blockcheck2.cmd create mode 100644 blockcheck/zapret/blockcheck.sh create mode 100644 blockcheck/zapret/blog.sh create mode 100644 blockcheck/zapret/blog_kyber.sh create mode 100644 blockcheck/zapret/common/base.sh create mode 100644 blockcheck/zapret/common/dialog.sh create mode 100644 blockcheck/zapret/common/elevate.sh create mode 100644 blockcheck/zapret/common/fwtype.sh create mode 100644 blockcheck/zapret/common/virt.sh create mode 100644 blockcheck/zapret/files/fake/dht_find_node.bin create mode 100644 blockcheck/zapret/files/fake/dht_get_peers.bin create mode 100644 blockcheck/zapret/files/fake/discord-ip-discovery-with-port.bin create mode 100644 blockcheck/zapret/files/fake/discord-ip-discovery-without-port.bin create mode 100644 blockcheck/zapret/files/fake/dtls_clienthello_w3_org.bin create mode 100644 blockcheck/zapret/files/fake/http_iana_org.bin create mode 100644 blockcheck/zapret/files/fake/isakmp_initiator_request.bin create mode 100644 blockcheck/zapret/files/fake/quic_initial_facebook_com.bin create mode 100644 blockcheck/zapret/files/fake/quic_initial_facebook_com_quiche.bin create mode 100644 blockcheck/zapret/files/fake/quic_initial_rr1---sn-xguxaxjvh-n8me_googlevideo_com_kyber_1.bin create mode 100644 blockcheck/zapret/files/fake/quic_initial_rr1---sn-xguxaxjvh-n8me_googlevideo_com_kyber_2.bin create mode 100644 blockcheck/zapret/files/fake/quic_initial_rr2---sn-gvnuxaxjvh-o8ge_googlevideo_com.bin create mode 100644 blockcheck/zapret/files/fake/quic_initial_rutracker_org.bin create mode 100644 blockcheck/zapret/files/fake/quic_initial_rutracker_org_kyber_1.bin create mode 100644 blockcheck/zapret/files/fake/quic_initial_rutracker_org_kyber_2.bin create mode 100644 blockcheck/zapret/files/fake/quic_initial_vk_com.bin create mode 100644 blockcheck/zapret/files/fake/quic_initial_www_google_com.bin create mode 100644 blockcheck/zapret/files/fake/quic_short_header.bin create mode 100644 blockcheck/zapret/files/fake/stun.bin create mode 100644 blockcheck/zapret/files/fake/tls_clienthello_gosuslugi_ru.bin create mode 100644 blockcheck/zapret/files/fake/tls_clienthello_iana_org.bin create mode 100644 blockcheck/zapret/files/fake/tls_clienthello_rutracker_org_kyber.bin create mode 100644 blockcheck/zapret/files/fake/tls_clienthello_sberbank_ru.bin create mode 100644 blockcheck/zapret/files/fake/tls_clienthello_vk_com.bin create mode 100644 blockcheck/zapret/files/fake/tls_clienthello_vk_com_kyber.bin create mode 100644 blockcheck/zapret/files/fake/tls_clienthello_www_google_com.bin create mode 100644 blockcheck/zapret/files/fake/wireguard_initiation.bin create mode 100644 blockcheck/zapret/files/fake/wireguard_response.bin create mode 100644 blockcheck/zapret/files/fake/zero_1024.bin create mode 100644 blockcheck/zapret/files/fake/zero_256.bin create mode 100644 blockcheck/zapret/files/fake/zero_512.bin create mode 100644 blockcheck/zapret/ip2net/ip2net.exe create mode 100644 blockcheck/zapret/mdig/mdig.exe create mode 100644 blockcheck/zapret/nfq/WinDivert.dll create mode 100644 blockcheck/zapret/nfq/WinDivert64.sys create mode 100644 blockcheck/zapret/nfq/winws.exe create mode 100644 blockcheck/zapret2/blockcheck2.d/custom/10-list.sh create mode 100644 blockcheck/zapret2/blockcheck2.d/custom/README.txt create mode 100644 blockcheck/zapret2/blockcheck2.d/custom/list_http.txt create mode 100644 blockcheck/zapret2/blockcheck2.d/custom/list_https_tls12.txt create mode 100644 blockcheck/zapret2/blockcheck2.d/custom/list_https_tls13.txt create mode 100644 blockcheck/zapret2/blockcheck2.d/custom/list_quic.txt create mode 100644 blockcheck/zapret2/blockcheck2.d/standard/10-http-basic.sh create mode 100644 blockcheck/zapret2/blockcheck2.d/standard/15-misc.sh create mode 100644 blockcheck/zapret2/blockcheck2.d/standard/17-oob.sh create mode 100644 blockcheck/zapret2/blockcheck2.d/standard/20-multi.sh create mode 100644 blockcheck/zapret2/blockcheck2.d/standard/23-seqovl.sh create mode 100644 blockcheck/zapret2/blockcheck2.d/standard/24-syndata.sh create mode 100644 blockcheck/zapret2/blockcheck2.d/standard/25-fake.sh create mode 100644 blockcheck/zapret2/blockcheck2.d/standard/30-faked.sh create mode 100644 blockcheck/zapret2/blockcheck2.d/standard/35-hostfake.sh create mode 100644 blockcheck/zapret2/blockcheck2.d/standard/50-fake-multi.sh create mode 100644 blockcheck/zapret2/blockcheck2.d/standard/55-fake-faked.sh create mode 100644 blockcheck/zapret2/blockcheck2.d/standard/60-fake-hostfake.sh create mode 100644 blockcheck/zapret2/blockcheck2.d/standard/90-quic.sh create mode 100644 blockcheck/zapret2/blockcheck2.d/standard/def.inc create mode 100644 blockcheck/zapret2/blockcheck2.sh create mode 100644 blockcheck/zapret2/blog.sh create mode 100644 blockcheck/zapret2/blog_kyber.sh create mode 100644 blockcheck/zapret2/common/base.sh create mode 100644 blockcheck/zapret2/common/dialog.sh create mode 100644 blockcheck/zapret2/common/elevate.sh create mode 100644 blockcheck/zapret2/common/fwtype.sh create mode 100644 blockcheck/zapret2/common/virt.sh create mode 100644 blockcheck/zapret2/ip2net/ip2net.exe create mode 100644 blockcheck/zapret2/lua/zapret-antidpi.lua create mode 100644 blockcheck/zapret2/lua/zapret-auto.lua create mode 100644 blockcheck/zapret2/lua/zapret-lib.lua create mode 100644 blockcheck/zapret2/lua/zapret-obfs.lua create mode 100644 blockcheck/zapret2/lua/zapret-pcap.lua create mode 100644 blockcheck/zapret2/lua/zapret-tests.lua create mode 100644 blockcheck/zapret2/mdig/mdig.exe create mode 100644 blockcheck/zapret2/nfq2/WinDivert.dll create mode 100644 blockcheck/zapret2/nfq2/WinDivert64.sys create mode 100644 blockcheck/zapret2/nfq2/winws2.exe create mode 100644 cygwin/bin/[.exe create mode 100644 cygwin/bin/arch.exe create mode 100644 cygwin/bin/awk create mode 100644 cygwin/bin/basename.exe create mode 100644 cygwin/bin/bash.exe create mode 100644 cygwin/bin/bunzip2.exe create mode 100644 cygwin/bin/bzcat.exe create mode 100644 cygwin/bin/bzgrep create mode 100644 cygwin/bin/bzip2.exe create mode 100644 cygwin/bin/cat.exe create mode 100644 cygwin/bin/chattr.exe create mode 100644 cygwin/bin/chgrp.exe create mode 100644 cygwin/bin/chmod.exe create mode 100644 cygwin/bin/chown.exe create mode 100644 cygwin/bin/chrt.exe create mode 100644 cygwin/bin/clear.exe create mode 100644 cygwin/bin/cmp.exe create mode 100644 cygwin/bin/cp.exe create mode 100644 cygwin/bin/cut.exe create mode 100644 cygwin/bin/cygattr-1.dll create mode 100644 cygwin/bin/cygbsd-0.dll create mode 100644 cygwin/bin/cygbz2-1.dll create mode 100644 cygwin/bin/cygcrypto-1.1.dll create mode 100644 cygwin/bin/cyggcc_s-seh-1.dll create mode 100644 cygwin/bin/cyggmp-10.dll create mode 100644 cygwin/bin/cygiconv-2.dll create mode 100644 cygwin/bin/cygintl-8.dll create mode 100644 cygwin/bin/cyglz4-1.dll create mode 100644 cygwin/bin/cyglzma-5.dll create mode 100644 cygwin/bin/cygmagic-1.dll create mode 100644 cygwin/bin/cygmd-0.dll create mode 100644 cygwin/bin/cygmpfr-6.dll create mode 100644 cygwin/bin/cygncursesw-10.dll create mode 100644 cygwin/bin/cygpath.exe create mode 100644 cygwin/bin/cygpcre-1.dll create mode 100644 cygwin/bin/cygpcre2-8-0.dll create mode 100644 cygwin/bin/cygpopt-0.dll create mode 100644 cygwin/bin/cygproc2-0.dll create mode 100644 cygwin/bin/cygreadline7.dll create mode 100644 cygwin/bin/cygssl-1.1.dll create mode 100644 cygwin/bin/cygstart.exe create mode 100644 cygwin/bin/cygtls-26.dll create mode 100644 cygwin/bin/cygwin-console-helper.exe create mode 100644 cygwin/bin/cygwin1.dll create mode 100644 cygwin/bin/cygz.dll create mode 100644 cygwin/bin/cygzstd-1.dll create mode 100644 cygwin/bin/date.exe create mode 100644 cygwin/bin/dircolors.exe create mode 100644 cygwin/bin/dirname.exe create mode 100644 cygwin/bin/dos2unix.exe create mode 100644 cygwin/bin/echo.exe create mode 100644 cygwin/bin/egrep create mode 100644 cygwin/bin/env.exe create mode 100644 cygwin/bin/expr.exe create mode 100644 cygwin/bin/false.exe create mode 100644 cygwin/bin/fgrep create mode 100644 cygwin/bin/find.exe create mode 100644 cygwin/bin/fmt.exe create mode 100644 cygwin/bin/fold.exe create mode 100644 cygwin/bin/gawk.exe create mode 100644 cygwin/bin/getconf.exe create mode 100644 cygwin/bin/getopt.exe create mode 100644 cygwin/bin/grep.exe create mode 100644 cygwin/bin/gunzip create mode 100644 cygwin/bin/gzip.exe create mode 100644 cygwin/bin/head.exe create mode 100644 cygwin/bin/hexdump.exe create mode 100644 cygwin/bin/hostname.exe create mode 100644 cygwin/bin/id.exe create mode 100644 cygwin/bin/install.exe create mode 100644 cygwin/bin/kill.exe create mode 100644 cygwin/bin/killall.exe create mode 100644 cygwin/bin/ldd.exe create mode 100644 cygwin/bin/ldh.exe create mode 100644 cygwin/bin/link.exe create mode 100644 cygwin/bin/ln.exe create mode 100644 cygwin/bin/look.exe create mode 100644 cygwin/bin/ls.exe create mode 100644 cygwin/bin/md5sum.exe create mode 100644 cygwin/bin/mkdir.exe create mode 100644 cygwin/bin/more.exe create mode 100644 cygwin/bin/mount.exe create mode 100644 cygwin/bin/mv.exe create mode 100644 cygwin/bin/nano.exe create mode 100644 cygwin/bin/nc.exe create mode 100644 cygwin/bin/nice.exe create mode 100644 cygwin/bin/nl.exe create mode 100644 cygwin/bin/pgrep.exe create mode 100644 cygwin/bin/pidof.exe create mode 100644 cygwin/bin/pkill.exe create mode 100644 cygwin/bin/printenv.exe create mode 100644 cygwin/bin/printf.exe create mode 100644 cygwin/bin/ps.exe create mode 100644 cygwin/bin/pwd.exe create mode 100644 cygwin/bin/readlink.exe create mode 100644 cygwin/bin/realpath.exe create mode 100644 cygwin/bin/renice.exe create mode 100644 cygwin/bin/rm.exe create mode 100644 cygwin/bin/rmdir.exe create mode 100644 cygwin/bin/sed.exe create mode 100644 cygwin/bin/seq.exe create mode 100644 cygwin/bin/sh.exe create mode 100644 cygwin/bin/sha1sum.exe create mode 100644 cygwin/bin/sha224sum.exe create mode 100644 cygwin/bin/sha256sum.exe create mode 100644 cygwin/bin/sha384sum.exe create mode 100644 cygwin/bin/sha512sum.exe create mode 100644 cygwin/bin/sleep.exe create mode 100644 cygwin/bin/sort.exe create mode 100644 cygwin/bin/stat.exe create mode 100644 cygwin/bin/sync.exe create mode 100644 cygwin/bin/tac.exe create mode 100644 cygwin/bin/tail.exe create mode 100644 cygwin/bin/tar.exe create mode 100644 cygwin/bin/tee.exe create mode 100644 cygwin/bin/test.exe create mode 100644 cygwin/bin/timeout.exe create mode 100644 cygwin/bin/touch.exe create mode 100644 cygwin/bin/tr.exe create mode 100644 cygwin/bin/true.exe create mode 100644 cygwin/bin/truncate.exe create mode 100644 cygwin/bin/tset.exe create mode 100644 cygwin/bin/tty.exe create mode 100644 cygwin/bin/ul.exe create mode 100644 cygwin/bin/umount.exe create mode 100644 cygwin/bin/uname.exe create mode 100644 cygwin/bin/uniq.exe create mode 100644 cygwin/bin/unix2dos.exe create mode 100644 cygwin/bin/unzip.exe create mode 100644 cygwin/bin/wc.exe create mode 100644 cygwin/bin/which.exe create mode 100644 cygwin/bin/xargs.exe create mode 100644 cygwin/bin/xz.exe create mode 100644 cygwin/bin/yes.exe create mode 100644 cygwin/bin/zcat create mode 100644 cygwin/bin/zgrep create mode 100644 cygwin/bin/zip.exe create mode 100644 cygwin/bin/zstd.exe create mode 100644 cygwin/cygwin-admin.cmd create mode 100644 cygwin/cygwin.cmd create mode 100644 cygwin/dev/mqueue/.gitkeep create mode 100644 cygwin/dev/shm/.gitkeep create mode 100644 cygwin/etc/DIR_COLORS create mode 100644 cygwin/etc/bash.bash_logout create mode 100644 cygwin/etc/bash.bashrc create mode 100644 cygwin/etc/defaults/etc/DIR_COLORS create mode 100644 cygwin/etc/defaults/etc/bash.bash_logout create mode 100644 cygwin/etc/defaults/etc/bash.bashrc create mode 100644 cygwin/etc/defaults/etc/cygserver.conf create mode 100644 cygwin/etc/defaults/etc/man_db.conf create mode 100644 cygwin/etc/defaults/etc/pki/ca-trust/ca-legacy.conf create mode 100644 cygwin/etc/defaults/etc/pki/tls/ct_log_list.cnf create mode 100644 cygwin/etc/defaults/etc/pki/tls/openssl.cnf create mode 100644 cygwin/etc/defaults/etc/profile create mode 100644 cygwin/etc/defaults/etc/shells create mode 100644 cygwin/etc/defaults/etc/skel/.bash_profile create mode 100644 cygwin/etc/defaults/etc/skel/.bashrc create mode 100644 cygwin/etc/defaults/etc/skel/.inputrc create mode 100644 cygwin/etc/defaults/etc/skel/.profile create mode 100644 cygwin/etc/fstab create mode 100644 cygwin/etc/pki/tls/certs/ca-bundle.crt create mode 100644 cygwin/etc/pki/tls/openssl.cnf create mode 100644 cygwin/etc/profile create mode 100644 cygwin/etc/profile.d/gawk.csh create mode 100644 cygwin/etc/profile.d/gawk.sh create mode 100644 cygwin/etc/shells create mode 100644 cygwin/etc/skel/.bash_profile create mode 100644 cygwin/etc/skel/.bashrc create mode 100644 cygwin/etc/skel/.inputrc create mode 100644 cygwin/etc/skel/.profile create mode 100644 cygwin/home/.gitkeep create mode 100644 cygwin/lib/charset.alias create mode 100644 cygwin/lib/gawk/.gitkeep create mode 100644 cygwin/sbin/.gitkeep create mode 100644 cygwin/tmp/.gitkeep create mode 100644 cygwin/usr/libexec/awk/grcat.exe create mode 100644 cygwin/usr/libexec/awk/pwcat.exe create mode 100644 cygwin/usr/libexec/coreutils/libstdbuf.so create mode 100644 cygwin/usr/local/bin/curl-kyber.exe create mode 100644 cygwin/usr/local/bin/curl.exe create mode 100644 cygwin/usr/local/bin/cygcrypto-3.dll create mode 100644 cygwin/usr/local/bin/cygcurl-4.dll create mode 100644 cygwin/usr/local/bin/cygidn2-0.dll create mode 100644 cygwin/usr/local/bin/cygnghttp2-14.dll create mode 100644 cygwin/usr/local/bin/cygnghttp3-9.dll create mode 100644 cygwin/usr/local/bin/cygssl-3.dll create mode 100644 cygwin/usr/local/bin/idn2.exe create mode 100644 cygwin/usr/local/etc/.gitkeep create mode 100644 cygwin/usr/local/lib/.gitkeep create mode 100644 cygwin/usr/sbin/.gitkeep create mode 100644 cygwin/usr/share/awk/.gitkeep create mode 100644 cygwin/usr/share/bash-completion/completions/getopt create mode 100644 cygwin/usr/share/bash-completion/completions/more create mode 100644 cygwin/usr/share/bash-completion/completions/renice create mode 100644 cygwin/usr/share/bash-completion/completions/ul create mode 100644 cygwin/usr/share/cygwin/cygwin.ldif create mode 100644 cygwin/usr/share/locale/.gitkeep create mode 100644 cygwin/usr/share/tabset/std create mode 100644 cygwin/usr/share/tabset/stdcrt create mode 100644 cygwin/usr/share/tabset/vt100 create mode 100644 cygwin/usr/share/tabset/vt300 create mode 100644 cygwin/usr/share/terminfo/45/Eterm create mode 100644 cygwin/usr/share/terminfo/45/Eterm-256color create mode 100644 cygwin/usr/share/terminfo/45/Eterm-88color create mode 100644 cygwin/usr/share/terminfo/45/Eterm-color create mode 100644 cygwin/usr/share/terminfo/61/ansi create mode 100644 cygwin/usr/share/terminfo/61/aterm create mode 100644 cygwin/usr/share/terminfo/62/bracketed+paste create mode 100644 cygwin/usr/share/terminfo/62/bterm create mode 100644 cygwin/usr/share/terminfo/63/cons25 create mode 100644 cygwin/usr/share/terminfo/63/cygwin create mode 100644 cygwin/usr/share/terminfo/63/cygwinB19 create mode 100644 cygwin/usr/share/terminfo/63/cygwinDBG create mode 100644 cygwin/usr/share/terminfo/64/dumb create mode 100644 cygwin/usr/share/terminfo/64/dumb-emacs-ansi create mode 100644 cygwin/usr/share/terminfo/65/eterm create mode 100644 cygwin/usr/share/terminfo/65/eterm-color create mode 100644 cygwin/usr/share/terminfo/67/gnome create mode 100644 cygwin/usr/share/terminfo/67/gnome-256color create mode 100644 cygwin/usr/share/terminfo/68/hurd create mode 100644 cygwin/usr/share/terminfo/6a/jfbterm create mode 100644 cygwin/usr/share/terminfo/6b/konsole create mode 100644 cygwin/usr/share/terminfo/6b/konsole-16color create mode 100644 cygwin/usr/share/terminfo/6b/konsole-256color create mode 100644 cygwin/usr/share/terminfo/6c/linux create mode 100644 cygwin/usr/share/terminfo/6d/mach create mode 100644 cygwin/usr/share/terminfo/6d/mach-bold create mode 100644 cygwin/usr/share/terminfo/6d/mach-color create mode 100644 cygwin/usr/share/terminfo/6d/mach-gnu create mode 100644 cygwin/usr/share/terminfo/6d/mach-gnu-color create mode 100644 cygwin/usr/share/terminfo/6d/mintty create mode 100644 cygwin/usr/share/terminfo/6d/mintty+common create mode 100644 cygwin/usr/share/terminfo/6d/mintty-direct create mode 100644 cygwin/usr/share/terminfo/6d/mlterm create mode 100644 cygwin/usr/share/terminfo/6d/mrxvt create mode 100644 cygwin/usr/share/terminfo/6d/mrxvt-256color create mode 100644 cygwin/usr/share/terminfo/6e/nsterm create mode 100644 cygwin/usr/share/terminfo/70/pcansi create mode 100644 cygwin/usr/share/terminfo/70/putty create mode 100644 cygwin/usr/share/terminfo/70/putty-256color create mode 100644 cygwin/usr/share/terminfo/70/putty-m1 create mode 100644 cygwin/usr/share/terminfo/70/putty-m1b create mode 100644 cygwin/usr/share/terminfo/70/putty-m2 create mode 100644 cygwin/usr/share/terminfo/70/putty-noapp create mode 100644 cygwin/usr/share/terminfo/70/putty-sco create mode 100644 cygwin/usr/share/terminfo/70/putty-screen create mode 100644 cygwin/usr/share/terminfo/70/putty-vt100 create mode 100644 cygwin/usr/share/terminfo/72/rxvt create mode 100644 cygwin/usr/share/terminfo/72/rxvt+pcfkeys create mode 100644 cygwin/usr/share/terminfo/72/rxvt-16color create mode 100644 cygwin/usr/share/terminfo/72/rxvt-256color create mode 100644 cygwin/usr/share/terminfo/72/rxvt-88color create mode 100644 cygwin/usr/share/terminfo/72/rxvt-basic create mode 100644 cygwin/usr/share/terminfo/72/rxvt-color create mode 100644 cygwin/usr/share/terminfo/72/rxvt-cygwin create mode 100644 cygwin/usr/share/terminfo/72/rxvt-cygwin-native create mode 100644 cygwin/usr/share/terminfo/72/rxvt-unicode create mode 100644 cygwin/usr/share/terminfo/72/rxvt-unicode-256color create mode 100644 cygwin/usr/share/terminfo/72/rxvt-xpm create mode 100644 cygwin/usr/share/terminfo/73/screen create mode 100644 cygwin/usr/share/terminfo/73/screen-16color create mode 100644 cygwin/usr/share/terminfo/73/screen-256color create mode 100644 cygwin/usr/share/terminfo/73/screen.Eterm create mode 100644 cygwin/usr/share/terminfo/73/screen.gnome create mode 100644 cygwin/usr/share/terminfo/73/screen.konsole create mode 100644 cygwin/usr/share/terminfo/73/screen.konsole-256color create mode 100644 cygwin/usr/share/terminfo/73/screen.linux create mode 100644 cygwin/usr/share/terminfo/73/screen.linux-m1 create mode 100644 cygwin/usr/share/terminfo/73/screen.linux-m1b create mode 100644 cygwin/usr/share/terminfo/73/screen.linux-m2 create mode 100644 cygwin/usr/share/terminfo/73/screen.linux-s create mode 100644 cygwin/usr/share/terminfo/73/screen.minitel1 create mode 100644 cygwin/usr/share/terminfo/73/screen.minitel1-nb create mode 100644 cygwin/usr/share/terminfo/73/screen.minitel12-80 create mode 100644 cygwin/usr/share/terminfo/73/screen.minitel1b create mode 100644 cygwin/usr/share/terminfo/73/screen.minitel1b-80 create mode 100644 cygwin/usr/share/terminfo/73/screen.minitel1b-nb create mode 100644 cygwin/usr/share/terminfo/73/screen.minitel2-80 create mode 100644 cygwin/usr/share/terminfo/73/screen.mlterm create mode 100644 cygwin/usr/share/terminfo/73/screen.mlterm-256color create mode 100644 cygwin/usr/share/terminfo/73/screen.mrxvt create mode 100644 cygwin/usr/share/terminfo/73/screen.putty create mode 100644 cygwin/usr/share/terminfo/73/screen.putty-256color create mode 100644 cygwin/usr/share/terminfo/73/screen.putty-m1 create mode 100644 cygwin/usr/share/terminfo/73/screen.putty-m1b create mode 100644 cygwin/usr/share/terminfo/73/screen.putty-m2 create mode 100644 cygwin/usr/share/terminfo/73/screen.rxvt create mode 100644 cygwin/usr/share/terminfo/73/screen.teraterm create mode 100644 cygwin/usr/share/terminfo/73/screen.vte create mode 100644 cygwin/usr/share/terminfo/73/screen.vte-256color create mode 100644 cygwin/usr/share/terminfo/73/screen.xterm-256color create mode 100644 cygwin/usr/share/terminfo/73/screen.xterm-new create mode 100644 cygwin/usr/share/terminfo/73/screen.xterm-r6 create mode 100644 cygwin/usr/share/terminfo/73/screen.xterm-xfree86 create mode 100644 cygwin/usr/share/terminfo/73/st create mode 100644 cygwin/usr/share/terminfo/73/st-0.6 create mode 100644 cygwin/usr/share/terminfo/73/st-0.7 create mode 100644 cygwin/usr/share/terminfo/73/st-0.8 create mode 100644 cygwin/usr/share/terminfo/73/st-16color create mode 100644 cygwin/usr/share/terminfo/73/st-256color create mode 100644 cygwin/usr/share/terminfo/73/st-direct create mode 100644 cygwin/usr/share/terminfo/73/sun create mode 100644 cygwin/usr/share/terminfo/74/tek4014 create mode 100644 cygwin/usr/share/terminfo/74/tek4014-sm create mode 100644 cygwin/usr/share/terminfo/74/teraterm create mode 100644 cygwin/usr/share/terminfo/74/teraterm-256color create mode 100644 cygwin/usr/share/terminfo/74/teraterm2.3 create mode 100644 cygwin/usr/share/terminfo/74/teraterm4.59 create mode 100644 cygwin/usr/share/terminfo/74/teraterm4.97 create mode 100644 cygwin/usr/share/terminfo/74/tmux create mode 100644 cygwin/usr/share/terminfo/74/tmux-256color create mode 100644 cygwin/usr/share/terminfo/74/tmux-direct create mode 100644 cygwin/usr/share/terminfo/76/vt100 create mode 100644 cygwin/usr/share/terminfo/76/vt100-nav create mode 100644 cygwin/usr/share/terminfo/76/vt102 create mode 100644 cygwin/usr/share/terminfo/76/vt220 create mode 100644 cygwin/usr/share/terminfo/76/vt320 create mode 100644 cygwin/usr/share/terminfo/76/vt420 create mode 100644 cygwin/usr/share/terminfo/76/vt52 create mode 100644 cygwin/usr/share/terminfo/76/vt520 create mode 100644 cygwin/usr/share/terminfo/76/vte create mode 100644 cygwin/usr/share/terminfo/76/vte-256color create mode 100644 cygwin/usr/share/terminfo/76/vwmterm create mode 100644 cygwin/usr/share/terminfo/77/wsvt25 create mode 100644 cygwin/usr/share/terminfo/77/wsvt25m create mode 100644 cygwin/usr/share/terminfo/78/xfce create mode 100644 cygwin/usr/share/terminfo/78/xterm create mode 100644 cygwin/usr/share/terminfo/78/xterm-1002 create mode 100644 cygwin/usr/share/terminfo/78/xterm-1003 create mode 100644 cygwin/usr/share/terminfo/78/xterm-1005 create mode 100644 cygwin/usr/share/terminfo/78/xterm-1006 create mode 100644 cygwin/usr/share/terminfo/78/xterm-16color create mode 100644 cygwin/usr/share/terminfo/78/xterm-24 create mode 100644 cygwin/usr/share/terminfo/78/xterm-256color create mode 100644 cygwin/usr/share/terminfo/78/xterm-88color create mode 100644 cygwin/usr/share/terminfo/78/xterm-8bit create mode 100644 cygwin/usr/share/terminfo/78/xterm-basic create mode 100644 cygwin/usr/share/terminfo/78/xterm-bold create mode 100644 cygwin/usr/share/terminfo/78/xterm-color create mode 100644 cygwin/usr/share/terminfo/78/xterm-direct create mode 100644 cygwin/usr/share/terminfo/78/xterm-direct16 create mode 100644 cygwin/usr/share/terminfo/78/xterm-direct2 create mode 100644 cygwin/usr/share/terminfo/78/xterm-direct256 create mode 100644 cygwin/usr/share/terminfo/78/xterm-hp create mode 100644 cygwin/usr/share/terminfo/78/xterm-mono create mode 100644 cygwin/usr/share/terminfo/78/xterm-new create mode 100644 cygwin/usr/share/terminfo/78/xterm-nic create mode 100644 cygwin/usr/share/terminfo/78/xterm-noapp create mode 100644 cygwin/usr/share/terminfo/78/xterm-old create mode 100644 cygwin/usr/share/terminfo/78/xterm-p370 create mode 100644 cygwin/usr/share/terminfo/78/xterm-p371 create mode 100644 cygwin/usr/share/terminfo/78/xterm-pcolor create mode 100644 cygwin/usr/share/terminfo/78/xterm-r5 create mode 100644 cygwin/usr/share/terminfo/78/xterm-r6 create mode 100644 cygwin/usr/share/terminfo/78/xterm-sco create mode 100644 cygwin/usr/share/terminfo/78/xterm-sun create mode 100644 cygwin/usr/share/terminfo/78/xterm-utf8 create mode 100644 cygwin/usr/share/terminfo/78/xterm-vt220 create mode 100644 cygwin/usr/share/terminfo/78/xterm-vt52 create mode 100644 cygwin/usr/share/terminfo/78/xterm-x10mouse create mode 100644 cygwin/usr/share/terminfo/78/xterm-x11hilite create mode 100644 cygwin/usr/share/terminfo/78/xterm-x11mouse create mode 100644 cygwin/usr/share/terminfo/78/xterm-xf86-v32 create mode 100644 cygwin/usr/share/terminfo/78/xterm-xf86-v33 create mode 100644 cygwin/usr/share/terminfo/78/xterm-xf86-v333 create mode 100644 cygwin/usr/share/terminfo/78/xterm-xf86-v40 create mode 100644 cygwin/usr/share/terminfo/78/xterm-xf86-v43 create mode 100644 cygwin/usr/share/terminfo/78/xterm-xf86-v44 create mode 100644 cygwin/usr/share/terminfo/78/xterm-xfree86 create mode 100644 cygwin/usr/share/terminfo/78/xterm-xi create mode 100644 cygwin/var/cache/.gitkeep create mode 100644 cygwin/var/lib/.gitkeep create mode 100644 cygwin/var/log/.gitkeep create mode 100644 cygwin/var/run/.gitkeep create mode 100644 cygwin/var/tmp/.gitkeep create mode 100644 readme.md create mode 100644 tools/elevator.exe create mode 100644 win7/WinDivert.dll create mode 100644 win7/WinDivert64.sys create mode 100644 win7/install_win7.cmd create mode 100644 windivert-hide/Monkey64.sys create mode 100644 windivert-hide/README.txt create mode 100644 windivert-hide/WinDivert.dll create mode 100644 windivert-hide/monkey_delete.cmd create mode 100644 zapret-winws/WinDivert.dll create mode 100644 zapret-winws/WinDivert64.sys create mode 100644 zapret-winws/_CMD_ADMIN.cmd create mode 100644 zapret-winws/cygwin1.dll create mode 100644 zapret-winws/elevator.exe create mode 100644 zapret-winws/enable_timestamps.cmd create mode 100644 zapret-winws/files/list-youtube.txt create mode 100644 zapret-winws/files/quic_initial_www_google_com.bin create mode 100644 zapret-winws/killall.exe create mode 100644 zapret-winws/lua/zapret-antidpi.lua create mode 100644 zapret-winws/lua/zapret-auto.lua create mode 100644 zapret-winws/lua/zapret-lib.lua create mode 100644 zapret-winws/lua/zapret-obfs.lua create mode 100644 zapret-winws/lua/zapret-pcap.lua create mode 100644 zapret-winws/lua/zapret-tests.lua create mode 100644 zapret-winws/preset1_example.cmd create mode 100644 zapret-winws/preset2_example.cmd create mode 100644 zapret-winws/preset2_wireguard.cmd create mode 100644 zapret-winws/service1_create.cmd create mode 100644 zapret-winws/service2_create.cmd create mode 100644 zapret-winws/service_create.cmd create mode 100644 zapret-winws/service_del.cmd create mode 100644 zapret-winws/service_start.cmd create mode 100644 zapret-winws/service_stop.cmd create mode 100644 zapret-winws/windivert.filter/README.txt create mode 100755 zapret-winws/windivert.filter/windivert_part.dht.txt create mode 100644 zapret-winws/windivert.filter/windivert_part.discord_media.txt create mode 100644 zapret-winws/windivert.filter/windivert_part.quic_initial_ietf.txt create mode 100644 zapret-winws/windivert.filter/windivert_part.stun.txt create mode 100644 zapret-winws/windivert.filter/windivert_part.wireguard.txt create mode 100644 zapret-winws/windivert_delete.cmd create mode 100644 zapret-winws/winws.exe create mode 100644 zapret-winws/winws2.exe diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a23dc7c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +* text=auto eol=lf +readme.md eol=crlf +*.cmd eol=crlf +*.bat eol=crlf diff --git a/.github/lockdown.yml b/.github/lockdown.yml new file mode 100644 index 0000000..b9a7134 --- /dev/null +++ b/.github/lockdown.yml @@ -0,0 +1,2 @@ +# Lock issues and pull requests +lock: true diff --git a/arm64/WinDivert64.sys b/arm64/WinDivert64.sys new file mode 100644 index 0000000000000000000000000000000000000000..20fd7a1adfde495e59381a98ffe16a8fbefdf5b6 GIT binary patch literal 79808 zcmeFa3w%?@l|MdL*N-d7Zwq5=h-C~x5)i`EI0@m(CW#CrDVFoz76W<6I89<`(h5o} z<0h4%+n_*73cuC{x{0LJEe+71X15sJhk>Ty(WH;v78^(+c_itb#V=Mt79A<1Up7ba4|F8aE4?d?A{49;_ z*1l1=S6KK)VWp#brSXXsk3X_v$(N1GmOS>@<6ki@eaN`t$;XViXQ?Du9YS<(228Z5f!9XlKo|pS+`cse4_n)S(=kbc_We%!aZOIpIVeCPFGQ0Q7nGdRIJ!~w~Yto9?A*8sJ z)YdjUGx)nK(1YGJjOp-D10}N!_zL2^l&xU`tFkJTM7oha(w|a^`iM#4UuRbd>}&M) z1fHmeeL-NkfWt-$tTi7`m%w%c#1mS9%|>*%zw0G|$;cP|JAyZ=XPCe1zVgu5zJhN{ ze~$kM#a0A@AMl0bMR{0AB-L?4*X2=uR8v2w*SWZ|@X0^gGmF$~Nn zGgf-tiiaM392tq0L{pAm-q3vb`hV5m25@kOMh+FQjP7lWRkn(Y-;O1~mDNA@T@jgw z@_8b8rzXjvp4$Xp%Otjmv73Jvo8KrD3@9HiV@IjnRKVz6HuZ3CG7H7Rpl?0Na)`e7 zEW7@2fhM!N9(bUfhw>E|#kV@d3_sY(Kya?C7JOIm?N~Ux`O0dmFSf2&Jk)oQ35V;L zrn^nYD%%9MyO6m;i;b-Jl*s&JHLP+e%a~;}hEuDI`%;%OX_k@UozXj+HI~UGc$QoZ zMyZSSiixa}p34$gWueg(DrG`%o5(8XrpRZPpe=QHf`u!M#uE$2Ar#84P+^rTRAp>h z_#i?l)AWuFhbxzAuAh~Gb{Z4pma!?;mT`vCmTO0swG=XqCt4-Si=t3J2jLk@ErZnTMLK$fY z#wU>W1f}K9Dl{Su0cq$9mh#`F*%|P$F-5pT7~On_20=tv>|(t?Ok$M+d-(fqNMmjF z(%F($yPjceT5_^Rj~bDgIf9k-AJmuP^6uEF;s$9rYsgI&@!8jmp z6_jzJe2@JWQ!b`Ve}0xi_1ZumNzkolwQQk`5RV_ER#(MhCUu`dUzdM;%SLk|>y@`P zE&L6}PHBex{Mx?oo_OVAn`BFs&o*OBN>+9>C`yM*nRHmLbuTRc_|}aiYX%1nqc8%) zAU|JvIlP zZc~CBN@cDJbA}w~o+$hD;KS`B*lybotiE+Q?B3h)ty9$a^@8q@4RMPg9kTsE_H|EW zzBI(Mg|tH^CWqc1!R{R^q#WwPGg;6caxm7DW=;0oBC_4yOqS`pUiKZj&(YTnTx|6H zzR7*BB(ltEd~3h2y6*#|`+$QEbv%l6|9untno?OUREbJA&*SI=e|i2D-?S)Se&3|N z5y165m-dhi&zH~^f^!fs+JO)BBEycDGzZcWkv0x;SIy@}8sS52S`K_#P&d)QjW$a{ z>VkcMZv*cZ6tdbjjB!cJva0dzT0vUy<54X09h5zd0Qv3dLrGxf z-$yv3Wtk9~nVHwjdTgJNRFhf#Z#Q}HJ($TBY4P2LFb&_PRsZ0oEG0dY(r3`Sm}>bD zW$pO>0>aAb9XGvDz3rxhABQUo2sh9s2)O#&C$CrAL~S6vEdo2V{2A6)4t}IIJ)~v# zy01&z`Y@i_XWBOgO^I74tx4M2rI$kz;(EM0u1(z9l`e<=bxq>d#}Fu8hjiPx#I1Km z;#!IyJ+yHG;^x4?jiBB7>UR!rTp(!I`<{7YqXpmHSAMhcQKa9V1eo9({mi7T?a%yn zBb5z4^XA6o=s$X2i1gq$e!X#BB)$Og_Y>H?^xZZ!3Gi*mm$=o9G|Q9ahiq%4t*qX5 z2z=}r0e(JbxB9NEKHycxnd=y(rw>Y}G31$7T>Ijbb)~`s4OuVxlmF1RCgrZ5KQnb) zZ)Wd(4;;9=ao_WTjY^o#&_6cbV>6+oXHnWx#EqaQy%#W6Yr?yf=)QlRhRraePnRRi6?8Ra zps@qIU`F3AN1(JFh_?eTa{|&3C{09KHPSjn$wGCS8NMOVH^8Fw1(Z&4R^OCI?=*j0 zS^YCE*FSnd|)iS4Xd2Ykxch=KKZIu42fUY{U`I*J4j)ft>1hqP;4 z$4bCQ;l(WUBFeM%*3dg;f=8QraLefijYq_{lcK@jDQ5fU3ar;8Hg2JMZGRL(QiAK4 z7T<$)I-f~k)3jKAnd{A-;Oi`~8FdApwT8MLU?J(KHT0n<`D>9jRbveqHFMwY0DRER zGW}7s3;C+?t#hIr8f#7Q5DwBqa@;Z=AKBt)cEz$cfz0QnlALsqH@$%@!Dwuo>HQ#B3vf)1us+o z5S`|DB&@il`bnN}0SkodL|<1?2Ifih`D8xV9x30S<5>Xuu4k=hgGDTqm+Y$Onv&^5 z`6DJ_il+-OFJ-epaEiuvs*HI~o)SH#G4b&w{7|lk@E&W;RA_7-KJSgJ^%&tx?K@S( zJmEH>?<8PcF4OeUyiE9pffKBKX76=`R{)$T-dJlu}&BY-lsV zFGrsd>`ts93Fc`r$*VX$7C%)T-OqOnT1f- zu^{kvqpl!uC0c}DODGA4v!iX0mXyZrJHkKv9)(9wmVqyT2j?H_@a^4rmy$o4_sjA5 z0)5@1v8H(()aPsDP`%))kbxtOO@eE;_Z9Ozodff9fX~%D(<>r*mJG}jTTk{Pp67^0 zNcY$PGajsScSiE;PaTja7S{1Q)Oyl}&9m$FzGB{o*JCVdAk)^lkD1^2(b>*2qo*f% z?HtJcW5H}G5W2@$(v=R`NBE>FG7fD$!rl@>#?J8W_J!=;@I)yP%#P$KltY~jMwk;^ z$EfW*?@=MtdLq1=*HJEqUO@RDj7{S*OM`p@ctg!k^gM3sD{lUkRe`xk4&i&0j+A~} z?kjfCm@F*tWI%?OTVo+ukS(|>OJhjyp_V+#M=^E|IMiX4%FYK)YDs*Hn9E%CEkhei=K+q|9CRT zy>aZVz6;BeojoT|znB)k{u@#M)2Lre=k@kBC{LmX$G=U9cjEgZSET-QDN_GJ-vv=} z_MAigW$E$jpN;yzZ$&?3DD}4~Pmd-grVlcsZR$k6Me8DPeyqUhZOBmiUfnj8XkC8k95+1NjzxKLX>!2n;b>fpH2jrVNE~?mEEu5%q;Zp;d$O?C%RD z-ihyvypg(}(?$BC!grxT=j_T0e|3B~9sz9M7VEkHB~{ z0;4TQfzbvSHA7+S8V?vb)E7!Uy=A!(7$f^(G$?6GUySrD`c(wR<0(oz#9Rf&vJ_`e z-B1`C#{$N?rRa-M3auKHr>B%~i^z^PC5^*CzC}kOFw#>M7-hs8kR4*GvuEQ_7%K|^ z<5|Ec%Tr*qDNj!+@rf#*^7%KVKk___{uF`n;|Pp~JO#!Mz<7Bm4Et!nxE3%PlzMu_ z(F(0fX-q|6lqqRSf8=`>osPh`GfinnTfPFLEX~>T`cN3tM*&6}`n*l4r?+fO6lX3& z8kBe^zAyS~r0x%ux*NxS$#>xt>U|S@D~^fFx6^Y_|1~r&u2JaJpgaj*MMf#{PJCa~ z7pecbbdG!DSQ+CY-Pv=B#>F-9>(560KP`oxGs+jP%lCN>7^1WZ*Nyfmv`_LZx2cAgX-gD)k>A85Zf&1|^Nxk9>>nQ0cDJ-z#dBK0O5(&kcpK zQ3n`LVT_5o2+ftJ=K%4W%Ku6lhk<;H?p0}@sPIi0wHN%~km&5$F%-tiqYmiqM~P0-Gs^m`8t=wNS|cfX^I$wb!Ws_tnoXS6e^zLX_aoZE63_L}f96ZB zV|?8_wH0%(Yfdnmg}Us_c@Oe*ZJ*^a!9D_bGv>oa;)i|YkOX@x%E0D)SR1N4z8GuQ zGg!OYwajxjf>FbEO9{;tu+;>*+L)&c`&JxwR}^-S6p*nNWFD+JEmr8})W1Pdb{bIL z1-f}*iwmO72EldAp)st_HVdA*17dFwc1?P&e7Uhf_`wB#CQ?+{0DKB4yR zf&J(t_=fb*q)Xw=4m_o#<`q53t#f?ipRH*8k#_}PKnIpXzBJ%zZ*}gn2%eK-j(=yG zYfdNH?H$WF@A;l*&N-kvU#p`%RhpdjC5Us_EySM+T=a`4AL$qK3<$3{f%MLJBLXR43oZpnDn<|(nrPM z16xBB&rBtKBk-@nI5uWQ@Q=~`U679sd>0BwdngZY-}jVqJbl|R>78TZ=U*~h{%hjr zFC4C(VbTlZ*0WPsQWC%ZZNt>lSr9+}5@Y=I&iwf4+lHy9a~L`-iHkqzKMdR@!_>cR zn0mGigD2K>(f+k6{Tq!(WPUTobTlm@@1t?2Qs&C){oZrQ*1peTH!SHRIhb&?4|_e} zr5+9JI!-)I-?WAEu+Y9AvA|itrgHmAg^+i?&Ql<;fc}!}80>{k$>6Hk zSvsOcCp912S(?+*JeGNOmX2)MS(@9Dk-+ZsYGBV{YmdFQRPgP4I?3mKI+^CLog}-p zYxGz5nxDu`;dIUEL9zJCuWLZ&P5iMW1zHZdUC?=%XWp=UF>+l~~*e z9?kDF051&t6Tu9(Y5I1o)p&YD*PN3LnC~(Fm_b{Ukn0Iz4l==3rG=fZN6)SV%fvo{ z%k6DttRy@Ub6yeV`?)O8SCW7a+g(L}+#+=(r~`MsmP^ zn@f{CTS~Pa8dr{8uu%#Dtk1)yQw#6|4sJWVM~Ym;-H~Ipirk+n-hR>aXIxW1TXGMCOj6<1WH$ojdyZY-3(ofa6Q} zA)VT_F_F!9;iTSUg08z;2brA5lsqU8{r$*vta+#ob*ednp()5%7R~NYWL@}N?R`W+#pZf_sgMNfn~WdA7!Ji zI*rurf*;Zgh!fx3hd?~E8F6ZFfiR+bNgk{8;$4gUa}n#2g!a3r4_YyXO@}dN*10PR-}uoA zmDZehW7>2M@ai-pyO&`6xG{ICxK~NQ9q|P*xKleeBQ1)*VG#b=gYZW@7Jv6Fv=!?r z_sw#saTW_LzXt8GS`IhfjJ8GO0`>dXs6REj!zVPl?s6gLu=ywME$&;1MpE~;_}*)_ z|N0!ZiTp^avSgYAcAL&A?Y6~fvjclYpQ&%PVr^k6t0bCGyNNE_`al;=KV4drK^Mda z^eN&hP4?>t(!`2*Y@hCjf8hX{OjBsmI1Mz2$cfKNgAYf1b{c#x9tRydvG!DXqc9Y% z+=#i8*FobP{6jqUBxvNtxFb2zig8E!kMu$*w_(vfZ#+3d`RNy8vzP0Pm}9qiomT+qYj_N$d;oJ9f`h4Y9^mhcWCBT*B(XZhT zQ3c(^rPu?GNKR!8pI74tW965D>nJqdqxpN4{IPK2&wG1$zi`??*3#N%usrA^x)%u^ zTEh@+y`cMQw1?(JlJ$jCSY-&Zv;?wrWeLlrb%p_TH9^kH*TD}Ca{OmVD-iO!J7=Mv zVAE6NdS3Su#2ce>-O$}R6Ml&z3*7*jz7Fy(oQ?fwQFpjNBzc$1<(*fRci{IR#tiBB zq`y`{*OZ*f9`oR}gKKJEu@^Fy{4z++dLd_hkhAL|a@Geq8_PczVGkmmEbYB`=%$7S>_`f|_li7dAhu|~j?#%(p8G-e5JT3g2(x1&&QB!bo``_kYe*_97FYY_|mH6JoPqPdfOt9j$bzw7jsB8EEylgJ+k$aFA9{`h{6IV)5iH1n z#enleoDraL9XqB~-6=Arcam)F0NykKCY~@F&@W9<;c#dF}`3MQ&=v?0l3G=c;2t^WIW{i zPU>6N(Qu{r=W;+wVl%wIk^}8n!}vf06Y8Ngi50p$*_hNg=Yi!x4weD#UX*vUhsvgXZ;}@4pU%}KYG6s36uo+%8z1w z1IN?0z@|}z@W+U4gT7x`{d)g?5BW(JDSJMjoF!YQ<|wy$k*`}a<2Ftw=xW3~(o-h3 zoCMDW+n5vQ;dV-}xAc^;D<8q`37a3u@ne#CUWmqSL|zY|UGNc%uM$>UkF^PvJ-rNj zIH>nj8RPb>PV8?;Gvo7?5&Np#UeK)A3xe>+F0kS}3uFh`+sHPjh0TrZZB!@O*i4uk zg0Qo3KDJ^E118z-P8E^wTY`_~b%Gh32%FvH=o~Wu=PKAL2f$qo8SeQ%73J`Y0&ms? z;Ri3Lz<1d5t!SDNeObP-KQ3b(a&SX`nW>P8LA@Nx#@u1JPxj4%%;5A86?!y)ezZTt z>G8$*^k{~ilFE=Bko@te&5|~L8?^5?9;5a2af}&9sc@9W6!^4q6Xs>3p5>MSpBYIC z4z%|q0cI}J%+L4Z+(Ei!VBR9_U0I9fI!CW)#<;7(xSJ7a3&GIbF8iYO!>%G-Xgo%1 zadi)E`^RD4PU*gR9AD*(KsIk@JbrP(Zuwc;NOrhjvW$H^*jMqKo{2p-JaaI9sE(89 zXQC0;C%zorzZ}rlt%Gb*N;zgx%7HhBkqO{EPcg<$s7MYC+;3IZCzvZ+RokL6{)YEc z9z$cWErs@7caADd@tDxJ#J@MdrxuI6kc{|cj5qjfLYGdkNO#Q(UA~dgn5&3KL#l`D zO;iu;g?=g@qfZTJzxQYJ7TpWJy%)T#9ff}WBC933deQeLVMB$K0bl9y2lIlA!A6){ z(~NW-_%A$xg~G*z12Yhu(>nwY!8rwasPJe0u;ZHRp713K7Axa<*+f=(W`Z0l#u&Q? zcpS#KS%4?Oqj9xQqpu-e+@~4I;gie>*CqNSJfrZJMc|jkz%PkEjyU`YfImeJsj$xc z=R6k3A&-ui1|^fbuO0rqa#<^<@B?w?`)h7E~i?+e&la{r74I*|7}*jIWH`%9be zXXJ0OQ(Y&cFAcxX&zN-v^Bd)};hVZv-MEA0{sG_b5JDwuzNOphOJ#d@;k{0i&|3;S9z9o1Q+y|I*k<>V zr*&KF@#HwX0U3t%{Eb-8Guc&fQp~qdose&Sr(W6L&w^aita-(6w62PUc$yqv-8-3$T%TrUStsriYISQe>|WSUrOXjoTJ}r@&Cw>rZEQn@ z4QFArIL9(Kk=6RpPm6`*nsV3_7Yo_l8a#iT2;L1pSJ8zrW5T#9h~%4#d|J%&bz`S= zAA~O2uF-mQ<&Vv-F8o8@VnMsyh_u6Fghh2Y50?mhArmViYvKwwWL9Gx@!~53#<4$D z4m>WpifvXoQ~N!ZIaf%j2@>D(yg%A&PVOJ`lThCm(3juB^A0@ed{hd?egeXL#9zX? zvLKt)2GJ(1n_%tT+a>mwe>Q>5=md>B#8G}uf2>1@-n-l^_cG+P1A%n=F6h3UH)4Lk zJZA*o#G6krH+jC^bM^g?cAO)kHGX>vTSRMaS_8Hl@eX>n!`3|sdlRFP_CB6uKYYKy zRYCg3`{9O)9R6&oFyQ$O_{hI6CRsA^p7P1QEIJE}b6Z(w;D6nXKz0Zn&d5-jp6$#c zx{!YqY!QgNvM8Nk)3aODSx#Cr><0uk*@eDMC|tM-W2@5SaPFPNMy=N_8j&?oNV80IlRpFW4!Zz7$%f#74FP!qWLrRA-rHc#NlkmuP=8W=*((_m=(6 zM#$f$JTb5lYk&9lL}xI$DbM{Y*l`{fNcL|~=N$)pIwUKfPunq{VqVQ`SLah2FOVO- zA&eCP^CXQOvZ)*Kl;Cp|88aJV*TqU6oB^ji{l0Sp@|eiCq_ddL%le6Szt87>bev9| zMPhWGp}Ne-TaP`bafP!zRHvwEs31K{niQg_$zVLd4cAVn~-YA4-BLAC+ zzk<-!ruDRIk~}8o%s$#L{w>mesHU%lJtC5RX9}A!2|>v(M$`WVV<~u}74|Atdk|+7 zJ`(j7Q>J?h!TF&sk{{;^OwNgYPeN}a8Gjh{yH7ID!O~HlV2u#!ir_R!i}bVbam2Y2 zf_sK=TbtmqMR2g9Y`4f}5WIZ^Z>~e2$!!I~CeLmo~!&jc@tEQWfpJ;Hm)6^#c{s_d$j=bk!ct#L38s&VdkMhsPlk+|4 zJ*R}|IC5hx+<`dBntJS|w$EaojfdpGhE>6v4nE90TOcDgV}GP)t831NRb4l!W2a}L zYYvSaX~H}o@#WdAt#i&TV4+OB_bi6bK~bhphw)<*ZuSHxWcjp3R-X>z`D~eMPEVVz zrKgQu=_)e#f(=QYvv<1Yd;xy3+IsjBp={N<9|<|jAxeic4s$b++Tp00C3AQ;Aa z7_y4S-uaP2h;?XjAqe4rQ$oIfD zsJcDRyGS{s)d4#`(T(a_nKV#e<@stM#~{P_da*45a;HE4xr8|RpNz?0mNX#$%0d24 zyngO~(qE??_P=;-amVmQC+5ob3asrxO zSWhJ}J{QyauoY!#eYj+EnC@42)qOzUmjrxit>-?#0)#t%|2g+LiO6teEk*eE!JqL# zz`Yx~1i=G*W!?q+!LYYI7p}~KOgRDgxCg581mJH2KJDSA=e-(fy&1gHHMjXJjhEo_ z;YuIu(~YHk4L1O;4e-3r3r8E#v1gL*nO)3b6j|OqzzwtPHkfA{WG?)OtlVL#{`pb zUI6J$sAt)CkY8h{Sw{8ZxoK?Fe{F;Gh8)`R3ClbwYT*x<=clzT^(FP~TbshWgXiRu zeGjt|9oj;$*Mk4NOIe8*dw^t@Y{tB=b*5(p?bu_3-`3@N$@l7W*pspVVVdQL@lC(&WT6osgf|oYToL+NF*dy?={}5Cb9t8X!<6~fipX9!9J{zd9ifH`fAwr-qsivlq9pvbsC+X`v1%n_~G`1D=%Tb zBR#!rjeMNevnRz|3-LM4fiZhm1NeMC_>6e{COrH7wnq48PYxc?|rHA)V>hcg37C`&e> zFJ!jPDZ+Cs0{PNvabJvtdt&ImqF{DoUa*J-7L90~V@A3uHhlsMRE)wocBI>4(s6BL z)_>uw72Uztf7j37jvw@|zZ-tLKLdVe#6bD;-}f;}OD&034SuoTd61KJ!*qi)cs zMl=<}Kv8_H3HJnnwhx(gb`R)^`>)jbBuZbRV~3dPA3#gccmrr0TQ8?QXxumm*LL;| z*b8x|$EVQu?~T7o|Ids6eg94TYe0MA;aL9t!uX*yYR6rA2SF1b8%UEyV_N4BzsK@A z&FzFg@jKC9<@pZs(@^=nF2Ou$5YCa|h5c#eK1&*3{}cGBG#`u~enqy? z^H}HBLvM1x_leHxjljHja)-e8sLjx|z61S_f5Z7ZvWfC{oY5m4D_Ra``N#$u&5N^l zq?hx&0V}s1sdbwERk6{TP&e7*X#VS5rtx$@4<)@N2pyF4&;8iT3c^3bJ)X@BLdOIy zNBSc6r*f1fKdnp9K^y*9UvU|236{YR3qFUSEB2;y{g;+uFZLAIulZS0)lP+d@SdqL z{v#X@tb00u1HpGB!Dj5dW(DbbRnQsgum*sgqq2nfif|VC{Y*}1SnY#)>#9qjbrp0F z=rJMfh(vqWV(0`(!22HD@dRB!lE@Y=S%{vd5z#dy_lYE!EV*x%jp~Nq3k;S==E24` zA8{FNluF7%r~XpUZEfl~ufc72547fcnL=Jo@KU()YIU{!>FRa;4t3FbDu_0a?*#0w zr2h|#+p<4jy}nk$?KU~|u9#y1Qv}|#%Yk=9gXQF0MIS!}oi(UO-z_G6l=cgH zY?BN3eXRt)W`7digE<-Jd)S_<;Ub>8Ixf^7?rfzmI?yk?KcHhqYyezu-UK*Z=*RQ; zZW7pvAjZ=Y@IjL%yPNi0peF}tkLX?C{|@lI1V75P(4`@Nj$w@zI0cp14q^UD^P z)qd|oTh)Fi9*FIG>T~LU>h}id;wrvNfo})!C!7giYR>@Lf`()RS802m=n6RR?zqhd zJ3(kP@UDXF;`m$+@9A5B`Ti<=Jdn215ZcmM@WP(l4LNIKYbzX(snvyLW*zP?GdT;g z9A*(_d!j$aN{l?AvpZK-|9V)Ttp52&IWzsUF7k&Gj+$rFm`U`Ts^pL!y2+!MGrNie zpIOHK3i|5_ZR?ya>_?Grk%ak<&IQsuhc@GmWDS-v7^~_m|`PYneuIH%f&oSo;=sD## zXDT`)<`zZA6iS|$(>iD6)c*N>d5lh(2%XY_d3!ORquqHpZ(4hLWK-U^`8+6io(4VW z?5uijb}+pj`yBL&(rGf*l0+xaj%YO&v^oR79ornaq`X8f!Tn$*wwZEC*Jf5yJ{9q; zh)+hm32`&xI}jg__{)eFBK`{EV-Wu_;-e7Xh4=`>Uqd_-@z)VgMSLIPTEyEBPelCJ zhzp1xW+h#3vXUpzPeXAOfulGS$K$AjaQr>$ARPY_al-Kg;)LTV#0kgu5GNeF5hol! zM4WIuhdAMQ5plxtGU9||7;(Z;6cikj1qDaFfP1%u65J}<<~^Q4!PUjiT7&{;5O z{GHH|sv?Ss6bIr0KzEa|OO zw}3bpfy?dvNo

VKWJT^4(S2q3SZE!|VuOy*&*WgM`Nnja+=SdQL(1Dmq?#y40#N z7jc7NAMRR6^mz6nl__J44;6Xb3HMks)52eSE2v72}9pK5Gq+b(H79|g%$C22z z!C#<{{jD$>60Z*9mw-WY+By5b_n+U*r?b1t*)2t8Y5ZSF#hFLy6VQ{!FOB&ZuwTg2 zAd@=F1P`tGnj|NkH*YhkZm1+7l3?I=|lJsym{!GQ_y$ML8n`L06x!<6(n;= z4$+;y<1-WN$*E#?l2(&V?MTwY{)#2wi{v?m)T@=AR$oJFOQ?k@W(t57hNS5IoZb-uXOyLp(!mB)&O`K>VWe4)F}} z&gbGAtQF$%&E1jqJ^Lx`d+IZ`@1LD-RJs!1{3GegB6Pie5M9;rI5t90k~d@nCwXI% z*ev3iCt}uUw3d7y_V4%cn=PdOwsRY-;K_@rm*f+zPyf;DQd)~XgLR@R&(?y5v@Rvy zq<$xxJNdl-ch{%8G>Qy6^-lj-Q|a|K(rA3e(yKlFv(xLhF?9|{uYY#l{ok-IjpY#< zV}EZRu|#;}{+Rw$WidTfewiQP7wYT(Y5NV0528b??EbsiaN_LGknQHQ5Sjl6(M6?4 z(&wPZ{~HIezx<8%8I=cO=b3*r4=juDz{b-<<>#|VQ{|_s-@FfXOJRPgg{ypjVmxygHZ4ez* znW@T$Pfqpo#}IvFa=*=ZIDO;-%B$;+;pW%Bx1C&_YZAauBx?^K{5|!N=OVP*7t=PC zUa!WXS5zPQ4D|BH)Hxiz{@Ho`UmM zV`S$J(tauGMqiOXcm@4F4cU>XUa}>@w#Mx+_(|GLM%cOsw@+;s*@wjYuHL3X*lMm; ze#fVjpANef?nJ>EDz@SmdAF@J^@+qc$N!q8tUGo7m_9SU7Uu-a~o%VqEI3YfwbQMq9J0Kln@ZQf7@ct{H z`=g~e?`55cqkpW@PiMYxuU!+r*UrH2d2-yU+-sMDyD}ZPuSsj2xE|*)yS?Ot^U|$8 z9nO9&hR--~t6YxzIx5j#H`+;U+y)r9FDBZ?Lc|-RZ8UUmgC9QGaq0dr-p0rsG6bhO z=3c03+zS=kX7z3sp4O|-fxmNGdJcRt6q_hd13s_AW=*(}{TOEtLpZnCy`OBzG4_5d z;(pls3746`=`NzVf{#bV#}9hpKEU;Z@fn5jq2fp7iT=%zd#Z-VQMspF7pE+ZUyRvJ zv?osQWAM)FA-nmGp?%rO2UE>#Ca?a(ub_Gw!GL z9%M-f{+eA6D0jD>hOD9c6vFAC%h%=OePW`;BFJaYyr=Pc{(i}l&7iiz65o1h^cS6?idux_4PyHRZw}#|^ zQ@NjP@Yv?}rQp8Ru3hdeU1)2Rrhrd0y_7D8?!Oe?O?NjF{u1sz(9TqF2meQLKLfc# z_ofgm@^M%16dMeWWPP@Q-^-5Q#ln4J@X3yMpO`Tfc6F6c_J7KKVyL4E=K?lPWx0)1 z#w_#x$Og_N8>o*ig60Lu_SR%6($^JpBOTRs61!yyzK{ z!Sqd?E&FcA?;`|p$J$=pHwO9!h%e!@(Hs0K&JW<;v2ohlR-MUSmj_>&kXMWGO=k;0 z9}D(47dX?h&Kw7SDrIU-nN4|%;qP(gKlwQUiyP?@(k3}mvl?+OfPZVl9ZiCgKGB(y zh4TbFUBa0J3Hzv%oO+(uwECJX%ahtHZQ@AF{JXS(C1p9jIKtwM+%eWQR^h9IF?TZ@ zgzQxB6+3dP%sF&cZn#XVQJi>;y^zCa{f zb{SbN(UHbS1I}3xJ(c^bK-0+mRfB121aHu9WDIxDi5?zg#?wY`J&-2Rp zj{wenVDH!8c_qA?kF7Vb--NlcIC{syNPfow#)bbl?!kHTIu>Y0n{h9VWywjpk2l}% z$YY^huo-v2*N)f0W&TL;o$|XRxaVnP5c^o#a@=m`Ctft+w^c28 zpNMqYlS?H&6en7`M2jUI@7Ez*OZh+-I;(OL_>BdAo!FCSva2GLrtHZRj=L^~ch><& z>We3^2Tpyl0(;=tC^Q7VB=EM@U+8bES{Kzr@`UQx_>t01s)O#|p>b9Pc}Dd$bc8pj zgWhQf^gGM&xhwe^&cZAf!Gj~ggE%MS!2C}<8_Tb@2w$qaNBsJ?@M^mgyjm-PSJN#) z$nyF35x*v79n!dPE{0`!aV|!iskH=Or*Si8S{KGv&0RW6&BLPEf&KCz&R|yKjEo}- zV+=fq-zN2&L0{9+n7KPf&O^p<9mXB;Q?cT13X=5_{Q2B;_Zi6xjA?f=+oQBUDXTgU zdL(qDb&&m##hym!NplnB-fGCWyD&F+Rhhh`2ARlZ@!zhI2O2z2*M;j#7QG z`oj{;Ke75lC*auV+!pp=mqU-hxY|JDX*%SJ9lAt)1=bId^V}Fy8>SBQ>D|ER?#Mjz z(djT~G{Qdu^Zq#SvpQ#+sD4^oMDh{OryvjHdPP3+(b*6REb@o@l-PeFPC-qh_jvc9 zspmN8duKM)f9>dv@W3(=!v4S;F1)V2x4SA=@n;S*Q)2JY)X-^&Pk_yyFpU_Qlr-A`~96F$}_pij88wpFPDY%ho(#+?<{ z0zU`UojE3JIp9nw)LE7kN_M)dL(;O$)F-d8lOI4`ui_tBH%3!y1z$=y!<||?#@-~P z*0h2D4#OAkTSDrB-&!ZHPsg1ce*zEKQqdnHfFFFjf(f#7Vd^#Z?s5I?5z(GHmQv#y zyKvQxT+k;4ZI&mkFVAFI_>FA475?Dq$TJsscWC8R@8bT4XxmxJf;SV`%(`2ky8%A- z?kelxHwj&}l76=uIzZ(+Vw%5ck@8!;2S>?H6P{_&q?r~XH-KbKRMR$f=L>;6THx(-NoJJh>14CUGtNnpazC`)pe}%Je$OpQ9OVBMK z9J^Pu5=m~Z&`xd2(;1s9Z1~;dGX-=Hh-9IDuzeA~!H#zc?dU3ij|P4}`28E1Q)@-r zF^}U+pQURm%c8a~xCQ43ac>IE?++t=EY5Z3V9ja+KM{|SF16UeoFeEu6MB)1cgQ*1 zX9{`9T8p2>-Tx=9PhUa$mP~EO^Q%-xs#F|=y`c=h%^pr-PWVsx)%uE1PY2RK3&URg zZqrZo8O3fr*6zr=du{7Y3vhSep0)dLg6`(jYFqE`F3^+&zbOZ(E}Y-<3%HN){5@ie zG)BrI`vZPw*PMnr!Sl}fsPiHCIp=6|i-UBJORnsc&>v-5NnZ-Q%A2ibT`P3;oAUyB23U;j`&XLwU#O+^i5_?gTE?UzhAUt7!QN@G*_a&FTUkdhjvf&~uyE zVge4`fPWJEw)>3m-vB<{n9rK=J^^+80=WD%!C34DKN0>>9E@v+#R2EiI1cgPPlCT1 z!GAwO6BQ4lg@Q+dzbQq*;~>qeXj>S%+;d0^&Otjfo9=JKJIyC1&5N_b#E+06Wpqvg zeXfQ4m<#z~#5kM_Ua!Zz!Q}>?!O?OFolWVYF?vPJ431_cT<(3q&kP(Rdm7nj;9Czp zC7Ii*$d)xCk?r|BGP5<4<$~`GL8Ah%8e^r)fPN&HMplAz-_X7AoAQEGW1G1y4`){O zUEs?<(;V_SWOH*G%dG|+-iD88zEReyHuy_2{2rAV^N?v9_6y6H2WKPvWHTgRcWNW& zW#~4rJ6M|FKe!2JRX0U`t79JO+!Xn(j%v`E@-KlOl?gJC=w}g9vbI5%5F9Pe=q$j~ zfiphu;vUF{rg8sQ+&9Z=37!#mgwT5z`rU?j5qudrz8>g)z;D9-@qEp84Pa6}>Vt!V zo1a_J;=B*WLyrw-gifRGcQKDreGG%i%oHgE_aFF$ad! za>;7BXOwc({_~o?S)2xu_IIE>ults$-m^h^tDnA~r;lLcu+W`~C;vSBor(oGze#5` zX>QMIR_68C-#eo@JRZ#0xtimP`J43B*x!V@+V8*Y0Z!pIhTnq{{L*uBz?aK%K@a~q z=m689OJkj0L-&bjZ^IqaRjp?w7v0O>dbX*S1TyKFckj)YNr(zh8ken7*!bkS$wlH=hOkFWO7whQ<=5Q>7I|X?H@K()T95ZD)4(2x8gTO zp2odjw_;t8n3q*OAHJ1B-ZT@|B7|qP3-!%q_UbK|E71n?oD6$)1q&R&I(IVolXU0X zaKFFGlTtExJd^vjZ!lv_8o}@CSXF;-#}!A0;!F>>H^z<=@V@8c|GN79Z%LZScqF^E zp8RK(^EAAkF>=TbJKK4TACh%N2#}RHCzx&Fdmz9~#+*$y7qWHI9qfI8XGA_4qaQ)e zoU<$TKD9oz9>tbJI4d%}0P|c2biBdk`t9ioUQN)696Q(MWeW-VI*q1=@VJ1v{dd4~ zJ#=9QGc3S8wl$ORPEYBmGA`;c2i%S^LC=*3lr)Z$w*MR(wTtA-U|f|p)10Z`+5w$N zX>$(Qn*6V$%`?zus{70FV8onVRQf4W4`e5AFaLdv;pjwn3-`lr{W!dbY-I0XE`{!= z&^f03)#PC<@C-L-j-Fb8GhrL)?he6%{VV_Jf=u(fVP+;db`g6#w3azFh3<`a9i#m& ztow1)U-ZEqcdVmMM`F^U(p%TRnM^9 z^F@qv((!R;g&n%^{%>IZ#<-_3H&-y!SSbz}Kx>laV=Gs+HxMrvYH;5%mz(A3vNL$9 zsRDON>PDap?&F+U%}mAAPO?#v-i&)S1GWir3GH=tz`jX(1NCR{MsB0sAc2<%r-zZB zbg~^TvPI)u8^)2!_ry!26H>m8xh&+WgFJ;^myI;_UXISEQ4VWBE-xbYa#)de888WU z4%UUdUce(9s6MhuT>u_b@6TRf_hSC&!P=#V+fkuMzleM%eygkzZ4=(!BH?WQiC2}i zp=mIF$WQfAU9Z7!-IWL&v4-m^XsReiJr_X-0ePU;>1Kjfw0=5qR#_vSxCVE-Lblrm z)oDdJwN9+psJ;@y$DI9Qo@tGgFF^M;v21+-`bvWC#h)IfZ_bI5B?mN8+e|c|cE`3^ zZSP08|L{Vw93o!5IGx`?bF7cfbxwdR!k*+?SaaYGtWW{gjyCAj9l(`zJ{fC9z8;6% zpt^`A)W@;?rt%y*!T(*{!EMg(Uso>0+KOOaN4$ddj2?4!wUDhR-dl&?p|I7j&l`_# zf5LiWxcZ5voG%Jk2!q@3srfK&pjR0RupUj&%a=MJdp@;H5erFxL-IB#y7MI97zAB- zImjt$vr1o89#$>yD}E0?@~~$Hp4B8Tco$>cK{`afHQ=shGd_5|%y(ffAH$Fv_$@&6 z4Xu+e<6d;Kb$)~==@}QwSm;fbtUsM?4Sa~b9qa`hBYkDO5x%|QrekzREu96Pl&ah6 zWg2}V=6xg12)wfZdV?SbNbbE~jI#{5Kei6{$C@6(IBC^*bmcX(&BouuCazuXdJy}6 zli8xh$Dy_TDfq+E`jzyMrI3~H zgO3QW?9sMYKZMQxy?m>g+D7>2P$fDF{=FB$^x%wptr4u&j6kuBK|U- zU1$%@Lt#7Q(UrR61z2y;S!PpWJUAkrTC-{vO$XcB3#Q78@@2zTH`@p=Jly@TJ7}iy) z4XX>~rbo&>tCqu>JQjwCa$_TT2IB!68g$Zh%O&VcDjwivj`LtV)Vv>3-Z*%Wy@%R5 z7!S1^_6Ih1Eu(c|MwZ@MZXx@E7CNNmi@Ej%g$pd*XbbU(d^?+Q8|W5Hru$<-bDYC1 zjl^M(GtjuX8Bf?*YTb8YeE@kRp`T0W8@(suyb!%(jRHn6oF*FKNxVh(o=(9#@fN*L z!h0C^y4h~W{^By?jo0=b6#99i12%3xwvo3GdC51!{a4%x3;menT;X5Cm7S#O3xDC&m+S zHD8asYhmk*9Tz{P^dh-r7d@e8{Dht(ht~T;rF?*o^_Stl)28hsI~>vG-{>1;RlINC z$2SRW(xNRow2Stnw3#{!m4hFQK_Yz#_29|dZ7zfz65lq^w>a%vN9p-;$v5d)AeZ2* zfkB#JH4|(d>MuyFqdewnR#g zmcN|QhhMFdK3Q*{tiIzeC5!q#UTde{7~}Q8 zc0Z2Z3x?tXxnwXE4Nb?sw!t)EXnHo%-$mbN;@Pel`dv@yxNC24o8b#=Xs5gR2GJr6 zS=*jAG#!UBIWJtqo>~}p#xUqGBp0mLV(!~sYVIn^Hv3;HGoP7YF#i>Kt9K}A%U@Q~ zx{&rKtjB_&b2u^<+M$~)NXMBz+~FHUIDElr$~UU{{AcH$%4TtU8Oyy1=5v zzJmp}Tbdh>Bmaw7+fu#lXTmdxulsp*C{O8GOTB z7E?!#{}A!dpnR*5uU*GHhlqy;eftW&(YObmydL*n&>v&>%ao3B%=Sjw{hE^g2+{|) z%}T$y`WSxi72h0>%g!(1iSf?sqr1_EYujDOcXuS8beZzS#~(J~0XRB#p$~u~*_H{% zj#m{Ny{{_iHzR#8j)l0FlIFHze53hnCZ55SGS`o2EXa|u&`SMcE0#a^{qE}hE3 zHl@bN4~XLe{V7>}pW5n7n3HZl4V@Eo0RKn}NKbU9%Ffed!e*GW+ zr0CdO=bfXsFUH#3jWyZ9YiR!V?`@3H2cXl`c3}P|Jor22a?-W=`^!yvq-*o{UpM8E zuFc8NQWnVUe)8@Ss({Um!~xg_+*9~d!nR=;~6-F-Jb_co*XApAN4?j#7eBOFG6aVz|L1nh-}vG2w2y6nR9LxhhILI^}_Y8SN! zyu!f43_Q*6y@XAL;deF|_Kny$1dMMs31J$-Yy?VUD6c^f1;!v>*b0Of5#B`TL&!k- zH3*XsrXYL^bl8s2g77-RFA&~D`17FmZzH||VGF|d5SkG#AQ0XZP&I_i(0CuxDA4!I zk@wg*@gniu;C9pg5YPjINLTg4H^CNQs898Ti*T+#{L5psZ*(5}FyH}x=f(xtsbl?8 zpM>8$`7N(3olmx-BjmF}_7%ME)LLhHy0I?%YxtRp*%*^`LR!r-jO{+uO}c_fXf1Ki zpE$b)dna^Xf@w_a?BFNinFo=#8nVKS-`oI6MxKEmTMF(mi7ij#elFI5HsM=&v302B zK*N!#Y;VPHP}j)Tmn+^!eN9-)c;OTFfySM;Psm>WEz~b#uLf=2nIMevjDkN~EDVx; zZf%O*CuHlI0LwhSJ3Bzzu$xX5D9jfvPx-d9e!IUmPSE*mu&qsaxgidwu^q_XK1_9qV0Ol z#XPa~(R`w`CoQHu^7BFA8(VDE!P&8J;K<^(9#S#+OTi!wtYs} z@L!3x9dq0NB<#nee!8DX)T|INUtJCUKZ^ER^tq)Lwzs#iuE)NlkNb}L_a02cd>*k~ zJ(lwSKdz7C_lMQK3J*)K^eC@>dstpgAHb{apMzH)GxX!|kM1+r3kJv+8v8U}mY^@_ zoB$@O&D{lMW*Y0{8$e_KG1&W0;9g84^uQCaVHzJv3}wk-|%=>Mkn+3=fInla42827}ty%FYZ+ktr&>*X0i{PtLZ%`_YO zkD(w!lfyWNMQ25Z^XvXs=noWz(`)}H(&ORK1Dq(t!Y7sH)BY$wl~eP@KM(U-^xk6V z14nZ9r+A<%9x?qy4$+<;zXurWRMKsZW6jn+7IQ1kdKt%YAEuqT(3$$M=ZkgbksF|M zIFRQc^3XYz{m27*4UfYn&CjkBBCR^=i=5rPtq6IL|6mgK72rb*-acZ3E~Vc6`y|Q} z4o>)ia6JonH6uUavm56ZDc>%CW*FnJ^2|Tl#z=R+SqWeiR!T5rrdSN=@F@i z_Sor+W)hxsmU28jMHV=XJL^tiZ+81hou?jYL_6Gcx!DMx-`zNGL-(1HpTc$6yC7dD z6Y`w2%Yn<-Q>4A1_fVeSQw!W)LLJXgy%VY496#yRwD(7Q-gN(NP-O7A!@Y)p{~h|R zTeORCtPh1NFJKRqcepl5;`gl~uNP-#gKsAKV*Ba$;1BBeFpU%R)t~TA{Y7hm5c-Q~PklD_l#buU#(f?@ zf9enFiv;YUQa`ADu>B%@Z*g9h?zilK-R!p?hc|;({M;Dz1L3TWiRsu^bw^4sIRDB`p{pe;ZsBX!}|sOL-eEmp+4@*#{KT-8~k2$=sNU|3o`W_`Xj8# z>+X!{Bf7&^#U&OGl~#oqZ$HCt>kY<d@MkP=inPZZ{ViGL9PPnj<$M*|Pj?m4Iofk}0cUD8KKLDku3$fM-*NK&7mfml z4cfvI&-M5XE&5$^6Z|2_pT!J2R8O*N4*BkN*_rdFTKI=Zxa$shn#RjtbAV3safa0& z4(~aHb6GZglLXyiZK&?}V(itP5gWJIwajx50({EhtI%A5u@LBL!*9AN{I-*RJCXX0 z(;+}-gXmlkvsfd0_(9lBv4QV#!SB?Y#O{Uf2!8L{br<`p1|Y=_g8~IjpWod`rE9(TOwP(r9M)LSMof zvLf6j^pOt@=YvAMhjdT)9)#cz6!-=5RtbH@Ch&-WbMDj@Gv19>=Aqv{gS;4UR{F~S z*WP!4HL-O4ZvZKZh=PbcpeP99QbfQOIw(ST>E-__-0+L_;+Idf)qclK=j$-Ey>m&Cs@ zs#khXDLi8?477#z0pB2?h_4**MHI{ElDZS(CHqKQ@$rPcX5>CNV!tTpR_CGE8rTm( z>~n+hATH}!(ujem-}6|bFG}h1NH^i-m;=aGpSbp8J-W|}aA>Ze5O}lz4+<;Kmrqr( z5y8F|tsP~s4l0HDRvE?Hbb{|%-Y=zszQMhpLU}vYRMfs;Xcy{RwD)c{w5JNbrAF`p z`-|GHqGyL}bK%oO$|u-+OT5#+8oqJnME*wKJ44^CN98vIF1VjE4AL#2&J;O{VJcC# zjuKHfnjap)UMJAO3K3i%AS`fSY<(u2pjX5`wkDsAO?{&R?;h!w(5%AX8e|E)$2<)1 zIH%ftg8L({49LCC$|XHhT~gtDpzy9WS}(&mhWEsjEkI9F4CePtMfgE>9>~x8VmOhm zHP^SsJ&T1Zz}p4x-=j7lzOVR|@j}H82C74*;Ik(DpD`n*fjf zZH=2iHQ0v>`T4f`%i#MvaQ_;83(dG$UrYBfJcH1d+_y%u`T*ln{2q5xAEUm2=Q$u| z@%V3h4J+;=LXIVJVmZRM6jA>m8wcwuk4AYuXu{JdPgRg7lxs_#7Nk5!L*H1#=?nRM z;G6>IR5-=*>s^QR3FOj-Y_&<*YSr0-O%8+i9#KE!!MXs+3cWXk-pe;r0@)6LJ+T3> z4u*YP!JykPCSbo1yeB{3piMgk_G8!@@I6e(S;w?d&Ma7iGk_P;l_&6Q1kLl(a!32> zk-Xcw4wC3=koY}W7{5Jt%z-gY)CKSRAk3(LPe}T=#4MEw^#O)LWpX^DZ%H8R(se$P zg5u zW?E;=G1gNM73{)c3%ueYS$u0Mn-d)r&Spw7u_J;)Sw>Vr7>gRjWb#;iK9w6n<;O(? zbHk|t0TU*8kr+f9;UA*)TOpBmdmz(u%!+8(=bHj5)@Y$8=J(ug`0xjj$_%=UHqV7ES|uRAIJBLfgU76 z#_)s%j@I>>V#dVNKO*_RfBuh3U=EXblG%vv6dA52sRC>sKu154hLhBXq+>`bVK5CQ zD|B#3x{#!{B*jT8$!{4-)=$zGA>wd3NxjJUaFXsN0y#qkn|Zzzmimq ztiKN#UPa>1CuuoJt4XRz)MdCp;`6JR|s5Aq3t$9zaz4COXJ{86ayB*dSFFr0u93xqQg&WTtA z#>7IvezCD&uxmkZ0!!@l_{vo7*a)|S>1vtbR}yRNF>8#D>4Uu-4gZ`-IvVrDd@+MI z;%y-Ztnn}lVz&Z@RaS`Qar`p3^ny-;i|9x%TfbyKpMOlL@A_@1aa`Yj2*qJz>bd-_ zeghUR9chzgvbKwtZu*5;JNIQVM=p0x?e)ejQFAC`@cChR58NKO?Pq=KulJ97wzl)S z__MvOT@DRgU}UkdVtK@MryhY_dQMnjKij+fowe!%daifpfOBrSp2_b<581JNxBrpk z8_`2;H_yJ`dEAY^69(Tan{&69rt|(|+rN}eGwoZm^}>S#Z~3R^B_dMe5w0+{%51*cYWN(gVh!-#cpbEsn zW6chbj*~TS1VB$kK@Yn^562O+mJ7_A!7z_S0cFB$$bz{u2EsgS7Ulwd9gUeo4YK%A zF+RaBypbOj_(=1hf>xlpxv36nBVVK$;zJhy0L%_Jhr>UFPyi*RImtrX9$rQ>e!quS zHva(35n3A#NYN^!qiALGqr#YM;`h5~W%F;X5AKAVn|e#Oj3s@CsI30$n0|=+wyDn6 z8X}8-Oa165dRhFau%49Gx3(nybF{MM(Of?|idHtipX*0Q(8}iDT0efS({R21FZH2q zdtpJ$Bx0?T)qgGZp<`&*tKuePD(*g!fZtG?gYC+XJ6 z=Kt^YN!%LQ_@(Vp$MvZ>`u6buJAIP$g>3vS?~k->0}6-3iEId~(PBvKgoMiC-!Xkc z8rD=tTb4-{|DWlPEcCMYbwpo&j#hSmwr_uAp_R?A<@|-PNzX1+ScU#fw(XD4-_ehj z+T9-hj?7=O+91(x+5CS;KM?x=3H@k7E1UnX>xWp@vhn`Re*9dvzos8H#Qn4|xR1$& zwG6s9%4lOnBO7mPeF!2sqOmE>vn@OEGkerhA3BCsc7L_D7r%p6Hvi`O&{4Fq`L(nc z9Yrgvzgn+H+QZmn7i95kYrgn7M(L3y)&N=jf2IGM(6%SfmiNnk2d!-W9q)f>w6gjA zdjE@MD_fo|=LZKE^Gw()z$Ko72*3`YXBlWzBTFN>;*g9}36;gaEqy@ONYXW+F(_R} zTXsPf|CajDQS`F-wYCSpgI0F`HP?rZqLt0Br9S)~TG{+t+lP)|Zm!EnM`X*p^?cFs zHZ<7{S^R%TKM;CZ{Qix8G@+Hv|JU_HENj_#o39^!N4D+tUu*r4%pd53$Z5lB z$i~}RADS$3xD?N}tOPqE!T%El*sJ=#%p?cr-Tr*tmVShg zHBf;gT4A)T@0R-UJ80XJx3qqA6s>H2E$zkcp_R?QwY}&FW{Fle>4Gm`tdV+*W7;mD%yk2Vf?Otub3b@@lfuL zfhp|hC65O2zS=;N7L!!{l{h|!N7u5M8=S&n*JoKHy7a+2bA$as>{ zN&ea-f7mnKCjTVhy$9Mr`zlTskrewT4%10mNK)*(I9{EUPcq3L_FfbGVgEHjCGv5v zyE=3%v?1lXIKF|T^c&)^h@==PKRQWiBz}E~d;-MzTgqP&u6iy`r@bKglC*)O^p|8j zNogd0ONo5q+vh*9Ygc*sZp0z~Ye!f4eqGU_s;aI&u&F5VQ-U7$qrVl`A4t+-lB&NW z<4Ia5p`?5&N&K*%z0LlW)KEq01%6kYFNLI4B&FRW<4GDw@-HI!(}UaRpK3p9cG`%g zwmG*CJiYX#_`s{~uY9MUm|}HpM!%ieiQ`vMrZ4D`wnM4%Iz$sgWLXqSK0 zQ*k=}OiWWqT18SC*}fE#R+0QaDvIqHyc5wbf9h*-dL&89NlJY~#*?&|q#}~PvNCBe z6WZrrTq91W){3c+q~#>V$@U2)?Yt_^r%m#Q_d43eFCz5^^fB8K#~@dRQ(fK zj-61M?y}YMP z_3@n+6wF|#P`(0f&x$hqXZPt&VGdepQcW~`ea(jHj{8if%m&iYy zls`Osvai+<#h?$okk_JEhgEbH`L1ru9nUBoDI7ieyUl`Sm80$!McHUo2y`w{Ub0y>Y;LwOeBOi1YH9$#b4xD75dsL&0g)wha}BeCLEQGe_zzt3U6OeSN|F z8v#3?#OYDyOgn2Z>5!Ac?lJME>@#vnnS^WcP@*nbXRsY zu+mY}J5r)_Z>LS-i{0@*G%k*;dr=VIu&{7q>cE8H;rziyiNO|f8&bB}tv$KZBWd63 zJG-~Pc9|j6w>xrc)zkyp*0c#3Ujt*JD;$pa^}L-wF@Bb$f0`+SB=SE&)y4Lz6)W;R zEM<~vlXQqAqXT+-?f>qfPU4kD=o8VMiNfHg0(K9=(HYwC9sR&CNg8}72djeUFh~m{ z(})cJ;XfXp_MRJc=k8!$JZ~dXEbDZ|QTrQ`=&!sF%;vzG*5ToPlRT%``Pq0(vM~1( zzXc613tN~QM>65PKqosdSM>5f9h?*xqgUFY4th^`r|$q69vs0zO)G|X{4&A89+77- zyfs!1ksv5zHZw>NG#K7Sgrh?2YuFga86hA*&WrJb2EWIm}=rcV|`b6oKlBCG&v;ViCj}lR*)L0WxMhD}ot9yk8y+Z#@r29KrDc zh42sEB8_+%x~T0mqR)$^c?#gQem1xy0G8!##xt-gi2rB`7=roGGC1gB2PYs^aoYkZ z#2bsqEdfflgfOazloyo5u+0#s*%W7n;tC;7O0MYDIdISeb)o(d%UXPa7)i>6$LBEy z<0dGd2;wS{+{AH29hF#$`XNX=2IqrPxdqja9z7C5Usi&zzzgzp>IumIprUhGa+zZ3 z!cw_qlJqo4kH+ZQ;42?{aG6L;lB5+unmmOLQ@rf5DHu+b#TR_ZsrScdm>!%D7G0$v zzTg8+8O4nv;&iKPDKza<6i8oLpNE!a$Tk_G@*ssF5JoyQhzz@6xblPfVt%#2Z*hz8aKQ5laEyA8H z!mi+2s0Z+LL42j^UP8vhYq!nf?OK!CnyDb0 zk3GoR8evFn!W9O6kDNEOrHh>~nz91$udXJ1pDRQEV$(31HjStg>CTX^NXOt3mg-5w zHS#6mp(i+~n`f))csb32+}_4{HN6Daa0un?%F5r*l> z2T_o30TF~FVKyoTiu?@B?(|fF3VsIeK)4ua1JJxNfW0g5vj^u!K#~6e94PWXumKCC z;DKUV4wR1KgT#~`3_b%O+(6P~7$^@qu@#Yjf=Gx*J_>|Di@=d*3Q**);3=g>K9G-L z*${^N7TA82FABp>0Y&}`t^!3q461=5rvqPsB3}lYYLFlN84N}gd>WVoMSczJfd&f2 z`H_DEl)q>J*kQS+3dq-i7o_7$Kt4d}sTdXuR3H2wxL`pPgcd;I?)0r>t$1Ki4i@B6{`K`EFI@>whbm8g~1 z-%$o>$bT~O`BhB%&6La+7_1c~M>zN%pQv#0Q6Ho`N98tjSTVC>GN* zlFf1DGT=Uifr1NnDvvE-Iq-N~o+~$$a1IAwlj$@m!ZwN>&YZ*ycjWTixEwmTd}GqN z+;D8YqI+=ayjx?1n&(9gGWmQ#h62^ z1Ob9Nl`RPK3JS%ZLp&-e9T!D$i1m(QGwld}bQo3wEuIttFD$?6%7fXko7F%h{4U? z#naf+*AoM`yN)rDe8+HZj18a9Ww1f@NH2gm%*!avg@arJ0-zW!ZC6+Y|7?wcH0DRtod;~1WaZHLYjE$He9+PAkOYrmJ z1#$R63;`6e<3>cV1yF`VqC;LYK&LV+iXM}ja$ zsSysGP&S9<9?9b1*kK}nt3Ck~r={wFc8gJnhZdwV2u>0?H*aYSktQWGTR;JInG^Aj z>~H|oyhMK@g+$#f=^#oWw84WF!HsTG1=uZz+9FkpO)!@S;>#jRki0y|_5$1a@9N4gOb6FG|!&Jh@c+dp*eI+YnBA~hbQ$qsZN#f6w2B0N6b!|uz%O(!(O#;CS_r4eH$|Y;&Ttcf z13D2Vb116^ekG~!*9`vZlin@SPE_=+ybH#J>lZ!9XMlCZIyW*(kw>>Ur+`G zdB86h@TchpVHf!82*1&BOyMQmZAZ0AZbXRbc!*JfQvv=Vc#3dJjt0m=0e%8_QwDjh z2_=1Np|@r@;1`Pv8P5}WkPX1$dJIup_=~=grwC=yJ9iP#k|4+*2WWx_j{=ClE&N7a z2H-LkZeyd*&5HN=un51Re6T~PPP7M?4Lpcj=$IFV_S{k1*n3F@$sw8| zwI7sq1>T`VDb!1mkcK1|O0*T8leCJXf+tt1RKFpa?tiET^bpCjIj@#dmBGK8oS~EG8$1;fa0sD5?xw?7a9xSBjFH zD6wxQM5W77C??(Tu8Jywi=8Pfc?CI2Ck*#f>};q=QJ^G_lA|by+;CUCmsCtQTt%LO zi4-#B;JJ}Wi?RyTr2MB`hk)mqo8F}_Q0~#S=+!N^qw%*7iqh-LQuEns= z{qaOO6_LCgMNUq=%O7@v+2+m%ol5`waIIVzfU78WGE|e7>knA^n)HU+<-HZ;HPj^z zskssQUU0QwfDh=^)zl0(GZ|@WW-|7QBT+Y&DpM`^2p4ey;h{L_F8`WBg(ar3Ry3Q z{>_eb@zZ~^9XtBIx88v@XVgC1Pty;q@4sX5{08~8K_de*&R#upZOdkbU1isAuJ6C% z=(&L1yOlx@?$em>|NVI7)q%;=%jfINxSUI=9pH3#Yp3nJ$QiT+LjQi1K7DU&ech>F zWz~?{1+ko`n!R879~$neJKLo< zv(*->w|&-N+qZD9!)M{@ZMrElT)r4hzN&sS^wp*w=R7Ob{L8NNvvznpIJfkX{f%S# zS9eygDi1gr|NZ95WnaekP)ba5$0t$bpqD9GES!OBfc*RGDX8L|6_r6TI(1T#m&aXE zBt^jiw-c(H#D`hL8%KMRW(Z5~MC$`t)&;3*pn}NHE)pTyVz>~8+WJF9~fi3)9=!NEma1ZFAr#&Ul)cCu+!w) zJ$YnS*5^{_v7E_QDAq37rjH7YlG-Q$$( z?&5AV){uF<4-X1<8Skl_9o4Ovv0;1PoC|U`UpLP3NL!$P>*)Li3*Q9#4<6HXqxOgQ zqugSJ5hK<;mkZrc{ruZxP0VQBK9Ra_z1{|Q*2WV{^&K6uL;UItW@_V!omSw93Q^<$ zQQM^b=cn@FH7{?|A1c$dr%CIrDhv{qNf#J1Fh~?N!6Hz>HvhQL~_26;^R684DxS8UX zFzAT`4L1`L6WmHN+=Blt3>|!+7>0Hu3@=_3T;DUr7@W+(YP24;a%j}b!Kjs^V8@@N z@WbvMsrH{R2G_;eX7wkw=^2;ljD5Yd()YvzgKcAdc1CZ!kRRW7Vb@dmz&CxfEw$>V zoLL{yf9Kw~*XO!dR0mw|G{&Qw$G|h`J#!NN-nxCNmajLjAZ&HyiM@xTHq7LkuDPsk zuWo!l@r}~LCxX!tvmXvu?fZgyt&G~AVKDq+{S3F#)gN_&HksFTIy0kwdY_|pWtT4O zGN%RXnG^CNrqnqvWa`wdUOs=S8Xj`rhToj>;#|D{qupihGaiquG5P1#>KS+bTq(SD zFg1;q5_dB8?7=;!4$RcHlviI-d398_ai>3$-zAPyPmSE^ooHivjv5sxo`@4cRC-cW>f=8Z}1#ldCURt+GxZdk3p_&|7kFqkV6~gyJ>( zD}o~G%x<2(KT!cY|3|;ICs%&Z*}J#?HVm$gYDnQTOKT3Rp3|?C2Gn z?mebIR;SmQoIc0X(p9-X*EMQ9qh2TA6m{|}?w*~Cm${#~?hvqr`ZZ&~>Ee}{dlEVi z+3>EKJtD3D@OL-2@9qD%uh?oOQmny_Tj1T0kV+QG}X;mV##ejYo+U zv;CQ__l-lx*BnmE@7K+pP{00z6trpQxQ&$E+bB98UZe5)~G&WPcMEMLC;A^huO#)sFudxMX9$d|g654-ny_>@bZ-hSAH z&)K+a?~JRLF5B5}veT(s$IEcuzu})P?%NdQHDZR^U#*!}>zmhbd_JGw5T#MyrG^+{!(7o4R6T zU_Uwef2f7Kd_-zA#_2TOlD)p~yk}h+x-&fbB6ra6w+XXn4w|L=qeqd~@SzEn);Ajt zCawE6{j%RK?UR$X@()qAZ=JehhW^99*5HYX`CyROkp@}GV$`9*UUMs*c74+i88&0O zw8*-ELH^&cglO?&ikra#sL>jaf}p9y8Z(+(<6d}A=xLY~)Fet}gk}X}lhL>pN|4tu zl_XFlM%T%l>fvc)j$2t!J)Lb#M_N$5*b(rgASeQ!#)P6N;b-Rf%;J%XF8fNx@?0i+ zpVgB;^*VLb_Vtr9u2(F$obH+#Au2q-;M27C-81Za+6H7NzX|*N$D7Sdy3E@$Fuj}E zK)ObkA^dd_AE)NY{qfCi|H50{U-9?sdtoSCxKvmBe%-CHr+UrX+1qfO?VZp+pG_Xy zaDB?v8vWsQSN0r;su`%rTCv99%FTNA{hKLCj#&I{dz&S9=FXftr(smwR{vf9)GlQ1 z_jn!c^dV?L@4Er}y}IaxaYpGJq3sITdvC%Y7vEX+2z{xR!w9d=J>CC;MOVLTPx|JS zFa@-2#k|vp-3IPC;4>-i`;C?S)w_(W9_Bb-Zzwd;*gn-@-B9CqNx3WCqI-G|iA)F?^h>HjP?c_HWE|Zo~D~zU&j5Ex8;}Cds&>rg z7<7dBh*6dMVBGr?g1zGhs6^NA^mmMU7?|awLea<67J9w7_|(622HxYCWBP$B(SKE_ z&Dx+^VYdIm9*H^j2XpL;_dvFWFvnnQz=*niVqDuZ)8x28M%u}oFw%CY#RC<< zMB`whMdpi5C46KW>6T2waVla$Re%d2Tv<^ubiOJ@K@RUCzGhqeEnJDx!u-gih0q_q ze-^Jk$W7aBuS-b?xn8Mb`=C(USbdVlCEWAkaqTZ>>HZHV8hnXd+I5Ek`zyQTQh%kV z;{r=7yFB)rej_63^Fpegxk>1SgFV)9Ptje2`>QG^=4l<@-@lG*c zcmmBEKX$q=HJYLq*-Szm}@}tZlN#U!GZJAph*?I2EyrWU> zho^nmuD;j*=?{IcB@Ne>&W>i?I^V#{8uYn%Xrg`ohM|3T4jwS1TF5L%-J{3Xb4qK9o%{$DQWN#_bivcVnR}1@isr5 zDCes}jt&qX$jI-Z8zr)s$m{Sp|e zl@W6Iu6MDu!Q#R+k>T^THixXQ^-MF_AFR@?^Rf9iHNGFuzWiqD&7%sR6YrVcS6I>j zyY)_dDjzft>rx#pH{@mmE7~^KAW6l^@X5SB*^9b;O=FXaSpO@t zg?P%cGL^c3fGY^o#_M&*=2KR8V*LhFma=4KYU@G;O-Xz-B~eXrQ&Z}2AU~UxF4gA@ zu|Bi?^{gW+O1f^mol&c~NMP1y$gc8!-U9|$L>yh^ts3-pi%QJcp6irH%wlGLQ(T~R zBXyN!KNGoiUwC`gTYDFn)dwwonyY_1h2eK>iD#Ad@a0Li`9rd+kHp6QHAm~glrzPL znVv_6Y1Po3k0i5Ilh3^RyK2NAqxYQiTtQnfpynT*i~ayt;ebU`Y8E|z9dvYuwbCE& zcXA$w+O8>c!WWO<*?ga6*Vqhj;H5AK}UQ~Kkx`gNl#jykM-b7by; z0k>j(`dih0bWK%XmoVwU-4nZW5)@P)d$CJ`cLGTtT9;j z#3q}yrr784V`GDq+(SXk&o`;z+LHqh=g#k@qUZVQ_~@rQmDFY`Sq1klyS`|i#?2LR zmx52%KZyV9e5i)f#**0QXOc?`Ii_)EyZA0xapuK4qq*^a{=;1IYR{>n8qXO4-W7lJ zHt>~q`|SVBf!}Xo!i|d$uUf}QW~F5?DY!8y@KQV!-sR|%dD%!xmPBxq|6^WHJ6 z&l|@#u~SFkU!xwmUtcun)z?pJtv2aB`M_J6b~5HF^J~v97AIUL8^tCwyj2{nu&?Z^ z=QbI9$r@i=hHcX5UzoP!PVDOoa~ECk+)@zyFeoHTbC^TYgfv@2`q#b((v@+Q&(*_k zs4R*5r1B*B;vapBW@c_G@eEX{%_`b*WB0&*MfGVm4e!;2U#frH-=e;)4m%t$VPzj{ zkNwY%tGM(WY2mxEn^(o&zVi}hsO*mRS}KS*SJ5fdFuLwX+TI~+Eqf>1Yd-Gmn>njS zcbvUW#rS^3o1V{g-dnj!HPwAg$eIFwInTQEhw0T<1}>&BH)AKBP7_3R9s3|I`FKCd z`m)}Ggf}dv1+3HB!%#irNE?08f8KHxTIL-^a;^sCd-O1B-hV=_$A1TZGI~g(Z^eop?D#lyidi?nPlTCLLjL!e);NWC`X~-Big;C*v3ud<~OxPb8&U4o7k!*Xl(ax zywFvVH&K;JR>1p7g}Ruifl+9>C*Bhu(Ns{uL|1{@D{Qp7`Jc5~N77<#DvO*<+01`V zJv-7zVc_WO;^cg_SZU>k8_f!dup84bs@i~}Jpan+H_H7kh5y*};OnZ`_f}#1OEu|6 zrz3hC)v#AubKu9vQyTT(lGer+QEu&-KJUZ&#e0t}Nlm)3v*Gi_x9XGZW~TbT>N$8; zy_x*n@l+l69Tw4ea^C5Y=K@xKOpKUll1l06oL2GFe1|y`^-$S`i8h1hA5n-K!_U;hH+`8g zGtb0)y>4%VZ}ydcJzd0$!LE4T?H07R+|D8AVecrzZ_8d9Ii{%eiZ)zx`|nxuNy5VK zrWqyX-~a9rJoTxQY1i3bFV5XO1~)M{IlyDt^ooo`c`7^y=+`7kMUzDNt`Mbyx;y57 zWkn*V-qyNE>RE`0jcYd{lsAD@x8xZL1$0CbQ0ZjSjeHhi0axR2Nj|NWjtmzaU3j*n zmz$NZ?p_s>4+T0dmQ7J7xpRP9ols~p+;mjX3X&D8>2tZUA^qm-kj0PDzk!8;;oG4(XE%erDff@a0;s~>>Ti@ zcfiKz2lRg~PQ0G`sYHQ3`Qj}qNyL#?}Vb|WJ1wRoQvHAoZvwht4%QVBG z^_}9qn3c~K@7?q8jF#M#F4#g{|Eln%C0DxqP`PzWJ1O=h?Wqd$L{ycL+s!4h4_s2y z&Tf3PV_!+hqzQDR}>D&l8t>;<%U1Ic)rFvs4I2P8}`j* zLq;wQomFaMeMoPi$HjynzQ^lE2oJa|sa`w(T!V(qWHpmYYv#_|I&11q=TpkwuXo*Z zEPYN{nTTHZc)4Xa(br>NO_Rpm9zAZr;c01SeWR1E9QKLcQ!~fMXH@;<;`o6tZ$)LR z**^_xFje_HmcckaVCQAd&0dT9%n9+Ro!1(tys5X0N3~N^=b6coaudL$;a+~H2kR&Hr8jr5uMBxA7W0f zu|2pX^z9bGNuBs5m2>($alLEEUU$dAL~|~^|DPjn4;jTNQ-3k&cKNB0io|@4+P9B9 zV~%QO4t5w_?taPVS#hQP$nul +echo setting testsigning on +bcdedit /set {current} testsigning on +echo replacing WinDivert64.sys with unsigned ARM64 version +copy WinDivert64.sys ..\zapret-winws +copy WinDivert64.sys ..\blockcheck\zapret\nfq +copy WinDivert64.sys ..\blockcheck\zapret2\nfq2 +echo copying ip2net and mdig +copy ip2net.exe ..\blockcheck\zapret\ip2net +copy ip2net.exe ..\blockcheck\zapret2\ip2net +copy mdig.exe ..\blockcheck\zapret\mdig +copy mdig.exe ..\blockcheck\zapret2\mdig +echo DONE. now reboot if testsigning was not enabled earlier. + +:ex +pause diff --git a/arm64/ip2net.exe b/arm64/ip2net.exe new file mode 100644 index 0000000000000000000000000000000000000000..3e366ed2e64f19a667e52117f2c325100d2425be GIT binary patch literal 23552 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 literal 0 HcmV?d00001 diff --git a/blockcheck/blockcheck-kyber.cmd b/blockcheck/blockcheck-kyber.cmd new file mode 100644 index 0000000..0705b9e --- /dev/null +++ b/blockcheck/blockcheck-kyber.cmd @@ -0,0 +1,8 @@ +@echo off + +cd /d "%~dp0" +FOR /F "tokens=* USEBACKQ" %%F IN (`..\cygwin\bin\cygpath -C OEM -a -m zapret\blog_kyber.sh`) DO ( +SET P='%%F' +) + +"%~dp0..\tools\elevator" ..\cygwin\bin\bash -i "%P%" diff --git a/blockcheck/blockcheck.cmd b/blockcheck/blockcheck.cmd new file mode 100644 index 0000000..44c26dd --- /dev/null +++ b/blockcheck/blockcheck.cmd @@ -0,0 +1,8 @@ +@echo off + +cd /d "%~dp0" +FOR /F "tokens=* USEBACKQ" %%F IN (`..\cygwin\bin\cygpath -C OEM -a -m zapret\blog.sh`) DO ( +SET P='%%F' +) + +"%~dp0..\tools\elevator" ..\cygwin\bin\bash -i "%P%" diff --git a/blockcheck/blockcheck2-kyber.cmd b/blockcheck/blockcheck2-kyber.cmd new file mode 100644 index 0000000..9448d74 --- /dev/null +++ b/blockcheck/blockcheck2-kyber.cmd @@ -0,0 +1,8 @@ +@echo off + +cd /d "%~dp0" +FOR /F "tokens=* USEBACKQ" %%F IN (`..\cygwin\bin\cygpath -C OEM -a -m zapret2\blog_kyber.sh`) DO ( +SET P='%%F' +) + +"%~dp0..\tools\elevator" ..\cygwin\bin\bash -i "%P%" diff --git a/blockcheck/blockcheck2.cmd b/blockcheck/blockcheck2.cmd new file mode 100644 index 0000000..96aaf4e --- /dev/null +++ b/blockcheck/blockcheck2.cmd @@ -0,0 +1,8 @@ +@echo off + +cd /d "%~dp0" +FOR /F "tokens=* USEBACKQ" %%F IN (`..\cygwin\bin\cygpath -C OEM -a -m zapret2\blog.sh`) DO ( +SET P='%%F' +) + +"%~dp0..\tools\elevator" ..\cygwin\bin\bash -i "%P%" diff --git a/blockcheck/zapret/blockcheck.sh b/blockcheck/zapret/blockcheck.sh new file mode 100644 index 0000000..e7025e3 --- /dev/null +++ b/blockcheck/zapret/blockcheck.sh @@ -0,0 +1,2349 @@ +#!/bin/sh + +EXEDIR="$(dirname "$0")" +EXEDIR="$(cd "$EXEDIR"; pwd)" +ZAPRET_BASE=${ZAPRET_BASE:-"$EXEDIR"} +ZAPRET_RW=${ZAPRET_RW:-"$ZAPRET_BASE"} +ZAPRET_CONFIG=${ZAPRET_CONFIG:-"$ZAPRET_RW/config"} +ZAPRET_CONFIG_DEFAULT="$ZAPRET_BASE/config.default" + +CURL=${CURL:-curl} + +[ -f "$ZAPRET_CONFIG" ] || { + [ -f "$ZAPRET_CONFIG_DEFAULT" ] && { + ZAPRET_CONFIG_DIR="$(dirname "$ZAPRET_CONFIG")" + [ -d "$ZAPRET_CONFIG_DIR" ] || mkdir -p "$ZAPRET_CONFIG_DIR" + cp "$ZAPRET_CONFIG_DEFAULT" "$ZAPRET_CONFIG" + } +} +[ -f "$ZAPRET_CONFIG" ] && . "$ZAPRET_CONFIG" +. "$ZAPRET_BASE/common/base.sh" +. "$ZAPRET_BASE/common/dialog.sh" +. "$ZAPRET_BASE/common/elevate.sh" +. "$ZAPRET_BASE/common/fwtype.sh" +. "$ZAPRET_BASE/common/virt.sh" + +DOMAINS_DEFAULT=${DOMAINS_DEFAULT:-rutracker.org} +QNUM=${QNUM:-59780} +SOCKS_PORT=${SOCKS_PORT:-1993} +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 +IPFW_RULE_NUM=${IPFW_RULE_NUM:-1} +IPFW_DIVERT_PORT=${IPFW_DIVERT_PORT:-59780} +CURL_MAX_TIME=${CURL_MAX_TIME:-2} +CURL_MAX_TIME_QUIC=${CURL_MAX_TIME_QUIC:-$CURL_MAX_TIME} +CURL_MAX_TIME_DOH=${CURL_MAX_TIME_DOH:-2} +MIN_TTL=${MIN_TTL:-1} +MAX_TTL=${MAX_TTL:-12} +MIN_AUTOTTL_DELTA=${MIN_AUTOTTL_DELTA:-1} +MAX_AUTOTTL_DELTA=${MAX_AUTOTTL_DELTA:-5} +USER_AGENT=${USER_AGENT:-Mozilla} +HTTP_PORT=${HTTP_PORT:-80} +HTTPS_PORT=${HTTPS_PORT:-443} +QUIC_PORT=${QUIC_PORT:-443} +UNBLOCKED_DOM=${UNBLOCKED_DOM:-iana.org} +PARALLEL_OUT=/tmp/zapret_parallel +SIM_SUCCESS_RATE=${SIM_SUCCESS_RATE:-10} + +HDRTEMP=/tmp/zapret-hdr + +NFT_TABLE=blockcheck + +DNSCHECK_DNS=${DNSCHECK_DNS:-8.8.8.8 1.1.1.1 77.88.8.1} +DNSCHECK_DOM=${DNSCHECK_DOM:-pornhub.com ej.ru rutracker.org www.torproject.org bbc.com} +DOH_SERVERS=${DOH_SERVERS:-"https://cloudflare-dns.com/dns-query https://dns.google/dns-query https://dns.quad9.net/dns-query https://dns.adguard.com/dns-query https://common.dot.dns.yandex.net/dns-query"} +DNSCHECK_DIG1=/tmp/dig1.txt +DNSCHECK_DIG2=/tmp/dig2.txt +DNSCHECK_DIGS=/tmp/digs.txt + +IPSET_FILE=/tmp/blockcheck_ipset.txt + +unset PF_STATUS +PF_RULES_SAVE=/tmp/pf-zapret-save.conf + +unset ALL_PROXY + +killwait() +{ + # $1 - signal (-9, -2, ...) + # $2 - pid + kill $1 $2 + # suppress job kill message + wait $2 2>/dev/null +} + +exitp() +{ + local A + + [ "$BATCH" = 1 ] || { + echo + echo press enter to continue + read A + } + exit $1 +} + +pf_is_avail() +{ + [ -c /dev/pf ] +} +pf_status() +{ + pfctl -qsi | sed -nre "s/^Status: ([^ ]+).*$/\1/p" +} +pf_is_enabled() +{ + [ "$(pf_status)" = Enabled ] +} +pf_save() +{ + PF_STATUS=0 + pf_is_enabled && PF_STATUS=1 + [ "$UNAME" = "OpenBSD" ] && pfctl -sr >"$PF_RULES_SAVE" +} +pf_restore() +{ + [ -n "$PF_STATUS" ] || return + case "$UNAME" in + OpenBSD) + if [ -f "$PF_RULES_SAVE" ]; then + pfctl -qf "$PF_RULES_SAVE" + else + echo | pfctl -qf - + fi + ;; + Darwin) + # it's not possible to save all rules in the right order. hard to reorder. if not ordered pf will refuse to load conf. + pfctl -qf /etc/pf.conf + ;; + esac + if [ "$PF_STATUS" = 1 ]; then + pfctl -qe + else + pfctl -qd + fi +} +pf_clean() +{ + rm -f "$PF_RULES_SAVE" +} +opf_dvtws_anchor() +{ + # $1 - tcp/udp + # $2 - port + # $3 - ip list + local iplist family=inet + [ "$IPV" = 6 ] && family=inet6 + make_comma_list iplist "$3" + echo "set reassemble no" + [ "$1" = tcp ] && echo "pass in quick $family proto $1 from {$iplist} port $2 flags SA/SA divert-packet port $IPFW_DIVERT_PORT no state" + echo "pass in quick $family proto $1 from {$iplist} port $2 no state" + echo "pass out quick $family proto $1 to {$iplist} port $2 divert-packet port $IPFW_DIVERT_PORT no state" + echo "pass" +} +opf_prepare_dvtws() +{ + # $1 - tcp/udp + # $2 - port + # $3 - ip list + opf_dvtws_anchor $1 $2 "$3" | pfctl -qf - + pfctl -qe +} + +cleanup() +{ + case "$UNAME" in + OpenBSD) + pf_clean + ;; + esac +} + +IPT() +{ + $IPTABLES -C "$@" >/dev/null 2>/dev/null || $IPTABLES -I "$@" +} +IPT_DEL() +{ + $IPTABLES -C "$@" >/dev/null 2>/dev/null && $IPTABLES -D "$@" +} +IPT_ADD_DEL() +{ + on_off_function IPT IPT_DEL "$@" +} +IPFW_ADD() +{ + ipfw -qf add $IPFW_RULE_NUM "$@" +} +IPFW_DEL() +{ + ipfw -qf delete $IPFW_RULE_NUM 2>/dev/null +} +ipt6_has_raw() +{ + ip6tables -nL -t raw >/dev/null 2>/dev/null +} +ipt6_has_frag() +{ + ip6tables -A OUTPUT -m frag 2>/dev/null || return 1 + ip6tables -D OUTPUT -m frag 2>/dev/null +} +ipt_has_nfq() +{ + # cannot just check /proc/net/ip_tables_targets because of iptables-nft or modules not loaded yet + iptables -A OUTPUT -t mangle -p 255 -j NFQUEUE --queue-num $QNUM --queue-bypass 2>/dev/null || return 1 + iptables -D OUTPUT -t mangle -p 255 -j NFQUEUE --queue-num $QNUM --queue-bypass 2>/dev/null + return 0 +} +nft_has_nfq() +{ + local res=1 + nft delete table ${NFT_TABLE}_test 2>/dev/null + nft add table ${NFT_TABLE}_test 2>/dev/null && { + nft add chain ${NFT_TABLE}_test test + nft add rule ${NFT_TABLE}_test test queue num $QNUM bypass 2>/dev/null && res=0 + nft delete table ${NFT_TABLE}_test + } + return $res +} + +doh_resolve() +{ + # $1 - ip version 4/6 + # $2 - hostname + # $3 - doh server URL. use $DOH_SERVER if empty + "$MDIG" --family=$1 --dns-make-query=$2 | "$CURL" --max-time $CURL_MAX_TIME_DOH -s --data-binary @- -H "Content-Type: application/dns-message" "${3:-$DOH_SERVER}" | "$MDIG" --dns-parse-query +} +doh_find_working() +{ + local doh + + [ -n "$DOH_SERVER" ] && return 0 + echo "* searching working DoH server" + DOH_SERVER= + for doh in $DOH_SERVERS; do + echo -n "$doh : " + if doh_resolve 4 iana.org $doh >/dev/null 2>/dev/null; then + echo OK + DOH_SERVER="$doh" + return 0 + else + echo FAIL + fi + done + echo all DoH servers failed + return 1 +} + +mdig_vars() +{ + # $1 - ip version 4/6 + # $2 - hostname + + hostvar=$(echo $2 | sed -e 's/[\./?&#@%*$^:~=!()+-]/_/g') + cachevar=DNSCACHE_${hostvar}_$1 + countvar=${cachevar}_COUNT + eval count=\$${countvar} +} +mdig_cache() +{ + # $1 - ip version 4/6 + # $2 - hostname + local hostvar cachevar countvar count ip ips + mdig_vars "$@" + [ -n "$count" ] || { + # windows version of mdig outputs 0D0A line ending. remove 0D. + if [ "$SECURE_DNS" = 1 ]; then + ips="$(echo $2 | doh_resolve $1 $2 | tr -d '\r' | xargs)" + else + ips="$(echo $2 | "$MDIG" --family=$1 | tr -d '\r' | xargs)" + fi + [ -n "$ips" ] || return 1 + count=0 + for ip in $ips; do + eval ${cachevar}_$count=$ip + count=$(($count+1)) + done + eval $countvar=$count + } + return 0 +} +mdig_resolve() +{ + # $1 - ip version 4/6 + # $2 - var to receive result + # $3 - hostname, possibly with uri : rutracker.org/xxx/xxxx + local hostvar cachevar countvar count n sdom + + split_by_separator "$3" / sdom + mdig_vars "$1" "$sdom" + if [ -n "$count" ]; then + n=$(random 0 $(($count-1))) + eval $2=\$${cachevar}_$n + return 0 + else + mdig_cache "$1" "$sdom" && mdig_resolve "$1" "$2" "$sdom" + fi +} +mdig_resolve_all() +{ + # $1 - ip version 4/6 + # $2 - var to receive result + # $3 - hostname + + local hostvar cachevar countvar count ip__ ips__ n sdom + + split_by_separator "$3" / sdom + mdig_vars "$1" "$sdom" + if [ -n "$count" ]; then + n=0 + while [ "$n" -le $count ]; do + eval ip__=\$${cachevar}_$n + if [ -n "$ips__" ]; then + ips__="$ips__ $ip__" + else + ips__="$ip__" + fi + n=$(($n + 1)) + done + eval $2="\$ips__" + return 0 + else + mdig_cache "$1" "$sdom" && mdig_resolve_all "$1" "$2" "$sdom" + fi +} + +netcat_setup() +{ + [ -n "$NCAT" ] || { + if exists ncat; then + NCAT=ncat + elif exists nc; then + # busybox netcat does not support any required options + is_linked_to_busybox nc && return 1 + NCAT=nc + else + return 1 + fi + } + return 0 + +} +netcat_test() +{ + # $1 - ip + # $2 - port + local cmd + netcat_setup && { + cmd="$NCAT -z -w 2 $1 $2" + echo $cmd + $cmd 2>&1 + } +} + +tpws_can_fix_seg() +{ + # fix-seg requires kernel 4.6+ + "$TPWS" --port 1 --dry-run --fix-seg >/dev/null 2>/dev/null +} + +check_system() +{ + echo \* checking system + + UNAME=$(uname) + SUBSYS= + FIX_SEG= + local s + + # can be passed FWTYPE=iptables to override default nftables preference + case "$UNAME" in + Linux) + PKTWS="$NFQWS" + PKTWSD=nfqws + if [ -x "$TPWS" ] ; then + if tpws_can_fix_seg ; then + echo tpws supports --fix-seg on this system + FIX_SEG='--fix-seg' + else + echo tpws does not support --fix-seg on this system + fi + fi + linux_fwtype + [ "$FWTYPE" = iptables -o "$FWTYPE" = nftables ] || { + echo firewall type $FWTYPE not supported in $UNAME + exitp 5 + } + ;; + FreeBSD) + PKTWS="$DVTWS" + PKTWSD=dvtws + FWTYPE=ipfw + [ -f /etc/platform ] && read SUBSYS /dev/null + ;; + *) + echo $UNAME not supported + exitp 5 + esac + echo $UNAME${SUBSYS:+/$SUBSYS} detected + echo -n 'kernel: ' + if [ -f "/proc/version" ]; then + cat /proc/version + else + uname -a + fi + [ -f /etc/os-release ] && { + . /etc/os-release + [ -n "$PRETTY_NAME" ] && echo "distro: $PRETTY_NAME" + [ -n "$OPENWRT_RELEASE" ] && echo "openwrt release: $OPENWRT_RELEASE" + [ -n "$OPENWRT_BOARD" ] && echo "openwrt board: $OPENWRT_BOARD" + [ -n "$OPENWRT_ARCH" ] && echo "openwrt arch: $OPENWRT_ARCH" + } + echo firewall type is $FWTYPE + echo CURL=$CURL + "$CURL" --version +} + +zp_already_running() +{ + case "$UNAME" in + CYGWIN) + win_process_exists $PKTWSD || win_process_exists goodbyedpi + ;; + *) + process_exists $PKTWSD || process_exists tpws + esac +} +check_already() +{ + echo \* checking already running DPI bypass processes + if zp_already_running; then + echo "!!! WARNING. some dpi bypass processes already running !!!" + echo "!!! WARNING. blockcheck requires all DPI bypass methods disabled !!!" + echo "!!! WARNING. pls stop all dpi bypass instances that may interfere with blockcheck !!!" + fi +} + +freebsd_module_loaded() +{ + # $1 - module name + kldstat -qm "${1}" +} +freebsd_modules_loaded() +{ + # $1,$2,$3, ... - module names + while [ -n "$1" ]; do + freebsd_module_loaded $1 || return 1 + shift + done + return 0 +} + +check_prerequisites() +{ + echo \* checking prerequisites + + [ "$SKIP_PKTWS" = 1 -o "$UNAME" = Darwin -o -x "$PKTWS" ] && [ "$SKIP_TPWS" = 1 -o "$UNAME" = CYGWIN -o -x "$TPWS" ] && [ -x "$MDIG" ] || { + local target + case $UNAME in + Darwin) + target="mac" + ;; + OpenBSD) + target="bsd" + ;; + esac + echo $PKTWS or $TPWS or $MDIG is not available. run \"$ZAPRET_BASE/install_bin.sh\" or \`make -C \"$ZAPRET_BASE\" $target\` + exitp 6 + } + + local prog progs="$CURL" + [ "$SKIP_PKTWS" = 1 ] || { + case "$UNAME" in + Linux) + case "$FWTYPE" in + iptables) + ipt_has_nfq || { + echo NFQUEUE iptables or ip6tables target is missing. pls install modules. + exitp 6 + } + progs="$progs iptables ip6tables" + ;; + nftables) + nft_has_nfq || { + echo nftables queue support is not available. pls install modules. + exitp 6 + } + progs="$progs nft" + ;; + esac + ;; + FreeBSD) + freebsd_modules_loaded ipfw ipdivert || { + echo ipfw or ipdivert kernel module not loaded + exitp 6 + } + [ "$(sysctl -qn net.inet.ip.fw.enable)" = 0 -o "$(sysctl -qn net.inet6.ip6.fw.enable)" = 0 ] && { + echo ipfw is disabled. use : ipfw enable firewall + exitp 6 + } + pf_is_avail && { + pf_save + [ "$SUBSYS" = "pfSense" ] && { + # pfsense's ipfw may not work without these workarounds + sysctl net.inet.ip.pfil.outbound=ipfw,pf 2>/dev/null + sysctl net.inet.ip.pfil.inbound=ipfw,pf 2>/dev/null + sysctl net.inet6.ip6.pfil.outbound=ipfw,pf 2>/dev/null + sysctl net.inet6.ip6.pfil.inbound=ipfw,pf 2>/dev/null + pfctl -qd + pfctl -qe + pf_restore + } + } + progs="$progs ipfw" + ;; + OpenBSD|Darwin) + pf_is_avail || { + echo pf is not available + exitp 6 + } + pf_save + progs="$progs pfctl" + ;; + esac + } + + case "$UNAME" in + CYGWIN) + SKIP_TPWS=1 + ;; + esac + + for prog in $progs; do + exists $prog || { + echo $prog does not exist. please install + exitp 6 + } + done + + if exists nslookup; then + LOOKUP=nslookup + elif exists host; then + LOOKUP=host + else + echo nslookup or host does not exist. please install + exitp 6 + fi +} + + +curl_translate_code() +{ + # $1 - code + printf $1 + case $1 in + 0) printf ": ok" + ;; + 1) printf ": unsupported protocol" + ;; + 2) printf ": early initialization code failed" + ;; + 3) printf ": the URL was not properly formatted" + ;; + 4) printf ": feature not supported by libcurl" + ;; + 5) printf ": could not resolve proxy" + ;; + 6) printf ": could not resolve host" + ;; + 7) printf ": could not connect" + ;; + 8) printf ": invalid server reply" + ;; + 9) printf ": remote access denied" + ;; + 27) printf ": out of memory" + ;; + 28) printf ": operation timed out" + ;; + 35) printf ": SSL connect error" + ;; + esac +} +curl_supports_tls13() +{ + local r + "$CURL" --tlsv1.3 -Is -o /dev/null --max-time 1 http://127.0.0.1:65535 2>/dev/null + # return code 2 = init failed. likely bad command line options + [ $? = 2 ] && return 1 + # curl can have tlsv1.3 key present but ssl library without TLS 1.3 support + # this is online test because there's no other way to trigger library incompatibility case + "$CURL" --tlsv1.3 --max-time 1 -Is -o /dev/null https://iana.org 2>/dev/null + r=$? + [ $r != 4 -a $r != 35 ] +} + +curl_supports_tlsmax() +{ + # supported only in OpenSSL and LibreSSL + "$CURL" --version | grep -Fq -e OpenSSL -e LibreSSL -e BoringSSL -e GnuTLS -e quictls || return 1 + # supported since curl 7.54 + "$CURL" --tls-max 1.2 -Is -o /dev/null --max-time 1 http://127.0.0.1:65535 2>/dev/null + # return code 2 = init failed. likely bad command line options + [ $? != 2 ] +} + +curl_supports_connect_to() +{ + "$CURL" --connect-to 127.0.0.1:: -o /dev/null --max-time 1 http://127.0.0.1:65535 2>/dev/null + [ "$?" != 2 ] +} + +curl_supports_http3() +{ + # if it has http3 : curl: (3) HTTP/3 requested for non-HTTPS URL + # otherwise : curl: (2) option --http3-only: is unknown + "$CURL" --connect-to 127.0.0.1:: -o /dev/null --max-time 1 --http3-only http://127.0.0.1:65535 2>/dev/null + [ "$?" != 2 ] +} + +hdrfile_http_code() +{ + # $1 - hdr file + sed -nre '1,1 s/^HTTP\/1\.[0,1] ([0-9]+) .*$/\1/p' "$1" +} +hdrfile_location() +{ + # $1 - hdr file + + # some DPIs return CRLF line ending + tr -d '\015' <"$1" | sed -nre 's/^[Ll][Oo][Cc][Aa][Tt][Ii][Oo][Nn]:[ ]*([^ ]*)[ ]*$/\1/p' +} + +curl_with_subst_ip() +{ + # $1 - domain + # $2 - port + # $3 - ip + # $4+ - curl params + local ip="$3" + case "$ip" in + *:*) ip="[$ip]" ;; + esac + local connect_to="--connect-to $1::$ip${2:+:$2}" arg + shift ; shift ; shift; + [ "$CURL_VERBOSE" = 1 ] && arg="-v" + [ "$CURL_CMD" = 1 ] && echo $CURL ${arg:+$arg }$connect_to "$@" + ALL_PROXY="$ALL_PROXY" "$CURL" ${arg:+$arg }$connect_to "$@" +} +curl_with_dig() +{ + # $1 - ip version : 4/6 + # $2 - domain name + # $3 - port + # $4+ - curl params + local dom="$2" port=$3 + local sdom suri ip + + split_by_separator "$dom" / sdom suri + mdig_resolve $1 ip $sdom + shift ; shift ; shift + if [ -n "$ip" ]; then + curl_with_subst_ip "$sdom" "$port" "$ip" "$@" + else + return 6 + fi +} +curl_probe() +{ + # $1 - ip version : 4/6 + # $2 - domain name + # $3 - port + # $4 - subst ip + # $5+ - curl params + local ipv=$1 dom="$2" port=$3 subst=$4 + shift; shift; shift; shift + if [ -n "$subst" ]; then + curl_with_subst_ip "$dom" $port $subst "$@" + else + curl_with_dig $ipv "$dom" $port "$@" + fi +} +curl_test_http() +{ + # $1 - ip version : 4/6 + # $2 - domain name + # $3 - subst ip + # $4 - "detail" - detail info + + local code loc hdrt="${HDRTEMP}_${!:-$$}.txt" dom="$(tolower "$2")" + curl_probe $1 "$2" $HTTP_PORT "$3" -SsD "$hdrt" -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT "http://$2" -o /dev/null 2>&1 || { + code=$? + rm -f "$hdrt" + return $code + } + if [ "$4" = "detail" ] ; then + head -n 1 "$hdrt" + grep "^[lL]ocation:" "$hdrt" + else + code=$(hdrfile_http_code "$hdrt") + [ "$code" = 301 -o "$code" = 302 -o "$code" = 307 -o "$code" = 308 ] && { + loc=$(hdrfile_location "$hdrt") + split_by_separator "$dom" / dom + tolower "$loc" | grep -qE "^https?://.*$dom(/|$)" || + tolower "$loc" | grep -vqE '^https?://' || { + echo suspicious redirection $code to : $loc + rm -f "$hdrt" + return 254 + } + } + fi + rm -f "$hdrt" + [ "$code" = 400 ] && { + # this can often happen if the server receives fake packets it should not receive + echo http code $code. likely the server receives fakes. + return 254 + } + return 0 +} +curl_test_https_tls12() +{ + # $1 - ip version : 4/6 + # $2 - domain name + # $3 - subst ip + + # do not use tls 1.3 to make sure server certificate is not encrypted + curl_probe $1 $2 $HTTPS_PORT "$3" $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.2 $TLSMAX12 "https://$2" -o /dev/null 2>&1 +} +curl_test_https_tls13() +{ + # $1 - ip version : 4/6 + # $2 - domain name + # $3 - subst ip + + # force TLS1.3 mode + curl_probe $1 $2 $HTTPS_PORT "$3" $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.3 $TLSMAX13 "https://$2" -o /dev/null 2>&1 +} + +curl_test_http3() +{ + # $1 - ip version : 4/6 + # $2 - domain name + + # force QUIC only mode without tcp + curl_with_dig $1 $2 $QUIC_PORT $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME_QUIC --http3-only $CURL_OPT "https://$2" -o /dev/null 2>&1 +} + +ipt_aux_scheme() +{ + # $1 - 1 - add , 0 - del + # $2 - tcp/udp + # $3 - port + + # to avoid possible INVALID state drop + [ "$2" = tcp ] && IPT_ADD_DEL $1 INPUT -p $2 --sport $3 ! --syn -j ACCEPT + + local icmp_filter="-p icmp -m icmp --icmp-type" + [ "$IPV" = 6 ] && icmp_filter="-p icmpv6 -m icmp6 --icmpv6-type" + IPT_ADD_DEL $1 INPUT $icmp_filter time-exceeded -m connmark --mark $DESYNC_MARK/$DESYNC_MARK -j DROP + + # for strategies with incoming packets involved (autottl) + IPT_ADD_DEL $1 OUTPUT -p $2 --dport $3 -m conntrack --ctstate INVALID -j ACCEPT + if [ "$IPV" = 6 -a -n "$IP6_DEFRAG_DISABLE" ]; then + # the only way to reliable disable ipv6 defrag. works only in 4.16+ kernels + IPT_ADD_DEL $1 OUTPUT -t raw -p $2 -m frag -j CT --notrack + elif [ "$IPV" = 4 ]; then + # enable fragments + IPT_ADD_DEL $1 OUTPUT -f -j ACCEPT + fi + # enable everything generated by nfqws (works only in OUTPUT, not in FORWARD) + # raw table may not be present + IPT_ADD_DEL $1 OUTPUT -t raw -m mark --mark $DESYNC_MARK/$DESYNC_MARK -j CT --notrack +} +ipt_scheme() +{ + # $1 - tcp/udp + # $2 - port + # $3 - ip list + + local ip + + $IPTABLES -t mangle -N blockcheck_output 2>/dev/null + $IPTABLES -t mangle -F blockcheck_output + IPT OUTPUT -t mangle -j blockcheck_output + + # prevent loop + $IPTABLES -t mangle -A blockcheck_output -m mark --mark $DESYNC_MARK/$DESYNC_MARK -j RETURN + $IPTABLES -t mangle -A blockcheck_output ! -p $1 -j RETURN + $IPTABLES -t mangle -A blockcheck_output -p $1 ! --dport $2 -j RETURN + + for ip in $3; do + $IPTABLES -t mangle -A blockcheck_output -d $ip -j CONNMARK --or-mark $DESYNC_MARK + $IPTABLES -t mangle -A blockcheck_output -d $ip -j NFQUEUE --queue-num $QNUM + done + + ipt_aux_scheme 1 $1 $2 +} +nft_scheme() +{ + # $1 - tcp/udp + # $2 - port + # $3 - ip list + + local iplist ipver=$IPV + [ "$IPV" = 6 ] || ipver= + make_comma_list iplist $3 + + nft add table inet $NFT_TABLE + nft "add chain inet $NFT_TABLE postnat { type filter hook postrouting priority 102; }" + nft "add rule inet $NFT_TABLE postnat meta nfproto ipv${IPV} $1 dport $2 mark and $DESYNC_MARK == 0 ip${ipver} daddr {$iplist} ct mark set ct mark or $DESYNC_MARK queue num $QNUM" + # for strategies with incoming packets involved (autottl) + nft "add chain inet $NFT_TABLE prenat { type filter hook prerouting priority -102; }" + # enable everything generated by nfqws (works only in OUTPUT, not in FORWARD) + nft "add chain inet $NFT_TABLE predefrag { type filter hook output priority -402; }" + nft "add rule inet $NFT_TABLE predefrag meta nfproto ipv${IPV} mark and $DESYNC_MARK !=0 notrack" + [ "$IPV" = 4 ] && { + nft "add rule inet $NFT_TABLE prenat icmp type time-exceeded ct mark and $DESYNC_MARK != 0 drop" + nft "add rule inet $NFT_TABLE prenat icmp type time-exceeded ct state invalid drop" + } + [ "$IPV" = 6 ] && { + nft "add rule inet $NFT_TABLE prenat icmpv6 type time-exceeded ct mark and $DESYNC_MARK != 0 drop" + nft "add rule inet $NFT_TABLE prenat icmpv6 type time-exceeded ct state invalid drop" + } +} + +pktws_ipt_prepare() +{ + # $1 - tcp/udp + # $2 - port + # $3 - ip list + + local ip + + case "$FWTYPE" in + iptables) + ipt_scheme $1 $2 "$3" + ;; + nftables) + nft_scheme $1 $2 "$3" + ;; + ipfw) + # disable PF to avoid interferences + pf_is_avail && pfctl -qd + for ip in $3; do + IPFW_ADD divert $IPFW_DIVERT_PORT $1 from me to $ip $2 proto ip${IPV} out not diverted + done + ;; + opf) + opf_prepare_dvtws $1 $2 "$3" + ;; + windivert) + WF="--wf-l3=ipv${IPV} --wf-${1}=$2" + rm -f "$IPSET_FILE" + for ip in $3; do + echo $ip >>"$IPSET_FILE" + done + ;; + + esac +} +pktws_ipt_unprepare() +{ + # $1 - tcp/udp + # $2 - port + + case "$FWTYPE" in + iptables) + ipt_aux_scheme 0 $1 $2 + IPT_DEL OUTPUT -t mangle -j blockcheck_output + $IPTABLES -t mangle -F blockcheck_output 2>/dev/null + $IPTABLES -t mangle -X blockcheck_output 2>/dev/null + ;; + nftables) + nft delete table inet $NFT_TABLE 2>/dev/null + ;; + ipfw) + IPFW_DEL + pf_is_avail && pf_restore + ;; + opf) + pf_restore + ;; + windivert) + unset WF + rm -f "$IPSET_FILE" + ;; + esac +} + +pktws_ipt_prepare_tcp() +{ + # $1 - port + # $2 - ip list + + local ip iplist ipver + + pktws_ipt_prepare tcp $1 "$2" + + # for autottl mode + case "$FWTYPE" in + iptables) + $IPTABLES -N blockcheck_input -t mangle 2>/dev/null + $IPTABLES -F blockcheck_input -t mangle 2>/dev/null + IPT INPUT -t mangle -j blockcheck_input + $IPTABLES -t mangle -A blockcheck_input ! -p tcp -j RETURN + $IPTABLES -t mangle -A blockcheck_input -p tcp ! --sport $1 -j RETURN + $IPTABLES -t mangle -A blockcheck_input -p tcp ! --tcp-flags SYN,ACK SYN,ACK -j RETURN + for ip in $2; do + $IPTABLES -A blockcheck_input -t mangle -s $ip -j NFQUEUE --queue-num $QNUM + done + ;; + nftables) + ipver=$IPV + [ "$IPV" = 6 ] || ipver= + make_comma_list iplist $2 + nft "add rule inet $NFT_TABLE prenat meta nfproto ipv${IPV} tcp sport $1 tcp flags & (syn | ack) == (syn | ack) ip${ipver} saddr {$iplist} queue num $QNUM" + ;; + ipfw) + for ip in $2; do + IPFW_ADD divert $IPFW_DIVERT_PORT tcp from $ip $1 to me proto ip${IPV} tcpflags syn,ack in not diverted + done + ;; + esac +} +pktws_ipt_unprepare_tcp() +{ + # $1 - port + + pktws_ipt_unprepare tcp $1 + + case "$FWTYPE" in + iptables) + IPT_DEL INPUT -t mangle -j blockcheck_input + $IPTABLES -t mangle -F blockcheck_input 2>/dev/null + $IPTABLES -t mangle -X blockcheck_input 2>/dev/null + ;; + esac +} +pktws_ipt_prepare_udp() +{ + # $1 - port + # $2 - ip list + + pktws_ipt_prepare udp $1 "$2" +} +pktws_ipt_unprepare_udp() +{ + # $1 - port + + pktws_ipt_unprepare udp $1 +} + +pktws_start() +{ + case "$UNAME" in + Linux) + "$NFQWS" --uid $TPWS_UID:$TPWS_GID --dpi-desync-fwmark=$DESYNC_MARK --qnum=$QNUM "$@" >/dev/null & + ;; + FreeBSD|OpenBSD) + "$DVTWS" --port=$IPFW_DIVERT_PORT "$@" >/dev/null & + ;; + CYGWIN) + "$WINWS" $WF --ipset="$IPSET_FILE" "$@" >/dev/null & + ;; + esac + PID=$! + # give some time to initialize + minsleep +} +tpws_start() +{ + local uid + [ -n "$HAVE_ROOT" ] && uid="--uid $TPWS_UID:$TPWS_GID" + "$TPWS" $uid --socks --bind-addr=127.0.0.1 --port=$SOCKS_PORT "$@" >/dev/null & + PID=$! + # give some time to initialize + minsleep +} +ws_kill() +{ + [ -z "$PID" ] || { + killwait -9 $PID 2>/dev/null + PID= + } +} + +check_domain_port_block() +{ + # $1 - domain + # $2 - port + local ip ips + echo + echo \* port block tests ipv$IPV $1:$2 + if netcat_setup; then + mdig_resolve_all $IPV ips $1 + if [ -n "$ips" ]; then + for ip in $ips; do + if netcat_test $ip $2; then + echo $ip connects + else + echo $ip does not connect. netcat code $? + fi + done + else + echo "ipv${IPV} $1 does not resolve" + fi + else + echo suitable netcat not found. busybox nc is not supported. pls install nmap ncat or openbsd netcat. + fi +} + +curl_test() +{ + # $1 - test function + # $2 - domain + # $3 - subst ip + # $4 - param of test function + local code=0 n=0 p pids + + if [ "$PARALLEL" = 1 ]; then + rm -f "${PARALLEL_OUT}"* + for n in $(seq -s ' ' 1 $REPEATS); do + $1 "$IPV" $2 $3 "$4" >"${PARALLEL_OUT}_$n" & + pids="${pids:+$pids }$!" + done + n=1 + for p in $pids; do + [ $REPEATS -gt 1 ] && printf "[attempt $n] " + if wait $p; then + [ $REPEATS -gt 1 ] && echo 'AVAILABLE' + else + code=$? + cat "${PARALLEL_OUT}_$n" + fi + n=$(($n+1)) + done + rm -f "${PARALLEL_OUT}"* + else + while [ $n -lt $REPEATS ]; do + n=$(($n+1)) + [ $REPEATS -gt 1 ] && printf "[attempt $n] " + if $1 "$IPV" $2 $3 "$4" ; then + [ $REPEATS -gt 1 ] && echo 'AVAILABLE' + else + code=$? + [ "$SCANLEVEL" = quick ] && break + fi + done + fi + [ "$4" = detail ] || { + if [ $code = 254 ]; then + echo "UNAVAILABLE" + elif [ $code = 0 ]; then + echo '!!!!! AVAILABLE !!!!!' + else + echo "UNAVAILABLE code=$code" + fi + } + return $code +} +ws_curl_test() +{ + + # $1 - ws start function + # $2 - test function + # $3 - domain + # $4,$5,$6, ... - ws params + local code ws_start=$1 testf=$2 dom="$3" + + [ "$SIMULATE" = 1 ] && { + n=$(random 0 99) + if [ "$n" -lt "$SIM_SUCCESS_RATE" ]; then + echo "SUCCESS" + return 0 + else + echo "FAILED" + return 7 + fi + } + shift + shift + shift + $ws_start "$@" + curl_test $testf "$dom" + code=$? + ws_kill + return $code +} +tpws_curl_test() +{ + # $1 - test function + # $2 - domain + # $3,$4,$5, ... - tpws params + echo - $1 ipv$IPV $2 : 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 testf=$1 dom="$2" strategy code=$? + [ "$code" = 0 ] && { + shift; shift; + strategy="$@" + strategy_append_extra_tpws + report_append "$dom" "$testf ipv${IPV}" "tpws ${WF:+$WF }$strategy" + } + return $code +} +pktws_curl_test() +{ + # $1 - test function + # $2 - domain + # $3,$4,$5, ... - nfqws/dvtws params + local testf=$1 dom="$2" strategy code + + shift; shift; + echo - $testf ipv$IPV $dom : $PKTWSD ${WF:+$WF }${PKTWS_EXTRA_PRE:+$PKTWS_EXTRA_PRE }${PKTWS_EXTRA_PRE_1:+"$PKTWS_EXTRA_PRE_1" }${PKTWS_EXTRA_PRE_2:+"$PKTWS_EXTRA_PRE_2" }${PKTWS_EXTRA_PRE_3:+"$PKTWS_EXTRA_PRE_3" }${PKTWS_EXTRA_PRE_4:+"$PKTWS_EXTRA_PRE_4" }${PKTWS_EXTRA_PRE_5:+"$PKTWS_EXTRA_PRE_5" }${PKTWS_EXTRA_PRE_6:+"$PKTWS_EXTRA_PRE_6" }${PKTWS_EXTRA_PRE_7:+"$PKTWS_EXTRA_PRE_7" }${PKTWS_EXTRA_PRE_8:+"$PKTWS_EXTRA_PRE_8" }${PKTWS_EXTRA_PRE_9:+"$PKTWS_EXTRA_PRE_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 $testf "$dom" ${PKTWS_EXTRA_PRE:+$PKTWS_EXTRA_PRE }${PKTWS_EXTRA_PRE_1:+"$PKTWS_EXTRA_PRE_1" }${PKTWS_EXTRA_PRE_2:+"$PKTWS_EXTRA_PRE_2" }${PKTWS_EXTRA_PRE_3:+"$PKTWS_EXTRA_PRE_3" }${PKTWS_EXTRA_PRE_4:+"$PKTWS_EXTRA_PRE_4" }${PKTWS_EXTRA_PRE_5:+"$PKTWS_EXTRA_PRE_5" }${PKTWS_EXTRA_PRE_6:+"$PKTWS_EXTRA_PRE_6" }${PKTWS_EXTRA_PRE_7:+"$PKTWS_EXTRA_PRE_7" }${PKTWS_EXTRA_PRE_8:+"$PKTWS_EXTRA_PRE_8" }${PKTWS_EXTRA_PRE_9:+"$PKTWS_EXTRA_PRE_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"} + + code=$? + [ "$code" = 0 ] && { + strategy="$@" + strategy_append_extra_pktws + report_append "$dom" "$testf ipv${IPV}" "$PKTWSD ${WF:+$WF }$strategy" + } + return $code +} + +strategy_append_extra_pktws() +{ + strategy="${strategy:+${PKTWS_EXTRA_PRE:+$PKTWS_EXTRA_PRE }${PKTWS_EXTRA_PRE_1:+"$PKTWS_EXTRA_PRE_1" }${PKTWS_EXTRA_PRE_2:+"$PKTWS_EXTRA_PRE_2" }${PKTWS_EXTRA_PRE_3:+"$PKTWS_EXTRA_PRE_3" }${PKTWS_EXTRA_PRE_4:+"$PKTWS_EXTRA_PRE_4" }${PKTWS_EXTRA_PRE_5:+"$PKTWS_EXTRA_PRE_5" }${PKTWS_EXTRA_PRE_6:+"$PKTWS_EXTRA_PRE_6" }${PKTWS_EXTRA_PRE_7:+"$PKTWS_EXTRA_PRE_7" }${PKTWS_EXTRA_PRE_8:+"$PKTWS_EXTRA_PRE_8" }${PKTWS_EXTRA_PRE_9:+"$PKTWS_EXTRA_PRE_9" }$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:+${PKTWS_EXTRA_PRE:+$PKTWS_EXTRA_PRE }${PKTWS_EXTRA_PRE_1:+"$PKTWS_EXTRA_PRE_1" }${PKTWS_EXTRA_PRE_2:+"$PKTWS_EXTRA_PRE_2" }${PKTWS_EXTRA_PRE_3:+"$PKTWS_EXTRA_PRE_3" }${PKTWS_EXTRA_PRE_4:+"$PKTWS_EXTRA_PRE_4" }${PKTWS_EXTRA_PRE_5:+"$PKTWS_EXTRA_PRE_5" }${PKTWS_EXTRA_PRE_6:+"$PKTWS_EXTRA_PRE_6" }${PKTWS_EXTRA_PRE_7:+"$PKTWS_EXTRA_PRE_7" }${PKTWS_EXTRA_PRE_8:+"$PKTWS_EXTRA_PRE_8" }${PKTWS_EXTRA_PRE_9:+"$PKTWS_EXTRA_PRE_9" }$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 + # $2 - test function + # $3 - domain + # $4,$5,$6, ... - nfqws/dvtws params + local code xxxf=$1 testf=$2 dom="$3" + shift + shift + shift + $xxxf $testf "$dom" "$@" + code=$? + [ $code = 0 ] && strategy="${strategy:-$@}" + return $code +} +pktws_curl_test_update() +{ + xxxws_curl_test_update pktws_curl_test "$@" +} +tpws_curl_test_update() +{ + xxxws_curl_test_update tpws_curl_test "$@" +} + +report_append() +{ + # $1 - domain + # $2 - test function + ipver + # $3 - value + local hashstr hash hashvar hashcountvar val ct + + # save resources if only one domain + [ "$DOMAINS_COUNT" -gt 1 ] && { + hashstr="$2 : $3" + hash="$(echo -n "$hashstr" | md5f)" + hashvar=RESHASH_${hash} + hashcountvar=${hashvar}_COUNTER + + NRESHASH=${NRESHASH:-0} + + eval val="\$$hashvar" + if [ -n "$val" ]; then + eval ct="\$$hashcountvar" + ct=$(($ct + 1)) + eval $hashcountvar="\$ct" + else + eval $hashvar=\"$hashstr\" + eval $hashcountvar=1 + eval RES_$NRESHASH="\$hash" + NRESHASH=$(($NRESHASH+1)) + fi + } + + NREPORT=${NREPORT:-0} + eval REPORT_${NREPORT}=\"$2 $1 : $3\" + NREPORT=$(($NREPORT+1)) +} +report_print() +{ + local n=0 s + NREPORT=${NREPORT:-0} + while [ $n -lt $NREPORT ]; do + eval s=\"\${REPORT_$n}\" + echo $s + n=$(($n+1)) + done +} +result_intersection_print() +{ + local n=0 hash hashvar hashcountvar ct val + while : ; do + eval hash=\"\$RES_$n\" + [ -n "$hash" ] || break + hashvar=RESHASH_${hash} + hashcountvar=${hashvar}_COUNTER + eval ct=\"\$$hashcountvar\" + [ "$ct" = "$DOMAINS_COUNT" ] && { + eval val=\"\$$hashvar\" + echo "$val" + } + n=$(($n + 1)) + done +} +report_strategy() +{ + # $1 - test function + # $2 - domain + # $3 - daemon + echo + if [ -n "$strategy" ]; then + # trim spaces at the end + strategy="$(echo "$strategy" | xargs)" + echo "!!!!! $1: working strategy found for ipv${IPV} $2 : $3 $strategy !!!!!" + echo + return 0 + else + echo "$1: $3 strategy for ipv${IPV} $2 not found" + echo + report_append "$2" "$1 ipv${IPV}" "$3 not working" + return 1 + fi +} +test_has_fakedsplit() +{ + contains "$1" fakedsplit || contains "$1" fakeddisorder +} +test_has_split() +{ + contains "$1" multisplit || contains "$1" multidisorder || test_has_fakedsplit "$1" +} +test_has_hostfakesplit() +{ + contains "$1" hostfakesplit +} +test_has_fake() +{ + [ "$1" = fake ] || starts_with "$1" fake, +} +warn_fool() +{ + case "$1" in + md5sig) echo 'WARNING ! although md5sig fooling worked it will not work on all sites. it typically works only on linux servers.' + [ "$2" = "fakedsplit" -o "$2" = "fakeddisorder" ] && \ + echo "WARNING ! fakedsplit/fakeddisorder with md5sig fooling and low split position causes MTU overflow with multi-segment TLS (kyber)" + ;; + datanoack) echo 'WARNING ! although datanoack fooling worked it may break NAT and may only work with external IP. Additionally it may require nftables to work correctly.' ;; + ts) echo 'WARNING ! although ts fooling worked it will not work without timestamps being enabled in the client OS. In windows timestamps are DISABLED by default.' + esac +} +pktws_curl_test_update_vary() +{ + # $1 - test function + # $2 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk + # $3 - domain + # $4 - desync mode + # $5,$6,... - strategy + + local testf=$1 sec=$2 domain=$3 desync=$4 proto splits= pos fake ret=1 + local fake1=- fake2=- fake3=- fake4=- + + shift; shift; shift; shift + + proto=http + [ "$sec" = 0 ] || proto=tls + test_has_fake $desync && { + fake1="--dpi-desync-fake-$proto=0x00000000" + [ "$sec" = 0 ] || { + fake2='--dpi-desync-fake-tls=0x00000000 --dpi-desync-fake-tls=! --dpi-desync-fake-tls-mod=rnd,rndsni,dupsid' + # this splits actual fake to '1603' and modified standard fake from offset 2 + fake3='--dpi-desync-fake-tls=0x1603 --dpi-desync-fake-tls=!+2 --dpi-desync-fake-tls-mod=rnd,dupsid,rndsni --dpi-desync-fake-tcp-mod=seq' + fake4='--dpi-desync-fake-tls-mod=rnd,dupsid,rndsni,padencap' + } + } + if test_has_fakedsplit $desync ; then + splits="method+2 midsld" + [ "$sec" = 0 ] || splits="1 midsld" + # do not send fake first + fake1='--dpi-desync-fakedsplit-mod=altorder=1' + elif test_has_split $desync ; then + splits="method+2 midsld" + [ "$sec" = 0 ] || splits="1 midsld 1,midsld" + fi + test_has_hostfakesplit $desync && { + fake1="--dpi-desync-hostfakesplit-mod=altorder=1" + fake2="--dpi-desync-hostfakesplit-midhost=midsld" + fake3="--dpi-desync-hostfakesplit-mod=altorder=1 --dpi-desync-hostfakesplit-midhost=midsld" + } + for fake in '' "$fake1" "$fake2" "$fake3" "$fake4" ; do + [ "$fake" = "-" ] && continue + if [ -n "$splits" ]; then + for pos in $splits ; do + pktws_curl_test_update $testf "$domain" --dpi-desync=$desync "$@" --dpi-desync-split-pos=$pos $fake && { + [ "$SCANLEVEL" = force ] || return 0 + ret=0 + } + done + else + pktws_curl_test_update $testf "$domain" --dpi-desync=$desync "$@" $fake && { + [ "$SCANLEVEL" = force ] || return 0 + ret=0 + } + fi + done + + return $ret +} + +pktws_check_domain_http_bypass_() +{ + # $1 - test function + # $2 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk + # $3 - domain + + local ok ttls attls s f f2 e desync pos fooling frag sec="$2" delta orig splits + local need_split need_disorder need_fakedsplit need_hostfakesplit need_fakeddisorder need_fake need_wssize + local splits_http='method+2 midsld method+2,midsld' + local splits_tls='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1' + + [ "$sec" = 0 ] && { + for s in '--hostcase' '--hostspell=hoSt' '--hostnospace' '--domcase' '--methodeol'; do + pktws_curl_test_update $1 $3 $s && [ "$SCANLEVEL" = quick ] && return + done + } + + ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL) + attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA) + need_wssize=1 + for e in '' '--wssize 1:6'; do + need_split= + need_disorder= + + [ -n "$e" ] && { + pktws_curl_test_update $1 $3 $e && [ "$SCANLEVEL" = quick ] && return + } + + for desync in multisplit multidisorder; do + ok=0 + splits="$splits_http" + [ "$sec" = 0 ] || splits="$splits_tls" + for pos in $splits; do + pktws_curl_test_update $1 $3 --dpi-desync=$desync --dpi-desync-split-pos=$pos $e && { + [ "$SCANLEVEL" = quick ] && return + ok=1 + need_wssize=0 + [ "$SCANLEVEL" = force ] || break + } + done + [ "$ok" = 1 -a "$SCANLEVEL" != force ] || { + case $desync in + multisplit) + need_split=1 + ;; + multidisorder) + need_disorder=1 + ;; + esac + } + done + + need_fakedsplit=1 + need_hostfakesplit=1 + need_fakeddisorder=1 + need_fake=1 + for desync in fake ${need_split:+fakedsplit fake,multisplit fake,fakedsplit hostfakesplit fake,hostfakesplit} ${need_disorder:+fakeddisorder fake,multidisorder fake,fakeddisorder}; do + [ "$need_fake" = 0 ] && test_has_fake "$desync" && continue + [ "$need_fakedsplit" = 0 ] && contains "$desync" fakedsplit && continue + [ "$need_hostfakesplit" = 0 ] && contains "$desync" hostfakesplit && continue + [ "$need_fakeddisorder" = 0 ] && contains "$desync" fakeddisorder && continue + ok=0 + for ttl in $ttls; do + # orig-ttl=1 with start/cutoff limiter drops empty ACK packet in response to SYN,ACK. it does not reach DPI or server. + # missing ACK is transmitted in the first data packet of TLS/HTTP proto + for f in '' '--orig-ttl=1 --orig-mod-start=s1 --orig-mod-cutoff=d1'; do + pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-ttl=$ttl $f $e && { + [ "$SCANLEVEL" = quick ] && return + ok=1 + need_wssize=0 + [ "$SCANLEVEL" = force ] || break + } + done + [ "$ok" = 1 ] && break + done + # only skip tests if TTL succeeded. do not skip if TTL failed but fooling succeeded + [ $ok = 1 -a "$SCANLEVEL" != force ] && { + [ "$desync" = fake ] && need_fake=0 + [ "$desync" = fakedsplit ] && need_fakedsplit=0 + [ "$desync" = hostfakesplit ] && need_hostfakesplit=0 + [ "$desync" = fakeddisorder ] && need_fakeddisorder=0 + } + f= + [ "$UNAME" = "OpenBSD" ] || f="badsum" + f="$f badseq datanoack ts md5sig" + [ "$IPV" = 6 ] && f="$f hopbyhop hopbyhop2" + for fooling in $f; do + ok=0 + f2= + pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling $e && { + warn_fool $fooling $desync + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + ok=1 + } + [ "$fooling" = badseq ] && { + [ "$ok" = 1 -a "$SCANLEVEL" != force ] && continue + # --dpi-desync-badseq-increment=0 leaves modified by default ack increment + pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling --dpi-desync-badseq-increment=0 $e && { + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + } + } + [ "$fooling" = md5sig ] && { + [ "$ok" = 1 -a "$SCANLEVEL" != force ] && continue + pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling --dup=1 --dup-cutoff=n2 --dup-fooling=md5sig $e && { + warn_fool $fooling $desync + echo "HINT ! To avoid possible 1 sec server response delay use --dup-ttl or --dup-autottl and block ICMP time exceeded" + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + } + } + done + done + + [ "$IPV" = 6 ] && { + f="hopbyhop ${need_split:+hopbyhop,multisplit} ${need_disorder:+hopbyhop,multidisorder} destopt ${need_split:+destopt,multisplit} ${need_disorder:+destopt,multidisorder}" + [ -n "$IP6_DEFRAG_DISABLE" ] && f="$f ipfrag1 ${need_split:+ ipfrag1,multisplit} ${need_disorder:+ ipfrag1,multidisorder}" + for desync in $f; do + pktws_curl_test_update_vary $1 $2 $3 $desync $e && { + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + } + done + } + + [ "$need_split" = 1 ] && { + # relative markers can be anywhere, even in subsequent packets. first packet can be MTU-full. + # make additional split pos "10" to guarantee enough space for seqovl and likely to be before midsld,sniext,... + # method is always expected in the beginning of the first packet + f="method+2 method+2,midsld" + [ "$sec" = 0 ] || f="10 10,sniext+1 10,sniext+4 10,midsld" + for pos in $f; do + pktws_curl_test_update $1 $3 --dpi-desync=multisplit --dpi-desync-split-pos=$pos --dpi-desync-split-seqovl=1 $e && { + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + } + done + [ "$sec" != 0 ] && pktws_curl_test_update $1 $3 --dpi-desync=multisplit --dpi-desync-split-pos=2 --dpi-desync-split-seqovl=336 --dpi-desync-split-seqovl-pattern="$ZAPRET_BASE/files/fake/tls_clienthello_iana_org.bin" $e && { + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + } + } + [ "$need_disorder" = 1 ] && { + if [ "$sec" = 0 ]; then + for pos in 'method+1 method+2' 'midsld-1 midsld' 'method+1 method+2,midsld'; do + f="$(extract_arg 1 $pos)" + f2="$(extract_arg 2 $pos)" + pktws_curl_test_update $1 $3 --dpi-desync=multidisorder --dpi-desync-split-pos=$f2 --dpi-desync-split-seqovl=$f $e && { + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + } + done + else + for pos in '1 2' 'sniext sniext+1' 'sniext+3 sniext+4' 'midsld-1 midsld' '1 2,midsld'; do + f=$(extract_arg 1 $pos) + f2=$(extract_arg 2 $pos) + pktws_curl_test_update $1 $3 --dpi-desync=multidisorder --dpi-desync-split-pos=$f2 --dpi-desync-split-seqovl=$f $e && { + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + } + done + fi + } + + need_fakedsplit=1 + need_fakeddisorder=1 + need_hostfakesplit=1 + need_fake=1 + for desync in fake ${need_split:+fakedsplit fake,multisplit fake,fakedsplit hostfakesplit fake,hostfakesplit} ${need_disorder:+fakeddisorder fake,multidisorder fake,fakeddisorder}; do + [ "$need_fake" = 0 ] && test_has_fake "$desync" && continue + [ "$need_fakedsplit" = 0 ] && contains "$desync" fakedsplit && continue + [ "$need_hostfakesplit" = 0 ] && contains "$desync" hostfakesplit && continue + [ "$need_fakeddisorder" = 0 ] && contains "$desync" fakeddisorder && continue + ok=0 + # orig-ttl=1 with start/cutoff limiter drops empty ACK packet in response to SYN,ACK. it does not reach DPI or server. + # missing ACK is transmitted in the first data packet of TLS/HTTP proto + for delta in $attls; do + for f in '' '--orig-ttl=1 --orig-mod-start=s1 --orig-mod-cutoff=d1'; do + pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-ttl=1 --dpi-desync-autottl=-$delta $f $e && ok=1 + [ "$ok" = 1 -a "$SCANLEVEL" != force ] && break + done + done + [ "$SCANLEVEL" = force ] && { + for orig in 1 2 3; do + for delta in $attls; do + pktws_curl_test_update_vary $1 $2 $3 $desync ${orig:+--orig-autottl=+$orig} --dpi-desync-ttl=1 --dpi-desync-autottl=-$delta $e && ok=1 + done + [ "$ok" = 1 -a "$SCANLEVEL" != force ] && break + done + } + [ "$ok" = 1 ] && + { + echo "WARNING ! although autottl worked it requires testing on multiple domains to find out reliable delta" + echo "WARNING ! if a reliable delta cannot be found it's a good idea not to use autottl" + [ "$SCANLEVEL" = quick ] && return + need_wssize=0 + [ "$SCANLEVEL" = force ] || { + [ "$desync" = fake ] && need_fake=0 + [ "$desync" = fakedsplit ] && need_fakedsplit=0 + [ "$desync" = hostfakesplit ] && need_hostfakesplit=0 + [ "$desync" = fakeddisorder ] && need_fakeddisorder=0 + } + } + done + + s="http_iana_org.bin" + [ "$sec" = 0 ] || s="tls_clienthello_iana_org.bin" + for desync in syndata ${need_split:+syndata,multisplit} ${need_disorder:+syndata,multidisorder} ; do + pktws_curl_test_update_vary $1 $2 $3 $desync $e && [ "$SCANLEVEL" = quick ] && return + pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fake-syndata="$ZAPRET_BASE/files/fake/$s" $e && [ "$SCANLEVEL" = quick ] && return + done + + # do not do wssize test for http and TLS 1.3. it's useless + [ "$sec" = 1 ] || break + [ "$SCANLEVEL" = force -o "$need_wssize" = 1 ] || break + done +} +pktws_check_domain_http_bypass() +{ + # $1 - test function + # $2 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk + # $3 - domain + + local strategy + pktws_check_domain_http_bypass_ "$@" + strategy_append_extra_pktws + report_strategy $1 $3 $PKTWSD +} + +pktws_check_domain_http3_bypass_() +{ + # $1 - test function + # $2 - domain + + local f desync frag tests rep fake + + for fake in '' "--dpi-desync-fake-quic=$ZAPRET_BASE/files/fake/quic_initial_www_google_com.bin"; do + for rep in '' 2 5 10 20; do + pktws_curl_test_update $1 $2 --dpi-desync=fake ${fake:+"$fake" }${rep:+--dpi-desync-repeats=$rep} && [ "$SCANLEVEL" != force ] && { + [ "$SCANLEVEL" = quick ] && return + break + } + done + done + + [ "$IPV" = 6 ] && { + f="hopbyhop destopt" + [ -n "$IP6_DEFRAG_DISABLE" ] && f="$f ipfrag1" + for desync in $f; do + pktws_curl_test_update $1 $2 --dpi-desync=$desync && [ "$SCANLEVEL" = quick ] && return + done + } + + # OpenBSD has checksum issues with fragmented packets + [ "$UNAME" != "OpenBSD" ] && [ "$IPV" = 4 -o -n "$IP6_DEFRAG_DISABLE" ] && { + for frag in 8 16 24 32 40 64; do + tests="ipfrag2" + [ "$IPV" = 6 ] && tests="$tests hopbyhop,ipfrag2 destopt,ipfrag2" + for desync in $tests; do + pktws_curl_test_update $1 $2 --dpi-desync=$desync --dpi-desync-ipfrag-pos-udp=$frag && [ "$SCANLEVEL" = quick ] && return + done + done + } + +} +pktws_check_domain_http3_bypass() +{ + # $1 - test function + # $2 - domain + + local strategy + pktws_check_domain_http3_bypass_ "$@" + strategy_append_extra_pktws + report_strategy $1 $2 $PKTWSD +} +warn_mss() +{ + [ -n "$1" ] && echo 'WARNING ! although mss worked it may not work on all sites and will likely cause significant slowdown. it may only be required for TLS1.2, not TLS1.3' + return 0 +} +fix_seg() +{ + # $1 - split-pos + [ -n "$FIX_SEG" ] && contains "$1" , && echo "$FIX_SEG" +} + +tpws_check_domain_http_bypass_() +{ + # $1 - test function + # $2 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk + # $3 - domain + + local s mss s2 s3 oobdis pos sec="$2" + local splits_tls='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld,endhost-1' + local splits_http='method+2 midsld method+2,midsld' + + # simulteneous oob and disorder works properly only in linux. other systems retransmit oob byte without URG tcp flag and poison tcp stream. + [ "$UNAME" = Linux ] && oobdis='--oob --disorder' + if [ "$sec" = 0 ]; then + for s in '--hostcase' '--hostspell=hoSt' '--hostdot' '--hosttab' '--hostnospace' '--domcase' ; do + tpws_curl_test_update $1 $3 $s && [ "$SCANLEVEL" = quick ] && return + done + for s in 1024 2048 4096 8192 16384 ; do + tpws_curl_test_update $1 $3 --hostpad=$s && [ "$SCANLEVEL" != force ] && { + [ "$SCANLEVEL" = quick ] && return + break + } + done + for s2 in '' '--hostcase' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do + for s in $splits_http ; do + tpws_curl_test_update $1 $3 --split-pos=$s $(fix_seg $s) $s2 && [ "$SCANLEVEL" != force ] && { + [ "$SCANLEVEL" = quick ] && return + break + } + done + done + for s in '--methodspace' '--unixeol' '--methodeol'; do + 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 $(fix_seg $pos) $s2 $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && { + [ "$SCANLEVEL" = quick ] && return + need_mss=0 + break + } + done + done + for s in '' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do + for s2 in '--tlsrec=midsld' '--tlsrec=sniext+1 --split-pos=midsld' '--tlsrec=sniext+4 --split-pos=midsld' "--tlsrec=sniext+1 --split-pos=1,midsld $FIX_SEG" "--tlsrec=sniext+4 --split-pos=1,midsld $FIX_SEG" ; 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 +} +tpws_check_domain_http_bypass() +{ + # $1 - test function + # $2 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk + # $3 - domain + + local strategy + tpws_check_domain_http_bypass_ "$@" + strategy_append_extra_tpws + report_strategy $1 $3 tpws +} + +check_dpi_ip_block() +{ + # $1 - test function + # $2 - domain + + local blocked_dom="$2" + local blocked_ip blocked_ips unblocked_ip + + echo + echo "- IP block tests (requires manual interpretation)" + + echo "> testing $UNBLOCKED_DOM on it's original ip" + if curl_test $1 $UNBLOCKED_DOM; then + mdig_resolve $IPV unblocked_ip $UNBLOCKED_DOM + [ -n "$unblocked_ip" ] || { + echo $UNBLOCKED_DOM does not resolve. tests not possible. + return 1 + } + + echo "> testing $blocked_dom on $unblocked_ip ($UNBLOCKED_DOM)" + curl_test $1 $blocked_dom $unblocked_ip detail + + mdig_resolve_all $IPV blocked_ips $blocked_dom + for blocked_ip in $blocked_ips; do + echo "> testing $UNBLOCKED_DOM on $blocked_ip ($blocked_dom)" + curl_test $1 $UNBLOCKED_DOM $blocked_ip detail + done + else + echo $UNBLOCKED_DOM is not available. skipping this test. + fi +} + +curl_has_reason_to_continue() +{ + # $1 - curl return code + for c in 1 2 3 4 6 27 ; do + [ $1 = $c ] && return 1 + done + return 0 +} + +check_domain_prolog() +{ + # $1 - test function + # $2 - port + # $3 - domain + + local code + + [ "$SIMULATE" = 1 ] && return 0 + + echo + echo \* $1 ipv$IPV $3 + + echo "- checking without DPI bypass" + curl_test $1 $3 && { + report_append "$3" "$1 ipv${IPV}" "working without bypass" + [ "$SCANLEVEL" = force ] || return 1 + } + code=$? + curl_has_reason_to_continue $code || { + report_append "$3" "$1 ipv${IPV}" "test aborted, no reason to continue. curl code $(curl_translate_code $code)" + return 1 + } + return 0 +} +check_domain_http_tcp() +{ + # $1 - test function + # $2 - port + # $3 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk + # $4 - domain + + local ips + + # in case was interrupted before + pktws_ipt_unprepare_tcp $2 + ws_kill + + check_domain_prolog $1 $2 $4 || return + + [ "$SKIP_IPBLOCK" = 1 ] || check_dpi_ip_block $1 $4 + + [ "$SKIP_TPWS" = 1 ] || { + echo + tpws_check_domain_http_bypass $1 $3 $4 + } + + [ "$SKIP_PKTWS" = 1 ] || { + echo + echo preparing $PKTWSD redirection + mdig_resolve_all $IPV ips $4 + pktws_ipt_prepare_tcp $2 "$ips" + + pktws_check_domain_http_bypass $1 $3 $4 + + echo clearing $PKTWSD redirection + pktws_ipt_unprepare_tcp $2 + } +} +check_domain_http_udp() +{ + # $1 - test function + # $2 - port + # $3 - domain + + local ips + + # in case was interrupted before + pktws_ipt_unprepare_udp $2 + ws_kill + + check_domain_prolog $1 $2 $3 || return + + [ "$SKIP_PKTWS" = 1 ] || { + echo + echo preparing $PKTWSD redirection + mdig_resolve_all $IPV ips $3 + pktws_ipt_prepare_udp $2 "$ips" + + pktws_check_domain_http3_bypass $1 $3 + + echo clearing $PKTWSD redirection + pktws_ipt_unprepare_udp $2 + } +} + + +check_domain_http() +{ + # $1 - domain + check_domain_http_tcp curl_test_http $HTTP_PORT 0 $1 +} +check_domain_https_tls12() +{ + # $1 - domain + check_domain_http_tcp curl_test_https_tls12 $HTTPS_PORT 1 $1 +} +check_domain_https_tls13() +{ + # $1 - domain + check_domain_http_tcp curl_test_https_tls13 $HTTPS_PORT 2 $1 +} +check_domain_http3() +{ + # $1 - domain + check_domain_http_udp curl_test_http3 $QUIC_PORT $1 +} + +configure_ip_version() +{ + if [ "$IPV" = 6 ]; then + LOCALHOST=::1 + LOCALHOST_IPT=[${LOCALHOST}] + IPVV=6 + else + IPTABLES=iptables + LOCALHOST=127.0.0.1 + LOCALHOST_IPT=$LOCALHOST + IPVV= + fi + IPTABLES=ip${IPVV}tables +} +configure_curl_opt() +{ + # wolfssl : --tlsv1.x mandates exact ssl version, tls-max not supported + # openssl : --tlsv1.x means "version equal or greater", tls-max supported + TLSMAX12= + TLSMAX13= + curl_supports_tlsmax && { + TLSMAX12="--tls-max 1.2" + TLSMAX13="--tls-max 1.3" + } + TLS13= + curl_supports_tls13 && TLS13=1 + HTTP3= + curl_supports_http3 && HTTP3=1 + + HTTPS_HEAD=-I + [ "$CURL_HTTPS_GET" = 1 ] && HTTPS_HEAD= +} + +linux_ipv6_defrag_can_be_disabled() +{ + linux_min_version 4 16 +} + +configure_defrag() +{ + IP6_DEFRAG_DISABLE= + + [ "$IPVS" = 4 ] && return + + [ "$UNAME" = "Linux" ] && { + linux_ipv6_defrag_can_be_disabled || { + echo "WARNING ! ipv6 defrag can only be effectively disabled in linux kernel 4.16+" + echo "WARNING ! ipv6 ipfrag tests are disabled" + echo + return + } + } + + case "$FWTYPE" in + iptables) + if ipt6_has_raw ; then + if ipt6_has_frag; then + IP6_DEFRAG_DISABLE=1 + else + echo "WARNING ! ip6tables does not have '-m frag' module, ipv6 ipfrag tests are disabled" + echo + fi + else + echo "WARNING ! ip6tables raw table is not available, ipv6 ipfrag tests are disabled" + echo + fi + [ -n "$IP6_DEFRAG_DISABLE" ] && { + local ipexe="$(readlink -f $(whichq ip6tables))" + if contains "$ipexe" nft; then + echo "WARNING ! ipv6 ipfrag tests may have no effect if ip6tables-nft is used. current ip6tables point to : $ipexe" + else + echo "WARNING ! ipv6 ipfrag tests may have no effect if ip6table_raw kernel module is not loaded with parameter : raw_before_defrag=1" + fi + echo + } + ;; + *) + IP6_DEFRAG_DISABLE=1 + ;; + esac +} + +ask_params() +{ + echo + echo NOTE ! this test should be run with zapret or any other bypass software disabled, without VPN + echo + + curl_supports_connect_to || { + echo "installed curl does not support --connect-to option. pls install at least curl 7.49" + echo "current curl version:" + "$CURL" --version + exitp 1 + } + + local dom + [ -n "$DOMAINS" ] || { + DOMAINS="$DOMAINS_DEFAULT" + [ "$BATCH" = 1 ] || { + echo "specify domain(s) to test. multiple domains are space separated. URIs are supported (rutracker.org/forum/index.php)" + printf "domain(s) (default: $DOMAINS) : " + read dom + [ -n "$dom" ] && DOMAINS="$dom" + } + } + DOMAINS_COUNT="$(echo "$DOMAINS" | wc -w | trim)" + + local IPVS_def=4 + [ -n "$IPVS" ] || { + # yandex public dns + pingtest 6 2a02:6b8::feed:0ff && IPVS_def=46 + [ "$BATCH" = 1 ] || { + printf "ip protocol version(s) - 4, 6 or 46 for both (default: $IPVS_def) : " + read IPVS + } + [ -n "$IPVS" ] || IPVS=$IPVS_def + [ "$IPVS" = 4 -o "$IPVS" = 6 -o "$IPVS" = 46 ] || { + echo 'invalid ip version(s). should be 4, 6 or 46.' + exitp 1 + } + } + [ "$IPVS" = 46 ] && IPVS="4 6" + + configure_curl_opt + + [ -n "$ENABLE_HTTP" ] || { + ENABLE_HTTP=1 + [ "$BATCH" = 1 ] || { + echo + ask_yes_no_var ENABLE_HTTP "check http" + } + } + + [ -n "$ENABLE_HTTPS_TLS12" ] || { + ENABLE_HTTPS_TLS12=1 + [ "$BATCH" = 1 ] || { + echo + ask_yes_no_var ENABLE_HTTPS_TLS12 "check https tls 1.2" + } + } + + [ -n "$ENABLE_HTTPS_TLS13" ] || { + ENABLE_HTTPS_TLS13=0 + if [ -n "$TLS13" ]; then + [ "$BATCH" = 1 ] || { + echo + echo "TLS 1.3 uses encrypted ServerHello. DPI cannot check domain name in server response." + echo "This can allow more bypass strategies to work." + echo "What works for TLS 1.2 will also work for TLS 1.3 but not vice versa." + echo "Most sites nowadays support TLS 1.3 but not all. If you can't find a strategy for TLS 1.2 use this test." + echo "TLS 1.3 only strategy is better than nothing." + ask_yes_no_var ENABLE_HTTPS_TLS13 "check https tls 1.3" + } + else + echo + echo "installed curl version does not support TLS 1.3 . tests disabled." + fi + } + + [ -n "$ENABLE_HTTP3" ] || { + ENABLE_HTTP3=0 + if [ -n "$HTTP3" ]; then + ENABLE_HTTP3=1 + [ "$BATCH" = 1 ] || { + echo + echo "make sure target domain(s) support QUIC or result will be negative in any case" + ask_yes_no_var ENABLE_HTTP3 "check http3 QUIC" + } + else + echo + echo "installed curl version does not support http3 QUIC. tests disabled." + fi + } + + [ -n "$REPEATS" ] || { + [ "$BATCH" = 1 ] || { + echo + echo "sometimes ISPs use multiple DPIs or load balancing. bypass strategies may work unstable." + printf "how many times to repeat each test (default: 1) : " + read REPEATS + } + REPEATS=$((0+${REPEATS:-1})) + [ "$REPEATS" = 0 ] && { + echo invalid repeat count + exitp 1 + } + } + [ -z "$PARALLEL" -a $REPEATS -gt 1 ] && { + PARALLEL=0 + [ "$BATCH" = 1 ] || { + echo + echo "parallel scan can greatly increase speed but may also trigger DDoS protection and cause false result" + ask_yes_no_var PARALLEL "enable parallel scan" + } + } + PARALLEL=${PARALLEL:-0} + + [ -n "$SCANLEVEL" ] || { + SCANLEVEL=standard + [ "$BATCH" = 1 ] || { + echo + echo quick - scan as fast as possible to reveal any working strategy + echo standard - do investigation what works on your DPI + echo force - scan maximum despite of result + ask_list SCANLEVEL "quick standard force" "$SCANLEVEL" + # disable tpws checks by default in quick mode + [ "$SCANLEVEL" = quick -a -z "$SKIP_TPWS" -a "$UNAME" != Darwin ] && SKIP_TPWS=1 + } + } + + echo + + configure_defrag +} + + + +ping_with_fix() +{ + local ret + $PING $2 $1 >/dev/null 2>/dev/null + ret=$? + # can be because of unsupported -4 option + if [ "$ret" = 2 -o "$ret" = 64 ]; then + ping $2 $1 >/dev/null + else + return $ret + fi +} + +pingtest() +{ + # $1 - ip version : 4 or 6 + # $2 - domain or ip + + # ping command can vary a lot. some implementations have -4/-6 options. others don.t + # WARNING ! macos ping6 command does not have timeout option. ping6 will fail + + local PING=ping ret + if [ "$1" = 6 ]; then + if exists ping6; then + PING=ping6 + else + PING="ping -6" + fi + else + if [ "$UNAME" = Darwin -o "$UNAME" = FreeBSD -o "$UNAME" = OpenBSD ]; then + # ping by default pings ipv4, ping6 only pings ipv6 + # in FreeBSD -4/-6 options are supported, in others not + PING=ping + else + # this can be linux or cygwin + # in linux it's not possible for sure to figure out if it supports -4/-6. only try and check for result code=2 (invalid option) + PING="ping -4" + fi + fi + case "$UNAME" in + Darwin) + $PING -c 1 -t 1 $2 >/dev/null 2>/dev/null + # WARNING ! macos ping6 command does not have timeout option. ping6 will fail. but without timeout is not an option. + ;; + OpenBSD) + $PING -c 1 -w 1 $2 >/dev/null + ;; + CYGWIN) + if starts_with "$(which ping)" /cygdrive; then + # cygwin does not have own ping by default. use windows PING. + $PING -n 1 -w 1000 $2 >/dev/null + else + ping_with_fix $2 '-c 1 -w 1' + fi + ;; + *) + ping_with_fix $2 '-c 1 -W 1' + ;; + esac +} +dnstest() +{ + # $1 - dns server. empty for system resolver + "$LOOKUP" iana.org $1 >/dev/null 2>/dev/null +} +find_working_public_dns() +{ + local dns + for dns in $DNSCHECK_DNS; do + pingtest 4 $dns && dnstest $dns && { + PUBDNS=$dns + return 0 + } + done + return 1 +} +lookup4() +{ + # $1 - domain + # $2 - DNS + case "$LOOKUP" in + nslookup) + if is_linked_to_busybox nslookup; then + nslookup $1 $2 2>/dev/null | sed -e '1,3d' -nre 's/^.*:[^0-9]*(([0-9]{1,3}\.){3}[0-9]{1,3}).*$/\1/p' + else + nslookup $1 $2 2>/dev/null | sed -e '1,3d' -nre 's/^[^0-9]*(([0-9]{1,3}\.){3}[0-9]{1,3}).*$/\1/p' + fi + ;; + host) + host -t A $1 $2 | grep "has address" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' + ;; + esac +} +check_dns_spoof() +{ + # $1 - domain + # $2 - public DNS + + # 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" +} +check_dns_cleanup() +{ + rm -f "$DNSCHECK_DIG1" "$DNSCHECK_DIG2" "$DNSCHECK_DIGS" 2>/dev/null +} +check_dns_() +{ + local C1 C2 dom + + DNS_IS_SPOOFED=0 + + [ "$SKIP_DNSCHECK" = 1 ] && return 0 + + echo \* checking DNS + + [ -f "$DNSCHECK_DIGS" ] && rm -f "$DNSCHECK_DIGS" + + dnstest || { + echo -- DNS is not working. It's either misconfigured or blocked or you don't have inet access. + return 1 + } + echo system DNS is working + + if find_working_public_dns ; then + echo comparing system resolver to public DNS : $PUBDNS + for dom in $DNSCHECK_DOM; do + if check_dns_spoof "$dom" $PUBDNS ; then + echo $dom : MISMATCH + echo -- system resolver : + cat "$DNSCHECK_DIG1" + echo -- $PUBDNS : + cat "$DNSCHECK_DIG2" + check_dns_cleanup + echo -- POSSIBLE DNS HIJACK DETECTED. ZAPRET WILL NOT HELP YOU IN CASE DNS IS SPOOFED !!! + echo -- DNS CHANGE OR DNSCRYPT MAY BE REQUIRED + DNS_IS_SPOOFED=1 + return 1 + else + echo $dom : OK + cat "$DNSCHECK_DIG1" >>"$DNSCHECK_DIGS" + fi + done + else + echo no working public DNS was found. looks like public DNS blocked. + for dom in $DNSCHECK_DOM; do echo $dom; done | "$MDIG" --threads=10 --family=4 >"$DNSCHECK_DIGS" + fi + + echo "checking resolved IP uniqueness for : $DNSCHECK_DOM" + echo "censor's DNS can return equal result for multiple blocked domains." + C1=$(wc -l <"$DNSCHECK_DIGS") + C2=$(sort -u "$DNSCHECK_DIGS" | wc -l) + [ "$C1" -eq 0 ] && + { + echo -- DNS is not working. It's either misconfigured or blocked or you don't have inet access. + check_dns_cleanup + return 1 + } + [ "$C1" = "$C2" ] || + { + echo system dns resolver has returned equal IPs for some domains checked above \($C1 total, $C2 unique\) + echo non-unique IPs : + sort "$DNSCHECK_DIGS" | uniq -d + echo -- POSSIBLE DNS HIJACK DETECTED. ZAPRET WILL NOT HELP YOU IN CASE DNS IS SPOOFED !!! + echo -- DNSCRYPT MAY BE REQUIRED + check_dns_cleanup + DNS_IS_SPOOFED=1 + return 1 + } + echo all resolved IPs are unique + echo -- DNS looks good + echo -- NOTE this check is Russia targeted. In your country other domains may be blocked. + check_dns_cleanup + return 0 +} + +check_dns() +{ + local r + check_dns_ + r=$? + [ "$DNS_IS_SPOOFED" = 1 ] && SECURE_DNS=${SECURE_DNS:-1} + [ "$SECURE_DNS" = 1 ] && { + doh_find_working || { + echo could not find working DoH server. exiting. + exitp 7 + } + } + return $r +} + +unprepare_all() +{ + # make sure we are not in a middle state that impacts connectivity + ws_kill + wait + [ -n "$IPV" ] && { + pktws_ipt_unprepare_tcp $HTTP_PORT + pktws_ipt_unprepare_tcp $HTTPS_PORT + pktws_ipt_unprepare_udp $QUIC_PORT + } + cleanup + rm -f "${HDRTEMP}"* "${PARALLEL_OUT}"* +} +sigint() +{ + echo + echo terminating... + unprepare_all + exitp 1 +} +sigint_cleanup() +{ + cleanup + exit 1 +} +sigsilent() +{ + # must not write anything here to stdout + unprepare_all + exit 1 +} + +fsleep_setup +fix_sbin_path +check_system +check_already +# no divert sockets in MacOS +[ "$UNAME" = "Darwin" ] && SKIP_PKTWS=1 +[ "$UNAME" != CYGWIN -a "$SKIP_PKTWS" != 1 ] && require_root +check_prerequisites +trap sigint_cleanup INT +check_dns +check_virt +ask_params +trap - INT + +PID= +NREPORT= +unset WF +trap sigint INT +trap sigsilent PIPE +trap sigsilent HUP +for dom in $DOMAINS; do + for IPV in $IPVS; do + configure_ip_version + [ "$ENABLE_HTTP" = 1 ] && { + [ "$SKIP_IPBLOCK" = 1 ] || check_domain_port_block $dom $HTTP_PORT + check_domain_http $dom + } + [ "$ENABLE_HTTPS_TLS12" = 1 -o "$ENABLE_HTTPS_TLS13" = 1 ] && [ "$SKIP_IPBLOCK" != 1 ] && check_domain_port_block $dom $HTTPS_PORT + [ "$ENABLE_HTTPS_TLS12" = 1 ] && check_domain_https_tls12 $dom + [ "$ENABLE_HTTPS_TLS13" = 1 ] && check_domain_https_tls13 $dom + [ "$ENABLE_HTTP3" = 1 ] && check_domain_http3 $dom + done +done +trap - HUP +trap - PIPE +trap - INT + +cleanup + +echo +echo \* SUMMARY +report_print +[ "$DOMAINS_COUNT" -gt 1 ] && { + echo + echo \* COMMON + result_intersection_print + echo + [ "$SCANLEVEL" = force ] || { + echo "blockcheck optimizes test sequence. To save time some strategies can be skipped if their test is considered useless." + echo "That's why COMMON intersection can miss strategies that would work for all domains." + echo "Use \"force\" scan level to test all strategies and generate trustable intersection." + echo "Current scan level was \"$SCANLEVEL\"". + } +} +echo +echo "Please note this SUMMARY does not guarantee a magic pill for you to copy/paste and be happy." +echo "Understanding how strategies work is very desirable." +echo "This knowledge allows to understand better which strategies to prefer and which to avoid if possible, how to combine strategies." +echo "Blockcheck does it's best to prioritize good strategies but it's not bullet-proof." +echo "It was designed not as magic pill maker but as a DPI bypass test tool." + +exitp 0 diff --git a/blockcheck/zapret/blog.sh b/blockcheck/zapret/blog.sh new file mode 100644 index 0000000..1bd7f84 --- /dev/null +++ b/blockcheck/zapret/blog.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +EXEDIR="$(dirname "$0")" +EXEDIR="$(cd "$EXEDIR"; pwd)" + +"$EXEDIR/blockcheck.sh" 2>&1 | tee "$EXEDIR/../blockcheck.log" +# windows 7 notepad does not view unix EOL correctly +unix2dos "$EXEDIR/../blockcheck.log" diff --git a/blockcheck/zapret/blog_kyber.sh b/blockcheck/zapret/blog_kyber.sh new file mode 100644 index 0000000..a7bd700 --- /dev/null +++ b/blockcheck/zapret/blog_kyber.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +EXEDIR="$(dirname "$0")" +EXEDIR="$(cd "$EXEDIR"; pwd)" + +CURL=curl-kyber exec "$EXEDIR/blog.sh" diff --git a/blockcheck/zapret/common/base.sh b/blockcheck/zapret/common/base.sh new file mode 100644 index 0000000..bba049f --- /dev/null +++ b/blockcheck/zapret/common/base.sh @@ -0,0 +1,460 @@ +which() +{ + # on some systems 'which' command is considered deprecated and not installed by default + # 'command -v' replacement does not work exactly the same way. it outputs shell aliases if present + # $1 - executable name + local IFS=: + [ "$1" != "${1#/}" ] && [ -x "$1" ] && { + echo "$1" + return 0 + } + for p in $PATH; do + [ -x "$p/$1" ] && { + echo "$p/$1" + return 0 + } + done + return 1 +} +exists() +{ + which "$1" >/dev/null 2>/dev/null +} +existf() +{ + type "$1" >/dev/null 2>/dev/null +} +whichq() +{ + which $1 2>/dev/null +} +exist_all() +{ + while [ -n "$1" ]; do + exists "$1" || return 1 + shift + done + return 0 +} +on_off_function() +{ + # $1 : function name on + # $2 : function name off + # $3 : 0 - off, 1 - on + local F="$1" + [ "$3" = "1" ] || F="$2" + shift + shift + shift + "$F" "$@" +} +contains() +{ + # check if substring $2 contains in $1 + [ "${1#*$2}" != "$1" ] +} +starts_with() +{ + # $1 : what + # $2 : starts with + case "$1" in + "$2"*) + return 0 + ;; + esac + return 1 +} +extract_arg() +{ + # $1 - arg number + # $2,$3,... - args + local n=$1 + while [ -n "$1" ]; do + shift + [ $n -eq 1 ] && { echo "$1"; return 0; } + n=$(($n-1)) + done + return 1 +} +find_str_in_list() +{ + # $1 - string + # $2 - space separated values + local v + [ -n "$1" ] && { + for v in $2; do + [ "$v" = "$1" ] && return 0 + done + } + return 1 +} +end_with_newline() +{ + local c="$(tail -c 1)" + [ "$c" = "" ] +} +trim() +{ + awk '{gsub(/^ +| +$/,"")}1' +} +split_by_separator() +{ + # $1 - string + # $2 - separator + # $3 - var name to get "before" part + # $4 - var name to get "after" part + local before="${1%%$2*}" + local after="${1#*$2}" + [ "$after" = "$1" ] && after= + [ -n "$3" ] && eval $3="\$before" + [ -n "$4" ] && eval $4="\$after" +} +tolower() +{ + echo "$@" | tr 'A-Z' 'a-z' +} + +dir_is_not_empty() +{ + # $1 - directory + local n + [ -d "$1" ] || return 1 + n=$(ls "$1" | wc -c | xargs) + [ "$n" != 0 ] +} + +append_separator_list() +{ + # $1 - var name to receive result + # $2 - separator + # $3 - quoter + # $4,$5,... - elements + local _var="$1" sep="$2" quo="$3" i + + eval i="\$$_var" + shift; shift; shift + while [ -n "$1" ]; do + if [ -n "$i" ] ; then + i="$i$sep$quo$1$quo" + else + i="$quo$1$quo" + fi + shift + done + eval $_var="\$i" +} +make_separator_list() +{ + eval $1='' + append_separator_list "$@" +} +make_comma_list() +{ + # $1 - var name to receive result + # $2,$3,... - elements + local var="$1" + shift + make_separator_list $var , '' "$@" +} +make_quoted_comma_list() +{ + # $1 - var name to receive result + # $2,$3,... - elements + local var="$1" + shift + make_separator_list $var , '"' "$@" +} +unique() +{ + local i + for i in "$@"; do echo $i; done | sort -u | xargs +} + +is_linked_to_busybox() +{ + local IFS F P + + IFS=: + for path in $PATH; do + F=$path/$1 + P="$(readlink $F)" + if [ -z "$P" ] && [ -x $F ] && [ ! -L $F ]; then return 1; fi + [ "${P%busybox*}" != "$P" ] && return + done +} +get_dir_inode() +{ + local dir="$1" + [ -L "$dir" ] && dir=$(readlink "$dir") + ls -id "$dir" | awk '{print $1}' +} + +linux_min_version() +{ + # $1 - major ver + # $2 - minor ver + local V1=$(sed -nre 's/^Linux version ([0-9]+)\.[0-9]+.*$/\1/p' /proc/version) + local V2=$(sed -nre 's/^Linux version [0-9]+\.([0-9]+).*$/\1/p' /proc/version) + [ -n "$V1" -a -n "$V2" ] && [ "$V1" -gt "$1" -o "$V1" -eq "$1" -a "$V2" -ge "$2" ] +} +linux_get_subsys() +{ + local INIT="$(sed 's/\x0/\n/g' /proc/1/cmdline | head -n 1)" + + [ -L "$INIT" ] && INIT=$(readlink "$INIT") + INIT="$(basename "$INIT")" + if [ -f "/etc/openwrt_release" ] && [ "$INIT" = "procd" ] ; then + SUBSYS=openwrt + elif [ -x "/bin/ndm" ] ; then + SUBSYS=keenetic + else + # generic linux + SUBSYS= + fi +} +openwrt_fw3() +{ + [ ! -x /sbin/fw4 -a -x /sbin/fw3 ] +} +openwrt_fw4() +{ + [ -x /sbin/fw4 ] +} +openwrt_fw3_integration() +{ + [ "$FWTYPE" = iptables ] && openwrt_fw3 +} + +create_dev_stdin() +{ + [ -e /dev/stdin ] || ln -s /proc/self/fd/0 /dev/stdin +} + +call_for_multiple_items() +{ + # $1 - function to get an item + # $2 - variable name to put result into + # $3 - space separated parameters to function $1 + + local i item items + for i in $3; do + $1 item $i + [ -n "$item" ] && { + if [ -n "$items" ]; then + items="$items $item" + else + items="$item" + fi + } + done + eval $2=\"$items\" +} + +fix_sbin_path() +{ + local IFS=':' + printf "%s\n" $PATH | grep -Fxq '/usr/sbin' || PATH="/usr/sbin:$PATH" + printf "%s\n" $PATH | grep -Fxq '/sbin' || PATH="/sbin:$PATH" + export PATH +} + +# it can calculate floating point expr +calc() +{ + LC_ALL=C awk "BEGIN { print $*}"; +} + +fsleep_setup() +{ + [ -n "$FSLEEP" ] || { + if sleep 0.001 2>/dev/null; then + FSLEEP=1 + elif busybox usleep 1 2>/dev/null; then + FSLEEP=2 + else + local errtext="$(read -t 0.001 2>&1)" + if [ -z "$errtext" ]; then + FSLEEP=3 + # newer openwrt has ucode with system function that supports timeout in ms + elif ucode -e "system(['sleep','1'], 1)" 2>/dev/null; then + FSLEEP=4 + # older openwrt may have lua and nixio lua module + elif lua -e 'require "nixio".nanosleep(0,1)' 2>/dev/null ; then + FSLEEP=5 + else + FSLEEP=0 + fi + fi + } +} +msleep() +{ + # $1 - milliseconds + case "$FSLEEP" in + 1) + sleep $(calc $1/1000) + ;; + 2) + busybox usleep $(calc $1*1000) + ;; + 3) + read -t $(calc $1/1000) + ;; + 4) + ucode -e "system(['sleep','2147483647'], $1)" + ;; + 5) + lua -e "require 'nixio'.nanosleep($(($1/1000)),$(calc $1%1000*1000000))" + ;; + *) + sleep $((($1+999)/1000)) + esac +} +minsleep() +{ + msleep 100 +} + +replace_char() +{ + local a="$1" + local b="$2" + shift; shift + echo "$@" | tr "$a" "$b" +} + +replace_str() +{ + local a=$(echo "$1" | sed 's/\//\\\//g') + local b=$(echo "$2" | sed 's/\//\\\//g') + shift; shift + echo "$@" | sed "s/$a/$b/g" +} + +setup_md5() +{ + [ -n "$MD5" ] && return + MD5=md5sum + exists $MD5 || MD5=md5 +} + +md5f() +{ + setup_md5 + $MD5 | cut -d ' ' -f1 +} + +setup_random() +{ + [ -n "$RCUT" ] && return + RCUT="cut -c 1-17" + # some shells can operate with 32 bit signed int + [ $((0x100000000)) = 0 ] && RCUT="cut -c 1-9" +} + +random() +{ + # $1 - min, $2 - max + local r rs + setup_random + if [ -c /dev/urandom ]; then + read rs /dev/null + elif exists pidof; then + pidof $1 >/dev/null + else + return 1 + fi +} + +win_process_exists() +{ + tasklist /NH /FI "IMAGENAME eq ${1}.exe" | grep -q "^${1}.exe" +} + +alloc_num() +{ + # $1 - source var name + # $2 - target var name + # $3 - min + # $4 - max + + local v + eval v="\$$2" + # do not replace existing value + [ -n "$v" ] && return + eval v="\$$1" + [ -n "$v" ] || v=$3 + eval $2="$v" + v=$((v + 1)) + [ $v -gt $4 ] && v=$3 + eval $1="$v" +} + +std_ports() +{ + TPWS_PORTS_IPT=$(replace_char - : $TPWS_PORTS) + NFQWS_PORTS_TCP_IPT=$(replace_char - : $NFQWS_PORTS_TCP) + NFQWS_PORTS_TCP_KEEPALIVE_IPT=$(replace_char - : $NFQWS_PORTS_TCP_KEEPALIVE) + NFQWS_PORTS_UDP_IPT=$(replace_char - : $NFQWS_PORTS_UDP) + NFQWS_PORTS_UDP_KEEPALIVE_IPT=$(replace_char - : $NFQWS_PORTS_UDP_KEEPALIVE) +} + +has_bad_ws_options() +{ + # $1 - nfqws/tpws opts + + contains "$1" "--ipset" && { + echo + echo "WARNING !!! --ipset parameter is present" + echo "It's OK if you only specialize already redirected traffic and also process the rest." + echo "If you redirect port X to process several IPs from the list and do nothing with the rest - IT'S VERY INEFFECTIVE !" + echo "Kernel ipsets should be used instead. Write custom scripts and filter IPs in kernel." + echo + } + + return 1 +} +check_bad_ws_options() +{ + # $1 - 0 = stop, 1 = start + # $2 - nfqws/tpws options + if [ "$1" = 1 ] && has_bad_ws_options "$2"; then + echo "!!! REFUSING TO USE BAD OPTIONS : $2" + help_bad_ws_options + return 1 + else + return 0 + fi +} +help_bad_ws_options() +{ + echo "WARNING ! BAD options detected" +} diff --git a/blockcheck/zapret/common/dialog.sh b/blockcheck/zapret/common/dialog.sh new file mode 100644 index 0000000..ec1c9aa --- /dev/null +++ b/blockcheck/zapret/common/dialog.sh @@ -0,0 +1,57 @@ +read_yes_no() +{ + # $1 - default (Y/N) + local A + read A + [ -z "$A" ] || ([ "$A" != "Y" ] && [ "$A" != "y" ] && [ "$A" != "N" ] && [ "$A" != "n" ]) && A=$1 + [ "$A" = "Y" ] || [ "$A" = "y" ] || [ "$A" = "1" ] +} +ask_yes_no() +{ + # $1 - default (Y/N or 0/1) + # $2 - text + local DEFAULT=$1 + [ "$1" = "1" ] && DEFAULT=Y + [ "$1" = "0" ] && DEFAULT=N + [ -z "$DEFAULT" ] && DEFAULT=N + printf "$2 (default : $DEFAULT) (Y/N) ? " + read_yes_no $DEFAULT +} +ask_yes_no_var() +{ + # $1 - variable name for answer : 0/1 + # $2 - text + local DEFAULT + eval DEFAULT="\$$1" + if ask_yes_no "$DEFAULT" "$2"; then + eval $1=1 + else + eval $1=0 + fi +} +ask_list() +{ + # $1 - mode var + # $2 - space separated value list + # $3 - (optional) default value + local M_DEFAULT + eval M_DEFAULT="\$$1" + local M_DEFAULT_VAR="$M_DEFAULT" + local M="" m + + [ -n "$3" ] && { find_str_in_list "$M_DEFAULT" "$2" || M_DEFAULT="$3" ;} + + n=1 + for m in $2; do + echo $n : $m + n=$(($n+1)) + done + printf "your choice (default : $M_DEFAULT) : " + read m + [ -n "$m" ] && M=$(echo $2 | cut -d ' ' -f$m 2>/dev/null) + [ -z "$M" ] && M="$M_DEFAULT" + echo selected : $M + eval $1="\"$M\"" + + [ "$M" != "$M_DEFAULT_VAR" ] +} diff --git a/blockcheck/zapret/common/elevate.sh b/blockcheck/zapret/common/elevate.sh new file mode 100644 index 0000000..bc86a96 --- /dev/null +++ b/blockcheck/zapret/common/elevate.sh @@ -0,0 +1,28 @@ +require_root() +{ + local exe preserve_env + echo \* checking privileges + [ $(id -u) -ne "0" ] && { + echo root is required + exe="$EXEDIR/$(basename "$0")" + exists sudo && { + echo elevating with sudo + exec sudo -E sh "$exe" + } + exists su && { + echo elevating with su + case "$UNAME" in + Linux) + preserve_env="--preserve-environment" + ;; + FreeBSD|OpenBSD|Darwin) + preserve_env="-m" + ;; + esac + exec su $preserve_env root -c "sh \"$exe\"" + } + echo su or sudo not found + exitp 2 + } + HAVE_ROOT=1 +} diff --git a/blockcheck/zapret/common/fwtype.sh b/blockcheck/zapret/common/fwtype.sh new file mode 100644 index 0000000..61390bb --- /dev/null +++ b/blockcheck/zapret/common/fwtype.sh @@ -0,0 +1,64 @@ +linux_ipt_avail() +{ + exists iptables && exists ip6tables +} +linux_maybe_iptables_fwtype() +{ + linux_ipt_avail && FWTYPE=iptables +} +linux_nft_avail() +{ + exists nft +} +linux_fwtype() +{ + [ -n "$FWTYPE" ] && return + + FWTYPE=unsupported + + linux_get_subsys + if [ "$SUBSYS" = openwrt ] ; then + # linux kernel is new enough if fw4 is there + if [ -x /sbin/fw4 ] && linux_nft_avail ; then + FWTYPE=nftables + else + linux_maybe_iptables_fwtype + fi + else + SUBSYS= + # generic linux + # flowtable is implemented since kernel 4.16 + if linux_nft_avail && linux_min_version 4 16; then + FWTYPE=nftables + else + linux_maybe_iptables_fwtype + fi + fi + + export FWTYPE +} + +get_fwtype() +{ + [ -n "$FWTYPE" ] && return + + local UNAME="$(uname)" + + case "$UNAME" in + Linux) + linux_fwtype + ;; + FreeBSD) + if exists ipfw ; then + FWTYPE=ipfw + else + FWTYPE=unsupported + fi + ;; + *) + FWTYPE=unsupported + ;; + esac + + export FWTYPE +} diff --git a/blockcheck/zapret/common/virt.sh b/blockcheck/zapret/common/virt.sh new file mode 100644 index 0000000..6e566d6 --- /dev/null +++ b/blockcheck/zapret/common/virt.sh @@ -0,0 +1,39 @@ +get_virt() +{ + local vm s v UNAME + UNAME=$(uname) + case "$UNAME" in + Linux) + if exists systemd-detect-virt; then + vm=$(systemd-detect-virt --vm) + elif [ -f /sys/class/dmi/id/product_name ]; then + read s v`S1dvdT;`GO${!>Dbb;`8!TfV>h5tA5rTL!&CigN9a>K-p9Plp`j0 literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/dht_get_peers.bin b/blockcheck/zapret/files/fake/dht_get_peers.bin new file mode 100644 index 0000000..916bc10 --- /dev/null +++ b/blockcheck/zapret/files/fake/dht_get_peers.bin @@ -0,0 +1,2 @@ +d1:ad2:id20:.+NA-¢ÔutÚÛE–wΑiJ·9:info_hash20:; +ÂÅÙ侧¾“äÙOÁ£2IÂe1:q9:get_peers1:t2:äâ1:v4:LT1:y1:qe \ No newline at end of file diff --git a/blockcheck/zapret/files/fake/discord-ip-discovery-with-port.bin b/blockcheck/zapret/files/fake/discord-ip-discovery-with-port.bin new file mode 100644 index 0000000000000000000000000000000000000000..44a3fbec20bd7de4f9747997887fb8460d4a2fe7 GIT binary patch literal 74 UcmZQzWN>3(adlvz5WIc>06N3(KC_;IVgLYm$pOXy literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/dtls_clienthello_w3_org.bin b/blockcheck/zapret/files/fake/dtls_clienthello_w3_org.bin new file mode 100644 index 0000000000000000000000000000000000000000..8d90faf51272dfe4526dafd077fee2cf09de4243 GIT binary patch literal 226 zcmWgp_n!dSXI#54111AFmTe-1beo;D*!@|tK$i%?Kzyrjx4B`xO43Z2I49Y-- zVn8eo#Jmg!40dpzOw7!TOpMG-OiV0H ItW0c70Fc2gFaQ7m literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/http_iana_org.bin b/blockcheck/zapret/files/fake/http_iana_org.bin new file mode 100644 index 0000000..3ae50b3 --- /dev/null +++ b/blockcheck/zapret/files/fake/http_iana_org.bin @@ -0,0 +1,9 @@ +GET / HTTP/1.1 +Host: www.iana.org +Connection: keep-alive +Upgrade-Insecure-Requests: 1 +User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4300.0 Safari/537.36 +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 +Accept-Encoding: gzip, deflate +Accept-Language: en-US,en;q=0.9,ru;q=0.8 + diff --git a/blockcheck/zapret/files/fake/isakmp_initiator_request.bin b/blockcheck/zapret/files/fake/isakmp_initiator_request.bin new file mode 100644 index 0000000000000000000000000000000000000000..c58f1d9979f987978fb1f628c51e38bdc3d9535d GIT binary patch literal 584 zcmV-O0=NAD00030N>G{z4Q@k@E;nf|%j#7%AR`C>0003100KlK00Jlg0RRMv`;dm4 z5FaU}X{f=&AoY*=9u&Rhh1_#6jqt5~0d`&PX_4iC?KZ)aqas~j@p<|5a6o-)ho@uz zgaNL!zPJq6Arf20Y3!O zbpJY!B&E|`d5mbOJ~D|>VJWqUgD$IUKFWce$OMErh2w9K0$~HBEhrH@5XH)i50ek* zr|jSgMH=pR^`bhYXb*?0vA1z;?)WaMrAZj`;DOkpm^r2 zy|$1b(+?lF|F%I}a2J(+vz^?L;8!>@kDH)*Gb_ZMYs2UKDk@+>cN7C;hD?Te3Q(+( zdTqEUDzjPMFe#x9B{ZEU$TXqSTF~DDTILJX7lpBK-iqD;S>6zN!E2&V1b@CCaki2A z#3pm>`3V;u5%a8Sv8{99aZR3XP|K*CZwGfBJJGEI{$77&1jT}qIr8QFxjJi1yyc?` zGP693n1G^4i0?fVgB#ZTg^^Gt0VLLMNnJ%-TrE0Ks`tZZR1VwS1*oC;ppSY4_)DO$ WbcqMyhhYh0(yRu;B+yL}f;EYz1Pdns literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/quic_initial_facebook_com.bin b/blockcheck/zapret/files/fake/quic_initial_facebook_com.bin new file mode 100644 index 0000000000000000000000000000000000000000..5d21a5927a7b06adfb99ddfc48d9590c8a596464 GIT binary patch literal 1200 zcmV;h1W)_V000016gruq*wYT$J`J?I59H{X2d>QDOccila+`}`c8!_0eOUUwEEmfI z6uX|y0v#Oyw!GnYUNw7iI>yjsW#TDHKRry0j!m+*O~Jd6rS>=-#eRr_NI^R&1lS9d1WDSR3D&^DS1M=NFCCNO!Si+wlQFW z$istR@*ZM|k92~$1pHaEDuKU{MjmTJV$i($M^jkPs{+QixUoRW*FlB8iN0r$qG=<5 zDtHBURbwyi9OeoI(uhB{Z(y?8>4SdcebN|-yC0=kek?|301Y58hhb{3u{I@Sj)iyM<&! z!Af|P?*4ZNFn>86>gaUqt{P=1$Nyx<3;xiAsP6a-07+v)@=ll+h7ZHX85S0 zPkus0@cQd{?G7S>(gG?)-^M9=mq3MEo*%HKlST15%)#Z34njYiE6R;AoPOc4HGMT# zta~c_bQWz%X&JArvmf8Y%uiw4fkjKwLa}R)cM|sI3Aknu9~&^eDAjd2s<0eSdtq$^ zqYW3IRP_H7bMJYR0WIO`Ir@CC`gT!$ z9ResO_!0bsY*_~Ou8x!`^srkZmZjdkB4k7?b>1xeC=o2`8&2+U#B1B9kT@ zHPy>^^>{`x0TM2vOt1(O52Jr7(!yVQBFeaJDL{Pm4GOhHn8}|G9bW%J0Fx%H9LacU zeQ447xe+<%q7m3~)GW{FCGT3xfZZc_Zl*XRPB3Lj7c9`zJlk~eL`g4c6&y@bbF~Pp zKf|sN$^RH{kzrFGe>)BMJ?E>u=2uuRSC~Vi`f?r$^N>tewY5>a5oW(uMtm8As-jr& z?+-KV#9otVD>S+5JRdG7g3=8E3hsw5J$^-@H*dmk&N?v6@=M)FSnu2P8F*ceOdt^*~Nk0Xtk7tr!VA-rKE43bM>gKEP} z5<>k&<&aCov+#3>1gFh{#ZqJ_Qw&vvUva4`BtR%d3<-4~NTFM_<$oNh3|I$| zRP1|AnF>;sOpPaVWK-md7r$Z^HtBL4@4BGeC{0`)+>_M=}y@j_WkZSxc2Oi=g-3J(Zg2o(=y3W>1m8iGARnCJrHtNj Oz&ejo+=e$P_+sWMkxVZD literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/quic_initial_facebook_com_quiche.bin b/blockcheck/zapret/files/fake/quic_initial_facebook_com_quiche.bin new file mode 100644 index 0000000000000000000000000000000000000000..84dceabb6676148afae10e33afac59ac0ce3a584 GIT binary patch literal 1200 zcmX@az`(#LV7Y0!Kqk{P*VN*JN@6H|wNl&pUZ1 zUsN#l{=J*mB6DXX@0fo{I6H*fPWE&2`dMDzR_?#h`J}V{r}<0mg^$#gCwFA7U!-ol z)bZt&!=b0>V}~)r)cB{c*+i!uj;|#wllf_B(D{Yx(QOs@NN9f27vW3D0buEcAM% zxACk!M}+3TWo4ZCSj6z1Yc|UiB?g<`bob-_Jqq%HOq1S)RCxu&irC+34EkKTbK!-h z6VE1=9lpBBiu*>s0ITSK#yb6VA#n@k!gr{PWk3G&q9J#%#V?zyLr&0Qusph(l>s|B8U&h>&OR2SspOz&yI*68{ph z+Qvp-dNQA&BlkFH`6S_CbN=Q-WXbV|TWl(+9QWC~j8Yi`0z`V-Pgs%m&M7tJ{c+0H zRJoV~!)b9B>nVG75U5m4p6H{&q(G6*;(?g6gwIonMj>*WjprE7(~u=8&BtQACJXl@ z|03>B^QphWR)SwhGp>uEne&r6e8UNPdv)=N0*kvr#DmLgc#$gGEfo=-n0U;TBMk^7sJc8JRS@JB4}k^VVFKWOsSGDuCve`kOvzoLQ5d(&i+i6SM5|3o3YabL6t9; ziX&VGm*JvSZS&eY=DYDN0$=^8J(3FrMpZr$)^_m=s(FRj`Ia72B6JD<-`}NNuhm(J zUeRJzVK;wRy^vcCZ?6Oz=B{Fa82e#>XWlvigiDQAe4U;R<9;~lf~_0uLbs0L)bCS- z$0XfcKQsr?h)HzY>x9eM7O7LQ;XVo04(1AB4HDxs1wi%phXIpkvB^|QuO(>Il=x`R z%Uk9!gk^X}MyWHm!@ff-`3JT_s|ca^PZcgJ4xw-y@dsFGuFGOi_;Y$p*<7 z{4yQsa{q->yyi6dm#w+TeB9c-MlW_KFk&ma|sM*}I%odlEJjwgaf6N`8QGI7f`XN~;oeqzR7#bN^U=d$3RYwsi zh$iZX%3$hlI^BI)s7n8%iUM0}ouW#y3{TliFq1TqlS=K%ks7vy-mwd`h|gWnLSFyZ zI>@0Q{TTNbpBF_#`u08g@wyue0#R{qr4qbPP%y}*_Dl!siFByaI_L*CWs46_?F?p@ sZjPZ*)!b|n*P|{xE-9-eZyHsXHlyyMfC((yl^&7u?&{4TB3tHud~L2;6#xJL literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/quic_initial_rr1---sn-xguxaxjvh-n8me_googlevideo_com_kyber_2.bin b/blockcheck/zapret/files/fake/quic_initial_rr1---sn-xguxaxjvh-n8me_googlevideo_com_kyber_2.bin new file mode 100644 index 0000000000000000000000000000000000000000..ec4119939afe5a74ff5a074655a11907cc3a8bcb GIT binary patch literal 1230 zcmV;<1Tp)|000012>q9J#%#V?zyLr&0Qusph(l>s|B8U&h>&OR2SspOz&yI*68{ph z+Qvp-dNQA&BlkFH`6S_CbN=Q-WXbV|TWl(+9QWC~j8Yi`0z`T;WSY+MPI5k|j0Wb& znVynCD3z$qlL(b&>V3EFnM$W_i7-69#77u1 zezctv-kQ6WWyHQ+Lp63G@umD&)*7u=C870TZi#MT76NEVinTET{Il&}QXMTT;!t&# zm)RdWPH9Jq6!LRgL+f=u@ky(R;YyVClvMA8&=j;rW7nA}QWhBKmp4oeEv?sL_W>PL ztn!PY|NjSEz3CdeqflD+!h%y2<*;%Ew_hYwh{s+>+D5#+;gQK^>#gnAkAYE71?I#; z_^!eo(6XA;Txo=|FLZCFD$p~j_BL08I_K};S~=pxIO9lCx&P0Mm0+X~U!+heb-!K% z|DV0dtt?7eX_%*M7x;x#bCnVdv|_LHC!Kjf%wJO`mh;tJe2(Bk{$`x)QsaA>6SH6^7&Z_%?%9h3 z)r=L+=bGWhe=W#Bxz~xra6E(-@YKT1Nyxz_dW?E#7O%t`gXIvCuF7E?&W)T+ zCp=hZ3SLFo8HdlJ8l3$f@s+8sEOrEC>@0Qaimlg$_{eh3JGv!6Fv&fVY!@|ado*ek zwIe~y-j3tD-l+_9WBp3WZk4D%-j54KBk==z3K_!nPX2icxFmBYz^hruPdJx*#fi@s z>V0dc*J@#lR&;_@o_;zCu@|~H@fS6LZ+P}P&1RhknBF;Eda=l`81M7D*muLcaEf!5(I2xsWq79l2W2A6n;EY8A3cZgCcSZlbWHu%4-;n+t30+Pm`$? zI))CR^)|pC&B*oDBsrA68IFxcQTdo@Wj&vAhOG>^8%6M=+PFBw7e2c0LE}5lX+T)% zMzh=~VM!7ly`+oh`O6D%6>_!){PJVs;*zey0vQf-5NyT}SM4xU(k2Y1v|)|LKi#DV zO|Z#6>KTFr0CrAh%ds?eW?RhK&N}0I%C&m?2cZ)O{GaboFMe~rg#O6 zLbk0ev#Csatd%V__Wa+LzD!UZ5J1hsZ`jS9TDEhID*ak~?^x(G`U#Om?b!O*8oprD z70_8KGv5)X3t=n05ItEgr}xWrg+z$30KMzIzyoO}MRubVKG0n2qzQ4KEMjggh~ ziqD{${#?DJmnYi$HxQS`2R8)3Q{X`n_qp%7pR8HZYjl}(X1?A&4)EJsH6rVoqU?F2 zZfu_sWrJ;(h56-tE2NJOrb6vGDv5f1dpCvewl4+itiP7Tq0Ay(Mn6esaue&)T&^MU sKw$n`M_9KcH(FBTlN(S`)}LH%Lpxo^^FP^yMjd;ufr;_NLApveW?^Gzl>h($ literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/quic_initial_rr2---sn-gvnuxaxjvh-o8ge_googlevideo_com.bin b/blockcheck/zapret/files/fake/quic_initial_rr2---sn-gvnuxaxjvh-o8ge_googlevideo_com.bin new file mode 100644 index 0000000000000000000000000000000000000000..d65c0e6cc4026e7658736e0545479eb881962cd2 GIT binary patch literal 1200 zcmV;h1W)_I000012&1%%rsNWMXaE32o<0M$RZ16Y=xeZ_qj9~O3ek;)uu00^)KYtT zGO!^Q{{dhh=Wq=?lLh$Ttdr2_itE@&c{d1V2{I(a+FpS;#hh^hPX42IADj|+b6>s7 zQt>NQ-5EA~eBYJKpqDecy+Zi6@stS(tfzyI*V95`yb;VbH#7*0-A}6YM4a^LHFf54 zW^lT)&E*k!_bU7?c9->hyKtD%Y~7AAk~uB)8dgO*vrfyVNaiS)EvUgF_m#jKffJs7 zoG?C}&zB_z8Z<2&iM5JKh`Z*8%RAh{`-RmptXv*{(;Mt;1jl^K4-OQgJ+Zem-nG$$ zKZcLAJHrK;Jf7&Jf?T=4nV))e+6!UGc3WgzuUkaY1xt)Ec6jMcp*jLR@JfKYOFp=A zgJk(zo?dxN63~^RWw2#uDq=N<$RtB&yUbzQ2iegl{@lHOnjjN;*haVzkSm+T6Wa zQI9)y2WW)3GUI-x#wvig-6RTUlAk>PCI6F9vcYzKSH{NBD$x7X6Y4tw#%dstT(y-h zro%Db^m;9TQ`%^C%pZO#?-(2G3DoxSPQ~;BWTxn=g+bVMoHFJL#>bnI z4U2?mxs7H`3M!v{)(WKilTY6JM8MYCtUzMo*kub^o^bI8C$tP5l3&wca|?E}^HjmU zbf*FSd8$NwDyo$igH8U5%q|-qA{}gtWZ9>M&+!F>A#j`Ftm?^ih&PRKBUN*>Lj8{f zz@Rq{2y+a1$TkSf+fm*bFgU-t@OBQ@-#h&7;31~Sjt@50#Wfw+pQ=)pk3!5qh=-H1 z3ZDULWU#O{_CA(i0RnR0OD`8Lv@D{;2Hk1#-mDg;b&d&v zJXVaSb+=w^L}|jGrJ2-EClj4KekjPY*#rNN4!0c)0=;IH{;ujtKXq{J`jPYI@Bb?7 zC>+%v7g88$&{+5KjnjK+VyB2ET!v$kvvK%}vHWSSk|_#Kotkw6I=!Q`geGl)uNt&^ z7Kqpi=Q-M`$XbRB62O0;^(FL6uFdC`!+~iQ<8#%6l{h;4#)ZFd5@3E!BZLOK zBi*$9Fm&vAGpw8?2O&G(Y!~q!te0;tZ`nzF>AH;#Ov4S#q_r)F!_Ryvs&7l8-!p;`AWn{r0;NrK14TGxr*m=fJSF-(xDc;NiE2=W`2s919mMh_#SmcFF57nkO<(F3*=#bH!X(Yt*IF;B zFAgrQ5VhlV%4R|V6RSG;uUeNyBA`+?v`kKPFxxuguKx$Lnl6|rf5x=2)gFsaVR9y< zC3bk!ujKnleIOWDsqOeD-g&qQitH14abJV>SbD@V#I)WnEkb5J>`5(bMw@fL75h;( z#o4oFiKvUqPEywYE4e(`g1049iA}m%vEsgf1Uhw%lbh@ppo1QP;Mvb~Gb{r+Llah% z;RtM^=DU!f>nxtbJR$)SMzJqY?b#iGn6EOc&exnm1EyX<1y|lEka8_ano;^Q;@5sH zBN0yPC6o&FwOUViZeCc0bQ#A3a*FjhsNwY0vQpZiY&=DddXt9x&<%RJW!pAmYwEpm zBW8wt13n{j(#@uA|m8@>_vYL{@^Lr0|wG6H-8f;r`lUnd85T!+-Z7>d~D@ zi~}C@ydS3@*vYd2$qWD;4HgvYR&0)Ql(q8%Z|E#=xik9)wdV)-nOW1JW}|(tf#DaMM z#djjtckt)5ZC|)0VFtSfW6>9JwSQui-hX6t^`uG^gJHg2!X~On!3sL$+LDJ_D*e#m zn5tohh05A*KKiop-c6@HJ@NlT65Hj0(3>ymdX7+91ip^=E^F0njgLZf;F&G#_I*v zjALI)TU|x9IqKgP29L}!Ze;$ySZV-wxbEfs*$Sx@0O3qc7Fc9|6L@U@sMJN7ZOf`|JN-HR`vV47 z=@hWT!UDwbw4`=b(y}FVh#oGAEGa0rbb>vs&C!2lJ0n;PoIYpY(9Nr{49lP9CTqBX OadevX!I|^r!a%=2%2Ia# literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/quic_initial_rutracker_org_kyber_1.bin b/blockcheck/zapret/files/fake/quic_initial_rutracker_org_kyber_1.bin new file mode 100644 index 0000000000000000000000000000000000000000..9a16d987978b018a7900ced331c405b9d63e1bc8 GIT binary patch literal 1230 zcmV;<1Tp)|000012ysIPQ5%p*%>V#Iy!#f$*^4{9?|uXET6T@S)>`3W{=) zVCdnV(NZ}V+z{Y8@tO2rv-Zp_qTWBr&6w#X^O6$@Xdj?bo9@eIl3+qoOnra9<=^r-nS2!=49k5c_jv}DUJd>X$xOgUOdJWH8W)}TZcOr^ zqVo2~4Rxe0KXzJ|AS<(61)8a$3fW0o&2HownewVJcPtYkMJQ1ydcY4as30UZcC{1L zsBr&}1YDD7m=O9ei#n=^!WA3WxeBYFHJ8o(5Fv=nG^Za2z(91qsav6TkeyS1bC;3! ziN8;`;;YHlUekK&33Pi*)8sBBsmtTHnwUemG}YzpP0nd10=8!Us-xs-xd+#Q6*JKJ znOnhIsz!=riiWisPxCXrPn9u0G*_7CQH+sJ2Vzj(UqxQRK}LjKRHXgPiwFh4d(N-W zq%^Fc+aB_2UkY>$iVUD_G+|HP{a;NSwR+ta+umoeUGq<3MagHPQ0_w)tt!YCeqKSM zw9V7_zuuixK76phrRKt%K;7&l%1zpf?rWn*?WP9CS!xK}HL>SaE!^PxMKclCkh~aw zNX#S%>r?d%1H2QzPzHLXMl1`Zz)I{Ev&BFVJiU<-%5+-KK-aN}dcLq(R+I(Pnw2aI z7{t^U!}@Y!hAa1}j^Uyt1Pw(du}&jq|F_7`0NiIt4P|(&R=q_BF1odjs(^43mMBNIU2pQPF;e_$}33yRm=J!8I)W8YLJ--yqDAv$HuOQ+0unqM!Y?Vk~jQ{`u literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/quic_initial_rutracker_org_kyber_2.bin b/blockcheck/zapret/files/fake/quic_initial_rutracker_org_kyber_2.bin new file mode 100644 index 0000000000000000000000000000000000000000..f3a721b7ed48e68f8e3dfcf8b573d4fc65bdd1d8 GIT binary patch literal 1230 zcmV;<1Tp){000012ysIPQ5%p*%>V#Iyl5F|ez2ut7E3~Gksw+$8{-8xVu@JEvK<>x zRY|^GA~TiKuQPQiE_63clk;h%!3BN11F!*@2p3sLfjNofq~osGP_^Vyx2F6lJ{aO;oPPTQGVz0hAT z3|diTnwSyP+O67PIlb1t4=qc0L_D?s5*CCAq~s7th+0{nXcaengR92iBEa5Nvj5(BAtb>RkB+Vlpw zPMd*$-mZsQQd6fOi{bf^+l2EeWdHo($1yeMZwsA-uZeyQ^Z|wUOI%C3twKOFGXMD~ zZlYuhKegAQ>ijfcZydVsb>tSq0)jX8-R5;#aZYl@Ci~3Ev>j%AK923y`bMZzsU>&( z0g(!X!5S(hbrui`9GHORL_a;59PD9|!pnui`PR=1Aos?qE^WKdZzq|BXh6dxwY~fr zj0Dyoa#48U!&#h@t_^2U0X5}uih3Kfy$K3AgkQRy&Py-g`;!QnP;OAp?G45cD+dWp zr2PCv6{u7A31kUdv+#L~+_--FhFH1=XrfKdQN3kBM|u2y#t74W-Wu5clZY9^AFjc= zl){tBlI0)qxeGDQJvt1^oc{xkpA!DFQcOSAXf9<)>y}+BTi%$d^v=Tt#xIg5KwAl4 zAvjvjU~E1Sl+27yJqJf$&i#MT`yu3?=k7^sv`h?dMJ4>xMw~;hRIm~EpQ2#?m#Beb z+PIXHQz4yk{(S_+jLqX5uBlS#J87MwV%B|Y~T*~PK^m;9l5PmXL zv}(fzE-iYJHXKpgFT9u{zMv_0PPxNU*a5rgG_cPN=&opIq&PeK+Mi1CvN=Y|0(+3h z2Nn`%S}v{@_Rww?9AZc&z9? zGNERe@%j8!H#sfK>}9H3@(i1=Ec{1+lDK#*MTtO`e%lQ#(akbFe&u!fz{7I+mYLyr zkh62>B+QmI#vfEEW4pUHzBFO|Ct>xB``RNR;+onm9OFQ;uo6^J$m|;>-D$qW zK$(*I|H+?Cf^?@QiRhkvU*xzoWdEZ>RaP6)u8MuREae`QEOE@`VeEvL9Wx)r@Vr=7 zCvsn8dgkGa9>$ldR3F9P>-wAVwf#)ET~EhTrb_F8q(!q(lb9_puf0Cx&r+l$;xohTi h>ULVQnx^{0&9_hQc(F`iH87!!g3%Bd4FTLC008NC7P9~V literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/quic_initial_www_google_com.bin b/blockcheck/zapret/files/fake/quic_initial_www_google_com.bin new file mode 100644 index 0000000000000000000000000000000000000000..80a07cc8870c88be6d8ac7f9bf9dc9bb1979468b GIT binary patch literal 1200 zcmV;h1W)_J000012zck1M!WNQga80Up0eT_O^eJg$v*FaNtH@lrZ!8F85?~L=|4FC zk&^uu@3*1@yE;Nr+phxdvmjKlDvv)J(yS~3><6w zEp#coJfYUm9CGLZ~DKk^PzBnc1%f|fM8tBsxh*3hcADV z^CU8<{XVqh;7whf0$D!%XlMGTw798<*&-QJ!J_F4aM6Bx6zTZRd8tC1&6A?yHRR@V z*(Y6i13lm}>32F&=^G*!oie_jmxN)fv~C)yRenn~>%$c!gCi?1$YU~52E7>9OR|Sm z*0or11T~hM0jX)6M$%)CyQ}2u+gTPF+39I^(olCjZ|S`FNZIz}o)#b)O`EEWD&X)8 zD*dxPl59gAxb#Z3@fjs3yr%)0G$8EX4eO0kwYPK?fVME93!RHm-IjwaEHlyOY$UAS z{-}PnuMtXZ1oyFzaHYi8wq0%YZT;bX@31QPpE;duWeOLIey~ZX({>Ct)#s~nnhkyg*!711_$gJmQ;g6N?g|dE*sv|JA3izy z`WHxH{1S6cV)gmesLpz!3FW>#E;01f9ec}Cg*NAeT5z}|OVuqL`24o6^a-?V+mF*w z3qPYBq?4tc`GvPoX}H_!HLWNemb3d@-DH`AHC0J+!`aiI!Emr{8hgF5EJH9)0BV{>t4FO7*Rn83&5KIgU<<>6KLttmv1oYA4 z=|Qj2Xr}J3MOQM@D{!=(O6=H0PX(AxaHfuc;q&mm6Vt28(`Z@~;(wo0Y%3HWd~aSl z#&4OA#_}K!cZ%ml1$@I>#6AZw$cQNc^h7W*BMq7~M7ltAZU;k10h-}sc%+cuBv6GG zu)B$*t&^YX_t`}*mbbnz$4fW~M3li?vQy=t9K+{XI^~X8D9^1+9dPY=(HU+JS5O)2G_una37W{$E@A=Y6 zz6l_Y^XKXZ?u$rOQPL8qadZWlusq6)AxNH-W5i0Hb>l zMxnwI0H0_{axGEA-0IMAcn{0>x(qs#vJ}YC{N&g*WJ!#t0}~F^x&%%+5@#2PtFl)EW9rnwIqJO$|OVm&@0-}$W~0{Gnz$OG;cp&Tq2 zMXteAz3Hl3v5Fi!8N~1O&=t>LMTGs3>>=xCX^3nz6qv9yY?hxf9q#kwo2nFg@9 z`IM}DtVEY8&Qf=x{;H3I51HJWQ|}!(OwswAQR!y&rYZYIl3-dFP=o z@DzlxL&8>!4A<9HaKC|naSThcsV3`W*%yQFl?EC}rZsGxY~S>-Pd@;atKm(^bBme|%03QDU2mlnSPn7u|_0GQE?4D+=)7_i5mF;eTC;$X2 GAGS5sQX+l; literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/tls_clienthello_gosuslugi_ru.bin b/blockcheck/zapret/files/fake/tls_clienthello_gosuslugi_ru.bin new file mode 100644 index 0000000000000000000000000000000000000000..d9e0f4a83de2f26855876574b8cf00797258558c GIT binary patch literal 517 zcmWe*W@KVuWMKTm%)FvEY)1Vw9##Ig(Ot>b-Z|@ej#_j)DfoMb!>R4u@8wGswlOC? z{O6YMcSv{FPS=`){ht(C4{Q-C-mv_Xyi_}{T_%Hql$0=|Fq1Iz0qq0&2Xqb?oLPBh z#R1_1A`EjF<}&Crm;x=DylWQ&!+#)y!6lP{m4TTl!-zqbfr*ikL5P8YfeQ#Zs;U@d z8N?YR7^H#H3`{^(tc*Z82A~)N120gW01Gn*3kxGFGY2axBL^EBBLg?k1O^6e26nbz zznEE=nHiM98bld{85jhT@=Ns6^NUN1b4t@Q^@>UvjDadOfwlm($TBE=a@*lJe|eOB z!j!<|Otbblz1F~5E{|Di{+qj$XVgwtWe{NCW8eY0lOv;~q(I+L&k&+jl;JqolA%uk E02%L3Bme*a literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/tls_clienthello_iana_org.bin b/blockcheck/zapret/files/fake/tls_clienthello_iana_org.bin new file mode 100644 index 0000000000000000000000000000000000000000..e641d731d161fb0ba957f374615d1ff823cb8948 GIT binary patch literal 517 zcmWe*W@KVuWMKTm%$(1?tu;a;@+xmmg=M`qx9j3Uf6r?s;>RMF%62k7ERt22tFu}y zVtMoa?RVleRtYXo4v{>4>g5-u134_r3_wS6G4KGfEQ2_M9D^i-gmDQ_sQ?2X0}oS%5l2QzNrAqh zo*{!6P*fa<4Z#K(FzB%`vofmQ*E&)`46kandPM&R7vsEb|dSvN=KE(Et_pA=LM> zDOp!{JK2LqwlhR24l66pNvx~Ibs?2L0Tt#7D~H+T6t?d=fd};dltiXSfpkot)u?}t z%7R#A9~Io~2zJMbC-1}%fX`j0Mp{*9;`f8q7ytzT1pxp60000001^NY000egb#!uJV{2t{E^l&Y{{a92 z001)t?*#1{8UO(RW0?fN0?6E0Cv@q`9_G~tFm{O@8k4UxJuWE0F$CKog{*^Y3wSeY z(t|`pUNrX(VB(T1T8+_cthR%DxZ7~nYNt5LevxSm5#SheQV0O#8$OUzbXhQoNX0sM zv(TKB_hhpJ)p)h*T<}FWYZMdK>0J(+v1t&Nb>Pe$@n@ghU!WvAMwJK)roTQKS-`1~ zH90;|HjRfc!{e}v?wC{l`b^NLUTS5TYx-%I1O_zHz1GDReMyO2GR^*se2R%w%_{(I zDXkWK4+1HQw4*oINpQC)6m9TL$)dsSGD}PagD+E{CW~E;x0uIBj!_hvORK)nYblNQ9b`MEITs-=F~L?6Nj_Ey?^UC)G)2B)Y7urt0{p0kIa(EHy=lY?)#Dp(375d8 zIuCG(1DMOLWlCP$dLKrd^eh{_$Tp9-6eyH=Qs8nH%nC%XRxI19BWF#4=|QOEj^%}7 z@i!zW%9Q^Hxov@-Ge93a7y$0@DpGlW@*8)*OdAW7n#J`RDx#tRBn+TC4&DKffVNKJ zS#Z{&c7i!XF#`*kY&20o8lZ?jQlQNbS*qN7lPMF*jyp42hI z{|FO~(=Y>2bL%OK&3Q}c8+@hIQ)lomx&Vv==ncamnyiD0gp$v>I}My$%ldK*Tf3<# zlz`d@K5SGFMLB>!I*{KBPp(W1UC}9?L7>uO!C~cs9kUsZC0hujM8dQd4!S0KJB?(B z3<|@zqZu>x90==2s(8a~y~Hq@s}>5y%Jm`{qKG%`b!|KGT#*ux2gqzxVLr`BP&%o= z5rrYNkQu5Xo%vvoc~BBT1_Im|RURy~r>r=hMY?^KuCt}Alu>zCvP5=Pw+qU0-IS{? z3&3r)HGT+?WATsG0+ml=X}2b>-l`jDQpBVxANx9W4dV!S=8+yJLOdzMN^+WK*Hp;h zHhvLy@kzp3m?2o%NXxXOHiJcOx}Z6xpV}Id{aIH2_pJ}(82c5zUHW@VX$q-Q9Tw6| z_4UT}d^}W&#RJr>jzcKY*FNWjtzs(=N2_^>vn`>yQ#$0viI%x-RT<+1Hfj-hySy#K zu+Cyzq}RH<=F&4@j6nXYxN$(Gtktj%1a6}kR$9X`dU^;fMXCh(%<$+~G}wMlwmu(2 zP%&JDZKRo9ka)0DY`Nnhs}l|7TLj>#vlVua3>jDaRsoiJf8c;YN8pDRDgml{D%|_R zdn^fV?8X7uWZ>K)VCuvY8F*>|XfOu8=oBAP_c6DOhQH&we>^#JHNo$8zU1XsO9qB_ zBF1StE4@ZSq=a2dmuy_B7L)iK2%xTxT*#W^DfGlC-6TZl8DO|Pd^6u}db2Rj%U z!nn*DLlA0@H(#47^D0h6ugWNM1uSgn#fR{o+L~I-QEVA50384zQ-XEZG|{7-!2_^? z9J!PxpS7_(+2{hup_!=3i{o4c02crN04o3o23lGJ1Oo#A5&!^1X#fQP0|IC=02=@U d0ssO45C9GU3<78}2xxS4a4#_~F$xL*0RXt?{JsDH literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/tls_clienthello_sberbank_ru.bin b/blockcheck/zapret/files/fake/tls_clienthello_sberbank_ru.bin new file mode 100644 index 0000000000000000000000000000000000000000..59571bb1dfc0924e8029e1389b2328dba0020f7f GIT binary patch literal 517 zcmWe*W@KVuWMKTm%xrb;#C9Gh-BOh)2{wMk*OW^e-|h+7{3Ja$O7drE*ONYlyTVbA z%w)}4lY|nI)*dtDb2+hm^TfGAmu5|}Sfa3tyM#eOOG}thm`RxVfc63X13Cu`&a6DM z;(+i05r#Poa~bp*Oo0|n_VQw2U=U#7W8h)RFyhE4DJjr5)H4K%i8F{YFbL)6J=xY79}O-W$P7{G8i*xGic751#~8ZEQ7+`)la9oHhes}!?|}&=>FG!L2KtL9Y6GV z?j6?Ot*%;~91O}pv!ofAnHZQ{G8tHbj0__NZU!cxZXuuyD+4Q#1q56`$N@A}7HF{q z&<1ukD=TIeW@ZLmpjyWNK&OJ7#K6D{)F!~f%)!FK$jZ#Y%F4*W#>RN-7D!r@;V9Us Hp-un*`=U|c literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/tls_clienthello_vk_com.bin b/blockcheck/zapret/files/fake/tls_clienthello_vk_com.bin new file mode 100644 index 0000000000000000000000000000000000000000..ec908c2bfffc29500a938f1d4ef180321393b9ca GIT binary patch literal 517 zcmWe*W@KVuWMKTm%skEWrTZ>trEL{~oEtKkvRo(L-X8Q)H8vse;Nkq7CwG4 z+ZfM$7#MgNgct-^m^oNj7+IM)SXmi4*w`3dG8tGIn3*z+ z7_=GK*>>$>W?^Oqs^wgvI<|94=60DIsUYVv?AirVEXr^ZZ1->?0LGk5Q2+n{ literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/tls_clienthello_vk_com_kyber.bin b/blockcheck/zapret/files/fake/tls_clienthello_vk_com_kyber.bin new file mode 100644 index 0000000000000000000000000000000000000000..92c639e39c7e012a239f30405744059e73d739ca GIT binary patch literal 1812 zcmV+v2kZD20|5sQ0RRUJ0|U5*L&>8durC^rtjuu{+?pZrU{1kk2jl7ua2iZ;PB|c) z*}x<1`s4b-4To7$a=|)97TobQ%eInL&-^N7)HJ97AQ~DI0TTif1Hdc5FTgCoFwCjU zsK67z6abt6od7QYH30wyqMDij07Pj31posAXfgl_01N;MdU|7-0384q02lxT00jX6 z00000D*y)u3JL=R0|NjX00RO50ss;K001oj0s#U40RRC201E&D0RR9H01f~Q0%$S_ zXmoUNFEK7L0000B00{s926k&MV{dH$4FD1V5Cj7V1Ox#E0|*5L0SE>L0RR^O001KZ z0R9aD8UO$R00Eri2T!2kbXPc_m?>2if}4-asi;KnmyY5?$Yts+1E zOwRv`{uOi2(Jr}Xc*7Vo_UN+Soa>(Lp2~oGX(Dh?Rt6u0RUr}1i-ASkt(0Sy=0j* zO6N*G^Q{a~_L8iqVwy4K{SoSh#zpJ-uqXwi?MN}g4abg#l+c_u}`3F4&ipKjnUezek_=cY*n|c+- z@6xg8#JWBpe_C9$|I~1O@S4Ao$IV#K^Hj8?{x{9~PF*YJIgyDr~ zk_;(I2|_76wH#@HP+98JB0qbj-n+1~#whiAXal^=L2%GwaTruH_R05n zW^%-jvO*S15w<-+WeGHpUGoN`9-1XVX+6>C1-^T?@_BIL;fVrQiUOMTZ$Bs#*j zV&O9J(O^TFp)J5+nkWNxU>T=6C_fUJW;vky0EYQ`aUkM&`XiRN%rD3`lh43}2wPn! zEPtgpctyyG+YnT=>1%{nGp`{zA_za#af}|YAcpf(8bG(3qB4l$3b#qYh2YAD0*}uY zhufqoBd0NE=_&kjs`+yyR`^Na;3Gj-0kXrluBv)yBc`0t0tFi_vPuHhFmdX(8Y0{= z1Nck9hR;4l3HgP>tmC#?7g|@<8IHSRpT{r2e8MK&JE~hPs!F;s*GDjBe9?5G4f`oB zwS|6ieLbX{#~@9B*OcJPd2IN>J37Yi^?NO_hzn2zvtupPC!@qbjD@my<|r=_iOk?} zPo6wTPb-X$2?!(tHz+)2wGw3v@R>LPhK7MWX#->#B~7_hx>@USzS@)nx@6)!&Gfrh z!hn++e3MYxU-3sHn(TPAhnu@2w?J98f+1~hON|U>%p3Vaxhqp|n#|IGt1f0;s251Hq9;Y9r7sYwZ zV>=f;z%l{V#Xq*gTsm=Tas|Rxws!}W0wc0G#b?aroR{hvfd}Uq85)rAd6=VcKRD7X zza%c_0=)x>OYt!@jF~&Bt31KTh~PH>HBs-7~eOF;C{903dtmw*g$>&{*(f>}xhB`m%sM@ld})-}|R!kF}-b?`#SR0098r C+Z{as literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/tls_clienthello_www_google_com.bin b/blockcheck/zapret/files/fake/tls_clienthello_www_google_com.bin new file mode 100644 index 0000000000000000000000000000000000000000..62985b63657c9343b805f915e5774a4e26a554d5 GIT binary patch literal 681 zcmV;a0#^MN0|5f00RRG^0|QeVTbDJ`aqq^!i#)(90~?C3sgivz>!@{iZ)Wz&%v2z) z$RoP%!7?G|r!sCXSzLDkuvzP9mVqgr6@=>Gs&>i%A`<}<0}}$kE5I+zsm!RrEWj|p z3cv}#6TlPzoB*8wF90UUk{!P@xKzx>s zpe>y`!2U{*0{vID`cuxAYKi&3MnaN)9|45`D*y=y0|WyD0|Em901W^b02TxT1p@{H z2m}ZP2nGZJ1px*D0s{g804)Fl0RaFU00KY(02=@Y1^@v70ssU44FMSd00964$p9eM z(fL4?(6*7RoVIwfUDnNb%ALfKl#LI;123|*9lJdM@953`rrYTbN4h4Es`QiojJkBZ zF1l{kVdzJTQ8KQO9Zd^=ti!lX(Ks9ay)4UUTIEK+40n>!y?3`VvFWT(w5MKwcI8CP z#7tf@713g5AF(pBNDK?~NMAJ4J_jy=SR?9^Y%VP$9B%XAdXFXA0Gvkf2JDPh7C?~m zwz_TkSI2I#{7PR#Zp%NfWM$`Z{27y$A z1c)@8t+4?F!h@j7i5hEr&0zY# literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/wireguard_initiation.bin b/blockcheck/zapret/files/fake/wireguard_initiation.bin new file mode 100644 index 0000000000000000000000000000000000000000..80558634c7c372f32ea0a866c09e9084a51a8e0c GIT binary patch literal 148 zcmZQ%U|?XiUtnKpB>8B=!70fNv&{NVd9%l6C#+rnOkhVt#vEbJ6VZV}HV%sMjNg0e zveuWiU2yxhB%SG!VX3q^I~%jgo_YK&&$n4vu%A2q$>Q$I`@V->D#b)Hx}VE)NP6vD t`A2@?7nVgypD(RDDw_Y^MQQc5FYBE8UjF25RQ4wYfGUtq64J#AHrWZRji7j(N)Cvd#I#jkZE^|@sXgE!yOWqJh}@pleg muFSYtwo=8|UE$xVKQGJ`ug~w6nzrz0WSi4wL2sZ@C;$M9)FBiA literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/zero_1024.bin b/blockcheck/zapret/files/fake/zero_1024.bin new file mode 100644 index 0000000000000000000000000000000000000000..06d7405020018ddf3cacee90fd4af10487da3d20 GIT binary patch literal 1024 ScmZQz7zLvtFd70QH3R?z00031 literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/zero_256.bin b/blockcheck/zapret/files/fake/zero_256.bin new file mode 100644 index 0000000000000000000000000000000000000000..65f57c2ee985713476ac0b6e3483e6fe472e2176 GIT binary patch literal 256 LcmZQz7})>-0RR92 literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/files/fake/zero_512.bin b/blockcheck/zapret/files/fake/zero_512.bin new file mode 100644 index 0000000000000000000000000000000000000000..a64a5a93fb4aef4d5f63d79cb2582731b9ac5063 GIT binary patch literal 512 NcmZQz7zHCa1ONg600961 literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/ip2net/ip2net.exe b/blockcheck/zapret/ip2net/ip2net.exe new file mode 100644 index 0000000000000000000000000000000000000000..3dcbbcab345ef8b72c504b84b7610e6e1a2686ee GIT binary patch literal 92672 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 VVDxf#*X8o%xyu-A=eXw{_!ecs5SIV| literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/mdig/mdig.exe b/blockcheck/zapret/mdig/mdig.exe new file mode 100644 index 0000000000000000000000000000000000000000..56a4fb097f7e5298013952a9230280c37dc6e98a GIT binary patch literal 130560 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 literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/nfq/WinDivert.dll b/blockcheck/zapret/nfq/WinDivert.dll new file mode 100644 index 0000000000000000000000000000000000000000..b63927441eaf2c3e39354309bf4cd5af4eaeaa7d GIT binary patch literal 47616 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%0A0F;Lb6usweP(dk=OO-@&g+nO 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 M7(DZxZNnA#1>Yv7CjbBd literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/nfq/WinDivert64.sys b/blockcheck/zapret/nfq/WinDivert64.sys new file mode 100644 index 0000000000000000000000000000000000000000..218ccaf423ef0a67696226f9ef3a09149e4441d0 GIT binary patch literal 94144 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 Mok_m={2+h)7u^}>0RR91 literal 0 HcmV?d00001 diff --git a/blockcheck/zapret/nfq/winws.exe b/blockcheck/zapret/nfq/winws.exe new file mode 100644 index 0000000000000000000000000000000000000000..ea098a19fc808b11cd95466c3a04f64849580585 GIT binary patch literal 223232 zcmd?S4Rlo1x%fSkOkjY(85A@s%AipbMa>AE)V~6IhSh#Px%*8fB)-0jeH(6 zanl&rFGjpPX@fiV@}vbz?pp3&y6oP+TlS@|`tSJC*S>ad+<*I*{mT+x^WXI~fB3WW z{a?NJ&M#j%di2QheA9Iim+Q{eBVGIc^*`<^^mf#BWzndjqDt2>Hy?qnh%dhUe;^~* zNs}*d%fAv;h?gCdC-cMy#WJo&m&;Ek|D?Y9mw)L?5BMbC8;f1L<=fN6uDbJh))l*& zOXWlUUt6(ji2x8Pc1 zrTCXfuQT}L0|9e*o)Ccg|Akzxwkwx81*>}+Q+XJ!_!WjVuX=-!h0(Gr zewHzPWMZr}(|g6#8(gkr&qVDX+O*cTjzW8?U`K!Z3vao3z8aHtUvH(4Yd1!VHtI~x{zVc zGNNX?(bA^1T%OD2)Yt6e4eNlJ@mV*A+`EHaTDa4k6%MoocWSHSlybji-W=)!NWmkx zvR8hT%SlT=pd-P4*qZ4xI%if007j=?cq*1jx=QjREp3V0jg7RLb2Un_nO>P8!<yC{fu|$XN+O#)gUHbVodkOHB~{7@07RdyiErcDfLcV z`A%nOhH9iU6q0A=16m(ItlC7Ez93IfW_Q&5tzG-qT+ZAgxO$xOhIM~+%idKFn13*L zr$6!}_i4#3CCSrOT5NZ!rYG4me1)fFZ{i-qy2TJ$K70BXtK(-xtyp=To?B3E7@f0) zi@VH~zL>e+{9?8J!Czz|64yqpaC!9*;PUgPFUlA|Sr||9^oI|QI=MId%{;xR;r12n zSf?-47s!I}8|HT1e7zRXn|IKs-dG*bTDHhr^3+nTy02Mu$NVU`)4AvL_tkfIFx=YXx7FEKM` z7}ngnn0X*K9~{(FQ_&SRZJ_plPG6*dp2ZCa<0omwG&tYLu2bm}x1>9DMJtA>hXPwO z_dpB|UFg5+6~fq{{|Xf5vd`J2q)_kvU2h{J`8P)Um=yu7c^@%Yz{; zF|0bcfz*+iI>VS=lo&mL>#P_aHoF9_NMI`zcWl+{Sv`&$AUxu%5t>` z!{(fN3K`w|!sgDT?bau?QC08W7jw_7V?I!@p_ z#^3t8BA0Q8=MlrbBe$=g9w)Ax(sDv;{_D8gWjeCuAG!^Ge+#-Lp1#!*$2E4^8{b`6muVo1WwSk zVMhE>bM|7uzaGfL*1~ZSVf9}s>l0=%b5VK7Zog76!rOovGID1gtY(GAq+OEiacisp z7wSvcsx3uOXw6F*uepZ~Zlrkfou1_W;nD67tc5-(<=*7!i7Tg?dsr!LG2#*8Nqg~`Ja4h8s2%6X)tG3(f2(1&fXceB6rFRx10$}A~!~Eq~);I{HHU)R;;|r ziYzv_g)0vRcWA5Eqh!xajjJ$sRCWa;Auah3NDo^-5&0Ntc~@)x8fm6<$?ieDgsnTv ztArpxZZ1-JNXEgsm?6{k@p)pkBr3x}R(L!j+@KDKR!+|ojVCeYx?0J&EKk=Flco9= z6K;R|grhWE3g9xas@KTnf9Ge7RaYK2cSF#=u*ozzbbTV?^TbC8*e$m(KP;}mu9mG< ztyg=pJ$+zU@xuDlBaKjF(+qzb(Uj*At+mb_)>>U*ZT;dRt+gG- z8VYtS|E$o@SGuok$}E* z&xp>MhLn;OHZz;qiuUCCCFU|ZC5v24=)t*mlc@{oZXw!?NQ^FotW&jHv#=n_7 zt*x9YSer^o1jZO={Y#EtcwFn*ee&Xfk{53zPiZUmncIb)wB~1JZLVMFj|Gou%|9T) za+v+vU>qDmB`EMSCYj!A=v|0q1v3-eqRrY84%)gl`z77nEZILB21%Q3hS?i4_k=6o zi^*g}D*tF-ACz&E2v>f2QPk{Uy~Ny|weF70A9|#ZkPuP!C*U(|J^2{8vsy&$WXZ1K zp}RNJkP!*Krmb#QOJLO|VS8co&hk*qiY)0qaB`Qq!=bQ7t<`|S)*Db)I=FkqO@a|0 zfPtek`t2Rb?SYAZ0(}i=slL!s2c-2|-TW=XGT&)HZPB#VV*y28eK1-Wj=YZ5n*S`U zCbf8YIQY);Y0}FR^fGvU8p&Y|X!!|>cJF6`YTd7dgZr1gZElBjH=bg6LZX%Fu=!!w zy&dK|9PKE%|KVhMlQ0te{E|7EXD}{xJ#ZYTDeGiyUpn>FS`1) z9wT+W9|cNJh1?PISTa*QOIz=$(US*;n+g#krW$6MPef$=VQjhNHdp{s3&N!B6+ebL zvzy>wGX9nTa|m6F?v@FkR6^9jkKjS+W3QtZ4AIBL{qbpdFsulCpe^o+nM=JVBIgvv zN2&$a@>Rx0PoJSDG?KvH>`1lVWf`k}zWVWg>OZX?)^VYqvAWj!hFRxB*Aw;6tQ%)7 zEIYBKD1MES8&!r?>o-yh%I{PRNZ(KdRv?df`JMJTmqR=Y%ldRX1rH!r1EOMmC$@Ov zcgR%iq!u_B#rl+F8_7=`e;%%|nOLN75H^?k1(rMteuf^a8qQt-{(;h?wfu|Xa}Lhn zb0M@(g{L4um^&KZgQotC9BbjC;2XO6T3DO)o}$&YWHPp@h zek)oYHe=->y>e$bxOGKMP0E9&gXI`ZFCXpRX>Plm)niD;+*B!=70gBPtVQK@QY>VD zV=7%n6l&^XXlkK#!gKS(xCL$rJi_1HZ-y%mmNQGN*5GK3SGy;_UR z<3L_s;S?y8n@+jRa3ugj(n59{cow=)>|-I#4xzsgS)Yb~^kXwohJL3ve&p4fmkWAR zB^SRkcnzKbsWa1IdLF3Og;{>5M?3xg9w3MG+eOwV_B&eS3i@0vyoxoM9fML=5>01D zCJ#(Z?whD5_iIhW1COh2vni?6WXyTds{>1X`^QVa&fwm`- z{2ZEG7qxCF!*D^*V`;HuD%&w(;^)|Zx)d<-rc$Pnl6ig3er6JC=^y*}Y0HWD|AvMl zfp@bbl-?M8Z^blOq%iuCdUCT{7Q}fmD^x91dWKcIXu1(vJ~E}Fg)fS%DfJr3c6X$C zYhsIH8dYlbUM8RjL?TcZl^fwT5Vid!K$1mk&@^d*4t^@s_&yD2Ef*m>AfwDH1NoU% zyQ-j+MV2_01Be&b-9YuMQG}<~>dR|qB0m?(ir;}505J@apW-w51bXPx&l&-+uCF;5 zRXb92i%{s!W@OJas-I{_N1Kjda^_U2XiO=h??k&_Yc7L)`^_A|E3+wTZl?J|M{f}5 zuBIUe_x!Xjb*eDn=VW!l8 zFX_QH?UBzw={2cwUcA#s&#Ky=DXkp?JBeSNM5g6SeE$(yhY3!;K^mmSO)NyVE6JX1a~LM zWM;kcZu9;L^BLT^Y(HAb&J9%0xt|nOy0W`_-$_xpiX$>tkZ|VIan){Rhn|}0mOLem zk;IQJRGNs%(3H+HpGDO4b!FCR&E_$1l>F6GB9^okQ7c*V#e6V_A=tN(o>}_1*7PNb=~{SohNsQ-Uyi8cG$fSR{;hHG+8h{LT-#iZ}6=Z z_sZxGozCTCmDP)bp)M>7EIYPu{-i|A(MT|Tv7`H(F=2D7vZ#0G`)PCf(OSLvRaEF^ zve1)bL-_eRKmr|E&*AY#R_}yUleDfGA$-myRtzF`WL41W_-FD^gkE+HzSL~ zX5`LH=BQwudSQ$xB`+>!7(@8BkE~Ca*Kjbs489#U(+<|$$}kF7cI4+4xZIJ&nQzhs z(nwo<41SWCfW9uWDIf^h2w~AzK`;2J$goe+4;{Osy(m69+Vs&xi>YqD3XQy=!wkpa zDYTV5fXCrJ5tf_A&h$=d_RaL7{UTS=`@KjMZ_|G9Z5i&gY)+g!Ab%@&;Jy%VR@(N+ zl1LvYfpr@=?prEoNclOmWDi341b`!cJXWMSnf1^vLJ74Sv!$h5tb^KWrPS{hxKbrr z=U@`tua*;dW*)W_97D{7SlCd%);teR<~w;%I771wTlk3#-;L6wqvHo%nuoTSuLKNbjFLN zA5HHob5Iq*78}u}3hWo`DgR&EaCaHO2;6n=A*G->6$2W#PJ+O2;r7?Pn#ptOP%J>1;hB5}PpEYE%{QfJu2i7^%?kQGw&+ufrI8)3j z5!=2^)cIu387t>*l5I^W80bdsU>MAO%3~PrZET~ReiesZs&t-OAKH2!mN+c42<^97 zu_Uy?gx#sw6s{PGw#e>FXJi#q>B1A8dQupdVYaN}5lf}yp>I${l}E6pOh^?D!$x3a zmAt5l4B0+hR5E!Xv59+NZ9rH5(qIZ$#~dmRMDYYsL%vPU5P9z?qxVg8nlqFpD%6nq z`kzH~hP38CB0*^Vt3z79I^UMk{B@xy7>jTmrTF{v4Jy?k^LHSXCbAua0Xzb6ILM*0 zY;P)0ZUlPI+zN#=+eLctcPo_R@8_bF_49$JN&c7fT-gC{QR0fN38wEuWQHuxqGYxR zrumq%-IDu@WzIDO8Vl_vI_{HU3kt}~d>$y>?T%(+?nIlxcouilHqrm#{KvWvhTR9u zUF<=wqvd%t-x@_F84DF4jUrghIs)J;LbF+r>R^evGqR%<-N=XgKr;T6!F>M!8zk;G z!sc83oz&6^S`H@J`e;!^I?A`da-$-L2C+#*#nIM_E5uZy6igrv!j;=$BfO&+wYY`R zUIH}8Y4n=RjR%D{3hR%81#{t@nI?ukfD0*yUyGT^la$~|O&U}+Bde$in{;a&8%P<6 z@L6;00E31-Y|*Q(p>c8@fpjR700q|P*)&WH?~GK-uGApE+Km9C zzcA6t>j|<(3}Fh`y?t;m!sNY#a=>;Z2cw z_rA`EGPeU;&Bz4%EjE|+ruQVUqpuy=Aab_1!J6pZfxVfL?+I}zrnu3WG#E=~^}k6iEsV+*imc z&^J;*@^2*{@U80{PRLkxj2G4us1S|^*S z*8FPOS{<~nx=-x}>xBsEX~gWr|yJ@e=Y)c1|4-zVJnW z$oHT9SpV#i1lQzCuIa@`Qty|Ac8vkQop_B#25UcPhakw zrC9a`u{pB;+@RuBKIg<6EO6otY9-!4clO;u(wRgZB*s{Vw<)8-4A|Tp#qJ*1Zv;ly ziIA@-egv=#v#yGKeC(3V=Vo~#m}P#Xf@2@_?fh27tn)v61ln?Tek%fPQFE*PtKZ3V zwTt$5Cq!)B&nEA!)ok##bkLYpQ%?|rwt60)njY}Z2ZLJkg(To9)&q5&H7YB)Pj)no z?jweIDz&snxJ^0Q5gW3pu;*fCdkt1Xn_IN9Xs|8u;cpbO&AD~SE$%>DXHC7p{VNZD zD&Ndj750gm0qJ2%nwiRU@>H?erF|zIPI=DOgKU?58x5x2tv7eYznJV1Sypt;){{H+ z>aIj5J;~PHchcFNVkh^3J)gE1&j7e_5i7_|as~JY>KK5G_t9%Wq2g{x`=of4br92% zi&}w@_T)<;|I1qQESd}K(q9y?vzPbJe?;JZlgzNWzaMab4fZa-ym@Qw&UBTQZl653_1~ z$$h8I8XTZoqt;y&_B(GW;vUyoqhug)5+N$M?77Uiv=KG$sxTiYV-AI%$yQfI^z!1w z--lV9$<0;HE?398JQ^}hkd=Zf6KKm^0e6=8S&b9=$26ko6;MG2Q0kL2Mq8Fq;k=MkZ+)t=Q%vmoH72hRo$Uf6} ziSP1RbG+eH({J18g%Gb5Bm3iZ0&M@uu5IEFp%#HQ9F$MUT5_pnBJn}}u@MNamkokD z%x?Q%_eksPszxAoSsd5#j9GUp?l>@dWqzm-zH%`oYVm2*ie+*$)S+9oLqo5Gvr-|A z4@_(Rh%(2udyAu~2g}*>-XAkRFp}^0Xk#OiJ=bSco-!(5X-Z3|j5fB`N9KHgI#aBT zUFhfib5+{d&sXtsM@Sp{&vVPl`$(H9h4~ zOKnj`&E|61syuG|Bx+73H?qWF$M})2Gj+A8mUsCSO+8jFwPL}xmFJ3q>F$c6+e?E> z#dNA9awlBAG+L|-0;6(g)O@U5Yy&V5pCF@;S_=&)?o7g0;5Iif!3@7vbkaau%=~h- zk}dfSRi-5b-6)AFt*4qj4%E%6+3d6OopJtu3S-Gvpu|rHI^%;*1#U%enbD+_D998G z{q{vMIeABDO6YyAL+@dS-me=(?}&$yh=(}?#DhoZx$_a()Q6;8N+k8kgFK!0`Fo}P zyPfv$blU$sTL#stm}mpzqKF?&A1r?c#7F8@NWxaiq-e6sqnjaL09n)5K1`^Pr}TyY zM*lKCqq9vyI6iendl^t8gCk(*5pld3>3zPYQ?d;kzoO}s1VJQzAGX#CNrx|=vnb{+ z#7E^D?!$+5(<0m?{ro}j@iBR<;9-IkJfDE^0sO_V9ub-^ge+Ee8R?#)0r;SQX{ax3 zbx=H3)1lo`*P7P)J|?>LV!7;S80LfJ;?f~0+vl=9QzbeyEBh=XAFV}rET#NLXLETY zEyzE4mpugeC+`B4{F8T4+U1`pVV4_3WL4=Y19k9NEET)4DDM{-iAXJKNH)hBDTzaM zXCiBe0cfP2DE~fL*7O&|-pJ2GL-JY|@tetm*sAWthtenj4l`19-cFY@jI%mJ9`z>1 zM5m%n)D~;n*7szvPS}}o`B_@atq4)0X|v#BP;iCf|EXV;Kf(uHMGFFQ^0Yf~cJ{nJ zeFvE-fMdPJhY3*e!v?;x)IXI!O)XVPjSr)DgnL)Ga+|hhgkTkmBO2VEu%YF#!j1n# zX`0qrvb=~$ioyPV%zFb|?O#-$YNw&N^sENmEFCMI8p+-XiNk~l26hQ*b3g!1DDQkfXL1Rg67!Mw4|q&x*KMi3nH}r3zZ|vj39hh@NI=i2khCW4eOe4@J(Ht ziPjk}uQyLI>65z;KoK+Ou7Sv;coc0ydm>!^P}76uGwP5*TI+-553MK(HRlr3jns8B zeqAK~f@=Czltl#BbxX(-`dOU4VciCy&P)TGM;cgwy{E1IF3l(#DRZN6BnwKDCM4)~ z3q9rAkp?6-iq0QqhG&Rh1- I85QNG%J`OmhptHG(KV(#g?6n&{$=p9KsbdXsN=h z>IFAt*nA@r*c-0=fZgob^jw{)a}&f8>|J(2ut$63_rOruBXqe~YAgY%r8Ve(6K1oS z5;jkVP0@YBm6`5$P{6w151W~8+f1811$wF6jjIC{^+{KF&AFj9%Opl%PEo?vQ*)@< z)4fjzvtQ}wXFF{&5~ujTkREhY)`sM>&JsyXa-t8KuMmP_0r=VU)7Fo>S*ZjXPDB3r}iy@5uhp(bsYE=`Sp1lo<)jZdk`|Uc`LO zNZs=*3?=bgY2hq`#NJcmBXBPG*79h?+`;yLbGVU;;mUN&)`zYUAeKhhgSau}nUy`e zF#d?P-W$dH7p^1@^&y|mj+}ez>{RSxS0uQ7CGqQE0lc{(2JkzhDJLYcVpQXUr$Mr`hcLc`I@qZo7Fh{6xUYbLF^RWPj=Wj=zWK=Bzy zD%^qwy~Py@tzkWwbwx6(^+HLwE|Zc#A1@ZgRNg0>Xu6qSqcUP6zyE?m)UuT-BqU*p zXTB&z9WGxCi9SqZA9R}eGLYHdg>L%~4N&qfO7_Wv4L<{A1Nn8T^f3b{#aKJ=c|4C=rHYAEQ8Kx(4((h~Fmf{~U84rNFJd{F!&U)_o}Ewt0>Ig+KaVW9~o3-1~UFKWDg)7;ZKqJ~G@G zf)lQ$c#q*eYQP-4Msb)w?zd>?lt?w7WcUnsH-$cmy7wCH-L>wwV)A!q%)O)5-GvyB zx!Ys7P26uHwSkV1rt&g1N>QVUm1z;v!r1WgOIMBF@6tfPgJALG`!P9a;p~aD6Az*p zceQ_*1Lc*S1InI!-}vNW2E|fMAICFoJIH?Yabb-4nPDQgYb^(uBLR#s<9)u^h#oZC z>Os=1uXwydq@S7^DIarh!&y2anoPT+?pGP3NCJeIkV8}Ms6d^1R1@V$#%63P3^k_B zh7n4KvIW#P+#TYhNZX9KO-3xcKv;AROqss}Sz7BEF?X-g)GJLxPO52b_70~lwveuK zKCH=qNK0j+s56%dru(V!2a4>BYwvr#yo_hNTe%qh{;-K=}SrcfjcQA;zg1aT}4qN zY0KVpF+RU7UbSD-b@dn{$$RTo^1ar$ZyEuXTl>|sPRXf^^g*xXdDI99ce?uKUab|H zl2ZRrD0TYdrT+5qQh)t;sgH(~N?$z-o=1-vr^j@Rpv;y z-SMh*-%sC$F4@9@r)r_o4F-69(Vh)WI&^cYjdZ1MtLpZyiZajfPl%B;l#>EuCoB5Q6n zP{@78l$*UqVB1EiP~e9g_JV$(L#KRuG9%@88B=EYpiI?vUe8NIR6@eg6;toD+ZLO0 zV_7ti-rzKeJ{U8%A*Z&^5^7=EqX9Y7mB_@Ve1U+rt*TsYV0-`k5eY&0y|b(dKXA%- ztMXyCO_EzGGAr3ffS>->`8SYi5b`G-a;9DhD)hIRm13jPp(_k^h>tOAEk8jpI246K z{af@H9yR1e&7+y)G(Uh@=H*4#0C^$j$n+OLSR))m97bRH4a@*8aK*8o7rC-t!hxbY zd*TZ?RN#&uGkZ2kQDPshMJ>3*chhm!FLphf4wzQ#QnLxW^Pt}Jp+C9dFk9ie7D=~s z$M=P?$Misl-m)k0n$u?D*+83WEjtmobaU&@3?W3sRI2(%o%&m;-=)*Q+hMlS16`4p z-HF!%M@12X1u`F>4*%8vzkvVd`5P4S@hIG<-d=FfKW+K*pnt?VR1IV2srbSZX?OfM zn_a35;is(L@0jg@w(La?Khw=!pj|B518$v}7&rktBP|{AKSU6^fgKShpxbFQ@yzGG z(DAALAAj!umHq>5`bI%O|2Vb_9cakDv+G7!r(EMPP>F*J1PhsQEiR z6~zgMw=aK;90e7AuawK0I$EUPKPP*~tegb<{hT{B$IEjH%4Ctz{SMnm?LMRXJwtTf z-3B}BK4Vfkd*O++FY&n(>5$g)2!H~Ow*Cu6-S4xpm2p$RaPNtxrmodmZ-j5#c*9!9 znA?e->eANVSR^t|Ut{EIgU6Sb)CPN&JrXnDG0YD#uYmEq-%nfrP!S+|lkaHpsaosl z;F~MX6tK*lqU9#rIamiwN6kII775qbu_M_d2Jq5&iMq*_`_8I_XngyP%LO?rvh zcSd2DU$4@Utt#RY^c@)Ppgm^JDq~wEO5}+I&cw_Mbb5$RO4kPepsjw9p%Y*htK6Mz zD=}wzL5r6B2bI~wc6Eu6gE)M(MhkLb4v~-6w_QQx6b*Yot~pNP9#XtCKQX>kN9BfnVTlL)c`nCvixOwR%~S z6#`BSFGpRFrnKaxOaahURnl5ut5g>~rULh+rmvZRs+Oh!_Qn#2u_~*jqV&V&VA`nM zlgU5`>(mD`t?B|=H6Qx$W4Qb>AD;8W3wXCm%dbtvsM zo;7oe!JyWX6Jg)_Sr2(7Yvy_~M@T~)%URn#hd^b0XEJ#t4w|{uvj7p-p;y2Qz}r}D zTB|3hukoJ()l(!Q{q|Yc0q#@lt!8it(OY3qMUp=K5e_`(83-ix2^3S6D z^Vrq$y`V4VF8<0@k}mwqU3~kH^ld}ZH~o$D(E3BuL)#nr{coj*)*lMb|8zWmtGzix z#yd1UbIA8=horCm8|ll2d>@*=aLD(+)!+Zq{SSp_X#cklfo~{2hkpOckn)4S%Y7_? zUG_pmL2mr;D+ZFLBGJB$$UMRRPt*C^am-f;lTe0}y-A$Za!bTmF>*yicijqCHO%E9 zBQ@1@tAJIs2ob<^->zJmM$gZYgCT#&XRTAM7m#x(E zx{W{-UKjIv)meh*8re?StZ-hll-J-NMBhmI1&mZljgzWyQh)u4U^`hw%5Gu|%J=BF zK^%L_FqeivdW%d&KW(H&KS;2xVLsoez?rr}&D6R)c^J;O!hEZ5bq2(80~diArUBio zakiMBS5%OicC#w;e4YfBjF(~~nP6wXX!K{0697_e{JNiB@QkFUT_9*T>--e$mI0Xt zWHGu&UORydvIynLVku-%2U)D?Ba43(fn|0KpbWJ=miY$x1N1e^XPDzp{KD_}3-9*GZ#mjQ^FSf90g5gP%zH z2TmH7(D;<3n@Gp3lKaOML$43;*RV!E$Ri_TE5uWIxk|RMaU>?Su9^ z9QxrYp{2>q6>>pD2AEyBi?>}mxV_tkq&E#o4=vw5Pgmz`rY zWmGCT!ev~c-qhEX?{j#~AhZ6~Ap|+#Hm0US!o;FD-c2mk(ciCEo7&|@+!qW!r~2O~JYG#0qhM!t3JYFFBAc63DjDCK#|k;M`>P0(pCvH&9S6$Hh{kZ>Ny{3%C6R z%856*X|qgCza`&4iJv}yZ_Xbuf8*64#)k-&mid$OnuF)>1xnjjQL1nL{=@re^S6Z9 z<^23zK|`N1e-BEF|IF0_|Bd+@Hgx`$OXa7j>`d4&x*0HkCpj85VE(=;g_l!!!2C6m z=gi-^(#oLuW7|&6Un9*7p1(0zb%W>co}u%%=O#KECc|RZuA~KL{>pjlpTG0yUFPrm zTrTln&tKs#JHs-S?$FfH26Xm#n%h#do8iyhN2v4;@?5q{;O(s0CkdWC`R7sfWEDIQ zk+AY)NW<-SNMtkce*fqCsb$@|TO`hYTNGtksh5Dv(t7jwGu*2dAFC6!t(!A(kkpjw zW>L0W9O~!lTV|G5>YC3e<4*{u-`F{9QI9RkmdKZ!gx3xutjwJqNjM$xYsK37qSc!T zN}K7IZ^QYf7iC8|A3fUonfb35K0l1_i4jDtxzA}!c8%57%)FQ@j0XMdJ1^iTl&b}e zks~9o;qnnr;*)L7yW)N$r&k$nJp`;AOlO&_oi*BQPae3T5jDb}y`JwCe3$e6iFYlX zoA&DDwjtffoCI;n2kKpMG?qQ~GNnK5v3tq2W_h$Ovu08D?;3m0NKE0#hSnt|Q%iF3 z@xi+nIWMSl@#^rJ zn!B=BOPM-%k6FX!#kbQDE%PcqsxYmTVdB%GT3{ z=xSO8v3ibFG52c~vGT#O@xX>(5B`5-Y7<%nNk7`HkbcG;H_vbf10N- zGqAHqt8k*)2|aBfly)_rWXKLqWYqsbT1LHCG8;*d_q@uBl`oY%L5uw^$HMYp_(i4( zWdeat7*-xAy9vNEKl5O8;P>M*f%J#tXX=`8Ab4!6y zg#tzKF|{qZ#E3{UM>TJt8C5?=c?j>2}%s@^|w?98#@zFdSHc$B{Y}`|8 z&MQMM#LP2uZFjegR2OC3!`P#&WobP5&{TpiC05Y75f|}-a*kU{lz4i7Nf;`Lsk4m| z^i*xH=a{SrcFz0}LJD%^d}mCKW7ZLoAty5H6X!>vTLBcJ~GLDrU<>z>r3v%S;9tv0*aVBQrrXH|rQudi4U zQ}Jh>s8u>#qV2!Lc{jf>plY+{B7G_|=pnYxs^d#`s98jy-eVUnNcP3JW(^sOyNyujM?u-bM4s{t{9XJ?`r#64$;ck z)I2fNYQywdb-rAvbmwC4&V#|a$tz1cLsimVrj(&tORG{hyE$ElnABE_bm|OEC7;`U z`4c5RM5apwug5TFmPyk>5i*zZai0`|(4~<4llQ{B3RzxC&BTRVZ(;vX1!)Qmsi-Ua zTaxaKs9M=&vEVIbiBX32S--mI;j?8_jyq{{f!CL%^MwkUeN+%=#&IZ?woGT7Q9<+~^yDfY+GGDB4O>52L!uUorBu9xyl2*uA4LSnxOL)^zfNjFxj%86fhu3Q zLtpzuxddc4_6|#2r3-0;Z?EyB`HC zYW~HrezQ;De@OH(Q9;z9*&*|*JR`)EaT-npAlJh0y?gH@uI(9yTyb|JSt=4A$bu2n zDcYRm1W^_j#Vl6!yYU+hYbIFej8<+oPQI;A|0gw`#Kk(%T1wa?&K1aesIPCR;4dQD zF6D|2#&t%m^<#wyX{aRX{!8{Zv4O{k`*aL^IWPpsdlPyBgpA^XiXxn}p2IO5g6FNm zJ|V5+q~iW%=R7r|V^>Z5TBGc9)Io5gEIYy;{q>6r@P2arnoq8;yjOm}w{Q9*>)LDI&EyKKsnORyEGN&A`J4R!{WvZ* zdUWhvQBn~e7k}+Pv9s1TmrwAq8qAk<^Nkn*q0Mdasr)}*N8>1SCC2MWmofxFd^U$u z;t#Pb{Mk!D3CAPQH6<3j!u|!cqc^^&T5=^`7EAIaAnq$=ON2Fsd`8?EQD$NS?vQ^R zNB7C!=ImL(9?dHa-*Bp-x{4QMGHL}DxA;2T6v{5gi&%}bdy@;5Cu;5yE|$9ZlK;SR ztK1fI@3%)$p{4Dih!Fb2XbT2@OmU81mjl7^(XvP?VKbiG$iyUmoZ!&U`IZ`g29R)H zhkcz)cxTBj+_&;ie^H*!f%R&27rFk00_St45kZ>lEm;x8Gc)#dV{jxfg^8=z&T}UZ zyxrJqBraV$uSmUqHZfuCykhk_KQVUgJdb)^kQml@f62A+kw%Wl!>+`yIeRyVJc##P zFgC}%Kg%y`y!J|i7^wIdM11zJ-q?F(e5`>4SnDHhe%TSpz!uE4Wj%0uC{}45!wB1r znq!}L7n&{1f72o1Rvhk$vh`z){_@X-XFF%OB!pBJaSTmnH_yh6hMx!bBl6cs{gb*q z8l3GtgE~!V`KTvf2GJZYvmbn?Un^Zlc`-`r#3DJ)APHYMTt(EsEpOQXV- z;3x|!C9CcylrlJpZy9CwKgxTjEN55dasC+AO=Yp5hy?@AuB87Q)C~C05ZM4TA0=I> z{PFZBh3NMtx^UzN^1oOztJy{@O!&iq z^V4t@b$F#>sF(%pK;PJ(2rBSf5%g=gROm!09g(&pH9{TYG%$h#M`=y1!7LSm9JUQ zdRv7t{VTo)*4$Y1d!6s;JOT_SmMv6s6myNIaHv9Vy+3R$tA zHQXF?WWF6AuLt819{irfH&oChu`A-@_48Vi@EV-O;*8lias4DpWYG^Zb{>>w`Jnwq zj@~f&t4fSu=gJ~sQO?;F#xlU)$&Wx-&#D1H=hoOTqY&r8tB8(AuP<_iwAK^$zxN1U za`9q32chP}@v{xjP#+Wz-0GCT-Z#S&( zNk>GM{GK!XgsG0Ae{nx0_o>2_&%3jnux2R{Q!G7TE5B*Kr<7Z@Jn29d;^zQnZ{m&Y zGx@$Y)2QG(`x}v${hIEO=^y(03-yLo$)&{Q8<>0Hq#{5&WSIAdB|4LsnP58$CC5T3 zRf^K9*~12RpE(LrL3cMSQ8we;gm4qfo@T;Xh?8ek&e|Gyu16b@Q{-F4U1fX9ksT~^^ux>F^mf;N`k~+!`M49*jq8xkXR6P5`aOq*{8~2;y)D7|51ztTD@}*W`{uB29 zKIZ?cj#D7axz@0G3+6vZhNUx6U=hK4;~2B^%dFYhJ7?z&|90(>AaF)8-f?7#)qfdD zi@*j^Tpc@KS^b;~7BvzNvj_#={Pv5#leHpjA}=V!>gNJZiZU3-A3(woU7AWUbE3kw z=+`l`-miSNV*H=P_^)w{{~Dh)ztnmFC&qcHIc^U9q~bT^xL<72QMud1o!o=GP# zIifw+8wvJ^<=-AQ>#+RsfzDL)5mU}??3bu`UQCdGF#CgOE}dN~mi6qtjttJ*`G#5b zaZ`UE=pJn9zd}yI)NkiqBn=BCZxbnTr39=@o6J}hWfc9YsS~=oP?*K}a?{02+`gjd z!tmJ}<-HTehKbn_4b~ypYb~rUHy2?D1H-JZMc&OZV=iB|IBJejy-3HtT5A}ec*y6l z8`BL^Gkk0B3nDWLzQ$FgGh3L+ntv9lt&+RD9ir?r^g%@^*nowG9Uj$U5{G7*A zas2vzCf0ARqu;2AAIN7C++Hz<9vLpNBGI}XnjeJA|M`i@eY@&@q0 zna*3kMFJ+*8J9-QKN;2vzdEz+Fng|uDoFXh{UlZ{KT9;qz8pSGeTBb%`oVRqmU z5gDQC42eIlj%dGT8`d+H5OX4`YR%1#Yu35CiDkJw&cK;U7RSxEEpt}5o%;U0Mz;AE#k*aF1u$~R8vU$IKokV_FXUgj%XcV+}2JdUaEQt&Gw3Zj{DQ9Pk+mvbuz}{?N<_*Nyr^7e1 zAHGdf0q9=<$bs+IlAQnFf^YQuf*J+izq~ydzGLsP!2c$E`FKpLr2B`W-cCDp4G-(7 z3iKhF&j5<`^P>NPSNWMcanBGWUMAN}sOwNgIjons3hR42D3{$PRL?n|0@0dXoSVCj zb>d2R%&zPgo7NtdgBY4P8G>>PSdF|@|>A!+Oh4`XHWoEe5UDC)wHU4T(-CE z`SY6&X#8vH9m&7=#OE(eo^r>_noe!5`|i>>8`w>!UagsOcVgJ{cV>&8Kd)n*qId6# zk&Qvu{Uw&}*1GyY$lu@`oOLfRtspUDKaI@;L9s!k!B%{k~N2(Nly_F|{_CHdmNQe{_BHW&XLJ71K& z#h2aX7_fP(V(9qQ=I+z7q|EIc!813r(H=iX){LKn0=7ldxwiO~1|EmSuJ|QJ%38<7 zhMG^rhx7gv@8Sq)+AK}TLe5n3;`m19Tn*uV7jFo&&|hE>0R8a+gYm!M2MYhP?mv$I z;pi9z{8u>mpZe~93;!=8WT@GX|G&Ibs5c1zukZXH;s0Or#s6>Mf8c&JPSL;#sKBuP zsr;v45tk_8ToJP~#>*Xl3I3v7ko-{9+VC&AZrO_clH>P1ge57z){N7zA;0|qC2)qr z|AyQ_?+9(Ryv z7PcvNSV+d;KAK%9&K)c~2`jbtJH8S_3V?+-aJWEjdw@g1(^n7R{B|?0?CeBlrulH9 ztfA$EpzZ$Rem_q~-p|vg_2*alApNxIkie<{@0zK##$1=plE0TLW}~O~`_lW%!Xvh- z%qt2nllkB!G1H8B{Ly5ahbsg^iMCkE*&F4zVYwA{j!Xf!&!;11hn}`a>gkTr>9iIO z?1^v_e;`e%zl4it`pF*?c2lZL=Zv17?&8;Th` zg82t-p)%8WWmwMXt;5pWM(LA|1h`K-olXxA?6ek4@ax6nF5rBT$IZ=C?I(9l>J0~a zBj($Z+!mSiru)ON`AT|QQTmn90WQeimTn&@&$q(tjZfM}*;%O>l@arG_c8M$ZX9Vk zEk<|zEb~Z&GUiJl0&anBn~B5Gb@yuw!_&|ist`5IA9imu>pW^??zfOOyp@LCyRedZ z^M&2L{1y^#_2Vt_TSG0a z&~5Vmd+SHy}>OH|DjLgl%MV!B+m-|U|F2#6K~2rZV9DTi~PP@ zh8rK#sjFWY-+*c7%HCq>OHumkm?BhX8Et-?YfC?~CRThIuqWHRW=;9>F}WIlf~YjP znaPzMmwaHUD>0@a*&D(k3o^bXfl4{-s}B+zEKXV|#cQYo*($m1J8qZhwn}d1N#KK@ zwp^y}u}Y$3G<53FgQlvyPgs+S4u9t~RW z$wNkHy<2>>70Orpw0c~(goh*T88iMy1iaRa_A6S0Y}IVQWiAXVv`e<^aMy7dNRGu2 z7D5~d0g%Bq@d)mcbIjvBOo{H^l|9HMrH+Xno+S4Z;r?gi*DIkf4bH}Idz2XJlW&QW z%O9COFPykOGX2(2f@?*i)$}YE*Ut#ER!J0mUiN6Dr1EqrH^hyZtbIX1UyN^!rq??;8vOE2`o&5QzXRJ4as(nwtB5f zvNq7Wq7ycCk^@9Ph#Mnq>%V62e z4HKm?^8@ZdrT39ZhUNulEWp1O|I#nB}^RuaS>*Sa~Clu?~a%%>>sl8 zCJS5wc^i3h&-5iWA;<_tzuMu7F*}26dy3oD2v5;we6|Qo`&?nQhrvcAxM$& z|49)DyWQzjcIKnK}u5@Fr2~rwYb60#U@=lO6@a>RoZxJ`pOx`h8%8ae^UPkkXlBuPi%){=8&!nQ^`x2UFq zr(%LbN zr!LZ((-Z;O{EU@)xoYKjV}q-l)*I=d+x{t+T791{hPivw!{myExETL<%zU5aB$wHl zX<@hfVYiE2_IpTTwmLnzSa9F6acg~zy(1IeEmY5SWe+v>j*cJSbd|J%5@w0ehAl!t z#Qzv*b7D@W#&;feyX+hJnCnX14bKZDd;BYJ53ju*^v>8a%#|%c<(T1@kOI-Jlv+_M zmz7HV+s$n>+Hyjas)~4Vc+K@Ra*5)0Gq95VD>P99^n85d)P1qk_!D2JN^10xCbw&6Z|b%jf}~V@ zMA!ZPez!|&wRNlBmp)h)v8Fz!wPqqyraq3tA~L0laz1lc#G3q^`7+ls^5NU&vGieX z2ieNyj$Cv`&bQ2VsXArys*pXMoynH?isE1h(4vxYaZrTiRSM%J!vnIa~Hc#qPCjX~C zWeIz{Z>Eowk$Qxk@^O0lh>v#@(e*MHpvnH#I4+&z_8jDnY11p$*aO71}Z~}7K&-((<3W|pyEV=TWWQe38FQ`(B$`{F7o%Ri-q@~WEvC8er#mY-@ zg!nDzT4TRH#q*z2B&r}a?R-9y{H~~y6;|mt^eLq;u-QH(Rz8kbm0e{`{Z7r4sn1Ly z+(4f)RpnJ%GoGuN;@L?0AEj!jW=iSL^(iyHr&Q7@50+0Lp-R^A@{gGv=tC&z&#mCZ z6Oko&yitl6PN`S*gd2y%INuc91mVEez9LoRdRzjk_;mEZ)*7l*;rF4?Y+l)UiaWrAwG?(P9N||w}u{2Un=Nqf}TFWFU@i_6h0AEh>XH}8SiwY z@)2Zc<~mA8sZ6bFRW^p5}w8# zU8q22^Ai#vYL0u1AJ5dA_6ZB(l-&kyEpl1;HZ)*v%@rq2Lgf1GEMwI|EH$&j zETZ1Us#Zy%5)Lk^$OVza)lW&dU3ciJeAL{pZxW3ZR&zet{NhT@<(?+vDeD)_3W%er z3D=~1hL7mrB0!>MQxnc3rH|-f%=n~s^IM;iF`}LIYrdKCoRQ8AAHluNZGoeK-QmFQ zz>eh6J7%u&xTCqYXj6{@_pz=z*hPx-4*1A-c`b~7-n)e*^^I0B2Y<$jyio2y~a{A`@@mJ9r=8GRJWhP&(Ts>@wL~sx|+ZPUM!c=Bw#WPj=;!y(6`j z(ZvoAoLK0aCOQ1QV zpg9UG3bN8XWIodv7lTZbnJ*y?LDHj1LDIT?4p{du14;E0*cF3^2~-Ftpn5Zpqrf(E zPdXzEq|^&*2ymy|_I#qu`G%n3UPkrVOAdg%s{pYTAcu658^Eb`0_UX+P8FSE97X!5 z0f1Jr1pCZ)V2^GdXBq|!Z4YhMIk+D8f3fy1@KG06|9>`w5H8^xZi3Zns?i2f8@wh0 zx(f+xaATvOQmd5~OR1uw>_QaO#Z4faWfhgSwzVzwu`RZ?Qhy4Fr~!opuYj#$pFSFW zZ2hjQg4%M?YX0xf%=f$5pte4**FP_1zjHrx=FFKhXU?2ak6u8}nVfMrJ#t#~4nZdM ziR>cU&8cRu_1GFUhg0{;V>?GCqEDmf%4p9vT}lI(Q;_dD?yx^ge9?iSeXt^x*l3Q@ zGNd-Tb&q2_&?f~(Z0&k49En@B9_WXx7XEM{js`GXQ_?9LDFnYgv6 zii!80xro=XOmNif$eGa%Dq}X)aq-TW(M4pE7OX>8Aq|7m@?$mYs|vh}cK&Aj(X|4F z<Ce+i@5(#d+0idn;{7~}v6wsid8%a#u4VDI)$T|yAflWQ%#)LVN z`cn7AUKVw)8jCu|UZ|UbMI92XnygZjJy+?baFx!tsN>D)3xHTwOrz{Qx+w%x_8wi6 z27R7?k8ZB)>t<@dJ3}gmuzNZE)lQjn7{%GA3}@;bVJ=9P2s%$U>YA)Y9kzIm8S=iG z@w!g;FQC#56Is-G*Xg)RcL7Z3Moj9CFeY`A(u-wM_m%zm7Io)T)?rb{b-G>_bsSmi zmJCNiT&Kgb4o#|@^&ezacc`rDlF!=fbZ>=FSbY(rI=T_ob-GQuPWQ6A=l?-W^mCNG zJ{S2cvpU_B>1|f`1~I-_-7dam-Bzt_E~Zx@EG8jUMOD@&rx>%kYVsI*Hsc5GV#kp? zc8nmn3J5%!FsAe0Qnf-4@lwon)?%ekpyny_HE`uD$wnj67CLg@gQBABvuy~Qi=6IZA2xiD0l0g z=0ZdSw)8Lb#iF@jZK@A?H+FtDD`gXuC3BUjQ2sI`3Rk+vJx5VfT?k{X5@)&YBKz&7 zDC4^9(J>VeTG$Y|hdxgM51!3R?hRX>7Kv z&QW)l`~qC7xS7)kGzhXETBFk5Esi|3eCB?2)GspPH>QmeH?ziP-nBQo7$pcC0(yKnF@oQ<^@BbyL^qOtG zJD)DSRz;H!+I8tO;J@@4;Qw@dPPw7|C-*aqjSw51r#ZVpV_JtU1InMyT~Q6OTLVE@ z`)&>e?6AAXfL#ICMF;A+)a3pN&4FwSmva~aso@Pqdu7ogIj&WXosi@TtFz0y#_yl6 z(K^m_Idf;vZVre}6HQEbmg`gn7tA>|k z_5(}Xq^4loRYTCRP8$E}!b8%HzleW$#Dbye@T+5Y#t$5^aL@z6Z1Dr#*}@0nqc^u+ zFoZgOP94Y+ZhvV=(xvwj3|3z?BzjEt2q`v)BIf>?_|?R_e?uQ3g2|ugwvxIx;r^U$oZw)Oj$P7iwdcxW_ZZJK=qXiu(aIb?I ziVcsJbsU8EC8z+7jA`}G*gseUs?cdxg_GfGU3Qh3RCS*IJI_7^i;HLNg$cBAGI~1M zv|}3?P9vT@*WnykaGk^5^m|1ai7QqrPFqC;r%%~$$*h+nB*^jQ5AHD!B(lb{37Lyk zKa6b@P@AKYqcts3LEV;!{Uaw*V7b7mew4Y)kR6(fZoscV1680s>+(r8Zz6abP%~cf z>rRBYpN^iIc=#@%D0Y0Rz9Jp^B+>OTW~K)QEgZDId>9}|PZ&EYHK{V)xSyk*1tSyt z2StY_9+|E}(Q^`yG@8{I&|>31>+%mWJcFIl&Vc7BeaD_nCK-M!>`vmkKJbOd!q(VzHIcoJVNDOiH%Av z8w0Lip2R1IgGSj4YmSMA&R9$9NzPfa*ASYe&?1GzXBQF5o>!Z?MV(SZXUKr@4Ck>Q z))S!v^RB*diAUn}9Z8ahiz$>)71gTZ%Y^P#=r}_70?Il>JfVm~iD206X(Kw|UKRj7 z_N!mMjpIf&bMJlP!~Vr{r&-fbP8Ygp7dCHiW3Mz<9Y1{&+`5B+vUPJnH^I4o@>`JG z`zH9W6_s}r{0~$e85cC7i*5!mmvu8>r$m=vIdW%V{!MVtrwcRS$gqDi-Cn))Z=&~@ z!+YS`TjAk6PXPZv+z(&FjzIHj*S++HDK*(x%C8lkGB3al>Qh_{g>h-}JN2AO?@}PS zLO*_x@|@th=OZbpsx(!Bdzr6dWe|HbdzujtRYQL(vn3lV&4)4Yq~td#q5Hw3+;fpr zR7bt7!!reqJ!b1b+Vkpwwi~Nd2mcI0Y%X+1=IXfN5er9OTZd=P7<&wu?nE9HOe6SS zWxt)4v!IR4U_&5LPX4I0QNrvD-TY*OkWe9pkd4~T*a@Nt4$Vs3->fziVH3k)_eTnM zn9Sg=!064t2sx+%;YYg=Oh8k2*a-7hFK+u!L$jRBh1Y-tqF58z?@JF=IB~J=B`wWeqwlrdx^pwCbPku_QGET zbE;jKqjMH>HiDyMutxJenDY~wz}yTEbIldYY3H+%H?J4+nhr)@*!}IVE%NT>*C6lt z9P;L5{=v7esx-f-ufnOJ;hG`W7CS$Z3Nl}~BgcPA*Zl=lK{)d2Obw{xZ57TJLJrTW zZR4vXb>1Kzgdz|Q>_7*`KaDtJ;op)}a1b9{K6cizb>Ww%vD_n9@i@?SEp9m|RKLlR z+?kZ(n3~X3@Xi2FY;EI(6JFpN;J*2bTsh%mWc=ZuXtbh(H?T$&Yz- znMeGDO_W=Xe1Rf#JyCjU)oK2|O}v>zF{T19U1nq^-8>7F9x>NT?_%Lmd6YvoU5@an zywOW<_tIGgZF+y3e!7>w%1akgP5l`yoaqrqc0Q6G{U6|$A8pfr?4`FKoZjE2 z$G!AbUiv`4e1;GDf0dUWKRA7xO`qYV&-Bs<`Q`7m>65+mpqDNq4b#7*O+V2~FZa?1 z+w|y_w0)SDR^+8QUfQ{&_4CqPqyddPoKf}acyz=E92E%X&v36;+R;gwwBy;T^9E2Pz{TPJKD*B#OjT}w0tFNEHTD*<4e6qG>9;cSd$4zNQFK5k zrB@r^N(2ir%68T%Tu4|T;_Ps30pD&j#@5MAOEY!NJDu82s_>YUC*RFO+-AR9g;ed1 z{-s%<%>DBTcZ)*o-Se^bTel_LW9+wXOSp&H?w5{`$O76!OD?!c=0$VB z4Hfdt1V46noapqvD~aFkeOK|l%lpRpDq~{v2l;lr?=aso`BFWNeDBxyk|zoZ6(yZy zniEYW&dAIpN$V)05t^m&D#>1K&9#=I)w)9tCk$dgF4 z1M87Us`D3BO_B?L;Vq@sL6NR&R%YJQvI;1stPvhjfiz-0YFvO78lc=SQ&L}*?lAKO z_6G2wN(=RyI#xrw9_zi5aOz~1YhL$AJUOpt6LHXaLaRYo-^n;?^Gr3l8nVYk-e)`& zwMHtYguILY9d*fPqTiB%Mk5A+oaVQ4v5j54u5aUR>tpx%4vkwku5F#V-R_WwnRm`w z_GO%IyZ`G-Qk~0{ZHZ*;b=pkf#rCE*=h2(pa*iBi+fZb#<)`|txk7hz)=Rjio+nK! za_h896y@iuPu*%}#?fpE(O~s&NIfnYKKo}9R`cNwFbUB&Yf~rA4kbP=j136IACHoP z{e&V$nuwSpqMPy0HKiC04(9|nzb{I-Rny2>w>^8Pl7_?%Q_}Zrl4cc2?i{RCQC_r! zQp;M2V(7n)?}Z{9R7}z9-$knf+3Lhcg?todzn1u@4Y&p+hF`yvH}bGKv$h&o)gm{eZ69Y7kE|s`*C!sArjl#a zj6`hUUZQxS_wNuFcW+Bfhoi$RBKk+tR~6w?GF!|)a+Q;KT+9TcZ@$Dz&~!;Z9!ia5 zypG|fo_hm_2{dYW&T9s-PIH?f+*=LrdDe?tKwLxWH;Ur`w}hh5W%R82R8a+b@i4Mm zx^IG8l5lZkmhJ8_rrsjCH75uD0T zc|i;x9Kn+88)^i2f2rzCLtn~kXruHlWXNmiP}5M%cxAz!`;FLRnRVD7_=tqCWBm*o znYE31;IH|D71<>haXl_6^~yNu|^T8 zHgiX_BW_4UwRFS{jo8m7s?Z;?nil%&2p&G?>iN-*V08&05~^9vBr|LcmUM58OBmzl z8}{dy`ss+z;YY1@#P8!vAkOZHhxxqfDn3@4kFCK0S9QeOX+?r*M|>V%a0Koa#5Ju0 zfsS|+86}kxwb+yq2R@d&UGg_b9)hv=fJoo^3oqGhqVZ{bXgGPZ>FJWqUWap;tR}!; zsqFw9#7|e#nl7`I15gAT*irnV#m4XzQcONOw*6rtKzxu>yXPY5W@9BAN#19iP8p5! zN<%*%{7yFValw}OaM*%cyrv>ABwpJSKM;(awyCQy(KTL{s$)WJ4gFQ#aB`es1-AIL zwJxu?Q{|~g6q!ZQmvN8(Uu#G9qEgZ}C7fPvnm5N1_VH~&ro!%h;L$d|RobuJyyi+v?IwMrK?YAdV7qI*?dq8a zrd0K2t_4CD*mq3-E|;&IwI6${p3~ePVv<^2O7zhO*d5)@NlDl@W9Hnt*%&2bkB@9~ z{vcy-7_y_8zR%!9Ti8qN%?Wycml@+o5B$bT(eH%rsziGC{)Sl`paL~4(e)#J1E>sg9XRARVYr0YqmTfpTI|vS*gQ z$dl4fZD<4tcgfHEo}8hcO#FlGNjqtb(-`8+9!6s%zfT@@qZWt>fZ3^`J`6PEklTPl z8*0vL=LofPXs(@|duit{?AleEX@}ZQrm@$Rp!0=X0!xx6kay4K#oG-`zfrcIkju{2b z5AvNS7XCSlEi6BD;rd-aqN)r0gC6%McY)T?PpY0UEHje&CU%31M&TMsT&hx0$!DFF z+#KkJ=gFD^W>gEasv-%F)FO3kBsHrN_G{#Ymqo@^fTZy^YcDQ&SCL77wW$d&N1+@c zi{nlsQHM#t(@SS6EYPPrAB<~TkYdhBgTz;y0ER$RR-Ksfs&{I6Co>TF9)um>xT8Zvkddv{V!$ z-r$SC`lwRIhowSNs8XTSQf>JSIhB4uZIjEmtv;FaGUGnshq>B+r1O~x2kxL#9tYt- zmzlu(4MyQT4Jp;@bGr0tvZ<47UF>Ms?x!Y&dm)7F&Ds1vX_WguqF8f#o2?+$ADnkm zbry`k&1lk#h@`$_mNN~Y5QH~UgP;=V&>f7%Bx5ch;Xqi0Afo7i_)TR1`ZRJeV9%LP ztws#x2p=Tc80L@45qFw(^Ypf}V zJvue~K{cFA4Wbhr3`^t0ejR%A#skCpj9@?KH4s)p>HM4wR!>e`P%f_sGTO?1)~iAc z%-Gz&-vo~iwrw<1skwbkz^U8MzHf0waY3-v#zt?@&C0nzd1FBx+wwutBhg4tuNa`p zj>^E-(xvMdI8HC!1Sc2S2Ay;A_Nt%f6W8SVlb7dG@)$f8Lr+rU*H-j*pK^Q9XiOB8 z+dV~DF|RI5Px%B*k+aNbjwr>5c&~E|by_$SE=Y9kZVlmO;EGW^VGL`XRt<6xqTJWs z#8uTa-b#HSBo4TOyq8r-tA-L>k13Dc%LMp7697S2WNfx*wW%2USuUEZi_dc)C}d*c zs*7JBzb}M{C#BT1N~n{|54@#7wP7a2oyS4&Yc1o%st0e&C$!R$v3uo4c8wv}jfP;w z#wjNTP92hDX zX#<+{DQ=`066AymrNqR+gsVCJ;ioD!k;AbMNi0`RVk+I(Q<~1P=?rkIsPTLbcQQv# zD<~L0EjCtGk}H2D)J!S~K^9f2yqq@xw1A7&WbiT!ZKAfVZ$X{m?&qB5_u;0Gfh@KQ zrwHBSL$L>hjI<)3ogP&M9Z=zUsQ1LIK~YMWSsodpx6E!fXz zHDYYE)W8|86Kb1$9bt$}9XcVLSTu^QwVXa{OPMXvm-vBZf(p?>ZHHHYwYoCY##=Vd z+G$u^yqxHAup95cdA1gA^14U-4Mw7kB#D$6rMTa|VS<=rxL5O;TQt}0i5|*z!lgHp zUC(Ij(yy#+UnKVHP8Xue+EG z?@ZCQkQip`BAU+$AJ}tQ@@64t4&>4H41YezLuj0`kUmxAkvzm1T0c~^63=xLi$ZKu z=V=+I=GCNq4(ao9g-E|Pd6y9$*)q?ek|6xW5_ia>Zhnh;(e{tgLNZvL6c#zvHwx&| z-S~KMA45LzXb^iauJl{7?4fJ$?be{q%bvI4D9T5YJKPPgQ(nsG4WD>1t8EPDeocWs z3kGrR`#`KX-qa@(@WnY+EgRX-A5pkvIn7kM zPjAVgOryEz91%5_tvCZz-wwFH)jpkz5?Hvoub7jBl?HKkYa7EV5)ruMY~jB4%MwSGB4^Kn&%OQ@xv+AYp9m9~*jkcZ z4|WF#cX5;qG;c^ijO{#FlqX0PW(FF*WPRrNb%oYzkX)BNd~&NsuSRu3hiZsgpScT< zAgN#L0H~a|a=AV&0K4IJU0tMVm6`#Ah{{mfbpcTezT#Nf3hs-*x_C@4td!RhNiJ^c%0WQXNvd1{rC8Uh#HTL zL_gPe!4SU!RM&mouRf**tn>|Q(yRj@TUIhffu=sxUG5_a0mS`IyTy`>q*hviMMFYX zGsfWBz5j7#G1BEg#ypgGw3(UVCbm>I}OI@s5p`(oZyij`?P*8f?X%QrKfbq1Qb1+lXL z>WYF`sR3kb-4$4e*3Baj20D0B>E*wWRe7+xE?F0KKh%EPBMjgSmDC}?F0L3zrvzy( zDbY&E@4K;smEc_2kbbD01noB@*_&aYBgoN{s@=h_62q3xh~Mwk4&>pkJBjhPA`BVF zf0MXDwqNC{j2~{sSA%cmBCQ_}@1O|l?WN2WH8pl;cBJ|px*-pqb23+S(+^FwpUJOI zD!!kr_(FTTew>-$PRlQemnfD5g`A@QKki?vngIkeEh>{P-AG(U_I|>^2?f#PaGU3} zoK~*_r4N(nKJ!yml5zj^LeC~QqlZvfb+^-^NJg80a)tocL5FGxP9QE28dDdY0Ejm( zr`PWgs=-*5;(p)}_i5$PQ*o3&sMc`N&$+rE%)gfuG0+4h86v zkpaIFYFqkazC+1w0N@N-M`2qMe+#f`56C=dQ*fA=E*+-w4^tjsoMtmQQn!eExKAz- zLJ`|F&qlVfNVKkH=-K+1-7EtYliK3VpHV@j#VIuG-mo(dt@|bdB)e)lAaDZgC7$zl zbO-OS;o55HQ6^MwrHKvB{FQMX`%Z|*5(~$^18==f*yXp$`(3DC`Osi$f`K;(3a?0m zM(4qn%jilPtga+`7=$Sd3KDn>Sc~F$%(kuGsyf4maujaPW|y1xbbSc@&T<2U0+nW~ z?mo<>l#B6dceHL=A=e1Zkn}8})?$K!Hq<&fz^7W^vyj{FPV(Rc=UxQWtUs=Ik_PDa6Lwn6^10EHS8R+gK8w+bEFqVzI=A#F z#QhB`q}P}?x`aAuh7|-|!F%qD92RCH0`Wxu*c3I@Mgvm;I=`(;jRBpq{!Up-yqEw) zu=^(v!7=76B;%fd^pd&%EO!0g)Q=q%YMX*%h|)b|>uL2lVg~#a=GRHDy}Sql+&^Je zylE61!|aV%oFJBu~VQ;y`?!Pk$V%2#QG?gYa3&1Q7mP;lavno z6PfCC0`;%U1cbP@l>X#?!_Ij zvup}!lJ9i3tZkK8Y(x6%<9!*=3J2n|MdA@wuvTOxCL-f0WGL&~D0kx%icJ^wMyP57 z%*TElC_uA`QC;cJ_#FEV??3&D4>thlHM?)bk^IWHRWaIqD8_y34ru93a(DiKOn)UL zkW`tm`I8esoZ5AVYPR2aI)cid3{2yi&B+9E>lpi${(2x>Gby~VD0zV0WwQBSCL4F+ zXC25s8J{roVnJ^p+|{_zBF3`xt~BEd7%R(t=M@SfvlqqV$$JnmM? z{b9%rfxn%3nsq`~XP8@SsjZz#Vqw3^@mkkU#|uMz@%?8O#42rloZ6P>#`RMbUatzN z4ZjyShp`@w=+Sv}I_%VSNHNW(V*2eYlIhwCrkLGntyhmC&g3q!iO9HnEdIX|8Dqb2 zl(PVxr0BF<=o?P?OgCkSI9U;W6p);EEwdI>poBO@yGeA@ zb#yzF*xz^IVf@?2SvHqlC0~WnDGEnNW*P<%kq*8uuggoPm(cZb#7GGs*w_o!5%lhK>MPoY64b4C0+W3%rPMBw*m+cGdZkYQfKR_uUF;N zlT;q2pyqVBd;1n6B{ml_?LpUYYSmgNR2H~D_!-0uP1xQ(Z6l6*=oV zlABrjB$H9!41Nf$v7wpDjf)u%Sa;f2+mqf53;lW2tOB4=%wqnSyS%&Jv@Bu%yI zkf&xz1)^So%}xbv_HuK?EeLigFJ(j*WKrv6X;hX``d(@D%%m7dP)ZvdduniR9Ldyb ziwhajT(8kDnWSPx?=gq+A_AF*G)WIGUkk+TAzLluHBZVB!!#{8R`o6AcAOj(3Oehi z4u;~`fThmE)@KL#t1O?kqwWjoXo9_ovIZEWplSWs?(z3L0TEus;b?ftMuUk5`!aCL zrm)**C^?lrzg+lG_c&W|nolHQ?B2ccB|w0U=xM}DlVN&@JfdG|=bW_{_CqlwG7|1^ zZ{z1O9!{OL!D6QNwn!hV%fz)&|Lv41>A$_6n?QZ+@>idH0>`LDyzzBjN&S-lrRwh4 zso^830f#&szD2xzOK~>8i8oNfeY~Zr|Bl(HwfplB=F_ufiQoU_=m_vyE?_am6eoAt zu4fl5MVX5h!gRt~Um5WH*=Ab$;GX2B;M%}!9avn!q+8mBm$BC66oB#uQK_!uBS}y-};wB@iA{SKXOEMrpFUwX~336iRG5zG2q3NR1_x`FSI` zNx6P{eYgt%hQLh`RZhFghug;Mv6$8o?*xfOg}R-wqp#qk&(74P9|U4(qT zR+uWuv9+D#RGWEhtr3lt-Rhe|K-RsGOmekiUNpEaHMN8y>ajODL#bPLN)lUbq5%OuX4sL(>|i%@yn*}_i_1GTGES_?n|IKM zrby@BMCMNU{Np|1f}m>^&FW966DQVR^1h0=eim0W`P@x(ERft6Ft^O@_nqcfcQbP7 z(l3E^cR$-@5u8TgGnPopV6{YE{aCL$eo7tQN~zx4mGTO9?tr8S{rQV!MwYu?d>QeG z9fMJ`CH6ZTf&|yc`3DV+KbF$vaAX2N2yB(CWM3b5n5NI!!4sbq9|4XBY6UzPlRZ% zgIYk%880iOPFPtMmFzE4&RVNkV)m%BVu7pp)!urIX~2#P!zkgU(v-B@ZEEAhaHUyL zHCCE{dng+6jtIF#tmILqmX+QSVeV{q1v&Kxv?4wI@fp`Ie~kMa?{}ttW!|c#lI5^* zFu&E@?c}Elag5!OPbJV)rTfQwdyVdOsI9^EkXxXT7f~09_^IDv{dx&xJP=G znnbD0>3{1*1ODt5JVqWDzVzp@2s0Rojs952@O+7o?v^lbon`MIFEBGr$o&Rk@@FPpbw&=j+I_XP-O^yeunXP8Mwm0bX$yN56fP!Og8clgcXah?nWC5tpX zW8Kl;BX_#=Ic2_A2G|C&Jday^i~NYON;3X~L1 zH+H)}R3uBZB8wMH^wX)a@4rrTcg_qkCzaXq@c~*_M0O zIZ(K5ZHDSb1QIyfQkyLhB{cyQZx5L<{~=860?xP5AlE7zJBL_SVaaSbA)&l%^KR6h@5M;S&p4{ZY>K>{c zJj7W-azSzn_N1@^XI-b2H$F;phQCD}Dp$wY_NZg*Y(!eXW=KnOGpJ;(_Vl@m@7gg| zkF33xM^hY?O~Rh*V-coDO^ueC?8P$i)hgzJ&zwbF?f^y>wl>G(q3XJt)o#L&juuLV zJ(9{}uX&s3?dn<{m-VFy(KYd6z9Jf*`O-C!nEv<_Y3WZL)-Qih5u|jnNXg^6sD-Qm z5JCdT@m;7%yf;r2aDV$tJ1V1%isG`JCW2qW&m=C76?G3i7TCJ7melyDdN=L zW4MG6>1{+c1T)nIt&z^Uzk*<=`BqBdd^NL7r5Qqvi-@p5zdS0j6jh`*ToG@$I8WgK ze!1PLoymcZ^4p3r+@+ky)u(;iRMF=~$a5swR8O2_^Kwg%__Fu`)7zHAQL|-EgF}e~ zKFv*5dfKN44Y%-3!R+`ir4X~ZQ82?D4J@9lXqb&Z@@6biaL`w>X~caRVMozKl$n{Z ziq#|$HHWBbDwR@Wm5rJ~)EuIOd}8!RM%LyBjQ~lsPYd#tr|2@9J8tr-F4zl6GW+Wx z2Qd|qL5`;|6r(68)T&$V4}W24Vg$00C-DndI|HxNjy*l%=S?sWf0{<%VC8z8qwlRm z=PlKp&E(QEA2boBigVI~%H4(6YZ&dA`V8iE_ckp`C=n3#-1Eudugii;qNi?CP{;uI z&>9P1v=3!`Ae`m{rW2MWXss?G?5#R0_!RMqF4dPDVMDLV24B6)8xfDSK)4>CKu(;b z_2=)OMJOulZx4GB%4-R==BdLNnsSrTZYut7gd(c&?F1Q2pDOYQC7&dGN;!xmd`f|6 zdQpd2eEv@)5(XT1K1bkMecmUKW8ylSy$E%IhE7NpA-Iqt!}^b#?Rq10VbKz8vNKt^ zG^#?5Hm;yD|LkA6H`y4tjQ2ZX713{rJUMOLh7rN^+2?-{%BJyP0A}+|3%w{Nx zIP7%RJ!k3okIQ5YrrNd8<$;>;K8uuR;L-(-z zEyNqBoU_{D0Zt$cfP)0!DKOz|Ve(y{If@Ne2}SABx+P33IB$W19?#^Ck@%x~tN|gP zAHw0?papUdGtw<0hq@Z~N*i-4|JYY2tu*Xj`g_3^JxUNrq}+W;kBtaubDGb239fna zkzk9|9i(O^5nzzDJ!4{tP{rquCiaW%r6?p_Pa@j^k~L%*b`b?rQya}8ucnP6WpAm~N6f-I;fNFTnx~}DiVVQZ zqqed7~l_$u0RYuEM0L!df7%~8;y?Ob?=|1!2F=u zKW{X!=LR(J?g#f|k5Ow~z`^~sAQMwS=r26ltq;8Iw`^FG0YPi26{2(O%#)7Ap?nkP zPjRW_TVwn+)-GsfAq(9^L%xy&+6&USzmxP=DtclTE>D;-Y>VnyJequch%ciMm(z0O zIMZ}3R#uB2N#0}DLTM*Za#?)`efHTEpP$E~ByLfv_af$NSq@&z%yOY2vDy{)DV7eg zh#w!G$EYx}dmzCsCw+c^H_@40FC#bjx+}&+15w|-MRof_#F&_aBR?EThr8Y1&$rw` zqvNk+uelvFgvru{F(zJ$9G~W3dqg-wxSK@_Bk(>vj52KWx~M7hB~B##`GdcX7t9%; zIMD1+(p-?pJgK+`&AgK--UF2O3;cWKg>)CH$qLmkc0U)H^{)GCcFXF$S!leeq%MI8 zMJY*CPEeCobSVVopXZe;>X~TT zV>V1Ae=}gWmS*;JsbWtFY-UfN#ftD$g#Y*1!=zBVd6Q?3KcVs_Pi{i_>KtZ4ZbIeF zorCAp=T4-9C(*%^$DdROPokC|SSp=TFYK0{dMz`kp2UAQgYNycg>C&P;qyLI zD@z2fX}TBBdz3m^{HLbwv&#Wf)kfXfMJfG>oK-_+MXy``^5dn9cx;ckmrLf#+nMQ1C=A#>P} zq4UOhY!}D77C>(T$_z%ZEyUHXh0=O({*j;@3Y6K>P5b*$&dbj#E3|9a6<> zSTCTMYDg`UzbwP#+)dj0N;Gl|dm(2>ZvDYtsRhA|XMS@^4G?+92T}uS|DsB?w>8r#^1fow8 z?nG>Bw9pM1VGK*e!V%T);@_O8eyGn@l;#d$7w<30qC>HUbZKFe)U2B%_BM=u%{_ju z7GRmFF1J)*xyb0(-HEzTlP-P#O6Eeb$z@UdpGEYh|FV#NkC~_bi{havDJu_JMxdiL zinX>I8U^7)G^AgG8jU>iLPWEgSi9bcYmj=-dLy!#L%G_~?{bYy3QZe!SH#RHwo;1K zZMzER79gv9`qb%x)%B|#7=$4W|9HU)f|9JLOU*%2t5hW!HRDLpu|SuiV3DF1UpOQQ zy0FIszC`G2tqgM|zadtt6jefwqC>4~aq}yk1P243(n^daGJP0q2X7vE5}`-L=7&Bo_UA}Hr^xqI_tKe0 zd!1B?1kIW0Uwi_jno9SE<#zBRWqHFr%;Pe||OD)rYO1R~i8=JDR-Jc%5CTk(KSnejRQMeZO6_oSXgd9(msTyxfsIX>~Hy!iX z1_>G-62z+VnFh$6=Lsym`G%zf-(7$PQB)*miB*_?)nC_W#a3!zFP5)ZjTW`e5nJ&! zojoVt`9tXQ81Wa=58xC0?%f;~37yw)NkB8X*Pyn4Psob@$VntBuB<*jeYXk$q7^ zVm>^_NJ>7M_HvMz!I4I1f`#av+2jZ)hYo8X^>VEoYk(vF#73m$E@DL%8ZIyGkx`xI z^S7`Thmw!o41Ad|fiJe%G|Y@Q^k6FsFZI@@~k&{myqji+~qTF;nXJ%g7NVM~^)A@7N>z zOZR~vTi|{$E?0&gG1#my^{yX(_MV#-|Uu+{mmf^cTj3DHDuMDC46bY zRg5o89?ZjyT`=GUO&;F}Si+o$-an#%Ang(X6BvD&Qv^y%m+J7CJ5qpHtFJd9M^0|cI}0^EAx+dRlJ$M*BYNo#QOc`~Jd(1I?wBt`h+=l-GD(#Q=ZmSnLtF@##5UR=@bu3!fp zlCPXDv&Stx9)bYPuDkA15u&G3_0|c?d);Sh)!)*^--dQpknPh;z#d;u+r4g%_?*9;w#!f9Gts(*h4!a1Mzci*6$5@0tBQHH7Z_Ei$~d z7V@@g05a!x&zf1aM0{%Z>{F=EZr!4r?Kr%^F++|zMnHSQktK-N*yM^JK&iJ^e)aNR z+lvAYZ2awo8JpZ*`4E;`sCMhOppU;?tX%kF0$-oESGKrY43~|pv~Z0BE*cKzDQH#z z*<}@UaEzr8Pc6fdic~Pdv5@N#2q7((ggnKJH}*b%Go~8aeM2O&`mv8a{*a$s|WU-j0=e1&uh7$iw3}#0n~pNQjJ!M(hcR9e0jJ2+tvt zZvi)ha2MIEZY589YgD!*x+KDzv>86v7;J`8=Nd%{{0hpb6a|QX`4r*v9rt~XZ!|ME z_36#K+?Uzs+U?~~HWeWm%g7@`PGxf7BA*O$vg_#ABZ1f4vY;?k+I}%q@Fy~T4(}2| z-BUbm&Lmp*co*VpFKy0OKA(4;28bSD7ScPwSssWNqT!Hqt9;82po_(p6M-4V0iPR! zM&;)MqiOeO`l?5es%F!D%_h8N`Acy2YwpSr55!749{zE7-+}byf#h3DUv$>Jl^yP0 zXOn2sOLCsY0QQv7#!*xPc{{wO6&W|H`r2X}1sX?*_m=o}wVG7 z?ve*W>l=X|UvXnD!hArow*loTSp=!O?!^-XTE?yL$|+KYBKSxHG-I)xyu~&rj?PrT z`K?HPSf0>LI2 zQ=?B@Ag>?q;9v7#uQ`l}!OS1&zV##%dKUM64w#oexZq@j}!btqalJeN(w#oe!?!Rz+ z+vEZE>!h~H1MOF(e0`-$e@h+i!_%PzTRqop(7c}=l+%twGr!dUn|y1O?>6#f?j|l2 zKNEy6=L=_f{c&`z>Jx8OU9oe(744S=xa@ZBz;tcd_6Y{v11FrUoGoy8$b_v1>;-bU zohl>Aoedlgu4W%7{&9xt_Pck3Nk8EJx9MK=Sp08<)viiGM@V!5dZLN(Z0B`&hFVNz|R8k7nBdgol6C5tc?E`hJ`2$&fP_jn1I1_ zhNuJXn4Vm^+DMdgo$uvZCV-d|#uFgYo7k_rexgPM(-V9UoCl;cruERxpz}YAZeAhV zL3HCzq=`_<__2Z_@MO~>hIbIniO5{{W=;n65W|0~wYSb=&dKc_hcO&r`qb<+UkA&n zPo+gh?%!&te5Vlhnr5lhq?Qfwu0M1$2Yl%)BS%=$)bqF8%I2QH|_19++<| z$@awwsdbzLIpt;v30ed^uxHUFX{NxAC#)TsH|1}hNab@yi#BVo0 zZUMRuHW1$oQ+tqmEy*n*gilGck~UWJD+!^Fy@BAPRF@gi<_eTE3c6kpBVei574A=slCrM7yh1|W(W>m!k41o?iAet|%2rWQ)$c)$w%x(uTk)N^bVLBEXk zr5b3I$o^?XGx}kw;DJ1EJ84+Dby`l(?LdbTuLaywqgwE=TjR2XHeDkcnJ6XnIz+ED zK|;y*#_pvT9ps28$E2?_1IImR66aql(Ofw5g`5Vx`;u{g-eN@^F1j&J*1b_qVX#RX ze^C@R^;kn%9~IqOv-j$CsY)7DbM(O2@=8fzq^F9>Go1>qUKlx5ltUvkrzCZcZL>XuDdyybF(jCV-lV78( zM6KsnPUZ1o3fzmhmDz5XfpIFopZ@DEfF`1*gveBX!dNA*P?!yZ68778U3hy}pYAa% z1@u=9GNIq$Un2^`?u>o9aSpGXp!RO=k*gvuRoIFY;JvC^@uFxQwU{bnR1Qy9soEr6A-u2b=yQI>}u@Z_=Fv&f-NrFQ{Mf1J!3@oOqY!V zX><40_=Y!gKVAA$vRgE;do?J4A(&l+`1>gL1=d-KcB%rroFes#WgATf8wN9;=0={* zhnc5`-meD(`_G1MkJA{!%1oIaukbH^VzASgrds*SX}((@sr$uYa$ez;DhCiPzdP3Q z`~1`;I$o& z(<(4MfmGm|>}?PoXlaa2SBJeZPq!N9@GD?qtbWlZ%$0CMZG{P=yekg2%`3^4Xf@yq zS8W{0!sbOF68o=;6YV26J{QezSfkcc*@lz=6=>FV#5QZT^Nm8Brp9 z2dVmsU^vlzle6>{hZy7&M4snS&2dj^t9t<-UlHrOVLJhT@M^Z>>eZC!JASyctcA}+doj))gKg2i1;O|yM9w3!d#e^i5h{a% zfA;seiWuhBUxE8v8?f}TX^<60%Kwbi>~@x(L8)`nwI^5y=ApKd_Dt~$e-F>v%VEf= zxLoLPZXQV%s=_;k+e$5wKKGdxB7t|qHT#^K_YbD#bm^~=pxhZ@Z8hJBj+D^Dl7T2R zC02`yS!`YvB=c=^&~`6YgX|iqcO1=q(i4=3EQ7cT(zT}1gr3pP38ur)#kd3 zz6q@*w`j9ftn6vCeBKQ{e@K@*De1s`s z5AVd;u9J|)lG^%UMH8QFLM8@y9W1@D*xub-@^RIvRp&-$lTc4W$b_dyFChF48y zAN1o)+OBPm#?!h*&^G0i6SNC*T4t9DxRnN8BSai6ChMg z$k0ZEdM5|a?!XgmMPDW<^l&-Z)YyL8=YL+HP1}17$^Gv9>ny+f=OFSe`B=2-KmXKh z?}{W3I4j#p66LZ)_eW1PVh9x^whK3mw*6SH$Oq?}A|LW&AyL)pU9~L&I^0LSQfE<0#3n|J)ZRDD#L>7f zJ=P@Had*}Z?-xnWEek|y-f@-=BITTP(bwct5yeGGa=#`;SNP6Iz%@m)oSF*t(ll#Y zT*Ky2qLRYS+C7oLTj9Wq;hKLsOE)Q}*LoyfRF&NCO)+W<2lklSe&*FCAyTy+O>J_b zt#EzfV_q3sL=KTF1>iz!G*T9lo4-v;VnX?Tb*_23sR$(>lADIIiC_EHf;fTJ3MC-y ztf%IJ0sOB><#LbYcvnOLPb1#}&%_233$(X~DMp%&*x6 zuB_N?>V8Rbj_}UD0oEh9Y3~Dm+L|jOluG=~ktNYTh=B?3mwI+3J^k zQc$AAS4kAxFp`DWU+s639b?-+xF^_ZnI(;<2W_ETLGnd(6!rUdz3}eD)@Z-(P<6*b zl$z+;D#25`d2ZW(ALAwMt16FE{r3Dq0%{`@Sbsc|N2}GOY70!l3@<^Qs#3I80^)j) zwyJZ-VwbG}JQ~;y>wvju+>cQ0E4EZU0#&9kRIQ5DK+|a3a!8I9P0W5^)?eshXoz{+ z8Frph^Xti}1Dk4olRN6U+`r?k`c1E&#r_F@KHuL)=GP+qcZN5;RvsSPSwCxAXa^Gb z%4bv`<)2YYq3+Ju6SgVOwdY+GCY^36T@sma7M``kkaKv`>wOy1!-s_f??+O{)$6~F zo9?8g$XG1J$8WArE#5RLJa%_I-;6-brkh>~Y*QnTW!8L&YJA$D!>cIelr68=Pcu9n z-$zw5p3acv<~DS=|4UBuz2sT?K3JIp{pin!M+B|7*`#r-%O4-}yiADJ(k38GtgN_- z4=8bIS9sG~WvweKVhU4u6eA>IV*%l@?J$ipz=dl}JSkF!Y*m7uuq@`*C%2>HcP~7u zrx34?um%^LRCE&Fj`Za_Rr=9kxl z98;d{!6jmJtz@sqPt|%=%A<#;OQ=(%c!lUDCvDD#4Xe0vHZVO_sRX@KW}b0Rm)_Ng z+)y4w4!ovV5F!?^0_j#6?x2-Zpeb5>3e~ovOeN#&iLaBO0=RS${uH*14=i|dd@&ot zu%CLz<`QJ5$48MR@$pU0tq<|lkS;pW&`drrcID1cP&tX)$fI7WWijO2mk=xVyTz1J z@y{-~>_V@k0945tlvGWEorQt>E#dU>hva};_EqxBj!RuWCq2Bde#wV>&m!xx!K#Q( z8?Laewk8uD8R3=X0pW3tB~EhzSD?E$v67W#-)N}WzhDGyos(WZ{-U%Ynb9oo&wub+ zEbogH(@=vuI^IF(sGqf^!I}7BB(RrTHk-PNLfu=8+w$fjGm&ubBQ{TWTz(3`aNc+b7)SgBRpxoi-L_E!77;sIPhA+L5^FjnwR_cP2g&Hq6%~W)E>HCzjREYUh=6 z0qcymV20H3&1Ko27-mTKiVND&^z2{SrAafxU_jG)FdQE7NA00DXlFf@)IX4OsArAX z(_9J{gZ@J2K!2+y7%hf)c(K#6jf|Qq8a1sX=MwFvZ&JVt(5hI85-eS(1#=}`IWxpj zpXeBX?2tzwEY!fB1mOWlvZ(oZdZFyfl?J-?S)M|H?tI`ifd0%y9)GK zFj@<$(&K0HHkY$@GOOeTg*c$YN1c4oUC@VrTXryjOe3VM(pOk--G|59ZQhyj3CX_Z z{fJ`5%dfSsv(#ULRkP^UK$2cwB*eI9vvtY*nG~~0Jc^P&Uog~S%CLSkL-Q0ydzhM5 zr6*pLppC3{Wl{%}=N=u{cB9D|4r%Y3@i&GB^@5AM)l^jCDHGtqY<`6(?FUUw?v!iz zQlpj3Ac3RCcy?g2&(F=qy`hI8h1M4Y{lZU0C0ODpe;=)h(Vbflg2m_xqLVY|&5f7o zfjuu2>;aJ?I&9AvL31&)3Gnn}i6&kSl)&8B< z;AF6Nyv>Wm4nnj)?`;o%b&1g);b+d0k9fICNj8w`K^lqM7@3fHXQbti!)#k|+K4xu zfK({epJ00CT7g)ak|t>l%8AVXnh7vsGZC3zsaU%7B_-ZLq8Z|Ms3V7wSk)In>B9L| zR{s@6eH!@ev43{4$zjHxE=eQc54_&2YgYwdfB+_6O+J>TF+GE?;6Z~{H=cey!iZ*? zu>Gf_Hz?vFIx5UO01;($8<`Ot3I@h*bC0~rkj9YAV>bFrLQYWzVXzSE{|r4$H4> zaIUhxs;rxTIMIt;No9f9-1v=!1+m%j8~aR-&BOQjon+G#KYA*f!@xJq95OV*5Dt z|8xfT;!=TMnkB-#>)!2l5S=~F44TlHJ<@y%8QJ0HQ&496n@_dCqjszm`}xv|`52Cw zTlr?;^^S6Rss-1?bsQv}n$ZS?lQm@sP=!>EUoA5L+`{>$8=+}3V&zYUy5v7p;bEaR zvsxtfXjhZ$NW2+9om7&!hb*-?yF@vtqC+UEQ@CdB-DyG#Ou#?T8-4^ME!F`Qy5D07 z4z)fcG}k9vjHpC~hf&e#s;G&Iq(h36KK7kVt=aNU!;Rj*d!EBoe8krf-O--$GDk6` z@J0ThUgprdn-W&c%N*XXk$_=zdYJ?5A&w^v@-PlGN1ANT(t@ucW#G$>RO>9*k{nPu znpZj0r23?)v_kltKyPoLTBfs_h6GTpBbR%DN~0}xkG@fw)+dGE<9M*8jC)LBrXl>a z)#)(};m45e^MFwgepa!Jx!s40A4W$gVznaPH4#pW_CaX%R98Xo=QK2?3^mVb;OW8+ ztviEtlQuLQ(ioUuULNNqjf}gTiyGNW1YpE0I<$ge7Iho?;$g$BEym;{dqVJ&=e}yrBX#&gV)_rehu32HyH%E{e z<4Uhry2l|UFQ^dxKdl-Pe)J>}W^F}OJ#uI9(AaJN%+I5h>4 z@N{%Rl$k+Iw9Vb)nu}0L@C|C^Ksf8us(KLY|Nt9R{2eEdisuiA#P=u|kM5*-= z_x(p5b#p@vNL+8?*O;Npnb;~SiOAO$I}i^!7RhQsJjw|84Jv`?Df>AA6)M zgSa`WVg`a-BZ=mqE$n{;^`TSdN^vpw-f!ATh(}@88LEhr%z$j31Y(aL3m+%WFl~TS zr#(~j&><$ZU5631z+u zuha8W4+S!ZgQC#mWi&5OuS0S48hSiPXnmZ2usYnY<1xJ)Sjicg)0`z1OqaT6GhsPi zu?MbDrH^v$|6%&iG5IYeNRGoPEA!n9ijQ(I>8#Tu(mmur#+i(GFo#?sW`qfS8pGA8 zLii|2mB6D#Bj*##J?SDJ5!0CT;Co*+h}?*FLt6}iX^w7<;fT=aer2{TkolSb^x#po zV2C%Vm^GEGs(robGbB1Pv45!3TuNp<-8wDrAX;R?mK|^neUaWq$m^7D_th~{^WbO= z%-VUSG?JrWd#ZF01&a;^XM`m$C|u^S2mQ_Ssnll?B2aK4qOHtBI{1YWXBuji5p$zK zWIHGkg;tZh-0k-bBj@%9Ng+hd?Du5FAV7(@iU@bvJ<18$%m6B-hCk0m?qQglv&Ya}Jh*S?s4$gE7Qv(d& z(DY^r$D^x`C1rDjA-YGkpkihZQtd`uR((05&0$p{h%|irsb6fR5)&Sc59lpt2n>4= zx&H_DQ0?Awp+#PTc}U-`34)U^od8a5RfO3+8x!WLgLY5Wgn5P8_3VwFA`@oy42vdu zX_;8|6nFdZd>iK4^tFN70cxBCO zl-a$lnf>P7yJ-qW)_jbr_nKr(-e&oWq$gZ)f`05uQlCDL%cN*ty>o>*V|r$XHF(Aa zinn5`XYNASs?M;^@-iwCBWE2Dc$3M!=i9b*?VK3+YC+JdZ@lFKfh?VqJFU}%9qzv4 zY=i2#-=J^oth(J|ufgZMjEXe#wWq<8O@q-h{KHtMc^30fYpW=!XWek8vOmTSx#eb} zGiQ;5JL>hpJGwW-yzenJ@-!{a=Amm6R-GP#jx=otwbn;Zs3a-TI4yo^Of zqu-Ex+2F*tpZL)IJ!{w(F%p!(>&EBWmVGP1pH?%So*pe+c~*kPkEEDa<|4zWmzxft zwR9iEkXfVOsQ7$S!D9^3`~8y%;hJyI!)!l3GzE~{jJaU5tqK_=vHoJ>3t~JzyUl67 zp6|r^CjKpQny=)?uS!+}=dk%_IxfOuZ+=jxW|03J@`(Jclhimh)u!%LjfNjEEAb*z z;@RT;nKj0@#SR|Na(AEUOA;){f1XWm&JwP!l&XW}(1DF1PZ2 z#-e*MG7+UJ-5uwNWQ~kC71`Py0;V%*F>_D&%(sCHlOwf4wBgoNinm#Oja#EAC(%MT zwJfUx{+vLkCB01Bx9rR~Ij?5lCayLW7iQgGv%_VadQ9V{!v!#nyR)}x-0Oa`+VL6D zNmS=Hp={UK?=UoB0gFq!0Ye?k1bpH&dY3>ElAVOSEBn)sVy+=3&r(hl?t||B`4WSh zVVN6vC7PgN*9QMQav`ZiKA?n77+>J+i#Z9CSh$fN5Y zmhsyHj=(>&PpG4<6xCaDD@=PH!>3(!EYfFV#VVx}Hgrb2Muw2zQ`;4RvP(tf zlWq6^vR5*|Y!F0|n!P+KP?n4;vnf__yVU%j((+>rN`_SJzrNxvi*DpS7(;$TIEq^zaoO?2X>r5ZD(9>~ou7 zf|>85i1sYCUwE0v$l8mHMn8!L9wP$Yq*^Vw(|vzVgfj``P3+7Jag8CS(FQDeat3_w zQ-+w~#M_l(2kw8(q<(#TX;^pnirim#$=my>*li|RT)~i8x->doMi=8r5r^o@Z)pAT z5W)s8DyV!UReNE*s%f;|<%gT!auW|J5zRCZDGBdYpM2t97umDRn4@K`H@osKG*P7Vq=8?FLo7QQXP=tPJT@5_7D*?s ze~t$>oj2W|p?J4xC~}pk-hFpSKCXnca0>A|lG0`o#;m(7yiX-rvmY-KG!|wDN%Gtl z?Mvv~LYCF@3RCBn@l!Or14LM%G*y-zXtNcOZOH6oBbf#z8;i0xNS19X=vrkOlmXGQZA{i6t~+i?WX?p&3(9&Ge6?^vKUt%*n%r9YIqv zk_?talHszBpsC;q`Zo=NSVe8&KqUSLW*4sn8`r^D$}U|AnT4|gX~UPZgp6EBQ^ z*neT4^u(&xKH=^svagzYXiGJOF6=Rdrs-;US|?T2qPbgTem5H8ujLTEoiOUb?I!v@ zqpp?>y=Flz(xWDZ*_;4I@})ZL4r?op52vpg9_|RC%S9uhFccmWUPS>#^S^MWuVoM>S%GTOp!;7}o_8DFn+}ja|j%T~|Hs7K=ce+*un!*re<`|wZ(;7Yl{N| zw3H}EI8{=gEQvaxrHi2Z94l)mi4nn;0m1mk-O*!IUQS2_Ssy?K)SaaAW|)DvPq1}v zpW&gsTlz#xP1f!$TZ@VV*>^xrsQsNndS1rjxf!gszg1Klcx%(^Mg6yfAV{M6Q@q;H z2k$1oU0$DjM(pLJaN@d>g6Np|bvG8ojzL_AmLZqCd_;G*_r&vSyy8%CBg@p2<)Mo+ z@k)ARK6BG=ML5~%tlPmWVBt+}d0=zkspR%eZdqWvpCdH=d`S8cN61K@`tx1ditKDV zytOT6xYryX~a6iHpYgUddz{(ro^33$}i_5YtqG9f_11SN_n8a38LMUx6jBx;6C zbVer{cdQ!~rL-=kIs;g@z$BVa#;Mk&rLAA3Ra=+VqP7UQC4dQt3yUI%3%JzJFfJ%o z7A^C8z3=^G0qyVieV+gG{PQStKlh${?so3E=bn4+xxw~fBO0Bz6CVd6ou6>hf5c7} zb!R1Q3wM583k5_6evFbn-1$+J0Z4oki0wl($9BtvCvx-+%Z4)_qtzS2)kuHu1rr|x zn5PtVT5`X4!=0alXk%@7;C8B;A2~X@a(LuuTZKsH2UXGPwaoc&BI64r(7T z2c6YHXVrqwpZ|2{LPZ4=I|c`C*@tx|Fi&SSVW01!?xwR{#5 zUE)RM`PT6@Jm^zH{MZ46e2W0BD+pp1;DrYe1_A?trhyHWod6l=L7nfHn84u9_lHw} zvn=SWtXvtaT)`AB4)QLN)7juG4OK1+RlWp@!eI4MqC%C6NUmN9CbTg{!NjH_=cQof zvS8)X&P_$3YQifjSBfb(AliU$6Hq8u&=JPYv_Dk641|^Rz)I((&P{pW$ur32>B$fv zL;4*wB*E-UA=;bRF(`0ryT~v#avRFK(8HtX^43 zXT22S-^yk5c=ZZrQDtY4-rrPQ{gOj3udH0rnWn#%RW7ABoDOHHMy$G{Qg9C7otx+> zdX3)Hkhpn0{okP>*f^+qDL-zYdPV;=DR_>Z!O(eyRzGKTv}V!tVxz-VmsNk7DTq3Y z(ExMknL6aaNl1_Lh8@cW1GSp_s}W41ns=}Hge?rRWe%xunJ+Iz_R`lg6kO_MXV2C|N! zf2~X`Si%R_n7U1@q>lOeCld&#B1P`0CtzcrF!0~AJl~=I&>B7SlMeD&tH?4!k;JyT zu*0K3%OlPk-NC{-;*bNPsml;ux@VdqiJI0JPDRV35_*jQSbU6?^B*TIs5@NTzQTVr zhD4J74QotYDgEF^lHAw4_-3G=FXJEGAFBBxwtszls94Lu<_i;F9y7kJWpE3L^=-q7 zFl)`cv#^e@(^L6H(bN@1bB~EuBBykpmax)#aaO%_&_Zm(s z>93*oJfB+;Itv>`4ZPl&xugS7h9G!h@S@%hSO1tkkEVWFWP0Ouf#-LF-1M#ql%IY`QeTuC}W}TMH{?q9WWdepJb;fX6;w2-6nao@r zig%bkRR3wNMVwa_s2ki2c(mkE2KQ<{jqR^`&nwVjb$&UqabCUNhzh_RuL92rcasTn zgu)6Hpm!cw&Z5gVl7dYbZWHbZQ$R#(j6~dl5eTy^?3@Cz%~49&Z_~9O!2=SrtFIT# z(r5lL{n0)Y7M+?%P|l*{v&()dtzFkThU;N%F$-sgcx_ z!tl7m!!UMdc`)#sMa-f@1HWAqEL#}ac78#yEm+~6Qw9MA*#d-}!$T-`J>IZ*clmgVE?cbtiIkEX z_?5#nGx?oY5LDo7Y|*iu$3a<6yN?<6{^sT#b%EAP_)ZOz)+vW(M`~6DW?>q~eEbwi zc0izYA)C_4?9k-%hy!=N*vN~|cXkE~UkS9flFoA3 zNz%$_&FVm6IuSB`UrQOhnvxf-84{Q!oevP(^o9{?3YWB?@3qEB*+}Jk(V7zjvw{Hl z*0T0SF$8fwyJg9i2a#6QB9yS*Cl!>bTTaT26?q#2eK8xP$E%Gx_**tlPpC|t8kI$f zr}qn`2dr=d=2RhCUcvsf)>$hr>pIEcpR&oUCzWr7E7zTpiWTSFvgDRE{R<{{0VSPX zo*OIfD>zh+h-a@2L&L#;`l8NQ_p$$=s=|dh<*$;#!ZQuxjM$I_S}rH{>%{}=0{3)9 z5<3nJ{HCL>uq)7tQ5AjNkblb(xfM!uKqRnNHfe!bhm)jjW>{QzLKr3GgeajVB=z!> z-I9~k!@x$9a;{giIFQ(38oon)t3C)pX^M} z=TcB%sO{J;Ob8}-pPZY+BC<8=>{RdC(Pv!DOo%#rfqKhBsqlty{TA$79*jD}L(XSG z=iiw;Xc+J5%$O-X%WLrBpxsrL9rea5;lzV8A-xn0|Pm}H>!RwB}C1`2$$R9ttLYXP|8>jMMx3Q>>wUd7Zr zzBvL3V^v(3U3%bV83u>*a-+#InQ#7$X!u}vq;g4k>wCd*vGN<@2L}^eDzA#~8)00h z2Io^j(0}RvD#t9;EfI=qOkP$##aKK}Ve1g_eVbYAHBmim+7>ih=+^bIy(64dr2H@3 z;mh$_w$Z&4T;b%Hom(0>-)}Ld*mrau(F_kG`7p<=($d-K5FE;Q+ubCm{InAYe)LdV6Qed6QZF zScKUTj&wJag~_x)`Za8!hRcc!bPf?JJ6^1%>6xuNv*~|{ zcRAf=aOAkb4C$7~GAD$SOu z!mO>V`sP#K`Ixga!njQ;Y)l4%*^^6B6SAQLw}d-C$dCG#v+hTed#0Lvs23V3WQvNM zs4kGACO_i*a(I$GvNJB*aYe@l{vUDy140a`G(RHF| z&dDw+gz8Iz$s3CrlkuGT)P?(Egu5tpy6?cX!PT1*+kC;qTe#_IaL%a+)_gPVsxZ!t zpw~!pSb>)93C`Ms$8-7lXJv|w`Z|)~!fdA#E)3SZbnU*OWVoooc{7-8IHDo&_wAvY z?b8Ne`W|w^MW`mio??$h9}xhT4Cuia2gH|6nFqqz?#!<=v0N9WlMAyG|6Clm3c-k`t;@XZf6_sszvS-ts;%-F2gBJJXVXG=-*k z#RZ28X%oYw5t>3O$!wN;$4g{&810N>?zYUmgj)2HL^$l8uJ3L`6Uv&oCQ@_r@c7_J z^7OK>uQTGDZhTMJZ|Cg7lFWdxbB`vEDMa0e1B{d+ki($D2=hKP2=4AtU6bVypnM0zExHte|7*(7#JEw zq1eX_pGfxOhArS?X?U)~a>Hy_1Cxbz^s&P?VTZNxOeA@W`lx|Bzp7%R^PsJjr=!<7 zfo7rEOZ5_2FJGKUa*liJ7Rwir5Ll#WfsQE*U;Mh4FK)Jc5j&##GVxZ!7qu1X<%@h2 zy0xHU<07^w&9%59>%IHXmvF@${kh`iM#l`U#}y69+X(=>nE+She{sdG@Zr}Ot~enA z$A_s*M00JL3|FMWO-v#4Db6_|N?eeaLmQKY!E9YgY6e^}i|!20@EXiAnmix`TMRkp z!51$qpP>$!sxD|`7~qR%4Nsm7U)%EUUkXL4{5TJzep8K~ktKFKJo zicPYsI?OBNY!=7Vn(x~j;sih!jY4SmLN%S&jv%5a=)9J#7sK4qz_lnC=Aw|(R1{6J zH61@(y%lxFBP#Hsb3}_043mbGWoB!$orp5pPj9x|a)M=)VW;Z5jB*Qjl2fZv=k_wn zjl}dY$~Op$QO?+fQBE|xQ=_MWn*oerE@lKpYH-SBmQ#)~HSowJJi$Fg-`(b0xx^`( z;FOKYa9PCH+318Vr)*5tm7U^5bKsN_=U19nz1(_Oqa`yyCRnhLudtUA!xPvCXP1T! z^!SL+aLSTCP8lg-2KzE6HQxvusS}f|b927%m}HY}hr|sGBjh^2D&yBrog|8N)IG!H zw2kg1pYLRdKh3Z#Z*^vKM!Macig`b!wefRmI(*ks#^dby0Joz?~h@6VW8U)dl}Vd35uv6km^3d zxq!~`7fNeDg<;SCx`p^o)`0ftHo0`peOOCoM!K;?dnI>A=5YcEEY% z`q;>@^OlN}IMv!QqcDb;al!D+hx}WTc^3#>s!S}Ia6#{WqDP*o)J8c1 z>++N%H1iZV+#G>~{RWU8Af~@^MD_J_95Clsf~hbv$C?IbNnqYGXL;v0dErUR-Mvj4 zUaan*@_`oFqswsV^Mw_JSm55?@}NB)KFX|1M)&hG2S&q@W4d~M)In>)4hsM4EVPlD zC9(69CBbpS%BPJJeVSo%)|!FZ@)#pSz40Ex{j`vc`pIi)5tVn|>&)bF4I=UJ0M|!vi3wr@@`J#<{QVacQVTTlp^-V2+gEQ3 zuHJ_JW+`{&S6rjZz0fe_869%J0(UMdX+l?Jla*8#T>n#q0rTvc4pln zq-0(fzOHZpVP9|4)%lDZQ)7p1@7+%w&8}JK1C2)Qew8H zW#G0$j%@EffG&pyEzgY9K<2+G9b>YtBs}S@uF$Zl7|SeDdp~04bIpD6O#|6*bZ1W~ z&#-g8p&Xgx%JP!bS-N=^FAq=RnfR91RjI(dvxiMZ&$6N!^&+aTq)n~)A$?zlk=dY%JAmc0Zr#ASO$BWzu<9Lb_ z`m`kToY|i0kbbm;t_t^E&1xfJXTn|V`0u4LEfrfVxzwhthhIqvJni(3n zKQyc?aQ~u6wwrtA9FB*Ru{9-`hor@#{!9$nni-BgT(qm5Hd5 zp%o>Ww*t@Cmmxzp@5r4tfkU-z2N=f^otq9wEcG$|;lxU2@aW}%=T9rE!PC&Xc)&fG zQoHKQa=K0`qdsmMpPD$h0&2j_1slwoOG*Owz}-V{mWZ8wWrsnXyZbPlWhkY3eJFW; zIrIW?Lo%VxlE!3o1=E~Oe2|m|G=7ISl?Q!qg`6|^noy2--dPgG)vNtUW=QcRu^3dTC%2>B` zH424t<@23i&S@$N%+V`Ob@G=sCih!$nzJ9Xv}naXt03rbS>pZN>`TF#mGR=>)^(ym zO}orq4K2&!gSzVIBBC+_m@oREzCrz7aB(k(<`gl>(OGs`Vtc`K4%13+<%^qF?P1@F z>;_UJd}l@z2q|zlfjR|nisTO}un&P+1(4tT;}jS`UBqtI#O>EtnUNdmkF3fzKn&Jb3EZU@-m97mnj3} z$jKtC0TI-+{NW^{ytXQSgIqoPX2fG?+R!ZLVsPecY{X}gvu9(?rob(dC4zzH2ezQ| zl|x^54<;xP5ze(cT)#e=w`F7bwb}RpBY|i3<#azE4+xP&XKrv{M?+f!+$4`}xG(dl z)-CSna^oqjqf)Ji5|(mm503{U*(K8FSI`|F10adwT>3P-G`5e;_6D(T9?B9sFp)Po z`KJ*NzYz12H?yU-E}log+@>_=ufHWXMw!QllW6c(#l{#VpWfL>70(f_r%_Hs5d;{< zib&1M>4#u$N!oL!^!MG_BxmljW&cL-$5M7?mS)h9Fgko=n`3%AQVD^j@$}Rv!!bz~ zSnVh!9g>(JRZ*_EbE^2$@#e_8CwUA-7>Q$deoRk?lgF?5P<_-=K1Y4TpTb&I^(PzI zf^g!*oOqzy|2qKnm!3k#Xv(|Xma_JZ)vF9^b2n^2KJ#A#s1zwWA!a2txMeLYya-9l z4NxOM&SHUmM6@h+H}ETq**o-|v}R@FMg$Vi@a?P(|FmNmT#hrE+``1d5`sSK2}5T! z6+OkUt@r#qGwxMnWRR~!D|wQLniF|%{AwWG9SIhu9XC86Y9W5+CAE;Kzj$BHsn!2{0hGH z(IlXky$_BHTgqQ$- zzKZ5pYYsnK7jYh&jsJ+m`FuWNzM}Hy^dO&M=HbKq>YC-B`K^X%&%U*YOb}lDkhWny zBo|s<82`A($ro(*3pa-{)thfZrR=y1(@zno{`x7O-kBfyXdpKyySlaG=KSpH%%JRQ z4ok6^9nkFfXK$bkhFesjk;;~S25c{lXuL~W*2hY9Ri))l&Sx`&1fIcy{3)NIJVQJs zil|=Zg^wK~0CTmxv zir$6a+g};m0cO?DqCAtL)0`hS?Y@+7xO>xX2Q4lCccJ}OF6 z68kmW_Iys<0xxbtj)~i%xQB?N+zXLG9^)HvPEI-hLJ-At45yr&^_0%x6Is*zm}gju zUr^qkl9wXI(jI?9dOnr@SEZaziX4LII(=W4c()l-V}2ui>e(rd|MjdSeKdLeLu8+fkRn$z zH&U6q%a;id#l}SEOU7^F0etojT%#UkTcI9NMS52n1uBRzF=Yy9e;f{G-*o){Sa15L zReCQ5YNBMfu;*wD9fyait0iCMQd7&P%}g{ciJAPkTI@<+4E>ph3Fu#RSPbmRpVy|fM<%36j% zlr24kt`MeP&c{L)X#HRZHb!}@F(}vtIMt9m`XQZ6oANSceeq507z&-rZUegKETXw%V;NQpZ(wy&c1j*kkb z&L|8n5dCt~c7axc%pSz$_r+KY5eoj^hCS-8+8b zv4nSiYrDY|vcVEJN{Sy{efl54R5U4W4ZPxu&Mo+>Qm`uw6eWJD~Jqw;$ zk8wDZ$2O+}fG+>`KO)5Uu9>^7huc(No(~uc_^$!SN!AV;B%$y5vDwA15Us_6o+Sy9)V~U-Z-=(^c%kQBqTS zKz9u{iQC)t*Z|`RxILk4~Bz51jz~^MJ>=om88*UdU95YCk47C%_Ub|+!j}p za}j0K+X7W89m;GeZ#FSnbcqQoMkVVccA{cxRr1ucDXz?XAPE=Wr3<}xtcQ|DB|n!nRYm6Qt+(D$Mg4ds4vP?tTB`UrrW%)VIC`xq=YAQdXjZi1j>j>-i8bUPt zd^l4W|BS2D_(C$t?O7ilqynKXMxHf?!zGRApVp~{^!|@v zj;8mgP00K%oKi8Ct8Ft}%@*_FN>dEiU`}Nw^cGX+6?2AH%npiKqGHS$mWml?i-`@i zMNG;3k7W{xB~$x2MEVe*tbW8;>nA=5!*Y!kB6oz*NG+wuLP@8YUT= z9nIID^)-esN$wjp@~FB;wBOYRy7q)4q=}n{=LABFP+<+u3~4{`Y%$$d zD&8>epUQqM>OkWTLXQH&5DwelT-6`ZlLJI;q4J~LGs%MFa8zdRAf5zZ^cEq>?y)2p zrE66m$$AT_HIJ{G>kGAU&b7L0ye}`*c1o@x+UFSTc3T?6zrYuf64 zWE-8>cJuU?oJD92V!2!2YTMJaxQ-V0$POAq$q()L+FOj_Zg9Jq3(of)b?zL|iWyk#}Li%mbk+-}PW7bS2Jld(tU>=wz zM2(@XY_ZNKr!}UC@h(Y47b`bTkq2lR9ge2NS!bL+xR(Nk$gSNg-dIxkdF~xtRc0!! z$rN*8V_;p|k>S+EzRaJffH#gbY!`V)ccxOuA3z7gjr9ZXJ;?lw(SxG6g*lWT9Tq#Q z%@OSiy0_OL_zBjQo_bPAxhYDOcG7mO2M?0Ss1zm!`_gxki=@AKNsdkOCkE$deo6dn zFa8(3@wu5xjjhN=_oCjo!pv#d@CkLqLp^ga%S29wyIdyvhrOUB8PswpPB*&y_r{fF z0zAs5xIs3qh-0kup)3XVa*IZ(kJ$U{$y31!0pV1s};2r_Oj`Znk-c zpDWJ6W&LSI^kU9F+Bsobooafc`ThUI2Bn%-RCnk`bcy@-mv&|YFL2u=57V`~MH#zZ zz9Ikrf<9`rtQupR|0{ir2W(gRn8OwA|0jKz`?sQaPFGfNj#A8Ao)M3j6*#juQ}qNQ zs^VjHyplV^O!4^Pyw1x&ZpE3TtT@KH(^#aX=NQ}Canq1sb8Y#kxxV;5!L7qH!+=|5 z;5NEVK(Y5WQv}lk)0N)rfCa3PP#}x3*ahCyh?Y-uYt8ach=mw4DD}Wt5g+EA8}kkG z-kUW`pQ}(8RWH+;!R(T0EkDK89d&Kv!l_ez(B^}^1|;SxvK`5u`Qe>m>4?d#U5~5D`qJCtfnux0RqE5C^L86ZJqDI@O9};!A z7j+;}oMp`&&_KES2HW<})I;lg%+1XVnVXjxG&es}FxL<7;zm+KF3G4+hnumv3CRLi8&`)>whz z8;eCDIj~aa?F_f^;AdaBU$Gs5RzLAfe9C(EbUowa(Ft3OG3&PK()P>YihY|mlXSziyOh_5I@9A}0pB|dm^GLJL(^hDJmRr;2f`lJ4- zxoOVPl-l8?*7i@$PnX-&KYOYBo7C8zWcaNYHMoCz`7We#oR4*7|@=8APLsn$x$L1jAq3O+pM;$EEvvb((IYRLx>9 z>N1#pFY>0f0DU;MJ+Su_QxINi2~JXDrEjtx9^&o00I> zEIiKinJ#E?rv1b#3_FrG0&@pv?}nH;rgfJsAs!9sA-W&j@k~xUg(qjJ1**ClE)iB05db*DEV(QdB zR7=cZ@nJ^r8s3ez1Le_NU;57^Ht)D8&Xcj7$Tui-PHy9NDf1*MFMeebx5D(|VPC56 zVc6PAPj%|^#vPoeu#+e>7vh{#Fx|qp{seXxyq;#HGL@zA zMaCN|;jcz)Bz}~%x`#0$2h$d&f$Pv3_^2E?v-|NThK!O}TRfw{zA@^x&-;Jfzdd>} zg8g^z-%<}&yp!pc*wK?iNgp0W@J>BBab2#p!HVsfDdcb=RI})sf&7j;BbRH2?2Ll> zK@NJDj>_0 zmlcp@%1a6`+x$xvC?U|LfGkt)BG5NHyULd{Kbg-UC0oq%L-O4s)+bjlGx$wf&%k;I z^I<+wQi+K~oR=cb8nU1YW20+T`6x)usTgkvwv^v%QP!DstAmx-+bI^u9X54>{d$EE zDZ`?^ZC!Z{ytB*OFWv3dx7B3lR1Ctl<0IzO{I+^-U5&?QQav|}xs4u7o|J#f8m^iL zp6=4r2|4dGS!d8q+R74~O0dlarx0wm!HH79sSVmtO;C%~2Et8x>{T5}ILyuDlX3~v z5g4z4obpsz3{?ax2tr|AS1YIVf56dPJ7|Q<+=J%pM)j+@6grz6%#$q-(tvUWw}+C~ z7V(6#J92;K(t-l=qwaUUq*p@R?N#>r5u`MKm^<02FOQYFUv*#(Blcq45oH%mu0D(V zkepSU)>NeTV6m1WnUfn6I*yQ!(ErC_4LKX>TSjzcI`Mv$4!HkHT~nc|VTp|;`n;P@ z_WRr>PHZR~*vaVcC}I783{v@>NnOd6;TH3d6c^0^MvrP|2jL3$@Ba{q zbumI{^?FH?B;Hf@$dcUuKTQeMXqO3a;6Hbn0H#W!0j2@cbBQ{YzUSJ5WjyZCeRWug z)`eRIQR>|cES+Gd2iVKp*Y@(}M9^s{iS6ya_gw!;f$i_)VD&j13)yMG?Q~XFt)p1T zg6li7j0A|?u|eO4bC}reCXcq2rayTr_hpeNxwKxHgu_ zch+rrRLq^bR-xqOMWJN8#3GY8F=8L>CS6<=!!FEt4+V!A?-NV)$ZErgudUO8+}K|3 zC(rCYycXjK=`gb6$?R*r-Sk6Z9CM&9XZO z1V;p_YE0c&=w)q=O)#LkCwO6q&D#aKEZF2uUFh*X*;h6J!l}jYG?(dIT@<`n<`zF-bWas3U^(7cL%70S@^@{z zk)Cm)m^?REG#TtZ8HSH%gp+eMT0QiC%aT6o4LW;=C#@DpK6HEVcj#7{LXT+OCn+IQ zzy*?yEss*H#>0*_DDQMs~LB zpoe6!kB0)BDx++j@?93?-QPhussm^ph5SXGm2@Oi=qTh|$@F0zh1^XHMT6&!%b zFiRV?ZFs?yy6a|x0p&sQUxeWdVc3ta)%vREi`}LSt-sLs(R?fOxI!^Fwl?8-+o0yv*XZd2Z!2mWUyg#uzA}=jO7!XD)1oUd2B&fdsm0u>zVyj!%Nyv z4UJtj9c`QcJoA+wyJR}^!#~P=`C?}@Z^xp_U&&{tmV|wqt zV+S;E7rJk;@5u~m-hLe6j|eZMCAcALSmf3DtYDX#jed4jJ5KM~P)99`;iier*;&Yk zL&FJQMI>=pMI^Zg6D8210jNDXcIxzD!DpbvoZ2H|7fe5!jqE|Shi6J^$HlIyJ#Jd4 z_SV=Q(+g^AV?~*%9kLinUHPL?Rk|~SU zymigK)TTX8_2R0?KGDjzBF-LB-#*5}Z@-%zR-dtpJi>h)(KxcF74z{_!|YftiK&AG z_vg<_J<<_2T9d%7yp+J|KO;YaEB?T(GUC@PIu8bZF4y5A&O4G6LgizBt)+4<^DMlveb=LMi`BjX0>-=4bZpwqF>zMrqtbEiD;dvbQ^23r zpnF5`aijBv(ROcnDCqpv2+fg{-9BUP^pg!#uz^KV!en!fr$-imc1Qr6v;lx}0C?Ni z$d?*saWt7SAoR8olviIXnl(}a8Ms-7V|0G?r(sdLdMxU&;j&3`0HK>(^h)1Y@7kTc z=TA$TnPjO#Rs_lpxt-ygUFftqQ19H$1)V0M7-mu%^! z@B5&Bj#!ptOMkUdk)?kp%|ZD=6FzCSP1vpa=DaqXEI#K+k?FD+PGd_eXUb&!V1uH# zmIUm__0jD=oDcnxVLyPBVQ9A0XA=vEF^P%qJ-;oh{@Nbkie6r>dH2SBwE|7mEgZd& zvfYJPbV;Xx!}X0u+VMJl*BVEY&IU?}CTEIp!>M132-4HYYblocU;6?vUon)5k#|Rr z;<@_8vn+Dh!=C#?OQsP>Wv&oOV0fB5U%lXk`bw;c(#OMG@apTm`_0 zaTJy+{u!8iV7R$x%59_`!Wi*!G1wO5e%r;NmEFZcrr))wkiNF(&b9Wc&EywzN;-20 zL7p6`GkxFq8|~>%C{BL_dzwM8rxlTz-{#bzpT7o`dtGz3Af6veUV&7!!g-4 z(IxU7a1#3Yi>Y1a%t*~AjB&_$Or0lBT!E7~wt7Hl8Gd}7`re?;&Rr^!oJHjHfZdTG zKuR2{4P>f#Kj9oil%$Zp^XL8)vdew#bHa%Qrt)0ReyEzkc{UKq4O?@!O%%A+e6!!tD^bmSh-No?krm3JDPT-MT*>o^4SBV` z*q*hyv4c4ftTcwX$54L8Z*9I`LjSKZdy?zBnL&#C!kuU1B0L}Lf-Jk(eH~RqI?D1# zYwP-PKYO0wa6?q{2(8-WfonOjj8#rf`nIkk5@V0oZAP#VqHSJfT2Ea^$_S$~r=JJc&Il{`S*`&O@r^UHARcP1@WJc%8uyO4tg z$>o3A)-y1%J=8yUVo$8!mx#yLh3Jhl_r%6;vdiK_yZo!Bp$qT!-^&kkS}buRLD)~b zezJ!wU+)tG^6DdTrH;P%%Lv0re+G}Se>xPAEdDY7x>pVYQ?j@LU{bsNpTwy)g*g7t z2ysc;Ygm}ewq6r0BlZ6E>K~YgRQfW#bi`NcB~$9Yti7)UF(@ukrOgyk7o~s4@*Xt) z@E+oDcK6il`w187A0uDr6bLVITrz(-*uGzR^EYLPT3yZG3}oR87IxWtogZm5?j<`{ zrSL;0LT&!$g7`TR1VZHd6~T5+z*+ygYA*`h(-|y#RoOZ+E}yN>034}g*+iolLS69B zxsoRcpo=FzHgMr*5vS>ns_xZZ+RN)5qHkR zDl!38H6yvCBvvtd0MX5xUXKj*!c# zVG|Cm2$=iOIL`egC8@+~_|3euJCT{X8~-945x3w=w|RRd2P3?#us5R+2zBCgw#VLd zt$PzVG>7xL@(dfk0C%pRRLD7Nj(ZUQXtP5@2J;F~e%#M_U>(wrSu1+@L#RE7r+s|I z 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

;b_F_>X!oZaKBfPImQ(wqLr_mA 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 YE=O$d4{noU98V&ON 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/dev/null; then + # real run in the current shell. can modify vars + eval pktws_curl_test_update "$1" "$2" $line && ok=1 + else + # $line contains characters that are meaningful to nfqws2/lua-desync + # syntax (e.g. "<" in --out-range=s1&2 'WARNING: this strategy fails eval (may be unescaped special characters). using fallback space separated method' + echo >&2 "WARNING: exact line : $line" + fi + done < "$3" + + [ "$ok" = 1 ] +} + +pktws_check_http() +{ + # $1 - test function + # $2 - domain + + check_list "$1" "$2" "$LIST_HTTP" +} + +pktws_check_https_tls12() +{ + # $1 - test function + # $2 - domain + + check_list "$1" "$2" "$LIST_HTTPS_TLS12" +} + +pktws_check_https_tls13() +{ + # $1 - test function + # $2 - domain + + check_list "$1" "$2" "$LIST_HTTPS_TLS13" +} + +pktws_check_http3() +{ + # $1 - test function + # $2 - domain + + check_list "$1" "$2" "$LIST_QUIC" +} diff --git a/blockcheck/zapret2/blockcheck2.d/custom/README.txt b/blockcheck/zapret2/blockcheck2.d/custom/README.txt new file mode 100644 index 0000000..7f5ea8c --- /dev/null +++ b/blockcheck/zapret2/blockcheck2.d/custom/README.txt @@ -0,0 +1,12 @@ +Простой тестер стратегий по списку из файла. +Скопируйте эту директорию под другим именем в blockcheck2.d, отредактируйте list файлы, впишите туда свои стратегии. +В диалоге blockcheck2.sh выберите тест с названием вашей директории. +Можно комментировать строки символом '#' в начале строки. +Параметры со спец символами типа "<" должны быть эскейпнуты по правилам shell. +Альтернативный путь до файлов стратегий можно задать переменными LIST_HTTP, LIST_HTTPS_TLS12, LIST_HTTPS_TLS13, LIST_QUIC. + +This is simple strategy tester from a file. +Copy this folder, write your strategies into list files and select your test in blockcheck2 dialog. +Lines can be commented using the '#' symbol at the line start. +Parameters with special symbols like "<" must be escaped. +Strategy list files paths can be overriden in env variables : LIST_HTTP, LIST_HTTPS_TLS12, LIST_HTTPS_TLS13, LIST_QUIC. diff --git a/blockcheck/zapret2/blockcheck2.d/custom/list_http.txt b/blockcheck/zapret2/blockcheck2.d/custom/list_http.txt new file mode 100644 index 0000000..ea7c8e1 --- /dev/null +++ b/blockcheck/zapret2/blockcheck2.d/custom/list_http.txt @@ -0,0 +1,5 @@ +# write nfqws2 parameters here +# WARNING : parameters with special symbols like "<" must be escaped or will cause error +--payload=http_req --lua-desync=http_hostcase +--payload=http_req --lua-desync=http_methodeol +--payload=http_req --lua-desync=fake:blob=fake_default_http:tcp_ts=-1000 diff --git a/blockcheck/zapret2/blockcheck2.d/custom/list_https_tls12.txt b/blockcheck/zapret2/blockcheck2.d/custom/list_https_tls12.txt new file mode 100644 index 0000000..bcc7470 --- /dev/null +++ b/blockcheck/zapret2/blockcheck2.d/custom/list_https_tls12.txt @@ -0,0 +1,4 @@ +# write nfqws2 parameters here +# WARNING : parameters with special symbols like "<" must be escaped or will cause error +--payload tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_ts=-1000 +--payload=tls_client_hello --lua-desync=fake:blob=0x00000000:tcp_md5:repeats=1 --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,dupsid:repeats=1 --lua-desync=multisplit:pos=2 diff --git a/blockcheck/zapret2/blockcheck2.d/custom/list_https_tls13.txt b/blockcheck/zapret2/blockcheck2.d/custom/list_https_tls13.txt new file mode 100644 index 0000000..1a69be2 --- /dev/null +++ b/blockcheck/zapret2/blockcheck2.d/custom/list_https_tls13.txt @@ -0,0 +1,5 @@ +# write nfqws2 parameters here +# WARNING : parameters with special symbols like "<" must be escaped or will cause error +--payload tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_ts=-1000 +--payload tls_client_hello --lua-desync=tcpseg:pos=0,-1:seqovl=1 --lua-desync=drop +--payload tls_client_hello --lua-desync=luaexec:code="desync.pat=tls_mod(fake_default_tls,'rnd,rndsni,dupsid,padencap',desync.reasm_data)" --lua-desync=tcpseg:pos=0,-1:seqovl=#pat:seqovl_pattern=pat --lua-desync=drop diff --git a/blockcheck/zapret2/blockcheck2.d/custom/list_quic.txt b/blockcheck/zapret2/blockcheck2.d/custom/list_quic.txt new file mode 100644 index 0000000..6f333bf --- /dev/null +++ b/blockcheck/zapret2/blockcheck2.d/custom/list_quic.txt @@ -0,0 +1,4 @@ +# write nfqws2 parameters here +# WARNING : parameters with special symbols like "<" must be escaped or will cause error +--payload quic_initial --lua-desync=fake:blob=fake_default_quic:repeats=11 +--payload quic_initial --lua-desync=send:ipfrag --lua-desync=drop diff --git a/blockcheck/zapret2/blockcheck2.d/standard/10-http-basic.sh b/blockcheck/zapret2/blockcheck2.d/standard/10-http-basic.sh new file mode 100644 index 0000000..6755184 --- /dev/null +++ b/blockcheck/zapret2/blockcheck2.d/standard/10-http-basic.sh @@ -0,0 +1,12 @@ +pktws_check_http() +{ + # $1 - test function + # $2 - domain + local s + + [ "$NOTEST_BASIC_HTTP" = 1 ] && { echo "SKIPPED"; return; } + + for s in 'http_hostcase' 'http_hostcase:spell=hoSt' 'http_domcase' 'http_methodeol' 'http_unixeol'; do + pktws_curl_test_update $1 $2 --payload=http_req --lua-desync=$s + done +} diff --git a/blockcheck/zapret2/blockcheck2.d/standard/15-misc.sh b/blockcheck/zapret2/blockcheck2.d/standard/15-misc.sh new file mode 100644 index 0000000..eadf1b2 --- /dev/null +++ b/blockcheck/zapret2/blockcheck2.d/standard/15-misc.sh @@ -0,0 +1,42 @@ +. "$TESTDIR/def.inc" + +pktws_check_http() +{ + # $1 - test function + # $2 - domain + + local PAYLOAD="--payload=http_req" repeats ok + + [ "$NOTEST_MISC_HTTP" = 1 ] && { echo "SKIPPED"; return; } + + for repeats in 1 20 100 260; do + # send starting bytes of original payload + pktws_curl_test_update "$1" "$2" $PAYLOAD --lua-desync=tcpseg:pos=0,method+2:ip_id=rnd:repeats=$repeats && ok=1 + pktws_curl_test_update "$1" "$2" $PAYLOAD --lua-desync=tcpseg:pos=0,midsld:ip_id=rnd:repeats=$repeats && ok=1 + [ "$ok" = 1 -a "$SCANLEVEL" != force ] && break + done +} + +pktws_check_https_tls12() +{ + # $1 - test function + # $2 - domain + + local PAYLOAD="--payload=tls_client_hello" repeats ok + + [ "$NOTEST_MISC_HTTPS" = 1 ] && { echo "SKIPPED"; return; } + + for repeats in 1 20 100 260; do + # send starting bytes of original payload + pktws_curl_test_update "$1" "$2" $PAYLOAD --lua-desync=tcpseg:pos=0,1:ip_id=rnd:repeats=$repeats && ok=1 + pktws_curl_test_update "$1" "$2" $PAYLOAD --lua-desync=tcpseg:pos=0,midsld:ip_id=rnd:repeats=$repeats && ok=1 + [ "$ok" = 1 -a "$SCANLEVEL" != force ] && break + done +} + +pktws_check_https_tls13() +{ + # $1 - test function + # $2 - domain + pktws_check_https_tls12 "$1" "$2" +} diff --git a/blockcheck/zapret2/blockcheck2.d/standard/17-oob.sh b/blockcheck/zapret2/blockcheck2.d/standard/17-oob.sh new file mode 100644 index 0000000..4228743 --- /dev/null +++ b/blockcheck/zapret2/blockcheck2.d/standard/17-oob.sh @@ -0,0 +1,39 @@ +. "$TESTDIR/def.inc" + +pktws_oob() +{ + # $1 - test function + # $2 - domain + + local urp + for urp in b 0 2 midsld; do + pktws_curl_test_update "$1" "$2" --in-range=-s1 --lua-desync=oob:urp=$urp + done +} + +pktws_check_http() +{ + # $1 - test function + # $2 - domain + + [ "$NOTEST_OOB_HTTP" = 1 ] && { echo "SKIPPED"; return; } + + pktws_oob "$@" +} + +pktws_check_https_tls12() +{ + # $1 - test function + # $2 - domain + + [ "$NOTEST_OOB_HTTPS" = 1 ] && { echo "SKIPPED"; return; } + + pktws_oob "$@" +} + +pktws_check_https_tls13() +{ + # $1 - test function + # $2 - domain + pktws_check_https_tls12 "$1" "$2" +} diff --git a/blockcheck/zapret2/blockcheck2.d/standard/20-multi.sh b/blockcheck/zapret2/blockcheck2.d/standard/20-multi.sh new file mode 100644 index 0000000..e473b77 --- /dev/null +++ b/blockcheck/zapret2/blockcheck2.d/standard/20-multi.sh @@ -0,0 +1,74 @@ +. "$TESTDIR/def.inc" + +pktws_simple_split_tests() +{ + # $1 - test function + # $2 - domain/uri + # $3 - splits + # $4 - PRE args for nfqws2 + local pos ok ok_any pre="$4" func + local splitf splitfs="multisplit multidisorder" + + ok_any=0 + for splitf in $splitfs; do + func=$splitf + [ "$func" = multidisorder ] && func=$MULTIDISORDER + eval need_$splitf=0 + ok=0 + for pos in $3; do + pktws_curl_test_update $1 $2 $pre $PAYLOAD --lua-desync=$func:pos=$pos && ok=1 + done + [ "$ok" = 1 -a "$SCANLEVEL" != force ] || eval need_$splitf=1 + [ "$ok" = 1 ] && ok_any=1 + done + [ "$ok_any" = 1 ] +} + + +pktws_check_http() +{ + # $1 - test function + # $2 - domain + local splits_http='method+2 midsld method+2,midsld' + local PAYLOAD="--payload=http_req" + + [ "$NOTEST_MULTI_HTTP" = 1 ] && { echo "SKIPPED"; return; } + + pktws_simple_split_tests "$1" "$2" "$splits_http" +} + +pktws_check_https_tls() +{ + # $1 - test function + # $2 - domain + # $3 - PRE args for nfqws2 + local splits_tls='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,midsld,1220 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1' + local PAYLOAD="--payload=tls_client_hello" + + pktws_simple_split_tests "$1" "$2" "$splits_tls" "$3" +} + +pktws_check_https_tls12() +{ + # $1 - test function + # $2 - domain + + [ "$NOTEST_MULTI_HTTPS" = 1 ] && { echo "SKIPPED"; return; } + + pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return + + # do not use 'need' values obtained with wssize + local need_multisplit_save=$need_multisplit need_multidisorder_save=$need_multidisorder + pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6 + need_multisplit=$need_multisplit_save; need_multidisorder=$need_multidisorder_save +} + +pktws_check_https_tls13() +{ + # $1 - test function + # $2 - domain + + [ "$NOTEST_MULTI_HTTPS" = 1 ] && { echo "SKIPPED"; return; } + + pktws_check_https_tls "$1" "$2" +} diff --git a/blockcheck/zapret2/blockcheck2.d/standard/23-seqovl.sh b/blockcheck/zapret2/blockcheck2.d/standard/23-seqovl.sh new file mode 100644 index 0000000..b310fb7 --- /dev/null +++ b/blockcheck/zapret2/blockcheck2.d/standard/23-seqovl.sh @@ -0,0 +1,92 @@ +. "$TESTDIR/def.inc" + +pktws_check_http() +{ + # $1 - test function + # $2 - domain + + [ "$NOTEST_SEQOVL_HTTP" = 1 ] && { echo "SKIPPED"; return; } + + local PAYLOAD="--payload=http_req" + + local ok pat= split f f2 + + pat=${SEQOVL_PATTERN_HTTP:+seqovl_pat} + pat=${pat:-fake_default_http} + + pktws_curl_test_update $1 $2 $PAYLOAD --lua-desync=tcpseg:pos=0,-1:seqovl=1 --lua-desync=drop + pktws_curl_test_update $1 $2 ${SEQOVL_PATTERN_HTTP:+--blob=$pat:@"$SEQOVL_PATTERN_HTTP" }$PAYLOAD --lua-desync=tcpseg:pos=0,-1:seqovl=#$pat:seqovl_pattern=$pat --lua-desync=drop + + ok=0 + for split in method+2 method+2,midsld; do + pktws_curl_test_update $1 $2 $PAYLOAD --lua-desync=multisplit:pos=$split:seqovl=1 && ok=1 + pktws_curl_test_update $1 $2 ${SEQOVL_PATTERN_HTTP:+--blob=$pat:@"$SEQOVL_PATTERN_HTTP" }$PAYLOAD --lua-desync=multisplit:pos=$split:seqovl=#$pat:seqovl_pattern=$pat && ok=1 + [ "$ok" = 1 -a "$SCANLEVEL" != force ] && break + done + for split in 'method+1 method+2' 'midsld-1 midsld' 'method+1 method+2,midsld'; do + f="$(extract_arg 1 $split)" + f2="$(extract_arg 2 $split)" + pktws_curl_test_update $1 $2 $PAYLOAD --lua-desync=$MULTIDISORDER:pos=$f2:seqovl=$f + pktws_curl_test_update $1 $2 ${SEQOVL_PATTERN_HTTP:+--blob=$pat:@"$SEQOVL_PATTERN_HTTP" }$PAYLOAD --lua-desync=$MULTIDISORDER:pos=$f2:seqovl=$f:seqovl_pattern=$pat + done +} + +pktws_seqovl_tests_tls() +{ + # $1 - test function + # $2 - domain/uri + # $3 - PRE args for nfqws2 + + local ok ok_any + local testf=$1 domain="$2" pre="$3" + local pat rnd_mod padencap_mod split f f2 + local PAYLOAD="--payload=tls_client_hello" + + pat=${SEQOVL_PATTERN_HTTPS:+seqovl_pat} + pat=${pat:-fake_default_tls} + rnd_mod="--lua-init=$pat=tls_mod($pat,'rnd')" + padencap_mod="--lua-desync=luaexec:code=desync.patmod=tls_mod($pat,'rnd,dupsid,padencap',desync.reasm_data)" + + ok=0 + pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=tcpseg:pos=0,-1:seqovl=1 --lua-desync=drop && ok=1 + pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$rnd_mod $pre $PAYLOAD --lua-desync=tcpseg:pos=0,-1:seqovl=#$pat:seqovl_pattern=$pat --lua-desync=drop && ok=1 + pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$pre $PAYLOAD $padencap_mod --lua-desync=tcpseg:pos=0,-1:seqovl=#patmod:seqovl_pattern=patmod --lua-desync=drop && ok=1 + ok_any=$ok + + ok=0 + for split in 10 10,sniext+1 10,sniext+4 10,midsld; do + pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=multisplit:pos=$split:seqovl=1 && ok=1 + pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$rnd_mod $pre $PAYLOAD --lua-desync=multisplit:pos=$split:seqovl=#$pat:seqovl_pattern=$pat && ok=1 + pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$pre $PAYLOAD $padencap_mod --lua-desync=multisplit:pos=$split:seqovl=#patmod:seqovl_pattern=patmod && ok=1 + [ "$ok" = 1 -a "$SCANLEVEL" != force ] && break + done + for split in '1 2' 'sniext sniext+1' 'sniext+3 sniext+4' 'midsld-1 midsld' '1 2,midsld'; do + f="$(extract_arg 1 $split)" + f2="$(extract_arg 2 $split)" + pktws_curl_test_update $1 $2 $pre $PAYLOAD --lua-desync=$MULTIDISORDER:pos=$f2:seqovl=$f && ok=1 + pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$rnd_mod $pre $PAYLOAD --lua-desync=$MULTIDISORDER:pos=$f2:seqovl=$f:seqovl_pattern=$pat && ok=1 + done + [ "$ok" = 1 ] && ok_any=1 + [ "$ok_any" = 1 ] +} + +pktws_check_https_tls12() +{ + # $1 - test function + # $2 - domain + + [ "$NOTEST_SEQOVL_HTTPS" = 1 ] && { echo "SKIPPED"; return; } + + pktws_seqovl_tests_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return + pktws_seqovl_tests_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6 +} + +pktws_check_https_tls13() +{ + # $1 - test function + # $2 - domain + + [ "$NOTEST_SEQOVL_HTTPS" = 1 ] && { echo "SKIPPED"; return; } + + pktws_seqovl_tests_tls "$1" "$2" +} diff --git a/blockcheck/zapret2/blockcheck2.d/standard/24-syndata.sh b/blockcheck/zapret2/blockcheck2.d/standard/24-syndata.sh new file mode 100644 index 0000000..5bfb26d --- /dev/null +++ b/blockcheck/zapret2/blockcheck2.d/standard/24-syndata.sh @@ -0,0 +1,55 @@ +. "$TESTDIR/def.inc" + +pktws_check_http() +{ + # $1 - test function + # $2 - domain + + local PAYLOAD="--payload=http_req" split + + [ "$NOTEST_SYNDATA_HTTP" = 1 ] && { echo "SKIPPED"; return; } + + for split in '' multisplit $MULTIDISORDER; do + pktws_curl_test_update "$1" "$2" --lua-desync=syndata ${split:+$PAYLOAD --lua-desync=$split} + pktws_curl_test_update "$1" "$2" --lua-desync=syndata:blob=fake_default_http ${split:+$PAYLOAD --lua-desync=$split} + done +} + +pktws_check_https_tls() +{ + # $1 - test function + # $2 - domain + # $3 - PRE args for nfqws2 + + local PAYLOAD="--payload=tls_client_hello" ok=0 pre="$3" split + + for split in '' multisplit $MULTIDISORDER; do + pktws_curl_test_update "$1" "$2" $pre --lua-desync=syndata ${split:+$PAYLOAD --lua-desync=$split} && ok=1 + pktws_curl_test_update "$1" "$2" $pre --lua-desync=syndata:blob=0x1603 ${split:+$PAYLOAD --lua-desync=$split} && ok=1 + pktws_curl_test_update "$1" "$2" $pre --lua-desync=syndata:blob=fake_default_tls:tls_mod=rnd,dupsid,rndsni ${split:+$PAYLOAD --lua-desync=$split} && ok=1 + pktws_curl_test_update "$1" "$2" $pre --lua-desync=syndata:blob=fake_default_tls:tls_mod=rnd,dupsid,sni=google.com ${split:+$PAYLOAD --lua-desync=$split} && ok=1 + done + + [ "$ok" = 1 ] +} + +pktws_check_https_tls12() +{ + # $1 - test function + # $2 - domain + + [ "$NOTEST_SYNDATA_HTTPS" = 1 ] && { echo "SKIPPED"; return; } + + pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return + pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6 +} + +pktws_check_https_tls13() +{ + # $1 - test function + # $2 - domain + + [ "$NOTEST_SYNDATA_HTTPS" = 1 ] && { echo "SKIPPED"; return; } + + pktws_check_https_tls "$1" "$2" +} diff --git a/blockcheck/zapret2/blockcheck2.d/standard/25-fake.sh b/blockcheck/zapret2/blockcheck2.d/standard/25-fake.sh new file mode 100644 index 0000000..121c115 --- /dev/null +++ b/blockcheck/zapret2/blockcheck2.d/standard/25-fake.sh @@ -0,0 +1,153 @@ +. "$TESTDIR/def.inc" + +pktws_check_http() +{ + # $1 - test function + # $2 - domain + [ "$NOTEST_FAKE_HTTP" = 1 ] && { echo "SKIPPED"; return; } + + local testf=$1 domain="$2" + local ok ok_any ttls attls f ff fake fooling + local PAYLOAD="--payload=http_req" + + if [ -n "$FAKE_HTTP" ]; then + fake=fake_http + else + fake=fake_default_http + fi + + need_fake=0 + + [ "$MAX_TTL" = 0 ] || ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL) + [ "$MAX_AUTOTTL_DELTA" = 0 ] || attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA) + + ok_any=0 + ok=0 + for ttl in $ttls; do + # orig-ttl=1 with start/cutoff limiter drops empty ACK packet in response to SYN,ACK. it does not reach DPI or server. + # missing ACK is transmitted in the first data packet of TLS/HTTP proto + for ff in $fake 0x00000000; do + for f in '' "--payload=empty --out-range=s1/dev/null; then + left=$CURL_PAD + CURL_PAD_FILE=/tmp/zapret-curlpad-$$ + rm -f "$CURL_PAD_FILE" + touch "$CURL_PAD_FILE" + while [ "$left" -ge 14 ]; do + left=$(($left-14)) + if [ "$left" -gt "$PAD_MAX_HEADER" ]; then + size="$PAD_MAX_HEADER" + else + size=$left + fi + left=$(($left-$size)) + # if the next header would be too small add the remainder to the current header + [ "$left" -lt 14 ] && size=$(($size+$left)) + + printf 'X-Pad-%04d: ' $n >> "$CURL_PAD_FILE" + head -c $size /dev/zero | tr '\0' A >> "$CURL_PAD_FILE" + # curl internally adds 0D0A line ending even if it's 0A in the file + echo >> "$CURL_PAD_FILE" + n=$(($n+1)) + done + CURL_OPT="${CURL_OPT}${CURL_OPT:+ }-H @$CURL_PAD_FILE" + fi +} + + +killwait() +{ + # $1 - signal (-9, -2, ...) + # $2 - pid + local KILL=kill + # avoid internal bash kill in cygwin to support -f + [ "$UNAME" = "CYGWIN" ] && KILL=/bin/kill + $KILL $1 $2 + # suppress job kill message + wait $2 2>/dev/null +} + +exitp() +{ + local A + + [ "$BATCH" = 1 ] || { + echo + echo press enter to continue + read A + } + exit $1 +} + +pf_is_avail() +{ + [ -c /dev/pf ] +} +pf_status() +{ + pfctl -qsi | sed -nre "s/^Status: ([^ ]+).*$/\1/p" +} +pf_is_enabled() +{ + [ "$(pf_status)" = Enabled ] +} +pf_save() +{ + PF_STATUS=0 + pf_is_enabled && PF_STATUS=1 + [ "$UNAME" = "OpenBSD" ] && pfctl -sr >"$PF_RULES_SAVE" +} +pf_restore() +{ + [ -n "$PF_STATUS" ] || return + case "$UNAME" in + OpenBSD) + if [ -f "$PF_RULES_SAVE" ]; then + pfctl -qf "$PF_RULES_SAVE" + else + echo | pfctl -qf - + fi + ;; + esac + if [ "$PF_STATUS" = 1 ]; then + pfctl -qe + else + pfctl -qd + fi +} +pf_clean() +{ + rm -f "$PF_RULES_SAVE" +} +opf_dvtws_anchor() +{ + # $1 - tcp/udp + # $2 - port + # $3 - ip list + local iplist family=inet + [ "$IPV" = 6 ] && family=inet6 + make_comma_list iplist "$3" + echo "set reassemble no" + [ "$1" = tcp ] && echo "pass in quick $family proto $1 from {$iplist} port $2 flags SA/SA divert-packet port $IPFW_DIVERT_PORT no state" + echo "pass in quick $family proto $1 from {$iplist} port $2 no state" + echo "pass out quick $family proto $1 to {$iplist} port $2 divert-packet port $IPFW_DIVERT_PORT no state" + echo "pass" +} +opf_prepare_dvtws() +{ + # $1 - tcp/udp + # $2 - port + # $3 - ip list + opf_dvtws_anchor $1 $2 "$3" | pfctl -qf - + pfctl -qe +} + +cleanup() +{ + case "$UNAME" in + OpenBSD) + pf_clean + ;; + esac + [ -n "$CURL_PAD_FILE" ] && rm -f "$CURL_PAD_FILE" +} + +IPT() +{ + $IPTABLES -C "$@" >/dev/null 2>/dev/null || $IPTABLES -I "$@" +} +IPT_DEL() +{ + $IPTABLES -C "$@" >/dev/null 2>/dev/null && $IPTABLES -D "$@" +} +IPT_ADD_DEL() +{ + on_off_function IPT IPT_DEL "$@" +} +IPFW_ADD() +{ + ipfw -qf add $IPFW_RULE_NUM "$@" +} +IPFW_DEL() +{ + ipfw -qf delete $IPFW_RULE_NUM 2>/dev/null +} +ipt6_has_raw() +{ + ip6tables -nL -t raw >/dev/null 2>/dev/null +} +ipt6_has_frag() +{ + ip6tables -A OUTPUT -m frag 2>/dev/null || return 1 + ip6tables -D OUTPUT -m frag 2>/dev/null +} +ipt_has_nfq() +{ + # cannot just check /proc/net/ip_tables_targets because of iptables-nft or modules not loaded yet + iptables -A OUTPUT -t mangle -p 255 -j NFQUEUE --queue-num $QNUM --queue-bypass 2>/dev/null || return 1 + iptables -D OUTPUT -t mangle -p 255 -j NFQUEUE --queue-num $QNUM --queue-bypass 2>/dev/null + return 0 +} +nft_has_nfq() +{ + local res=1 + nft delete table ${NFT_TABLE}_test 2>/dev/null + nft add table ${NFT_TABLE}_test 2>/dev/null && { + nft add chain ${NFT_TABLE}_test test + nft add rule ${NFT_TABLE}_test test queue num $QNUM bypass 2>/dev/null && res=0 + nft delete table ${NFT_TABLE}_test + } + return $res +} + +doh_resolve() +{ + # $1 - ip version 4/6 + # $2 - hostname + # $3 - doh server URL. use $DOH_SERVER if empty + "$MDIG" --family=$1 --dns-make-query=$2 | "$CURL" --max-time $CURL_MAX_TIME_DOH -s --data-binary @- -H "Content-Type: application/dns-message" "${3:-$DOH_SERVER}" | "$MDIG" --dns-parse-query +} +doh_find_working() +{ + local doh + + [ -n "$DOH_SERVER" ] && return 0 + echo "* searching working DoH server" + DOH_SERVER= + for doh in $DOH_SERVERS; do + echo -n "$doh : " + if doh_resolve 4 iana.org $doh >/dev/null 2>/dev/null; then + echo OK + DOH_SERVER="$doh" + return 0 + else + echo FAIL + fi + done + echo all DoH servers failed + return 1 +} + +mdig_vars() +{ + # $1 - ip version 4/6 + # $2 - hostname + + hostvar=$(echo $2 | sed -e 's/[\./?&#@%*$^:~=!()+-]/_/g' | tr 'A-Z' 'a-z') + cachevar=DNSCACHE_${hostvar}_$1 + countvar=${cachevar}_COUNT + eval count=\$${countvar} +} +mdig_cache() +{ + # $1 - ip version 4/6 + # $2 - hostname + local hostvar cachevar countvar count ip ips + mdig_vars "$@" + [ -n "$count" ] || { + # windows version of mdig outputs 0D0A line ending. remove 0D. + if [ "$SECURE_DNS" = 1 ]; then + ips="$(echo $2 | doh_resolve $1 $2 | tr -d '\r' | xargs)" + else + ips="$(echo $2 | "$MDIG" --family=$1 | tr -d '\r' | xargs)" + fi + [ -n "$ips" ] || return 1 + count=0 + for ip in $ips; do + eval ${cachevar}_$count=$ip + count=$(($count+1)) + done + eval $countvar=$count + } + return 0 +} +mdig_resolve() +{ + # $1 - ip version 4/6 + # $2 - var to receive result + # $3 - hostname, possibly with uri : rutracker.org/xxx/xxxx + local hostvar cachevar countvar count n sdom + + split_by_separator "$3" / sdom + mdig_vars "$1" "$sdom" + if [ -n "$count" ]; then + n=$(random 0 $(($count-1))) + eval $2=\$${cachevar}_$n + return 0 + else + mdig_cache "$1" "$sdom" && mdig_resolve "$1" "$2" "$sdom" + fi +} +mdig_resolve_all() +{ + # $1 - ip version 4/6 + # $2 - var to receive result + # $3 - hostname + + local hostvar cachevar countvar count ip__ ips__ n sdom + + split_by_separator "$3" / sdom + mdig_vars "$1" "$sdom" + if [ -n "$count" ]; then + n=0 + while [ "$n" -lt $count ]; do + eval ip__=\$${cachevar}_$n + if [ -n "$ips__" ]; then + ips__="$ips__ $ip__" + else + ips__="$ip__" + fi + n=$(($n + 1)) + done + eval $2="\$ips__" + return 0 + else + mdig_cache "$1" "$sdom" && mdig_resolve_all "$1" "$2" "$sdom" + fi +} + +netcat_setup() +{ + [ -n "$NCAT" ] || { + if exists ncat; then + NCAT=ncat + elif exists nc; then + # busybox netcat does not support any required options + is_linked_to_busybox nc && return 1 + NCAT=nc + else + return 1 + fi + } + return 0 +} +netcat_test() +{ + # $1 - ip + # $2 - port + local cmd + netcat_setup && { + cmd="$NCAT -z -w 2 $1 $2" + echo $cmd + $cmd 2>&1 + } +} + +check_system() +{ + echo \* checking system + + UNAME=$(uname) + SUBSYS= + local s + + # can be passed FWTYPE=iptables to override default nftables preference + case "$UNAME" in + Linux) + PKTWS="$NFQWS2" + PKTWSD=nfqws2 + linux_fwtype + [ "$FWTYPE" = iptables -o "$FWTYPE" = nftables ] || { + echo firewall type $FWTYPE not supported in $UNAME + exitp 5 + } + ;; + FreeBSD) + PKTWS="$DVTWS2" + PKTWSD=dvtws2 + FWTYPE=ipfw + [ -f /etc/platform ] && read SUBSYS /dev/null + ;; + *) + echo $UNAME not supported + exitp 5 + esac + echo $UNAME${SUBSYS:+/$SUBSYS} detected + echo -n 'kernel: ' + if [ -f "/proc/version" ]; then + cat /proc/version + else + uname -a + fi + [ -f /etc/os-release ] && { + . /etc/os-release + [ -n "$PRETTY_NAME" ] && echo "distro: $PRETTY_NAME" + [ -n "$OPENWRT_RELEASE" ] && echo "openwrt release: $OPENWRT_RELEASE" + [ -n "$OPENWRT_BOARD" ] && echo "openwrt board: $OPENWRT_BOARD" + [ -n "$OPENWRT_ARCH" ] && echo "openwrt arch: $OPENWRT_ARCH" + } + echo firewall type is $FWTYPE + echo CURL=$CURL + "$CURL" --version +} + +zp_already_running() +{ + case "$UNAME" in + CYGWIN) + win_process_exists $PKTWSD || win_process_exists winws || win_process_exists goodbyedpi + ;; + FreeBSD|OpenBSD) + process_exists $PKTWSD || process_exists tpws || process_exists dvtws + ;; + Linux) + process_exists $PKTWSD || process_exists tpws || process_exists nfqws + ;; + *) + return 1 + esac +} +check_already() +{ + echo \* checking already running DPI bypass processes + if zp_already_running; then + echo "!!! WARNING. some dpi bypass processes already running !!!" + echo "!!! WARNING. blockcheck requires all DPI bypass methods disabled !!!" + echo "!!! WARNING. pls stop all dpi bypass instances that may interfere with blockcheck !!!" + fi +} + +freebsd_module_loaded() +{ + # $1 - module name + kldstat -qm "${1}" +} +freebsd_modules_loaded() +{ + # $1,$2,$3, ... - module names + while [ -n "$1" ]; do + freebsd_module_loaded $1 || return 1 + shift + done + return 0 +} + +check_prerequisites() +{ + echo \* checking prerequisites + + [ "$SKIP_PKTWS" = 1 -o -x "$PKTWS" ] && [ -x "$MDIG" ] || { + local target + case $UNAME in + OpenBSD) + target="bsd" + echo $PKTWS or $MDIG is not available. \`gmake -C \"$ZAPRET_BASE\" bsd \` + ;; + *) + echo $PKTWS or $MDIG is not available. run \"$ZAPRET_BASE/install_bin.sh\" or \`make -C \"$ZAPRET_BASE\" $target\` + esac + exitp 6 + } + + local prog progs='curl' + [ "$SKIP_PKTWS" = 1 ] || { + case "$UNAME" in + Linux) + case "$FWTYPE" in + iptables) + ipt_has_nfq || { + echo NFQUEUE iptables or ip6tables target is missing. pls install modules. + exitp 6 + } + progs="$progs iptables ip6tables" + ;; + nftables) + nft_has_nfq || { + echo nftables queue support is not available. pls install modules. + exitp 6 + } + progs="$progs nft" + ;; + esac + ;; + FreeBSD) + freebsd_modules_loaded ipfw ipdivert || { + echo ipfw or ipdivert kernel module not loaded + exitp 6 + } + [ "$(sysctl -qn net.inet.ip.fw.enable)" = 0 -o "$(sysctl -qn net.inet6.ip6.fw.enable)" = 0 ] && { + echo ipfw is disabled. use : ipfw enable firewall + exitp 6 + } + pf_is_avail && { + pf_save + [ "$SUBSYS" = "pfSense" ] && { + # pfsense's ipfw may not work without these workarounds + sysctl net.inet.ip.pfil.outbound=ipfw,pf 2>/dev/null + sysctl net.inet.ip.pfil.inbound=ipfw,pf 2>/dev/null + sysctl net.inet6.ip6.pfil.outbound=ipfw,pf 2>/dev/null + sysctl net.inet6.ip6.pfil.inbound=ipfw,pf 2>/dev/null + pfctl -qd + pfctl -qe + pf_restore + } + } + progs="$progs ipfw" + ;; + OpenBSD) + pf_is_avail || { + echo pf is not available + exitp 6 + } + pf_save + progs="$progs pfctl" + ;; + esac + } + + for prog in $progs; do + exists $prog || { + echo $prog does not exist. please install + exitp 6 + } + done + + if exists nslookup; then + LOOKUP=nslookup + elif exists host; then + LOOKUP=host + else + echo nslookup or host does not exist. please install + exitp 6 + fi +} + + +curl_translate_code() +{ + # $1 - code + printf $1 + case $1 in + 0) printf ": ok" + ;; + 1) printf ": unsupported protocol" + ;; + 2) printf ": early initialization code failed" + ;; + 3) printf ": the URL was not properly formatted" + ;; + 4) printf ": feature not supported by libcurl" + ;; + 5) printf ": could not resolve proxy" + ;; + 6) printf ": could not resolve host" + ;; + 7) printf ": could not connect" + ;; + 8) printf ": invalid server reply" + ;; + 9) printf ": remote access denied" + ;; + 27) printf ": out of memory" + ;; + 28) printf ": operation timed out" + ;; + 35) printf ": SSL connect error" + ;; + esac +} +curl_supports_tls13() +{ + local r + "$CURL" --tlsv1.3 -Is -o /dev/null --max-time 1 http://127.0.0.1:65535 2>/dev/null + # return code 2 = init failed. likely bad command line options + [ $? = 2 ] && return 1 + # curl can have tlsv1.3 key present but ssl library without TLS 1.3 support + # this is online test because there's no other way to trigger library incompatibility case + "$CURL" --tlsv1.3 --max-time 1 -Is -o /dev/null https://iana.org 2>/dev/null + r=$? + [ $r != 4 -a $r != 35 ] +} + +curl_supports_tlsmax() +{ + # supported only in OpenSSL and LibreSSL + "$CURL" --version | grep -Fq -e OpenSSL -e LibreSSL -e BoringSSL -e GnuTLS -e quictls || return 1 + # supported since curl 7.54 + "$CURL" --tls-max 1.2 -Is -o /dev/null --max-time 1 http://127.0.0.1:65535 2>/dev/null + # return code 2 = init failed. likely bad command line options + [ $? != 2 ] +} + +curl_supports_connect_to() +{ + "$CURL" --connect-to 127.0.0.1:: -o /dev/null --max-time 1 http://127.0.0.1:65535 2>/dev/null + [ "$?" != 2 ] +} + +curl_supports_http3() +{ + # if it has http3 : curl: (3) HTTP/3 requested for non-HTTPS URL + # otherwise : curl: (2) option --http3-only: is unknown + "$CURL" --connect-to 127.0.0.1:: -o /dev/null --max-time 1 --http3-only http://127.0.0.1:65535 2>/dev/null + [ "$?" != 2 ] +} + +hdrfile_http_code() +{ + # $1 - hdr file + sed -nre '1,1 s/^HTTP\/1\.[0,1] ([0-9]+) .*$/\1/p' "$1" +} +hdrfile_location() +{ + # $1 - hdr file + + # some DPIs return CRLF line ending + tr -d '\015' <"$1" | sed -nre 's/^[Ll][Oo][Cc][Aa][Tt][Ii][Oo][Nn]:[ ]*([^ ]*)[ ]*$/\1/p' +} + +curl_with_subst_ip() +{ + # $1 - domain + # $2 - port + # $3 - ip + # $4+ - curl params + local ip="$3" + case "$ip" in + *:*) ip="[$ip]" ;; + esac + local connect_to="--connect-to $1::$ip${2:+:$2}" arg + shift ; shift ; shift; + [ "$CURL_VERBOSE" = 1 ] && arg="-v" + [ "$CURL_CMD" = 1 ] && echo $CURL ${arg:+$arg }$connect_to "$@" + ALL_PROXY="$ALL_PROXY" "$CURL" ${arg:+$arg }$connect_to "$@" +} +curl_with_dig() +{ + # $1 - ip version : 4/6 + # $2 - domain name + # $3 - port + # $4+ - curl params + local dom="$2" port=$3 + local sdom suri ip + + split_by_separator "$dom" / sdom suri + mdig_resolve $1 ip "$sdom" + shift ; shift ; shift + if [ -n "$ip" ]; then + curl_with_subst_ip "$sdom" "$port" "$ip" "$@" + else + return 6 + fi +} +curl_probe() +{ + # $1 - ip version : 4/6 + # $2 - domain name + # $3 - port + # $4 - subst ip + # $5+ - curl params + local ipv=$1 dom="$2" port=$3 subst=$4 + shift; shift; shift; shift + if [ -n "$subst" ]; then + curl_with_subst_ip "$dom" $port $subst "$@" + else + curl_with_dig $ipv "$dom" $port "$@" + fi +} +curl_test_http() +{ + # $1 - ip version : 4/6 + # $2 - domain name + # $3 - subst ip + # $4 - "detail" - detail info + + local code loc hdrt="${HDRTEMP}_${!:-$$}.txt" dom="$(tolower "$2")" + curl_probe $1 "$2" $HTTP_PORT "$3" -SsD "$hdrt" -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT "http://$2" -o /dev/null 2>&1 || { + code=$? + rm -f "$hdrt" + return $code + } + if [ "$4" = "detail" ] ; then + head -n 1 "$hdrt" + grep "^[lL]ocation:" "$hdrt" + else + code=$(hdrfile_http_code "$hdrt") + [ "$code" = 301 -o "$code" = 302 -o "$code" = 307 -o "$code" = 308 ] && { + loc=$(hdrfile_location "$hdrt") + split_by_separator "$dom" / dom + tolower "$loc" | grep -qE "^https?://.*$dom(/|$)" || + tolower "$loc" | grep -vqE '^https?://' || { + echo suspicious redirection $code to : $loc + rm -f "$hdrt" + return 254 + } + } + fi + rm -f "$hdrt" + [ "$code" = 400 ] && { + # this can often happen if the server receives fake packets it should not receive + echo http code $code. likely the server receives fakes. + return 254 + } + return 0 +} +curl_test_https_tls12() +{ + # $1 - ip version : 4/6 + # $2 - domain name + # $3 - subst ip + + # do not use tls 1.3 to make sure server certificate is not encrypted + curl_probe $1 "$2" $HTTPS_PORT "$3" $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.2 $TLSMAX12 "https://$2" -o /dev/null 2>&1 +} +curl_test_https_tls13() +{ + # $1 - ip version : 4/6 + # $2 - domain name + # $3 - subst ip + + # force TLS1.3 mode + curl_probe $1 "$2" $HTTPS_PORT "$3" $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.3 $TLSMAX13 "https://$2" -o /dev/null 2>&1 +} + +curl_test_http3() +{ + # $1 - ip version : 4/6 + # $2 - domain name + + # force QUIC only mode without tcp + curl_with_dig $1 "$2" $QUIC_PORT $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME_QUIC --http3-only $CURL_OPT "https://$2" -o /dev/null 2>&1 +} + +ipt_aux_scheme() +{ + # $1 - 1 - add , 0 - del + # $2 - tcp/udp + # $3 - port + + # to avoid possible INVALID state drop + [ "$2" = tcp ] && IPT_ADD_DEL $1 INPUT -p $2 --sport $3 ! --syn $IPT_COMMENT -j ACCEPT + + local icmp_filter="-p icmp -m icmp --icmp-type" + [ "$IPV" = 6 ] && icmp_filter="-p icmpv6 -m icmp6 --icmpv6-type" + IPT_ADD_DEL $1 INPUT $icmp_filter time-exceeded -m connmark --mark $DESYNC_MARK/$DESYNC_MARK $IPT_COMMENT -j DROP + + # for strategies with incoming packets involved (autottl) + IPT_ADD_DEL $1 OUTPUT -p $2 --dport $3 -m conntrack --ctstate INVALID $IPT_COMMENT -j ACCEPT + if [ "$IPV" = 6 -a -n "$IP6_DEFRAG_DISABLE" ]; then + # the only way to reliable disable ipv6 defrag. works only in 4.16+ kernels + IPT_ADD_DEL $1 OUTPUT -t raw -p $2 -m frag $IPT_COMMENT -j CT --notrack + elif [ "$IPV" = 4 ]; then + # enable fragments + IPT_ADD_DEL $1 OUTPUT -f $IPT_COMMENT -j ACCEPT + fi + # enable everything generated by nfqws (works only in OUTPUT, not in FORWARD) + # raw table may not be present + IPT_ADD_DEL $1 OUTPUT -t raw -m mark --mark $DESYNC_MARK/$DESYNC_MARK $IPT_COMMENT -j CT --notrack +} +ipt_scheme() +{ + # $1 - tcp/udp + # $2 - port + # $3 - ip list + + local ip + + $IPTABLES -t mangle -N $IPT_OUT_CHAIN 2>/dev/null + $IPTABLES -t mangle -F $IPT_OUT_CHAIN + IPT OUTPUT -t mangle -j $IPT_OUT_CHAIN + + # prevent loop + $IPTABLES -t mangle -A $IPT_OUT_CHAIN -m mark --mark $DESYNC_MARK/$DESYNC_MARK -j RETURN + $IPTABLES -t mangle -A $IPT_OUT_CHAIN ! -p $1 -j RETURN + $IPTABLES -t mangle -A $IPT_OUT_CHAIN -p $1 ! --dport $2 -j RETURN + + for ip in $3; do + $IPTABLES -t mangle -A $IPT_OUT_CHAIN -d $ip -j CONNMARK --or-mark $DESYNC_MARK + $IPTABLES -t mangle -A $IPT_OUT_CHAIN -d $ip -j NFQUEUE --queue-num $QNUM + done + + ipt_aux_scheme 1 $1 $2 +} +nft_scheme() +{ + # $1 - tcp/udp + # $2 - port + # $3 - ip list + + local iplist ipver=$IPV + [ "$IPV" = 6 ] || ipver= + make_comma_list iplist $3 + + nft add table inet $NFT_TABLE + nft "add chain inet $NFT_TABLE postnat { type filter hook postrouting priority 102; }" + nft "add rule inet $NFT_TABLE postnat meta nfproto ipv${IPV} $1 dport $2 mark and $DESYNC_MARK == 0 ip${ipver} daddr {$iplist} ct mark set ct mark or $DESYNC_MARK queue num $QNUM" + # for strategies with incoming packets involved (autottl) + nft "add chain inet $NFT_TABLE prenat { type filter hook prerouting priority -102; }" + # enable everything generated by nfqws (works only in OUTPUT, not in FORWARD) + nft "add chain inet $NFT_TABLE predefrag { type filter hook output priority -402; }" + nft "add rule inet $NFT_TABLE predefrag meta nfproto ipv${IPV} mark and $DESYNC_MARK !=0 notrack" + [ "$IPV" = 4 ] && { + nft "add rule inet $NFT_TABLE prenat icmp type time-exceeded ct mark and $DESYNC_MARK != 0 drop" + nft "add rule inet $NFT_TABLE prenat icmp type time-exceeded ct state invalid drop" + } + [ "$IPV" = 6 ] && { + nft "add rule inet $NFT_TABLE prenat icmpv6 type time-exceeded ct mark and $DESYNC_MARK != 0 drop" + nft "add rule inet $NFT_TABLE prenat icmpv6 type time-exceeded ct state invalid drop" + } +} + +pktws_ipt_prepare() +{ + # $1 - tcp/udp + # $2 - port + # $3 - ip list + + local ip v= + + case "$FWTYPE" in + iptables) + ipt_scheme $1 $2 "$3" + ;; + nftables) + nft_scheme $1 $2 "$3" + ;; + ipfw) + # disable PF to avoid interferences + pf_is_avail && pfctl -qd + for ip in $3; do + IPFW_ADD divert $IPFW_DIVERT_PORT $1 from me to $ip $2 proto ip${IPV} out not diverted + done + ;; + opf) + opf_prepare_dvtws $1 $2 "$3" + ;; + windivert) + [ "$IPV" = 6 ] && v="v6" + WF="--wf-l3=ipv${IPV} --wf-${1}-out=$2" + WFRAWF= + for ip in $3; do + [ -n "$WFRAWF" ] && WFRAWF="$WFRAWF or " + WFRAWF="${WFRAWF}ip${v}.DstAddr=$ip or ip${v}.SrcAddr=$ip" + done + ;; + + esac +} +pktws_ipt_unprepare() +{ + # $1 - tcp/udp + # $2 - port + + case "$FWTYPE" in + iptables) + ipt_aux_scheme 0 $1 $2 + IPT_DEL OUTPUT -t mangle -j $IPT_OUT_CHAIN + $IPTABLES -t mangle -F $IPT_OUT_CHAIN 2>/dev/null + $IPTABLES -t mangle -X $IPT_OUT_CHAIN 2>/dev/null + ;; + nftables) + nft delete table inet $NFT_TABLE 2>/dev/null + ;; + ipfw) + IPFW_DEL + pf_is_avail && pf_restore + ;; + opf) + pf_restore + ;; + windivert) + unset WF WFRAWF + ;; + esac +} + +pktws_ipt_prepare_tcp() +{ + # $1 - port + # $2 - ip list + + local ip iplist ipver + + pktws_ipt_prepare tcp $1 "$2" + + # for autottl mode and tcp_mss detection + case "$FWTYPE" in + iptables) + $IPTABLES -N $IPT_IN_CHAIN -t mangle 2>/dev/null + $IPTABLES -F $IPT_IN_CHAIN -t mangle 2>/dev/null + IPT INPUT -t mangle -j $IPT_IN_CHAIN + $IPTABLES -t mangle -A $IPT_IN_CHAIN ! -p tcp -j RETURN + $IPTABLES -t mangle -A $IPT_IN_CHAIN -p tcp ! --sport $1 -j RETURN + $IPTABLES -t mangle -A $IPT_IN_CHAIN -p tcp ! --tcp-flags SYN,ACK SYN,ACK -j RETURN + for ip in $2; do + $IPTABLES -A $IPT_IN_CHAIN -t mangle -s $ip -j NFQUEUE --queue-num $QNUM + done + ;; + nftables) + ipver=$IPV + [ "$IPV" = 6 ] || ipver= + make_comma_list iplist $2 + nft "add rule inet $NFT_TABLE prenat meta nfproto ipv${IPV} tcp sport $1 tcp flags & (syn | ack) == (syn | ack) ip${ipver} saddr {$iplist} queue num $QNUM" + ;; + ipfw) + for ip in $2; do + IPFW_ADD divert $IPFW_DIVERT_PORT tcp from $ip $1 to me proto ip${IPV} tcpflags syn,ack in not diverted + done + ;; + esac +} +pktws_ipt_unprepare_tcp() +{ + # $1 - port + + pktws_ipt_unprepare tcp $1 + + case "$FWTYPE" in + iptables) + IPT_DEL INPUT -t mangle -j $IPT_IN_CHAIN + $IPTABLES -t mangle -F $IPT_IN_CHAIN 2>/dev/null + $IPTABLES -t mangle -X $IPT_IN_CHAIN 2>/dev/null + ;; + esac +} +pktws_ipt_prepare_udp() +{ + # $1 - port + # $2 - ip list + + pktws_ipt_prepare udp $1 "$2" +} +pktws_ipt_unprepare_udp() +{ + # $1 - port + + pktws_ipt_unprepare udp $1 +} + + +pktws_start() +{ + case "$UNAME" in + Linux) + "$NFQWS2" --uid $WS_UID:$WS_GID --fwmark=$DESYNC_MARK --qnum=$QNUM --lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null & + ;; + FreeBSD|OpenBSD) + "$DVTWS2" --port=$IPFW_DIVERT_PORT --lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null & + ;; + CYGWIN) + # some methods require empty acks + # use raw filter to filter target ip addresses in-kernel to allow multiple blockchecks running at the same time + # use guard timer to kill unmanaged pktws instances + "$WINWS2" --wf-tcp-empty=1 $WF --wf-raw-filter="$WFRAWF" \ + --lua-init="timer_set('exit_guard',function(name,data) io.stderr:write('exit_guard\n'); os.exit(3000); end,20000,true)" \ + --lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null & + ;; + esac + PID=$! + # give some time to initialize + minsleep +} + +ws_kill() +{ + local sig + [ -z "$PID" ] || { + sig=-9 + # use fast kill using TerminateProcess() in cygwin + [ "$UNAME" = "CYGWIN" ] && sig=-f + killwait $sig $PID 2>/dev/null + PID= + } +} + +check_domain_port_block() +{ + # $1 - domain + # $2 - port + local ip ips + echo + echo \* port block tests ipv$IPV $1:$2 + if netcat_setup; then + mdig_resolve_all $IPV ips $1 + if [ -n "$ips" ]; then + for ip in $ips; do + if netcat_test $ip $2; then + echo $ip connects + else + echo $ip does not connect. netcat code $? + fi + done + else + echo "ipv${IPV} $1 does not resolve" + fi + else + echo suitable netcat not found. busybox nc is not supported. pls install nmap ncat or openbsd netcat. + fi +} + +curl_test() +{ + # $1 - test function + # $2 - domain + # $3 - subst ip + # $4 - param of test function + local code=0 n=0 p pids + + if [ "$PARALLEL" = 1 ]; then + rm -f "${PARALLEL_OUT}"* + for n in $(seq -s ' ' 1 $REPEATS); do + $1 "$IPV" "$2" $3 "$4" >"${PARALLEL_OUT}_$n" & + pids="${pids:+$pids }$!" + done + n=1 + for p in $pids; do + [ $REPEATS -gt 1 ] && printf "[attempt $n] " + if wait $p; then + [ $REPEATS -gt 1 ] && echo 'AVAILABLE' + else + code=$? + cat "${PARALLEL_OUT}_$n" + fi + n=$(($n+1)) + done + rm -f "${PARALLEL_OUT}"* + else + while [ $n -lt $REPEATS ]; do + n=$(($n+1)) + [ $REPEATS -gt 1 ] && printf "[attempt $n] " + if $1 "$IPV" "$2" $3 "$4" ; then + [ $REPEATS -gt 1 ] && echo 'AVAILABLE' + else + code=$? + [ "$SCANLEVEL" = quick ] && break + fi + done + fi + [ "$4" = detail ] || { + if [ $code = 254 ]; then + echo "UNAVAILABLE" + elif [ $code = 0 ]; then + echo '!!!!! AVAILABLE !!!!!' + else + echo "UNAVAILABLE code=$code" + fi + } + return $code +} +ws_curl_test() +{ + # $1 - ws start function + # $2 - test function + # $3 - domain + # $4,$5,$6, ... - ws params + local code ws_start=$1 testf=$2 dom="$3" + + [ "$SIMULATE" = 1 ] && { + n=$(random 0 99) + if [ "$n" -lt "$SIM_SUCCESS_RATE" ]; then + echo "SUCCESS" + return 0 + else + echo "FAILED" + return 7 + fi + } + shift + shift + shift + $ws_start "$@" + curl_test $testf "$dom" + code=$? + ws_kill + return $code +} +pktws_curl_test() +{ + # $1 - test function + # $2 - domain + # $3,$4,$5, ... - nfqws/dvtws params + local testf=$1 dom="$2" strategy code + + shift; shift; + echo - $testf ipv$IPV $dom : $PKTWSD ${WF:+$WF }${PKTWS_EXTRA_PRE:+$PKTWS_EXTRA_PRE }${PKTWS_EXTRA_PRE_1:+"$PKTWS_EXTRA_PRE_1" }${PKTWS_EXTRA_PRE_2:+"$PKTWS_EXTRA_PRE_2" }${PKTWS_EXTRA_PRE_3:+"$PKTWS_EXTRA_PRE_3" }${PKTWS_EXTRA_PRE_4:+"$PKTWS_EXTRA_PRE_4" }${PKTWS_EXTRA_PRE_5:+"$PKTWS_EXTRA_PRE_5" }${PKTWS_EXTRA_PRE_6:+"$PKTWS_EXTRA_PRE_6" }${PKTWS_EXTRA_PRE_7:+"$PKTWS_EXTRA_PRE_7" }${PKTWS_EXTRA_PRE_8:+"$PKTWS_EXTRA_PRE_8" }${PKTWS_EXTRA_PRE_9:+"$PKTWS_EXTRA_PRE_9" }$@${PKTWS_EXTRA_POST:+ $PKTWS_EXTRA_POST}${PKTWS_EXTRA_POST_1:+ "$PKTWS_EXTRA_POST_1"}${PKTWS_EXTRA_POST_2:+ "$PKTWS_EXTRA_POST_2"}${PKTWS_EXTRA_POST_3:+ "$PKTWS_EXTRA_POST_3"}${PKTWS_EXTRA_POST_4:+ "$PKTWS_EXTRA_POST_4"}${PKTWS_EXTRA_POST_5:+ "$PKTWS_EXTRA_POST_5"}${PKTWS_EXTRA_POST_6:+ "$PKTWS_EXTRA_POST_6"}${PKTWS_EXTRA_POST_7:+ "$PKTWS_EXTRA_POST_7"}${PKTWS_EXTRA_POST_8:+ "$PKTWS_EXTRA_POST_8"}${PKTWS_EXTRA_POST_9:+ "$PKTWS_EXTRA_POST_9"} + ws_curl_test pktws_start $testf "$dom" ${PKTWS_EXTRA_PRE:+$PKTWS_EXTRA_PRE }${PKTWS_EXTRA_PRE_1:+"$PKTWS_EXTRA_PRE_1" }${PKTWS_EXTRA_PRE_2:+"$PKTWS_EXTRA_PRE_2" }${PKTWS_EXTRA_PRE_3:+"$PKTWS_EXTRA_PRE_3" }${PKTWS_EXTRA_PRE_4:+"$PKTWS_EXTRA_PRE_4" }${PKTWS_EXTRA_PRE_5:+"$PKTWS_EXTRA_PRE_5" }${PKTWS_EXTRA_PRE_6:+"$PKTWS_EXTRA_PRE_6" }${PKTWS_EXTRA_PRE_7:+"$PKTWS_EXTRA_PRE_7" }${PKTWS_EXTRA_PRE_8:+"$PKTWS_EXTRA_PRE_8" }${PKTWS_EXTRA_PRE_9:+"$PKTWS_EXTRA_PRE_9" }"$@"${PKTWS_EXTRA_POST:+ $PKTWS_EXTRA_POST}${PKTWS_EXTRA_POST_1:+ "$PKTWS_EXTRA_POST_1"}${PKTWS_EXTRA_POST_2:+ "$PKTWS_EXTRA_POST_2"}${PKTWS_EXTRA_POST_3:+ "$PKTWS_EXTRA_POST_3"}${PKTWS_EXTRA_POST_4:+ "$PKTWS_EXTRA_POST_4"}${PKTWS_EXTRA_POST_5:+ "$PKTWS_EXTRA_POST_5"}${PKTWS_EXTRA_POST_6:+ "$PKTWS_EXTRA_POST_6"}${PKTWS_EXTRA_POST_7:+ "$PKTWS_EXTRA_POST_7"}${PKTWS_EXTRA_POST_8:+ "$PKTWS_EXTRA_POST_8"}${PKTWS_EXTRA_POST_9:+ "$PKTWS_EXTRA_POST_9"} + + code=$? + [ "$code" = 0 ] && { + strategy="$@" + strategy_append_extra_pktws + report_append "$dom" "$testf ipv${IPV}" "$PKTWSD ${WF:+$WF }$strategy" + } + return $code +} +strategy_append_extra_pktws() +{ + strategy="${strategy:+${PKTWS_EXTRA_PRE:+$PKTWS_EXTRA_PRE }${PKTWS_EXTRA_PRE_1:+"$PKTWS_EXTRA_PRE_1" }${PKTWS_EXTRA_PRE_2:+"$PKTWS_EXTRA_PRE_2" }${PKTWS_EXTRA_PRE_3:+"$PKTWS_EXTRA_PRE_3" }${PKTWS_EXTRA_PRE_4:+"$PKTWS_EXTRA_PRE_4" }${PKTWS_EXTRA_PRE_5:+"$PKTWS_EXTRA_PRE_5" }${PKTWS_EXTRA_PRE_6:+"$PKTWS_EXTRA_PRE_6" }${PKTWS_EXTRA_PRE_7:+"$PKTWS_EXTRA_PRE_7" }${PKTWS_EXTRA_PRE_8:+"$PKTWS_EXTRA_PRE_8" }${PKTWS_EXTRA_PRE_9:+"$PKTWS_EXTRA_PRE_9" }$strategy${PKTWS_EXTRA_POST:+ $PKTWS_EXTRA_POST}${PKTWS_EXTRA_POST_1:+ "$PKTWS_EXTRA_POST_1"}${PKTWS_EXTRA_POST_2:+ "$PKTWS_EXTRA_POST_2"}${PKTWS_EXTRA_POST_3:+ "$PKTWS_EXTRA_POST_3"}${PKTWS_EXTRA_POST_4:+ "$PKTWS_EXTRA_POST_4"}${PKTWS_EXTRA_POST_5:+ "$PKTWS_EXTRA_POST_5"}${PKTWS_EXTRA_POST_6:+ "$PKTWS_EXTRA_POST_6"}${PKTWS_EXTRA_POST_7:+ "$PKTWS_EXTRA_POST_7"}${PKTWS_EXTRA_POST_8:+ "$PKTWS_EXTRA_POST_8"}${PKTWS_EXTRA_POST_9:+ "$PKTWS_EXTRA_POST_9"}}" +} + + +xxxws_curl_test_update() +{ + # $1 - xxx_curl_test function + # $2 - test function + # $3 - domain + # $4,$5,$6, ... - nfqws2/dvtws2 params + local code xxxf=$1 testf=$2 dom="$3" + shift + shift + shift + $xxxf $testf "$dom" "$@" + code=$? + [ $code = 0 ] && strategy="${strategy:-$@}" + return $code +} +pktws_curl_test_update() +{ + xxxws_curl_test_update pktws_curl_test "$@" +} + +report_append() +{ + # $1 - domain + # $2 - test function + ipver + # $3 - value + local hashstr hash hashvar hashcountvar val ct + + # save resources if only one domain + [ "$DOMAINS_COUNT" -gt 1 ] && { + hashstr="$2 : $3" + hash="$(echo -n "$hashstr" | md5f)" + hashvar=RESHASH_${hash} + hashcountvar=${hashvar}_COUNTER + + NRESHASH=${NRESHASH:-0} + + eval val="\$$hashvar" + if [ -n "$val" ]; then + eval ct="\$$hashcountvar" + ct=$(($ct + 1)) + eval $hashcountvar="\$ct" + else + eval $hashvar=\"$hashstr\" + eval $hashcountvar=1 + eval RES_$NRESHASH="\$hash" + NRESHASH=$(($NRESHASH+1)) + fi + } + + NREPORT=${NREPORT:-0} + eval REPORT_${NREPORT}=\"$2 $1 : $3\" + NREPORT=$(($NREPORT+1)) +} +report_print() +{ + local n=0 s + NREPORT=${NREPORT:-0} + while [ $n -lt $NREPORT ]; do + eval s=\"\${REPORT_$n}\" + echo $s + n=$(($n+1)) + done +} +result_intersection_print() +{ + local n=0 hash hashvar hashcountvar ct val + while : ; do + eval hash=\"\$RES_$n\" + [ -n "$hash" ] || break + hashvar=RESHASH_${hash} + hashcountvar=${hashvar}_COUNTER + eval ct=\"\$$hashcountvar\" + [ "$ct" = "$DOMAINS_COUNT" ] && { + eval val=\"\$$hashvar\" + echo "$val" + } + n=$(($n + 1)) + done +} +result_coverage_print() +{ + # Lists every distinct successful strategy together with how many of the + # DOMAINS_COUNT domains/targets it worked for, most-covered first. + # Unlike result_intersection_print, a strategy doesn't need 100% coverage + # to be listed here - useful when DOMAINS is a set of largely independent + # targets (e.g. one IP per ASN/provider) where no single strategy is + # expected to satisfy every one of them, and the question is which + # strategy gets closest. + local n=0 hash hashvar hashcountvar ct val + while : ; do + eval hash=\"\$RES_$n\" + [ -n "$hash" ] || break + hashvar=RESHASH_${hash} + hashcountvar=${hashvar}_COUNTER + eval ct=\"\$$hashcountvar\" + eval val=\"\$$hashvar\" + printf '%s %s\n' "$ct" "$val" + n=$(($n + 1)) + done | sort -rn | while IFS=' ' read -r ct rest; do + echo "$ct/$DOMAINS_COUNT : $rest" + done +} +report_strategy() +{ + # $1 - test function + # $2 - domain + # $3 - daemon + echo + if [ -n "$strategy" ]; then + # trim spaces at the end + strategy="$(echo "$strategy" | xargs)" + echo "!!!!! $1: working strategy found for ipv${IPV} $2 : $3 $strategy !!!!!" + echo + return 0 + else + echo "$1: $3 strategy for ipv${IPV} $2 not found" + echo + report_append "$2" "$1 ipv${IPV}" "$3 not working" + return 1 + fi +} + +test_runner() +{ + # $1 - function name + # $2+ - params + + local n script FUNC=$1 + + shift + + TESTDIR="$BLOCKCHECK2D/$TEST" + [ -d "$TESTDIR" ] && { + dir_is_not_empty "$TESTDIR" && { + for script in "$TESTDIR/"*.sh; do + [ -f "$script" ] || continue + unset -f $FUNC + . "$script" + existf $FUNC && { + echo + echo "* script : $TEST/$(basename "$script")" + $FUNC "$@" + } + done + } + } +} + +pktws_check_domain_http_bypass() +{ + # $1 - test function + # $2 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk + # $3 - domain + + local strategy func + if [ "$2" = 0 ]; then + func=pktws_check_http + elif [ "$2" = 1 ]; then + func=pktws_check_https_tls12 + elif [ "$2" = 2 ]; then + func=pktws_check_https_tls13 + else + return 1 + fi + test_runner $func "$1" "$3" + strategy_append_extra_pktws + report_strategy $1 $3 $PKTWSD +} + +pktws_check_domain_http3_bypass() +{ + # $1 - test function + # $2 - domain + + local strategy + test_runner pktws_check_http3 "$@" + strategy_append_extra_pktws + report_strategy $1 $2 $PKTWSD +} + + +check_dpi_ip_block() +{ + # $1 - test function + # $2 - domain + + local blocked_dom=$2 + local blocked_ip blocked_ips unblocked_ip + + echo + echo "- IP block tests (requires manual interpretation)" + + echo "> testing $UNBLOCKED_DOM on it's original ip" + if curl_test $1 $UNBLOCKED_DOM; then + mdig_resolve $IPV unblocked_ip $UNBLOCKED_DOM + [ -n "$unblocked_ip" ] || { + echo $UNBLOCKED_DOM does not resolve. tests not possible. + return 1 + } + + echo "> testing $blocked_dom on $unblocked_ip ($UNBLOCKED_DOM)" + curl_test $1 $blocked_dom $unblocked_ip detail + + mdig_resolve_all $IPV blocked_ips $blocked_dom + for blocked_ip in $blocked_ips; do + echo "> testing $UNBLOCKED_DOM on $blocked_ip ($blocked_dom)" + curl_test $1 $UNBLOCKED_DOM $blocked_ip detail + done + else + echo $UNBLOCKED_DOM is not available. skipping this test. + fi +} + +curl_has_reason_to_continue() +{ + # $1 - curl return code + for c in 1 2 3 4 6 27 ; do + [ $1 = $c ] && return 1 + done + return 0 +} + +check_domain_prolog() +{ + # $1 - test function + # $2 - port + # $3 - domain + + local code + + [ "$SIMULATE" = 1 ] && return 0 + + echo + echo \* $1 ipv$IPV $3 + + echo "- checking without DPI bypass" + curl_test $1 $3 && { + report_append "$3" "$1 ipv${IPV}" "working without bypass" + [ "$SCANLEVEL" = force ] || return 1 + } + code=$? + curl_has_reason_to_continue $code || { + report_append "$3" "$1 ipv${IPV}" "test aborted, no reason to continue. curl code $(curl_translate_code $code)" + return 1 + } + return 0 +} +check_domain_http_tcp() +{ + # $1 - test function + # $2 - port + # $3 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk + # $4 - domain + + local ips + + # in case was interrupted before + ws_kill + + check_domain_prolog $1 $2 $4 || return + + [ "$SKIP_IPBLOCK" = 1 ] || check_dpi_ip_block $1 $4 + + [ "$SKIP_PKTWS" = 1 ] || { + echo + echo preparing $PKTWSD redirection + mdig_resolve_all $IPV ips $4 + pktws_ipt_prepare_tcp $2 "$ips" + + pktws_check_domain_http_bypass $1 $3 $4 + + echo clearing $PKTWSD redirection + pktws_ipt_unprepare_tcp $2 + } +} +check_domain_http_udp() +{ + # $1 - test function + # $2 - port + # $3 - domain + + local ips + + # in case was interrupted before + ws_kill + + check_domain_prolog $1 $2 $3 || return + + [ "$SKIP_PKTWS" = 1 ] || { + echo + echo preparing $PKTWSD redirection + mdig_resolve_all $IPV ips $3 + pktws_ipt_prepare_udp $2 "$ips" + + pktws_check_domain_http3_bypass $1 $3 + + echo clearing $PKTWSD redirection + pktws_ipt_unprepare_udp $2 + } +} + + +check_domain_http() +{ + # $1 - domain + check_domain_http_tcp curl_test_http $HTTP_PORT 0 $1 +} +check_domain_https_tls12() +{ + # $1 - domain + check_domain_http_tcp curl_test_https_tls12 $HTTPS_PORT 1 $1 +} +check_domain_https_tls13() +{ + # $1 - domain + check_domain_http_tcp curl_test_https_tls13 $HTTPS_PORT 2 $1 +} +check_domain_http3() +{ + # $1 - domain + check_domain_http_udp curl_test_http3 $QUIC_PORT $1 +} + +configure_ip_version() +{ + if [ "$IPV" = 6 ]; then + LOCALHOST=::1 + LOCALHOST_IPT=[${LOCALHOST}] + IPVV=6 + else + IPTABLES=iptables + LOCALHOST=127.0.0.1 + LOCALHOST_IPT=$LOCALHOST + IPVV= + fi + IPTABLES=ip${IPVV}tables +} +configure_curl_opt() +{ + # wolfssl : --tlsv1.x mandates exact ssl version, tls-max not supported + # openssl : --tlsv1.x means "version equal or greater", tls-max supported + TLSMAX12= + TLSMAX13= + curl_supports_tlsmax && { + TLSMAX12="--tls-max 1.2" + TLSMAX13="--tls-max 1.3" + } + TLS13= + curl_supports_tls13 && TLS13=1 + HTTP3= + curl_supports_http3 && HTTP3=1 + + HTTPS_HEAD=-I + [ "$CURL_HTTPS_GET" = 1 ] && HTTPS_HEAD= +} + +linux_ipv6_defrag_can_be_disabled() +{ + linux_min_version 4 16 +} + +configure_defrag() +{ + IP6_DEFRAG_DISABLE= + + [ "$IPVS" = 4 ] && return + + [ "$UNAME" = "Linux" ] && { + linux_ipv6_defrag_can_be_disabled || { + echo "WARNING ! ipv6 defrag can only be effectively disabled in linux kernel 4.16+" + echo "WARNING ! ipv6 ipfrag tests are disabled" + echo + return + } + } + + case "$FWTYPE" in + iptables) + if ipt6_has_raw ; then + if ipt6_has_frag; then + IP6_DEFRAG_DISABLE=1 + else + echo "WARNING ! ip6tables does not have '-m frag' module, ipv6 ipfrag tests are disabled" + echo + fi + else + echo "WARNING ! ip6tables raw table is not available, ipv6 ipfrag tests are disabled" + echo + fi + [ -n "$IP6_DEFRAG_DISABLE" ] && { + local ipexe="$(readlink -f $(whichq ip6tables))" + if contains "$ipexe" nft; then + echo "WARNING ! ipv6 ipfrag tests may have no effect if ip6tables-nft is used. current ip6tables point to : $ipexe" + else + echo "WARNING ! ipv6 ipfrag tests may have no effect if ip6table_raw kernel module is not loaded with parameter : raw_before_defrag=1" + fi + echo + } + ;; + *) + IP6_DEFRAG_DISABLE=1 + ;; + esac +} + +ask_params() +{ + local d dirs more_dirs= + + echo + echo NOTE ! this test should be run with zapret or any other bypass software disabled, without VPN + echo + + curl_supports_connect_to || { + echo "installed curl does not support --connect-to option. pls install at least curl 7.49" + echo "current curl version:" + "$CURL" --version + exitp 1 + } + + [ -n "$TEST" ] || { + dir_is_not_empty "$BLOCKCHECK2D" || { + echo "directory '$BLOCKCHECK2D' is absent or empty" + exitp 1 + } + TEST="$TEST_DEFAULT" + [ "$BATCH" = 1 ] || { + for d in "$BLOCKCHECK2D"/* ; do + more_dirs=${dirs:+1} + [ -d "$d" ] && dirs="${dirs:+$dirs }$(basename "$d")" + done + [ -n "$dirs" ] || { + echo "no subdirs found in '$BLOCKCHECK2D'" + exitp 1 + } + if [ -z "$more_dirs" ]; then + TEST="$dirs" + else + echo "select test :" + ask_list TEST "$dirs" "$TEST" + fi + } + } + [ -d "$BLOCKCHECK2D/$TEST" ] || { + echo "directory '$BLOCKCHECK2D/$TEST' does not exist" + exitp 1 + } + + local dom + [ -n "$DOMAINS" ] || { + DOMAINS="$DOMAINS_DEFAULT" + [ "$BATCH" = 1 ] || { + echo "specify domain(s) to test. multiple domains are space separated. URIs are supported (rutracker.org/forum/index.php)" + printf "domain(s) (default: $DOMAINS) : " + read dom + [ -n "$dom" ] && DOMAINS="$dom" + } + } + DOMAINS_COUNT="$(echo "$DOMAINS" | wc -w | trim)" + + local IPVS_def=4 + [ -n "$IPVS" ] || { + # yandex public dns + pingtest 6 2a02:6b8::feed:0ff && IPVS_def=46 + [ "$BATCH" = 1 ] || { + printf "ip protocol version(s) - 4, 6 or 46 for both (default: $IPVS_def) : " + read IPVS + } + [ -n "$IPVS" ] || IPVS=$IPVS_def + [ "$IPVS" = 4 -o "$IPVS" = 6 -o "$IPVS" = 46 ] || { + echo 'invalid ip version(s). should be 4, 6 or 46.' + exitp 1 + } + } + [ "$IPVS" = 46 ] && IPVS="4 6" + + configure_curl_opt + + [ -n "$ENABLE_HTTP" ] || { + ENABLE_HTTP=1 + [ "$BATCH" = 1 ] || { + echo + ask_yes_no_var ENABLE_HTTP "check http" + } + } + + [ -n "$ENABLE_HTTPS_TLS12" ] || { + ENABLE_HTTPS_TLS12=1 + [ "$BATCH" = 1 ] || { + echo + ask_yes_no_var ENABLE_HTTPS_TLS12 "check https tls 1.2" + } + } + + [ -n "$ENABLE_HTTPS_TLS13" ] || { + ENABLE_HTTPS_TLS13=0 + if [ -n "$TLS13" ]; then + [ "$BATCH" = 1 ] || { + echo + echo "TLS 1.3 uses encrypted ServerHello. DPI cannot check domain name in server response." + echo "This can allow more bypass strategies to work." + echo "What works for TLS 1.2 will also work for TLS 1.3 but not vice versa." + echo "Most sites nowadays support TLS 1.3 but not all. If you can't find a strategy for TLS 1.2 use this test." + echo "TLS 1.3 only strategy is better than nothing." + ask_yes_no_var ENABLE_HTTPS_TLS13 "check https tls 1.3" + } + fi + } + [ "$ENABLE_HTTPS_TLS13" = 1 -a -z "$TLS13" ] && { + echo + echo "WARNING ! installed curl version does not support TLS 1.3 . tests disabled." + ENABLE_HTTPS_TLS13=0 + } + + [ -n "$ENABLE_HTTP3" ] || { + ENABLE_HTTP3=0 + if [ -n "$HTTP3" ]; then + ENABLE_HTTP3=1 + [ "$BATCH" = 1 ] || { + echo + echo "make sure target domain(s) support QUIC or result will be negative in any case" + ask_yes_no_var ENABLE_HTTP3 "check http3 QUIC" + } + fi + } + [ "$ENABLE_HTTP3" = 1 -a -z "$HTTP3" ] && { + echo + echo "WARNING ! installed curl version does not support http3 QUIC. tests disabled." + ENABLE_HTTP3=0 + } + + [ -n "$REPEATS" ] || { + [ "$BATCH" = 1 ] || { + echo + echo "sometimes ISPs use multiple DPIs or load balancing. bypass strategies may work unstable." + printf "how many times to repeat each test (default: 1) : " + read REPEATS + } + REPEATS=$((0+${REPEATS:-1})) + [ "$REPEATS" = 0 ] && { + echo invalid repeat count + exitp 1 + } + } + [ -z "$PARALLEL" -a $REPEATS -gt 1 ] && { + PARALLEL=0 + [ "$BATCH" = 1 ] || { + echo + echo "parallel scan can greatly increase speed but may also trigger DDoS protection and cause false result" + ask_yes_no_var PARALLEL "enable parallel scan" + } + } + PARALLEL=${PARALLEL:-0} + + [ -n "$SCANLEVEL" ] || { + SCANLEVEL=standard + [ "$BATCH" = 1 ] || { + echo + echo quick - in multi-attempt mode skip further attempts after first failure + echo standard - do investigation what works on your DPI + echo force - scan maximum despite of result + ask_list SCANLEVEL "quick standard force" "$SCANLEVEL" + } + } + + echo + + configure_defrag +} + + + +ping_with_fix() +{ + local ret + $PING $2 $1 >/dev/null 2>/dev/null + ret=$? + # can be because of unsupported -4 option + if [ "$ret" = 2 -o "$ret" = 64 ]; then + ping $2 $1 >/dev/null + else + return $ret + fi +} + +pingtest() +{ + # $1 - ip version : 4 or 6 + # $2 - domain or ip + + # ping command can vary a lot. some implementations have -4/-6 options. others don.t + + local PING=ping ret + if [ "$1" = 6 ]; then + if exists ping6; then + PING=ping6 + else + PING="ping -6" + fi + else + if [ "$UNAME" = FreeBSD -o "$UNAME" = OpenBSD ]; then + # ping by default pings ipv4, ping6 only pings ipv6 + # in FreeBSD -4/-6 options are supported, in others not + PING=ping + else + # this can be linux or cygwin + # in linux it's not possible for sure to figure out if it supports -4/-6. only try and check for result code=2 (invalid option) + PING="ping -4" + fi + fi + case "$UNAME" in + OpenBSD) + $PING -c 1 -w 1 $2 >/dev/null + ;; + CYGWIN) + if starts_with "$(which ping)" /cygdrive; then + # cygwin does not have own ping by default. use windows PING. + $PING -n 1 -w 1000 $2 >/dev/null + else + ping_with_fix $2 '-c 1 -w 1' + fi + ;; + *) + ping_with_fix $2 '-c 1 -W 1' + ;; + esac +} +dnstest() +{ + # $1 - dns server. empty for system resolver + "$LOOKUP" iana.org $1 >/dev/null 2>/dev/null +} +find_working_public_dns() +{ + local dns + for dns in $DNSCHECK_DNS; do + pingtest 4 $dns && dnstest $dns && { + PUBDNS=$dns + return 0 + } + done + return 1 +} +lookup4() +{ + # $1 - domain + # $2 - DNS + case "$LOOKUP" in + nslookup) + if is_linked_to_busybox nslookup; then + nslookup $1 $2 2>/dev/null | sed -e '1,3d' -nre 's/^.*:[^0-9]*(([0-9]{1,3}\.){3}[0-9]{1,3}).*$/\1/p' + else + nslookup $1 $2 2>/dev/null | sed -e '1,3d' -nre 's/^[^0-9]*(([0-9]{1,3}\.){3}[0-9]{1,3}).*$/\1/p' + fi + ;; + host) + host -t A $1 $2 | grep "has address" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' + ;; + esac +} +check_dns_spoof() +{ + # $1 - domain + # $2 - public DNS + + # 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" +} +check_dns_cleanup() +{ + rm -f "$DNSCHECK_DIG1" "$DNSCHECK_DIG2" "$DNSCHECK_DIGS" 2>/dev/null +} +check_dns_() +{ + local C1 C2 dom + + DNS_IS_SPOOFED=0 + + [ "$SKIP_DNSCHECK" = 1 ] && return 0 + + echo \* checking DNS + + [ -f "$DNSCHECK_DIGS" ] && rm -f "$DNSCHECK_DIGS" + + dnstest || { + echo -- DNS is not working. It's either misconfigured or blocked or you don't have inet access. + return 1 + } + echo system DNS is working + + if find_working_public_dns ; then + echo comparing system resolver to public DNS : $PUBDNS + for dom in $DNSCHECK_DOM; do + if check_dns_spoof $dom $PUBDNS ; then + echo $dom : MISMATCH + echo -- system resolver : + cat "$DNSCHECK_DIG1" + echo -- $PUBDNS : + cat "$DNSCHECK_DIG2" + check_dns_cleanup + echo -- POSSIBLE DNS HIJACK DETECTED. ZAPRET WILL NOT HELP YOU IN CASE DNS IS SPOOFED !!! + echo -- DNS CHANGE OR DNSCRYPT MAY BE REQUIRED + DNS_IS_SPOOFED=1 + return 1 + else + echo $dom : OK + cat "$DNSCHECK_DIG1" >>"$DNSCHECK_DIGS" + fi + done + else + echo no working public DNS was found. looks like public DNS blocked. + for dom in $DNSCHECK_DOM; do echo $dom; done | "$MDIG" --threads=10 --family=4 >"$DNSCHECK_DIGS" + fi + + echo "checking resolved IP uniqueness for : $DNSCHECK_DOM" + echo "censor's DNS can return equal result for multiple blocked domains." + C1=$(wc -l <"$DNSCHECK_DIGS") + C2=$(sort -u "$DNSCHECK_DIGS" | wc -l) + [ "$C1" -eq 0 ] && + { + echo -- DNS is not working. It's either misconfigured or blocked or you don't have inet access. + check_dns_cleanup + return 1 + } + [ "$C1" = "$C2" ] || + { + echo system dns resolver has returned equal IPs for some domains checked above \($C1 total, $C2 unique\) + echo non-unique IPs : + sort "$DNSCHECK_DIGS" | uniq -d + echo -- POSSIBLE DNS HIJACK DETECTED. ZAPRET WILL NOT HELP YOU IN CASE DNS IS SPOOFED !!! + echo -- DNSCRYPT MAY BE REQUIRED + check_dns_cleanup + DNS_IS_SPOOFED=1 + return 1 + } + echo all resolved IPs are unique + echo -- DNS looks good + echo -- NOTE this check is Russia targeted. In your country other domains may be blocked. + check_dns_cleanup + return 0 +} + +check_dns() +{ + local r + check_dns_ + r=$? + [ "$DNS_IS_SPOOFED" = 1 ] && SECURE_DNS=${SECURE_DNS:-1} + [ "$SECURE_DNS" = 1 ] && { + doh_find_working || { + echo could not find working DoH server. exiting. + exitp 7 + } + } + return $r +} + +block_signals() +{ + # prevent signal function reenter + trap '' QUIT TERM HUP PIPE INT +} +untrap() +{ + trap - QUIT TERM HUP PIPE INT +} + +unprepare_all() +{ + # make sure we are not in a middle state that impacts connectivity + ws_kill + wait + [ -n "$IPV" ] && { + pktws_ipt_unprepare_tcp $HTTP_PORT + pktws_ipt_unprepare_tcp $HTTPS_PORT + pktws_ipt_unprepare_udp $QUIC_PORT + } + cleanup + rm -f "${HDRTEMP}"* "${PARALLEL_OUT}"* +} +sigint() +{ + block_signals + echo + echo terminating... + unprepare_all + # exitp can wait for the user input. restore default signal behavior without trap + untrap + exitp 1 +} +sigint_cleanup() +{ + block_signals + cleanup + exit 1 +} +sigsilent() +{ + block_signals + # must not write anything here to stdout + unprepare_all + exit 1 +} + +fsleep_setup +fix_sbin_path +check_system +check_already +[ "$UNAME" != CYGWIN -a "$SKIP_PKTWS" != 1 ] && require_root +check_prerequisites +trap sigint_cleanup INT +check_dns +check_virt +ask_params +apply_header_padfile +trap - INT + +PID= +NREPORT= +unset WF +trap sigint INT +trap sigsilent PIPE HUP TERM QUIT +for dom in $DOMAINS; do + for IPV in $IPVS; do + configure_ip_version + [ "$ENABLE_HTTP" = 1 ] && { + [ "$SKIP_IPBLOCK" = 1 ] || check_domain_port_block $dom $HTTP_PORT + check_domain_http $dom + } + [ "$ENABLE_HTTPS_TLS12" = 1 -o "$ENABLE_HTTPS_TLS13" = 1 ] && [ "$SKIP_IPBLOCK" != 1 ] && check_domain_port_block $dom $HTTPS_PORT + [ "$ENABLE_HTTPS_TLS12" = 1 ] && check_domain_https_tls12 $dom + [ "$ENABLE_HTTPS_TLS13" = 1 ] && check_domain_https_tls13 $dom + [ "$ENABLE_HTTP3" = 1 ] && check_domain_http3 $dom + done +done +untrap + +cleanup + +echo +echo \* SUMMARY +report_print +[ "$DOMAINS_COUNT" -gt 1 ] && { + echo + echo \* COMMON + result_intersection_print + echo + echo \* COVERAGE + result_coverage_print + echo + [ "$SCANLEVEL" = force ] || { + echo "blockcheck optimizes test sequence. To save time some strategies can be skipped if their test is considered useless." + echo "That's why COMMON intersection can miss strategies that would work for all domains, and COVERAGE counts can undercount." + echo "Use \"force\" scan level to test all strategies and generate trustable results." + echo "Current scan level was \"$SCANLEVEL\"". + } +} +echo +echo "Please note this SUMMARY does not guarantee a magic pill for you to copy/paste and be happy." +echo "Understanding how strategies work is very desirable." +echo "This knowledge allows to understand better which strategies to prefer and which to avoid if possible, how to combine strategies." +echo "Blockcheck does it's best to prioritize good strategies but it's not bullet-proof." +echo "It was designed not as magic pill maker but as a DPI bypass test tool." + +exitp 0 diff --git a/blockcheck/zapret2/blog.sh b/blockcheck/zapret2/blog.sh new file mode 100644 index 0000000..8889358 --- /dev/null +++ b/blockcheck/zapret2/blog.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +EXEDIR="$(dirname "$0")" +EXEDIR="$(cd "$EXEDIR"; pwd)" + +"$EXEDIR/blockcheck2.sh" 2>&1 | tee "$EXEDIR/../blockcheck2.log" +# windows 7 notepad does not view unix EOL correctly +unix2dos "$EXEDIR/../blockcheck2.log" diff --git a/blockcheck/zapret2/blog_kyber.sh b/blockcheck/zapret2/blog_kyber.sh new file mode 100644 index 0000000..a7bd700 --- /dev/null +++ b/blockcheck/zapret2/blog_kyber.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +EXEDIR="$(dirname "$0")" +EXEDIR="$(cd "$EXEDIR"; pwd)" + +CURL=curl-kyber exec "$EXEDIR/blog.sh" diff --git a/blockcheck/zapret2/common/base.sh b/blockcheck/zapret2/common/base.sh new file mode 100644 index 0000000..ef2db44 --- /dev/null +++ b/blockcheck/zapret2/common/base.sh @@ -0,0 +1,466 @@ +which() +{ + # on some systems 'which' command is considered deprecated and not installed by default + # 'command -v' replacement does not work exactly the same way. it outputs shell aliases if present + # $1 - executable name + local IFS=: + [ "$1" != "${1#/}" ] && [ -x "$1" ] && { + echo "$1" + return 0 + } + for p in $PATH; do + [ -x "$p/$1" ] && { + echo "$p/$1" + return 0 + } + done + return 1 +} +exists() +{ + which "$1" >/dev/null 2>/dev/null +} +existf() +{ + type "$1" >/dev/null 2>/dev/null +} +whichq() +{ + which $1 2>/dev/null +} +exist_all() +{ + while [ -n "$1" ]; do + exists "$1" || return 1 + shift + done + return 0 +} +on_off_function() +{ + # $1 : function name on + # $2 : function name off + # $3 : 0 - off, 1 - on + local F="$1" + [ "$3" = "1" ] || F="$2" + shift + shift + shift + "$F" "$@" +} +contains() +{ + # check if substring $2 contains in $1 + [ "${1#*$2}" != "$1" ] +} +starts_with() +{ + # $1 : what + # $2 : starts with + case "$1" in + "$2"*) + return 0 + ;; + esac + return 1 +} +extract_arg() +{ + # $1 - arg number + # $2,$3,... - args + local n=$1 + while [ -n "$1" ]; do + shift + [ $n -eq 1 ] && { echo "$1"; return 0; } + n=$(($n-1)) + done + return 1 +} +find_str_in_list() +{ + # $1 - string + # $2 - space separated values + local v + [ -n "$1" ] && { + for v in $2; do + [ "$v" = "$1" ] && return 0 + done + } + return 1 +} +end_with_newline() +{ + local c="$(tail -c 1)" + [ "$c" = "" ] +} +trim() +{ + awk '{gsub(/^[ \t]+|[ \t]+$/,"")}1' +} +split_by_separator() +{ + # $1 - string + # $2 - separator + # $3 - var name to get "before" part + # $4 - var name to get "after" part + local before="${1%%$2*}" + local after="${1#*$2}" + [ "$after" = "$1" ] && after= + [ -n "$3" ] && eval $3="\$before" + [ -n "$4" ] && eval $4="\$after" +} +tolower() +{ + echo "$@" | tr 'A-Z' 'a-z' +} + +dir_is_not_empty() +{ + # $1 - directory + local n + [ -d "$1" ] || return 1 + n=$(ls -A "$1" | wc -c | xargs) + [ "$n" != 0 ] +} + +append_separator_list() +{ + # $1 - var name to receive result + # $2 - separator + # $3 - quoter + # $4,$5,... - elements + local _var="$1" sep="$2" quo="$3" i + + eval i="\$$_var" + shift; shift; shift + while [ -n "$1" ]; do + if [ -n "$i" ] ; then + i="$i$sep$quo$1$quo" + else + i="$quo$1$quo" + fi + shift + done + eval $_var="\$i" +} +make_separator_list() +{ + eval $1='' + append_separator_list "$@" +} +make_comma_list() +{ + # $1 - var name to receive result + # $2,$3,... - elements + local var="$1" + shift + make_separator_list $var , '' "$@" +} +make_quoted_comma_list() +{ + # $1 - var name to receive result + # $2,$3,... - elements + local var="$1" + shift + make_separator_list $var , '"' "$@" +} +unique() +{ + local i + for i in "$@"; do echo $i; done | sort -u | xargs +} + +is_linked_to_busybox() +{ + local IFS F P BB + + BB="$(which busybox)" + + IFS=: + for path in $PATH; do + F="$path/$1" + if [ -L "$F" ]; then + P="$(readlink $F)" + if [ -z "$P" ] && [ -x $F ] && [ ! -L $F ]; then return 1; fi + [ "${P%busybox*}" != "$P" ] && return + elif [ -f "$F" -a -n "$BB" ]; then + # possible hardlink + [ $(get_dir_inode "$F") = $(get_dir_inode "$BB") ] && return + fi + done + return 1 +} +get_dir_inode() +{ + local dir="$1" + [ -L "$dir" ] && dir=$(readlink "$dir") + ls -id "$dir" | awk '{print $1}' +} + +linux_min_version() +{ + # $1 - major ver + # $2 - minor ver + local V1=$(sed -nre 's/^Linux version ([0-9]+)\.[0-9]+.*$/\1/p' /proc/version) + local V2=$(sed -nre 's/^Linux version [0-9]+\.([0-9]+).*$/\1/p' /proc/version) + [ -n "$V1" -a -n "$V2" ] && [ "$V1" -gt "$1" -o "$V1" -eq "$1" -a "$V2" -ge "$2" ] +} +linux_get_subsys() +{ + local INIT="$(sed 's/\x0/\n/g' /proc/1/cmdline | head -n 1)" + + [ -L "$INIT" ] && INIT=$(readlink "$INIT") + INIT="$(basename "$INIT")" + if [ -f "/etc/openwrt_release" ] && [ "$INIT" = "procd" ] ; then + SUBSYS=openwrt + elif [ -x "/bin/ndm" ] ; then + SUBSYS=keenetic + else + # generic linux + SUBSYS= + fi +} +openwrt_fw3() +{ + [ ! -x /sbin/fw4 -a -x /sbin/fw3 ] +} +openwrt_fw4() +{ + [ -x /sbin/fw4 ] +} +openwrt_fw3_integration() +{ + [ "$FWTYPE" = iptables ] && openwrt_fw3 +} + +create_dev_stdin() +{ + [ -e /dev/stdin ] || ln -s /proc/self/fd/0 /dev/stdin +} + +call_for_multiple_items() +{ + # $1 - function to get an item + # $2 - variable name to put result into + # $3 - space separated parameters to function $1 + + local i item items + for i in $3; do + $1 item $i + [ -n "$item" ] && { + if [ -n "$items" ]; then + items="$items $item" + else + items="$item" + fi + } + done + eval $2=\"$items\" +} + +fix_sbin_path() +{ + local IFS=':' + printf "%s\n" $PATH | grep -Fxq '/usr/sbin' || PATH="/usr/sbin:$PATH" + printf "%s\n" $PATH | grep -Fxq '/sbin' || PATH="/sbin:$PATH" + export PATH +} + +# it can calculate floating point expr +calc() +{ + LC_ALL=C awk "BEGIN { print $*}"; +} + +fsleep_setup() +{ + [ -n "$FSLEEP" ] || { + if sleep 0.001 2>/dev/null; then + FSLEEP=1 + elif busybox usleep 1 2>/dev/null; then + FSLEEP=2 + else + local errtext="$(read -t 0.001 2>&1)" + if [ -z "$errtext" ]; then + FSLEEP=3 + # newer openwrt has ucode with system function that supports timeout in ms + elif ucode -e "system(['sleep','1'], 1)" 2>/dev/null; then + FSLEEP=4 + # older openwrt may have lua and nixio lua module + elif lua -e 'require "nixio".nanosleep(0,1)' 2>/dev/null ; then + FSLEEP=5 + else + FSLEEP=0 + fi + fi + } +} +msleep() +{ + # $1 - milliseconds + case "$FSLEEP" in + 1) + sleep $(calc $1/1000) + ;; + 2) + busybox usleep $(calc $1*1000) + ;; + 3) + read -t $(calc $1/1000) + ;; + 4) + ucode -e "system(['sleep','2147483647'], $1)" + ;; + 5) + lua -e "require 'nixio'.nanosleep($(($1/1000)),$(calc $1%1000*1000000))" + ;; + *) + sleep $((($1+999)/1000)) + esac +} +minsleep() +{ + msleep 100 +} + +replace_char() +{ + local a="$1" + local b="$2" + shift; shift + echo "$@" | tr "$a" "$b" +} + +replace_str() +{ + local a=$(echo "$1" | sed 's/\//\\\//g') + local b=$(echo "$2" | sed 's/\//\\\//g') + shift; shift + echo "$@" | sed "s/$a/$b/g" +} + +setup_md5() +{ + [ -n "$MD5" ] && return + MD5=md5sum + exists $MD5 || MD5="md5 -q" +} + +md5f() +{ + setup_md5 + $MD5 | cut -d ' ' -f1 +} + +setup_random() +{ + [ -n "$RCUT" ] && return + RCUT="cut -c 1-17" + # some shells can operate with 32 bit signed int + [ $((0x100000000)) = 0 ] && RCUT="cut -c 1-9" +} + +random() +{ + # $1 - min, $2 - max + local r rs + setup_random + if [ -c /dev/urandom ]; then + rs=$(dd if=/dev/urandom count=1 bs=16 2>/dev/null | hexdump -e '1 "%02x"') + else + rs="$RANDOM$RANDOM$(date)" + fi + # shells use signed int64 + r=1$(echo $rs | md5f | sed 's/[^0-9]//g' | $RCUT) + echo $(( ($r % ($2-$1+1)) + $1 )) +} + +shell_name() +{ + [ -n "$SHELL_NAME" ] || { + [ -n "$UNAME" ] || UNAME="$(uname)" + + if [ "$UNAME" = "Linux" ]; then + SHELL_NAME="$(readlink /proc/$$/exe)" + SHELL_NAME="$(basename "$SHELL_NAME")" + else + SHELL_NAME=$(ps -p $$ -o comm=) + fi + + [ -n "$SHELL_NAME" ] || SHELL_NAME="$(basename "$SHELL")" + } +} + +process_exists() +{ + if exists pgrep; then + pgrep "^$1$" >/dev/null + elif exists pidof; then + pidof "$1" >/dev/null + else + return 1 + fi +} + +win_process_exists() +{ + tasklist /NH /FI "IMAGENAME eq ${1}.exe" | grep -q "^${1}.exe" +} + +alloc_num() +{ + # $1 - source var name + # $2 - target var name + # $3 - min + # $4 - max + + local v + eval v="\$$2" + # do not replace existing value + [ -n "$v" ] && return + eval v="\$$1" + [ -n "$v" ] || v=$3 + eval $2="$v" + v=$((v + 1)) + [ $v -gt $4 ] && v=$3 + eval $1="$v" +} + +has_bad_ws_options() +{ + # $1 - nfqws2 opts + + contains "$1" "--ipset" && { + echo + echo "WARNING !!! --ipset parameter is present" + echo "It's OK if you only specialize already redirected traffic and also process the rest." + echo "If you redirect port X to process several IPs from the list and do nothing with the rest - IT'S VERY INEFFECTIVE !" + echo "Kernel ipsets should be used instead. Write custom scripts and filter IPs in kernel." + echo + } + contains "$1" "--ipset=$ZAPRET_BASE" || contains "$1" "--ipset-exclude=$ZAPRET_BASE" || + contains "$1" "--hostlist=$ZAPRET_BASE" || contains "$1" "--hostlist-exclude=$ZAPRET_BASE" && { + echo + echo "WARNING !!! you store ipset or hostlist files inside '$ZAPRET_BASE'" + echo "It's not recommended. install_easy.sh will delete them during update." + echo + } + + return 1 +} +check_bad_ws_options() +{ + # $1 - 0 = stop, 1 = start + # $2 - nfqws options + if [ "$1" = 1 ] && has_bad_ws_options "$2"; then + echo "!!! REFUSING TO USE BAD OPTIONS : $2" + help_bad_ws_options + return 1 + else + return 0 + fi +} +help_bad_ws_options() +{ + echo "WARNING ! BAD options detected" +} diff --git a/blockcheck/zapret2/common/dialog.sh b/blockcheck/zapret2/common/dialog.sh new file mode 100644 index 0000000..ec1c9aa --- /dev/null +++ b/blockcheck/zapret2/common/dialog.sh @@ -0,0 +1,57 @@ +read_yes_no() +{ + # $1 - default (Y/N) + local A + read A + [ -z "$A" ] || ([ "$A" != "Y" ] && [ "$A" != "y" ] && [ "$A" != "N" ] && [ "$A" != "n" ]) && A=$1 + [ "$A" = "Y" ] || [ "$A" = "y" ] || [ "$A" = "1" ] +} +ask_yes_no() +{ + # $1 - default (Y/N or 0/1) + # $2 - text + local DEFAULT=$1 + [ "$1" = "1" ] && DEFAULT=Y + [ "$1" = "0" ] && DEFAULT=N + [ -z "$DEFAULT" ] && DEFAULT=N + printf "$2 (default : $DEFAULT) (Y/N) ? " + read_yes_no $DEFAULT +} +ask_yes_no_var() +{ + # $1 - variable name for answer : 0/1 + # $2 - text + local DEFAULT + eval DEFAULT="\$$1" + if ask_yes_no "$DEFAULT" "$2"; then + eval $1=1 + else + eval $1=0 + fi +} +ask_list() +{ + # $1 - mode var + # $2 - space separated value list + # $3 - (optional) default value + local M_DEFAULT + eval M_DEFAULT="\$$1" + local M_DEFAULT_VAR="$M_DEFAULT" + local M="" m + + [ -n "$3" ] && { find_str_in_list "$M_DEFAULT" "$2" || M_DEFAULT="$3" ;} + + n=1 + for m in $2; do + echo $n : $m + n=$(($n+1)) + done + printf "your choice (default : $M_DEFAULT) : " + read m + [ -n "$m" ] && M=$(echo $2 | cut -d ' ' -f$m 2>/dev/null) + [ -z "$M" ] && M="$M_DEFAULT" + echo selected : $M + eval $1="\"$M\"" + + [ "$M" != "$M_DEFAULT_VAR" ] +} diff --git a/blockcheck/zapret2/common/elevate.sh b/blockcheck/zapret2/common/elevate.sh new file mode 100644 index 0000000..bc86a96 --- /dev/null +++ b/blockcheck/zapret2/common/elevate.sh @@ -0,0 +1,28 @@ +require_root() +{ + local exe preserve_env + echo \* checking privileges + [ $(id -u) -ne "0" ] && { + echo root is required + exe="$EXEDIR/$(basename "$0")" + exists sudo && { + echo elevating with sudo + exec sudo -E sh "$exe" + } + exists su && { + echo elevating with su + case "$UNAME" in + Linux) + preserve_env="--preserve-environment" + ;; + FreeBSD|OpenBSD|Darwin) + preserve_env="-m" + ;; + esac + exec su $preserve_env root -c "sh \"$exe\"" + } + echo su or sudo not found + exitp 2 + } + HAVE_ROOT=1 +} diff --git a/blockcheck/zapret2/common/fwtype.sh b/blockcheck/zapret2/common/fwtype.sh new file mode 100644 index 0000000..61390bb --- /dev/null +++ b/blockcheck/zapret2/common/fwtype.sh @@ -0,0 +1,64 @@ +linux_ipt_avail() +{ + exists iptables && exists ip6tables +} +linux_maybe_iptables_fwtype() +{ + linux_ipt_avail && FWTYPE=iptables +} +linux_nft_avail() +{ + exists nft +} +linux_fwtype() +{ + [ -n "$FWTYPE" ] && return + + FWTYPE=unsupported + + linux_get_subsys + if [ "$SUBSYS" = openwrt ] ; then + # linux kernel is new enough if fw4 is there + if [ -x /sbin/fw4 ] && linux_nft_avail ; then + FWTYPE=nftables + else + linux_maybe_iptables_fwtype + fi + else + SUBSYS= + # generic linux + # flowtable is implemented since kernel 4.16 + if linux_nft_avail && linux_min_version 4 16; then + FWTYPE=nftables + else + linux_maybe_iptables_fwtype + fi + fi + + export FWTYPE +} + +get_fwtype() +{ + [ -n "$FWTYPE" ] && return + + local UNAME="$(uname)" + + case "$UNAME" in + Linux) + linux_fwtype + ;; + FreeBSD) + if exists ipfw ; then + FWTYPE=ipfw + else + FWTYPE=unsupported + fi + ;; + *) + FWTYPE=unsupported + ;; + esac + + export FWTYPE +} diff --git a/blockcheck/zapret2/common/virt.sh b/blockcheck/zapret2/common/virt.sh new file mode 100644 index 0000000..6e566d6 --- /dev/null +++ b/blockcheck/zapret2/common/virt.sh @@ -0,0 +1,39 @@ +get_virt() +{ + local vm s v UNAME + UNAME=$(uname) + case "$UNAME" in + Linux) + if exists systemd-detect-virt; then + vm=$(systemd-detect-virt --vm) + elif [ -f /sys/class/dmi/id/product_name ]; then + read s NTXGqalwVC`SOKYqMk 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 VVDxf#*X8o%xyu-A=eXw{_!ecs5SIV| literal 0 HcmV?d00001 diff --git a/blockcheck/zapret2/lua/zapret-antidpi.lua b/blockcheck/zapret2/lua/zapret-antidpi.lua new file mode 100644 index 0000000..80f372a --- /dev/null +++ b/blockcheck/zapret2/lua/zapret-antidpi.lua @@ -0,0 +1,1250 @@ +--[[ + +NFQWS2 ANTIDPI LIBRARY + +--lua-init=@zapret-lib.lua --lua-init=@zapret-antidpi.lua +--lua-desync=func1:arg1[=val1]:arg2[=val2] --lua-desync=func2:arg1[=val1]:arg2[=val2] .... --lua-desync=funcN:arg1[=val1]:arg2[=val2] + +BLOBS + +blobs can be 0xHEX, field name in desync or global var +standard way to bring binary data to lua code is using the "--blob" parameter of nfqws2 +dynamic blobs can be inside desync table. one function can prepare data for next functions. + +STANDARD FUNCTION ARGS + +standard direction : + +* dir = in|out|any + +standard fooling : + +* ip_ttl=N - set ipv.ip_ttl to N +* ip6_ttl=N - set ip6.ip6_hlim to N +* ip_autottl=delta,min-max - set ip.ip_ttl to auto discovered ttl +* ip6_autottl=delta,min-max - set ip.ip_ttl to auto discovered ttl + +* ip6_hopbyhop[=hex] - add hopbyhop ipv6 header with optional data. data size must be 6+N*8. all zero by default. +* ip6_hopbyhop2[=hex] - add second hopbyhop ipv6 header with optional data. data size must be 6+N*8. all zero by default. +* ip6_destopt[=hex] - add destopt ipv6 header with optional data. data size must be 6+N*8. all zero by default. +* ip6_destopt2[=hex] - add second destopt ipv6 header with optional data. data size must be 6+N*8. all zero by default. +* ip6_routing[=hex] - add routing ipv6 header with optional data. data size must be 6+N*8. all zero by default. +* ip6_ah[=hex] - add authentication ipv6 header with optional data. data size must be 6+N*4. 0000 + 4 random bytes by default. + +* tcp_seq=N - add N to tcp.th_seq +* tcp_ack=N - add N to tcp.th_ack +* tcp_ts=N - add N to timestamp value +* tcp_md5[=hex] - add MD5 header with optional 16-byte data. all zero by default. +* tcp_flags_set= - set tcp flags in comma separated list +* tcp_flags_unset= - unset tcp flags in comma separated list +* tcp_ts_up - move timestamp tcp option to the top if present (workaround for badack without badseq fooling) +* tcp_nop_del - delete NOP tcp options to free space in tcp header + +* fool=fool_function - custom fooling function : fool_func(dis, fooling_options) + +standard reconstruct : + +* badsum - make L4 checksum invalid + +standard rawsend : + +* repeats - how many time send the packet +* ifout - override outbound interface (if --bind_fix4, --bind-fix6 enabled) +* fwmark - override fwmark. desync mark bit(s) will be set unconditionally + +standard payload : + +* payload - comma separated list of allowed payload types. if not present - allow non-empty known payloads. + +standard ip_id : + +* ip_id - seq|rnd|zero|none +* ip_id_conn - in 'seq' mode save current ip_id in track.lua_state to use it between packets + +standard ipfrag : + +* ipfrag[=frag_function] - ipfrag function name. "ipfrag2" by default if empty +* ipfrag_disorder - send fragments from last to first +* ipfrag2 : ipfrag_pos_tcp - tcp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 32 +* ipfrag2 : ipfrag_pos_udp - udp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 8 +* ipfrag2 : ipfrag_pos_icmp - icmp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 8 +* ipfrag2 : ipfrag_pos - frag position for other L4. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 32 +* ipfrag2 : ipfrag_next - next protocol field in ipv6 fragment extenstion header of the second fragment. same as first by default. + +]] + + +-- drop packet +-- standard args : direction, payload +function drop(ctx, desync) + direction_cutoff_opposite(ctx, desync, "any") + if direction_check(desync, "any") and payload_check(desync,"all") then + DLOG("drop") + return VERDICT_DROP + end +end + +-- nfqws1 : "--dup" +-- standard args : direction, fooling, ip_id, ipfrag, rawsend, reconstruct +-- arg : delay= - drop and send delayed +function send(ctx, desync) + direction_cutoff_opposite(ctx, desync, "any") + if direction_check(desync, "any") then + DLOG("send") + local dis = deepcopy(desync.dis) + apply_fooling(desync, dis) + apply_ip_id(desync, dis, nil, "none") + if desync.arg.delay then + local tname = desync_timer_name(desync) + timer_set(tname, "send_timer_delayed", tonumber(desync.arg.delay), true, {dis = dis, opts = desync_opts(desync)}) + else + -- it uses rawsend, reconstruct and ipfrag options + rawsend_dissect_ipfrag(dis, desync_opts(desync)) + end + end +end +function send_timer_delayed(name, data) + -- oneshot timer, auto deletes + rawsend_dissect_ipfrag(data.dis, data.opts) +end + +-- nfqws1 : "--orig" +-- apply modification to current packet +-- standard args : direction, fooling, ip_id +function pktmod(ctx, desync) + direction_cutoff_opposite(ctx, desync, "any") + if direction_check(desync, "any") then + -- apply to current packet + apply_fooling(desync) + apply_ip_id(desync, nil, nil, "none") + DLOG("pktmod: applied") + return VERDICT_MODIFY + end +end + +-- nfqws1 : "--domcase" +-- standard args : direction +function http_domcase(ctx, desync) + if not desync.dis.tcp then + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + return + end + direction_cutoff_opposite(ctx, desync) + if desync.l7payload=="http_req" and direction_check(desync) then + local host_range = resolve_multi_pos(desync.dis.payload,desync.l7payload,"host,endhost") + if #host_range == 2 then + local host = string.sub(desync.dis.payload,host_range[1],host_range[2]-1) + local newhost="" + for i = 1, #host do + newhost=newhost..((i%2)==0 and string.lower(string.sub(host,i,i)) or string.upper(string.sub(host,i,i))) + end + DLOG("http_domcase: "..host.." => "..newhost) + desync.dis.payload = string.sub(desync.dis.payload, 1, host_range[1]-1)..newhost..string.sub(desync.dis.payload, host_range[2]) + return VERDICT_MODIFY + else + DLOG("http_domcase: cannot find host range") + end + end +end + +-- nfqws1 : "--hostcase" +-- standard args : direction +-- arg : spell= . spelling of the "Host" header. must be exactly 4 chars long +function http_hostcase(ctx, desync) + if not desync.dis.tcp then + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + return + end + direction_cutoff_opposite(ctx, desync) + if desync.l7payload=="http_req" and direction_check(desync) then + local spell = desync.arg.spell or "host" + if #spell ~= 4 then + error("http_hostcase: invalid host spelling '"..spell.."'") + else + local hdis = http_dissect_req(desync.dis.payload) + if hdis then + local idx_host = array_field_search(hdis.headers, "header_low", "host") + if idx_host then + DLOG("http_hostcase: 'Host:' => '"..spell.."'") + desync.dis.payload = string.sub(desync.dis.payload,1,hdis.headers[idx_host].pos_start-1)..spell..string.sub(desync.dis.payload,hdis.headers[idx_host].pos_header_end+1) + return VERDICT_MODIFY + else + DLOG("http_hostcase: 'Host:' header not found") + end + else + DLOG("http_hostcase: http dissect error") + end + end + end +end + +-- nfqws1 : "--methodeol" +-- standard args : direction +-- NOTE : if using with other http tampering methodeol should be the last ! +function http_methodeol(ctx, desync) + if not desync.dis.tcp then + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + return + end + direction_cutoff_opposite(ctx, desync) + if desync.l7payload=="http_req" and direction_check(desync) then + local hdis = http_dissect_req(desync.dis.payload) + if hdis then + local idx_ua = array_field_search(hdis.headers, "header_low", "user-agent") + if idx_ua then + local ua = hdis.headers[idx_ua] + if (ua.pos_end - ua.pos_value_start) < 2 then + DLOG("http_methodeol: 'User-Agent:' header is too short") + else + DLOG("http_methodeol: applied") + desync.dis.payload="\r\n"..string.sub(desync.dis.payload,1,ua.pos_end-2)..(string.sub(desync.dis.payload,ua.pos_end+1) or ""); + return VERDICT_MODIFY + end + else + DLOG("http_methodeol: 'User-Agent:' header not found") + end + else + DLOG("http_methodeol: http dissect error") + end + end +end + +-- nfqws1 : not available +-- tpws : --unixeol +-- standard args : direction +function http_unixeol(ctx, desync) + if not desync.dis.tcp then + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + return + end + direction_cutoff_opposite(ctx, desync) + if desync.l7payload=="http_req" and direction_check(desync) then + local hdis = http_dissect_req(desync.dis.payload) + if hdis then + local idx_ua = array_field_search(hdis.headers, "header_low", "user-agent") + if idx_ua then + local http = http_reconstruct_req(hdis, true) + if #http < #desync.dis.payload then + hdis.headers[idx_ua].value = hdis.headers[idx_ua].value .. string.rep(" ", #desync.dis.payload - #http) + end + http = http_reconstruct_req(hdis, true) + if #http==#desync.dis.payload then + desync.dis.payload = http + DLOG("http_unixeol: applied") + return VERDICT_MODIFY + else + DLOG("http_unixeol: reconstruct differs in size from original: "..#http.."!="..#desync.dis.payload) + end + else + DLOG("http_unixeol: 'User-Agent:' header absent") + end + else + DLOG("http_unixeol: could not dissect http") + end + end +end + +-- nfqws1 : "--synack-split" +-- standard args : rawsend, reconstruct, ipfrag +-- arg : mode=syn|synack|acksyn . "synack" by default +function synack_split(ctx, desync) + if desync.dis.tcp then + if bitand(desync.dis.tcp.th_flags, TH_SYN + TH_ACK) == (TH_SYN + TH_ACK) then + local mode = desync.arg.mode or "synack" + local options = desync_opts(desync) + if mode=="syn" then + local dis = deepcopy(desync.dis) + dis.tcp.th_flags = bitand(desync.dis.tcp.th_flags, bitnot(TH_ACK)) + DLOG("synack_split: sending SYN") + if not rawsend_dissect_ipfrag(dis, options) then return VERDICT_PASS end + return VERDICT_DROP + elseif mode=="synack" then + local dis = deepcopy(desync.dis) + dis.tcp.th_flags = bitand(desync.dis.tcp.th_flags, bitnot(TH_ACK)) + DLOG("synack_split: sending SYN") + if not rawsend_dissect_ipfrag(dis, options) then return VERDICT_PASS end + dis.tcp.th_flags = bitand(desync.dis.tcp.th_flags, bitnot(TH_SYN)) + DLOG("synack_split: sending ACK") + if not rawsend_dissect_ipfrag(dis, options) then return VERDICT_PASS end + return VERDICT_DROP + elseif mode=="acksyn" then + local dis = deepcopy(desync.dis) + dis.tcp.th_flags = bitand(desync.dis.tcp.th_flags, bitnot(TH_SYN)) + DLOG("synack_split: sending ACK") + if not rawsend_dissect_ipfrag(dis, options) then return VERDICT_PASS end + dis.tcp.th_flags = bitand(desync.dis.tcp.th_flags, bitnot(TH_ACK)) + DLOG("synack_split: sending SYN") + if not rawsend_dissect_ipfrag(dis, options) then return VERDICT_PASS end + return VERDICT_DROP + else + error("synack_split: bad mode '"..mode.."'") + end + else + instance_cutoff_shim(ctx, desync) -- mission complete + end + else + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + end +end + +-- nfqws1 : "--dpi-desync=synack" +-- standard args : rawsend, reconstruct, ipfrag +function synack(ctx, desync) + if desync.dis.tcp then + if bitand(desync.dis.tcp.th_flags, TH_SYN + TH_ACK)==TH_SYN then + local dis = deepcopy(desync.dis) + dis.tcp.th_flags = bitor(dis.tcp.th_flags, TH_ACK) + DLOG("synack: sending") + rawsend_dissect_ipfrag(dis, desync_opts(desync)) + else + instance_cutoff_shim(ctx, desync) -- mission complete + end + else + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + end +end + + +-- nfqws1 : "--wsize" +-- arg : wsize=N . tcp window size +-- arg : scale=N . tcp option scale factor +function wsize(ctx, desync) + if desync.dis.tcp then + if bitand(desync.dis.tcp.th_flags, TH_SYN + TH_ACK) == (TH_SYN + TH_ACK) then + if wsize_rewrite(desync.dis, desync.arg) then + return VERDICT_MODIFY + end + else + instance_cutoff_shim(ctx, desync) -- mission complete + end + else + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + end +end + +-- nfqws1 : "--wssize" +-- standard args : direction +-- arg : wsize=N . tcp window size +-- arg : scale=N . tcp option scale factor +-- arg : forced_cutoff= - comma separated list of payloads that trigger forced wssize cutoff. by default - any non-empty payload +function wssize(ctx, desync) + if not desync.dis.tcp then + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + return + end + local verdict = VERDICT_PASS + direction_cutoff_opposite(ctx, desync) + if direction_check(desync) then + if wsize_rewrite(desync.dis, desync.arg) then + verdict = VERDICT_MODIFY + end + if #desync.dis.payload>0 and (not desync.arg.forced_cutoff or in_list(desync.arg.forced_cutoff, desync.l7payload)) then + DLOG("wssize: forced cutoff") + instance_cutoff_shim(ctx, desync) + end + end + return verdict +end + +-- nfqws1 : not available +-- standard args : direction +-- arg: blob - blob name to store cloned tls client hello (stored in desync, not global) +-- arg: fallback - copy this blob if could not clone +-- arg: sni_snt - server name type value in existing names +-- arg: sni_snt_new - server name type value for new names +-- arg: sni_del_ext - delete sni extension +-- arg: sni_del - delete all names +-- arg: sni_first - add name to the beginning +-- arg: sni_last - add name to the end +function tls_client_hello_clone(ctx, desync) + if not desync.dis.tcp then + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + return + end + direction_cutoff_opposite(ctx, desync) + if direction_check(desync) then + if not desync.arg.blob then + error("tls_client_hello_clone: 'blob' arg required") + end + if desync.l7payload=="tls_client_hello" then + desync[desync.arg.blob] = tls_client_hello_mod(desync.reasm_data or desync.dis.payload, desync.arg) + if desync[desync.arg.blob] then + DLOG("tls_client_hello_clone: cloned to desync."..desync.arg.blob) + end + end + if not desync[desync.arg.blob] and desync.arg.fallback then + DLOG("tls_client_hello_clone: desync."..desync.arg.blob.."="..desync.arg.fallback) + desync[desync.arg.blob] = blob(desync, desync.arg.fallback) + end + end +end + +-- nfqws1 : "--dpi-desync=syndata" +-- standard args : fooling, rawsend, reconstruct, ipfrag +-- arg : blob= - fake payload. must fit to single packet. no segmentation possible. default - 16 zero bytes. +-- arg : tls_mod= - comma separated list of tls mods : rnd,rndsni,sni=. sni=%var is supported +function syndata(ctx, desync) + if desync.dis.tcp then + if bitand(desync.dis.tcp.th_flags, TH_SYN + TH_ACK)==TH_SYN then + local dis = deepcopy(desync.dis) + dis.payload = blob(desync, desync.arg.blob, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + apply_fooling(desync, dis) + if desync.arg.tls_mod then + local pl = tls_mod_shim(desync, dis.payload, desync.arg.tls_mod, nil) + if pl then dis.payload = pl end + end + if b_debug then DLOG("syndata: "..hexdump_dlog(dis.payload)) end + if rawsend_dissect_ipfrag(dis, desync_opts(desync)) then + return VERDICT_DROP + end + else + instance_cutoff_shim(ctx, desync) -- mission complete + end + else + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + end +end + +-- nfqws1 : "--dpi-desync=rst" +-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct, ipfrag +-- arg : rstack - send RST,ACK instead of RST +function rst(ctx, desync) + if not desync.dis.tcp then + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + return + end + direction_cutoff_opposite(ctx, desync) + if direction_check(desync, "any") and payload_check(desync) then + if replay_first(desync) then + local dis = deepcopy(desync.dis) + dis.payload = "" + dis.tcp.th_flags = TH_RST + (desync.arg.rstack and TH_ACK or 0) + apply_fooling(desync, dis) + apply_ip_id(desync, dis, nil, "none") + DLOG("rst") + -- it uses rawsend, reconstruct and ipfrag options + rawsend_dissect_ipfrag(dis, desync_opts(desync)) + else + DLOG("rst: not acting on further replay pieces") + end + end +end + +-- nfqws1 : "--dpi-desync=fake" +-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct, ipfrag +-- arg : blob= - fake payload +-- arg : optional - skip if blob is absent +-- arg : tls_mod= - comma separated list of tls mods : rnd,rndsni,sni=,dupsid,padencap . sni=%var is supported +function fake(ctx, desync) + direction_cutoff_opposite(ctx, desync) + -- by default process only outgoing known payloads. works only for tcp and udp + if (desync.dis.tcp or desync.dis.udp) and direction_check(desync) and payload_check(desync) then + if replay_first(desync) then + if not desync.arg.blob then + error("fake: 'blob' arg required") + end + if desync.arg.optional and not blob_exist(desync, desync.arg.blob) then + DLOG("fake: blob '"..desync.arg.blob.."' not found. skipped") + return + end + local fake_payload = blob(desync, desync.arg.blob) + if desync.reasm_data and desync.arg.tls_mod then + local pl = tls_mod_shim(desync, fake_payload, desync.arg.tls_mod, desync.reasm_data) + if pl then fake_payload = pl end + end + -- check debug to save CPU + if b_debug then DLOG("fake: "..hexdump_dlog(fake_payload)) end + rawsend_payload_segmented(desync,fake_payload) + else + DLOG("fake: not acting on further replay pieces") + end + end +end + +-- nfqws1 : "--dpi-desync=multisplit" +-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct, ipfrag +-- arg : pos= . position marker list. for example : "1,host,midsld+1,-10" +-- arg : seqovl=N . decrease seq number of the first segment by N and fill N bytes with pattern (default - all zero) +-- arg : seqovl_pattern= . override pattern +-- arg : blob= - use this data instead of desync.dis.payload +-- arg : optional - skip if blob is absent. use zero pattern if seqovl_pattern blob is absent +-- arg : nodrop - do not drop current dissect +function multisplit(ctx, desync) + if not desync.dis.tcp then + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + return + end + direction_cutoff_opposite(ctx, desync) + if desync.arg.optional and desync.arg.blob and not blob_exist(desync, desync.arg.blob) then + DLOG("multisplit: blob '"..desync.arg.blob.."' not found. skipped") + return + end + local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload + if #data>0 and direction_check(desync) and payload_check(desync) then + if replay_first(desync) then + local spos = desync.arg.pos or "2" + -- check debug to save CPU + if b_debug then DLOG("multisplit: split pos: "..spos) end + local pos = resolve_multi_pos(data, desync.l7payload, spos) + if b_debug then DLOG("multisplit: resolved split pos: "..table.concat(zero_based_pos(pos)," ")) end + delete_pos_1(pos) -- cannot split at the first byte + if #pos>0 then + for i=0,#pos do + local pos_start = pos[i] or 1 + local pos_end = i<#pos and pos[i+1]-1 or #data + local part = string.sub(data,pos_start,pos_end) + local seqovl=0 + if i==0 and desync.arg.seqovl and tonumber(desync.arg.seqovl)>0 then + seqovl = tonumber(desync.arg.seqovl) + local pat="\x00" + if desync.arg.seqovl_pattern then + if desync.arg.optional and not blob_exist(desync, desync.arg.seqovl_pattern) then + DLOG("multisplit: blob '"..desync.arg.seqovl_pattern.."' not found. using zero pattern") + else + pat = blob(desync,desync.arg.seqovl_pattern) + end + end + part = pattern(pat,1,seqovl)..part + end + if b_debug then DLOG("multisplit: sending part "..(i+1).." "..(pos_start-1).."-"..(pos_end-1).." len="..#part.." seqovl="..seqovl.." : "..hexdump_dlog(part)) end + if not rawsend_payload_segmented(desync,part,pos_start-1-seqovl) then + return VERDICT_PASS + end + end + replay_drop_set(desync) + return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP + else + DLOG("multisplit: no valid split positions") + end + else + DLOG("multisplit: not acting on further replay pieces") + end + -- drop replayed packets if reasm was sent successfully in splitted form + if replay_drop(desync) then + return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP + end + end +end + + +function pos_normalize(pos, low, hi) + return (pos>=low and pos0 then + if seqovl>=pos[1] then + DLOG("multidisorder: seqovl cancelled because seqovl "..(seqovl-1).." is not less than the first split pos "..(pos[1]-1)) + else + ovl = seqovl - 1 + local pat="\x00" + if desync.arg.seqovl_pattern then + if desync.arg.optional and not blob_exist(desync, desync.arg.seqovl_pattern) then + DLOG("multidisorder: blob '"..desync.arg.seqovl_pattern.."' not found. using zero pattern") + else + pat = blob(desync,desync.arg.seqovl_pattern) + end + end + part = pattern(pat,1,ovl)..part + end + end + if b_debug then DLOG("multidisorder: sending part "..(i+1).." "..(pos_start-1).."-"..(pos_end-1).." len="..#part.." seqovl="..ovl.." : "..hexdump_dlog(part)) end + if not rawsend_payload_segmented(desync,part,pos_start-1-ovl) then + return VERDICT_PASS + end + end + return VERDICT_DROP +end + +-- nfqws1 : "--dpi-desync=multidisorder" +-- algorithm is not 100% the same as in nfqws1. multi-segment queries can produce different segment ordering. +-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct, ipfrag +-- arg : pos= . position marker list. example : "1,host,midsld+1,-10" +-- arg : seqovl=N . decrease seq number of the second segment in the original order by N and fill N bytes with pattern (default - all zero). N must be less than the first split pos. +-- arg : seqovl_pattern= . override pattern +-- arg : blob= - use this data instead of reasm_data +-- arg : optional - skip if blob is absent. use zero pattern if seqovl_pattern blob is absent +-- arg : nodrop - do not drop current dissect +function multidisorder(ctx, desync) + if not desync.dis.tcp then + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + return + end + direction_cutoff_opposite(ctx, desync) + if desync.arg.optional and desync.arg.blob and not blob_exist(desync, desync.arg.blob) then + DLOG("multidisorder: blob '"..desync.arg.blob.."' not found. skipped") + return + end + local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload + if #data>0 and direction_check(desync) and payload_check(desync) then + if replay_first(desync) then + local spos = desync.arg.pos or "2" + -- check debug to save CPU + if b_debug then DLOG("multidisorder: split pos: "..spos) end + local pos = resolve_multi_pos(data, desync.l7payload, spos) + if b_debug then DLOG("multidisorder: resolved split pos: "..table.concat(zero_based_pos(pos)," ")) end + delete_pos_1(pos) -- cannot split at the first byte + if #pos>0 then + local seqovl + if desync.arg.seqovl then + seqovl = resolve_pos(data, desync.l7payload, desync.arg.seqovl) + if not seqovl then + DLOG("multidisorder: seqovl cancelled because could not resolve marker '"..desync.arg.seqovl.."'") + end + end + if multidisorder_send(desync, data, seqovl, pos)==VERDICT_PASS then + return VERDICT_PASS + end + replay_drop_set(desync) + return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP + else + DLOG("multidisorder: no valid split positions") + end + else + DLOG("multidisorder: not acting on further replay pieces") + end + -- drop replayed packets if reasm was sent successfully in splitted form + if replay_drop(desync) then + return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP + end + end +end + +-- nfqws1 : "--dpi-desync=multidisorder". segment ordering is the same as in nfqws1 +-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct, ipfrag +-- arg : pos= . position marker list. example : "1,host,midsld+1,-10" +-- arg : seqovl=N . decrease seq number of the second segment in the original order by N and fill N bytes with pattern (default - all zero). N must be less than the first split pos. +-- arg : seqovl_pattern= . override pattern +-- arg : optional - use zero pattern if seqovl_pattern blob is absent +function multidisorder_legacy(ctx, desync) + if not desync.dis.tcp then + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + return + end + direction_cutoff_opposite(ctx, desync) + -- by default process only outgoing known payloads + local data = desync.dis.payload + local fulldata = desync.reasm_data + if #data>0 and direction_check(desync) and payload_check(desync) then + local range_low = (desync.reasm_offset or 0) + 1 + local range_hi = range_low + #data + local spos = desync.arg.pos or "2" + -- check debug to save CPU + if b_debug then DLOG("multidisorder_legacy: split pos: "..spos) end + local pos = resolve_multi_pos(fulldata, desync.l7payload, spos) + if b_debug then DLOG("multidisorder_legacy: resolved split pos: "..table.concat(zero_based_pos(pos)," ")) end + DLOG("multidisorder_legacy: reasm piece range: "..(range_low-1).."-"..(range_hi-2)) + pos_array_normalize(pos, range_low, range_hi) + delete_pos_1(pos) -- cannot split at the first byte + if #pos>0 then + if b_debug then DLOG("multidisorder_legacy: normalized split pos: "..table.concat(zero_based_pos(pos)," ")) end + local seqovl + if desync.arg.seqovl then + seqovl = resolve_pos(fulldata, desync.l7payload, desync.arg.seqovl) + if seqovl then + DLOG("multidisorder_legacy: resolved seqovl pos: "..(seqovl-1)) + seqovl = pos_normalize(seqovl, range_low, range_hi) + if seqovl then + DLOG("multidisorder_legacy: normalized seqovl pos: "..(seqovl-1)) + else + DLOG("multidisorder_legacy: normalized seqovl pos is outside of the reasm piece range") + end + else + DLOG("multidisorder_legacy: seqovl cancelled because could not resolve marker '"..desync.arg.seqovl.."'") + end + end + return multidisorder_send(desync, data, seqovl, pos) + else + DLOG("multidisorder_legacy: no normalized split pos in this packet") + -- send as is with applied options + if rawsend_payload_segmented(desync) then + return VERDICT_DROP + end + end + end +end + +-- nfqws1 : "--dpi-desync=hostfakesplit" +-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct. FOOLING AND REPEATS APPLIED ONLY TO FAKES. +-- arg : host= - hostname template. generate hosts like "random.template". example : e8nzn.vk.com +-- arg : midhost= - additionally split segment containing host at specified posmarker. must be within host+1 .. endhost-1 or split won't happen. example : "midsld" +-- arg : nofake1, nofake2 - do not send individual fakes +-- arg : disorder_after= - send after_host part in 2 disordered segments. if posmarker is empty string use marker "-1" +-- arg : blob= - use this data instead of desync.dis.payload +-- arg : optional - skip if blob is absent +-- arg : nodrop - do not drop current dissect +function hostfakesplit(ctx, desync) + if not desync.dis.tcp then + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + return + end + direction_cutoff_opposite(ctx, desync) + if desync.arg.optional and desync.arg.blob and not blob_exist(desync, desync.arg.blob) then + DLOG("hostfakesplit: blob '"..desync.arg.blob.."' not found. skipped") + return + end + local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload + if #data>0 and direction_check(desync) and payload_check(desync) then + if replay_first(desync) then + local pos = resolve_range(data, desync.l7payload, "host,endhost-1", true) + if pos then + if b_debug then DLOG("hostfakesplit: resolved host range: "..table.concat(zero_based_pos(pos)," ")) end + + -- do not apply fooling to original parts except tcp_ts_up but apply ip_id + local part, fakehost + local opts_orig = {rawsend = rawsend_opts_base(desync), reconstruct = {}, ipfrag = {}, ipid = desync.arg, fooling = {tcp_ts_up = desync.arg.tcp_ts_up}} + local opts_fake = {rawsend = rawsend_opts(desync), reconstruct = reconstruct_opts(desync), ipfrag = {}, ipid = desync.arg, fooling = desync.arg} + + part = string.sub(data,1,pos[1]-1) + if b_debug then DLOG("hostfakesplit: sending before_host part 0-"..(pos[1]-2).." len="..#part.." : "..hexdump_dlog(part)) end + if not rawsend_payload_segmented(desync,part,0, opts_orig) then return VERDICT_PASS end + + fakehost = genhost(pos[2]-pos[1]+1, desync.arg.host) + + if not desync.arg.nofake1 then + if b_debug then DLOG("hostfakesplit: sending fake host part (1) "..(pos[1]-1).."-"..(pos[2]-1).." len="..#fakehost.." : "..hexdump_dlog(fakehost)) end + if not rawsend_payload_segmented(desync,fakehost,pos[1]-1, opts_fake) then return VERDICT_PASS end + end + + local midhost + if desync.arg.midhost then + midhost = resolve_pos(data,desync.l7payload,desync.arg.midhost) + if midhost then + DLOG("hosfakesplit: midhost marker resolved to "..midhost) + if midhost<=pos[1] or midhost>pos[2] then + DLOG("hostfakesplit: midhost is not inside the host range") + midhost = nil + end + else + DLOG("hostfakesplit: cannot resolve midhost marker '"..desync.arg.midhost.."'") + end + end + -- if present apply ipfrag only to real host parts. fakes and parts outside of the host must be visible to DPI. + if midhost then + part = string.sub(data,pos[1],midhost-1) + if b_debug then DLOG("hostfakesplit: sending real host part 1 "..(pos[1]-1).."-"..(midhost-2).." len="..#part.." : "..hexdump_dlog(part)) end + if not rawsend_payload_segmented(desync,part,pos[1]-1, opts_orig) then return VERDICT_PASS end + + part = string.sub(data,midhost,pos[2]) + if b_debug then DLOG("hostfakesplit: sending real host part 2 "..(midhost-1).."-"..(pos[2]-1).." len="..#part.." : "..hexdump_dlog(part)) end + if not rawsend_payload_segmented(desync,part,midhost-1, opts_orig) then return VERDICT_PASS end + else + part = string.sub(data,pos[1],pos[2]) + if b_debug then DLOG("hostfakesplit: sending real host part "..(pos[1]-1).."-"..(pos[2]-1).." len="..#part.." : "..hexdump_dlog(part)) end + if not rawsend_payload_segmented(desync,part,pos[1]-1, opts_orig) then return VERDICT_PASS end + end + + if not desync.arg.nofake2 then + if b_debug then DLOG("hostfakesplit: sending fake host part (2) "..(pos[1]-1).."-"..(pos[2]-1).." len="..#fakehost.." : "..hexdump_dlog(fakehost)) end + if not rawsend_payload_segmented(desync,fakehost,pos[1]-1, opts_fake) then return VERDICT_PASS end + end + + local disorder_after_pos + if desync.arg.disorder_after then + disorder_after_pos = resolve_pos(data, desync.l7payload, desync.arg.disorder_after=="" and "-1" or desync.arg.disorder_after) + if disorder_after_pos then + -- pos[2] points to the last letter of the host starting from 1 + if disorder_after_pos<=(pos[2]+1) then + DLOG("hostfakesplit: disorder_after marker '"..(disorder_after_pos-1).."' resolved to pos not after after_host pos "..pos[2]) + disorder_after_pos = nil + end + + else + DLOG("hostfakesplit: could not resolve disorder_after marker '"..desync.arg.disorder_after.."'") + end + end + if disorder_after_pos then + part = string.sub(data,disorder_after_pos) + if b_debug then DLOG("hostfakesplit: sending after_host part (2) "..(disorder_after_pos-1).."-"..(#data-1).." len="..#part.." : "..hexdump_dlog(part)) end + if not rawsend_payload_segmented(desync,part,disorder_after_pos-1, opts_orig) then return VERDICT_PASS end + + part = string.sub(data,pos[2]+1,disorder_after_pos-1) + if b_debug then DLOG("hostfakesplit: sending after_host part (1) "..pos[2].."-"..(disorder_after_pos-2).." len="..#part.." : "..hexdump_dlog(part)) end + else + part = string.sub(data,pos[2]+1) + if b_debug then DLOG("hostfakesplit: sending after_host part "..pos[2].."-"..(#data-1).." len="..#part.." : "..hexdump_dlog(part)) end + end + if not rawsend_payload_segmented(desync,part,pos[2], opts_orig) then return VERDICT_PASS end + + replay_drop_set(desync) + return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP + else + DLOG("hostfakesplit: host range cannot be resolved") + end + else + DLOG("hostfakesplit: not acting on further replay pieces") + end + -- drop replayed packets if reasm was sent successfully in splitted form + if replay_drop(desync) then + return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP + end + end +end + +-- nfqws1 : "--dpi-desync=fakedsplit" +-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct. FOOLING AND REPEATS APPLIED ONLY TO FAKES. +-- arg : pos= - split position marker +-- arg : nofake1, nofake2, nofake3, nofake4 - do not send individual fakes +-- arg : pattern= . fill fake parts with this pattern +-- arg : seqovl=N . decrease seq number of the first segment by N and fill N bytes with pattern (default - all zero) +-- arg : seqovl_pattern= . override seqovl pattern +-- arg : blob= - use this data instead of reasm_data +-- arg : optional - skip if blob is absent. use zero pattern if seqovl_pattern blob is absent +-- arg : nodrop - do not drop current dissect +function fakedsplit(ctx, desync) + if not desync.dis.tcp then + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + return + end + direction_cutoff_opposite(ctx, desync) + if desync.arg.optional and desync.arg.blob and not blob_exist(desync, desync.arg.blob) then + DLOG("fakedsplit: blob '"..desync.arg.blob.."' not found. skipped") + return + end + local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload + if #data>0 and direction_check(desync) and payload_check(desync) then + if replay_first(desync) then + local spos = desync.arg.pos or "2" + local pos = resolve_pos(data, desync.l7payload, spos) + if pos then + if pos == 1 then + DLOG("fakedsplit: split pos resolved to 0. cannot split.") + else + if b_debug then DLOG("fakedsplit: resolved split pos: "..tostring(pos-1)) end + + -- do not apply fooling to original parts except tcp_ts_up but apply ip_id + local fake, fakepat, part, pat + local opts_orig = {rawsend = rawsend_opts_base(desync), reconstruct = {}, ipfrag = {}, ipid = desync.arg, fooling = {tcp_ts_up = desync.arg.tcp_ts_up}} + local opts_fake = {rawsend = rawsend_opts(desync), reconstruct = reconstruct_opts(desync), ipfrag = {}, ipid = desync.arg, fooling = desync.arg} + + fakepat = desync.arg.pattern and blob(desync,desync.arg.pattern) or "\x00" + + -- first fake + fake = pattern(fakepat,1,pos-1) + + if not desync.arg.nofake1 then + if b_debug then DLOG("fakedsplit: sending fake part 1 (1) : 0-"..(pos-2).." len="..#fake.." : "..hexdump_dlog(fake)) end + if not rawsend_payload_segmented(desync,fake,0, opts_fake) then return VERDICT_PASS end + end + + -- first real + part = string.sub(data,1,pos-1) + local seqovl=0 + if desync.arg.seqovl and tonumber(desync.arg.seqovl)>0 then + seqovl = tonumber(desync.arg.seqovl) + pat="\x00" + if desync.arg.seqovl_pattern then + if desync.arg.optional and not blob_exist(desync, desync.arg.seqovl_pattern) then + DLOG("fakedsplit: blob '"..desync.arg.seqovl_pattern.."' not found. using zero pattern") + else + pat = blob(desync,desync.arg.seqovl_pattern) + end + end + part = pattern(pat,1,seqovl)..part + end + if b_debug then DLOG("fakedsplit: sending real part 1 : 0-"..(pos-2).." len="..#part.." seqovl="..seqovl.." : "..hexdump_dlog(part)) end + if not rawsend_payload_segmented(desync,part,-seqovl, opts_orig) then return VERDICT_PASS end + + -- first fake again + if not desync.arg.nofake2 then + if b_debug then DLOG("fakedsplit: sending fake part 1 (2) : 0-"..(pos-2).." len="..#fake.." : "..hexdump_dlog(fake)) end + if not rawsend_payload_segmented(desync,fake,0, opts_fake) then return VERDICT_PASS end + end + + -- second fake + fake = pattern(fakepat,pos,#data-pos+1) + if not desync.arg.nofake3 then + if b_debug then DLOG("fakedsplit: sending fake part 2 (1) : "..(pos-1).."-"..(#data-1).." len="..#fake.." : "..hexdump_dlog(fake)) end + if not rawsend_payload_segmented(desync,fake,pos-1, opts_fake) then return VERDICT_PASS end + end + + -- second real + part = string.sub(data,pos) + if b_debug then DLOG("fakedsplit: sending real part 2 : "..(pos-1).."-"..(#data-1).." len="..#part.." : "..hexdump_dlog(part)) end + if not rawsend_payload_segmented(desync,part,pos-1, opts_orig) then return VERDICT_PASS end + + -- second fake again + if not desync.arg.nofake4 then + if b_debug then DLOG("fakedsplit: sending fake part 2 (2) : "..(pos-1).."-"..(#data-1).." len="..#fake.." : "..hexdump_dlog(fake)) end + if not rawsend_payload_segmented(desync,fake,pos-1, opts_fake) then return VERDICT_PASS end + end + + replay_drop_set(desync) + return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP + end + else + DLOG("fakedsplit: cannot resolve pos '"..spos.."'") + end + else + DLOG("fakedsplit: not acting on further replay pieces") + end + -- drop replayed packets if reasm was sent successfully in splitted form + if replay_drop(desync) then + return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP + end + end +end + +-- nfqws1 : "--dpi-desync=fakeddisorder" +-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct. FOOLING AND REPEATS APPLIED ONLY TO FAKES. +-- arg : pos= - split position marker +-- arg : nofake1, nofake2, nofake3, nofake4 - do not send individual fakes +-- arg : pattern= . fill fake parts with this pattern +-- arg : seqovl=N . decrease seq number of the second segment by N and fill N bytes with pattern (default - all zero). N must be less than the split pos. +-- arg : seqovl_pattern= . override seqovl pattern +-- arg : blob= - use this data instead of desync.dis.payload +-- arg : optional - skip if blob is absent. use zero pattern if seqovl_pattern blob is absent +-- arg : nodrop - do not drop current dissect +function fakeddisorder(ctx, desync) + if not desync.dis.tcp then + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + return + end + direction_cutoff_opposite(ctx, desync) + if desync.arg.optional and desync.arg.blob and not blob_exist(desync, desync.arg.blob) then + DLOG("fakeddisorder: blob '"..desync.arg.blob.."' not found. skipped") + return + end + local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload + if #data>0 and direction_check(desync) and payload_check(desync) then + if replay_first(desync) then + local spos = desync.arg.pos or "2" + local pos = resolve_pos(data, desync.l7payload, spos) + if pos then + if pos == 1 then + DLOG("fakeddisorder: split pos resolved to 0. cannot split.") + else + if b_debug then DLOG("fakeddisorder: resolved split pos: "..tostring(pos-1)) end + + -- do not apply fooling to original parts except tcp_ts_up but apply ip_id + local fake, part + local opts_orig = {rawsend = rawsend_opts_base(desync), reconstruct = {}, ipfrag = {}, ipid = desync.arg, fooling = {tcp_ts_up = desync.arg.tcp_ts_up}} + local opts_fake = {rawsend = rawsend_opts(desync), reconstruct = reconstruct_opts(desync), ipfrag = {}, ipid = desync.arg, fooling = desync.arg} + + local fakepat = desync.arg.pattern and blob(desync,desync.arg.pattern) or "\x00" + + -- second fake + fake = pattern(fakepat,pos,#data-pos+1) + if not desync.arg.nofake1 then + if b_debug then DLOG("fakeddisorder: sending fake part 2 (1) : "..(pos-1).."-"..(#data-1).." len="..#fake.." : "..hexdump_dlog(fake)) end + if not rawsend_payload_segmented(desync,fake,pos-1, opts_fake) then return VERDICT_PASS end + end + + -- second real + part = string.sub(data,pos) + local seqovl = 0 + if desync.arg.seqovl then + seqovl = resolve_pos(data, desync.l7payload, desync.arg.seqovl) + if seqovl then + seqovl = seqovl - 1 + if seqovl>=(pos-1) then + DLOG("fakeddisorder: seqovl cancelled because seqovl "..seqovl.." is not less than the split pos "..(pos-1)) + seqovl = 0 + else + local pat="\x00" + if desync.arg.seqovl_pattern then + if desync.arg.optional and not blob_exist(desync, desync.arg.seqovl_pattern) then + DLOG("fakeddisorder: blob '"..desync.arg.seqovl_pattern.."' not found. using zero pattern") + else + pat = blob(desync,desync.arg.seqovl_pattern) + end + end + part = pattern(pat,1,seqovl)..part + end + else + DLOG("fakeddisorder: seqovl cancelled because could not resolve marker '"..desync.arg.seqovl.."'") + seqovl = 0 + end + end + if b_debug then DLOG("fakeddisorder: sending real part 2 : "..(pos-1).."-"..(#data-1).." len="..#part.." seqovl="..seqovl.." : "..hexdump_dlog(part)) end + if not rawsend_payload_segmented(desync,part,pos-1-seqovl, opts_orig) then return VERDICT_PASS end + + -- second fake again + if not desync.arg.nofake2 then + if b_debug then DLOG("fakeddisorder: sending fake part 2 (2) : "..(pos-1).."-"..(#data-1).." len="..#fake.." : "..hexdump_dlog(fake)) end + if not rawsend_payload_segmented(desync,fake,pos-1, opts_fake) then return VERDICT_PASS end + end + + -- first fake + fake = pattern(fakepat,1,pos-1) + if not desync.arg.nofake3 then + if b_debug then DLOG("fakeddisorder: sending fake part 1 (1) : 0-"..(pos-2).." len="..#fake.." : "..hexdump_dlog(fake)) end + if not rawsend_payload_segmented(desync,fake,0, opts_fake) then return VERDICT_PASS end + end + + -- first real + part = string.sub(data,1,pos-1) + if b_debug then DLOG("fakeddisorder: sending real part 1 : 0-"..(pos-2).." len="..#part.." : "..hexdump_dlog(part)) end + if not rawsend_payload_segmented(desync,part,0, opts_orig) then return VERDICT_PASS end + + -- first fake again + if not desync.arg.nofake4 then + if b_debug then DLOG("fakeddisorder: sending fake part 1 (2) : 0-"..(pos-2).." len="..#fake.." : "..hexdump_dlog(fake)) end + if not rawsend_payload_segmented(desync,fake,0, opts_fake) then return VERDICT_PASS end + end + + replay_drop_set(desync) + return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP + end + else + DLOG("fakeddisorder: cannot resolve pos '"..spos.."'") + end + else + DLOG("fakeddisorder: not acting on further replay pieces") + end + -- drop replayed packets if reasm was sent successfully in splitted form + if replay_drop(desync) then + return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP + end + end +end + +-- nfqws1 : not available +-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct, ipfrag +-- arg : pos= . position marker list. 2 pos required, only 2 first pos used. example : "host,endhost" +-- arg : seqovl=N . decrease seq number of the first segment by N and fill N bytes with pattern (default - all zero) +-- arg : seqovl_pattern= . override pattern +-- arg : blob= - use this data instead of desync.dis.payload +-- arg : optional - skip if blob is absent. use zero pattern if seqovl_pattern blob is absent +function tcpseg(ctx, desync) + if not desync.dis.tcp then + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + return + end + direction_cutoff_opposite(ctx, desync) + if not desync.arg.pos then + error("tcpseg: no pos specified") + end + if desync.arg.optional and desync.arg.blob and not blob_exist(desync, desync.arg.blob) then + DLOG("tcpseg: blob '"..desync.arg.blob.."' not found. skipped") + return + end + local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload + if #data>0 and direction_check(desync) and payload_check(desync) then + if replay_first(desync) then + if b_debug then DLOG("tcpseg: pos: "..desync.arg.pos) end + -- always returns 2 positions or nil or causes error + local pos = resolve_range(data, desync.l7payload, desync.arg.pos) + if pos then + -- check debug to save CPU + if b_debug then DLOG("tcpseg: resolved range: "..table.concat(zero_based_pos(pos)," ")) end + local part = string.sub(data,pos[1],pos[2]) + local seqovl=0 + if desync.arg.seqovl and tonumber(desync.arg.seqovl)>0 then + seqovl = tonumber(desync.arg.seqovl) + local pat="\x00" + if desync.arg.seqovl_pattern then + if desync.arg.optional and not blob_exist(desync, desync.arg.seqovl_pattern) then + DLOG("tcpseg: blob '"..desync.arg.seqovl_pattern.."' not found. using zero pattern") + else + pat = blob(desync,desync.arg.seqovl_pattern) + end + end + part = pattern(pat,1,seqovl)..part + end + if b_debug then DLOG("tcpseg: sending "..(pos[1]-1).."-"..(pos[2]-1).." len="..#part.." seqovl="..seqovl.." : "..hexdump_dlog(part)) end + rawsend_payload_segmented(desync,part,pos[1]-1-seqovl) + else + DLOG("tcpseg: range cannot be resolved") + end + else + DLOG("tcpseg: not acting on further replay pieces") + end + end +end + +-- nfqws1 : not available +-- tpws : close analog is "--split-pos=.. --oob" but works not the same way +-- standard args : fooling, ip_id, rawsend, reconstruct, ipfrag +-- arg : char - oob char +-- arg : byte - oob byte +-- arg : urp - urgent pointer position marker, 'b' or 'e'. default - 0 +function oob(ctx, desync) + if not desync.track then return end + if not desync.dis.tcp then + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + return + end + local key = desync.func_instance.."_syn" + if not desync.track.lua_state[key] then + if bitand(desync.dis.tcp.th_flags, TH_SYN+TH_ACK)~=TH_SYN then + DLOG("oob: must be applied since the very beginning of the tcp connection - SYN packet") + instance_cutoff_shim(ctx, desync) + return + end + desync.track.lua_state[key] = true + end + if desync.outgoing then + -- direct pos - outgoing + local pos = pos_get(desync, 's', false) + if pos<=1 then + local dseq = u32add(desync.dis.tcp.th_seq, -1) + DLOG("oob: decreasing outgoing seq : "..desync.dis.tcp.th_seq.." => "..dseq) + desync.dis.tcp.th_seq = dseq + end + if pos==0 then + return VERDICT_MODIFY + elseif pos==1 then + local data = desync.reasm_data or desync.dis.payload + if #data==0 then + -- empty ACK + return VERDICT_MODIFY + else + local oob = desync.arg.char or (desync.arg.byte and bu8(desync.arg.byte) or nil) or "\x00" + if #oob~=1 then + error("oob: OOB must be exactly one byte") + end + local dis_oob = deepcopy(desync.dis) + local urp + if not desync.arg.urp or desync.arg.urp=='b' then + urp = 1 + dis_oob.tcp.th_urp = 0 + elseif desync.arg.urp=='e' then + urp = #data+1 + dis_oob.tcp.th_urp = urp + else + urp = resolve_pos(data, desync.l7payload, desync.arg.urp) + if not urp then + DLOG("oob: cannot resolve urp marker '"..desync.arg.urp.."'") + instance_cutoff_shim(ctx, desync) + return + end + DLOG("oob: resolved urp marker to "..urp-1) + dis_oob.tcp.th_urp = urp + end + DLOG("oob: th_urp "..dis_oob.tcp.th_urp) + -- one byte OOB payload + dis_oob.payload = string.sub(data, 1, urp-1) .. oob .. string.sub(data, urp) + dis_oob.tcp.th_flags = bitor(dis_oob.tcp.th_flags, TH_URG) + DLOG("oob: sending OOB") + if not rawsend_dissect_segmented(desync, dis_oob) then + instance_cutoff_shim(ctx, desync) + return + end + if not desync.replay then + instance_cutoff_shim(ctx, desync) + end + end + return VERDICT_DROP + else + -- drop replay and cutoff + if desync.replay then + DLOG("oob: dropping replay piece") + if desync.replay_piece_last then + instance_cutoff_shim(ctx, desync) + end + return VERDICT_DROP + end + instance_cutoff_shim(ctx, desync) + end + else + -- reverse pos - outgoing + local pos = pos_get(desync, 's', true) + if pos>1 then + DLOG("oob: unexpected outgoing position "..pos) + instance_cutoff_shim(ctx, desync) + return + end + local dack = u32add(desync.dis.tcp.th_ack, 1) + DLOG("oob: increasing incoming ack : "..desync.dis.tcp.th_ack.." => "..dack) + desync.dis.tcp.th_ack = dack + return VERDICT_MODIFY + end +end + +-- nfqws1 : "--dpi-desync=udplen" +-- standard args : direction, payload +-- arg : min=N . do not act on payloads smaller than N bytes +-- arg : max=N . do not act on payloads larger than N bytes +-- arg : increment=N . 2 by default. negative increment shrinks the packet, positive grows it. +-- arg : pattern= . used to fill extra bytes when length increases +-- arg : pattern_offset=N . offset in the pattern. 0 by default +function udplen(ctx, desync) + if not desync.dis.udp then + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + return + end + direction_cutoff_opposite(ctx, desync) + if direction_check(desync) and payload_check(desync) then + local len = #desync.dis.payload + if (desync.arg.min and #desync.dis.payload < tonumber(desync.arg.min)) then + DLOG("udplen: payload size "..len.." is less than the minimum size "..desync.arg.min) + elseif (desync.arg.max and #desync.dis.payload > tonumber(desync.arg.max)) then + DLOG("udplen: payload size "..len.." is more than the maximum size "..desync.arg.max) + else + local inc = desync.arg.increment and tonumber(desync.arg.increment) or 2 + if inc>0 then + local pat = desync.arg.pattern and blob(desync,desync.arg.pattern) or "\x00" + local pat_offset = desync.arg.pattern_offset and (tonumber(desync.arg.pattern_offset)+1) or 1 + desync.dis.payload = desync.dis.payload .. pattern(pat, pat_offset, inc) + DLOG("udplen: "..len.." => "..#desync.dis.payload) + return VERDICT_MODIFY + elseif inc<0 then + if (len+inc)<1 then + DLOG("udplen: will not shrink to zero length") + else + desync.dis.payload = string.sub(desync.dis.payload,1,len+inc) + DLOG("udplen: "..len.." => "..#desync.dis.payload) + return VERDICT_MODIFY + end + end + end + end +end + +-- nfqws1 : "--dpi-desync=tamper" for dht proto +-- standard args : direction +-- arg : dn=N - message starts from "dN". 3 by default +function dht_dn(ctx, desync) + if not desync.dis.udp then + -- do not cutoff on related icmp + if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end + return + end + direction_cutoff_opposite(ctx, desync) + if desync.l7payload=="dht" and direction_check(desync) then + local N = tonumber(desync.arg.dn) or 3 + -- remove "d1" from the start not breaking bencode + local prefix = "d"..tostring(N)..":"..string.rep("0",N).."1:x" + desync.dis.payload = prefix..string.sub(desync.dis.payload,2) + DLOG("dht_dn: tampered dht to start with '"..prefix.."' instead of 'd1:'") + return VERDICT_MODIFY + end +end diff --git a/blockcheck/zapret2/lua/zapret-auto.lua b/blockcheck/zapret2/lua/zapret-auto.lua new file mode 100644 index 0000000..c6999e2 --- /dev/null +++ b/blockcheck/zapret2/lua/zapret-auto.lua @@ -0,0 +1,576 @@ +-- standard automation/orchestration code +-- this is related to making dynamic strategy decisions without rewriting or altering strategy function code +-- orchestrators can decide which instances to call or not to call or pass them dynamic arguments +-- failure and success detectors test potential block conditions for orchestrators + +-- standard host key generator for per-host storage +-- arg: reqhost - require hostname, do not work with ip +-- arg: nld=N - cut hostname to N level domain. NLD=2 static.intranet.microsoft.com => microsoft.com +function standard_hostkey(desync) + local hostkey = desync.track and desync.track.hostname + if hostkey then + if desync.arg.nld and tonumber(desync.arg.nld)>0 and not (desync.track and desync.track.hostname_is_ip) then + -- dissect_nld returns nil if domain is invalid or does not have this NLD + -- fall back to original hostkey if it fails + local hktemp = dissect_nld(hostkey, tonumber(desync.arg.nld)) + if hktemp then + hostkey = hktemp + end + end + elseif not desync.arg.reqhost then + hostkey = host_ip(desync) + end + return hostkey +end + +-- per-host storage +-- arg: key - a string - table name inside autostate table. to allow multiple orchestrator instances to use single host storage +-- arg: hostkey - hostkey generator function name +function automate_host_record(desync) + local hostkey, hkf, askey + + if desync.arg.hostkey then + if type(_G[desync.arg.hostkey])~="function" then + error("automate: invalid hostkey function '"..desync.arg.hostkey.."'") + end + hkf = _G[desync.arg.hostkey] + else + hkf = standard_hostkey + end + hostkey = hkf(desync) + if not hostkey then + DLOG("automate: host record key unavailable") + return nil + end + + askey = (desync.arg.key and #desync.arg.key>0) and desync.arg.key or desync.func_instance + DLOG("automate: host record key 'autostate."..askey.."."..hostkey.."'") + if not autostate then + autostate = {} + end + if not autostate[askey] then + autostate[askey] = {} + end + if not autostate[askey][hostkey] then + autostate[askey][hostkey] = {} + end + return autostate[askey][hostkey] +end +-- per-connection storage +function automate_conn_record(desync) + if not desync.track then return nil end + if not desync.track.lua_state.automate then + desync.track.lua_state.automate = {} + end + return desync.track.lua_state.automate +end + +-- counts failure, optionally (if crec is given) prevents dup failure counts in a single connection +-- if 'maxtime' between failures is exceeded then failure count is reset +-- return true if threshold ('fails') is reached +-- hres is host record. host or ip bound table +-- cres is connection record. connection bound table +function automate_failure_counter(hrec, crec, fails, maxtime) + if crec and crec.failure then + DLOG("automate: duplicate failure in the same connection. not counted") + else + if crec then crec.failure = true end + local tnow=os.time() + if not hrec.failure_time_last then + hrec.failure_time_last = tnow + end + if not hrec.failure_counter then + hrec.failure_counter = 0 + elseif tnow>(hrec.failure_time_last + maxtime) then + DLOG("automate: failure counter reset because last failure was "..(tnow - hrec.failure_time_last).." seconds ago") + hrec.failure_counter = 0 + end + hrec.failure_counter = hrec.failure_counter + 1 + hrec.failure_time_last = tnow + if b_debug then DLOG("automate: failure counter "..hrec.failure_counter..(fails and ('/'..fails) or '')) end + if fails and hrec.failure_counter>=fails then + hrec.failure_counter = nil -- reset counter + return true + end + end + return false +end +-- resets failure counter if it has started counting +function automate_failure_counter_reset(hrec) + if hrec.failure_counter then + DLOG("automate: failure counter reset") + hrec.failure_counter = nil + end +end + +-- location is url compatible with Location: header +-- hostname is original hostname +function is_dpi_redirect(hostname, location) + local ds = dissect_url(location) + if ds and ds.domain then + local sld1 = dissect_nld(hostname,2) + local sld2 = dissect_nld(ds.domain,2) + return sld2 and sld1~=sld2 and true or false + end + return false +end + +function standard_detector_defaults(arg) + return { + inseq = tonumber(arg.inseq) or 4096, + retrans = tonumber(arg.retrans) or 3, + maxseq = tonumber(arg.maxseq) or 32768, + udp_in = tonumber(arg.udp_in) or 1, + udp_out = tonumber(arg.udp_out) or 4, + no_http_redirect = arg.no_http_redirect, + no_rst = arg.no_rst, + reset = arg.reset + } +end + +-- standard failure detector +-- works with tcp and udp +-- detected failures: +-- incoming RST +-- incoming http redirection +-- outgoing retransmissions +-- udp too much out with too few in +-- arg: maxseq= - tcp: test retransmissions only within this relative sequence. default is 32K +-- arg: retrans=N - tcp: retrans count threshold. default is 3 +-- arg: reset - send RST to retransmitter to break long wait +-- arg: inseq= - tcp: maximum relative sequence number to treat incoming RST as DPI reset. default is 4K +-- arg: no_http_redirect - tcp: disable http_reply dpi redirect trigger +-- arg: no_rst - tcp: disable incoming RST trigger +-- arg: udp_out - udp: >= outgoing udp packets. default is 4 +-- arg: udp_in - udp: with <= incoming udp packets. default is 1 +function standard_failure_detector(desync, crec) + local arg = standard_detector_defaults(desync.arg) + local trigger = false + if desync.dis.tcp then + local seq = pos_get(desync,'s') + if desync.outgoing then + if #desync.dis.payload>0 and arg.retrans and arg.maxseq>0 and seq<=arg.maxseq and (crec.retrans or 0)=arg.retrans + if trigger and arg.reset then + local dis = deepcopy(desync.dis) + dis.payload = nil + dis_reverse(dis) + dis.tcp.th_flags = TH_RST + dis.tcp.th_win = desync.track and desync.track.pos.reverse.tcp.winsize or 64 + dis.tcp.options = nil + if dis.ip6 then + dis.ip6.ip6_flow = (desync.track and desync.track.pos.reverse.ip6_flow) and desync.track.pos.reverse.ip6_flow or 0x60000000; + end + DLOG("standard_failure_detector: sending RST to retransmitter") + rawsend_dissect(dis, {ifout = desync.ifin}) + end + end + end + else + if not arg.no_rst and arg.inseq>0 and bitand(desync.dis.tcp.th_flags, TH_RST)~=0 and seq>=1 then + trigger = seq<=arg.inseq + if b_debug then + if trigger then + DLOG("standard_failure_detector: incoming RST s"..seq.." in range s"..arg.inseq) + else + DLOG("standard_failure_detector: not counting incoming RST s"..seq.." beyond s"..arg.inseq) + end + end + elseif not arg.no_http_redirect and desync.l7payload=="http_reply" and desync.track.hostname then + local hdis = http_dissect_reply(desync.dis.payload) + if hdis and (hdis.code==302 or hdis.code==307) then + local idx_loc = array_field_search(hdis.headers, "header_low", "location") + if idx_loc then + trigger = is_dpi_redirect(desync.track.hostname, hdis.headers[idx_loc].value) + if b_debug then + if trigger then + DLOG("standard_failure_detector: http redirect "..hdis.code.." to '"..hdis.headers[idx_loc].value.."'. looks like DPI redirect.") + else + DLOG("standard_failure_detector: http redirect "..hdis.code.." to '"..hdis.headers[idx_loc].value.."'. NOT a DPI redirect.") + end + end + end + end + end + end + elseif desync.dis.udp then + if desync.outgoing then + if arg.udp_out>0 then + local pos_out = pos_get(desync,'n',false) + local pos_in = pos_get(desync,'n',true) + trigger = pos_out>=arg.udp_out and pos_in<=arg.udp_in + if trigger then + if b_debug then + DLOG("standard_failure_detector: arg.udp_out "..pos_out..">="..arg.udp_out.." arg.udp_in "..pos_in.."<="..arg.udp_in) + end + end + end + end + end + return trigger +end + +-- standard success detector +-- success means previous failures were temporary and counter should be reset +-- detected successes: +-- tcp: outgoing seq is beyond 'maxseq' and maxseq>0 +-- tcp: incoming seq is beyond 'inseq' and inseq>0 +-- udp: incoming packets count > `udp_in` and `udp_out`>0 +-- arg: maxseq= - tcp: success if outgoing relative sequence is beyond this value. default is 32K +-- arg: inseq= - tcp: success if incoming relative sequence is beyond this value. default is 4K +-- arg: udp_out - udp : must be nil or >0 to test udp_in +-- arg: udp_in - udp: if number if incoming packets > udp_in it means success +function standard_success_detector(desync, crec) + local arg = standard_detector_defaults(desync.arg) + if desync.dis.tcp then + local seq = pos_get(desync,'s') + if desync.outgoing then + if arg.maxseq>0 and seq>arg.maxseq then + DLOG("standard_success_detector: outgoing s"..seq.." is beyond s"..arg.maxseq..". treating connection as successful") + return true + end + else + if arg.inseq>0 and seq>arg.inseq then + DLOG("standard_success_detector: incoming s"..seq.." is beyond s"..arg.inseq..". treating connection as successful") + return true + end + end + elseif desync.dis.udp then + if not desync.outgoing then + local pos = pos_get(desync,'n') + if arg.udp_out>0 and pos>arg.udp_in then + if b_debug then + DLOG("standard_success_detector: arg.udp_in "..pos..">"..arg.udp_in) + end + return true + end + end + end + + return false +end + +-- calls success and failure detectors +-- resets counter if success is detected +-- increases counter if failure is detected +-- returns true if failure counter exceeds threshold +function automate_failure_check(desync, hrec, crec) + if crec.nocheck then return false end + + local failure_detector, success_detector + if desync.arg.failure_detector then + if type(_G[desync.arg.failure_detector])~="function" then + error("automate: invalid failure detector function '"..desync.arg.failure_detector.."'") + end + failure_detector = _G[desync.arg.failure_detector] + else + failure_detector = standard_failure_detector + end + if desync.arg.success_detector then + if type(_G[desync.arg.success_detector])~="function" then + error("automate: invalid success detector function '"..desync.arg.success_detector.."'") + end + success_detector = _G[desync.arg.success_detector] + else + success_detector = standard_success_detector + end + + if success_detector(desync, crec) then + crec.nocheck = true + DLOG("automate: success detected") + automate_failure_counter_reset(hrec) + return false + end + if failure_detector(desync, crec) then + crec.nocheck = true + DLOG("automate: failure detected") + local fails = tonumber(desync.arg.fails) or 3 + local maxtime = tonumber(desync.arg.time) or 60 + return automate_failure_counter(hrec, crec, fails, maxtime) + end + + return false +end + + +-- circularily change strategy numbers when failure count reaches threshold ('fails') +-- this orchestrator requires redirection of incoming traffic to cache RST and http replies ! +-- each orchestrated instance must have strategy=N arg, where N starts from 1 and increment without gaps +-- if 'final' arg is present in an orchestrated instance it stops rotation +-- arg: fails=N - failture count threshold. default is 3 +-- arg: time= - if last failure happened earlier than `maxtime` seconds ago - reset failure counter. default is 60. +-- arg: success_detector - success detector function name +-- arg: failure_detector - failure detector function name +-- arg: hostkey - hostkey generator function name +-- args for failure detector - see standard_failure_detector or your own detector +-- args for success detector - see standard_success_detector or your own detector +-- args for hostkey generator - see standard_hostkey or your own generator +-- test case: --in-range=-s34228 --lua-desync=circular --lua-desync=argdebug:strategy=1 --lua-desync=argdebug:strategy=2 +function circular(ctx, desync) + local function count_strategies(hrec) + if not hrec.ctstrategy then + local uniq={} + local n + for i,instance in pairs(desync.plan) do + if instance.arg.strategy then + n = tonumber(instance.arg.strategy) + if not n or n<1 then + error("circular: strategy number '"..tostring(instance.arg.strategy).."' is invalid") + end + uniq[tonumber(instance.arg.strategy)] = true + if instance.arg.final then + hrec.final = n + end + end + end + n=0 + for i,v in pairs(uniq) do + n=n+1 + end + if n~=#uniq then + error("circular: strategies numbers must start from 1 and increment. gaps are not allowed.") + end + hrec.ctstrategy = n + end + end + + -- take over execution. prevent further instance execution in case of error + orchestrate(ctx, desync) + + if not desync.track then + DLOG_ERR("circular: conntrack is missing but required") + return + end + + local hrec = automate_host_record(desync) + if not hrec then + DLOG("circular: passing with no tampering") + return + end + + count_strategies(hrec) + if hrec.ctstrategy==0 then + error("circular: add strategy=N tag argument to each following instance ! N must start from 1 and increment") + end + if not hrec.nstrategy then + DLOG("circular: start from strategy 1") + hrec.nstrategy = 1 + end + + local verdict = VERDICT_PASS + if hrec.final~=hrec.nstrategy then + local crec = automate_conn_record(desync) + if automate_failure_check(desync, hrec, crec) then + hrec.nstrategy = (hrec.nstrategy % hrec.ctstrategy) + 1 + DLOG("circular: rotate strategy to "..hrec.nstrategy) + if hrec.nstrategy == hrec.final then + DLOG("circular: final strategy "..hrec.final.." reached. will rotate no more.") + end + end + end + + DLOG("circular: current strategy "..hrec.nstrategy) + while true do + local instance = plan_instance_pop(desync) + if not instance then break end + if instance.arg.strategy and tonumber(instance.arg.strategy)==hrec.nstrategy then + verdict = plan_instance_execute(desync, verdict, instance) + end + end + + return verdict +end + +-- test iff functions +function cond_true(desync) + return true +end +function cond_false(desync) + return false +end +-- arg: percent - of true . 50 by default +function cond_random(desync) + return math.random(0,99)<(tonumber(desync.arg.percent) or 50) +end +-- this iif function detects packets having 'arg.pattern' string in their payload +-- test case : --lua-desync=condition:iff=cond_payload_str:pattern=1234 --lua-desync=argdebug:testarg=1 --lua-desync=argdebug:testarg=2:morearg=xyz +-- test case (true) : echo aaz1234zzz | ncat -4u 1.1.1.1 443 +-- test case (false) : echo aaze124zzz | ncat -4u 1.1.1.1 443 +function cond_payload_str(desync) + if not desync.arg.pattern then + error("cond_payload_str: missing 'pattern'") + end + return desync.dis.payload and string.find(desync.dis.payload,desync.arg.pattern,1,true) +end +-- true if dissect is tcp and timestamp tcp option is present +function cond_tcp_has_ts(desync) + return desync.dis.tcp and find_tcp_option(desync.dis.tcp.options, TCP_KIND_TS) +end +-- exec lua code in "code" arg and return it's result +function cond_lua(desync) + if not desync.arg.cond_code then + error("cond_lua: no 'cond_code' parameter") + end + local fname = desync.func_instance.."_cond_cond_code" + if not _G[fname] then + local err + _G[fname], err = load(desync.arg.cond_code, fname) + if not _G[fname] then + error(err) + end + end + -- allow dynamic cond_code to access desync + _G.desync = desync + local res, v = pcall(_G[fname]) + _G.desync = nil + if not res then + error(v); + end + return v +end + +-- check iff function available. error if not +function require_iff(desync, name) + if not desync.arg.iff then + error(name..": missing 'iff' function") + end + if type(_G[desync.arg.iff])~="function" then + error(name..": invalid 'iff' function '"..desync.arg.iff.."'") + end +end +-- execute further desync instances only if user-provided 'iff' function returns true +-- for example, this can be used by custom protocol detectors +-- arg: iff - condition function. takes desync as arg and returns bool. (cant use 'if' because of reserved word) +-- arg: neg - invert condition function result +-- arg: instances - how many instances execute conditionally. all if not defined +-- test case : --lua-desync=condition:iff=cond_random --lua-desync=argdebug:testarg=1 --lua-desync=argdebug:testarg=2:morearg=xyz +function condition(ctx, desync) + require_iff(desync, "condition") + orchestrate(ctx, desync) + if logical_xor(_G[desync.arg.iff](desync), desync.arg.neg) then + DLOG("condition: true") + else + DLOG("condition: false") + plan_clear(desync, tonumber(desync.arg.instances)) + if #desync.plan>0 then + DLOG("condition: executing remaining "..#desync.plan.." instance(s)") + end + end + return replay_execution_plan(desync) +end +-- execute further desync instances. +-- each instance must have "cond" arg and may optionally have "cond_neg" arg. +-- "cond" - condition function. "neg" - invert condition function result +-- arg: instances - how many instances execute conditionally. all if not defined +function per_instance_condition(ctx, desync) + orchestrate(ctx, desync) + + local verdict = VERDICT_PASS + local n = 0 + local max = tonumber(desync.arg.instances) + while not max or n0 then + DLOG("per_instance_condition: executing remaining "..#desync.plan.." instance(s) unconditionally") + end + return verdict_aggregate(verdict, replay_execution_plan(desync)) +end + +-- clear execution plan if user provided 'iff' functions returns true +-- can be used with other orchestrators to stop execution conditionally +-- arg: iff - condition function. takes desync as arg and returns bool. (cant use 'if' because of reserved word) +-- arg: neg - invert condition function result +-- test case : --in-range=-s1 --lua-desync=circular --lua-desync=stopif:iff=cond_random:strategy=1 --lua-desync=argdebug:strategy=1 --lua-desync=argdebug:strategy=2 +function stopif(ctx, desync) + require_iff(desync, "stopif") + orchestrate(ctx, desync) + if logical_xor(_G[desync.arg.iff](desync), desync.arg.neg) then + DLOG("stopif: true") + plan_clear(desync) + else + -- do not do anything. allow other orchestrator to finish the plan + DLOG("stopif: false") + end +end + +-- repeat following 'instances' 'repeats' times, execute others with no tampering +-- arg: instances - number of following instances to be repeated. 1 by default +-- arg: repeats - number of repeats +-- arg: iff - condition function to continue execution. takes desync as arg and returns bool. (cant use 'if' because of reserved word) +-- arg: neg - invert condition function result +-- arg: stop - do not replay remaining execution plan after 'instances' +-- arg: clear - clear execution plan after 'instances' +-- test case : --lua-desync=repeater:repeats=2:instances=2 --lua-desync=argdebug:v=1 --lua-desync=argdebug:v=2 --lua-desync=argdebug:v=3 +function repeater(ctx, desync) + local repeats = tonumber(desync.arg.repeats) + if not repeats then + error("repeater: missing 'repeats'") + end + local iff = desync.arg.iff or "cond_true" + if type(_G[iff])~="function" then + error("repeater: invalid 'iff' function '"..iff.."'") + end + orchestrate(ctx, desync) + if #desync.plan==0 then + DLOG("repeater: execution plan is empty - nothing to repeat") + return + end + local neg = desync.arg.neg + local stop = desync.arg.stop + local clear = desync.arg.clear + local verdict = VERDICT_PASS + local instances = tonumber(desync.arg.instances) or 1 + local repinst = desync.func_instance + if instances>#desync.plan then + instances = #desync.plan + end + -- save plan copy + local plancopy = deepcopy(desync.plan) + for r=1,repeats do + if not logical_xor(_G[iff](desync), neg) then + DLOG("repeater: break by iff") + break + end + DLOG("repeater: "..repinst.." "..r.."/"..repeats) + -- nested orchestrators can also pop + local ct_end = #desync.plan - instances + repeat + local instance = plan_instance_pop(desync) + verdict = plan_instance_execute(desync, verdict, instance) + until #desync.plan <= ct_end + -- rollback desync plan + desync.plan = deepcopy(plancopy) + end + -- remove repeated instances from desync plan + for i=1,instances do + table.remove(desync.plan,1) + end + if clear then + plan_clear(desync) + return verdict + elseif stop then + return verdict + end + -- replay the rest + return verdict_aggregate(verdict, replay_execution_plan(desync)) +end diff --git a/blockcheck/zapret2/lua/zapret-lib.lua b/blockcheck/zapret2/lua/zapret-lib.lua new file mode 100644 index 0000000..c954afd --- /dev/null +++ b/blockcheck/zapret2/lua/zapret-lib.lua @@ -0,0 +1,2730 @@ +NFQWS2_COMPAT_VER_REQUIRED=6 + +if NFQWS2_COMPAT_VER~=NFQWS2_COMPAT_VER_REQUIRED then + error("Incompatible NFQWS2_COMPAT_VER. Use pktws and lua scripts from the same release !") +end + +HEXDUMP_DLOG_MAX = HEXDUMP_DLOG_MAX or 32 +NOT3=bitnot(3) +NOT7=bitnot(7) +-- xor pid,tid,sec,nsec +math.randomseed(bitxor(getpid(),gettid(),clock_gettime())) + +-- basic desync function +-- execute given lua code. "desync" is temporary set as global var to be accessible to the code +-- useful for simple fast actions without writing a func +-- arg: code= +function luaexec(ctx, desync) + if not desync.arg.code then + error("luaexec: no 'code' parameter") + end + local fname = desync.func_instance.."_code" + if not _G[fname] then + local err + _G[fname], err = load(desync.arg.code, fname) + if not _G[fname] then + error(err) + end + end + -- allow dynamic code to access desync + _G.desync = desync + local res, ret = pcall(_G[fname]) + _G.desync = nil + if not res then + error(ret) + else + return ret or VERDICT_PASS -- older nfqws2 failed if desync function returned explicit nil + end +end + +-- basic desync function +-- does nothing just acknowledges when it's called +-- no args +function pass(ctx, desync) + DLOG("pass") +end + +-- basic desync function +-- prints desync to DLOG +function pktdebug(ctx, desync) + DLOG("desync:") + var_debug(desync) +end +-- basic desync function +-- prints function args +function argdebug(ctx, desync) + var_debug(desync.arg) +end + +-- basic desync function +-- prints conntrack positions to DLOG +function posdebug(ctx, desync) + if not desync.track then + DLOG("posdebug: no track") + return + end + local s="posdebug: "..(desync.outgoing and "out" or "in").." time +"..desync.track.pos.dt.."s direct" + for i,pos in pairs({'n','d','b','s','p'}) do + s=s.." "..pos..pos_get(desync, pos, false) + end + s=s.." reverse" + for i,pos in pairs({'n','d','b','s','p'}) do + s=s.." "..pos..pos_get(desync, pos, true) + end + s=s.." payload "..#desync.dis.payload + if desync.reasm_data then + s=s.." reasm "..#desync.reasm_data + end + if desync.decrypt_data then + s=s.." decrypt "..#desync.decrypt_data + end + if desync.replay_piece_count then + s=s.." replay "..desync.replay_piece.."/"..desync.replay_piece_count + end + DLOG(s) +end + +-- basic desync function +-- set l7payload to 'arg.payload' if reasm.data or desync.dis.payload contains 'arg.pattern' substring +-- NOTE : this does not set payload on C code side ! +-- NOTE : C code will not see payload change. --payload args take only payloads known to C code and cause error if unknown. +-- arg: pattern - substring for search inside reasm_data or desync.dis.payload +-- arg: payload - set desync.l7payload to this if detected +-- arg: undetected - set desync.l7payload to this if not detected +-- test case : --lua-desync=detect_payload_str:pattern=1234:payload=my --lua-desync=fake:blob=0x1234:payload=my +function detect_payload_str(ctx, desync) + if not desync.arg.pattern then + error("detect_payload_str: missing 'pattern'") + end + local data = desync.reasm_data or desync.dis.payload + local b = data and string.find(data,desync.arg.pattern,1,true) + if b then + DLOG("detect_payload_str: detected '"..(desync.arg.payload or '?').."'") + if desync.arg.payload then desync.l7payload = desync.arg.payload end + else + DLOG("detect_payload_str: not detected '"..(desync.arg.payload or '?').."'") + if desync.arg.undetected then desync.l7payload = desync.arg.undetected end + end +end + + +-- this shim is needed then function is orchestrated. ctx services not available +-- have to emulate cutoff in LUA using connection persistent table track.lua_state +function instance_cutoff_shim(ctx, desync, dir) + if ctx then + instance_cutoff(ctx, dir) + elseif not desync.track then + DLOG("instance_cutoff_shim: cannot cutoff '"..desync.func_instance.."' because conntrack is absent") + else + if not desync.track.lua_state.cutoff_shim then + desync.track.lua_state.cutoff_shim = {} + end + if not desync.track.lua_state.cutoff_shim[desync.func_instance] then + desync.track.lua_state.cutoff_shim[desync.func_instance] = {} + end + if type(dir)=="nil" then + -- cutoff both directions by default + desync.track.lua_state.cutoff_shim[desync.func_instance][true] = true + desync.track.lua_state.cutoff_shim[desync.func_instance][false] = true + else + desync.track.lua_state.cutoff_shim[desync.func_instance][dir] = true + end + if b_debug then DLOG("instance_cutoff_shim: cutoff '"..desync.func_instance.."' in="..tostring(type(dir)=="nil" and true or not dir).." out="..tostring(type(dir)=="nil" or dir)) end + end +end +function cutoff_shim_check(desync) + if not desync.track then + DLOG("cutoff_shim_check: cannot check '"..desync.func_instance.."' cutoff because conntrack is absent") + return false + else + local b=desync.track.lua_state.cutoff_shim and + desync.track.lua_state.cutoff_shim[desync.func_instance] and + desync.track.lua_state.cutoff_shim[desync.func_instance][desync.outgoing] + if b and b_debug then + DLOG("cutoff_shim_check: '"..desync.func_instance.."' "..(desync.outgoing and "out" or "in").." cutoff") + end + return b + end +end + + +-- applies # and $ prefixes. #var means var length, %var means var value +function apply_arg_prefix(desync) + -- prevent double apply + if desync.arg.__prefix_applied then return end + for a,v in pairs(desync.arg) do + local c = string.sub(v,1,1) + if c=='#' then + local blb = blob(desync,string.sub(v,2)) + desync.arg[a] = tostring(type(blb)=='string' and #blb or 0) + elseif c=='%' then + desync.arg[a] = blob(desync,string.sub(v,2)) + elseif c=='\\' then + c = string.sub(v,2,2); + if c=='#' or c=='%' then + desync.arg[a] = string.sub(v,2) + end + end + end + desync.arg.__prefix_applied = true +end +-- copy instance identification and args from execution plan to desync table +-- NOTE : to not lose VERDICT_MODIFY dissect changes pass original desync table +-- NOTE : if a copy was passed and VERDICT_MODIFY returned you must copy modified dissect back to desync table or resend it and return VERDICT_DROP +-- NOTE : args and some fields are substituted. if you need them - make a copy before calling this. +function apply_execution_plan(desync, instance) + desync.func = instance.func + desync.func_n = instance.func_n + desync.func_instance = instance.func_instance + desync.arg = deepcopy(instance.arg) + -- no apply_arg_prefix here because it may refer non-existing blobs +end +-- produce resulting verdict from 2 verdicts +function verdict_aggregate(v1, v2) + v1 = v1 or VERDICT_PASS + v2 = v2 or VERDICT_PASS + local vn = bitor(bitand(v1,VERDICT_PRESERVE_NEXT),bitand(v2,VERDICT_PRESERVE_NEXT)) + local v + v1 = bitand(v1, VERDICT_MASK) + v2 = bitand(v2, VERDICT_MASK) + if v1==VERDICT_DROP or v2==VERDICT_DROP then + v=VERDICT_DROP + elseif v1==VERDICT_MODIFY or v2==VERDICT_MODIFY then + v=VERDICT_MODIFY + else + v=VERDICT_PASS + end + return bitor(v,vn) +end +function plan_instance_execute_preapplied(desync, verdict, instance) + if cutoff_shim_check(desync) then + DLOG("plan_instance_execute: not calling '"..desync.func_instance.."' because of voluntary cutoff") + elseif not payload_match_filter(desync.l7payload, instance.payload_filter) then + DLOG("plan_instance_execute: not calling '"..desync.func_instance.."' because payload '"..desync.l7payload.."' does not match filter '"..instance.payload_filter.."'") + elseif not pos_check_range(desync, instance.range) then + DLOG("plan_instance_execute: not calling '"..desync.func_instance.."' because pos "..pos_str(desync,instance.range.from).." "..pos_str(desync,instance.range.to).." is out of range '"..pos_range_str(instance.range).."'") + else + -- condition is satisfied. here blobs must be referenced + apply_arg_prefix(desync) + desync.arg.__prefix_applied = nil + DLOG("plan_instance_execute: calling '"..desync.func_instance.."'") + verdict = verdict_aggregate(verdict,_G[instance.func](nil, desync)) + end + return verdict +end +function plan_instance_execute(desync, verdict, instance) + apply_execution_plan(desync, instance) + return plan_instance_execute_preapplied(desync,verdict,instance) +end +function plan_instance_pop(desync) + return (desync.plan and #desync.plan>0) and table.remove(desync.plan, 1) or nil +end +function plan_clear(desync, max) + if max then + local n=0 + while n=max then + DLOG("replay_execution_plan: reached max instances limit "..max) + end + return verdict +end +-- this function demonstrates how to stop execution of upcoming desync instances and take over their job +-- this can be used, for example, for orchestrating conditional processing without modifying of desync functions code +-- test case : --lua-desync=desync_orchestrator_example --lua-desync=pass --lua-desync=pass +function desync_orchestrator_example(ctx, desync) + DLOG("orchestrator: taking over upcoming desync instances") + orchestrate(ctx, desync) + return replay_execution_plan(desync) +end + +-- if seq is over 2G s and p position comparision can be wrong +function pos_counter_overflow(desync, mode, reverse) + if not desync.track or (mode~='s' and mode~='p') then return false end + local track_pos = reverse and desync.track.pos.reverse or desync.track.pos.direct + return track_pos.tcp and track_pos.tcp.rseq_over_2G +end +-- these functions duplicate range check logic from C code +-- mode must be n,d,b,s,x,a +-- pos is {mode,pos} +-- range is {from={mode,pos}, to={mode,pos}, upper_cutoff} +-- upper_cutoff = true means non-inclusive upper boundary +function pos_get_pos(track_pos, mode) + if track_pos then + if mode=='n' then + return track_pos.pcounter + elseif mode=='d' then + return track_pos.pdcounter + elseif mode=='b' then + return track_pos.pbcounter + elseif track_pos.tcp then + if mode=='s' then + return track_pos.tcp.rseq + elseif mode=='p' then + return track_pos.tcp.pos + end + end + end + return 0 +end +function pos_get(desync, mode, reverse) + if desync.track then + local track_pos = reverse and desync.track.pos.reverse or desync.track.pos.direct + return pos_get_pos(track_pos,mode) + end + return 0 +end +function pos_check_from(desync, range) + if range.from.mode == 'x' or pos_counter_overflow(desync, range.from.mode) then return false end + if range.from.mode ~= 'a' then + if desync.track then + return pos_get(desync, range.from.mode) >= range.from.pos + else + return false + end + end + return true; +end +function pos_check_to(desync, range) + local ps + if range.to.mode == 'x' or pos_counter_overflow(desync, range.to.mode) then return false end + if range.to.mode ~= 'a' then + if desync.track then + ps = pos_get(desync, range.to.mode) + return (ps < range.to.pos) or not range.upper_cutoff and (ps == range.to.pos) + else + return false + end + end + return true; +end +function pos_check_range(desync, range) + return pos_check_from(desync,range) and pos_check_to(desync,range) +end +function pos_range_str(range) + return range.from.mode..range.from.pos..(range.upper_cutoff and '<' or '-')..range.to.mode..range.to.pos +end +function pos_str(desync, pos) + return pos.mode..pos_get(desync, pos.mode) +end + + +-- convert array a to packed string using 'packer' function. only numeric indexes starting from 1, order preserved +function barray(a, packer) + if a then + local sa={} + for i=1,#a do + sa[i] = packer(a[i]) + end + return table.concat(sa) + end +end +-- convert table a to packed string using 'packer' function. any indexes, any order +function btable(a, packer) + if a then + local sa={} + local i=1 + for k,v in pairs(a) do + sa[i] = packer(v) + i=i+1 + end + return table.concat(sa) + end +end +-- sequence comparision functions. they work only within 2G interval +-- seq1>=seq2 +function seq_ge(seq1, seq2) + return 0==bitand(u32add(seq1, -seq2), 0x80000000) +end +-- seq1>seq2 +function seq_gt(seq1, seq2) + return seq1~=seq2 and seq_ge(seq1, seq2) +end +-- seq11 then + ss = ss .. " " + end + ss = ss .. string.format("%02X", string.byte(s, i)) + end + return ss +end +function has_nonprintable(s) + return s:match("[^ -\r\n\t]") +end +function make_readable(v) + if type(v)=="string" then + return string.gsub(v,"[^ -]","."); + else + return tostring(v) + end +end +-- return hex dump of a binary string if it has nonprintable characters or string itself otherwise +function str_or_hex(s) + if has_nonprintable(s) then + return string2hex(s) + else + return s + end +end +function logical_xor(a,b) + return a and not b or not a and b +end +-- print to DLOG any variable. tables are expanded in the tree form, unprintables strings are hex dumped +function var_debug(v) + local function dbg(v,level) + if type(v)=="table" then + for key, value in pairs(v) do + DLOG(string.rep(" ",2*level).."."..tostring(key)) + dbg(v[key],level+1) + end + elseif type(v)=="string" then + DLOG(string.rep(" ",2*level)..type(v).." "..str_or_hex(v)) + else + DLOG(string.rep(" ",2*level)..type(v).." "..make_readable(v)) + end + end + dbg(v,0) +end + +-- make hex dump +function hexdump(s, max) + if not s then return nil end + local l = max<#s and max or #s + local ss = string.sub(s,1,l) + return string2hex(ss)..(#s>max and " ... " or " " )..make_readable(ss)..(#s>max and " ... " or "" ) +end +-- make hex dump limited by HEXDUMP_DLOG_MAX chars +function hexdump_dlog(s) + return hexdump(s,HEXDUMP_DLOG_MAX) +end + +-- make copy of an array recursively +function deepcopy(orig, copies) + copies = copies or {} + local orig_type = type(orig) + local copy + if orig_type == 'table' then + if copies[orig] then + copy = copies[orig] + else + copy = {} + copies[orig] = copy + for orig_key, orig_value in next, orig, nil do + copy[deepcopy(orig_key, copies)] = deepcopy(orig_value, copies) + end + setmetatable(copy, deepcopy(getmetatable(orig), copies)) + end + else -- number, string, boolean, etc + copy = orig + end + return copy +end + +-- check if string 'v' in comma separated list 's' +function in_list(s, v) + if s then + for elem in string.gmatch(s, "[^,]+") do + if elem==v then + return true + end + end + end + return false +end + +function blob_exist(desync, name) + return name and (string.sub(name,1,2)=="0x" or _G[name] or desync[name]) +end +-- blobs can be 0xHEX, field name in desync or global var +-- if name is nil - return def +function blob(desync, name, def) + if not name or #name==0 then + if def then + return def + else + error("empty blob name") + end + end + local blob + if string.sub(name,1,2)=="0x" then + blob = parse_hex(string.sub(name,3)) + if not blob then + error("invalid hex string : "..name) + end + else + blob = desync[name] + if not blob then + -- use global var if no field in dissect table + blob = _G[name] + if not blob then + error("blob '"..name.."' unavailable") + end + end + blob = tostring(blob) + end + return blob +end +function blob_or_def(desync, name, def) + return name and blob(desync,name,def) or def +end + +-- repeat pattern as needed to extract part of it with any length +-- pat="12345" len=10 offset=4 => "4512345123" +function pattern(pat, offset, len) + if not pat or #pat==0 then + error("pattern: bad or empty pattern") + end + local off = (offset-1) % #pat + local pats = divint((len + #pat - 1), #pat) + (off==0 and 0 or 1) + return string.sub(string.rep(pat,pats),off+1,off+len) +end + +-- decrease by 1 all number values in the array +function zero_based_pos(a) + if not a then return nil end + local b={} + for i,v in ipairs(a) do + b[i] = type(a[i])=="number" and a[i] - 1 or a[i] + end + return b +end + +-- delete elements with number value 1 +function delete_pos_1(a) + local i=1 + while i<=#a do + if type(a[i])=="number" and a[i] == 1 then + table.remove(a,i) + else + i = i+1 + end + end + return a +end + +-- linear search array a for a[index]==v. return index +function array_search(a, v) + for k,val in pairs(a) do + if val==v then + return k + end + end +end +-- linear search array a for a[index].f==v. return index +function array_field_search(a, f, v) + for k,val in pairs(a) do + if type(val)=="table" and val[f]==v then + return k + end + end +end + +-- find pos of the next eol and pos of the next non-eol character after eol +function find_next_line(s, pos) + local p1, p2 + p1 = string.find(s,"[\r\n]",pos) + if p1 then + p2 = p1 + p1 = p1-1 + if string.sub(s,p2,p2)=='\r' then p2=p2+1 end + if string.sub(s,p2,p2)=='\n' then p2=p2+1 end + if p2>#s then p2=nil end + else + p1 = #s + end + return p1,p2 +end + + +-- support sni=%var +function tls_mod_shim(desync, blob, modlist, payload) + local p1,p2 = string.find(modlist,"sni=%%[^,]+") + if p1 then + local var = string.sub(modlist,p1+5,p2) + local val = desync[var] or _G[var] + if not val then + error("tls_mod_shim: non-existent var '"..var.."'") + end + modlist = string.sub(modlist,1,p1+3)..tostring(val)..string.sub(modlist,p2+1) + end + return tls_mod(blob,modlist,payload) +end + +-- convert comma separated list of tcp flags to tcp.th_flags bit field +function parse_tcp_flags(s) + local flags={FIN=TH_FIN, SYN=TH_SYN, RST=TH_RST, PSH=TH_PUSH, PUSH=TH_PUSH, ACK=TH_ACK, URG=TH_URG, ECE=TH_ECE, CWR=TH_CWR} + local f=0 + local s_upper = string.upper(s) + for flag in string.gmatch(s_upper, "[^,]+") do + if flags[flag] then + f = bitor(f,flags[flag]) + else + error("tcp flag '"..flag.."' is invalid") + end + end + return f +end + +-- get ip protocol from l3 headers +function ip_proto_l3(dis) + if dis.ip then + return dis.ip.ip_p + elseif dis.ip6 then + return #dis.ip6.exthdr==0 and dis.ip6.ip6_nxt or dis.ip6.exthdr[#dis.ip6.exthdr].next + end +end +-- get ip protocol from l4 headers +function ip_proto_l4(dis) + if dis.tcp then + return IPPROTO_TCP + elseif dis.udp then + return IPPROTO_UDP + elseif dis.ip then + return dis.icmp and IPPROTO_ICMP or nil + elseif dis.ip6 then + return dis.icmp and IPPROTO_ICMPV6 or nil + end +end +function ip_proto(dis) + return ip_proto_l4(dis) or ip_proto_l3(dis) +end +-- discover ip protocol and fix "next" fields +function fix_ip_proto(dis, proto) + local pr = proto or ip_proto(dis) + if pr then + if dis.ip then + dis.ip.ip_p = pr + elseif dis.ip6 then + fix_ip6_next(dis.ip6, pr) + end + end +end + +-- find first tcp options of specified kind in dissect.tcp.options +function find_tcp_option(options, kind) + if options then + for i, opt in ipairs(options) do + if opt.kind==kind then return i end + end + end + return nil +end + +-- find first ipv6 extension header of specified protocol in dissect.ip6.exthdr +function find_ip6_exthdr(exthdr, proto) + if exthdr then + for i, hdr in ipairs(exthdr) do + if hdr.type==proto then return i end + end + end + return nil +end + +-- insert ipv6 extension header at specified index. fix next proto chain +function insert_ip6_exthdr(ip6, idx, header_type, data) + local prev + if not ip6.exthdr then ip6.exthdr={} end + if not idx then + -- insert to the end + idx = #ip6.exthdr+1 + elseif idx<0 or idx>(#ip6.exthdr+1) then + error("insert_ip6_exthdr: invalid index "..idx) + end + if idx==1 then + prev = ip6.ip6_nxt + ip6.ip6_nxt = header_type + else + prev = ip6.exthdr[idx-1].next + ip6.exthdr[idx-1].next = header_type + end + table.insert(ip6.exthdr, idx, {type = header_type, data = data, next = prev}) +end +-- delete ipv6 extension header at specified index. fix next proto chain +function del_ip6_exthdr(ip6, idx) + if idx<=0 or idx>#ip6.exthdr then + error("delete_ip6_exthdr: nonexistent index "..idx) + end + local nxt = ip6.exthdr[idx].next + if idx==1 then + ip6.ip6_nxt = nxt + else + ip6.exthdr[idx-1].next = nxt + end + table.remove(ip6.exthdr, idx) +end +-- fills next proto fields in ipv6 header and extension headers +function fix_ip6_next(ip6, last_proto) + if ip6.exthdr and #ip6.exthdr>0 then + for i=1,#ip6.exthdr do + if i==1 then + -- first header + ip6.ip6_nxt = ip6.exthdr[i].type + end + ip6.exthdr[i].next = i==#ip6.exthdr and (last_proto or IPPROTO_NONE) or ip6.exthdr[i+1].type + end + else + -- no headers + ip6.ip6_nxt = last_proto or IPPROTO_NONE + end +end + +function dis_ipsrc(dis) + if dis.ip then + return dis.ip.ip_src + elseif dis.ip6 then + return dis.ip6.ip6_src + end +end +function dis_ipdst(dis) + if dis.ip then + return dis.ip.ip_dst + elseif dis.ip6 then + return dis.ip6.ip6_dst + end +end + +function dis_l4_name(dis) + local l4 + if dis.tcp then + l4="tcp" + elseif dis.udp then + l4="udp" + elseif dis.icmp then + l4="icmp" + else + l4="raw"..ip_proto_l3(dis) + end + return l4 +end +function dis_l4_ports(dis) + local p1,p2 + if dis.tcp then + p1=dis.tcp.th_sport + p2=dis.tcp.th_dport + elseif dis.udp then + p1=dis.udp.uh_sport + p2=dis.udp.uh_dport + elseif dis.icmp then + p1=dis.icmp.icmp_type + p2=dis.icmp.icmp_code + end + return p1 and (p1..":"..p2) or "?" +end + +function dis_timer_name(dis) + return table.concat({ntop(dis_ipsrc(dis)),"->",ntop(dis_ipdst(dis)),"_",dis_l4_name(dis),"_",dis_l4_ports(dis)}) +end +function desync_timer_name(desync) + local name = desync.func_instance.."_"..dis_timer_name(desync.dis) + if desync.track then + name = name.."_n"..desync.track.pos.direct.pcounter + else + name = name.."_"..brandom_az09(10) + end + return name +end + + +-- reverses ip addresses, ports and seq/ack +function dis_reverse(dis) + if dis.ip then + dis.ip.ip_src, dis.ip.ip_dst = dis.ip.ip_dst, dis.ip.ip_src + end + if dis.ip6 then + dis.ip6.ip6_src, dis.ip6.ip6_dst = dis.ip6.ip6_dst, dis.ip6.ip6_src + end + if dis.tcp then + dis.tcp.th_sport, dis.tcp.th_dport = dis.tcp.th_dport, dis.tcp.th_sport + dis.tcp.th_ack, dis.tcp.th_seq = dis.tcp.th_seq, dis.tcp.th_ack + end + if dis.udp then + dis.udp.uh_sport, dis.udp.uh_dport = dis.udp.uh_dport, dis.udp.uh_sport + end +end + +function dis_reconstruct_l3(dis, options) + if dis.ip then + return csum_ip4_fix(reconstruct_iphdr(dis.ip)) + elseif dis.ip6 then + return reconstruct_ip6hdr(dis.ip6, options) + end +end + +-- parse autottl : delta,min-max +function parse_autottl(s) + if s then + local delta,min,max = string.match(s,"([-+]?%d+),(%d+)-(%d+)") + min = tonumber(min) + max = tonumber(max) + delta = tonumber(delta) + if not delta or min>max then + error("parse_autottl: invalid value '"..s.."'") + end + return {delta=delta,min=min,max=max} + else + return nil + end +end + +-- calculate ttl value based on incoming_ttl and parsed attl definition (delta,min-max) +function autottl(incoming_ttl, attl) + local function hop_count_guess(incoming_ttl) + -- 18.65.168.125 ( cloudfront ) 255 + -- 157.254.246.178 128 + -- 1.1.1.1 64 + -- guess original ttl. consider path lengths less than 32 hops + + local orig + + if incoming_ttl>223 then + orig=255 + elseif incoming_ttl<=128 and incoming_ttl>96 then + orig=128 + elseif incoming_ttl<=64 and incoming_ttl>32 then + orig=64 + else + return nil + end + + return orig-incoming_ttl + end + -- return guessed fake ttl value. 0 means unsuccessfull, should not perform autottl fooling + local function autottl_eval(hop_count, attl) + local d,fake + + d = hop_count + attl.delta + + if dattl.max then fake=attl.max + else fake=d + end + + if attl.delta<0 and fake>=hop_count or attl.delta>=0 and fake - set tcp flags in comma separated list +-- tcp_flags_unset= - unset tcp flags in comma separated list +-- tcp_ts_up - move timestamp tcp option to the top if it's present. this allows linux not to accept badack segments without badseq. this is very strange discovery but it works. +-- tcp_nop_del - delete NOP tcp options to free space in tcp header + +-- fool - custom fooling function : fool_func(dis, fooling_options) +function apply_fooling(desync, dis, fooling_options) + local function prepare_bin(hex,def) + local bin = parse_hex(hex) + if not bin then error("apply_fooling: invalid hex string '"..hex.."'") end + return #bin>0 and bin or def + end + local function ttl_discover(arg_ttl,arg_autottl) + local ttl + if arg_autottl and desync.track then + if desync.track.incoming_ttl then + -- use lua_cache to store discovered autottl + if type(desync.track.lua_state.autottl_cache)~="table" then desync.track.lua_state.autottl_cache={} end + if type(desync.track.lua_state.autottl_cache[desync.func_instance])~="table" then desync.track.lua_state.autottl_cache[desync.func_instance]={} end + if not desync.track.lua_state.autottl_cache[desync.func_instance].autottl_found then + local attl = parse_autottl(arg_autottl) + if not attl then + error("apply_fooling: invalid autottl value '"..arg_autottl.."'") + end + desync.track.lua_state.autottl_cache[desync.func_instance].autottl = autottl(desync.track.incoming_ttl,attl) + if desync.track.lua_state.autottl_cache[desync.func_instance].autottl then + desync.track.lua_state.autottl_cache[desync.func_instance].autottl_found = true + DLOG("apply_fooling: discovered autottl "..desync.track.lua_state.autottl_cache[desync.func_instance].autottl) + else + DLOG("apply_fooling: could not discover autottl") + end + elseif desync.track.lua_state.autottl_cache[desync.func_instance].autottl then + DLOG("apply_fooling: using cached autottl "..desync.track.lua_state.autottl_cache[desync.func_instance].autottl) + end + ttl=desync.track.lua_state.autottl_cache[desync.func_instance].autottl + else + DLOG("apply_fooling: cannot apply autottl because incoming ttl unknown") + end + end + if not ttl and arg_ttl then + ttl = tonumber(arg_ttl) + if not ttl or ttl<0 or ttl>255 then + error("apply_fooling: ip_ttl and ip6_ttl require valid value") + end + end + --io.stderr:write("TTL "..tostring(ttl).."\n") + return ttl + end + local function move_ts_top() + local tsidx = find_tcp_option(dis.tcp.options, TCP_KIND_TS) + if tsidx and tsidx>1 then + table.insert(dis.tcp.options, 1, dis.tcp.options[tsidx]) + table.remove(dis.tcp.options, tsidx + 1) + end + end + -- take default fooling from desync.arg + if not fooling_options then fooling_options = desync.arg end + -- use current packet if dissect not given + if not dis then dis = desync.dis end + if dis.tcp then + if fooling_options.tcp_seq then + if tonumber(fooling_options.tcp_seq) then + dis.tcp.th_seq = u32add(dis.tcp.th_seq, fooling_options.tcp_seq) + else + error("apply_fooling: tcp_seq requires increment parameter. there's no default value.") + end + end + if fooling_options.tcp_ack then + if tonumber(fooling_options.tcp_ack) then + dis.tcp.th_ack = u32add(dis.tcp.th_ack, fooling_options.tcp_ack) + else + error("apply_fooling: tcp_ack requires increment parameter. there's no default value.") + end + end + if fooling_options.tcp_flags_unset then + dis.tcp.th_flags = bitand(dis.tcp.th_flags, bitnot(parse_tcp_flags(fooling_options.tcp_flags_unset))) + end + if fooling_options.tcp_flags_set then + dis.tcp.th_flags = bitor(dis.tcp.th_flags, parse_tcp_flags(fooling_options.tcp_flags_set)) + end + if fooling_options.tcp_nop_del then + for i=#dis.tcp.options,1,-1 do + if dis.tcp.options[i].kind==TCP_KIND_NOOP then + table.remove(dis.tcp.options,i) + end + end + end + if fooling_options.tcp_ts then + if tonumber(fooling_options.tcp_ts) then + local idx = find_tcp_option(dis.tcp.options,TCP_KIND_TS) + if idx and (dis.tcp.options[idx].data and #dis.tcp.options[idx].data or 0)==8 then + dis.tcp.options[idx].data = bu32(u32add(u32(dis.tcp.options[idx].data),fooling_options.tcp_ts))..string.sub(dis.tcp.options[idx].data,5) + else + DLOG("apply_fooling: timestamp tcp option not present or invalid") + end + else + error("apply_fooling: tcp_ts requires increment parameter. there's no default value.") + end + end + if fooling_options.tcp_md5 then + if find_tcp_option(dis.tcp.options,TCP_KIND_MD5) then + DLOG("apply_fooling: md5 option already present") + else + table.insert(dis.tcp.options,{kind=TCP_KIND_MD5, data=prepare_bin(fooling_options.tcp_md5,brandom(16))}) + end + end + if fooling_options.tcp_ts_up then + move_ts_top() + end + end + if dis.ip6 then + local bin + if fooling_options.ip6_hopbyhop then + bin = prepare_bin(fooling_options.ip6_hopbyhop,"\x00\x00\x00\x00\x00\x00") + insert_ip6_exthdr(dis.ip6,1,IPPROTO_HOPOPTS,bin) + end + if fooling_options.ip6_hopbyhop2 then + bin = prepare_bin(fooling_options.ip6_hopbyhop2,"\x00\x00\x00\x00\x00\x00") + insert_ip6_exthdr(dis.ip6,1,IPPROTO_HOPOPTS,bin) + end + -- for possible unfragmentable part + if fooling_options.ip6_destopt then + bin = prepare_bin(fooling_options.ip6_destopt,"\x00\x00\x00\x00\x00\x00") + insert_ip6_exthdr(dis.ip6,nil,IPPROTO_DSTOPTS,bin) + end + if fooling_options.ip6_routing then + bin = prepare_bin(fooling_options.ip6_routing,"\x00\x00\x00\x00\x00\x00") + insert_ip6_exthdr(dis.ip6,nil,IPPROTO_ROUTING,bin) + end + -- for possible fragmentable part + if fooling_options.ip6_destopt2 then + bin = prepare_bin(fooling_options.ip6_destopt2,"\x00\x00\x00\x00\x00\x00") + insert_ip6_exthdr(dis.ip6,nil,IPPROTO_DSTOPTS,bin) + end + if fooling_options.ip6_ah then + -- by default truncated authentication header - only 6 bytes + bin = prepare_bin(fooling_options.ip6_ah,"\x00\x00"..brandom(4)) + insert_ip6_exthdr(dis.ip6,nil,IPPROTO_AH,bin) + end + end + if dis.ip then + local ttl = ttl_discover(fooling_options.ip_ttl,fooling_options.ip_autottl) + if ttl then dis.ip.ip_ttl = ttl end + end + if dis.ip6 then + local ttl = ttl_discover(fooling_options.ip6_ttl,fooling_options.ip6_autottl) + if ttl then dis.ip6.ip6_hlim = ttl end + end + + if fooling_options.fool and #fooling_options.fool>0 then + if type(_G[fooling_options.fool])=="function" then + DLOG("apply_fooling: calling '"..fooling_options.fool.."'") + _G[fooling_options.fool](dis, fooling_options) + else + error("apply_fooling: fool function '"..tostring(fooling_options.fool).."' does not exist") + end + end +end + + +-- assign dis.ip.ip_id value according to policy in ipid_options or desync.arg. apply def or "seq" policy if no ip_id options +-- ip_id=seq|rnd|zero|none +-- ip_id_conn - in 'seq' mode save current ip_id in track.lua_state to use it between packets +-- remember ip_id in desync +function apply_ip_id(desync, dis, ipid_options, def) + -- use current packet if dissect not given + if not dis then dis = desync.dis end + if dis.ip then -- ip_id is ipv4 only, ipv6 doesn't have it + -- take default ipid options from desync.arg + if not ipid_options then ipid_options = desync.arg end + local mode = ipid_options.ip_id or def or "seq" + if mode == "seq" then + if desync.track and ipid_options.ip_id_conn then + dis.ip.ip_id = desync.track.lua_state.ip_id or dis.ip.ip_id + desync.track.lua_state.ip_id = dis.ip.ip_id + 1 + else + dis.ip.ip_id = desync.ip_id or dis.ip.ip_id + desync.ip_id = dis.ip.ip_id + 1 + end + elseif mode == "zero" then + dis.ip.ip_id = 0 + elseif mode == "rnd" then + dis.ip.ip_id = math.random(1,0xFFFF) + end + end +end + + +-- return length of ipv4 or ipv6 header without options and extension headers. should be 20 for ipv4 and 40 for ipv6. +function l3_base_len(dis) + if dis.ip then + return IP_BASE_LEN + elseif dis.ip6 then + return IP6_BASE_LEN + else + return 0 + end +end +-- return length of ipv4 options or summary length of all ipv6 extension headers +-- ip6_exthdr_last_idx - count lengths for headers up to this index +function l3_extra_len(dis, ip6_exthdr_last_idx) + local l=0 + if dis.ip then + if dis.ip.options then + l = bitand(#dis.ip.options+3,NOT3) + end + elseif dis.ip6 and dis.ip6.exthdr then + local ct + if ip6_exthdr_last_idx and ip6_exthdr_last_idx>=0 and ip6_exthdr_last_idx<=#dis.ip6.exthdr then + ct = ip6_exthdr_last_idx + else + ct = #dis.ip6.exthdr + end + for i=1, ct do + if dis.ip6.exthdr[i].type == IPPROTO_AH then + -- length in 32-bit words + l = l + bitand(3+2+#dis.ip6.exthdr[i].data,NOT3) + else + -- length in 64-bit words + l = l + bitand(7+2+#dis.ip6.exthdr[i].data,NOT7) + end + end + end + return l +end +-- return length of ipv4/ipv6 header with options/extension headers +function l3_len(dis) + return l3_base_len(dis)+l3_extra_len(dis) +end +-- return length of tcp/udp headers without options. should be 20 for tcp and 8 for udp. +function l4_base_len(dis) + if dis.tcp then + return TCP_BASE_LEN + elseif dis.udp then + return UDP_BASE_LEN + elseif dis.icmp then + return ICMP_BASE_LEN + else + return 0 + end +end +-- return length of tcp options or 0 if not tcp +function l4_extra_len(dis) + local l=0 + if dis.tcp and dis.tcp.options then + for i=1, #dis.tcp.options do + l = l + 1 + if dis.tcp.options[i].kind~=TCP_KIND_NOOP and dis.tcp.options[i].kind~=TCP_KIND_END then + l = l + 1 + if dis.tcp.options[i].data then l = l + #dis.tcp.options[i].data end + end + end + -- 4 byte aligned + l = bitand(3+l,NOT3) + end + return l +end +-- return length of tcp header with options or base length of udp header - 8 bytes +function l4_len(dis) + return l4_base_len(dis)+l4_extra_len(dis) +end +-- return summary extra length of ipv4/ipv6 and tcp headers. 0 if no options, no ext headers +function l3l4_extra_len(dis) + return l3_extra_len(dis)+l4_extra_len(dis) +end +-- return summary length of ipv4/ipv6 and tcp/udp headers +function l3l4_len(dis) + return l3_len(dis)+l4_len(dis) +end +-- return summary length of ipv4/ipv6 , tcp/udp headers and payload +function packet_len(dis) + return l3l4_len(dis) + #dis.payload +end + +-- option : ipfrag.ipfrag_disorder - send fragments from last to first +function rawsend_dissect_ipfrag(dis, options) + if options and options.ipfrag and options.ipfrag.ipfrag and not dis.frag then + local frag_func = options.ipfrag.ipfrag=="" and "ipfrag2" or options.ipfrag.ipfrag + if type(_G[frag_func]) ~= "function" then + error("rawsend_dissect_ipfrag: ipfrag function '"..tostring(frag_func).."' does not exist") + end + local fragments = _G[frag_func](dis, options.ipfrag) + + -- allow ipfrag function to do extheader magic with non-standard "next protocol" + -- NOTE : dis.ip6 must have valid next protocol fields !!!!! + local reconstruct_frag = options.reconstruct and deepcopy(options.reconstruct) or {} + reconstruct_frag.ip6_preserve_next = true + + if fragments then + if options.ipfrag.ipfrag_disorder then + for i=#fragments,1,-1 do + DLOG("sending ip fragment "..i) + -- C function + if not rawsend_dissect(fragments[i], options.rawsend, reconstruct_frag) then return false end + end + else + for i, d in ipairs(fragments) do + DLOG("sending ip fragment "..i) + -- C function + if not rawsend_dissect(d, options.rawsend, reconstruct_frag) then return false end + end + end + return true + end + -- ipfrag failed. send unfragmented + end + -- C function + return rawsend_dissect(dis, options and options.rawsend, options and options.reconstruct) +end + +-- send dissect with tcp segmentation based on mss value. appply specified rawsend options. +function rawsend_dissect_segmented(desync, dis, mss, options) + dis = dis or desync.dis + local discopy = deepcopy(dis) + options = options or desync_opts(desync) + apply_fooling(desync, discopy, options and options.fooling) + + if dis.tcp then + mss = mss or desync.tcp_mss + local extra_len = l3l4_extra_len(discopy) + if extra_len >= mss then return false end + local max_data = mss - extra_len + local urp = dis.tcp.th_urp + local oob = bitand(dis.tcp.th_flags, TH_URG)~=0 + if #discopy.payload > max_data then + local pos=1 + local len + local payload=discopy.payload + while pos <= #payload do + len = #payload - pos + 1 + if len > max_data then len = max_data end + if oob then + if urp==0 and pos==1 then + discopy.tcp.th_flags = bitor(discopy.tcp.th_flags, TH_URG) + elseif urp>=pos and urp<(pos+len) then + discopy.tcp.th_flags = bitor(discopy.tcp.th_flags, TH_URG) + discopy.tcp.th_urp = urp-pos+1 + else + discopy.tcp.th_flags = bitand(discopy.tcp.th_flags, bitnot(TH_URG)) + discopy.tcp.th_urp = 0 + end + end + discopy.payload = string.sub(payload,pos,pos+len-1) + apply_ip_id(desync, discopy, options and options.ipid) + if not rawsend_dissect_ipfrag(discopy, options) then + -- stop if failed + return false + end + discopy.tcp.th_seq = u32add(discopy.tcp.th_seq, len) + pos = pos + len + end + return true + end + end + apply_ip_id(desync, discopy, options and options.ipid) + -- no reason to segment + return rawsend_dissect_ipfrag(discopy, options) +end + +-- send specified payload based on existing L3/L4 headers in the dissect. add seq to tcp.th_seq. +function rawsend_payload_segmented(desync, payload, seq, options) + -- save some cpu and ram + local dis = (payload or seq and seq~=0) and deepcopy(desync.dis) or desync.dis + if payload then dis.payload = payload end + if dis.tcp and seq then + dis.tcp.th_seq = dis.tcp.th_seq + seq + end + return rawsend_dissect_segmented(desync, dis, nil, options) +end + + +-- check if desync.outgoing comply with arg.dir or def if it's not present or "out" of they are not present both. dir can be "in","out","any" +function direction_check(desync, def) + local dir = desync.arg.dir or def or "out" + return desync.outgoing and dir~="in" or not desync.outgoing and dir~="out" +end +-- if dir "in" or "out" cutoff current desync function from opposite direction +function direction_cutoff_opposite(ctx, desync, def) + local dir = desync.arg.dir or def or "out" + if dir=="out" then + -- cutoff in + instance_cutoff_shim(ctx, desync, false) + elseif dir=="in" then + -- cutoff out + instance_cutoff_shim(ctx, desync, true) + end +end + +-- return true if l7payload matches filter l7payload_filter - comma separated list of payload types +function payload_match_filter(l7payload, l7payload_filter, def) + local argpl = l7payload_filter or def or "known" + local neg = string.sub(argpl,1,1)=="~" + local pl = neg and string.sub(argpl,2) or argpl + return neg ~= (in_list(pl, "all") or in_list(pl, l7payload) or in_list(pl, "known") and l7payload~="unknown" and l7payload~="empty") +end +-- check if desync payload type comply with payload type list in arg.payload +-- if arg.payload is not present - check for known payload - not empty and not unknown (nfqws1 behavior without "--desync-any-protocol" option) +-- if arg.payload is prefixed with '~' - it means negation +function payload_check(desync, def) + local b = payload_match_filter(desync.l7payload, desync.arg.payload, def) + if not b and b_debug then + local argpl = desync.arg.payload or def or "known" + DLOG("payload_check: payload '"..desync.l7payload.."' does not pass '"..argpl.."' filter") + end + return b +end + +-- return name of replay drop field in track.lua_state for the current desync function instance +function replay_drop_key(desync) + return desync.func_instance .. "_replay_drop" +end +-- set/unset replay drop flag in track.lua_state for the current desync function instance +function replay_drop_set(desync, v) + if desync.track then + if v == nil then v=true end + local rdk = replay_drop_key(desync) + if v then + if desync.replay then desync.track.lua_state[rdk] = true end + else + desync.track.lua_state[rdk] = nil + end + end +end +-- auto unset replay drop flag if desync is not replay or it's the last replay piece +-- return true if the caller should return VERDICT_DROP +function replay_drop(desync) + if desync.track then + local drop = desync.replay and desync.track.lua_state[replay_drop_key(desync)] + if not desync.replay or desync.replay_piece_last then + -- replay stopped or last piece of reasm + replay_drop_set(desync, false) + end + if drop then + DLOG("dropping replay packet because reasm was already sent") + return true + end + end + return false +end +-- true if desync is not replay or it's the first replay piece +function replay_first(desync) + return not desync.replay or desync.replay_piece==1 +end + +-- generate random host +-- template "google.com", len=16 : h82aj.google.com +-- template "google.com", len=11 : .google.com +-- template "google.com", len=10 : google.com +-- template "google.com", len=7 : gle.com +-- no template, len=6 : b8c54a +-- no template, len=7 : u9a.edu +-- no template, len=10 : jgha7c.com +function genhost(len, template) + if template and #template>0 then + if len <= #template then + return string.sub(template,#template-len+1) + elseif len==(#template+1) then + return "."..template + else + return brandom_az(1)..brandom_az09(len-#template-2).."."..template + end + else + if len>=7 then + local tlds = {"com","org","net","edu","gov","biz"} + local tld = tlds[math.random(#tlds)] + return brandom_az(1)..brandom_az09(len-#tld-1-1).."."..tld + else + return brandom_az(1)..brandom_az09(len-1) + end + end +end + +-- return ip addr of target host in text form +function host_ip(desync) + return desync.target.ip and ntop(desync.target.ip) or desync.target.ip6 and ntop(desync.target.ip6) +end +-- return hostname of target host if present or ip address in text form otherwise +function host_or_ip(desync) + if desync.track and desync.track.hostname then + return desync.track.hostname + end + return host_ip(desync) +end + +-- rate limited update of global ifaddrs +function update_ifaddrs() + if ifaddrs then + local now = os.time() + if not ifaddrs_last then ifaddrs_last = now end + if ifaddrs_last~=now then + ifaddrs = get_ifaddrs() + ifaddrs_last = now + end + else + ifaddrs = get_ifaddrs() + end +end +-- search ifaddrs for ip and return interface name or nil if not found +-- do not call get_ifaddrs too often to avoid overhead +function ip2ifname(ip) + update_ifaddrs() + if not ifaddrs then return nil end + for ifname,ifinfo in pairs(ifaddrs) do + if array_field_search(ifinfo.addr, "addr", ip) then + return ifname + end + end +end + +function is_absolute_path(path) + if string.sub(path,1,1)=='/' then return true end + local un = uname() + return string.sub(un.sysname,1,6)=="CYGWIN" and string.sub(path,2,2)==':' +end +function append_path(path,file) + return string.sub(path,#path,#path)=='/' and path..file or path.."/"..file +end +function writable_file_name(filename) + if is_absolute_path(filename) then return filename end + local writedir = os.getenv("WRITABLE") + if not writedir then return filename end + return append_path(writedir, filename) +end + +-- arg : wsize=N . tcp window size +-- arg : scale=N . tcp option scale factor +-- return : true of changed anything +function wsize_rewrite(dis, arg) + local b = false + if arg.wsize then + local wsize = tonumber(arg.wsize) + DLOG("wsize_rewrite: window size "..dis.tcp.th_win.." => "..wsize) + dis.tcp.th_win = tonumber(arg.wsize) + b = true + end + if arg.scale then + local scale = tonumber(arg.scale) + local i = find_tcp_option(dis.tcp.options, TCP_KIND_SCALE) + if i then + local oldscale = u8(dis.tcp.options[i].data) + if scale>oldscale then + DLOG("wsize_rewrite: not increasing scale factor") + elseif scale "..scale) + dis.tcp.options[i].data = bu8(scale) + b = true + end + end + end + return b +end + +-- standard fragmentation to 2 ip fragments +-- function returns 2 dissects with fragments +-- option : ipfrag_pos_udp - udp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 8 +-- option : ipfrag_pos_tcp - tcp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 32 +-- option : ipfrag_pos_icmp - icmp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 8 +-- option : ipfrag_pos - icmp frag position for other L4. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 32 +-- option : ipfrag_next - next protocol field in ipv6 fragment extenstion header of the second fragment. same as first by default. +function ipfrag2(dis, ipfrag_options) + local function frag_idx(exthdr) + -- fragment header after hopbyhop, destopt, routing + -- allow second destopt header to be in fragmentable part + -- test case : --lua-desync=send:ipfrag:ipfrag_pos_tcp=40:ip6_hopbyhop:ip6_destopt:ip6_destopt2 + -- WINDOWS may not send second ipv6 fragment with next protocol 60 (destopt) + -- test case windows : --lua-desync=send:ipfrag:ipfrag_pos_tcp=40:ip6_hopbyhop:ip6_destopt:ip6_destopt2:ipfrag_next=255 + if exthdr then + local first_destopts + for i=1,#exthdr do + if exthdr[i].type==IPPROTO_DSTOPTS then + first_destopts = i + break + end + end + for i=#exthdr,1,-1 do + if exthdr[i].type==IPPROTO_HOPOPTS or exthdr[i].type==IPPROTO_ROUTING or (exthdr[i].type==IPPROTO_DSTOPTS and i==first_destopts) then + return i+1 + end + end + end + return 1 + end + + local pos + local dis1, dis2 + local l3 + + if dis.tcp then + pos = ipfrag_options.ipfrag_pos_tcp or 32 + elseif dis.udp then + pos = ipfrag_options.ipfrag_pos_udp or 8 + elseif dis.icmp then + pos = ipfrag_options.ipfrag_pos_icmp or 8 + else + pos = ipfrag_options.ipfrag_pos or 32 + end + + DLOG("ipfrag2") + + if not pos then + error("ipfrag2: no frag position") + end + l3 = l3_len(dis) + if bitand(pos,7)~=0 then + error("ipfrag2: frag position must be multiple of 8") + end + if (pos+l3)>0xFFFF then + error("ipfrag2: too high frag offset") + end + + local plen = l3 + l4_len(dis) + #dis.payload + if dis.ip then + -- ipv4 frag is done by both lua and C part + -- lua code must correctly set ip_len, IP_MF and ip_off and provide full unfragmented payload + -- ip_len must be set to valid value as it would appear in the fragmented packet + -- ip_off must be set to fragment offset and IP_MF bit must be set if it's not the last fragment + -- C code constructs unfragmented packet then moves everything after ip header according to ip_off and ip_len + + if (pos+l3)>=plen then + DLOG("ipfrag2: ip frag pos "..pos.." exceeds packet length. ipfrag cancelled.") + return nil + end + + -- ip_id must not be zero or fragment will be dropped + local ip_id = dis.ip.ip_id==0 and math.random(1,0xFFFF) or dis.ip.ip_id + dis1 = deepcopy(dis) + -- ip_len holds the whole packet length starting from the ip header. it includes ip, transport headers and payload + dis1.ip.ip_len = l3 + pos -- ip header + first part up to frag pos + dis1.ip.ip_off = IP_MF -- offset 0, IP_MF - more fragments + dis1.ip.ip_id = ip_id + dis2 = deepcopy(dis) + dis2.ip.ip_off = bitrshift(pos,3) -- offset = frag pos, IP_MF - not set + dis2.ip.ip_len = plen - pos -- unfragmented packet length - frag pos + dis2.ip.ip_id = ip_id + end + + if dis.ip6 then + -- ipv6 frag is done by both lua and C part + -- lua code must insert fragmentation extension header at any desirable position, fill fragment offset, more fragments flag and ident + -- lua must set up ip6_plen as it would appear in the fragmented packet + -- C code constructs unfragmented packet then moves fragmentable part as needed + + local idxfrag = frag_idx(dis.ip6.exthdr) + local l3extra = l3_extra_len(dis, idxfrag-1) -- all ext headers before frag + + l3 = l3_base_len(dis) + l3extra + if (pos+l3)>=plen then + DLOG("ipfrag2: ip frag pos "..pos.." exceeds packet length. ipfrag cancelled.") + return nil + end + + l3extra = l3extra + 8 -- + 8 bytes for frag header + local ident = math.random(1,0xFFFFFFFF) + + dis1 = deepcopy(dis) + insert_ip6_exthdr(dis1.ip6, idxfrag, IPPROTO_FRAGMENT, bu16(IP6F_MORE_FRAG)..bu32(ident)) + dis1.ip6.ip6_plen = l3extra + pos + dis2 = deepcopy(dis) + insert_ip6_exthdr(dis2.ip6, idxfrag, IPPROTO_FRAGMENT, bu16(pos)..bu32(ident)) + -- only next proto of the first fragment is considered by standard + -- fragments with non-zero offset can have different "next protocol" field + -- this can be used to evade protection systems + if ipfrag_options.ipfrag_next then + dis2.ip6.exthdr[idxfrag].next = tonumber(ipfrag_options.ipfrag_next) + end + dis2.ip6.ip6_plen = plen - IP6_BASE_LEN + 8 - pos -- packet len without frag + 8 byte frag header - ipv6 base header + end + return {dis1,dis2} +end + + +-- option: sni_snt - server name type value in existing names +-- option: sni_snt_new - server name type value for new names +-- option: sni_del_ext - delete sni extension +-- option: sni_del - delete all names +-- option: sni_first - add name to the beginning +-- option: sni_last - add name to the end +function tls_client_hello_mod(tls, options) + local tdis = tls_dissect(tls) + if not tdis then + DLOG("tls_client_hello_mod: could not dissect tls") + return + end + if not tdis.handshake or not tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT] then + DLOG("tls_client_hello_mod: handshake not dissected") + return + end + local idx_sni + if options.sni_snt or options.sni_del_ext or options.sni_del or options.sni_first or options.sni_last then + if tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.ext then + idx_sni = array_field_search(tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.ext, "type", TLS_EXT_SERVER_NAME) + else + tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.ext={} + end + if not idx_sni then + DLOG("tls_client_hello_mod: no SNI extension. adding") + table.insert(tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.ext, 1, { type = TLS_EXT_SERVER_NAME, dis = { list = {} } } ) + idx_sni = 1 + end + end + if options.sni_del_ext then + table.remove(tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.ext, idx_sni) + else + if options.sni_del then + tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.ext[idx_sni].dis.list = {} + elseif options.sni_snt then + for i,v in pairs(tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.ext[idx_sni].dis.list) do + v.type = options.sni_snt + end + end + if options.sni_first then + table.insert(tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.ext[idx_sni].dis.list, 1, { name = options.sni_first, type = options.sni_snt_new } ) + end + if options.sni_last then + table.insert(tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.ext[idx_sni].dis.list, { name = options.sni_last, type = options.sni_snt_new } ) + end + end + local rtls = tls_reconstruct(tdis) + if not rtls then + DLOG_ERR("tls_client_hello_mod: reconstruct error") + end + return rtls +end + +-- checks if filename is gzip compressed +function is_gzip_file(filename) + local f, err = io.open(filename, "rb") + if not f then + error("is_gzip_file: "..err) + end + local hdr = f:read(2) + f:close() + return hdr and hdr=="\x1F\x8B" +end +-- ungzip file to raw string +-- expected_ratio = uncompressed_size/compressed_size (default 4) +function gunzip_file(filename, expected_ratio, read_block_size) + local f, err = io.open(filename, "rb") + if not f then + error("gunzip_file: "..err) + end + if not read_block_size then read_block_size=16384 end + if not expected_ratio then expected_ratio=4 end + + local decompressed="" + local gz = gunzip_init() + if not gz then + error("gunzip_file: stream init error") + end + repeat + local compressed, err = f:read(read_block_size) + if not compressed then + f:close() + gunzip_end(gz) + if err then + error("gunzip_file: file read error : "..err) + else + return nil + end + end + local decomp, eof = gunzip_inflate(gz, compressed, #compressed * expected_ratio) + if not decomp then + f:close() + gunzip_end(gz) + return nil + end + decompressed = decompressed .. decomp + until eof + f:close() + gunzip_end(gz) + return decompressed +end +-- zip file to raw string +-- expected_ratio = uncompressed_size/compressed_size (default 2) +-- level : 1..9 (default 9) +-- memlevel : 1..8 (default 8) +function gzip_file(filename, data, expected_ratio, level, memlevel, compress_block_size) + local f, err = io.open(filename, "wb") + if not f then + error("gzip_file: "..err) + end + if not compress_block_size then compress_block_size=16384 end + if not expected_ratio then expected_ratio=2 end + + local gz = gzip_init(nil, level, memlevel) + if not gz then + error("gzip_file: stream init error") + end + local off=1 + repeat + local block_size = #data-off+1 + if block_size>compress_block_size then block_size=compress_block_size end + local comp, eof = gzip_deflate(gz, string.sub(data,off,off+block_size-1), block_size / expected_ratio) + if not comp then + f:close() + gzip_end(gz) + return nil + end + f:write(comp) + off = off + block_size + until eof + f:close() + gzip_end(gz) +end +-- reads the whole file +function readfile(filename) + local f, err = io.open(filename, "rb") + if not f then + error("readfile: "..err) + end + local s, err = f:read("*a") + f:close() + if err then + error("readfile: "..err) + end + return s +end +-- reads plain or gzipped file with transparent decompression +-- expected_ratio = uncompressed_size/compressed_size (default 4) +function z_readfile(filename, expected_ratio) + return is_gzip_file(filename) and gunzip_file(filename, expected_ratio) or readfile(filename) +end +-- write data to filename +function writefile(filename, data) + local f, err = io.open(filename, "wb") + if not f then + error("writefile: "..err) + end + local s, err = f:write(data) + f:close() + if not s then + error("writefile: "..err) + end +end + + +-- DISSECTORS + +function http_dissect_header(header) + local p1,p2 + p1,p2 = string.find(header,":") + if p1 then + p2=string.find(header,"[^ \t]",p2+1) + return string.sub(header,1,p1-1), p2 and string.sub(header,p2) or "", p1-1, p2 or #header + end + return nil +end +-- make table with structured http header representation +function http_dissect_headers(http, pos) + local eol,pnext,header,value,headers,pos_endheader,pos_startvalue,pos_headers_end + headers={} + while pos do + eol,pnext = find_next_line(http,pos) + header = string.sub(http,pos,eol) + if #header == 0 then + pos_headers_end = pnext + break + end + header,value,pos_endheader,pos_startvalue = http_dissect_header(header) + if header then + headers[#headers+1] = { header_low = string.lower(header), header = header, value = value, pos_start = pos, pos_end = eol, pos_header_end = pos+pos_endheader-1, pos_value_start = pos+pos_startvalue-1 } + end + pos=pnext + end + return headers, pos_headers_end +end +-- make table with structured http request representation +function http_dissect_req(http) + if not http then return nil; end + local eol,pnext,req,hdrpos + local pos=1 + -- skip methodeol empty line(s) + while pos do + eol,pnext = find_next_line(http,pos) + req = string.sub(http,pos,eol) + pos=pnext + if #req>0 then break end + end + hdrpos = pos + if not req or #req==0 then return nil end + pos = string.find(req,"[ \t]") + if not pos then return nil end + local method = string.sub(req,1,pos-1); + pos = string.find(req,"[^ \t]",pos+1) + if not pos then return nil end + pnext = string.find(req,"[ \t]",pos+1) + if not pnext then pnext = #req + 1 end + local uri = string.sub(req,pos,pnext-1) + pos = string.find(req,"[^ \t]",pnext) + local http_ver + if pos then + pnext = string.find(req,"[\r\n]",pos) + if not pnext then pnext = #req + 1 end + http_ver = string.sub(req,pos,pnext-1) + end + local hdis = { method = method, uri = uri, http_ver = http_ver } + hdis.headers, hdis.pos_headers_end = http_dissect_headers(http,hdrpos) + if hdis.pos_headers_end then + hdis.body = string.sub(http, hdis.pos_headers_end) + end + return hdis +end +function http_dissect_reply(http) + if not http then return nil; end + local s, pos, code + s = string.sub(http,1,8) + if s~="HTTP/1.1" and s~="HTTP/1.0" then return nil end + pos = string.find(http,"[ \t\r\n]",10) + if not pos then return nil end + code = tonumber(string.sub(http,10,pos-1)) + if not code then return nil end + s,pos = find_next_line(http,pos) + local hdis = { code = code } + hdis.headers, hdis.pos_headers_end = http_dissect_headers(http,pos) + if hdis.pos_headers_end then + hdis.body = string.sub(http, hdis.pos_headers_end) + end + return hdis +end +function http_reconstruct_headers(headers, unixeol) + local eol = unixeol and "\n" or "\r\n" + return headers and barray(headers, function(a) return a.header..": "..a.value..eol end) or "" +end +function http_reconstruct_req(hdis, unixeol) + local eol = unixeol and "\n" or "\r\n" + return hdis.method.." "..hdis.uri..(hdis.http_ver and (" "..hdis.http_ver) or "")..eol..http_reconstruct_headers(hdis.headers, unixeol)..eol..(hdis.body or "") +end + +function dissect_url(url) + local p1,pb,pstart,pend + local proto, creds, domain, port, uri + p1 = string.find(url,"[^ \t]") + if not p1 then return nil end + pb = p1 + pstart,pend = string.find(url,"[a-z]+://",p1) + if pend then + proto = string.sub(url,pstart,pend-3) + p1 = pend+1 + end + pstart,pend = string.find(url,"[@/]",p1) + if pend and string.sub(url,pstart,pend)=='@' then + creds = string.sub(url,p1,pend-1) + p1 = pend+1 + end + pstart,pend = string.find(url,"[/?#]",p1) + if pend then + if pend==pb then + uri = string.sub(url,pb) + else + uri = string.sub(url,pend) + domain = string.sub(url,p1,pend-1) + end + else + if proto then + domain = string.sub(url,p1) + else + uri = string.sub(url,p1) + end + end + if domain then + pstart,pend = string.find(domain,':',1,true) + if pend then + port = string.sub(domain, pend+1) + domain = string.sub(domain, 1, pstart-1) + end + end + return { proto = proto, creds = creds, domain = domain, port = port, uri=uri } +end + +function dissect_nld(domain, level) + if domain then + local n=1 + for pos=#domain,1,-1 do + if string.sub(domain,pos,pos)=='.' then + if n==level then + return string.sub(domain, pos+1) + end + n=n+1 + end + end + if n==level then + return domain + end + end + return nil +end + + + +TLS_EXT_SERVER_NAME=0 +TLS_EXT_MAX_FRAGMENT_LENGTH=1 +TLS_EXT_CLIENT_CERTIFICATE_URL=2 +TLS_EXT_TRUSTED_CA_KEYS=3 +TLS_EXT_TRUNCATED_HMAC=4 +TLS_EXT_STATUS_REQUEST=5 +TLS_EXT_USER_MAPPING=6 +TLS_EXT_CLIENT_AUTHZ=7 +TLS_EXT_SERVER_AUTHZ=8 +TLS_EXT_CERT_TYPE=9 +TLS_EXT_SUPPORTED_GROUPS=10 +TLS_EXT_EC_POINT_FORMATS=11 +TLS_EXT_SRP=12 +TLS_EXT_SIGNATURE_ALGORITHMS=13 +TLS_EXT_USE_SRTP=14 +TLS_EXT_HEARTBEAT=15 +TLS_EXT_ALPN=16 +TLS_EXT_STATUS_REQUEST_V2=17 +TLS_EXT_SIGNED_CERTIFICATE_TIMESTAMP=18 +TLS_EXT_CLIENT_CERT_TYPE=19 +TLS_EXT_SERVER_CERT_TYPE=20 +TLS_EXT_PADDING=21 +TLS_EXT_ENCRYPT_THEN_MAC=22 +TLS_EXT_EXTENDED_MASTER_SECRET=23 +TLS_EXT_TOKEN_BINDING=24 +TLS_EXT_CACHED_INFO=25 +TLS_EXT_COMPRESS_CERTIFICATE=27 +TLS_EXT_RECORD_SIZE_LIMIT=28 +TLS_EXT_DELEGATED_CREDENTIALS=34 +TLS_EXT_SESSION_TICKET_TLS=35 +TLS_EXT_KEY_SHARE_OLD=40 +TLS_EXT_PRE_SHARED_KEY=41 +TLS_EXT_EARLY_DATA=42 +TLS_EXT_SUPPORTED_VERSIONS=43 +TLS_EXT_COOKIE=44 +TLS_EXT_PSK_KEY_EXCHANGE_MODES=45 +TLS_EXT_TICKET_EARLY_DATA_INFO=46 +TLS_EXT_CERTIFICATE_AUTHORITIES=47 +TLS_EXT_OID_FILTERS=48 +TLS_EXT_POST_HANDSHAKE_AUTH=49 +TLS_EXT_SIGNATURE_ALGORITHMS_CERT=50 +TLS_EXT_KEY_SHARE=51 +TLS_EXT_TRANSPARENCY_INFO=52 +TLS_EXT_CONNECTION_ID_DEPRECATED=53 +TLS_EXT_CONNECTION_ID=54 +TLS_EXT_EXTERNAL_ID_HASH=55 +TLS_EXT_EXTERNAL_SESSION_ID=56 +TLS_EXT_QUIC_TRANSPORT_PARAMETERS_V1=57 +TLS_EXT_TICKET_REQUEST=58 +TLS_EXT_DNSSEC_CHAIN=59 +TLS_EXT_GREASE_0A0A=2570 +TLS_EXT_GREASE_1A1A=6682 +TLS_EXT_GREASE_2A2A=10794 +TLS_EXT_NPN=13172 +TLS_EXT_GREASE_3A3A=14906 +TLS_EXT_ALPS_OLD=17513 +TLS_EXT_ALPS=17613 +TLS_EXT_GREASE_4A4A=19018 +TLS_EXT_GREASE_5A5A=23130 +TLS_EXT_GREASE_6A6A=27242 +TLS_EXT_CHANNEL_ID_OLD=30031 +TLS_EXT_CHANNEL_ID=30032 +TLS_EXT_GREASE_7A7A=31354 +TLS_EXT_GREASE_8A8A=35466 +TLS_EXT_GREASE_9A9A=39578 +TLS_EXT_GREASE_AAAA=43690 +TLS_EXT_GREASE_BABA=47802 +TLS_EXT_GREASE_CACA=51914 +TLS_EXT_GREASE_DADA=56026 +TLS_EXT_GREASE_EAEA=60138 +TLS_EXT_GREASE_FAFA=64250 +TLS_EXT_ECH_OUTER_EXTENSIONS=64768 +TLS_EXT_ENCRYPTED_CLIENT_HELLO=65037 +TLS_EXT_RENEGOTIATION_INFO=65281 +TLS_EXT_QUIC_TRANSPORT_PARAMETERS=65445 +TLS_EXT_ENCRYPTED_SERVER_NAME=65486 + +TLS_HELLO_EXT_NAMES = { + [TLS_EXT_SERVER_NAME] = "server_name", -- RFC 6066 + [TLS_EXT_MAX_FRAGMENT_LENGTH] = "max_fragment_length",-- RFC 6066 + [TLS_EXT_CLIENT_CERTIFICATE_URL] = "client_certificate_url", -- RFC 6066 + [TLS_EXT_TRUSTED_CA_KEYS] = "trusted_ca_keys", -- RFC 6066 + [TLS_EXT_TRUNCATED_HMAC] = "truncated_hmac", -- RFC 6066 + [TLS_EXT_STATUS_REQUEST] = "status_request", -- RFC 6066 + [TLS_EXT_USER_MAPPING] = "user_mapping", -- RFC 4681 + [TLS_EXT_CLIENT_AUTHZ] = "client_authz", -- RFC 5878 + [TLS_EXT_SERVER_AUTHZ] = "server_authz", -- RFC 5878 + [TLS_EXT_CERT_TYPE] = "cert_type", -- RFC 6091 + [TLS_EXT_SUPPORTED_GROUPS] = "supported_groups", -- RFC 4492, RFC 7919 + [TLS_EXT_EC_POINT_FORMATS] = "ec_point_formats", -- RFC 4492 + [TLS_EXT_SRP] = "srp", -- RFC 5054 + [TLS_EXT_SIGNATURE_ALGORITHMS] = "signature_algorithms", -- RFC 5246 + [TLS_EXT_USE_SRTP] = "use_srtp", -- RFC 5764 + [TLS_EXT_HEARTBEAT] = "heartbeat", -- RFC 6520 + [TLS_EXT_ALPN] = "application_layer_protocol_negotiation", -- RFC 7301 + [TLS_EXT_STATUS_REQUEST_V2] = "status_request_v2", -- RFC 6961 + [TLS_EXT_SIGNED_CERTIFICATE_TIMESTAMP] = "signed_certificate_timestamp", -- RFC 6962 + [TLS_EXT_CLIENT_CERT_TYPE] = "client_certificate_type", -- RFC 7250 + [TLS_EXT_SERVER_CERT_TYPE] = "server_certificate_type", -- RFC 7250 + [TLS_EXT_PADDING] = "padding", -- RFC 7685 + [TLS_EXT_ENCRYPT_THEN_MAC] = "encrypt_then_mac", -- RFC 7366 + [TLS_EXT_EXTENDED_MASTER_SECRET] = "extended_master_secret", -- RFC 7627 + [TLS_EXT_TOKEN_BINDING] = "token_binding", -- https://tools.ietf.org/html/draft-ietf-tokbind-negotiation + [TLS_EXT_CACHED_INFO] = "cached_info", -- RFC 7924 + [TLS_EXT_COMPRESS_CERTIFICATE] = "compress_certificate", -- https://tools.ietf.org/html/draft-ietf-tls-certificate-compression-03 + [TLS_EXT_RECORD_SIZE_LIMIT] = "record_size_limit", -- RFC 8449 + [TLS_EXT_DELEGATED_CREDENTIALS] = "delegated_credentials", -- draft-ietf-tls-subcerts-10.txt + [TLS_EXT_SESSION_TICKET_TLS] = "session_ticket", -- RFC 5077 / RFC 8447 + [TLS_EXT_KEY_SHARE_OLD] = "Reserved (key_share)", -- https://tools.ietf.org/html/draft-ietf-tls-tls13-22 (removed in -23) + [TLS_EXT_PRE_SHARED_KEY] = "pre_shared_key", -- RFC 8446 + [TLS_EXT_EARLY_DATA] = "early_data", -- RFC 8446 + [TLS_EXT_SUPPORTED_VERSIONS] = "supported_versions", -- RFC 8446 + [TLS_EXT_COOKIE] = "cookie", -- RFC 8446 + [TLS_EXT_PSK_KEY_EXCHANGE_MODES] = "psk_key_exchange_modes", -- RFC 8446 + [TLS_EXT_TICKET_EARLY_DATA_INFO] = "Reserved (ticket_early_data_info)", -- draft-ietf-tls-tls13-18 (removed in -19) + [TLS_EXT_CERTIFICATE_AUTHORITIES] = "certificate_authorities", -- RFC 8446 + [TLS_EXT_OID_FILTERS] = "oid_filters", -- RFC 8446 + [TLS_EXT_POST_HANDSHAKE_AUTH] = "post_handshake_auth", -- RFC 8446 + [TLS_EXT_SIGNATURE_ALGORITHMS_CERT] = "signature_algorithms_cert", -- RFC 8446 + [TLS_EXT_KEY_SHARE] = "key_share", -- RFC 8446 + [TLS_EXT_TRANSPARENCY_INFO] = "transparency_info", -- draft-ietf-trans-rfc6962-bis-41 + [TLS_EXT_CONNECTION_ID_DEPRECATED] = "connection_id (deprecated)", -- draft-ietf-tls-dtls-connection-id-07 + [TLS_EXT_CONNECTION_ID] = "connection_id", -- RFC 9146 + [TLS_EXT_EXTERNAL_ID_HASH] = "external_id_hash", -- RFC 8844 + [TLS_EXT_EXTERNAL_SESSION_ID] = "external_session_id", -- RFC 8844 + [TLS_EXT_QUIC_TRANSPORT_PARAMETERS_V1] = "quic_transport_parameters", -- draft-ietf-quic-tls-33 + [TLS_EXT_TICKET_REQUEST] = "ticket_request", -- draft-ietf-tls-ticketrequests-07 + [TLS_EXT_DNSSEC_CHAIN] = "dnssec_chain", -- RFC 9102 + [TLS_EXT_GREASE_0A0A] = "Reserved (GREASE)", -- RFC 8701 + [TLS_EXT_GREASE_1A1A] = "Reserved (GREASE)", -- RFC 8701 + [TLS_EXT_GREASE_2A2A] = "Reserved (GREASE)", -- RFC 8701 + [TLS_EXT_NPN] = "next_protocol_negotiation", -- https://datatracker.ietf.org/doc/html/draft-agl-tls-nextprotoneg-03 + [TLS_EXT_GREASE_3A3A] = "Reserved (GREASE)", -- RFC 8701 + [TLS_EXT_ALPS_OLD] = "application_settings_old", -- draft-vvv-tls-alps-01 + [TLS_EXT_ALPS] = "application_settings", -- draft-vvv-tls-alps-01 -- https://chromestatus.com/feature/5149147365900288 + [TLS_EXT_GREASE_4A4A] = "Reserved (GREASE)", -- RFC 8701 + [TLS_EXT_GREASE_5A5A] = "Reserved (GREASE)", -- RFC 8701 + [TLS_EXT_GREASE_6A6A] = "Reserved (GREASE)", -- RFC 8701 + [TLS_EXT_CHANNEL_ID_OLD] = "channel_id_old", -- https://tools.ietf.org/html/draft-balfanz-tls-channelid-00 + [TLS_EXT_CHANNEL_ID] = "channel_id", -- https://tools.ietf.org/html/draft-balfanz-tls-channelid-01 + [TLS_EXT_RENEGOTIATION_INFO] = "renegotiation_info", -- RFC 5746 + [TLS_EXT_GREASE_7A7A] = "Reserved (GREASE)", -- RFC 8701 + [TLS_EXT_GREASE_8A8A] = "Reserved (GREASE)", -- RFC 8701 + [TLS_EXT_GREASE_9A9A] = "Reserved (GREASE)", -- RFC 8701 + [TLS_EXT_GREASE_AAAA] = "Reserved (GREASE)", -- RFC 8701 + [TLS_EXT_GREASE_BABA] = "Reserved (GREASE)", -- RFC 8701 + [TLS_EXT_GREASE_CACA] = "Reserved (GREASE)", -- RFC 8701 + [TLS_EXT_GREASE_DADA] = "Reserved (GREASE)", -- RFC 8701 + [TLS_EXT_GREASE_EAEA] = "Reserved (GREASE)", -- RFC 8701 + [TLS_EXT_GREASE_FAFA] = "Reserved (GREASE)", -- RFC 8701 + [TLS_EXT_QUIC_TRANSPORT_PARAMETERS] = "quic_transport_parameters (drafts version)", -- https://tools.ietf.org/html/draft-ietf-quic-tls + [TLS_EXT_ENCRYPTED_SERVER_NAME] = "encrypted_server_name", -- https://tools.ietf.org/html/draft-ietf-tls-esni-01 + [TLS_EXT_ENCRYPTED_CLIENT_HELLO] = "encrypted_client_hello", -- https://datatracker.ietf.org/doc/draft-ietf-tls-esni/17/ + [TLS_EXT_ECH_OUTER_EXTENSIONS] = "ech_outer_extensions" -- https://datatracker.ietf.org/doc/draft-ietf-tls-esni/17/ +} + +TLS_RECORD_TYPE_CHANGE_CIPHER_SPEC=0x14 +TLS_RECORD_TYPE_ALERT=0x15 +TLS_RECORD_TYPE_HANDSHAKE=0x16 +TLS_RECORD_TYPE_DATA=0x17 +TLS_RECORD_TYPE_HEARTBEAT=0x18 + +TLS_RECORD_TYPE_NAMES = { + [TLS_RECORD_TYPE_CHANGE_CIPHER_SPEC] = "change_cipher_spec", + [TLS_RECORD_TYPE_ALERT] = "alert", + [TLS_RECORD_TYPE_HANDSHAKE] = "handshake", + [TLS_RECORD_TYPE_DATA] = "data", + [TLS_RECORD_TYPE_HEARTBEAT] = "heartbeat" +} + +TLS_HANDSHAKE_TYPE_HELLO_REQUEST=0 +TLS_HANDSHAKE_TYPE_CLIENT=1 +TLS_HANDSHAKE_TYPE_SERVER=2 +TLS_HANDSHAKE_TYPE_CERTIFICATE=11 +TLS_HANDSHAKE_TYPE_KEY_EXCHANGE=12 +TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST=13 +TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE=14 +TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY=15 +TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE=16 +TLS_HANDSHAKE_TYPE_FINISHED=20 +TLS_HANDSHAKE_TYPE_CERTIFICATE_URL=21 +TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS=22 +TLS_HANDSHAKE_TYPE_SUPPLEMENTAL_DATA=23 +TLS_HANDSHAKE_TYPE_KEY_UPDATE=24 +TLS_HANDSHAKE_TYPE_COMPRESSED_CERTIFICATE=25 + +TLS_HANDSHAKE_TYPE_NAMES = { + [TLS_HANDSHAKE_TYPE_HELLO_REQUEST]="hello_request", + [TLS_HANDSHAKE_TYPE_CLIENT]="client_hello", + [TLS_HANDSHAKE_TYPE_SERVER]="server_hello", + [TLS_HANDSHAKE_TYPE_CERTIFICATE]="certificate", + [TLS_HANDSHAKE_TYPE_KEY_EXCHANGE]="key_exchange", + [TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST]="certificate_request", + [TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE]="hello_done", + [TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY]="certificate_verify", + [TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE]="client_key_exchange", + [TLS_HANDSHAKE_TYPE_FINISHED]="finished", + [TLS_HANDSHAKE_TYPE_CERTIFICATE_URL]="certificate_url", + [TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS]="certificate_status", + [TLS_HANDSHAKE_TYPE_SUPPLEMENTAL_DATA]="supplemental_data", + [TLS_HANDSHAKE_TYPE_KEY_UPDATE]="key_update", + [TLS_HANDSHAKE_TYPE_COMPRESSED_CERTIFICATE]="compressed_certificate" +} + +TLS_VER_SSL30=0x0300 +TLS_VER_TLS10=0x0301 +TLS_VER_TLS11=0x0302 +TLS_VER_TLS12=0x0303 +TLS_VER_TLS13=0x0304 + +TLS_HANDSHAKE_QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID=0x00 +TLS_HANDSHAKE_QUIC_TP_MAX_IDLE_TIMEOUT=0x01 +TLS_HANDSHAKE_QUIC_TP_STATELESS_RESET_TOKEN=0x02 +TLS_HANDSHAKE_QUIC_TP_MAX_UDP_PAYLOAD_SIZE=0x03 +TLS_HANDSHAKE_QUIC_TP_INITIAL_MAX_DATA=0x04 +TLS_HANDSHAKE_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL=0x05 +TLS_HANDSHAKE_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE=0x06 +TLS_HANDSHAKE_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI=0x07 +TLS_HANDSHAKE_QUIC_TP_INITIAL_MAX_STREAMS_BIDI=0x08 +TLS_HANDSHAKE_QUIC_TP_INITIAL_MAX_STREAMS_UNI=0x09 +TLS_HANDSHAKE_QUIC_TP_ACK_DELAY_EXPONENT=0x0a +TLS_HANDSHAKE_QUIC_TP_MAX_ACK_DELAY=0x0b +TLS_HANDSHAKE_QUIC_TP_DISABLE_ACTIVE_MIGRATION=0x0c +TLS_HANDSHAKE_QUIC_TP_PREFERRED_ADDRESS=0x0d +TLS_HANDSHAKE_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT=0x0e +TLS_HANDSHAKE_QUIC_TP_INITIAL_SOURCE_CONNECTION_ID=0x0f +TLS_HANDSHAKE_QUIC_TP_RETRY_SOURCE_CONNECTION_ID=0x10 +TLS_HANDSHAKE_QUIC_TP_VERSION_INFORMATION=0x11 -- https://tools.ietf.org/html/draft-ietf-quic-version-negotiation-14 +TLS_HANDSHAKE_QUIC_TP_MAX_DATAGRAM_FRAME_SIZE=0x20 -- https://datatracker.ietf.org/doc/html/draft-ietf-quic-datagram-06 +TLS_HANDSHAKE_QUIC_TP_CIBIR_ENCODING=0x1000 -- https://datatracker.ietf.org/doc/html/draft-banks-quic-cibir-01 +TLS_HANDSHAKE_QUIC_TP_LOSS_BITS=0x1057 -- https://tools.ietf.org/html/draft-ferrieuxhamchaoui-quic-lossbits-03 +TLS_HANDSHAKE_QUIC_TP_GREASE_QUIC_BIT=0x2ab2 -- RFC 9287 +TLS_HANDSHAKE_QUIC_TP_ENABLE_TIME_STAMP=0x7157 -- https://tools.ietf.org/html/draft-huitema-quic-ts-02 +TLS_HANDSHAKE_QUIC_TP_ENABLE_TIME_STAMP_V2=0x7158 -- https://tools.ietf.org/html/draft-huitema-quic-ts-03 +TLS_HANDSHAKE_QUIC_TP_MIN_ACK_DELAY_OLD=0xde1a -- https://tools.ietf.org/html/draft-iyengar-quic-delayed-ack-00 +TLS_HANDSHAKE_QUIC_TP_GOOGLE_USER_AGENT=0x3129 +TLS_HANDSHAKE_QUIC_TP_GOOGLE_KEY_UPDATE_NOT_YET_SUPPORTED=0x312B +TLS_HANDSHAKE_QUIC_TP_GOOGLE_QUIC_VERSION=0x4752 +TLS_HANDSHAKE_QUIC_TP_GOOGLE_INITIAL_RTT=0x3127 +TLS_HANDSHAKE_QUIC_TP_GOOGLE_SUPPORT_HANDSHAKE_DONE=0x312A +TLS_HANDSHAKE_QUIC_TP_GOOGLE_QUIC_PARAMS=0x4751 +TLS_HANDSHAKE_QUIC_TP_GOOGLE_CONNECTION_OPTIONS=0x3128 +TLS_HANDSHAKE_QUIC_TP_FACEBOOK_PARTIAL_RELIABILITY=0xFF00 +TLS_HANDSHAKE_QUIC_TP_VERSION_INFORMATION_DRAFT=0xff73db -- https://datatracker.ietf.org/doc/draft-ietf-quic-version-negotiation/13/ +TLS_HANDSHAKE_QUIC_TP_ADDRESS_DISCOVERY=0x9f81a176 -- https://tools.ietf.org/html/draft-ietf-quic-address-discovery-00 +TLS_HANDSHAKE_QUIC_TP_MIN_ACK_DELAY_DRAFT_V1=0xFF03DE1A -- https://tools.ietf.org/html/draft-ietf-quic-ack-frequency-01 +TLS_HANDSHAKE_QUIC_TP_MIN_ACK_DELAY_DRAFT05=0xff04de1a -- https://tools.ietf.org/html/draft-ietf-quic-ack-frequency-04 / draft-05 +TLS_HANDSHAKE_QUIC_TP_MIN_ACK_DELAY=0xff04de1b -- https://tools.ietf.org/html/draft-ietf-quic-ack-frequency-07 + +TLS_HANDSHAKE_QUIC_TP_NAMES = { + [TLS_HANDSHAKE_QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID]="original_destination_connection_id", + [TLS_HANDSHAKE_QUIC_TP_MAX_IDLE_TIMEOUT]="max_idle_timeout", + [TLS_HANDSHAKE_QUIC_TP_STATELESS_RESET_TOKEN]="stateless_reset_token", + [TLS_HANDSHAKE_QUIC_TP_MAX_UDP_PAYLOAD_SIZE]="max_udp_payload_size", + [TLS_HANDSHAKE_QUIC_TP_INITIAL_MAX_DATA]="initial_max_data", + [TLS_HANDSHAKE_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL]="initial_max_stream_data_bidi_local", + [TLS_HANDSHAKE_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE]="initial_max_stream_data_bidi_remote", + [TLS_HANDSHAKE_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI]="initial_max_stream_data_uni", + [TLS_HANDSHAKE_QUIC_TP_INITIAL_MAX_STREAMS_UNI]="initial_max_streams_uni", + [TLS_HANDSHAKE_QUIC_TP_INITIAL_MAX_STREAMS_BIDI]="initial_max_streams_bidi", + [TLS_HANDSHAKE_QUIC_TP_ACK_DELAY_EXPONENT]="ack_delay_exponent", + [TLS_HANDSHAKE_QUIC_TP_MAX_ACK_DELAY]="max_ack_delay", + [TLS_HANDSHAKE_QUIC_TP_DISABLE_ACTIVE_MIGRATION]="disable_active_migration", + [TLS_HANDSHAKE_QUIC_TP_PREFERRED_ADDRESS]="preferred_address", + [TLS_HANDSHAKE_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT]="active_connection_id_limit", + [TLS_HANDSHAKE_QUIC_TP_INITIAL_SOURCE_CONNECTION_ID]="initial_source_connection_id", + [TLS_HANDSHAKE_QUIC_TP_RETRY_SOURCE_CONNECTION_ID]="retry_source_connection_id", + [TLS_HANDSHAKE_QUIC_TP_MAX_DATAGRAM_FRAME_SIZE]="max_datagram_frame_size", + [TLS_HANDSHAKE_QUIC_TP_CIBIR_ENCODING]="cibir_encoding", + [TLS_HANDSHAKE_QUIC_TP_LOSS_BITS]="loss_bits", + [TLS_HANDSHAKE_QUIC_TP_GREASE_QUIC_BIT]="grease_quic_bit", + [TLS_HANDSHAKE_QUIC_TP_ENABLE_TIME_STAMP]="enable_time_stamp", + [TLS_HANDSHAKE_QUIC_TP_ENABLE_TIME_STAMP_V2]="enable_time_stamp_v2", + [TLS_HANDSHAKE_QUIC_TP_VERSION_INFORMATION]="version_information", + [TLS_HANDSHAKE_QUIC_TP_VERSION_INFORMATION_DRAFT]="version_information_draft", + [TLS_HANDSHAKE_QUIC_TP_MIN_ACK_DELAY_OLD]="min_ack_delay", + [TLS_HANDSHAKE_QUIC_TP_GOOGLE_USER_AGENT]="google_user_agent", + [TLS_HANDSHAKE_QUIC_TP_GOOGLE_KEY_UPDATE_NOT_YET_SUPPORTED]="google_key_update_not_yet_supported", + [TLS_HANDSHAKE_QUIC_TP_GOOGLE_QUIC_VERSION]="google_quic_version", + [TLS_HANDSHAKE_QUIC_TP_GOOGLE_INITIAL_RTT]="google_initial_rtt", + [TLS_HANDSHAKE_QUIC_TP_GOOGLE_SUPPORT_HANDSHAKE_DONE]="google_support_handshake_done", + [TLS_HANDSHAKE_QUIC_TP_GOOGLE_QUIC_PARAMS]="google_quic_params", + [TLS_HANDSHAKE_QUIC_TP_GOOGLE_CONNECTION_OPTIONS]="google_connection_options", + [TLS_HANDSHAKE_QUIC_TP_FACEBOOK_PARTIAL_RELIABILITY]="facebook_partial_reliability", + [TLS_HANDSHAKE_QUIC_TP_ADDRESS_DISCOVERY]="address_discovery", + [TLS_HANDSHAKE_QUIC_TP_MIN_ACK_DELAY_DRAFT_V1]="min_ack_delay (draft-01)", + [TLS_HANDSHAKE_QUIC_TP_MIN_ACK_DELAY_DRAFT05]="min_ack_delay (draft-05)", + [TLS_HANDSHAKE_QUIC_TP_MIN_ACK_DELAY]="min_ack_delay" +} + + +-- tls record length without header +function tls_record_data_len(tls, offset) + if not offset then offset=1 end + return u16(tls, offset+3) +end +-- true if tls has enough data to store the whole tls record +function tls_record_full(tls, offset) + if not offset then offset=1 end + return tls_record_data_len(tls, offset) <= (#tls-offset+1-5) +end +function tls_record_type(tls, offset) + if not offset then offset=1 end + return u8(tls, offset) +end +function is_tls_record(tls, offset, ctype, partialOK) + if not tls then return false end + if not offset then offset=1 end + + if (#tls-offset+1)<5 or (ctype and ctype~=tls_record_type(tls, offset)) then return false end + local f2 = u16(tls, offset+1) + return f2>=TLS_VER_SSL30 and f2<=TLS_VER_TLS12 and (partialOK or tls_record_full(tls, offset)) + +end +-- tls handshake record length without header +function tls_handshake_data_len(tls, offset) + if not offset then offset=1 end + return u24(tls, offset+1) +end +-- tls handshake record length with header +function tls_handshake_len(tls, offset) + return tls_handshake_data_len(tls, offset) + 4 +end +-- true if tls has enough data to store the whole handshake +function tls_handshake_full(tls, offset) + if not offset then offset=1 end + return tls_handshake_data_len(tls, offset) <= (#tls-offset+1-4) +end +function tls_handshake_type(tls, offset) + return u8(tls,offset) +end +function is_tls_handshake_type_hello(tls, offset) + if not tls then return false end + local typ = tls_handshake_type(tls, offset) + return typ == TLS_HANDSHAKE_TYPE_CLIENT or typ == TLS_HANDSHAKE_TYPE_SERVER +end +function is_tls_handshake(tls, offset, htype, partialOK) + if not tls then return false end + if not offset then offset=1 end + + if (#tls-offset+1)<4 then return false end + local typ = tls_handshake_type(tls,offset) + -- requested handshake type + if htype and htype~=typ then return false end + -- valid handshake type + if not TLS_HANDSHAKE_TYPE_NAMES[typ] then return false end + if typ==TLS_HANDSHAKE_TYPE_CLIENT or typ==TLS_HANDSHAKE_TYPE_SERVER then + -- valid tls versions + if (#tls-offset+1)<6 then return false end + local f2 = u16(tls,offset+4) + if f2TLS_VER_TLS12 then return false end + end + -- length fits to data buffer + return partialOK or tls_handshake_full(tls, offset) +end +function is_tls_hello(tls, offset, partialOK) + return is_tls_handshake(tls, offset, TLS_HANDSHAKE_TYPE_CLIENT, partialOK) or is_tls_handshake(tls, offset, TLS_HANDSHAKE_TYPE_SERVER, partialOK) +end +-- quic-style tvb parse +function quic_tvb(data, offset) + if not offset then offset=1 end + if offset>#data then return end + local size = bitrshift(u8(data,offset), 6) + if size==0 then + return u8(data,offset), 1 + elseif size==1 then + if (offset+1)>#data then return end + return bitand(u16(data,offset),0x3FFF), 2 + elseif size==2 then + if (offset+3)>#data then return end + return bitand(u32(data,offset),0x3FFFFFFF), 4 + elseif size==3 then + if (offset+7)>#data then return end + -- only lua 5.3+ has 64-bit integer type. others can't store 64-bit integers. return raw string if the value cannot fit. + local msb = bitand(u32(data,offset),0x3FFFFFFF) + -- lua 5.3+ has math.type function, older lua and luajit - don't + if math.type==nil and msb>0x1FFFFF then + return string.sub(data,offset,offset+7), 8 + else + return msb * 0x100000000 + u32(data,offset+4), 8 + end + end +end +-- quic-style tvb reconstruct +function bquic_tvb(v) + if type(v)=="string" then + -- raw string. do not do anything, just return it + return v + else + if v<0x40 then + return bu8(v) + elseif v<0x4000 then + return bu16(v + 0x4000) + elseif v<0x40000000 then + return bu32(v + 0x80000000) + elseif v<0x4000000000000000 then + -- only lua 5.3+ can handle 64-bit int ! + return bu32(divint(v, 0x100000000) + 0xC0000000) .. bu32(v % 0x100000000) + end + end +end + + +-- dissect tls extension +-- create dis tables inside ext for supported exts. leave 'data' as is for unsupported exts +function tls_dissect_ext(ext) + local function len16_header() + local left, len, off + left = #ext.data + if left<2 then return end + len = u16(ext.data) + left = left - 2 + off = 3 + if len>left then + return + else + left = len + end + return left, off + end + local function len8_header() + local left, len, off + left = #ext.data + if left<1 then return end + len = u8(ext.data) + left = left - 1 + off = 2 + if len>left then + return + else + left = len + end + return left, off + end + + local dis={} + local off, len, left + + ext.dis = nil + + if ext.type==TLS_EXT_SERVER_NAME then + left, off = len16_header() + if not left then return end + dis.list = {} + while left>=3 do + len = u16(ext.data, off+1) + if (len+3)>left then return end + dis.list[#dis.list+1] = { type = u8(ext.data, off), name = string.sub(ext.data, off+3, off+3+len-1) } + left = left - 3 - len + off = off + 3 + len + end + elseif ext.type==TLS_EXT_ALPN then + left, off = len16_header() + if not left then return end + dis.list = {} + while left>=1 do + len = u8(ext.data, off) + if (len+1)>left then return end + dis.list[#dis.list+1] = string.sub(ext.data, off+1, off+1+len-1) + left = left - 1 - len + off = off + 1 + len + end + elseif ext.type==TLS_EXT_SUPPORTED_VERSIONS or ext.type==TLS_EXT_COMPRESS_CERTIFICATE then + left, off = len8_header() + if not left then return end + dis.list = {} + for i=1,left/2 do + dis.list[#dis.list+1] = u16(ext.data,off) + left = left - 2 + off = off + 2 + end + elseif ext.type==TLS_EXT_SIGNATURE_ALGORITHMS or ext.type==TLS_EXT_DELEGATED_CREDENTIALS or ext.type==TLS_EXT_SUPPORTED_GROUPS then + left, off = len16_header() + if not left then return end + dis.list = {} + for i=1,left/2 do + dis.list[#dis.list+1] = u16(ext.data,off) + left = left - 2 + off = off + 2 + end + elseif ext.type==TLS_EXT_EC_POINT_FORMATS or ext.type==TLS_EXT_PSK_KEY_EXCHANGE_MODES then + left, off = len8_header() + if not left then return end + dis.list = {} + for i=1,left do + dis.list[#dis.list+1] = u8(ext.data,off) + left = left - 1 + off = off + 1 + end + elseif ext.type==TLS_EXT_KEY_SHARE then + left, off = len16_header() + if not left then return end + dis.list = {} + while left>=4 do + len = u16(ext.data, off + 2) + if (len+4)>left then return end + dis.list[#dis.list+1] = { group = u16(ext.data, off) , kex = string.sub(ext.data, off+4, off+4+len-1) } + left = left - 4 - len + off = off + 4 + len + end + elseif ext.type==TLS_EXT_QUIC_TRANSPORT_PARAMETERS then + left, off = len16_header() + if not left then return end + dis.list = {} + while left>=4 do + len = u16(ext.data, off + 2) + if (len+4)>left then return end + local typ = u16(ext.data, off) + dis.list[#dis.list+1] = { type = typ, name = TLS_HANDSHAKE_QUIC_TP_NAMES[typ], data = string.sub(ext.data, off+4, off+4+len-1) } + left = left - 4 - len + off = off + 4 + len + end + elseif ext.type==TLS_EXT_QUIC_TRANSPORT_PARAMETERS_V1 then + left, off = #ext.data, 1 + dis.list = {} + local typ, size + while left>=2 do + typ, size = quic_tvb(ext.data, off) + if not typ then return end + off = off + size + left = left - size + len, size = quic_tvb(ext.data, off) + if type(len)~="number" then return end + off = off + size + left = left - size + if len > left then return end + dis.list[#dis.list+1] = { type = typ, name = TLS_HANDSHAKE_QUIC_TP_NAMES[typ], data = string.sub(ext.data, off, off+len-1) } + left = left - len + off = off + len + end + else + dis = nil + end + + ext.dis = dis +end + +-- dissect client/server hello. leave 'data' as is for others +function tls_dissect_handshake(handshake, partialOK) + if is_tls_hello(handshake.data, 1, partialOK) then + local hlen = tls_handshake_len(handshake.data, 1) + if hlen > #handshake.data then + if not partialOK then return false end + hlen = #handshake.data + end + local typ = tls_handshake_type(handshake.data, 1) + handshake.dis = { type = typ , ver = u16(handshake.data, 5), name = tostring(TLS_HANDSHAKE_TYPE_NAMES[typ]) } + + -- random + if hlen<38 then return partialOK end + handshake.dis.random = string.sub(handshake.data, 7, 38) + + -- session_id + if hlen<39 then return partialOK end + local len = u8(handshake.data, 39) + local left = hlen-39-len + if left<0 then return partialOK end + handshake.dis.session_id = string.sub(handshake.data, 40, 40+len-1) + local off = 40+len + + -- cipher suite(s) + if left<2 then return partialOK end + if handshake.dis.type==TLS_HANDSHAKE_TYPE_CLIENT then + -- client hello - array + len = u16(handshake.data, off) + if left<(2+len) then return partialOK end + handshake.dis.cipher_suites={} + for i=1,(len/2) do + handshake.dis.cipher_suites[i] = u16(handshake.data, off + i*2) + end + off = off + 2 + len + left = left - 2 - len + else + -- server hello - single + handshake.dis.cipher_suite = u16(handshake.data, off) + off = off + 2 + left = left - 2 + end + + -- compression method(s) + if left<1 then return partialOK end + if handshake.dis.type==1 then + -- client hello - array + len = u8(handshake.data, off) + if left<(1+len) then return partialOK end + handshake.dis.compression_methods={} + for i=1,len do + handshake.dis.compression_methods[i] = u8(handshake.data, off + i) + end + off = off + 1 + len + left = left - 1 - len + else + -- server hello - single + handshake.dis.compression_method = u8(handshake.data, off) + off = off + 1 + left = left - 1 + end + + -- tls extensions + if left<2 then return partialOK end + local extlen = u16(handshake.data, off) + if left<(2+extlen) and not partialOK then return end + off = off + 2 + left = left - 2 + if left>extlen then left=extlen end + + handshake.dis.ext = {} + while left>=4 do + len = u16(handshake.data, off + 2) + if len>(left-4) then + if partialOK then + break + else + return + end + end + local typ = u16(handshake.data, off) + handshake.dis.ext[#handshake.dis.ext+1] = { type = typ, name = tostring(TLS_HELLO_EXT_NAMES[typ]), data = string.sub(handshake.data, off+4, off+4+len-1) } + tls_dissect_ext(handshake.dis.ext[#handshake.dis.ext]) + left = left - 4 - len + off = off + 4 + len + end + + return true + end + return false +end + +-- convert tls blob tls dissect +-- auto detects record layer. can work with pure handshake message +function tls_dissect(tls, offset, partialOK) + if not offset then offset=1 end + + local tdis = {} + local off = offset + local encrypted = false + while is_tls_record(tls, off, nil, partialOK) do + if not tdis.rec then tdis.rec = {} end + local len = tls_record_data_len(tls, off) + local typ = tls_record_type(tls, off) + tdis.rec[#tdis.rec+1] = { type = typ, name = tostring(TLS_RECORD_TYPE_NAMES[typ]), len = len, ver = u16(tls, off+1), encrypted = encrypted, data = string.sub(tls, off+5, off+5+len-1) } + if typ==TLS_RECORD_TYPE_CHANGE_CIPHER_SPEC then + encrypted = true + elseif typ==TLS_RECORD_TYPE_HANDSHAKE and not encrypted then + -- need 4 bytes for handshake type and 24-bit length + if (#tls-off+1)<9 then + if not partialOK then return end + break + end + local htyp = tls_handshake_type(tls, off + 5) + tdis.rec[#tdis.rec].htype = htyp + if not tdis.handshake then tdis.handshake = {} end + local hlen = tls_handshake_len(tls, off + 5) + tdis.handshake[htyp] = { type = htyp, name = TLS_HANDSHAKE_TYPE_NAMES[htyp], data = "" } + -- reasm handshake if required + while true do + tdis.handshake[htyp].data = tdis.handshake[htyp].data .. string.sub(tls, off + 5, off + 5 + len - 1) + if #tdis.handshake[htyp].data >= hlen then + -- reasm complete + break + end + -- next record + if not is_tls_record(tls, off + 5 + len, nil, partialOK) or tls_record_type(tls, off + 5 + len) ~= typ then + if not partialOK then return end + goto endrec + end + off = off + 5 + len + len = tls_record_data_len(tls, off) + tdis.rec[#tdis.rec+1] = { type = typ, htype = htyp, len=len, ver = u16(tls, off+1), encrypted = false, not_first = true, name = tostring(TLS_RECORD_TYPE_NAMES[typ]), data = string.sub(tls, off+5, off+5+len-1) } + end + end + -- next record + off = off + 5 + len + end +::endrec:: + + if tdis.handshake then + for htyp, handshake in pairs(tdis.handshake) do + if (handshake.type == TLS_HANDSHAKE_TYPE_CLIENT or handshake.type == TLS_HANDSHAKE_TYPE_SERVER) then + tls_dissect_handshake(handshake, partialOK) + end + end + elseif not tdis.rec and is_tls_handshake(tls, offset, nil, partialOK) then + local htyp = tls_handshake_type(tls, offset) + tdis.handshake = { [htyp] = { type = htyp, name = TLS_HANDSHAKE_TYPE_NAMES[htyp], data = string.sub(tls, offset, #tls) } } + tls_dissect_handshake(tdis.handshake[htyp], partialOK) + end + + return (tdis.rec or tdis.handshake) and tdis or nil +end + + +-- reconstruct tls extension dissects +-- unsupported ext types must have their 'data' filled +function tls_reconstruct_ext(ext) + if ext.dis then + if ext.type==TLS_EXT_SERVER_NAME then + ext.data = barray(ext.dis.list, function(a) return bu8(a.type or 0) .. bu16(#a.name) .. a.name end) + ext.data = bu16(#ext.data) .. ext.data + elseif ext.type==TLS_EXT_ALPN then + ext.data = barray(ext.dis.list, function(a) return bu8(#a) .. a end) + ext.data = bu16(#ext.data) .. ext.data + elseif ext.type==TLS_EXT_SUPPORTED_VERSIONS or ext.type==TLS_EXT_COMPRESS_CERTIFICATE then + ext.data = barray(ext.dis.list, bu16) + ext.data = bu8(#ext.data) .. ext.data + elseif ext.type==TLS_EXT_SIGNATURE_ALGORITHMS or ext.type==TLS_EXT_DELEGATED_CREDENTIALS or ext.type==TLS_EXT_SUPPORTED_GROUPS then + ext.data = barray(ext.dis.list, bu16) + ext.data = bu16(#ext.data) .. ext.data + elseif ext.type==TLS_EXT_EC_POINT_FORMATS or ext.type==TLS_EXT_PSK_KEY_EXCHANGE_MODES then + ext.data = barray(ext.dis.list, bu8) + ext.data = bu8(#ext.data) .. ext.data + elseif ext.type==TLS_EXT_KEY_SHARE then + ext.data = barray(ext.dis.list, function(a) return bu16(a.group) .. bu16(#a.kex) .. a.kex end) + ext.data = bu16(#ext.data) .. ext.data + elseif ext.type==TLS_EXT_QUIC_TRANSPORT_PARAMETERS then + ext.data = barray(ext.dis.list, function(a) return bu16(a.type) .. bu16(#a.data) .. a.data end) + ext.data = bu16(#ext.data) .. ext.data + elseif ext.type==TLS_EXT_QUIC_TRANSPORT_PARAMETERS_V1 then + ext.data = barray(ext.dis.list, function(a) return bquic_tvb(a.type) .. bquic_tvb(#a.data) .. a.data end) + else + ext.data=nil + end + end + + return type(ext.data)=="string" +end + +-- reconstruct handshake dissect to raw string +-- deeper dissects are supported for client/server hello, others must have 'data' field +function tls_reconstruct_handshake(handshake) + if handshake.dis then + if handshake.dis.type == TLS_HANDSHAKE_TYPE_CLIENT or handshake.dis.type == TLS_HANDSHAKE_TYPE_SERVER then + handshake.data = nil + local header = + bu16(handshake.dis.ver or TLS_VER_TLS12) .. + ((handshake.dis.random and #handshake.dis.random==32) and handshake.dis.random or brandom(32)) .. + bu8(handshake.dis.session_id and #handshake.dis.session_id or 0) .. + (handshake.dis.session_id or "") + if handshake.dis.type == TLS_HANDSHAKE_TYPE_CLIENT then + header = header .. + bu16(handshake.dis.cipher_suites and 2*#handshake.dis.cipher_suites or 0) .. + (handshake.dis.cipher_suites and barray(handshake.dis.cipher_suites, bu16) or "") .. + bu8(handshake.dis.compression_methods and #handshake.dis.compression_methods or 0) .. + (handshake.dis.compression_methods and barray(handshake.dis.compression_methods, bu8) or "") + else + header = header .. + bu16(handshake.dis.cipher_suite) .. + bu8(handshake.dis.compression_method) + end + local exts="" + if handshake.dis.ext then + for i=1,#handshake.dis.ext do + if not tls_reconstruct_ext(handshake.dis.ext[i]) then + return nil + end + exts = exts .. bu16(handshake.dis.ext[i].type) .. bu16(#handshake.dis.ext[i].data) .. handshake.dis.ext[i].data + end + handshake.data = bu8(handshake.type) .. bu24(#header + 2 + #exts) .. header .. bu16(#exts) .. exts + else + handshake.data = bu8(handshake.type) .. bu24(#header) .. header + end + end + end + + return type(handshake.data)=="string" +end + +-- recconstruct tls dissect to raw tls +-- supports tls records with optional handshake dissects +-- supports single handshake without tls records +function tls_reconstruct(tdis) + if tdis.handshake then + for htyp, handshake in pairs(tdis.handshake) do + if not tls_reconstruct_handshake(handshake) then return nil end + end + end + + local tls + if tdis.rec then + -- need to follow in order + local i=1 + while i <= #tdis.rec do + local rec = tdis.rec[i] + if rec.type==TLS_RECORD_TYPE_HANDSHAKE and not rec.encrypted and rec.htype and tdis.handshake and tdis.handshake[rec.htype] and tdis.handshake[rec.htype].data then + rec.data = nil + + local data = tdis.handshake[rec.htype].data + local htyp = rec.htype + local j = i + 1 + while j <= #tdis.rec and tdis.rec[j].type==TLS_RECORD_TYPE_HANDSHAKE and not tdis.rec[j].encrypted and tdis.rec[j].htype == htyp do + j = j + 1 + end + j = j - 1 + local off = 1 + for k=i,j do + local chunk_size = #data-off+1 + -- last chunk takes all remaining data + if k~=j then + chunk_size = (chunk_size < tdis.rec[k].len) and chunk_size or tdis.rec[k].len + end + tdis.rec[k].data = string.sub(data, off, off + chunk_size - 1) + tdis.rec[k].len = chunk_size + off = off + chunk_size + end + i = j + 1 + else + i = i + 1 + end + if not rec.data then return nil end + end + tls = barray(tdis.rec, function(a) return (#a.data > 0) and (bu8(a.type) .. bu16(a.ver) .. bu16(#a.data) .. a.data) or "" end) + elseif tdis.handshake then + local i = next(tdis.handshake) + if i~=nil then + tls = tdis.handshake[i].data + end + end + + return tls +end diff --git a/blockcheck/zapret2/lua/zapret-obfs.lua b/blockcheck/zapret2/lua/zapret-obfs.lua new file mode 100644 index 0000000..1d39cea --- /dev/null +++ b/blockcheck/zapret2/lua/zapret-obfs.lua @@ -0,0 +1,487 @@ +-- test case : --in-range=a --out-range=a --lua-desync=wgobfs:secret=mycoolpassword +-- encrypt standard wireguard messages - initiation, response, cookie - and change udp packet size +-- do not encrypt data messages and keepalives +-- wgobfs adds maximum of 30+padmax bytes to udp size +-- reduce MTU of wireguard interface to avoid ip fragmentation ! +-- without knowing the secret encrypted packets should be crypto strong white noise with no signature +-- arg : secret - shared secret. any string. must be the same on both peers +-- arg : padmin - min random garbage bytes. 0 by default +-- arg : padmax - max random garbage bytes. 16 by default +-- NOTE : this function does not depend on zapret-lib.lua and should not be run under orchestrator (uses direct instance_cutoff) +function wgobfs(ctx, desync) + if not desync.dis.udp then + instance_cutoff_shim(ctx, desync) + return + end + + local padmin = desync.arg.padmin and tonumber(desync.arg.padmin) or 0 + local padmax = desync.arg.padmax and tonumber(desync.arg.padmax) or 16 + local function genkey() + -- cache key in a global var bound to instance name + local key_cache_name = desync.func_instance.."_key" + local key = _G[key_cache_name] + if not key then + key = hkdf("sha256", "wgobfs_salt", desync.arg.secret, nil, 16) + _G[key_cache_name] = key + end + return key + end + local function maybe_encrypted_payload(payload) + for k,plsize in pairs({2+12+16+148, 2+12+16+92, 2+12+16+64}) do + if #payload>=(plsize+padmin) and #payload<=(plsize+padmax) then + return true + end + end + return false + end + local function wg_payload_from_size(payload) + if #payload==148 then return "wireguard_initiation" + elseif #payload==92 then return "wireguard_response" + elseif #payload==64 then return "wireguard_cookie" + else return nil + end + end + + if not desync.arg.secret or #desync.arg.secret==0 then + error("wgobfs: secret required") + end + if padmin>padmax then + error("wgobfs: padmin>padmax") + end + if (desync.l7payload=="wireguard_initiation" or desync.l7payload=="wireguard_response" or desync.l7payload=="wireguard_cookie") and #desync.dis.payload<65506 then + DLOG("wgobfs: encrypting '"..desync.l7payload.."'. size "..#desync.dis.payload) + local key = genkey() + -- in aes-gcm every message require it's own crypto secure random iv + -- encrypting more than one message with the same iv is considered catastrophic failure + -- iv must be sent with encrypted message + local iv = bcryptorandom(12) + local encrypted, atag = aes_gcm(true, key, iv, bu16(#desync.dis.payload)..desync.dis.payload..brandom(math.random(padmin,padmax)), nil) + desync.dis.payload = iv..atag..encrypted + return VERDICT_MODIFY + end + + if desync.l7payload=="unknown" and maybe_encrypted_payload(desync.dis.payload) then + local key = genkey() + local iv = string.sub(desync.dis.payload,1,12) + local atag = string.sub(desync.dis.payload,13,28) + local decrypted, atag2 = aes_gcm(false, key, iv, string.sub(desync.dis.payload,29)) + if atag==atag2 then + local plen = u16(decrypted) + if plen>(#decrypted-2) then + DLOG("wgobfs: bad decrypted payload data") + else + desync.dis.payload = string.sub(decrypted, 3, 3+plen-1) + if b_debug then DLOG("wgobfs: decrypted '"..(wg_payload_from_size(desync.dis.payload) or "unknown").."' message. size "..plen) end + return VERDICT_MODIFY + end + else + DLOG("wgobfs: decrypt auth tag mismatch") + end + end +end + +-- test case : +-- endpoint1: +-- --filter-icmp=0,8,128,129 --filter-ipp=193,198,209,250 --filter-tcp=* --filter-udp=* --in-range=a --lua-desync=ippxor:ippxor=192:dataxor=0xABCD +-- nft add rule inet ztest pre meta mark and 0x40000000 == 0 meta l4proto {193, 198, 209, 250} queue num 200 bypass +-- nft add rule inet ztest post meta mark and 0x40000000 == 0 tcp dport "{5001}" queue num 200 bypass +-- nft add rule inet ztest post meta mark and 0x40000000 == 0 udp dport "{5001}" queue num 200 bypass +-- iperf -i 1 -c endpoint2 +-- endpoint2: +-- --filter-icmp=0,8,128,129 --filter-ipp=193,198,209,250 --filter-tcp=* --filter-udp=* --in-range=a --lua-desync=ippxor:ippxor=192:dataxor=0xABCD --server +-- nft add rule inet ztest pre meta mark and 0x40000000 == 0 meta l4proto {193, 198, 209, 250} queue num 200 bypass +-- nft add rule inet ztest post meta mark and 0x40000000 == 0 tcp sport "{5001}" queue num 200 bypass +-- nft add rule inet ztest post meta mark and 0x40000000 == 0 udp sport "{5001}" queue num 200 bypass +-- iperf -s +-- xor ip protocol number and optionally xor tcp,udp,icmp payload with supplied blob pattern +-- arg : ippxor - value to xor ip protocol number +-- arg : dataxor - blob to xor tcp, udp or icmp payload +-- arg : rebuild - always reconstruct desync.dis if after ippxor packet becomes tcp,udp or icmp +function ippxor(ctx, desync) + local dataxor + local function need_dxor(dis) + return dataxor and dis.payload and #dis.payload>0 and (dis.tcp or dis.udp or dis.icmp) + end + local function dxor(dis) + dis.payload = bxor(dis.payload, pattern(dataxor,1,#dis.payload)) + end + + if not desync.arg.ippxor then + error("ippxor: ippxor value required") + end + local ippxor = tonumber(desync.arg.ippxor) + if ippxor<0 or ippxor>0xFF then + error("ippxor: invalid ippxor value. should be 0..255") + end + if desync.arg.dataxor then + dataxor = blob(desync,desync.arg.dataxor) + if #dataxor==0 then + error("ippxor: empty dataxor value") + end + end + + local bdxor = need_dxor(desync.dis) + if bdxor then + DLOG("ippxor: dataxor size="..#desync.dis.payload) + dxor(desync.dis) + end + + local l3_from = ip_proto_l3(desync.dis) + local l3_to = bitxor(l3_from, ippxor) + DLOG("ippxor: "..l3_from.." => "..l3_to) + fix_ip_proto(desync.dis, l3_to) + + if (not bdxor and dataxor or desync.arg.rebuild) and + (l3_to==IPPROTO_TCP and not desync.dis.tcp or + l3_to==IPPROTO_UDP and not desync.dis.udp or + l3_to==IPPROTO_ICMP and not (desync.dis.ip and desync.dis.icmp) or + l3_to==IPPROTO_ICMPV6 and not (desync.dis.ip6 and desync.dis.icmp)) + then + DLOG("ippxor: packet rebuild") + local raw_ip = reconstruct_dissect(desync.dis, {ip6_preserve_next=true}) + local dis = dissect(raw_ip) + if not dis.ip and not dis.ip6 then + DLOG_ERR("ippxor: could not rebuild packet") + return + end + desync.dis = dis + end + + if not bdxor and need_dxor(desync.dis) then + DLOG("ippxor: dataxor size="..#desync.dis.payload) + dxor(desync.dis) + end + + return VERDICT_MODIFY + VERDICT_PRESERVE_NEXT +end + +-- test case: +-- endpoint1: +-- --in-range=a --lua-desync=udp2icmp +-- nft add rule inet ztest post meta mark and 0x40000000 == 0 udp dport 12345 queue num 200 bypass +-- nft add rule inet ztest pre meta mark and 0x40000000 == 0 meta l4proto "{icmp,icmpv6}" queue num 200 bypass +-- endpoint2: +-- --in-range=a --lua-desync=udp2icmp --server +-- nft add rule inet ztest post meta mark and 0x40000000 == 0 udp sport 12345 queue num 200 bypass +-- nft add rule inet ztest pre meta mark and 0x40000000 == 0 meta l4proto "{icmp,icmpv6}" queue num 200 bypass +-- packs udp datagram to icmp message without changing packet size +-- function keeps icmp identifier as (sport xor dport) to help traverse NAT (it won't help if NAT changes id) +-- one end must be in server mode, another - in client mode +-- arg : ctype - client icmp type +-- arg : ccode - client icmp code +-- arg : stype - server icmp type +-- arg : scode - server icmp code +-- arg : dataxor - blob to xor udp payload +-- arg : server=[0|1] - override server mode. by default use "--server" nfqws2 parameter +function udp2icmp(ctx, desync) + local dataxor + local bserver + if desync.arg.server then + bserver = desync.arg.server~="0" + else + bserver = b_server + end + + local function one_byte_arg(name) + if desync.arg[name] then + local v = tonumber(desync.arg[name]) + if v<0 or v>0xFF then + error("udp2icmp: invalid type or code value. should be 0..255") + end + return v + end + end + local function ictype(send) + local ctype = one_byte_arg("ctype") + local stype = one_byte_arg("stype") + if logical_xor(ctype,stype) then + error("udp2icmp: ctype and stype must be both set or not set") + end + if not ctype then + ctype = desync.dis.ip6 and ICMP6_ECHO_REQUEST or ICMP_ECHO + stype = desync.dis.ip6 and ICMP6_ECHO_REPLY or ICMP_ECHOREPLY + end + return logical_xor(send,bserver) and ctype or stype + end + local function iccode(send) + local ccode = one_byte_arg("ccode") + local scode = one_byte_arg("scode") + if logical_xor(ccode,scode) then + error("udp2icmp: ccode and scode must be both set or not set") + end + if not ccode then + ccode = 0 + scode = 0 + end + return logical_xor(send,bserver) and ccode or scode + end + local function plxor() + if dataxor then + DLOG("udp2icmp: dataxor") + desync.dis.payload = bxor(desync.dis.payload, pattern(dataxor,1,#desync.dis.payload)) + end + end + + if desync.arg.dataxor then + dataxor = blob(desync,desync.arg.dataxor) + if #dataxor==0 then + error("udp2icmp: empty dataxor value") + end + end + + if desync.dis.udp then + plxor() + if b_debug then -- save some cpu + DLOG("udp2icmp: udp => icmp sport="..desync.dis.udp.uh_sport.." dport="..desync.dis.udp.uh_dport.." size="..#desync.dis.payload) + end + desync.dis.icmp = { + icmp_type = ictype(true), + icmp_code = iccode(true), + icmp_data = u32( + bu16(bitxor(desync.dis.udp.uh_sport,desync.dis.udp.uh_dport)).. + (bserver and bu16(desync.dis.udp.uh_sport) or bu16(desync.dis.udp.uh_dport))) + } + desync.dis.udp = nil + fix_ip_proto(desync.dis) + return VERDICT_MODIFY + elseif desync.dis.icmp and desync.dis.icmp.icmp_type==ictype(false) and desync.dis.icmp.icmp_code==iccode(false) then + local pl = bitand(desync.dis.icmp.icmp_data,0xFFFF) + local pm = bitxor(bitrshift(desync.dis.icmp.icmp_data,16),pl) + desync.dis.udp = { + uh_sport = bserver and pm or pl, + uh_dport = bserver and pl or pm, + uh_ulen = UDP_BASE_LEN + #desync.dis.payload + } + desync.dis.icmp = nil + fix_ip_proto(desync.dis) + if b_debug then -- save some cpu + DLOG("udp2icmp: icmp => udp sport="..desync.dis.udp.uh_sport.." dport="..desync.dis.udp.uh_dport.." size="..#desync.dis.payload) + end + plxor() + return VERDICT_MODIFY + end +end + +--[[ + test case : + both: + nft create table inet ztest + nft add chain inet ztest post "{type filter hook output priority mangle;}" + nft add chain inet ztest pre "{type filter hook input priority mangle;}" + nft add chain inet ztest predefrag "{type filter hook output priority -401;}" + nft add rule inet ztest predefrag "mark & 0x40000000 != 0x00000000 notrack" + client: + --in-range=" administratively prohibited + x2 = 1 + end + + local kind + if desync.arg.kind then + kind = tonumber(desync.arg.kind) + -- do not allow noop and end + if kind<2 or kind>0xFF then + error("synhide: invalid kind value") + end + else + kind = 172 -- accurate ecn + end + + local opt + if desync.arg.opt then + opt = parse_hex(desync.arg.opt) + if not opt then + error("synhide: invalid opt value") + end + else + opt="" + end + + + local xorseq + if desync.arg.xorseq then + xorseq = parse_hex(desync.arg.xorseq) + if not xorseq or #xorseq~=4 then + error("synhide: invalid xorseq value") + end + xorseq = u32(xorseq) + end + + local function make_magic(client) + local m + -- use client seq0 + m = client and desync.dis.tcp.th_seq or desync.dis.tcp.th_ack-1 + m = bitxor(bitrshift(m,16),bitand(m,0xFFFF)) + if m==0 then + -- 0 is not acceptable + m = client and desync.dis.tcp.th_dport or desync.dis.tcp.th_sport + end + return m + end + local function xorhdr() + if xorseq then + desync.dis.tcp.th_ack = bitxor(desync.dis.tcp.th_ack, xorseq) + desync.dis.tcp.th_seq = bitxor(desync.dis.tcp.th_seq, xorseq) + end + end + local function ver_magic(client) + local r = false + xorhdr() + if magic=="tsecr" then + r = make_magic(client)==u16(string.sub(desync.dis.tcp.options[tsidx].data,7)) + elseif magic=="x2" then + r = bitand(desync.dis.tcp.th_x2, x2)~=0 + elseif magic=="urp" then + r = desync.dis.tcp.th_urp == make_magic(client) + elseif magic=="opt" then + local idx = find_tcp_option(desync.dis.tcp.options, kind) + r = idx and desync.dis.tcp.options[idx].data == opt + end + xorhdr() + return r + end + local function set_magic(client) + if magic=="tsecr" then + desync.dis.tcp.options[tsidx].data = string.sub(desync.dis.tcp.options[tsidx].data,1,6) .. bu16(make_magic(client)) + elseif magic=="x2" then + desync.dis.tcp.th_x2 = bitor(desync.dis.tcp.th_x2, x2) + elseif magic=="urp" then + desync.dis.tcp.th_urp = make_magic(client) + elseif magic=="opt" then + table.insert(desync.dis.tcp.options, {kind=kind, data=opt}) + end + xorhdr() + end + local function clear_magic() + xorhdr() + if magic=="tsecr" then + desync.dis.tcp.options[tsidx].data = string.sub(desync.dis.tcp.options[tsidx].data,1,6) .. "\x00\x00" + elseif magic=="x2" then + desync.dis.tcp.th_x2 = bitand(desync.dis.tcp.th_x2,bitnot(x2)) + elseif magic=="urp" then + desync.dis.tcp.th_urp = 0 + elseif magic=="opt" then + local idx = find_tcp_option(desync.dis.tcp.options, kind) + if idx then + table.remove(desync.dis.tcp.options, idx) + end + end + desync.track = conntrack_feed(desync.dis) + end + + if fl==TH_SYN then + -- client sent + local ttl = tonumber(desync.dis.ip and desync.arg.ghost or desync.arg.ghost6) + if ttl then + DLOG("synhide: punch NAT hole with ttl="..ttl) + local dis = deepcopy(desync.dis) + if dis.ip then + dis.ip.ip_ttl = ttl + elseif dis.ip6 then + dis.ip6.ip6_hlim = ttl + end + if not rawsend_dissect(dis, rawsend_opts_base(desync)) then + instance_cutoff_shim(ctx, desync) -- failed + return + end + end + DLOG("synhide: client sends SYN. remove SYN") + set_magic(true) + -- remove SYN, set ACK + desync.dis.tcp.th_flags = bitor(bitand(desync.dis.tcp.th_flags, bitnot(TH_SYN)), TH_ACK) + if not desync.arg.synack then + DLOG("synhide: mission complete") + instance_cutoff_shim(ctx, desync) + end + return VERDICT_MODIFY + elseif fl==(TH_SYN+TH_ACK) then + -- server sent + if desync.arg.synack then + DLOG("synhide: server sends SYN+ACK. remove SYN, set RST") + set_magic(false) + desync.dis.tcp.th_flags = bitor(bitand(desync.dis.tcp.th_flags, bitnot(TH_SYN)), TH_RST) + return VERDICT_MODIFY + else + DLOG("synhide: server sends SYN+ACK. do not remove SYN because 'synack' arg is not set.") + instance_cutoff_shim(ctx, desync) + return -- do nothing + end + elseif fl==TH_ACK and ver_magic(true) then + DLOG("synhide: server received magic. restore SYN") + desync.dis.tcp.th_flags = bitor(bitand(desync.dis.tcp.th_flags, bitnot(TH_ACK)), TH_SYN) + clear_magic() + if not desync.arg.synack then + DLOG("synhide: mission complete") + instance_cutoff_shim(ctx, desync) + end + return VERDICT_MODIFY + elseif fl==(TH_ACK+TH_RST) and ver_magic(false) then + DLOG("synhide: client received magic. restore SYN, remove RST") + desync.dis.tcp.th_flags = bitor(bitand(desync.dis.tcp.th_flags, bitnot(TH_RST)), TH_SYN) + clear_magic() + DLOG("synhide: mission complete") + instance_cutoff_shim(ctx, desync) + return VERDICT_MODIFY + end + + DLOG("synhide: sequence failed") + instance_cutoff_shim(ctx, desync) +end diff --git a/blockcheck/zapret2/lua/zapret-pcap.lua b/blockcheck/zapret2/lua/zapret-pcap.lua new file mode 100644 index 0000000..ff979dc --- /dev/null +++ b/blockcheck/zapret2/lua/zapret-pcap.lua @@ -0,0 +1,40 @@ +function pcap_write_header(file) + -- big endian, nanoseconds in timestamps, ver 2.4, max packet size - 0xFFFF (65535), 0x65 - l3 packets without l2 + file:write("\xA1\xB2\x3C\x4D\x00\x02\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\x00\x00\x00\x65") +end +function pcap_write_packet(file, raw) + local sec, nsec = clock_gettime(); + file:write(bu32(sec)..bu32(nsec)..bu32(#raw)..bu32(#raw)) + file:write(raw) +end +function pcap_write(file, raw) + local pos = file:seek('end') + if (pos==0) then + pcap_write_header(file) + end + pcap_write_packet(file, raw) +end + +-- test case : --writable=zdir --in-range=a --lua-desync=pcap:file=test.pcap +-- arg : file= - file for storing pcap data. if --writable is specified and filename is relative - append filename to writable path +-- arg : keep - do not overwrite file, append packets to existing +function pcap(ctx, desync) + if not desync.arg.file or #desync.arg.file==0 then + error("pcap requires 'file' parameter") + end + local fn_cache_name = desync.func_instance.."_fn" + if not _G[fn_cache_name] then + _G[fn_cache_name] = writable_file_name(desync.arg.file) + if not desync.arg.keep then + -- overwrite file + os.remove(_G[fn_cache_name]) + end + end + local f = io.open(_G[fn_cache_name], "ab") + if not f then + error("pcap: could not write to '".._G[fn_cache_name].."'") + end + local raw = ctx and raw_packet(ctx) or reconstruct_dissect(desync.dis) + pcap_write(f, raw) + f:close() +end diff --git a/blockcheck/zapret2/lua/zapret-tests.lua b/blockcheck/zapret2/lua/zapret-tests.lua new file mode 100644 index 0000000..b0eca54 --- /dev/null +++ b/blockcheck/zapret2/lua/zapret-tests.lua @@ -0,0 +1,1157 @@ +-- nfqws2 C functions tests +-- to run : --lua-init=@zapret-lib.lua --lua-init=@zapret-tests.lua --lua-init="test_all()" + +function test_assert(b) + assert(b, "test failed") +end + +function test_run(tests,...) + for k,f in pairs(tests) do + f(...) + end +end + + +function test_all(...) + test_run({ + test_crypto, test_bin, test_time, test_gzip, test_ipstr, test_dissect, test_csum, test_resolve, + test_get_source_ip, test_ifaddrs, test_rawsend, test_timer},...) +end + + +function test_crypto(...) + test_run({test_random, test_bop, test_aes, test_aes_gcm, test_aes_ctr, test_hkdf, test_hash},...) +end + +function test_random() + print("* random") + + local rnds={} + for i=1,20 do + local rnd = bcryptorandom(math.random(10,20)) + print("random: "..string2hex(rnd)) + test_assert(not rnds[rnd]) -- should not be repeats + rnds[rnd] = true + end +end + +function test_bop() + print("* bop") + + for n,test in ipairs( + { + { fb = bxor, fbit = bitxor, nb = "bxor", nbit="bitxor" }, + { fb = bor, fbit = bitor, nb = "bor", nbit="bitor" }, + { fb = band, fbit = bitand, nb = "band", nbit="bitand" } + }) do + for k=1,5 do + local r = {} + for i=1,6 do r[i] = math.random(0,0xFFFFFFFFFFFF) end + local v1 = bu48(r[1])..bu48(r[2])..bu48(r[3]) + local v2 = bu48(r[4])..bu48(r[5])..bu48(r[6]) + print("x1 : "..string2hex(v1)) + print("x2 : "..string2hex(v2)) + local v3 = test.fb(v1,v2) + local v4 = bu48(test.fbit(r[1],r[4]))..bu48(test.fbit(r[2],r[5]))..bu48(test.fbit(r[3],r[6])) + print(test.nb.." : "..string2hex(v3)) + print(test.nbit.." : "..string2hex(v4)) + print("result : "..(v3==v4 and "OK" or "FAIL")) + test_assert(v3==v4) + end + end +end + +function test_hash() + print("* hash") + + local hashes={} + for i=1,5 do + local rnd = brandom(math.random(5,64)) + print("data: "..string2hex(rnd)) + for k,sha in pairs({"sha256","sha224"}) do + local hsh = hash(sha, rnd) + print(sha..": "..string2hex(hsh)) + local hsh2 = hash(sha, rnd) + test_assert(hsh==hsh2) + test_assert(not hashes[hsh]) + hashes[hsh] = true + end + end +end + +function test_hkdf() + print("* hkdf") + + local nblob = 2 + local okms = {} + for nsalt=1,nblob do + local salt = brandom(math.random(10,20)) + for nikm=1,nblob do + local ikm = brandom(math.random(5,10)) + for ninfo=1,nblob do + local info = brandom(math.random(5,10)) + for k,sha in pairs({"sha256","sha224"}) do + local okm_prev + for k,okml in pairs({8, 16, 50}) do + local okm + print("* hkdf "..sha) + print("salt: "..string2hex(salt)) + print("ikm : "..string2hex(ikm)) + print("info: "..string2hex(info)) + print("okml: "..tostring(okml)) + okm = hkdf(sha, salt, ikm, info, okml) + test_assert(okm) + print("okm: "..string2hex(okm)) + if okms[okm] then + print("duplicate okm !") + end + okms[okm] = true + test_assert(not okm_prev or okm_prev==string.sub(okm, 1, #okm_prev)) + okm_prev = okm + end + end + end + end + end +end + +function test_aes() + print("* aes") + + local clear_text="test "..brandom_az09(11) + local encrypted, decrypted + + for key_size=16,32,8 do + local key = brandom(key_size) + + print() + print("* aes test key_size "..tostring(key_size)) + + print("clear text: "..clear_text) + + print("* encrypting") + encrypted = aes(true, key, clear_text) + print("encrypted: "..str_or_hex(encrypted)) + + print("* decrypting everything good") + decrypted = aes(false, key, encrypted) + print("decrypted: "..str_or_hex(decrypted)) + print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" ) + test_assert(decrypted==clear_text) + + print("* decrypting bad payload with good key") + decrypted = aes(false, key, brandom(16)) + print("decrypted: "..str_or_hex(decrypted)) + print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" ) + test_assert(decrypted~=clear_text) + + print("* decrypting good payload with bad key") + decrypted = aes(false, brandom(key_size), encrypted) + print("decrypted: "..str_or_hex(decrypted)) + print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" ) + test_assert(decrypted~=clear_text) + + end +end + +function test_aes_gcm() + print("* aes_gcm") + + local authenticated_data = "authenticated message "..brandom_az09(math.random(10,50)) + local clear_text="test message "..brandom_az09(math.random(10,50)) + local iv, key, encrypted, atag, decrypted, atag2 + + for key_size=16,32,8 do + iv = brandom(12) + key = brandom(key_size) + + print() + print("* aes_gcm test key_size "..tostring(key_size)) + + print("clear text: "..clear_text) + print("authenticated data: "..authenticated_data) + + print("* encrypting") + encrypted, atag = aes_gcm(true, key, iv, clear_text, authenticated_data) + print("encrypted: "..str_or_hex(encrypted)) + print("auth tag: "..string2hex(atag)) + + print("* decrypting everything good") + decrypted, atag2 = aes_gcm(false, key, iv, encrypted, authenticated_data) + print("decrypted: "..str_or_hex(decrypted)) + print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" ) + test_assert(decrypted==clear_text) + print("auth tag: "..string2hex(atag2)) + print( atag==atag2 and "TAG OK" or "TAG ERROR" ) + test_assert(atag==atag2) + + print("* decrypting bad payload with good key/iv and correct authentication data") + decrypted, atag2 = aes_gcm(false, key, iv, brandom(#encrypted), authenticated_data) + print("decrypted: "..str_or_hex(decrypted)) + print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" ) + test_assert(decrypted~=clear_text) + print("auth tag: "..string2hex(atag2)) + print( atag==atag2 and "TAG OK" or "TAG ERROR" ) + test_assert(atag~=atag2) + + print("* decrypting good payload with good key/iv and incorrect authentication data") + decrypted, atag2 = aes_gcm(false, key, iv, encrypted, authenticated_data.."x") + print("decrypted: "..str_or_hex(decrypted)) + print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" ) + test_assert(decrypted==clear_text) + print("auth tag: "..string2hex(atag2)) + print( atag==atag2 and "TAG OK" or "TAG ERROR" ) + test_assert(atag~=atag2) + + print("* decrypting good payload with bad key, good iv and correct authentication data") + decrypted, atag2 = aes_gcm(false, brandom(key_size), iv, encrypted, authenticated_data) + print("decrypted: "..str_or_hex(decrypted)) + print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" ) + test_assert(decrypted~=clear_text) + print("auth tag: "..string2hex(atag2)) + print( atag==atag2 and "TAG OK" or "TAG ERROR" ) + test_assert(atag~=atag2) + + print("* decrypting good payload with good key, bad iv and correct authentication data") + decrypted, atag2 = aes_gcm(false, key, brandom(12), encrypted, authenticated_data) + print("decrypted: "..str_or_hex(decrypted)) + print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" ) + test_assert(decrypted~=clear_text) + print("auth tag: "..string2hex(atag2)) + print( atag==atag2 and "TAG OK" or "TAG ERROR" ) + test_assert(atag~=atag2) + end +end + +function test_aes_ctr() + print("* aes_ctr") + + local clear_text="test message "..brandom_az09(math.random(10,50)) + local iv, key, encrypted, decrypted + + for key_size=16,32,8 do + iv = brandom(16) + key = brandom(key_size) + + print() + print("* aes_ctr test key_size "..tostring(key_size)) + + print("clear text: "..clear_text) + + print("* encrypting") + encrypted = aes_ctr(key, iv, clear_text) + print("encrypted: "..str_or_hex(encrypted)) + + print("* decrypting") + decrypted = aes_ctr(key, iv, encrypted) + print("decrypted: "..str_or_hex(decrypted)) + print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" ) + test_assert(decrypted==clear_text) + + print("* decrypting with bad key") + decrypted = aes_ctr(bu8(bitand(u8(string.sub(key,1,1))+1,0xFF))..string.sub(key,2), iv, encrypted) + print("decrypted: "..str_or_hex(decrypted)) + print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" ) + test_assert(decrypted~=clear_text) + + print("* decrypting with bad iv") + decrypted = aes_ctr(key, bu8(bitand(u8(string.sub(iv,1,1))+1,0xFF))..string.sub(iv,2), encrypted) + print("decrypted: "..str_or_hex(decrypted)) + print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" ) + test_assert(decrypted~=clear_text) + end + + -- openssl enc -aes-256-ctr -d -in rnd.bin -out rnd_decrypted.bin -K c39383634d87eb3b6e56edf2c8c0ba99cc8cadf000fb2cd737e37947eecde5fd -iv d745164b233f10b93945526ffe94b87f + print("* aes_ctr const tests") + + local data="\x9d\x9c\xa0\x78\x2e\x17\x84\xfc\x87\xc7\xf5\xdf\x5b\xb5\x71\xfd\xb9\xcb\xd2\x4d\xae\x2f\xf0\x19\xf3\xad\x79\xa8\x9a\xb4\xed\x28\x88\x3c\xe1\x78\x91\x23\x27\xd4\x8d\x94\xb3\xd0\x81\x88\xd2\x55\x95\x8a\x88\x70\x67\x99\x75\xb2\xee\x30\x0f\xe7\xc6\x32\x10" + local iv="\xd7\x45\x16\x4b\x23\x3f\x10\xb9\x39\x45\x52\x6f\xfe\x94\xb8\x7f" + local tests = { + { + key="\xc3\x93\x83\x63\x4d\x87\xeb\x3b\x6e\x56\xed\xf2\xc8\xc0\xba\x99\xcc\x8c\xad\xf0\x00\xfb\x2c\xd7\x37\xe3\x79\x47\xee\xcd\xe5\xfd", + result="\x8C\x2C\x15\x99\x83\x37\x33\xEE\xA1\x70\xA7\x4A\x44\x2E\x6F\x56\x22\x41\xE1\xFC\xC5\x84\x21\x1C\x16\xC6\xE9\x75\x22\x57\x55\x4A\x02\x04\xCE\xAD\xE9\x0A\x45\xAB\x4E\x38\xB8\xB2\x6F\x95\xDA\x46\x4F\x9E\xB1\xFF\xF4\x40\x8A\x57\x25\xD2\xF6\xB6\x93\x65\x75" + }, + { + key="\xc3\x93\x83\x63\x4d\x87\xeb\x3b\x6e\x56\xed\xf2\xc8\xc0\xba\x99\xcc\x8c\xad\xf0\x00\xfb\x2c\xd7", + result="\xB0\x4C\xC9\xDB\x0C\xE5\x67\x51\x1D\x24\x3C\x15\x87\x1B\xF9\x62\x84\x8C\xD0\x57\x33\x93\xE0\x71\x91\x3A\x11\x26\xCA\x77\xA7\x54\xBD\xC6\x5E\x96\x60\x2C\x94\x0F\xBA\x3E\x79\xDC\x48\xA0\x22\x97\xA7\x77\x55\xC8\x14\xEA\xC2\xF5\xA0\x88\x6F\xE2\x44\x32\x68" + }, + { + key="\xc3\x93\x83\x63\x4d\x87\xeb\x3b\x6e\x56\xed\xf2\xc8\xc0\xba\x99", + result="\xD9\xAC\xC7\x7D\xC8\xC9\xF1\x59\x9A\xDF\x15\xF3\x58\x61\xFD\x2B\x1D\x01\x9A\x5F\x04\x53\xA2\xA8\xFD\x52\xDC\x8A\xE9\x3B\x2E\x5E\x0D\x13\xCB\xBD\x16\xED\xC1\xF2\x0D\x68\x62\xB7\xD5\x0F\x8D\xD4\xEB\xA1\xC5\x75\xF2\x0B\x26\x75\x1D\x7E\x5A\x37\xA6\x8A\xCD" + } + } + for k,t in pairs(tests) do + local decrypted = aes_ctr(t.key, iv, data) + io.write("KEY SIZE "..(#t.key*8).." ") + print( decrypted==t.result and "DECRYPT OK" or "DECRYPT ERROR" ) + test_assert(decrypted==t.result) + end +end + +function test_ub() + print("* ub") + + for k,f in pairs({{u8,bu8,0xFF,8}, {u16,bu16,0xFFFF,16}, {u24,bu24,0xFFFFFF,24}, {u32,bu32,0xFFFFFFFF,32}, {u48,bu48,0xFFFFFFFFFFFF,48}}) do + local v = math.random(0,f[3]) + local pos = math.random(1,20) + local s = brandom(pos-1)..f[2](v)..brandom(20) + local v2 = f[1](s,pos) + print(string.format("u%u pos=%u %016X %016X",f[4],pos,v,v2)) + test_assert(v==v2) + end +end + +function test_bit() + print("* bit") + + local v, v2, v3, v4, b1, b2, pow + + for i=1,100 do + v = math.random(0,0xFFFFFFFFFFFF) + b1 = math.random(1,16) + + v2 = bitrshift(v, b1) + pow = 2^b1 + v3 = divint(v, pow) + print(string.format("rshift(0x%X,%u) = 0x%X 0x%X/%u = 0x%X", v,b1,v2, v,pow,v3)) + test_assert(v2==v3) + + v = math.random(0,0xFFFFFFFFF) + b1 = math.random(1,12) + v2 = bitlshift(v, b1) + pow = 2^b1 + v3 = (v * pow) % 0x1000000000000 + print(string.format("lshift(0x%X,%u) = 0x%X 0x%X*%u %% 0x100000000000 = 0x%X", v,b1,v2, v,pow,v3)) + test_assert(v2==v3) + + v2 = math.random(0,0xFFFFFFFFFFFF) + v3 = bitxor(v, v2) + v4 = bitor(v, v2) - bitand(v, v2) + print(string.format("xor(0x%X,0x%X) = %X or/and/minus = %X", v, v2, v3, v4)) + test_assert(v3==v4) + + b1 = math.random(1,31) + b2 = b1 + math.random(1,16) + v2 = bitget(v, b1, b2) + pow = 2^(b2-b1+1) - 1 + v3 = bitand(bitrshift(v,b1), pow) + print(string.format("bitget(0x%X,%u,%u) = 0x%X bitand/bitrshift/pow = 0x%X", v, b1, b2, v2, v3)) + test_assert(v2==v3) + + v4 = math.random(0,pow) + v2 = bitset(v, b1, b2, v4) + v3 = bitor(bitlshift(v4, b1), bitand(v, bitnot(bitlshift(pow, b1)))) + print(string.format("bitset(0x%X,%u,%u,0x%X) = 0x%X bitand/bitnot/bitlshift/pow = 0x%X", v, b1, b2, v4, v2, v3)) + test_assert(v2==v3) + end +end + +function test_swap() + print("* swap") + + local v1, v2, v3 + + v1 = math.random(0,0xFFFF) + v2 = swap16(v1) + v3 = divint(v1,0x100) + v1%0x100*0x100 + print("swap16: "..(v2==v3 and "OK" or "FAIL")) + test_assert(v2==v3) + + v1 = math.random(0,0xFFFFFF) + v2 = swap24(v1) + v3 = divint(v1,0x10000) + divint(v1,0x100)%0x100*0x100 + v1%0x100*0x10000 + print("swap24: "..(v2==v3 and "OK" or "FAIL")) + test_assert(v2==v3) + + v1 = math.random(0,0xFFFFFFFF) + v2 = swap32(v1) + v3 = divint(v1,0x1000000) + divint(v1,0x10000)%0x100*0x100 + divint(v1,0x100)%0x100*0x10000 + v1%0x100*0x1000000 + print("swap32: "..(v2==v3 and "OK" or "FAIL")) + test_assert(v2==v3) + + v1 = math.random(0,0xFFFFFFFFFFFF) + v2 = swap48(v1) + v3 = divint(v1,0x10000000000) + + divint(v1,0x100000000)%0x100*0x100 + + divint(v1,0x1000000)%0x100*0x10000 + + divint(v1,0x10000)%0x100*0x1000000 + + divint(v1,0x100)%0x100*0x100000000 + + v1%0x100*0x10000000000 + print("swap48: "..(v2==v3 and "OK" or "FAIL")) + test_assert(v2==v3) +end + +function test_ux() + print("* ux") + + local v1, v2, v3, usum, sum + + for k,test in pairs({ + { add=u8add, fname="u8add", max = 0xFF }, + { add=u16add, fname="u16add", max = 0xFFFF }, + { add=u24add, fname="u24add", max = 0xFFFFFF }, + { add=u32add, fname="u32add", max = 0xFFFFFFFF }, + { add=u48add, fname="u48add", max = 0xFFFFFFFFFFFF } + }) do + io.write(test.fname.." : ") + for i=1,1000 do + v1=math.random(-test.max,test.max) + v2=math.random(-test.max,test.max) + v3=math.random(-test.max,test.max) + usum = test.add(v1,v2,v3) + sum = bitand((v1+v2+v3)%(test.max+1),test.max) + if sum~=usum then + print(string.format("FAIL: 0x%012X + 0x%012X + 0x%012X = 0x%012X 0x%012X",v1,v2,v3,usum,sum)) + end + test_assert(sum==usum) + end + print("OK") + end +end + +function test_bin(...) + test_run({test_ub, test_bit, test_swap, test_ux},...) +end + +function test_time(...) + print("* time") + + local unixtime=os.time() + local tm = localtime(unixtime); + local t + print() + print("now: "..tm.str.." "..tm.zone.." = "..unixtime) + local tm = gmtime(unixtime); + print("gmt: "..tm.str.." "..tm.zone.." = "..unixtime) + print() + for i=1,20 do + unixtime = math.random(0,0x7FFFFFFF); + tm = localtime(unixtime); + t = timelocal(tm) + print("timelocal: "..tm.str.." "..tm.zone.." = "..t) + print( t==unixtime and "LOCALTIME OK" or "LOCALTIME FAILED" ) + test_assert(t==unixtime) + + unixtime = math.random(0,0x7FFFFFFF); + tm = gmtime(unixtime); + t = timegm(tm) + print("timegm: "..tm.str.." "..tm.zone.." = "..t) + print( t==unixtime and "GMTIME OK" or "GMTIME FAILED" ) + test_assert(t==unixtime) + end + unixtime = math.random(0x80000000,0xFFFFFFFF); + tm = gmtime(unixtime) + t = timegm(tm) + print( t==unixtime and "TIME 0x80000000..0xFFFFFFFF OK" or "TIME 0x80000000..0xFFFFFFFF FAILED : "..unixtime.." != "..t.." ("..tm.str..")" ) + unixtime = math.random(0x100000000,0x200000000); + tm = gmtime(unixtime) + t = timegm(tm) + print( t==unixtime and "TIME 64 OK" or "TIME 64 FAILED : "..unixtime.." != "..t.." ("..tm.str..")" ) +end + +function test_gzip() + print("* gzip") + + local s="" + for i=1,math.random(2000,3000) do + local rnd=brandom(math.random(1,50)) + s=s..rnd..string.rep(bu8(math.random(0,255)),100-#rnd) + end + local v=math.random(100001,199999) + local level=math.random(1,9) + local memlevel=math.random(1,8) + print("gzip: original size "..#s) + print("gzip: cut point "..(v+1)) + print("gzip: level "..level) + print("gzip: memlevel "..memlevel) + local gz = gzip_init(nil, level, memlevel) + local zip = gzip_deflate(gz,string.sub(s,1,v)) + zip = zip..gzip_deflate(gz,string.sub(s,v+1)) + zip = zip..gzip_deflate(gz,nil) -- finalize + gzip_end(gz) + print("gzip: deflated size "..#zip) + local v=math.random(2,#zip-1) + print("gunzip: cut point "..(v+1)) + gz = gunzip_init() + local unzip = gunzip_inflate(gz,string.sub(zip,1,v)) + unzip = unzip..gunzip_inflate(gz,string.sub(zip,v+1)) + gunzip_end(gz) + print("gunzip: inflated size "..#unzip) + print("gzip+gunzip: "..(s==unzip and "OK" or "FAIL")) + test_assert(s==unzip) +end + +function test_ipstr() + print("* ipstr") + + local s_ip, ip, s_ip2 + + s_ip = string.format("%u.%u.%u.%u", math.random(0,255), math.random(0,255), math.random(0,255), math.random(0,255)) + ip = pton(s_ip) + s_ip2 = ntop(ip) + print("IP: "..s_ip) + print("IPBIN: "..string2hex(ip)) + print("IP2: "..s_ip2) + test_assert(s_ip==s_ip2) + + s_ip = string.format("%x:%x:%x:%x:%x:%x:%x:%x", math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF)) + ip = pton(s_ip) + s_ip2 = ntop(ip) + print("IP: "..s_ip) + print("IPBIN: "..string2hex(ip)) + print("IP2: "..s_ip2) + test_assert(s_ip==s_ip2) +end + + +function test_dissect() + print("* dissect") + + local raw1, raw2 + + for i=1,20 do + print("* dissect test "..tostring(i)) + + local ip_tcp = { + ip = { + ip_tos = math.random(0,255), + ip_id = math.random(0,0xFFFF), + ip_off = 0, + ip_ttl = math.random(0,255), + ip_p = IPPROTO_TCP, + ip_src = brandom(4), + ip_dst = brandom(4), + options = brandom(math.random(0,40)) + }, + tcp = { + th_sport = math.random(0,0xFFFF), + th_dport = math.random(0,0xFFFF), + th_seq = math.random(0,0xFFFFFFFF), + th_ack = math.random(0,0xFFFFFFFF), + th_x2 = math.random(0,0xF), + th_flags = math.random(0,0xFF), + th_win = math.random(0,0xFFFF), + th_urp = math.random(0,0xFFFF), + options = { + { kind = 1 }, + { kind = 0xE0, data = brandom(math.random(1,10)) }, + { kind = 1 }, + { kind = 0xE1, data = brandom(math.random(1,10)) } + } + }, + payload = brandom(math.random(0, 20)) + } + raw1 = reconstruct_dissect(ip_tcp) + print("IP+TCP : "..string2hex(raw1)) + dis1 = dissect(raw1) + raw2 = reconstruct_dissect(dis1) + dis2 = dissect(raw2) + print("IP+TCP2: "..string2hex(raw2)) + print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" ) + test_assert(raw1==raw2) + + print("IP standalone") + raw1 = reconstruct_iphdr(ip_tcp.ip) + print("IP1: "..string2hex(raw1)) + dis1 = dissect_iphdr(raw1) + raw2 = reconstruct_iphdr(dis1) + print("IP2: "..string2hex(raw2)) + print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" ) + test_assert(raw1==raw2) + + print("TCP standalone") + raw1 = reconstruct_tcphdr(ip_tcp.tcp) + print("TCP1: "..string2hex(raw1)) + dis1 = dissect_tcphdr(raw1) + raw2 = reconstruct_tcphdr(dis1) + print("TCP2: "..string2hex(raw2)) + print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" ) + test_assert(raw1==raw2) + + local ip_icmp = { + ip = { + ip_tos = math.random(0,255), + ip_id = math.random(0,0xFFFF), + ip_off = 0, + ip_ttl = math.random(0,255), + ip_p = IPPROTO_ICMP, + ip_src = brandom(4), + ip_dst = brandom(4), + options = brandom(math.random(0,40)) + }, + icmp = { + icmp_type = ICMP_DEST_UNREACH, icmp_code=ICMP_UNREACH_PORT, + icmp_data = math.random(1,0xFFFFFFFF) + } + } + print("ICMP standalone") + raw1 = reconstruct_icmphdr(ip_icmp.icmp) + print("ICMP1: "..string2hex(raw1)) + dis1 = dissect_icmphdr(raw1) + raw2 = reconstruct_icmphdr(dis1) + print("ICMP2: "..string2hex(raw2)) + print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" ) + test_assert(raw1==raw2) + + local ip6_udp = { + ip6 = { + ip6_flow = 0x60000000 + math.random(0,0xFFFFFFF), + ip6_hlim = math.random(1,0xFF), + ip6_src = brandom(16), + ip6_dst = brandom(16), + exthdr = { + { type = IPPROTO_HOPOPTS, data = brandom(6+8*math.random(0,2)) }, + { type = IPPROTO_AH, data = brandom(6+4*math.random(0,4)) } + } + }, + udp = { + uh_sport = math.random(0,0xFFFF), + uh_dport = math.random(0,0xFFFF) + }, + payload = brandom(math.random(0, 20)) + } + + raw1 = reconstruct_dissect(ip6_udp) + print("IP6+UDP : "..string2hex(raw1)) + dis1 = dissect(raw1) + raw2 = reconstruct_dissect(dis1) + dis2 = dissect(raw2) + print("IP6+UDP2: "..string2hex(raw2)) + print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" ) + test_assert(raw1==raw2) + + raw1 = string.sub(reconstruct_dissect(ip6_udp),1,-4-#ip6_udp.payload) + dis1 = dissect(raw1, false) + dis2 = dissect(raw1, true) + local ok = not dis1.ip6 and dis2.ip6 + print("IP6 partial : "..(ok and "OK" or "FAIL")) + test_assert(ok) + + print("IP6+IPP") + dis1 = {ip6 = ip6_udp.ip6, payload=brandom(math.random(1,1))} + raw1 = reconstruct_dissect(dis1,{ip6_last_proto=IPPROTO_IPIP}) + dis2 = dissect(raw1) + raw2 = reconstruct_dissect(dis2,{ip6_preserve_next=true}) + print("IP6+IPP1: "..string2hex(raw1)) + print("IP6+IPP2: "..string2hex(raw2)) + print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" ) + test_assert(raw1==raw2) + + print("UDP standalone") + raw1 = reconstruct_udphdr(ip6_udp.udp) + print("UDP1: "..string2hex(raw1)) + dis1 = dissect_udphdr(raw1) + raw2 = reconstruct_udphdr(dis1) + print("UDP2: "..string2hex(raw2)) + print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" ) + test_assert(raw1==raw2) + + print("IP6 standalone") + ip6_udp.ip6.ip6_plen = nil + raw1 = reconstruct_ip6hdr(ip6_udp.ip6,{ip6_last_proto=IPPROTO_UDP}) + print("IP1: "..string2hex(raw1)) + dis1 = dissect_ip6hdr(raw1) + raw2 = reconstruct_ip6hdr(dis1,{ip6_last_proto=IPPROTO_UDP}) + print("IP2: "..string2hex(raw2)) + print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" ) + test_assert(raw1==raw2) + end +end + +function test_csum() + print("* csum") + + local payload = brandom(math.random(10,20)) + local ip4b, ip6b, raw, tcpb, udpb, icmpb, dis1, dis2 + local ip = { + ip_tos = math.random(0,255), + ip_id = math.random(0,0xFFFF), + ip_len = math.random(0,0xFFFF), + ip_off = 0, + ip_ttl = math.random(0,255), + ip_p = IPPROTO_TCP, + ip_src = brandom(4), + ip_dst = brandom(4), + options = brandom(4*math.random(0,10)) + } + ip4b = reconstruct_iphdr(ip) + raw = bu8(0x40 + 5 + #ip.options/4) .. + bu8(ip.ip_tos) .. + bu16(ip.ip_len) .. + bu16(ip.ip_id) .. + bu16(ip.ip_off) .. + bu8(ip.ip_ttl) .. + bu8(ip.ip_p) .. + bu16(0) .. + ip.ip_src .. ip.ip_dst .. + ip.options + raw = csum_ip4_fix(raw) + print( raw==ip4b and "IP4 RECONSTRUCT+CSUM OK" or "IP4 RECONSTRUCT+CSUM FAILED" ) + test_assert(raw==ip4b) + + + local tcp = { + th_sport = math.random(0,0xFFFF), + th_dport = math.random(0,0xFFFF), + th_seq = math.random(0,0xFFFFFFFF), + th_ack = math.random(0,0xFFFFFFFF), + th_x2 = math.random(0,0xF), + th_flags = math.random(0,0xFF), + th_win = math.random(0,0xFFFF), + th_urp = math.random(0,0xFFFF), + options = { + { kind = 1 }, + { kind = 0xE0, data = brandom(math.random(1,10)) }, + { kind = 1 }, + { kind = 0xE1, data = brandom(math.random(1,10)) } + } + } + tcpb = reconstruct_tcphdr(tcp) + raw = bu16(tcp.th_sport) .. + bu16(tcp.th_dport) .. + bu32(tcp.th_seq) .. + bu32(tcp.th_ack) .. + bu8(l4_len({tcp = tcp}) * 4 + tcp.th_x2) .. + bu8(tcp.th_flags) .. + bu16(tcp.th_win) .. + bu16(0) .. + bu16(tcp.th_urp) .. + bu8(tcp.options[1].kind).. + bu8(tcp.options[2].kind)..bu8(2 + #tcp.options[2].data)..tcp.options[2].data .. + bu8(tcp.options[3].kind).. + bu8(tcp.options[4].kind)..bu8(2 + #tcp.options[4].data)..tcp.options[4].data + raw = raw .. string.rep(bu8(0), bitand(4-bitand(#raw,3),3)) + print( raw==tcpb and "TCP RECONSTRUCT OK" or "TCP RECONSTRUCT FAILED" ) + test_assert(raw==tcpb) + + raw = reconstruct_dissect({ip=ip, tcp=tcp, payload=payload}) + dis1 = dissect(raw) + ip.ip_len = IP_BASE_LEN + #ip.options + #tcpb + #payload + ip4b = reconstruct_iphdr(ip) + tcpb = csum_tcp_fix(ip4b,tcpb,payload) + dis2 = dissect(ip4b..tcpb..payload) + print( dis1.tcp.th_sum==dis2.tcp.th_sum and "TCP+IP4 CSUM OK" or "TCP+IP4 CSUM FAILED" ) + test_assert(dis1.tcp.th_sum==dis2.tcp.th_sum) + + + local ip6 = { + ip6_flow = 0x60000000 + math.random(0,0xFFFFFFF), + ip6_hlim = math.random(1,0xFF), + ip6_src = brandom(16), + ip6_dst = brandom(16), + exthdr = { + { type = IPPROTO_HOPOPTS, data = brandom(6+8*math.random(0,2)) } + } + } + ip6.ip6_plen = packet_len({ip6=ip6,tcp=tcp,payload=payload}) - IP6_BASE_LEN + ip6b = reconstruct_ip6hdr(ip6, {ip6_last_proto=IPPROTO_TCP}) + raw = bu32(ip6.ip6_flow) .. + bu16(ip6.ip6_plen) .. + bu8(ip6.exthdr[1].type) .. + bu8(ip6.ip6_hlim) .. + ip6.ip6_src .. ip6.ip6_dst .. + bu8(IPPROTO_TCP) .. + bu8((#ip6.exthdr[1].data+2)/8 - 1) .. + ip6.exthdr[1].data + print( raw==ip6b and "IP6 RECONSTRUCT OK" or "IP6 RECONSTRUCT FAILED" ) + test_assert(raw==ip6b) + + raw = reconstruct_dissect({ip6=ip6, tcp=tcp, payload=payload}) + dis1 = dissect(raw) + tcpb = csum_tcp_fix(ip6b,tcpb,payload) + dis2 = dissect(ip6b..tcpb..payload) + print( dis1.tcp.th_sum==dis2.tcp.th_sum and "TCP+IP6 CSUM OK" or "TCP+IP6 CSUM FAILED" ) + test_assert(dis1.tcp.th_sum==dis2.tcp.th_sum) + + local udp = { + uh_sport = math.random(0,0xFFFF), + uh_dport = math.random(0,0xFFFF), + uh_ulen = UDP_BASE_LEN + #payload + } + + udpb = reconstruct_udphdr(udp) + raw = bu16(udp.uh_sport) .. + bu16(udp.uh_dport) .. + bu16(udp.uh_ulen) .. + bu16(0) + print( raw==udpb and "UDP RECONSTRUCT OK" or "UDP RECONSTRUCT FAILED" ) + test_assert(raw==udpb) + + ip.ip_p = IPPROTO_UDP + raw = reconstruct_dissect({ip=ip, udp=udp, payload=payload}) + dis1 = dissect(raw) + ip.ip_p = IPPROTO_UDP + ip.ip_len = IP_BASE_LEN + #ip.options + #udpb + #payload + ip4b = reconstruct_iphdr(ip) + udpb = csum_udp_fix(ip4b,udpb,payload) + dis2 = dissect(ip4b..udpb..payload) + print( dis1.udp.uh_sum==dis2.udp.uh_sum and "UDP+IP4 CSUM OK" or "UDP+IP4 CSUM FAILED" ) + test_assert(dis1.udp.uh_sum==dis2.udp.uh_sum) + + ip6.ip6_plen = packet_len({ip6=ip6,udp=udp,payload=payload}) - IP6_BASE_LEN + ip6b = reconstruct_ip6hdr(ip6, {ip6_last_proto=IPPROTO_UDP}) + raw = reconstruct_dissect({ip6=ip6, udp=udp, payload=payload}) + dis1 = dissect(raw) + udpb = csum_udp_fix(ip6b,udpb,payload) + dis2 = dissect(ip6b..udpb..payload) + print( dis1.udp.uh_sum==dis2.udp.uh_sum and "UDP+IP6 CSUM OK" or "UDP+IP6 CSUM FAILED" ) + test_assert(dis1.udp.uh_sum==dis2.udp.uh_sum) + + local icmp = { + icmp_type = math.random(0,0xFF), icmp_code=math.random(0,0xFF), + icmp_data = math.random(0,0xFFFFFFFF) + } + ip.ip_p = IPPROTO_ICMP + ip4b = reconstruct_iphdr(ip) + ip6.ip6_plen = packet_len({ip6=ip6,icmp=icmp,payload=payload}) - IP6_BASE_LEN + ip6b = reconstruct_ip6hdr(ip6, {ip6_last_proto=IPPROTO_ICMPV6}) + + icmpb = reconstruct_icmphdr(icmp) + raw = bu8(icmp.icmp_type) .. + bu8(icmp.icmp_code) .. + bu16(0) .. + bu32(icmp.icmp_data) + print( raw==icmpb and "ICMP RECONSTRUCT OK" or "ICMP RECONSTRUCT FAILED" ) + test_assert(raw==icmpb) + + raw = reconstruct_dissect({ip=ip, icmp=icmp, payload=payload}) + dis1 = dissect(raw) + icmpb = csum_icmp_fix(ip4b,icmpb,payload) + dis2 = dissect(ip4b..icmpb..payload) + print( dis1.icmp.icmp_cksum==dis2.icmp.icmp_cksum and "ICMP+IP4 CSUM OK" or "ICMP+IP4 CSUM FAILED" ) + test_assert(dis1.icmp.icmp_cksum==dis2.icmp.icmp_cksum) + + raw = reconstruct_dissect({ip6=ip6, icmp=icmp, payload=payload}) + dis1 = dissect(raw) + icmpb = csum_icmp_fix(ip6b,icmpb,payload) + dis2 = dissect(ip6b..icmpb..payload) + print( dis1.icmp.icmp_cksum==dis2.icmp.icmp_cksum and "ICMP+IP6 CSUM OK" or "ICMP+IP6 CSUM FAILED" ) + test_assert(dis1.icmp.icmp_cksum==dis2.icmp.icmp_cksum) +end + +function test_resolve() + print("* resolve") + + local pos + + local tdis = tls_dissect(fake_default_tls) + local extlen_pos = 5 + 6 + 32 + 1 + 2 + 1 + #tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.session_id + #tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.cipher_suites*2 + #tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.compression_methods + print("fake_default_tls size "..#fake_default_tls.." extlen="..extlen_pos) + local m="1,extlen,sniext,host,sld,midsld,endsld,endhost,-5" + pos = resolve_multi_pos(fake_default_tls,"tls_client_hello",m,true) + test_assert(pos) + print("resolve_multi_pos tls : "..m.." : "..table.concat(pos," ")) + m = "host,endhost" + pos = resolve_range(fake_default_tls,"tls_client_hello",m,false,true) + test_assert(pos) + print("resolve_range tls : "..m.." : "..table.concat(pos," ")) + m = "1" + pos = resolve_pos(fake_default_tls,"tls_client_hello",m,true) + test_assert(pos==1) + print("resolve_pos tls : "..m.." : "..pos) + m = "-1" + pos = resolve_pos(fake_default_tls,"tls_client_hello",m,true) + test_assert(pos==(#fake_default_tls-1)) + print("resolve_pos tls : "..m.." : "..pos) + m = "extlen" + pos = resolve_pos(fake_default_tls,"tls_client_hello",m,true) + test_assert(pos==extlen_pos) + print("resolve_pos tls : "..m.." : "..pos) + m = "midsld" + pos = resolve_pos(fake_default_tls,"tls_client_hello",m,true) + test_assert(pos) + print("resolve_pos tls : "..m.." : "..pos) + m = "method" + pos = resolve_pos(fake_default_tls,"tls_client_hello",m,true) + test_assert(not pos) + print("resolve_pos tls non-existent : "..m.." : "..tostring(pos)) + + local host_pos = string.find(fake_default_http,"Host: ")+6-1 + print("fake_default_http size "..#fake_default_http.." host="..host_pos) + m = "method,host,sld,midsld,endsld,endhost,-5" + pos = resolve_multi_pos(fake_default_http,"http_req",m,true) + test_assert(pos) + test_assert(pos[1]==0) + test_assert(pos[2]==host_pos) + print("resolve_multi_pos http : "..m.." : "..table.concat(pos," ")) + m = "sniext" + pos = resolve_pos(fake_default_http,"http_req",m,true) + test_assert(not pos) + print("resolve_pos http non-existent : "..m.." : "..tostring(pos)) +end + +function test_get_source_ip(opts) + print("* get_source_ip") + + for k,d in ipairs({ + '127.0.0.1','192.168.1.1','10.1.1.1','1.1.1.1','255.255.255.255', + '::1','fc81::4','2a06::1','2001:470::1','2002:0101:0101::1','::1.1.1.1'}) + do + local src = get_source_ip(pton(d)) + print((src and ntop(src) or "?").." => "..d) + end +end +function test_ifaddrs(opts) + print("* ifaddrs") + + local ifa = get_ifaddrs() + test_assert(ifa) + for ifname,ifinfo in pairs(ifa) do + print(ifname.." index="..tostring(ifinfo.index).." mtu="..tostring(ifinfo.mtu)) + for i,addr in ipairs(ifinfo.addr) do + print(" "..ntop(addr.addr)..(addr.netmask and " mask "..tostring(ntop(addr.netmask)) or "")) + end + end +end + +function print_current_time() + local sec,nsec = clock_gettime() + local t = sec + nsec/1000000000; + print("time: "..t) +end +function timer_info_print(tinfo) + print(" timer_info.name="..tinfo.name) + print(" timer_info.period="..tinfo.period) + print(" timer_info.oneshot="..tostring(tinfo.oneshot)) + print(" timer_info.fires="..tinfo.fires) +end +function timer_info_print_by_name(name) + local tinfo = timer_info(name) + timer_info_print(tinfo) +end + +function timer1(name, data) + print("timer "..name.." fired. data="..tostring(data)) + print_current_time() + timer_info_print_by_name(name) +end +function timer2(name, data) + data.n = data.n+1 + print("timer "..name.." fired. data.n="..tostring(data.n)) + print_current_time() + timer_info_print_by_name(name) + if data.n>=4 then + timer_del(name) + end +end +function test_timer(opts) + -- anonymous function + timer_set("t0",function(name,data) + print("timer "..name.." fired. anonymous timer function") + print_current_time() + end, + 100,true) + + -- pass function as function + timer_set("t1",timer1,500,true,"sample_data"); + local tbl = {n=0} + -- pass function through string name + timer_set("t2","timer2",700,false,tbl); + + print("* timers\n") + local timers=timer_enum() + for i,name in ipairs(timers) do + print("TIMER "..i.." :") + timer_info_print_by_name(name) + end + print_current_time() + print() +end + + +function test_rawsend(opts) + print("* rawsend") + + local ifout = (opts and opts.ifout) and opts.ifout + local function rawsend_fail_warning() + if not opts or not opts.ifout or #opts.ifout==0 then + local un = uname() + if string.sub(un.sysname,1,6)=="CYGWIN" then + print("windivert requires interface name in the form '.'. take it from winws2 output with '--debug' option and call test_rawsend({ifout=interface_name})") + end + end + end + local function rawsend_dissect_print(dis, options, reconstruct) + if options then + options.ifout = ifout + else + options = { ifout = ifout } + end + local b = rawsend_dissect(dis, options, reconstruct) + if not b then + print("rawsend_dissect failed") + rawsend_fail_warning() + end + return b + end + local function rawsend_print(raw, options) + if options then + options.ifout = ifout + else + options = { ifout = ifout } + end + print("rawsend: "..string2hex(raw)) + local b = rawsend(raw, options) + if not b then + print("rawsend failed") + rawsend_fail_warning() + end + return b + end + local ip, ip6, udp, dis, ddis, raw_ip, raw_udp, raw + local payload = brandom(math.random(100,1200)) + + local target + for ifname,ifinfo in pairs(get_ifaddrs()) do + for k,v in pairs(ifinfo.addr) do + if #v.addr==4 and string.sub(v.addr,1,2)=="\xC0\xA8" then + target = string.sub(v.addr,1,3)..bu8(u8add(u8(v.addr,4),1)) + break + end + end + end + target = target or pton("192.168.254.32") + print("ipv4 target is "..ntop(target)) + ip = { + ip_tos = 0, + ip_id = math.random(0,0xFFFF), + ip_off = 0, + ip_ttl = 1, + ip_p = IPPROTO_UDP, + ip_src = get_source_ip(target), + ip_dst = target + } + if not ip.ip_src then + print("dest "..ntop(target).." unreachable") + test_assert(false) + end + udp = { + uh_sport = math.random(0,0xFFFF), + uh_dport = math.random(0,0xFFFF) + } + dis = {ip = ip, udp = udp, payload = payload} + print("send ipv4 udp") + test_assert(rawsend_dissect_print(dis, {repeats=3})) + ddis = ipfrag2(dis, {ipfrag_pos_udp = 80}) + for k,d in pairs(ddis) do + print("send ipv4 udp frag "..k) + test_assert(rawsend_dissect_print(d)) + end + + local ip2=ip + ip2.ip_len = IP_BASE_LEN + UDP_BASE_LEN + #payload + raw_ip = reconstruct_iphdr(ip2) + raw_udp = reconstruct_udphdr({uh_sport = udp.uh_sport, uh_dport = udp.uh_dport, uh_ulen = UDP_BASE_LEN + #payload}) + raw_udp = csum_udp_fix(raw_ip,raw_udp,payload) + raw = raw_ip .. raw_udp .. payload + print("send ipv4 udp using pure rawsend without dissect") + test_assert(rawsend_print(raw, {repeats=5})) + + for ifname,ifinfo in pairs(get_ifaddrs()) do + for k,v in pairs(ifinfo.addr) do + if #v.addr==16 and (string.sub(v.addr,1,1)=="\xFC" or string.sub(v.addr,1,1)=="\xFD") then + target = string.sub(v.addr,1,1)..bu8(u8add(u8(v.addr,2),1))..string.sub(v.addr,3) + break + end + end + end + target = target or pton("fdce:3124:164a:5318::2") + print("ipv6 target is "..ntop(target)) + ip6 = { + ip6_flow = 0x60000000, + ip6_hlim = 1, + ip6_src = get_source_ip(target), + ip6_dst = target + } + if not ip6.ip6_src then + print("dest "..ntop(target).." unreachable") + test_assert(false) + end + dis = {ip6 = ip6, udp = udp, payload = payload} + print("send ipv6 udp") + test_assert(rawsend_dissect_print(dis, {repeats=3})) + + ip2 = deepcopy(ip6) + ip2.ip6_plen = UDP_BASE_LEN + #payload + raw_ip = reconstruct_ip6hdr(ip2, {ip6_last_proto = IPPROTO_UDP}) + raw_udp = reconstruct_udphdr({uh_sport = udp.uh_sport, uh_dport = udp.uh_dport, uh_ulen = UDP_BASE_LEN + #payload}) + raw_udp = csum_udp_fix(raw_ip,raw_udp,payload) + raw = raw_ip .. raw_udp .. payload + print("send ipv6 udp using pure rawsend without dissect") + test_assert(rawsend_print(raw, {repeats=7})) + + ddis = ipfrag2(dis, {ipfrag_pos_udp = 80}) + for k,d in ipairs(ddis) do + print("send ipv6 udp frag "..k) + test_assert(rawsend_dissect_print(d)) + end + + ip6.exthdr={{ type = IPPROTO_HOPOPTS, data = "\x00\x00\x00\x00\x00\x00" }} + print("send ipv6 udp with hopbyhop ext header") + test_assert(rawsend_dissect_print(dis, {repeats=3})) + + ddis = ipfrag2(dis, {ipfrag_pos_udp = 80}) + for k,d in ipairs(ddis) do + print("send ipv6 udp frag "..k.." with hopbyhop ext header") + test_assert(rawsend_dissect_print(d)) + end + + insert_ip6_exthdr(ip6, nil, IPPROTO_DSTOPTS, "\x00\x00\x00\x00\x00\x00") + insert_ip6_exthdr(ip6, nil, IPPROTO_DSTOPTS, "\x00\x00\x00\x00\x00\x00") + ip6.ip6_flow = 0x60001234 + ddis = ipfrag2(dis, {ipfrag_pos_udp = 80}) + for k,d in ipairs(ddis) do + print("send ipv6 udp frag "..k.." with hopbyhop, destopt ext headers in unfragmentable part and another destopt ext header in fragmentable part") + test_assert(rawsend_dissect_print(d, {fwmark = 0x50EA})) + end + + fix_ip_proto(dis) -- ip6_preserve_next requires next fields in ip6.exthdr + ip6.ip6_flow = 0x6000AE38 + ddis = ipfrag2(dis, {ipfrag_pos_udp = 72, ipfrag_next = IPPROTO_TCP}) + for k,d in ipairs(ddis) do + print("send ipv6 udp frag "..k.." with hopbyhop, destopt ext headers in unfragmentable part and another destopt ext header in fragmentable part. forge next proto in fragment header of the second fragment to TCP") + -- reconstruct dissect using next proto fields in the dissect. do not auto fix next proto chain. + -- by default reconstruct fixes next proto chain + test_assert(rawsend_dissect_print(d, {fwmark = 0x409A, repeats=2}, {ip6_preserve_next = true})) + end + + local icmp = { + icmp_type = ICMP_ECHO, icmp_code=0, + icmp_data = u32(bu16(math.random(1,0xFFFF))..bu16(1)) + } + ip.ip_p = IPPROTO_ICMP + payload=brandom_az09(math.random(10,1100)) + dis = {ip = ip, icmp = icmp, payload = payload} + print("send ipv4 icmp") + test_assert(rawsend_dissect_print(dis, {fwmark = 0xD133, repeats=3})) + + ip6.exthdr={{ type = IPPROTO_HOPOPTS, data = "\x00\x00\x00\x00\x00\x00" }} + ip6.ip6_flow=0x60009E3B + icmp.icmp_type = ICMP6_ECHO_REQUEST + dis = {ip6 = ip6, icmp = icmp, payload = payload} + print("send ipv6 icmp") + test_assert(rawsend_dissect_print(dis, {fwmark = 0x8E10, repeats=3})) + + ip2 = { + ip_tos = 0, + ip_id = math.random(0,0xFFFF), + ip_off = 0, + ip_ttl = 64, + ip_p = IPPROTO_UDP, + ip_src = pton("10.1.1.1"), + ip_dst = pton("10.1.1.2"), + } + + dis = {ip = ip2, udp = udp, payload = payload} + raw_udp = reconstruct_dissect(dis) + + ip6.ip6_flow=0x6000583F + dis = {ip6 = ip6, payload = raw_udp} + print("send ipv6 ipip") + test_assert(rawsend_dissect_print(dis, {fwmark = 0x8E10, repeats=3}, {ip6_last_proto=IPPROTO_IPIP})) + + dis = {ip = ip, payload = raw_udp} + dis.ip.ip_p = IPPROTO_IPIP + print("send ipv4 ipip") + test_assert(rawsend_dissect_print(dis, {fwmark = 0x8E10, repeats=3}, {ip6_last_proto=IPPROTO_IPIP})) +end diff --git a/blockcheck/zapret2/mdig/mdig.exe b/blockcheck/zapret2/mdig/mdig.exe new file mode 100644 index 0000000000000000000000000000000000000000..56a4fb097f7e5298013952a9230280c37dc6e98a GIT binary patch literal 130560 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 literal 0 HcmV?d00001 diff --git a/blockcheck/zapret2/nfq2/WinDivert.dll b/blockcheck/zapret2/nfq2/WinDivert.dll new file mode 100644 index 0000000000000000000000000000000000000000..2c55eeb6921351a6cad292a900f4b8d7d41c4bcc GIT binary patch literal 47616 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 za=me

2cZ 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 Mok_m={2+h)7u^}>0RR91 literal 0 HcmV?d00001 diff --git a/blockcheck/zapret2/nfq2/winws2.exe b/blockcheck/zapret2/nfq2/winws2.exe new file mode 100644 index 0000000000000000000000000000000000000000..8ffd2def2df7dc3e8b1623fdb9a67a94e916fa21 GIT binary patch literal 656384 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