50 Commits
v64 ... v65

Author SHA1 Message Date
bol-van
7e4d084c41 winws: fix non-working HUP reload 2024-10-28 09:32:35 +03:00
bol-van
7190b00849 remove bad file 2024-10-28 09:32:34 +03:00
bol-van
ea1545b45c recompile killall to remove huge dll depends 2024-10-28 09:32:34 +03:00
bol-van
076397eb99 nfqws: memleak fix 2024-10-28 09:32:34 +03:00
bol-van
2cbb497cb7 windivert libs reorganize 2024-10-28 09:32:34 +03:00
bol-van
2286996223 nfqws: remove tcp word from retrans threshold reached 2024-10-28 09:32:34 +03:00
bol-van
d5516dac8a nfqws: remove tcp word from retrans threshold reached 2024-10-28 09:32:34 +03:00
bol-van
7b07074ad7 readme: win32 info 2024-10-28 09:32:34 +03:00
bol-van
a5b68959f3 readme: win32 info 2024-10-28 09:32:34 +03:00
bol-van
8e336b746c winws: win32 build 2024-10-28 09:32:34 +03:00
bol-van
47578bf891 zapret-winws: add missing cygwin libs for killall 2024-10-28 09:32:34 +03:00
bol-van
d596d311e9 win64: remove --debug from presets. add killall and reload_lists.cmd 2024-10-28 09:32:34 +03:00
bol-van
cc0de2aa8b readme: ipset add ipv4/6 info 2024-10-28 09:32:34 +03:00
bol-van
852b7bb717 update bins 2024-10-28 09:32:34 +03:00
bol-van
5aa90185b4 docs: typo 2024-10-28 09:32:34 +03:00
bol-van
438e8a98b3 docs: v65 2024-10-28 09:32:34 +03:00
bol-van
6b2ce5410a nfqws: fix dp_match 2024-10-28 09:32:34 +03:00
bol-van
4a81603d05 winws: move windows specific files to separate folder 2024-10-28 09:32:34 +03:00
bol-van
af6a01f56d nfqws: minor regression 2024-10-28 09:32:34 +03:00
bol-van
a371ca6ea2 nfqws: minor regression 2024-10-28 09:32:33 +03:00
bol-van
83a629b832 nfqws: auto hostlist debug log client and proto info 2024-10-28 09:32:33 +03:00
bol-van
5963ba617a comment typo 2024-10-28 09:32:33 +03:00
bol-van
ebecc423c7 nfqws: user mode ipset support 2024-10-28 09:32:33 +03:00
bol-van
89ccf0bbc0 Revert "ip2net: ip6_and use 64-bit and. 128 can cause alignment segfaults"
This reverts commit 64b2f940a2.
2024-10-28 09:32:33 +03:00
bol-van
1099f248e5 ip2net: ip6_and use 64-bit and. 128 can cause alignment segfaults 2024-10-28 09:32:33 +03:00
bol-van
6be111f7b7 tpws: ip6_and use 64-bit and. 128 can cause alignment segfaults 2024-10-28 09:32:33 +03:00
bol-van
33caf4fd4a readme: add get_refilter*.sh info 2024-10-28 09:32:33 +03:00
bol-van
84fe7817e0 ipset: refilter scripts 2024-10-28 09:32:33 +03:00
bol-van
d80e415c63 tpws: move l7proto defs to one place 2024-10-28 09:32:33 +03:00
bol-van
4d66496cc3 tpws: move l7proto defs to one place 2024-10-28 09:32:33 +03:00
bol-van
6773370a87 tpws: autohostlist debug log write client and proto info 2024-10-28 09:32:33 +03:00
bol-van
47c08d0ab5 tpws: fix MSS apply in transparent mode 2024-10-28 09:32:33 +03:00
bol-van
ea97e9ade2 tpws: save some memory by using sockaddr_in64 2024-10-28 09:32:33 +03:00
bol-van
01b3f4d3cf readme: mark filter is mandatory to avoid deadlocks 2024-10-28 09:32:33 +03:00
bol-van
390c9419e8 list-youtube update 2024-10-28 09:32:33 +03:00
bol-van
94cd2212b8 list-youtube update 2024-10-28 09:32:33 +03:00
bol-van
5d4c81d3a5 tpws: fix regression 2024-10-28 09:32:33 +03:00
bol-van
05978d9b35 tpws: ipset support 2024-10-28 09:32:33 +03:00
bol-van
e23f61ed7d winws: update ru presets 2024-10-28 09:32:33 +03:00
bol-van
7171c776db init.d: 50-dht4all,50-quic4all fix wrong QNUM var name 2024-10-28 09:32:33 +03:00
bol-van
baca5a184d tpws,nfqws: fix 100% cpu hang on gzipped hostlist with comments 2024-10-28 09:32:33 +03:00
bol-van
f32df7d701 init.d: 50-discord adjust port range to 50000-50019 2024-10-28 09:32:33 +03:00
bol-van
2fa48f48ea init.d: 50-discord zapret_custom_firewall_nft_flush, ports 50000-50019 2024-10-28 09:32:33 +03:00
bol-van
db14cee73b init.d: zapret_custom_firewall_nft_flush 2024-10-28 09:32:33 +03:00
bol-van
f8ccb564ca ipt.sh : print_opt adding => inserting 2024-10-28 09:32:33 +03:00
bol-van
20e6ba721a init.d: ignore dirs in custom.d 2024-10-28 09:32:33 +03:00
SashaXser
5a5d9f7f31 Fix code scanning alert no. 2: Incorrect return-value check for a 'scanf'-like function
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2024-10-28 09:32:33 +03:00
SashaXser
fbc5b8e491 Fix code scanning alert no. 1: Multiplication result converted to larger type
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2024-10-28 09:32:33 +03:00
bol-van
f1392a3cf1 docs/nftables.txt : add mark filter 2024-10-28 09:32:33 +03:00
bol-van
8ff0b9bab9 init.d: number pools. FW_EXTRA. nft insert. customs reorder 2024-10-28 09:32:33 +03:00
97 changed files with 2968 additions and 641 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,721 @@
5.200.14.249
18.165.140.0/25
23.227.38.74
34.0.48.0/24
34.0.49.64/26
34.0.50.0/25
34.0.51.0/24
34.0.52.0/22
34.0.56.0/23
34.0.59.0/24
34.0.60.0/24
34.0.62.128/25
34.0.63.228
34.0.64.0/23
34.0.66.130
34.0.82.140
34.0.129.128/25
34.0.130.0/24
34.0.131.130
34.0.132.139
34.0.133.75
34.0.134.0/24
34.0.135.251
34.0.136.51
34.0.137.0/24
34.0.139.0/24
34.0.140.0/23
34.0.142.0/25
34.0.144.0/23
34.0.146.0/24
34.0.148.25
34.0.149.101
34.0.151.0/25
34.0.153.0/24
34.0.155.0/24
34.0.156.101
34.0.157.0/25
34.0.158.247
34.0.159.188
34.0.192.0/25
34.0.193.0/24
34.0.194.0/24
34.0.195.172
34.0.196.200/29
34.0.197.81
34.0.198.25
34.0.199.0/24
34.0.200.0/24
34.0.201.81
34.0.202.34
34.0.203.0/24
34.0.204.0/23
34.0.206.0/25
34.0.207.0/25
34.0.208.195
34.0.209.0/24
34.0.210.20
34.0.211.0/26
34.0.212.0/24
34.0.213.64/26
34.0.215.128/25
34.0.216.238
34.0.217.0/24
34.0.218.83
34.0.220.103
34.0.221.0/24
34.0.222.193
34.0.223.68
34.0.227.0/24
34.0.240.0/21
34.0.248.0/23
34.0.250.0/24
34.0.251.0/25
34.1.216.0/24
34.1.221.166
35.207.64.0/23
35.207.67.116
35.207.71.0/24
35.207.72.32
35.207.73.0/24
35.207.74.0/24
35.207.75.128/25
35.207.76.128/26
35.207.77.0/24
35.207.78.129
35.207.79.0/24
35.207.80.76
35.207.81.248/30
35.207.82.0/23
35.207.84.0/24
35.207.85.160
35.207.86.41
35.207.87.184
35.207.89.188
35.207.91.146
35.207.92.230
35.207.95.0/24
35.207.97.174
35.207.99.134
35.207.100.64/26
35.207.101.130
35.207.103.64/26
35.207.104.0/24
35.207.106.128/26
35.207.107.19
35.207.108.192/27
35.207.109.185
35.207.110.0/24
35.207.111.174
35.207.114.16
35.207.115.163
35.207.116.51
35.207.117.0/24
35.207.121.204
35.207.122.0/25
35.207.124.145
35.207.125.116
35.207.126.30
35.207.129.0/24
35.207.131.128/27
35.207.132.247
35.207.135.147
35.207.136.69
35.207.137.0/24
35.207.139.0/24
35.207.140.241
35.207.141.119
35.207.142.0/24
35.207.143.96/27
35.207.144.0/25
35.207.145.0/24
35.207.146.89
35.207.147.0/24
35.207.149.0/24
35.207.150.0/24
35.207.151.61
35.207.153.117
35.207.154.0/24
35.207.155.128/25
35.207.156.254
35.207.157.7
35.207.158.192
35.207.160.160
35.207.162.239
35.207.163.0/24
35.207.164.0/25
35.207.165.147
35.207.166.0/25
35.207.167.0/24
35.207.168.116
35.207.170.0/23
35.207.172.0/24
35.207.174.55
35.207.176.128/25
35.207.178.0/24
35.207.180.152
35.207.181.76
35.207.182.125
35.207.184.101
35.207.185.192
35.207.186.128/25
35.207.187.228
35.207.188.0/24
35.207.189.0/25
35.207.190.194
35.207.191.64/26
35.207.193.165
35.207.195.75
35.207.196.0/24
35.207.198.0/23
35.207.201.186
35.207.202.169
35.207.205.211
35.207.207.4
35.207.209.0/25
35.207.210.191
35.207.211.253
35.207.213.97
35.207.214.0/24
35.207.220.147
35.207.221.58
35.207.222.105
35.207.224.151
35.207.225.210
35.207.227.0/24
35.207.229.212
35.207.232.26
35.207.234.182
35.207.238.0/24
35.207.240.0/24
35.207.245.0/24
35.207.249.0/24
35.207.250.212
35.207.251.0/27
35.212.4.134
35.212.12.148
35.212.88.11
35.212.102.50
35.212.111.0/26
35.212.117.247
35.212.120.122
35.213.0.0/24
35.213.2.8
35.213.4.185
35.213.6.118
35.213.7.128/25
35.213.8.168
35.213.10.0/24
35.213.11.21
35.213.12.224/27
35.213.13.19
35.213.14.217
35.213.16.67
35.213.17.235
35.213.23.166
35.213.25.164
35.213.26.62
35.213.27.252
35.213.32.0/24
35.213.33.74
35.213.34.204
35.213.37.81
35.213.38.186
35.213.39.253
35.213.42.0/24
35.213.43.79
35.213.45.0/24
35.213.46.136
35.213.49.17
35.213.50.0/24
35.213.51.213
35.213.52.0/25
35.213.53.0/24
35.213.54.0/24
35.213.56.0/25
35.213.59.0/24
35.213.61.58
35.213.65.0/24
35.213.67.0/24
35.213.68.192/26
35.213.70.151
35.213.72.128/25
35.213.73.245
35.213.74.131
35.213.78.0/24
35.213.79.137
35.213.80.0/25
35.213.83.128/25
35.213.84.245
35.213.85.0/24
35.213.88.145
35.213.89.80/28
35.213.90.0/24
35.213.91.195
35.213.92.0/24
35.213.93.254
35.213.94.78
35.213.95.145
35.213.96.87
35.213.98.0/24
35.213.99.126
35.213.101.214
35.213.102.0/24
35.213.105.0/24
35.213.106.128/25
35.213.107.158
35.213.109.0/24
35.213.110.40
35.213.111.0/25
35.213.115.0/25
35.213.120.0/24
35.213.122.0/24
35.213.124.89
35.213.125.40
35.213.126.185
35.213.127.0/24
35.213.128.0/22
35.213.132.0/23
35.213.134.140
35.213.135.0/24
35.213.136.0/23
35.213.138.128/25
35.213.139.0/24
35.213.140.0/25
35.213.141.164
35.213.142.128/25
35.213.143.0/24
35.213.144.0/22
35.213.148.0/23
35.213.150.0/24
35.213.152.0/23
35.213.154.137
35.213.155.134
35.213.156.144
35.213.157.0/24
35.213.158.64/26
35.213.160.90
35.213.161.253
35.213.162.0/25
35.213.163.0/24
35.213.164.0/23
35.213.166.106
35.213.167.160/27
35.213.168.0/24
35.213.169.179
35.213.170.0/24
35.213.171.201
35.213.172.159
35.213.173.0/24
35.213.174.128/25
35.213.175.128/26
35.213.176.0/24
35.213.177.0/25
35.213.179.139
35.213.180.0/24
35.213.181.0/25
35.213.182.0/23
35.213.184.0/23
35.213.186.70
35.213.187.0/24
35.213.188.128/25
35.213.190.158
35.213.191.0/24
35.213.192.240/31
35.213.193.74
35.213.194.0/25
35.213.195.178
35.213.196.38
35.213.197.68
35.213.198.0/23
35.213.200.0/23
35.213.202.0/25
35.213.203.195
35.213.204.32/27
35.213.205.170
35.213.207.128/25
35.213.208.85
35.213.210.0/24
35.213.211.176/29
35.213.212.0/24
35.213.213.225
35.213.214.0/25
35.213.215.255
35.213.217.0/24
35.213.218.248
35.213.219.0/25
35.213.220.211
35.213.221.0/24
35.213.222.215
35.213.223.0/24
35.213.225.0/24
35.213.227.227
35.213.229.17
35.213.230.89
35.213.231.0/24
35.213.233.0/24
35.213.234.134
35.213.236.0/24
35.213.237.212
35.213.238.0/24
35.213.240.212
35.213.241.0/24
35.213.242.10
35.213.243.219
35.213.244.146
35.213.245.119
35.213.246.0/23
35.213.249.79
35.213.250.0/24
35.213.251.74
35.213.252.0/24
35.213.253.155
35.213.254.89
35.214.128.248
35.214.129.220
35.214.130.217
35.214.131.144
35.214.132.189
35.214.133.0/24
35.214.134.163
35.214.137.0/24
35.214.138.0/25
35.214.140.0/24
35.214.142.0/24
35.214.143.41
35.214.144.26
35.214.145.200
35.214.146.9
35.214.147.135
35.214.148.89
35.214.149.110
35.214.151.128/25
35.214.152.0/24
35.214.156.115
35.214.158.181
35.214.159.128/25
35.214.160.128/25
35.214.161.217
35.214.162.0/24
35.214.163.28
35.214.165.102
35.214.167.77
35.214.169.0/24
35.214.170.2
35.214.171.0/25
35.214.172.128/25
35.214.173.0/24
35.214.175.0/24
35.214.177.183
35.214.179.46
35.214.180.0/23
35.214.184.179
35.214.185.28
35.214.186.3
35.214.187.0/24
35.214.191.0/24
35.214.192.128/25
35.214.193.0/24
35.214.194.128/25
35.214.195.0/25
35.214.196.64/26
35.214.197.0/24
35.214.198.7
35.214.199.224
35.214.201.0/25
35.214.203.155
35.214.204.0/23
35.214.207.0/24
35.214.208.128/25
35.214.209.64
35.214.210.0/24
35.214.211.3
35.214.212.64/26
35.214.213.0/25
35.214.214.0/24
35.214.215.64/26
35.214.216.0/23
35.214.218.140
35.214.219.0/24
35.214.220.149
35.214.221.0/24
35.214.222.149
35.214.223.0/24
35.214.224.71
35.214.225.0/24
35.214.226.0/23
35.214.228.0/23
35.214.231.187
35.214.233.8
35.214.235.38
35.214.237.0/24
35.214.238.0/25
35.214.239.0/24
35.214.240.87
35.214.241.0/24
35.214.243.21
35.214.244.0/24
35.214.245.16/28
35.214.246.106
35.214.248.119
35.214.249.154
35.214.250.0/24
35.214.251.128/25
35.214.252.187
35.214.253.0/24
35.214.255.154
35.215.72.85
35.215.73.65
35.215.83.0
35.215.108.111
35.215.115.120
35.215.126.35
35.215.127.34
35.215.128.0/21
35.215.136.0/26
35.215.137.0/24
35.215.138.0/23
35.215.140.0/24
35.215.141.64/27
35.215.142.0/24
35.215.143.83
35.215.144.128/25
35.215.145.0/24
35.215.146.0/24
35.215.147.86
35.215.148.0/23
35.215.150.0/26
35.215.151.0/24
35.215.152.0/24
35.215.153.128/25
35.215.154.240/28
35.215.155.20
35.215.156.0/24
35.215.158.0/23
35.215.160.192/26
35.215.161.0/24
35.215.163.0/24
35.215.164.0/24
35.215.165.236
35.215.166.128/25
35.215.167.128/25
35.215.168.0/24
35.215.169.12
35.215.170.0/23
35.215.172.0/22
35.215.176.0/24
35.215.177.72
35.215.178.0/24
35.215.179.161
35.215.180.0/22
35.215.184.253
35.215.185.64/26
35.215.186.0/25
35.215.187.0/24
35.215.188.0/23
35.215.190.0/24
35.215.191.61
35.215.192.0/23
35.215.194.192/28
35.215.195.0/24
35.215.196.0/25
35.215.197.0/25
35.215.198.230
35.215.199.204
35.215.200.0/23
35.215.202.0/24
35.215.203.0/25
35.215.204.128/25
35.215.205.0/25
35.215.206.0/23
35.215.208.0/24
35.215.209.0/25
35.215.210.0/23
35.215.212.0/22
35.215.216.0/22
35.215.221.0/24
35.215.222.128/25
35.215.223.126
35.215.224.0/23
35.215.226.0/24
35.215.227.0/25
35.215.228.0/24
35.215.229.64
35.215.230.89
35.215.231.0/24
35.215.232.0/24
35.215.233.0/25
35.215.234.37
35.215.235.0/24
35.215.238.0/25
35.215.239.119
35.215.240.0/24
35.215.241.128/25
35.215.242.0/25
35.215.243.0/24
35.215.244.0/23
35.215.246.222
35.215.247.0/24
35.215.248.0/22
35.215.252.0/24
35.215.253.118
35.215.254.0/23
35.217.0.0/24
35.217.1.64/26
35.217.2.5
35.217.3.0/24
35.217.4.72
35.217.5.0/25
35.217.6.0/24
35.217.8.0/25
35.217.9.0/24
35.217.11.186
35.217.12.0/24
35.217.14.192/26
35.217.15.65
35.217.16.75
35.217.17.128/25
35.217.18.0/24
35.217.19.183
35.217.20.0/24
35.217.21.128/25
35.217.22.128/25
35.217.23.128/25
35.217.24.0/24
35.217.25.81
35.217.26.0/24
35.217.27.128/25
35.217.28.128/25
35.217.29.0/24
35.217.30.0/25
35.217.31.0/25
35.217.32.128/25
35.217.33.0/24
35.217.35.128/25
35.217.36.0/23
35.217.38.179
35.217.39.186
35.217.40.176
35.217.41.204
35.217.43.0/24
35.217.45.248
35.217.46.0/24
35.217.47.128/25
35.217.48.195
35.217.49.160/27
35.217.50.0/25
35.217.51.0/24
35.217.52.117
35.217.53.128/25
35.217.54.0/25
35.217.55.96/27
35.217.56.6
35.217.57.184
35.217.58.0/24
35.217.59.64/26
35.217.60.0/24
35.217.61.128/25
35.217.62.0/24
35.217.63.128/25
35.219.225.149
35.219.226.57
35.219.227.0/24
35.219.228.37
35.219.229.128/25
35.219.230.0/23
35.219.235.0/24
35.219.236.198
35.219.238.115
35.219.239.0/24
35.219.241.0/24
35.219.242.221
35.219.243.191
35.219.244.1
35.219.245.0/24
35.219.246.159
35.219.247.0/26
35.219.248.0/24
35.219.249.126
35.219.251.186
35.219.252.0/23
35.219.254.0/24
64.233.161.207
64.233.162.207
64.233.163.207
64.233.164.207
64.233.165.207
66.22.196.0/26
66.22.197.0/24
66.22.198.0/26
66.22.199.0/24
66.22.200.0/26
66.22.202.0/26
66.22.204.0/24
66.22.206.0/24
66.22.208.0/25
66.22.210.0/26
66.22.212.0/24
66.22.214.0/24
66.22.216.0/23
66.22.220.0/25
66.22.221.0/24
66.22.222.0/23
66.22.224.0/25
66.22.225.0/26
66.22.226.0/25
66.22.227.0/25
66.22.228.0/22
66.22.233.0/24
66.22.234.0/24
66.22.236.0/23
66.22.238.0/24
66.22.240.0/22
66.22.244.0/23
66.22.248.0/24
74.125.131.207
74.125.205.207
104.17.51.93
104.17.117.93
104.18.4.161
104.18.5.161
104.18.8.105
104.18.9.105
104.18.30.128
104.18.31.128
104.21.2.204
104.21.25.51
104.21.40.151
104.21.59.128
104.21.72.221
104.21.82.160
108.177.14.207
138.128.140.240/28
142.250.150.207
142.251.1.207
162.159.128.232/30
162.159.129.232/30
162.159.130.232/30
162.159.133.232/30
162.159.134.232/30
162.159.135.232/30
162.159.136.232/30
162.159.137.232/30
162.159.138.232/30
172.65.202.19
172.66.41.34
172.66.42.222
172.67.152.224/28
172.67.155.163
172.67.159.89
172.67.177.131
172.67.222.182
173.194.73.207
173.194.220.207
173.194.221.207
173.194.222.207
188.114.96.2
188.114.97.2
188.114.98.224
188.114.99.224
204.11.56.48
209.85.233.207

Binary file not shown.

View File

@@ -1,3 +1,13 @@
googlevideo.com
youtubei.googleapis.com
i.ytimg.com
ytimg.com
yt3.ggpht.com
yt4.ggpht.com
youtube.com
youtubeembeddedplayer.googleapis.com
ytimg.l.google.com
jnn-pa.googleapis.com
youtube-nocookie.com
youtube-ui.l.google.com
yt-video-upload.l.google.com
wide-youtube.l.google.com

View File

@@ -1,7 +1,9 @@
start "zapret: http,https,quic" /min "%~dp0winws.exe" ^
--wf-tcp=80,443 --wf-udp=443 ^
--wf-tcp=80,443 --wf-udp=443,50000-50099 ^
--filter-udp=50000-50099 --ipset="%~dp0ipset-discord.txt" --dpi-desync=fake --dpi-desync-repeats=6 --dpi-desync-any-protocol --dpi-desync-cutoff=n2 --new ^
--filter-udp=50000-50099 --new ^
--filter-udp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake --dpi-desync-repeats=11 --dpi-desync-fake-quic="%~dp0quic_initial_www_google_com.bin" --new ^
--filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=11 --new ^
--filter-tcp=80 --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --new ^
--filter-tcp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --dpi-desync-fake-tls="%~dp0tls_clienthello_www_google_com.bin" --new ^
--filter-tcp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake,split2 --dpi-desync-repeats=11 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --dpi-desync-fake-tls="%~dp0tls_clienthello_www_google_com.bin" --new ^
--dpi-desync=fake,disorder2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig

View File

@@ -1,7 +1,9 @@
start "zapret: http,https,quic" /min "%~dp0winws.exe" ^
--wf-tcp=80,443 --wf-udp=443 ^
--wf-tcp=80,443 --wf-udp=443,50000-50099 ^
--filter-udp=50000-50099 --ipset="%~dp0ipset-discord.txt" --dpi-desync=fake --dpi-desync-repeats=6 --dpi-desync-any-protocol --dpi-desync-cutoff=n2 --new ^
--filter-udp=50000-50099 --new ^
--filter-udp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake --dpi-desync-repeats=11 --dpi-desync-fake-quic="%~dp0quic_initial_www_google_com.bin" --new ^
--filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=11 --new ^
--filter-tcp=80 --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --hostlist-auto="%~dp0autohostlist.txt" --new ^
--filter-tcp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --dpi-desync-fake-tls="%~dp0tls_clienthello_www_google_com.bin" --new ^
--filter-tcp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake,split2 --dpi-desync-repeats=11 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --dpi-desync-fake-tls="%~dp0tls_clienthello_www_google_com.bin" --new ^
--dpi-desync=fake,disorder2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --hostlist-auto="%~dp0autohostlist.txt"

View File

@@ -0,0 +1 @@
%~dp0killall -HUP winws

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -329,6 +329,25 @@ 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()
{
HTTP_PORTS=${HTTP_PORTS:-80}

View File

@@ -16,6 +16,7 @@ custom_runner()
n=$(ls "$CUSTOM_DIR/custom.d" | wc -c | xargs)
[ "$n" = 0 ] || {
for script in "$CUSTOM_DIR/custom.d/"*; do
[ -f "$script" ] || continue
unset -f $FUNC
. "$script"
existf $FUNC && $FUNC "$@"
@@ -23,3 +24,20 @@ custom_runner()
}
}
}
alloc_tpws_port()
{
# $1 - target var name
alloc_num NUMPOOL_TPWS_PORT $1 910 979
}
alloc_qnum()
{
# $1 - target var name
alloc_num NUMPOOL_QNUM $1 65400 65499
}
alloc_dnum()
{
# alloc daemon number
# $1 - target var name
alloc_num NUMPOOL_DNUM $1 1000 1999
}

View File

@@ -3,15 +3,15 @@ readonly ipt_connbytes="-m connbytes --connbytes-dir=original --connbytes-mode=p
ipt()
{
iptables -C "$@" >/dev/null 2>/dev/null || iptables -I "$@"
iptables $FW_EXTRA_PRE -C "$@" $FW_EXTRA_POST >/dev/null 2>/dev/null || iptables $FW_EXTRA_PRE -I "$@" $FW_EXTRA_POST
}
ipta()
{
iptables -C "$@" >/dev/null 2>/dev/null || iptables -A "$@"
iptables $FW_EXTRA_PRE -C "$@" $FW_EXTRA_POST >/dev/null 2>/dev/null || iptables $FW_EXTRA_PRE -A "$@" $FW_EXTRA_POST
}
ipt_del()
{
iptables -C "$@" >/dev/null 2>/dev/null && iptables -D "$@"
iptables $FW_EXTRA_PRE -C "$@" $FW_EXTRA_POST >/dev/null 2>/dev/null && iptables $FW_EXTRA_PRE -D "$@" $FW_EXTRA_POST
}
ipt_add_del()
{
@@ -134,7 +134,7 @@ unprepare_tpws_fw()
ipt_print_op()
{
if [ "$1" = "1" ]; then
echo "Adding ip$4tables rule for $3 : $2"
echo "Inserting ip$4tables rule for $3 : $2"
else
echo "Deleting ip$4tables rule for $3 : $2"
fi

View File

@@ -199,7 +199,15 @@ nft_add_rule()
# $2,$3,... - rule(s)
local chain="$1"
shift
nft add rule inet $ZAPRET_NFT_TABLE $chain "$@"
nft add rule inet $ZAPRET_NFT_TABLE $chain $FW_EXTRA_PRE "$@"
}
nft_insert_rule()
{
# $1 - chain
# $2,$3,... - rule(s)
local chain="$1"
shift
nft insert rule inet $ZAPRET_NFT_TABLE $chain $FW_EXTRA_PRE "$@"
}
nft_add_set_element()
{
@@ -227,6 +235,7 @@ nft_clean_nfqws_rule()
nft_add_nfqws_flow_exempt_rule()
{
# $1 - rule (must be all filters in one var)
local FW_EXTRA_POST= FW_EXTRA_PRE=
nft_add_rule flow_offload $(nft_clean_nfqws_rule $1) return comment \"direct flow offloading exemption\"
# do not need this because of oifname @wanif/@wanif6 filter in forward chain
#nft_add_rule flow_offload $(nft_reverse_nfqws_rule $1) return comment \"reverse flow offloading exemption\"
@@ -236,6 +245,7 @@ nft_add_flow_offload_exemption()
# "$1" - rule for ipv4
# "$2" - rule for ipv6
# "$3" - comment
local FW_EXTRA_POST= FW_EXTRA_PRE=
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || nft_add_rule flow_offload oifname @wanif $1 ip daddr != @nozapret return comment \"$3\"
[ "$DISABLE_IPV6" = "1" -o -z "$2" ] || nft_add_rule flow_offload oifname @wanif6 $2 ip6 daddr != @nozapret6 return comment \"$3\"
}
@@ -399,7 +409,7 @@ nft_only()
nft_print_op()
{
echo "Adding nftables ipv$3 rule for $2 : $1"
echo "Inserting nftables ipv$3 rule for $2 : $1"
}
_nft_fw_tpws4()
{
@@ -410,8 +420,8 @@ _nft_fw_tpws4()
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || {
local filter="$1" port="$2"
nft_print_op "$filter" "tpws (port $2)" 4
nft_add_rule dnat_output skuid != $WS_USER ${3:+oifname @wanif }$filter ip daddr != @nozapret dnat ip to $TPWS_LOCALHOST4:$port
nft_add_rule dnat_pre iifname @lanif $filter ip daddr != @nozapret dnat ip to $TPWS_LOCALHOST4:$port
nft_insert_rule dnat_output skuid != $WS_USER ${3:+oifname @wanif }$filter ip daddr != @nozapret $FW_EXTRA_POST dnat ip to $TPWS_LOCALHOST4:$port
nft_insert_rule dnat_pre iifname @lanif $filter ip daddr != @nozapret $FW_EXTRA_POST dnat ip to $TPWS_LOCALHOST4:$port
prepare_route_localnet
}
}
@@ -425,9 +435,9 @@ _nft_fw_tpws6()
[ "$DISABLE_IPV6" = "1" -o -z "$1" ] || {
local filter="$1" port="$2" DNAT6 i
nft_print_op "$filter" "tpws (port $port)" 6
nft_add_rule dnat_output skuid != $WS_USER ${4:+oifname @wanif6 }$filter ip6 daddr != @nozapret6 dnat ip6 to [::1]:$port
nft_insert_rule dnat_output skuid != $WS_USER ${4:+oifname @wanif6 }$filter ip6 daddr != @nozapret6 $FW_EXTRA_POST dnat ip6 to [::1]:$port
[ -n "$3" ] && {
nft_add_rule dnat_pre $filter ip6 daddr != @nozapret6 dnat ip6 to iifname map @link_local:$port
nft_insert_rule dnat_pre $filter ip6 daddr != @nozapret6 $FW_EXTRA_POST dnat ip6 to iifname map @link_local:$port
for i in $3; do
_dnat6_target $i DNAT6
# can be multiple tpws processes on different ports
@@ -476,7 +486,7 @@ _nft_fw_nfqws_post4()
nft_print_op "$filter" "nfqws postrouting (qnum $port)" 4
rule="${3:+oifname @wanif }$filter ip daddr != @nozapret"
is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT"
nft_add_rule $chain $rule $setmark queue num $port bypass
nft_insert_rule $chain $rule $setmark $FW_EXTRA_POST queue num $port bypass
nft_add_nfqws_flow_exempt_rule "$rule"
}
}
@@ -491,7 +501,7 @@ _nft_fw_nfqws_post6()
nft_print_op "$filter" "nfqws postrouting (qnum $port)" 6
rule="${3:+oifname @wanif6 }$filter ip6 daddr != @nozapret6"
is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT"
nft_add_rule $chain $rule $setmark queue num $port bypass
nft_insert_rule $chain $rule $setmark $FW_EXTRA_POST queue num $port bypass
nft_add_nfqws_flow_exempt_rule "$rule"
}
}
@@ -515,7 +525,7 @@ _nft_fw_nfqws_pre4()
local filter="$1" port="$2" rule
nft_print_op "$filter" "nfqws prerouting (qnum $port)" 4
rule="${3:+iifname @wanif }$filter ip saddr != @nozapret"
nft_add_rule $(get_prechain) $rule queue num $port bypass
nft_insert_rule $(get_prechain) $rule $FW_EXTRA_POST queue num $port bypass
}
}
_nft_fw_nfqws_pre6()
@@ -528,7 +538,7 @@ _nft_fw_nfqws_pre6()
local filter="$1" port="$2" rule
nft_print_op "$filter" "nfqws prerouting (qnum $port)" 6
rule="${3:+iifname @wanif6 }$filter ip6 saddr != @nozapret6"
nft_add_rule $(get_prechain) $rule queue num $port bypass
nft_insert_rule $(get_prechain) $rule $FW_EXTRA_POST queue num $port bypass
}
}
nft_fw_nfqws_pre()
@@ -734,6 +744,7 @@ zapret_unapply_firewall_nft()
unprepare_route_localnet
nft_del_firewall
[ "$MODE" = custom ] && custom_runner zapret_custom_firewall_nft_flush
return 0
}
zapret_do_firewall_nft()

View File

@@ -108,8 +108,9 @@ pf_anchor_zapret_tables()
}
pf_nat_reorder_rules()
{
# this is dirty hack to move rdr above route-to and remove route-to dups
sort -rfu
# this is dirty hack to move rdr above route-to
# use only first word as a key and preserve order within a single key
sort -srfk 1,1
}
pf_anchor_port_target()
{

View File

@@ -323,3 +323,16 @@ v64:
blockcheck: warn if dpi bypass software is already running
blockcheck: TPWS_EXTRA, NFQWS_EXTRA
init.d: multiple custom scripts
v65:
init.d: dynamic number allocation for dnum,tpws_port,qnum
init.d: FW_EXTRA_PRE, FW_EXTRA_POST
init.d: zapret_custom_firewall_nft_flush
nfqws,tpws: l7proto and client ip:port info in autohostlist debug log
nfqws,tpws: user mode ipset filter support
nfqws,tpws: l7proto filter support
tpws: fixed MSS apply in transparent mode
nfqws: fixed autottl apply if desync profile changed
tpws,nfqws: fixed 100% cpu hang on gzipped list with comments
ipset: get_refilter_ipsum.sh , get_refilter_domain.sh

View File

@@ -19,8 +19,8 @@ For dpi desync attack :
nft delete table inet ztest
nft create table inet ztest
nft add chain inet ztest post "{type filter hook postrouting priority mangle;}"
nft add rule inet ztest post tcp dport "{80,443}" ct original packets 1-12 queue num 200 bypass
nft add rule inet ztest post udp dport 443 ct original packets 1-4 queue num 200 bypass
nft add rule inet ztest post meta mark and 0x40000000 == 0 tcp dport "{80,443}" ct original packets 1-12 queue num 200 bypass
nft add rule inet ztest post meta mark and 0x40000000 == 0 udp dport 443 ct original packets 1-4 queue num 200 bypass
# auto hostlist with avoiding wrong ACK numbers in RST,ACK packets sent by russian DPI
sysctl net.netfilter.nf_conntrack_tcp_be_liberal=1

View File

@@ -97,7 +97,8 @@ Then we can reduce CPU load, refusing to process unnecessary packets.
`iptables -t mangle -I POSTROUTING -o <external_interface> -p tcp --dport 80 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass`
Mark filter does not allow nfqws-generated packets to enter the queue again.
Its necessary to use this filter when also using `connbytes 1:6`. Without it packet ordering can be changed breaking the whole idea.
Its necessary to use this filter when also using `connbytes`. Without it packet ordering can be changed breaking the whole idea.
Also if there's huge packet send from nfqws it may deadlock without mark filter.
Some attacks require redirection of incoming packets :
@@ -210,6 +211,9 @@ nfqws takes the following parameters:
--filter-l3=ipv4|ipv6 ; L3 protocol filter. multiple comma separated values allowed.
--filter-tcp=[~]port1[-port2] ; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp.
--filter-udp=[~]port1[-port2] ; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp.
--filter-l7=[http|tls|quic|wireguard|dht|unknown] ; L6-L7 protocol filter. multiple comma separated values allowed.
--ipset=<filename> ; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
--ipset-exclude=<filename> ; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
```
The manipulation parameters can be combined in any way.
@@ -574,18 +578,18 @@ You need to use nftables instead with hook priority 101 or higher.
`nfqws` can apply different strategies to different requests. It's done with multiple desync profiles.
Profiles are delimited by the `--new` parameter. First profile is created automatically and does not require `--new`.
Each profile has a filter. By default it's empty and profile matches any packet.
Filter can have hard parameters : ip version and tcp/udp port range.
Hard parameters are always identified unambiguously even on zero-phase when hostname is unknown yet.
Hostlist can also act as a filter. They can be combined with hard parameters.
Filter can have hard parameters : ip version, ipset and tcp/udp port range.
Hard parameters are always identified unambiguously even on zero-phase when hostname and L7 are unknown yet.
Hostlists can also act as a filter. They can be combined with hard parameters.
When a packet comes profiles are matched from the first to the last until first filter condition match.
Hard filter is matched first. If it does not match verification goes to the next profile.
If a profile matches hard filter and has autohostlist it's selected immediately.
If a profile matches hard filter and has normal hostlist(s) and hostname is unknown yet verification goes to the next profile.
If a profile matches hard filter , L7 filter and has autohostlist it's selected immediately.
If a profile matches hard filter , L7 filter and has normal hostlist(s) and hostname is unknown yet verification goes to the next profile.
Otherwise profile hostlist(s) are checked for the hostname. If it matches profile is selected.
Otherwise verification goes to the next profile.
It's possible that before getting hostname connection is served by one profile and after
hostname is revealed it's switched to another profile.
It's possible that before knowing L7 and hostname connection is served by one profile and after
this information is revealed it's switched to another profile.
If you use 0-phase desync methods think carefully what can happen during strategy switch.
Use `--debug` logging to understand better what `nfqws` does.
@@ -596,6 +600,9 @@ IMPORTANT : multiple strategies exist only for the case when it's not possible t
Copy-pasting blockcheck results of different websites to multiple strategies lead to the mess.
This way you may never unblock all resources and only confuse yourself.
IMPORTANT : user-mode ipset implementation was not designed as a kernel version replacement. Kernel version is much more effective.
It's for the systems that lack ipset support : Windows and Linux without nftables and ipset kernel modules (Android, for example).
## tpws
tpws is transparent proxy.
@@ -636,6 +643,9 @@ tpws is transparent proxy.
--new ; begin new strategy
--filter-l3=ipv4|ipv6 ; L3 protocol filter. multiple comma separated values allowed.
--filter-tcp=[~]port1[-port2] ; TCP port filter. ~ means negation
--filter-l7=[http|tls|unknown] ; L6-L7 protocol filter. multiple comma separated values allowed.
--ipset=<filename> ; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
--ipset-exclude=<filename> ; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
--hostlist=<filename> ; only act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)
--hostlist-exclude=<filename> ; do not act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)

View File

@@ -1,4 +1,4 @@
zapret v.64
zapret v.65
English
-------
@@ -280,6 +280,9 @@ nfqws
--filter-l3=ipv4|ipv6 ; фильтр версии ip для текущей стратегии
--filter-tcp=[~]port1[-port2] ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. установка фильтра tcp и неустановка фильтра udp запрещает udp.
--filter-udp=[~]port1[-port2] ; фильтр портов udp для текущей стратегии. ~ означает инверсию. установка фильтра udp и неустановка фильтра tcp запрещает udp.
--filter-l7=[http|tls|quic|wireguard|dht|unknown] ; фильтр протокола L6-L7. поддерживается несколько значений через запятую.
--ipset=<filename> ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip.
--ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip.
Параметры манипуляции могут сочетаться в любых комбинациях.
@@ -464,8 +467,8 @@ mark нужен, чтобы сгенерированный поддельный
чтобы не допустить изменения порядка следования пакетов. Процессинг очереди - процесс отложенный.
Если ядро имеет пакеты на отсылку вне очереди - оно их отправляет незамедлительно.
Изменение правильного порядка следования пакетов при десинхронизации ломает всю идею.
При отсутствии ограничения на connbytes, атака будет работать и без фильтра по mark.
Но лучше его все же оставить для увеличения скорости.
Так же были замечены дедлоки при достаточно большой отсылке пакетов из nfqws и отсутствии mark фильтра.
Процесс может зависнуть. Поэтому наличие фильтра по mark в ip/nf tables можно считать обязательным.
Почему --connbytes 1:6 :
1 - для работы методов десинхронизации 0-й фазы и wssize
@@ -664,20 +667,22 @@ nfqws способен по-разному реагировать на разл
Профили разделяются в командной строке параметром --new. Первый профиль создается автоматически.
Для него не нужно --new. Каждый профиль имеет фильтр. По умолчанию он пуст, то есть профиль удовлетворяет
любым условиям.
Фильтр может содержать жесткие параметры : версия ip протокола или порты tcp/udp.
Они всегда однозначно идентифицируются даже на нулевой фазе десинхронизации, когда еще хост неизвестен.
В качестве фильтра могут выступать и хост-листы. Они могут сочетаться с жесткими параметрами.
Фильтр может содержать жесткие параметры : версия ip протокола, ipset и порты tcp/udp.
Они всегда однозначно идентифицируются даже на нулевой фазе десинхронизации, когда еще хост и L7 неизвестны.
В качестве мягкого фильтра могут выступать хост-листы и протокол прикладного уровня (l7).
L7 протокол становится известен обычно после первого пакета с данными.
При поступлении запроса идет проверка профилей в порядке от первого до последнего до
достижения первого совпадения с фильтром.
Жесткие параметры фильтра сверяются первыми. При несовпадении идет сразу же переход к следующему профилю.
Если какой-то профиль удовлетворяет жесткому фильтру и содержит авто-хостлист, он выбирается сразу.
Если профиль удовлетворяет жесткому фильтру, для него задан хостлист, и у нас еще нет имени хоста,
Если какой-то профиль удовлетворяет жесткому фильтру и L7 фильтру и содержит авто-хостлист, он выбирается сразу.
Если профиль удовлетворяет жесткому фильтру и L7 фильтру, для него задан хостлист, и у нас еще нет имени хоста,
идет переход к следующему профилю. В противном случае идет проверка по хостлистам этого профиля.
Если имя хоста удовлетворяет листам, выбирается этот профиль. Иначе идет переход к следующему.
Может так случиться, что до получения имени хоста соединение идет по одному профилю, а при получении
хоста профиль меняется на лету. Поэтому если у вас есть параметры дурения нулевой фазы, тщательно
продумывайте что может произойти при переключении стратегии. Смотрите debug log, чтобы лучше
понять что делает nfqws.
Может так случиться, что до получения имени хоста или узнавания L7 протокола соединение идет по одному профилю,
а при выяснении этих параметров профиль меняется на лету. Это может произойти даже дважды - при выяснении L7
и имени хоста. Чаще всего это выяснение совмещается в одно действие, поскольку по одному пакету как правило узнается и L7, и хост.
Поэтому если у вас есть параметры дурения нулевой фазы, тщательно продумывайте что может произойти при переключении стратегии.
Смотрите debug log, чтобы лучше понять что делает nfqws.
Нумерация профилей идет с 1 до N. Последним в цепочке создается пустой профиль с номером 0.
Он используется, когда никакие условия фильтров не совпали.
@@ -686,6 +691,10 @@ nfqws способен по-разному реагировать на разл
во множество профилей без понимания как они работают приведет к нагромождению параметров, которые все равно
не покроют все возможные заблокированные ресурсы. Вы только увязните в этой каше.
ВАЖНО : user-mode реализация ipset создавалась не как удобная замена *nix версии, реализованной в ядре.
Вариант в ядре работает гораздо эффективнее. Это создавалось для систем без подержки ipset в ядре.
Конкретно - Windows и ядра Linux, собранные без nftables и ipset модулей ядра. Например, в android нет ipset.
tpws
-----
@@ -777,6 +786,9 @@ tpws - это transparent proxy.
--new ; начало новой стратегии
--filter-l3=ipv4|ipv6 ; фильтр версии ip для текущей стратегии
--filter-tcp=[~]port1[-port2] ; фильтр портов tcp для текущей стратегии. ~ означает инверсию.
--filter-l7=[http|tls|quic|wireguard|dht|unknown] ; фильтр протокола L6-L7. поддерживается несколько значений через запятую.
--ipset=<filename> ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip.
--ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip.
--debug позволяет выводить подробный лог действий на консоль, в syslog или в файл.
@@ -981,10 +993,13 @@ Cкрипты с названием get_antifilter_* оперируют спис
9) ipset/get_antifilter_allyouneed.sh. получает лист https://antifilter.download/list/allyouneed.lst.
Суммарный список префиксов, созданный из ipsum.lst и subnet.lst.
Все варианты рассмотренных скриптов автоматически создают и заполняют ipset.
Варианты 2-9 дополнительно вызывают вариант 1.
10) ipset/get_refilter_ipsum.sh.
Список берется отсюда : https://github.com/1andrevich/Re-filter-lists
10) ipset/get_config.sh. этот скрипт вызывает то, что прописано в переменной GETLIST из файла config
Все варианты рассмотренных скриптов автоматически создают и заполняют ipset.
Варианты 2-10 дополнительно вызывают вариант 1.
11) ipset/get_config.sh. этот скрипт вызывает то, что прописано в переменной GETLIST из файла config
Если переменная не определена, то ресолвятся лишь листы для ipset nozapret/nozapret6.
Листы РКН все время изменяются. Возникают новые тенденции. Требования к RAM могут меняться.
@@ -1111,7 +1126,11 @@ ipset/zapret-hosts-users-exclude.txt.gz или ipset/zapret-hosts-users-exclude.
Поддомены учитываются автоматически. Например, строчка "ru" вносит в список "*.ru". Строчка "*.ru" в списке не сработает.
Список доменов РКН может быть получен скриптами ipset/get_reestr_hostlist.sh или ipset/get_antizapret_domains.sh
Список доменов РКН может быть получен скриптами
ipset/get_reestr_hostlist.sh
ipset/get_antizapret_domains.sh
ipset/get_reestr_resolvable_domains.sh
ipset/get_refilter_domains.sh
- кладется в ipset/zapret-hosts.txt.gz.
Чтобы обновить списки, перезапускать nfqws или tpws не нужно. Обновляете файлы, затем даете сигнал HUP.
@@ -1579,14 +1598,17 @@ custom код вынесен в отдельные shell includes.
/opt/zapret/init.d/macos/custom
Он считается устаревшим. Актуальный вариант - помещать отдельные скрипты там же, но в директорию "custom.d".
Она будет просканирована стандартным образом, т.е. в алфавитном порядке, и каждый скрипт будет применен.
Рядом имеется "custom.d.examples". Это готовые скрипты, который можно копировать в "custom.d".
Рядом имеется "custom.d.examples". Это готовые скрипты, которые можно копировать в "custom.d".
Особо стоит отметить "10-inherit-*". Они наследуют стандартные режимы nfqws/tpws/tpws-socks.
Полезно, чтобы не писать код заново. Достаточно лишь скопировать соответствующий файл.
Можно наследовать и более сложным образом.
"10-inherit-tpws4http-nfqws4https" наследует для http tpws, а для https и quic - nfqws.
Для linux пишется код в функции
zapret_custom_daemons
zapret_custom_firewall
zapret_custom_firewall_nft
zapret_custom_firewall_nft_flush
Для macos
zapret_custom_daemons
@@ -1594,18 +1616,44 @@ zapret_custom_firewall_v4
zapret_custom_firewall_v6
zapret_custom_daemons поднимает демоны nfqws/tpws в нужном вам количестве и с нужными вам параметрами.
Особо обратите внимание на номер демона в функциях "run_daemon" и "do_daemon".
Для систем традиционного linux (sysv) и MacOS в первом параметре передается код операции : 1 = запуск, 0 = останов.
Для openwrt логика останова отсутствует за ненадобностью.
Схема запуска демонов в openwrt отличается - используется procd.
zapret_custom_firewall поднимает и убирает правила iptables.
В первом параметре передается код операции : 1 = запуск, 0 = останов.
zapret_custom_firewall_nft поднимает правила nftables.
Логика останова отсутствует за ненадобностью. Стандартные цепочки zapret удаляются автоматически.
Однако, sets и правила из ваших собственных цепочек не удаляются.
Их нужно подчистить в zapret_custom_firewall_nft_flush.
Если set-ов и собственных цепочек у вас нет, функцию можно не определять или оставить пустой.
Если вам не нужны iptables или nftables - можете не писать соответствующую функцию.
В linux можно использовать локальные переменные FW_EXTRA_PRE и FW_EXTRA_POST.
FW_EXTRA_PRE добавляет код к правилам ip/nf tables до кода, генерируемого функциями-хелперами.
FW_EXTRA_POST добавляет код после.
В linux функции-хелперы добавляют правило в начало цепочек, то есть перед уже имеющимися.
Поэтому специализации должны идти после более общих вариантов.
Поэтому наследования идут с префиксом 10, а остальные custom скрипты с префиксом 50.
Допустим, у вас есть особые правила для IP подсети youtube. Порты те же самые.
Включен и общий обход. Чтобы youtube пошел приоритетом, скрипт должен применяться после
общего обхода.
Для macos правило обратное. Там правила добавляются в конец. Поэтому inherit скрипты
имеют префикс 90.
В macos firewall-функции ничего сами никуда не заносят. Их задача - лишь выдать текст в stdout,
содержащий правила для pf-якоря. Остальное сделает обертка.
Особо обратите внимание на номер демона в функциях "run_daemon" и "do_daemon", номера портов tpws
и очередей nfqueue.
Они должны быть уникальными во всех скриптах. При накладке будет ошибка.
Так же следует избегать пересечения номеров портов tpws и очередей nfqws.
При пересечении какой-то из демонов не запустится.
Чтобы как-то нивелировать эту проблему, в examples используется переменная DNUM.
На ее базе считается диапазон номеров очередей (5 шт), которые использует этот скрипт.
При таком подходе достаточно, чтобы DNUM был везде уникален.
Поскольку номера очереди и портов имеют нумерацию до 65536, можно использовать DNUM до 13106.
Однако, следует оставить номера очереди 200-299 для стандартных режимов и не использовать их.
Поэтому используйте функции динамического получения этих значений из пула.
custom скрипты могут использовать переменные из config. Можно помещать в config свои переменные
и использовать их в скриптах.
и задействовать их в скриптах.
Можно использовать функции-хелперы. Они являются частью общего пространства функций shell.
Полезные функции можно взять из примеров скриптов. Так же смотрите "common/*.sh".
Используя хелпер функции, вы избавитесь от необходимости учитывать все возможные случаи
@@ -1613,17 +1661,6 @@ custom скрипты могут использовать переменные
Хелперы это учитывают, вам нужно сосредоточиться лишь на фильтрах {ip,nf}tables и
параметрах демонов.
Код для openwrt и sysv немного отличается. В sysv нужно обрабатывать и запуск, и остановку демонов.
Запуск это или остановка передается в параметре $1 (0 или 1).
В openwrt за остановку отвечает procd.
Для фаервола в linux кастом пишется отдельно для iptables и nftables. Все очень похоже, но отличается
написание фильтров и названия процедур хелперов. Если вам не нужны iptables или nftables -
можете не писать соответствующую функцию.
В macos firewall-функции ничего сами никуда не заносят. Их задача - лишь выдать текст в stdout,
содержащий правила для pf-якоря. Остальное сделает обертка.
Простая установка
-----------------

View File

@@ -80,11 +80,13 @@ curl -O https://www.cygwin.com/setup-x86_64.exe
setup-x86_64.exe --allow-unsupported-windows --no-verify --site http://ctm.crouchingtigerhiddenfruitbat.org/pub/cygwin/circa/64bit/2024/01/30/231215
```
You must choose to install `curl`. To compile from sources install `gcc-core`,`make`,`zlib-devel`.
Make from directory `nfq` using `make cygwin`.
`winws` requires `cygwin1.dll`, `windivert.dll`, `windivert64.sys`. You can take them from `binaries/win64/zapret-winws`.
It's possible to build x86 32-bit version but this version is not shipped. You have to build it yourself.
32-bit `windivert` can be downloaded from it's developer github. Required version is 2.2.2.
32-bit x86 version can be build from 32-bit cygwin using `make cygwin32`.
`windivert.dll` and `windivert32.sys` can be taken from [windivert 2.2.2 archive](https://reqrypt.org/download)
There's no `arm64` signed `windivert` driver and no `cygwin`.
But it's possible to use unsigned driver version in test mode and user mode components with x64 emulation.
x64 emulation requires `windows 11` and not supported in `windows 10`.
@@ -159,3 +161,5 @@ unix2dos winws.log
```
`winws.log` will be in `cygwin/home/<username>`. `unix2dos` helps with `windows 7` notepad. It's not necessary in `Windows 10` and later.
Pre-compiled 32-bit binaries can be downloaded [here](https://github.com/bol-van/zapret-win32)

View File

@@ -120,8 +120,9 @@ setup-x86_64.exe --allow-unsupported-windows --no-verify --site http://ctm.crouc
Для сборки из исходников требуется gcc-core,make,zlib-devel.
Собирать из директории nfq командой "make cygwin".
winws требует cygwin1.dll, windivert.dll, windivert64.sys. Их можно взять из binaries/win64/zapret-winws.
Версию для 32-битных x86 windows собрать можно, но такие системы уже уходят в прошлое, поэтому если надо - собирайте сами.
32-битный windivert можно взять с сайта разработчика. Требуется версия 2.2.2.
32-битную x86 версию можно собрать из 32-битного cygwin командой "make cygwin32".
windivert.dll и windivert32.sys можно взять из комплекта windivert 2.2.2 : https://reqrypt.org/download
Для arm64 windows нет подписанного драйвера windivert и нет cygwin.
Однако, эмуляция x64 windows 11 позволяет использовать все, кроме WinDivert64.sys без изменений.
@@ -220,3 +221,6 @@ winws --debug --wf-tcp=80,443 | tee winws.log
winws.log будет в cygwin/home/<имя_пользователя>
Если у вас windows 7, то блокнот не поймет переводы строк в стиле unix. Воспользуйтесь командой
unix2dos winws.log
Готовую 32-битную версию можно скачать здесь : https://github.com/bol-van/zapret-win32
Поскольку 32-битные windows мало востребованы, выложены только бинарники и ничего больше.

View File

@@ -1,20 +1,21 @@
# this script is an example describing how to run tpws on a custom port
DNUM=100
TPPORT_MY=${TPPORT_MY:-987}
TPWS_OPT_MY=${TPWS_OPT_MY:-987}
TPWS_OPT_SUFFIX_MY="${TPWS_OPT_SUFFIX_MY:-}"
DPORTS_MY=${DPORTS_MY:-20443,20444,30000-30009}
TPWS_OPT_EXTRA=${TPWS_OPT_EXTRA:---split-pos=2}
TPWS_OPT_SUFFIX_EXTRA="${TPWS_OPT_SUFFIX_EXTRA:-}"
DPORTS_EXTRA=${DPORTS_EXTRA:-20443,20444,30000-30009}
alloc_dnum DNUM_EXTRA_TPWS
alloc_tpws_port TPPORT_EXTRA_TPWS
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
local opt="--user=root --port=$TPPORT_MY"
local opt="--user=root --port=$TPPORT_EXTRA_TPWS"
tpws_apply_binds opt
opt="$opt $TPWS_OPT_MY"
opt="$opt $TPWS_OPT_EXTRA"
filter_apply_hostlist_target opt
filter_apply_suffix opt "$TPWS_OPT_SUFFIX_MY"
do_daemon $1 $DNUM "$TPWS" "$opt"
filter_apply_suffix opt "$TPWS_OPT_SUFFIX_EXTRA"
do_daemon $1 $DNUM_EXTRA_TPWS "$TPWS" "$opt"
}
# custom firewall functions echo rules for zapret-v4 and zapret-v6 anchors
@@ -22,9 +23,9 @@ zapret_custom_daemons()
zapret_custom_firewall_v4()
{
pf_anchor_zapret_v4_tpws $TPPORT_MY $(replace_char - : $DPORTS_MY)
pf_anchor_zapret_v4_tpws $TPPORT_EXTRA_TPWS $(replace_char - : $DPORTS_EXTRA)
}
zapret_custom_firewall_v6()
{
pf_anchor_zapret_v6_tpws $TPPORT_MY $(replace_char - : $DPORTS_MY)
pf_anchor_zapret_v6_tpws $TPPORT_EXTRA_TPWS $(replace_char - : $DPORTS_EXTRA)
}

View File

@@ -4,7 +4,7 @@ OVERRIDE=tpws
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
# stop logic is managed by procd
MODE_OVERRIDE=$OVERRIDE start_daemons_procd
}

View File

@@ -4,7 +4,7 @@ OVERRIDE=tpws-socks
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
# stop logic is managed by procd
MODE_OVERRIDE=$OVERRIDE start_daemons_procd
}

View File

@@ -0,0 +1,35 @@
# this custom script demonstrates how to apply tpws to http and nfqws to https and quic
# it's desired that inherited basic rules are low priority to allow specializations and exceptions in other custom scripts
nfqws_tpws_inheritor()
{
# $1 - inherited function
# $2 - 1 - run, 0 - stop
[ "$MODE_HTTP" = "1" ] && {
MODE_OVERRIDE=tpws MODE_HTTPS=0 MODE_QUIC=0 $1 $2
}
[ "$MODE_HTTPS" = "1" -o "$MODE_QUIC" = "1" ] && {
MODE_OVERRIDE=nfqws MODE_HTTP=0 $1 $2
}
}
zapret_custom_daemons()
{
# stop logic is managed by procd
nfqws_tpws_inheritor start_daemons_procd
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
nfqws_tpws_inheritor zapret_do_firewall_rules_ipt $1
}
zapret_custom_firewall_nft()
{
# stop logic is not required
nfqws_tpws_inheritor zapret_apply_firewall_rules_nft
}

View File

@@ -1,15 +1,15 @@
# this custom script runs desync to DHT packets with udp payload length 101..399 , without ipset/hostlist filtering
# need to add to config : NFQWS_OPT_DESYNC_DHT="--dpi-desync=fake --dpi-desync-ttl=5"
DNUM=101
QNUM2=$(($DNUM * 5))
alloc_dnum DNUM_DHT4ALL
alloc_qnum QNUM_DHT4ALL
zapret_custom_daemons()
{
# stop logic is managed by procd
local opt="--qnum=$QNUM2 $NFQWS_OPT_BASE $NFQWS_OPT_DESYNC_DHT"
run_daemon $DNUM $NFQWS "$opt"
local opt="--qnum=$QNUM_DHT4ALL $NFQWS_OPT_BASE $NFQWS_OPT_DESYNC_DHT"
run_daemon $DNUM_DHT4ALL $NFQWS "$opt"
}
zapret_custom_firewall()
{
@@ -22,7 +22,7 @@ zapret_custom_firewall()
f='-p udp -m length --length 109:407 -m u32 --u32'
uf4='0>>22&0x3C@8>>16=0x6431'
uf6='48>>16=0x6431'
fw_nfqws_post $1 "$f $uf4 $desync $first_packet_only" "$f $uf6 $desync $first_packet_only" $QNUM2
fw_nfqws_post $1 "$f $uf4 $desync $first_packet_only" "$f $uf6 $desync $first_packet_only" $QNUM_DHT4ALL
}
zapret_custom_firewall_nft()
@@ -34,6 +34,5 @@ zapret_custom_firewall_nft()
local desync="mark and $DESYNC_MARK == 0"
f="meta length 109-407 meta l4proto udp @th,64,16 0x6431"
nft_fw_nfqws_post "$f $desync $first_packet_only" "$f $desync $first_packet_only" $QNUM2
nft_fw_nfqws_post "$f $desync $first_packet_only" "$f $desync $first_packet_only" $QNUM_DHT4ALL
}

File diff suppressed because one or more lines are too long

View File

@@ -2,15 +2,15 @@
# need to add to config : NFQWS_OPT_DESYNC_QUIC="--dpi-desync=fake"
# NOTE : do not use TTL fooling. chromium QUIC engine breaks sessions if TTL expired in transit received
DNUM=102
QNUM2=$(($DNUM * 5))
alloc_dnum DNUM_QUIC4ALL
alloc_qnum QNUM_QUIC4ALL
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
local opt="--qnum=$QNUM2 $NFQWS_OPT_BASE $NFQWS_OPT_DESYNC_QUIC"
run_daemon $DNUM $NFQWS "$opt"
local opt="--qnum=$QNUM_QUIC4ALL $NFQWS_OPT_BASE $NFQWS_OPT_DESYNC_QUIC"
run_daemon $DNUM_QUIC4ALL $NFQWS "$opt"
}
zapret_custom_firewall()
{
@@ -21,7 +21,7 @@ zapret_custom_firewall()
local desync="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK"
f="-p udp -m multiport --dports $QUIC_PORTS_IPT"
fw_nfqws_post $1 "$f $desync $first_packets_only" "$f $desync $first_packets_only" $QNUM2
fw_nfqws_post $1 "$f $desync $first_packets_only" "$f $desync $first_packets_only" $QNUM_QUIC4ALL
}
zapret_custom_firewall_nft()
@@ -33,5 +33,5 @@ zapret_custom_firewall_nft()
local desync="mark and $DESYNC_MARK == 0"
f="udp dport {$QUIC_PORTS}"
nft_fw_nfqws_post "$f $desync $first_packets_only" "$f $desync $first_packets_only" $QNUM2
nft_fw_nfqws_post "$f $desync $first_packets_only" "$f $desync $first_packets_only" $QNUM_QUIC4ALL
}

View File

@@ -1,71 +0,0 @@
# this custom script demonstrates how to apply tpws to http and nfqws to https
# it preserves config settings : MODE_HTTP, MODE_HTTPS, MODE_FILTER, TPWS_OPT, NFQWS_OPT_DESYNC, NFQWS_OPT_DESYNC_HTTPS
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
local opt
[ "$MODE_HTTP" = "1" ] && {
opt="--port=$TPPORT $TPWS_OPT"
filter_apply_hostlist_target opt
filter_apply_suffix opt "$TPWS_OPT_SUFFIX"
run_tpws 1 "$opt"
}
[ "$MODE_HTTPS" = "1" ] && {
opt="--qnum=$QNUM $NFQWS_OPT_DESYNC_HTTPS"
filter_apply_hostlist_target opt
filter_apply_suffix opt "$NFQWS_OPT_DESYNC_HTTPS_SUFFIX"
run_daemon 2 $NFQWS "$opt"
}
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
local f4 f6
local first_packet_only="$ipt_connbytes 1:$(first_packets_for_mode)"
local desync="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK"
[ "$MODE_HTTP" = "1" ] && {
f4="-p tcp -m multiport --dports $HTTP_PORTS_IPT"
f6=$f4
filter_apply_ipset_target f4 f6
fw_tpws $1 "$f4" "$f6" $TPPORT
}
[ "$MODE_HTTPS" = "1" ] && {
f4="-p tcp -m multiport --dports $HTTPS_PORTS_IPT $first_packet_only"
f6=$f4
filter_apply_ipset_target f4 f6
fw_nfqws_post $1 "$f4 $desync" "$f6 $desync" $QNUM
# for modes that require incoming traffic
fw_reverse_nfqws_rule $1 "$f4" "$f6" $QNUM
}
}
zapret_custom_firewall_nft()
{
# stop logic is not required
local f4 f6
local first_packet_only="$nft_connbytes 1-$(first_packets_for_mode)"
local desync="mark and $DESYNC_MARK == 0"
[ "$MODE_HTTP" = "1" ] && {
f4="tcp dport {$HTTP_PORTS}"
f6=$f4
nft_filter_apply_ipset_target f4 f6
nft_fw_tpws "$f4" "$f6" $TPPORT
}
[ "$MODE_HTTPS" = "1" ] && {
f4="tcp dport {$HTTPS_PORTS} $first_packet_only"
f6=$f4
nft_filter_apply_ipset_target f4 f6
nft_fw_nfqws_post "$f4 $desync" "$f6 $desync" $QNUM
# for modes that require incoming traffic
nft_fw_reverse_nfqws_rule "$f4" "$f6" $QNUM
}
}

View File

@@ -0,0 +1,35 @@
# this custom script demonstrates how to apply tpws to http and nfqws to https and quic
# it's desired that inherited basic rules are low priority to allow specializations and exceptions in other custom scripts
nfqws_tpws_inheritor()
{
# $1 - inherited function
# $2 - 1 - run, 0 - stop
[ "$MODE_HTTP" = "1" ] && {
MODE_OVERRIDE=tpws MODE_HTTPS=0 MODE_QUIC=0 $1 $2
}
[ "$MODE_HTTPS" = "1" -o "$MODE_QUIC" = "1" ] && {
MODE_OVERRIDE=nfqws MODE_HTTP=0 $1 $2
}
}
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
nfqws_tpws_inheritor zapret_do_daemons $1
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
nfqws_tpws_inheritor zapret_do_firewall_rules_ipt $1
}
zapret_custom_firewall_nft()
{
# stop logic is not required
nfqws_tpws_inheritor zapret_apply_firewall_rules_nft
}

View File

@@ -1,15 +1,15 @@
# this custom script runs desync to DHT packets with udp payload length 101..399 , without ipset/hostlist filtering
# need to add to config : NFQWS_OPT_DESYNC_DHT="--dpi-desync=fake --dpi-desync-ttl=5"
DNUM=101
QNUM2=$(($DNUM * 5))
alloc_dnum DNUM_DHT4ALL
alloc_qnum QNUM_DHT4ALL
zapret_custom_daemons()
{
# stop logic is managed by procd
local opt="--qnum=$QNUM2 $NFQWS_OPT_BASE $NFQWS_OPT_DESYNC_DHT"
do_nfqws $1 $DNUM "$opt"
local opt="--qnum=$QNUM_DHT4ALL $NFQWS_OPT_BASE $NFQWS_OPT_DESYNC_DHT"
do_nfqws $1 $DNUM_DHT4ALL "$opt"
}
zapret_custom_firewall()
{
@@ -22,7 +22,7 @@ zapret_custom_firewall()
f='-p udp -m length --length 109:407 -m u32 --u32'
uf4='0>>22&0x3C@8>>16=0x6431'
uf6='48>>16=0x6431'
fw_nfqws_post $1 "$f $uf4 $desync $first_packet_only" "$f $uf6 $desync $first_packet_only" $QNUM2
fw_nfqws_post $1 "$f $uf4 $desync $first_packet_only" "$f $uf6 $desync $first_packet_only" $QNUM_DHT4ALL
}
zapret_custom_firewall_nft()
@@ -34,6 +34,6 @@ zapret_custom_firewall_nft()
local desync="mark and $DESYNC_MARK == 0"
f="meta length 109-407 meta l4proto udp @th,64,16 0x6431"
nft_fw_nfqws_post "$f $desync $first_packet_only" "$f $desync $first_packet_only" $QNUM2
nft_fw_nfqws_post "$f $desync $first_packet_only" "$f $desync $first_packet_only" $QNUM_DHT4ALL
}

File diff suppressed because one or more lines are too long

View File

@@ -2,15 +2,15 @@
# need to add to config : NFQWS_OPT_DESYNC_QUIC="--dpi-desync=fake"
# NOTE : do not use TTL fooling. chromium QUIC engine breaks sessions if TTL expired in transit received
DNUM=102
QNUM2=$(($DNUM * 5))
alloc_dnum DNUM_QUIC4ALL
alloc_qnum QNUM_QUIC4ALL
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
local opt="--qnum=$QNUM2 $NFQWS_OPT_BASE $NFQWS_OPT_DESYNC_QUIC"
do_nfqws $1 $DNUM "$opt"
local opt="--qnum=$QNUM_QUIC4ALL $NFQWS_OPT_BASE $NFQWS_OPT_DESYNC_QUIC"
do_nfqws $1 $DNUM_QUIC4ALL "$opt"
}
zapret_custom_firewall()
{
@@ -21,7 +21,7 @@ zapret_custom_firewall()
local desync="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK"
f="-p udp -m multiport --dports $QUIC_PORTS_IPT"
fw_nfqws_post $1 "$f $desync $first_packets_only" "$f $desync $first_packets_only" $QNUM2
fw_nfqws_post $1 "$f $desync $first_packets_only" "$f $desync $first_packets_only" $QNUM_QUIC4ALL
}
zapret_custom_firewall_nft()
@@ -33,5 +33,5 @@ zapret_custom_firewall_nft()
local desync="mark and $DESYNC_MARK == 0"
f="udp dport {$QUIC_PORTS}"
nft_fw_nfqws_post "$f $desync $first_packets_only" "$f $desync $first_packets_only" $QNUM2
nft_fw_nfqws_post "$f $desync $first_packets_only" "$f $desync $first_packets_only" $QNUM_QUIC4ALL
}

View File

@@ -1,71 +0,0 @@
# this custom script demonstrates how to apply tpws to http and nfqws to https
# it preserves config settings : MODE_HTTP, MODE_HTTPS, MODE_FILTER, TPWS_OPT, NFQWS_OPT_DESYNC, NFQWS_OPT_DESYNC_HTTPS
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
local opt
[ "$MODE_HTTP" = "1" ] && {
opt="--port=$TPPORT $TPWS_OPT"
filter_apply_hostlist_target opt
filter_apply_suffix opt "$TPWS_OPT_SUFFIX"
do_tpws $1 1 "$opt"
}
[ "$MODE_HTTPS" = "1" ] && {
opt="--qnum=$QNUM $NFQWS_OPT_DESYNC_HTTPS"
filter_apply_hostlist_target opt
filter_apply_suffix opt "$NFQWS_OPT_DESYNC_HTTPS_SUFFIX"
do_nfqws $1 2 "$opt"
}
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
local f4 f6
local first_packet_only="$ipt_connbytes 1:$(first_packets_for_mode)"
local desync="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK"
[ "$MODE_HTTP" = "1" ] && {
f4="-p tcp -m multiport --dports $HTTP_PORTS_IPT"
f6=$f4
filter_apply_ipset_target f4 f6
fw_tpws $1 "$f4" "$f6" $TPPORT
}
[ "$MODE_HTTPS" = "1" ] && {
f4="-p tcp -m multiport --dports $HTTPS_PORTS_IPT $first_packet_only"
f6=$f4
filter_apply_ipset_target f4 f6
fw_nfqws_post $1 "$f4 $desync" "$f6 $desync" $QNUM
# for modes that require incoming traffic
fw_reverse_nfqws_rule $1 "$f4" "$f6" $QNUM
}
}
zapret_custom_firewall_nft()
{
# stop logic is not required
local f4 f6
local first_packet_only="$nft_connbytes 1-$(first_packets_for_mode)"
local desync="mark and $DESYNC_MARK == 0"
[ "$MODE_HTTP" = "1" ] && {
f4="tcp dport {$HTTP_PORTS}"
f6=$f4
nft_filter_apply_ipset_target f4 f6
nft_fw_tpws "$f4" "$f6" $TPPORT
}
[ "$MODE_HTTPS" = "1" ] && {
f4="tcp dport {$HTTPS_PORTS} $first_packet_only"
f6=$f4
nft_filter_apply_ipset_target f4 f6
nft_fw_nfqws_post "$f4 $desync" "$f6 $desync" $QNUM
# for modes that require incoming traffic
nft_fw_reverse_nfqws_rule "$f4" "$f6" $QNUM
}
}

View File

@@ -219,10 +219,10 @@ select_getlist()
echo
if ask_yes_no $D "do you want to auto download ip/host list"; then
if [ "$MODE_FILTER" = "hostlist" ] ; then
GETLISTS="get_antizapret_domains.sh get_reestr_resolvable_domains.sh get_reestr_hostlist.sh"
GETLISTS="get_refilter_domains.sh get_antizapret_domains.sh get_reestr_resolvable_domains.sh get_reestr_hostlist.sh"
GETLIST_DEF="get_antizapret_domains.sh"
else
GETLISTS="get_user.sh get_antifilter_ip.sh get_antifilter_ipsmart.sh get_antifilter_ipsum.sh get_antifilter_ipresolve.sh get_antifilter_allyouneed.sh get_reestr_resolve.sh get_reestr_preresolved.sh get_reestr_preresolved_smart.sh"
GETLISTS="get_user.sh get_refilter_ipsum.sh get_antifilter_ip.sh get_antifilter_ipsmart.sh get_antifilter_ipsum.sh get_antifilter_ipresolve.sh get_antifilter_allyouneed.sh get_reestr_resolve.sh get_reestr_preresolved.sh get_reestr_preresolved_smart.sh"
GETLIST_DEF="get_antifilter_allyouneed.sh"
fi
ask_list GETLIST "$GETLISTS" "$GETLIST_DEF" && write_config_var GETLIST
@@ -462,6 +462,8 @@ files/huawei/E8372/zapret \
files/huawei/E8372/run-zapret-ip \
ipset/get_exclude.sh \
ipset/clear_lists.sh \
ipset/get_refilter_domains.sh \
ipset/get_refilter_ipsum.sh \
ipset/get_antifilter_ipresolve.sh \
ipset/get_reestr_resolvable_domains.sh \
ipset/get_config.sh \

42
ipset/get_refilter_domains.sh Executable file
View File

@@ -0,0 +1,42 @@
#!/bin/sh
IPSET_DIR="$(dirname "$0")"
IPSET_DIR="$(cd "$IPSET_DIR"; pwd)"
. "$IPSET_DIR/def.sh"
TMPLIST="$TMPDIR/list.txt"
URL="https://github.com/1andrevich/Re-filter-lists/releases/latest/download/domains_all.lst"
dl()
{
# $1 - url
# $2 - file
# $3 - minsize
# $4 - maxsize
curl -L -H "Accept-Encoding: gzip" -k --fail --max-time 60 --connect-timeout 10 --retry 4 --max-filesize $4 -o "$TMPLIST" "$1" ||
{
echo list download failed : $1
exit 2
}
dlsize=$(LANG=C wc -c "$TMPLIST" | xargs | cut -f 1 -d ' ')
if test $dlsize -lt $3; then
echo list is too small : $dlsize bytes. can be bad.
exit 2
fi
zzcat "$TMPLIST" | tr -d '\015' | zz "$2"
rm -f "$TMPLIST"
}
# useful in case ipban set is used in custom scripts
FAIL=
getipban || FAIL=1
"$IPSET_DIR/create_ipset.sh"
[ -n "$FAIL" ] && exit
dl "$URL" "$ZHOSTLIST" 32768 4194304
hup_zapret_daemons
exit 0

39
ipset/get_refilter_ipsum.sh Executable file
View File

@@ -0,0 +1,39 @@
#!/bin/sh
IPSET_DIR="$(dirname "$0")"
IPSET_DIR="$(cd "$IPSET_DIR"; pwd)"
. "$IPSET_DIR/def.sh"
TMPLIST="$TMPDIR/list.txt"
URL="https://github.com/1andrevich/Re-filter-lists/releases/latest/download/ipsum.lst"
dl()
{
# $1 - url
# $2 - file
# $3 - minsize
# $4 - maxsize
curl -L -H "Accept-Encoding: gzip" -k --fail --max-time 60 --connect-timeout 10 --retry 4 --max-filesize $4 -o "$TMPLIST" "$1" ||
{
echo list download failed : $1
exit 2
}
dlsize=$(LANG=C wc -c "$TMPLIST" | xargs | cut -f 1 -d ' ')
if test $dlsize -lt $3; then
echo list is too small : $dlsize bytes. can be bad.
exit 2
fi
# remove DOS EOL \r
zzcat "$TMPLIST" | tr -d '\015' | zz "$2"
rm -f "$TMPLIST"
}
getuser && {
[ "$DISABLE_IPV4" != "1" ] && {
dl "$URL" "$ZIPLIST" 32768 4194304
}
}
"$IPSET_DIR/create_ipset.sh"

View File

@@ -5,7 +5,11 @@ CFLAGS_MAC = -mmacosx-version-min=10.8
CFLAGS_CYGWIN = -Wno-address-of-packed-member -static
LIBS_LINUX = -lnetfilter_queue -lnfnetlink -lz
LIBS_BSD = -lz
LIBS_CYGWIN = -lz -Lwindivert -lwindivert -lwlanapi -lole32 -loleaut32 -luuid
LIBS_CYGWIN = -lz -Lwindows/windivert -Iwindows -lwlanapi -lole32 -loleaut32 -luuid
LIBS_CYGWIN32 = -lwindivert32
LIBS_CYGWIN64 = -lwindivert64
RES_CYGWIN32 = windows/res/32/winmanifest.o windows/res/32/winicon.o
RES_CYGWIN64 = windows/res/64/winmanifest.o windows/res/64/winicon.o
SRC_FILES = *.c crypto/*.c
all: nfqws
@@ -23,8 +27,11 @@ mac: $(SRC_FILES)
lipo -create -output dvtws dvtwsx dvtwsa
rm -f dvtwsx dvtwsa
cygwin:
$(CC) -s $(CFLAGS) $(CFLAGS_CYGWIN) -o winws $(SRC_FILES) $(LDFLAGS) $(LIBS_CYGWIN) winmanifest.o winicon.o
cygwin64:
$(CC) -s $(CFLAGS) $(CFLAGS_CYGWIN) -o winws $(SRC_FILES) $(LDFLAGS) $(LIBS_CYGWIN) $(LIBS_CYGWIN64) $(RES_CYGWIN64)
cygwin32:
$(CC) -s $(CFLAGS) $(CFLAGS_CYGWIN) -o winws $(SRC_FILES) $(LDFLAGS) $(LIBS_CYGWIN) $(LIBS_CYGWIN32) $(RES_CYGWIN32)
cygwin: cygwin64
clean:
rm -f nfqws dvtws winws.exe

View File

@@ -12,6 +12,29 @@ static void ut_oom_recover(void *elem)
oom = true;
}
const char *l7proto_str(t_l7proto l7)
{
switch(l7)
{
case HTTP: return "http";
case TLS: return "tls";
case QUIC: return "quic";
case WIREGUARD: return "wireguard";
case DHT: return "dht";
default: return "unknown";
}
}
bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7)
{
return (l7proto==UNKNOWN && (filter_l7 & L7_PROTO_UNKNOWN)) ||
(l7proto==HTTP && (filter_l7 & L7_PROTO_HTTP)) ||
(l7proto==TLS && (filter_l7 & L7_PROTO_TLS)) ||
(l7proto==QUIC && (filter_l7 & L7_PROTO_QUIC)) ||
(l7proto==WIREGUARD && (filter_l7 & L7_PROTO_WIREGUARD)) ||
(l7proto==DHT && (filter_l7 & L7_PROTO_DHT));
}
static const char *connstate_s[]={"SYN","ESTABLISHED","FIN"};
static void connswap(const t_conn *c, t_conn *c2)
@@ -316,18 +339,6 @@ static void taddr2str(uint8_t l3proto, const t_addr *a, char *buf, size_t bufsiz
if (!inet_ntop(family_from_proto(l3proto), a, buf, bufsize) && bufsize) *buf=0;
}
static const char *ConntrackProtoName(t_l7proto proto)
{
switch(proto)
{
case HTTP: return "HTTP";
case TLS: return "TLS";
case QUIC: return "QUIC";
case WIREGUARD: return "WIREGUARD";
case DHT: return "DHT";
default: return "UNKNOWN";
}
}
void ConntrackPoolDump(const t_conntrack *p)
{
t_conntrack_pool *t, *tmp;
@@ -354,7 +365,7 @@ void ConntrackPoolDump(const t_conntrack *p)
t->track.seq_last, t->track.pos_orig,
t->track.ack_last, t->track.pos_reply);
printf(" req_retrans=%u cutoff=%u wss_cutoff=%u d_cutoff=%u hostname=%s l7proto=%s\n",
t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_wssize_cutoff, t->track.b_desync_cutoff, t->track.hostname, ConntrackProtoName(t->track.l7proto));
t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_wssize_cutoff, t->track.b_desync_cutoff, t->track.hostname, l7proto_str(t->track.l7proto));
};
}

View File

@@ -52,12 +52,23 @@ typedef struct {
// ESTABLISHED - any except SYN or SYN/ACK received
// FIN - FIN or RST received
typedef enum {SYN=0, ESTABLISHED, FIN} t_connstate;
typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT} t_l7proto;
#define L7_PROTO_HTTP 0x00000001
#define L7_PROTO_TLS 0x00000002
#define L7_PROTO_QUIC 0x00000004
#define L7_PROTO_WIREGUARD 0x00000008
#define L7_PROTO_DHT 0x00000010
#define L7_PROTO_UNKNOWN 0x80000000
const char *l7proto_str(t_l7proto l7);
bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7);
typedef struct
{
bool bCheckDone, bCheckResult, bCheckExcluded; // hostlist check result cache
struct desync_profile *dp; // desync profile cache
bool dp_search_complete;
bool bCheckDone, bCheckResult, bCheckExcluded; // hostlist check result cache
// common state
time_t t_start, t_last;
@@ -76,12 +87,13 @@ typedef struct
bool req_seq_present,req_seq_finalized,req_seq_abandoned;
uint32_t req_seq_start,req_seq_end; // sequence interval of the request (to track retransmissions)
uint8_t autottl;
uint8_t incoming_ttl, autottl;
bool b_cutoff; // mark for deletion
bool b_wssize_cutoff, b_desync_cutoff;
t_l7proto l7proto;
bool l7proto_discovered;
char *hostname;
bool hostname_ah_check; // should perform autohostlist checks

View File

@@ -22,6 +22,11 @@
#ifdef __CYGWIN__
#include <wlanapi.h>
#include <netlistmgr.h>
#ifndef ERROR_INVALID_IMAGE_HASH
#define ERROR_INVALID_IMAGE_HASH __MSABI_LONG(577)
#endif
#endif
uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment)

View File

@@ -5,6 +5,7 @@
#include "params.h"
#include "helpers.h"
#include "hostlist.h"
#include "ipset.h"
#include "conntrack.h"
#include <string.h>
@@ -145,20 +146,32 @@ enum dpi_desync_mode desync_mode_from_string(const char *s)
return DESYNC_INVALID;
}
static bool dp_match_l3l4(struct desync_profile *dp, bool ipv6, uint16_t tcp_port, uint16_t udp_port)
static bool dp_match_l3l4(struct desync_profile *dp, uint8_t l3proto, const struct sockaddr *dest)
{
return \
((!ipv6 && dp->filter_ipv4) || (ipv6 && dp->filter_ipv6)) &&
(!tcp_port || pf_in_range(tcp_port,&dp->pf_tcp)) &&
(!udp_port || pf_in_range(udp_port,&dp->pf_udp));
return ((dest->sa_family==AF_INET && dp->filter_ipv4) || (dest->sa_family==AF_INET6 && dp->filter_ipv6)) &&
(l3proto==IPPROTO_TCP && pf_in_range(saport(dest), &dp->pf_tcp) || l3proto==IPPROTO_UDP && pf_in_range(saport(dest), &dp->pf_udp)) &&
IpsetCheck(dp, dest->sa_family==AF_INET ? &((struct sockaddr_in*)dest)->sin_addr : NULL, dest->sa_family==AF_INET6 ? &((struct sockaddr_in6*)dest)->sin6_addr : NULL);
}
static bool dp_impossible(struct desync_profile *dp, const char *hostname, t_l7proto l7proto)
{
return !PROFILE_IPSETS_EMPTY(dp) &&
((dp->filter_l7 && !l7_proto_match(l7proto, dp->filter_l7)) || (!*dp->hostlist_auto_filename && !hostname && (dp->hostlist || dp->hostlist_exclude)));
}
static bool dp_match(
struct desync_profile *dp, bool ipv6, uint16_t tcp_port, uint16_t udp_port, const char *hostname,
struct desync_profile *dp,
uint8_t l3proto, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto,
bool *bCheckDone, bool *bCheckResult, bool *bExcluded)
{
if (bCheckDone) *bCheckDone = false;
if (dp_match_l3l4(dp,ipv6,tcp_port,udp_port))
// impossible case, hard filter
// impossible check avoids relatively slow ipset search
if (!dp_impossible(dp,hostname,l7proto) && dp_match_l3l4(dp,l3proto,dest))
{
// soft filter
if (dp->filter_l7 && !l7_proto_match(l7proto, dp->filter_l7))
return false;
// autohostlist profile matching l3/l4 filter always win
if (*dp->hostlist_auto_filename) return true;
@@ -181,15 +194,21 @@ static bool dp_match(
return false;
}
static struct desync_profile *dp_find(
struct desync_profile_list_head *head, bool ipv6, uint16_t tcp_port, uint16_t udp_port, const char *hostname,
struct desync_profile_list_head *head,
uint8_t l3proto, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto,
bool *bCheckDone, bool *bCheckResult, bool *bExcluded)
{
struct desync_profile_list *dpl;
DLOG("desync profile search for hostname='%s' ipv6=%u tcp_port=%u udp_port=%u\n", hostname ? hostname : "", ipv6, tcp_port, udp_port);
if (params.debug)
{
char ip_port[48];
ntop46_port(dest, ip_port,sizeof(ip_port));
DLOG("desync profile search for %s target=%s l7proto=%s hostname='%s'\n", proto_name(l3proto), ip_port, l7proto_str(l7proto), hostname ? hostname : "");
}
if (bCheckDone) *bCheckDone = false;
LIST_FOREACH(dpl, head, next)
{
if (dp_match(&dpl->dp,ipv6,tcp_port,udp_port,hostname,bCheckDone,bCheckResult,bExcluded))
if (dp_match(&dpl->dp,l3proto,dest,hostname,l7proto,bCheckDone,bCheckResult,bExcluded))
{
DLOG("desync profile %d matches\n",dpl->dp.n);
return &dpl->dp;
@@ -272,7 +291,7 @@ static void ctrack_stop_retrans_counter(t_ctrack *ctrack)
}
}
static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const char *hostname)
static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const char *hostname, const char *client_ip_port, t_l7proto l7proto)
{
if (hostname)
{
@@ -283,13 +302,13 @@ static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const ch
{
HostFailPoolDel(&dp->hostlist_auto_fail_counters, fail_counter);
DLOG("auto hostlist (profile %d) : %s : fail counter reset. website is working.\n", dp->n, hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : fail counter reset. website is working.", hostname, dp->n);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : fail counter reset. website is working.", hostname, dp->n, client_ip_port, l7proto_str(l7proto));
}
}
}
// return true if retrans trigger fires
static bool auto_hostlist_retrans(t_ctrack *ctrack, uint8_t l4proto, int threshold)
static bool auto_hostlist_retrans(t_ctrack *ctrack, uint8_t l4proto, int threshold, const char *client_ip_port, t_l7proto l7proto)
{
if (ctrack && ctrack->dp && ctrack->hostname_ah_check && ctrack->req_retrans_counter!=RETRANS_COUNTER_STOP)
{
@@ -301,7 +320,7 @@ static bool auto_hostlist_retrans(t_ctrack *ctrack, uint8_t l4proto, int thresho
{
DLOG("req retrans : tcp seq %u not within the req range %u-%u. stop tracking.\n", ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end);
ctrack_stop_retrans_counter(ctrack);
auto_hostlist_reset_fail_counter(ctrack->dp, ctrack->hostname);
auto_hostlist_reset_fail_counter(ctrack->dp, ctrack->hostname, client_ip_port, l7proto);
return false;
}
}
@@ -316,7 +335,7 @@ static bool auto_hostlist_retrans(t_ctrack *ctrack, uint8_t l4proto, int thresho
}
return false;
}
static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname)
static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname, const char *client_ip_port, t_l7proto l7proto)
{
hostfail_pool *fail_counter;
@@ -326,13 +345,13 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
fail_counter = HostFailPoolAdd(&dp->hostlist_auto_fail_counters, hostname, dp->hostlist_auto_fail_time);
if (!fail_counter)
{
fprintf(stderr, "HostFailPoolAdd: out of memory\n");
DLOG_ERR("HostFailPoolAdd: out of memory\n");
return;
}
}
fail_counter->counter++;
DLOG("auto hostlist (profile %d) : %s : fail counter %d/%d\n", dp->n, hostname, fail_counter->counter, dp->hostlist_auto_fail_threshold);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : fail counter %d/%d", hostname, dp->n, fail_counter->counter, dp->hostlist_auto_fail_threshold);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : fail counter %d/%d", hostname, dp->n, client_ip_port, l7proto_str(l7proto), fail_counter->counter, dp->hostlist_auto_fail_threshold);
if (fail_counter->counter >= dp->hostlist_auto_fail_threshold)
{
DLOG("auto hostlist (profile %d) : fail threshold reached. about to add %s to auto hostlist\n", dp->n, hostname);
@@ -343,10 +362,10 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
if (!HostlistCheck(dp, hostname, &bExcluded) && !bExcluded)
{
DLOG("auto hostlist (profile %d) : adding %s to %s\n", dp->n, hostname, dp->hostlist_auto_filename);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : adding to %s", hostname, dp->n, dp->hostlist_auto_filename);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : adding to %s", hostname, dp->n, client_ip_port, l7proto_str(l7proto), dp->hostlist_auto_filename);
if (!StrPoolAddStr(&dp->hostlist, hostname))
{
fprintf(stderr, "StrPoolAddStr out of memory\n");
DLOG_ERR("StrPoolAddStr out of memory\n");
return;
}
if (!append_to_list_file(dp->hostlist_auto_filename, hostname))
@@ -359,17 +378,22 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
else
{
DLOG("auto hostlist (profile %d) : NOT adding %s\n", dp->n, hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : NOT adding, duplicate detected", hostname, dp->n);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : NOT adding, duplicate detected", hostname, dp->n, client_ip_port, l7proto_str(l7proto));
}
}
}
static void process_retrans_fail(t_ctrack *ctrack, uint8_t proto)
static void process_retrans_fail(t_ctrack *ctrack, uint8_t proto, const struct sockaddr *client)
{
if (ctrack && ctrack->dp && ctrack->hostname && auto_hostlist_retrans(ctrack, proto, ctrack->dp->hostlist_auto_retrans_threshold))
char client_ip_port[48];
if (*params.hostlist_auto_debuglog)
ntop46_port((struct sockaddr*)client,client_ip_port,sizeof(client_ip_port));
else
*client_ip_port=0;
if (ctrack && ctrack->dp && ctrack->hostname && auto_hostlist_retrans(ctrack, proto, ctrack->dp->hostlist_auto_retrans_threshold, client_ip_port, ctrack->l7proto))
{
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : tcp retrans threshold reached", ctrack->hostname, ctrack->dp->n);
auto_hostlist_failed(ctrack->dp, ctrack->hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : retrans threshold reached", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(ctrack->l7proto));
auto_hostlist_failed(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
}
}
@@ -575,6 +599,21 @@ static size_t pos_normalize(size_t split_pos, size_t reasm_offset, size_t len_pa
return split_pos;
}
static void autottl_discover(t_ctrack *ctrack, bool bIpv6)
{
if (ctrack && ctrack->incoming_ttl)
{
autottl *attl = bIpv6 ? &ctrack->dp->desync_autottl6 : &ctrack->dp->desync_autottl;
if (AUTOTTL_ENABLED(*attl))
{
ctrack->autottl = autottl_guess(ctrack->incoming_ttl, attl);
if (ctrack->autottl)
DLOG("autottl: guessed %u\n",ctrack->autottl);
else
DLOG("autottl: could not guess\n");
}
}
}
static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, size_t transport_len, uint8_t *data_payload, size_t len_payload)
{
@@ -593,10 +632,10 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
size_t pkt1_len, pkt2_len;
uint8_t ttl_orig,ttl_fake,flags_orig,scale_factor;
uint32_t *timestamps;
t_l7proto l7proto = UNKNOWN;
ttl_orig = ip ? ip->ip_ttl : ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_hlim;
uint32_t desync_fwmark = fwmark | params.desync_fwmark;
extract_endpoints(ip, ip6hdr, tcphdr, NULL, &src, &dst);
if (replay)
{
@@ -611,10 +650,9 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
DLOG("using cached desync profile %d\n",dp->n);
else if (!ctrack_replay->dp_search_complete)
{
dp = ctrack_replay->dp = dp_find(&params.desync_profiles, !!ip6hdr, ntohs(bReverse ? tcphdr->th_sport : tcphdr->th_dport), 0, ctrack_replay->hostname, NULL, NULL, NULL);
dp = ctrack_replay->dp = dp_find(&params.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, ctrack_replay->hostname, ctrack_replay->l7proto, NULL, NULL, NULL);
ctrack_replay->dp_search_complete = true;
}
if (!dp)
{
DLOG("matching desync profile not found\n");
@@ -635,7 +673,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
DLOG("using cached desync profile %d\n",dp->n);
else if (!ctrack || !ctrack->dp_search_complete)
{
dp = dp_find(&params.desync_profiles, !!ip6hdr, ntohs(bReverse ? tcphdr->th_sport : tcphdr->th_dport), 0, ctrack ? ctrack->hostname : NULL, NULL, NULL, NULL);
dp = dp_find(&params.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, ctrack ? ctrack->hostname : NULL, ctrack ? ctrack->l7proto : UNKNOWN, NULL, NULL, NULL);
if (ctrack)
{
ctrack->dp = dp;
@@ -661,17 +699,14 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (bReverse)
{
if (ctrack && !ctrack->autottl && ctrack->pcounter_reply==1)
if (ctrack)
{
autottl *attl = ip ? &dp->desync_autottl : &dp->desync_autottl6;
if (AUTOTTL_ENABLED(*attl))
if (!ctrack->incoming_ttl)
{
ctrack->autottl = autottl_guess(ttl_orig, attl);
if (ctrack->autottl)
DLOG("autottl: guessed %u\n",ctrack->autottl);
else
DLOG("autottl: could not guess\n");
DLOG("incoming TTL %u\n",ttl_orig);
ctrack->incoming_ttl = ttl_orig;
}
if (!ctrack->autottl) autottl_discover(ctrack,!!ip6hdr);
}
// process reply packets for auto hostlist mode
@@ -680,10 +715,17 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (ctrack && ctrack->hostname && ctrack->hostname_ah_check && (ctrack->ack_last-ctrack->ack0)==1)
{
bool bFail=false;
char client_ip_port[48];
if (*params.hostlist_auto_debuglog)
ntop46_port((struct sockaddr*)&dst,client_ip_port,sizeof(client_ip_port));
else
*client_ip_port=0;
if (tcphdr->th_flags & TH_RST)
{
DLOG("incoming RST detected for hostname %s\n", ctrack->hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : incoming RST", ctrack->hostname, ctrack->dp->n);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : incoming RST", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(ctrack->l7proto));
bFail = true;
}
else if (len_payload && ctrack->l7proto==HTTP)
@@ -695,7 +737,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (bFail)
{
DLOG("redirect to another domain detected. possibly DPI redirect.\n");
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : redirect to another domain", ctrack->hostname, ctrack->dp->n);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : redirect to another domain", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(ctrack->l7proto));
}
else
DLOG("local or in-domain redirect detected. it's not a DPI redirect.\n");
@@ -707,10 +749,10 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
}
}
if (bFail)
auto_hostlist_failed(dp, ctrack->hostname);
auto_hostlist_failed(dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
else
if (len_payload)
auto_hostlist_reset_fail_counter(dp, ctrack->hostname);
auto_hostlist_reset_fail_counter(dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
if (tcphdr->th_flags & TH_RST)
ConntrackClearHostname(ctrack); // do not react to further dup RSTs
}
@@ -744,10 +786,12 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
flags_orig = *((uint8_t*)tcphdr+13);
scale_factor = tcp_find_scale_factor(tcphdr);
timestamps = tcp_find_timestamps(tcphdr);
extract_endpoints(ip, ip6hdr, tcphdr, NULL, &src, &dst);
if (!replay)
{
// start and cutoff limiters
if (!process_desync_interval(dp, ctrack)) return verdict;
if (tcp_syn_segment(tcphdr))
{
switch (dp->desync_mode0)
@@ -797,8 +841,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
return verdict;
}
// start and cutoff limiters
if (!process_desync_interval(dp, ctrack)) return verdict;
} // !replay
if (!(tcphdr->th_flags & TH_SYN) && len_payload)
@@ -811,6 +853,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
const uint8_t *rdata_payload = data_payload;
size_t rlen_payload = len_payload;
size_t split_pos;
t_l7proto l7proto = UNKNOWN;
if (replay)
{
@@ -823,13 +866,13 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
rlen_payload = ctrack->reasm_orig.size_present;
}
process_retrans_fail(ctrack, IPPROTO_TCP);
process_retrans_fail(ctrack, IPPROTO_TCP, (struct sockaddr*)&src);
if (IsHttp(rdata_payload,rlen_payload))
{
DLOG("packet contains HTTP request\n");
l7proto = HTTP;
if (ctrack && !ctrack->l7proto) ctrack->l7proto = l7proto;
if (ctrack && ctrack->l7proto==UNKNOWN) ctrack->l7proto = l7proto;
// we do not reassemble http
reasm_orig_cancel(ctrack);
@@ -874,7 +917,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
reasm_orig_cancel(ctrack);
return verdict;
}
}
if (!ctrack->req_seq_finalized)
{
@@ -901,7 +943,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
}
else
{
fprintf(stderr, "rawpacket_queue failed !'\n");
DLOG_ERR("rawpacket_queue failed !\n");
reasm_orig_cancel(ctrack);
return verdict;
}
@@ -929,70 +971,97 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (dseq>=0x1000000 && !(dseq & 0x80000000)) ctrack->req_seq_abandoned=true;
}
if (bHaveHost)
if (bHaveHost) DLOG("hostname: %s\n",host);
bool bDiscoveredL7;
if (ctrack_replay)
{
bool bCheckDone=false, bCheckResult=false, bCheckExcluded=false;
DLOG("hostname: %s\n",host);
bDiscoveredL7 = !ctrack_replay->l7proto_discovered && ctrack_replay->l7proto!=UNKNOWN;
ctrack_replay->l7proto_discovered=true;
}
else
bDiscoveredL7 = !ctrack_replay && l7proto!=UNKNOWN;
if (bDiscoveredL7) DLOG("discovered l7 protocol\n");
bool bDiscoveredHostname = bHaveHost && !(ctrack_replay && ctrack_replay->hostname);
if (bDiscoveredHostname)
{
DLOG("discovered hostname\n");
if (ctrack_replay)
{
ctrack_replay->hostname=strdup(host);
if (!ctrack_replay->hostname)
{
ctrack_replay->hostname=strdup(host);
if (!ctrack_replay->hostname)
{
DLOG_ERR("hostname dup : out of memory");
reasm_orig_cancel(ctrack);
return verdict;
}
DLOG("we have hostname now. searching desync profile again.\n");
struct desync_profile *dp_prev = dp;
dp = ctrack_replay->dp = dp_find(&params.desync_profiles, !!ip6hdr, ntohs(bReverse ? tcphdr->th_sport : tcphdr->th_dport), 0, ctrack_replay->hostname, &ctrack_replay->bCheckDone, &ctrack_replay->bCheckResult, &ctrack_replay->bCheckExcluded);
ctrack_replay->dp_search_complete = true;
if (!dp)
{
reasm_orig_cancel(ctrack);
return verdict;
}
if (dp!=dp_prev)
{
DLOG("desync profile changed by revealed hostname !\n");
// re-evaluate start/cutoff limiters
if (!replay)
{
maybe_cutoff(ctrack, IPPROTO_TCP);
if (!process_desync_interval(dp, ctrack))
{
reasm_orig_cancel(ctrack);
return verdict;
}
}
}
}
bCheckDone = ctrack_replay->bCheckDone;
bCheckResult = ctrack_replay->bCheckResult;
bCheckExcluded = ctrack_replay->bCheckExcluded;
}
if (dp->hostlist || dp->hostlist_exclude)
{
if (!bCheckDone)
bCheckResult = HostlistCheck(dp, host, &bCheckExcluded);
if (bCheckResult)
ctrack_stop_retrans_counter(ctrack_replay);
else
{
if (ctrack_replay)
{
ctrack_replay->hostname_ah_check = *dp->hostlist_auto_filename && !bCheckExcluded;
if (!ctrack_replay->hostname_ah_check)
ctrack_stop_retrans_counter(ctrack_replay);
}
DLOG("not applying tampering to this request\n");
DLOG_ERR("hostname dup : out of memory");
reasm_orig_cancel(ctrack);
return verdict;
}
}
}
bool bCheckDone=false, bCheckResult=false, bCheckExcluded=false;
if (bDiscoveredL7 || bDiscoveredHostname)
{
struct desync_profile *dp_prev = dp;
dp = dp_find(&params.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, ctrack_replay ? ctrack_replay->hostname : host, ctrack_replay ? ctrack_replay->l7proto : l7proto, &bCheckDone, &bCheckResult, &bCheckExcluded);
if (ctrack_replay)
{
ctrack_replay->dp = dp;
ctrack_replay->dp_search_complete = true;
ctrack_replay->bCheckDone = bCheckDone;
ctrack_replay->bCheckResult = bCheckResult;
ctrack_replay->bCheckExcluded = bCheckExcluded;
}
if (!dp)
{
reasm_orig_cancel(ctrack);
return verdict;
}
if (dp!=dp_prev)
{
DLOG("desync profile changed by revealed l7 protocol or hostname !\n");
// rediscover autottl
autottl_discover(ctrack_replay,!!ip6hdr);
// re-evaluate start/cutoff limiters
if (!replay)
{
maybe_cutoff(ctrack, IPPROTO_TCP);
if (!process_desync_interval(dp, ctrack))
{
reasm_orig_cancel(ctrack);
return verdict;
}
}
}
}
else if (ctrack_replay)
{
bCheckDone = ctrack_replay->bCheckDone;
bCheckResult = ctrack_replay->bCheckResult;
bCheckExcluded = ctrack_replay->bCheckExcluded;
}
if (bHaveHost && (dp->hostlist || dp->hostlist_exclude))
{
if (!bCheckDone)
bCheckResult = HostlistCheck(dp, host, &bCheckExcluded);
if (bCheckResult)
ctrack_stop_retrans_counter(ctrack_replay);
else
{
if (ctrack_replay)
{
ctrack_replay->hostname_ah_check = *dp->hostlist_auto_filename && !bCheckExcluded;
if (!ctrack_replay->hostname_ah_check)
ctrack_stop_retrans_counter(ctrack_replay);
}
DLOG("not applying tampering to this request\n");
reasm_orig_cancel(ctrack);
return verdict;
}
}
// desync profile may have changed after hostname was revealed
switch(l7proto)
{
@@ -1019,24 +1088,28 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (l7proto==UNKNOWN)
{
if (!dp->desync_any_proto) return verdict;
if (!dp->desync_any_proto)
{
DLOG("not applying tampering to unknown protocol\n");
return verdict;
}
DLOG("applying tampering to unknown protocol\n");
}
ttl_fake = (ctrack_replay && ctrack_replay->autottl) ? ctrack_replay->autottl : (ip6hdr ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig));
if ((l7proto == HTTP) && (dp->hostcase || dp->hostnospace || dp->domcase) && (phost = (uint8_t*)memmem(data_payload, len_payload, "\r\nHost: ", 8)))
if ((l7proto == HTTP) && (dp->hostcase || dp->hostnospace || dp->domcase) && HttpFindHost(&phost,data_payload,len_payload))
{
if (dp->hostcase)
{
DLOG("modifying Host: => %c%c%c%c:\n", dp->hostspell[0], dp->hostspell[1], dp->hostspell[2], dp->hostspell[3]);
memcpy(phost + 2, dp->hostspell, 4);
memcpy(phost, dp->hostspell, 4);
verdict=VERDICT_MODIFY;
}
if (dp->domcase)
{
DLOG("mixing domain case\n");
for (p = phost+7; p < (data_payload + len_payload) && *p != '\r' && *p != '\n'; p++)
for (p = phost+5; p < (data_payload + len_payload) && *p != '\r' && *p != '\n'; p++)
*p = (((size_t)p) & 1) ? tolower(*p) : toupper(*p);
verdict=VERDICT_MODIFY;
}
@@ -1048,12 +1121,12 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
DLOG("removing space after Host: and adding it to User-Agent:\n");
if (pua > phost)
{
memmove(phost + 7, phost + 8, pua - phost - 8);
phost[pua - phost - 1] = ' ';
memmove(phost + 5, phost + 6, pua - phost - 6);
pua[-1]=' ';
}
else
{
memmove(pua + 1, pua, phost - pua + 7);
memmove(pua + 1, pua, phost - pua + 5);
*pua = ' ';
}
verdict=VERDICT_MODIFY;
@@ -1404,6 +1477,9 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
uint8_t ttl_orig,ttl_fake;
t_l7proto l7proto = UNKNOWN;
ttl_orig = ip ? ip->ip_ttl : ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_hlim;
extract_endpoints(ip, ip6hdr, NULL, udphdr, &src, &dst);
if (replay)
{
// in replay mode conntrack_replay is not NULL and ctrack is NULL
@@ -1417,7 +1493,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
DLOG("using cached desync profile %d\n",dp->n);
else if (!ctrack_replay->dp_search_complete)
{
dp = ctrack_replay->dp = dp_find(&params.desync_profiles, !!ip6hdr, 0, ntohs(bReverse ? udphdr->uh_sport : udphdr->uh_dport), ctrack_replay->hostname, NULL, NULL, NULL);
dp = ctrack_replay->dp = dp_find(&params.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, ctrack_replay->hostname, ctrack_replay->l7proto, NULL, NULL, NULL);
ctrack_replay->dp_search_complete = true;
}
if (!dp)
@@ -1440,7 +1516,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
DLOG("using cached desync profile %d\n",dp->n);
else if (!ctrack || !ctrack->dp_search_complete)
{
dp = dp_find(&params.desync_profiles, !!ip6hdr, 0, ntohs(bReverse ? udphdr->uh_sport : udphdr->uh_dport), ctrack ? ctrack->hostname : NULL, NULL, NULL, NULL);
dp = dp_find(&params.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, ctrack ? ctrack->hostname : NULL, ctrack ? ctrack->l7proto : UNKNOWN, NULL, NULL, NULL);
if (ctrack)
{
ctrack->dp = dp;
@@ -1458,15 +1534,21 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
//ConntrackPoolDump(&params.conntrack);
}
if (bReverse) return verdict; // nothing to do. do not waste cpu
if (bReverse && ctrack)
{
if (!ctrack->incoming_ttl)
{
DLOG("incoming TTL %u\n",ttl_orig);
ctrack->incoming_ttl = ttl_orig;
}
if (!ctrack->autottl) autottl_discover(ctrack,!!ip6hdr);
return verdict; // nothing to do. do not waste cpu
}
// start and cutoff limiters
if (!replay && !process_desync_interval(dp, ctrack)) return verdict;
uint32_t desync_fwmark = fwmark | params.desync_fwmark;
ttl_orig = ip ? ip->ip_ttl : ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_hlim;
ttl_fake = ip6hdr ? dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig : dp->desync_ttl ? dp->desync_ttl : ttl_orig;
extract_endpoints(ip, ip6hdr, NULL, udphdr, &src, &dst);
if (len_payload)
{
@@ -1480,7 +1562,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
{
DLOG("packet contains QUIC initial\n");
l7proto = QUIC;
if (ctrack && !ctrack->l7proto) ctrack->l7proto = l7proto;
if (ctrack && ctrack->l7proto==UNKNOWN) ctrack->l7proto = l7proto;
uint8_t clean[16384], *pclean;
size_t clean_len;
@@ -1542,7 +1624,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
}
else
{
fprintf(stderr, "rawpacket_queue failed !'\n");
DLOG_ERR("rawpacket_queue failed !\n");
reasm_orig_cancel(ctrack);
return verdict;
}
@@ -1593,80 +1675,114 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
{
DLOG("packet contains wireguard handshake initiation\n");
l7proto = WIREGUARD;
if (ctrack && !ctrack->l7proto) ctrack->l7proto = l7proto;
if (ctrack && ctrack->l7proto==UNKNOWN) ctrack->l7proto = l7proto;
}
else if (IsDhtD1(data_payload,len_payload))
{
DLOG("packet contains DHT d1...e\n");
l7proto = DHT;
if (ctrack && !ctrack->l7proto) ctrack->l7proto = l7proto;
if (ctrack && ctrack->l7proto==UNKNOWN) ctrack->l7proto = l7proto;
}
else
{
if (!dp->desync_any_proto) return verdict;
if (!dp->desync_any_proto)
{
DLOG("not applying tampering to unknown protocol\n");
return verdict;
}
DLOG("applying tampering to unknown protocol\n");
}
}
if (bHaveHost)
if (bHaveHost) DLOG("hostname: %s\n",host);
bool bDiscoveredL7;
if (ctrack_replay)
{
bool bCheckDone=false, bCheckResult=false, bCheckExcluded=false;
DLOG("hostname: %s\n",host);
bDiscoveredL7 = !ctrack_replay->l7proto_discovered && ctrack_replay->l7proto!=UNKNOWN;
ctrack_replay->l7proto_discovered=true;
}
else
bDiscoveredL7 = !ctrack_replay && l7proto!=UNKNOWN;
if (bDiscoveredL7) DLOG("discovered l7 protocol\n");
bool bDiscoveredHostname = bHaveHost && !(ctrack_replay && ctrack_replay->hostname);
if (bDiscoveredHostname)
{
DLOG("discovered hostname\n");
if (ctrack_replay)
{
ctrack_replay->hostname=strdup(host);
if (!ctrack_replay->hostname)
{
ctrack_replay->hostname=strdup(host);
if (!ctrack_replay->hostname)
{
DLOG_ERR("hostname dup : out of memory");
return verdict;
}
DLOG("we have hostname now. searching desync profile again.\n");
struct desync_profile *dp_prev = dp;
dp = ctrack_replay->dp = dp_find(&params.desync_profiles, !!ip6hdr, 0, ntohs(bReverse ? udphdr->uh_sport : udphdr->uh_dport), ctrack_replay->hostname, &ctrack_replay->bCheckDone, &ctrack_replay->bCheckResult, &ctrack_replay->bCheckExcluded);
ctrack_replay->dp_search_complete = true;
if (!dp) return verdict;
if (dp!=dp_prev)
{
DLOG("desync profile changed by reavealed hostname !\n");
// re-evaluate start/cutoff limiters
if (!replay)
{
maybe_cutoff(ctrack, IPPROTO_UDP);
if (!process_desync_interval(dp, ctrack)) return verdict;
}
}
}
bCheckDone = ctrack_replay->bCheckDone;
bCheckResult = ctrack_replay->bCheckResult;
bCheckExcluded = ctrack_replay->bCheckExcluded;
}
if (dp->hostlist || dp->hostlist_exclude)
{
bool bCheckExcluded;
if (!bCheckDone)
bCheckResult = HostlistCheck(dp, host, &bCheckExcluded);
if (!bCheckResult)
{
if (ctrack_replay)
{
ctrack_replay->hostname_ah_check = *dp->hostlist_auto_filename && !bCheckExcluded;
if (ctrack_replay->hostname_ah_check)
{
// first request is not retrans
if (ctrack_replay->hostname)
process_retrans_fail(ctrack_replay, IPPROTO_UDP);
else
ctrack_replay->hostname=strdup(host);
}
}
DLOG("not applying tampering to this request\n");
DLOG_ERR("hostname dup : out of memory");
return verdict;
}
}
}
bool bCheckDone=false, bCheckResult=false, bCheckExcluded=false;
if (bDiscoveredL7 || bDiscoveredHostname)
{
struct desync_profile *dp_prev = dp;
dp = dp_find(&params.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, ctrack_replay ? ctrack_replay->hostname : host, ctrack_replay ? ctrack_replay->l7proto : l7proto, &bCheckDone, &bCheckResult, &bCheckExcluded);
if (ctrack_replay)
{
ctrack_replay->dp = dp;
ctrack_replay->dp_search_complete = true;
ctrack_replay->bCheckDone = bCheckDone;
ctrack_replay->bCheckResult = bCheckResult;
ctrack_replay->bCheckExcluded = bCheckExcluded;
}
if (!dp)
{
reasm_orig_cancel(ctrack);
return verdict;
}
if (dp!=dp_prev)
{
DLOG("desync profile changed by revealed l7 protocol or hostname !\n");
// rediscover autottl
autottl_discover(ctrack_replay,!!ip6hdr);
// re-evaluate start/cutoff limiters
if (!replay)
{
maybe_cutoff(ctrack, IPPROTO_UDP);
if (!process_desync_interval(dp, ctrack)) return verdict;
}
}
}
else if (ctrack_replay)
{
bCheckDone = ctrack_replay->bCheckDone;
bCheckResult = ctrack_replay->bCheckResult;
bCheckExcluded = ctrack_replay->bCheckExcluded;
}
if (bHaveHost && (dp->hostlist || dp->hostlist_exclude))
{
if (!bCheckDone)
bCheckResult = HostlistCheck(dp, host, &bCheckExcluded);
if (bCheckResult)
ctrack_stop_retrans_counter(ctrack_replay);
else
{
if (ctrack_replay)
{
ctrack_replay->hostname_ah_check = *dp->hostlist_auto_filename && !bCheckExcluded;
if (ctrack_replay->hostname_ah_check)
{
// first request is not retrans
if (!bDiscoveredHostname)
process_retrans_fail(ctrack_replay, IPPROTO_UDP, (struct sockaddr*)&src);
}
}
DLOG("not applying tampering to this request\n");
return verdict;
}
}
// desync profile may have changed after hostname was revealed
switch(l7proto)
{
@@ -1687,7 +1803,8 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
fake_size = dp->fake_unknown_udp_size;
break;
}
ttl_fake = ip6hdr ? dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig : dp->desync_ttl ? dp->desync_ttl : ttl_orig;
ttl_fake = (ctrack_replay && ctrack_replay->autottl) ? ctrack_replay->autottl : (ip6hdr ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig));
enum dpi_desync_mode desync_mode = dp->desync_mode;
uint32_t fooling_orig = FOOL_NONE;

View File

@@ -11,6 +11,12 @@
#include "params.h"
void rtrim(char *s)
{
if (s)
for (char *p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r'); p--) *p = '\0';
}
void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit)
{
size_t k;
@@ -181,6 +187,11 @@ bool pton6_port(const char *s, struct sockaddr_in6 *sa)
return true;
}
uint16_t saport(const struct sockaddr *sa)
{
return htons(sa->sa_family==AF_INET ? ((struct sockaddr_in*)sa)->sin_port :
sa->sa_family==AF_INET6 ? ((struct sockaddr_in6*)sa)->sin6_port : 0);
}
void dbgprint_socket_buffers(int fd)
{
@@ -385,3 +396,99 @@ bool cd_to_exe_dir(const char *argv0)
}
return bOK;
}
static void mask_from_preflen6_make(uint8_t plen, struct in6_addr *a)
{
if (plen >= 128)
memset(a->s6_addr,0xFF,16);
else
{
uint8_t n = plen >> 3;
memset(a->s6_addr,0xFF,n);
memset(a->s6_addr+n,0x00,16-n);
a->s6_addr[n] = (uint8_t)(0xFF00 >> (plen & 7));
}
}
struct in6_addr ip6_mask[129];
void mask_from_preflen6_prepare(void)
{
for (int plen=0;plen<=128;plen++) mask_from_preflen6_make(plen, ip6_mask+plen);
}
#if defined(__GNUC__) && !defined(__llvm__)
__attribute__((optimize ("no-strict-aliasing")))
#endif
void ip6_and(const struct in6_addr * restrict a, const struct in6_addr * restrict b, struct in6_addr * restrict result)
{
// int128 requires 16-bit alignment. in struct sockaddr_in6.sin6_addr is 8-byte aligned.
// it causes segfault on x64 arch with latest compiler. it can cause misalign slowdown on other archs
// use 64-bit AND
((uint64_t*)result->s6_addr)[0] = ((uint64_t*)a->s6_addr)[0] & ((uint64_t*)b->s6_addr)[0];
((uint64_t*)result->s6_addr)[1] = ((uint64_t*)a->s6_addr)[1] & ((uint64_t*)b->s6_addr)[1];
}
void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr)
{
char s_ip[16];
*s_ip=0;
inet_ntop(AF_INET, &cidr->addr, s_ip, sizeof(s_ip));
snprintf(s,s_len,cidr->preflen<32 ? "%s/%u" : "%s", s_ip, cidr->preflen);
}
void print_cidr4(const struct cidr4 *cidr)
{
char s[19];
str_cidr4(s,sizeof(s),cidr);
printf("%s",s);
}
void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr)
{
char s_ip[40];
*s_ip=0;
inet_ntop(AF_INET6, &cidr->addr, s_ip, sizeof(s_ip));
snprintf(s,s_len,cidr->preflen<128 ? "%s/%u" : "%s", s_ip, cidr->preflen);
}
void print_cidr6(const struct cidr6 *cidr)
{
char s[44];
str_cidr6(s,sizeof(s),cidr);
printf("%s",s);
}
bool parse_cidr4(char *s, struct cidr4 *cidr)
{
char *p,d;
bool b;
unsigned int plen;
if ((p = strchr(s, '/')))
{
if (sscanf(p + 1, "%u", &plen)!=1 || plen>32)
return false;
cidr->preflen = (uint8_t)plen;
d=*p; *p=0; // backup char
}
else
cidr->preflen = 32;
b = (inet_pton(AF_INET, s, &cidr->addr)==1);
if (p) *p=d; // restore char
return b;
}
bool parse_cidr6(char *s, struct cidr6 *cidr)
{
char *p,d;
bool b;
unsigned int plen;
if ((p = strchr(s, '/')))
{
if (sscanf(p + 1, "%u", &plen)!=1 || plen>128)
return false;
cidr->preflen = (uint8_t)plen;
d=*p; *p=0; // backup char
}
else
cidr->preflen = 128;
b = (inet_pton(AF_INET6, s, &cidr->addr)==1);
if (p) *p=d; // restore char
return b;
}

View File

@@ -9,6 +9,16 @@
#include <stdio.h>
#include <time.h>
// this saves memory. sockaddr_storage is larger than required. it can be 128 bytes. sockaddr_in6 is 28 bytes.
typedef union
{
struct sockaddr_in sa4; // size 16
struct sockaddr_in6 sa6; // size 28
char _align[32]; // force 16-byte alignment for ip6_and int128 ops
} sockaddr_in46;
void rtrim(char *s);
void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit);
char *strncasestr(const char *s,const char *find, size_t slen);
bool load_file(const char *filename,void *buffer,size_t *buffer_size);
@@ -22,6 +32,8 @@ void ntop46_port(const struct sockaddr *sa, char *str, size_t len);
bool pton4_port(const char *s, struct sockaddr_in *sa);
bool pton6_port(const char *s, struct sockaddr_in6 *sa);
uint16_t saport(const struct sockaddr *sa);
bool seq_within(uint32_t s, uint32_t s1, uint32_t s2);
void dbgprint_socket_buffers(int fd);
@@ -64,3 +76,33 @@ void fill_random_az(uint8_t *p,size_t sz);
void fill_random_az09(uint8_t *p,size_t sz);
bool cd_to_exe_dir(const char *argv0);
struct cidr4
{
struct in_addr addr;
uint8_t preflen;
};
struct cidr6
{
struct in6_addr addr;
uint8_t preflen;
};
void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr);
void print_cidr4(const struct cidr4 *cidr);
void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr);
void print_cidr6(const struct cidr6 *cidr);
bool parse_cidr4(char *s, struct cidr4 *cidr);
bool parse_cidr6(char *s, struct cidr6 *cidr);
static inline uint32_t mask_from_preflen(uint32_t preflen)
{
return preflen ? preflen<32 ? ~((1 << (32-preflen)) - 1) : 0xFFFFFFFF : 0;
}
void ip6_and(const struct in6_addr * restrict a, const struct in6_addr * restrict b, struct in6_addr * restrict result);
extern struct in6_addr ip6_mask[129];
void mask_from_preflen6_prepare(void);
static inline const struct in6_addr *mask_from_preflen6(uint8_t preflen)
{
return ip6_mask+preflen;
}

View File

@@ -4,17 +4,27 @@
#include "helpers.h"
// inplace tolower() and add to pool
static bool addpool(strpool **hostlist, char **s, const char *end)
static bool addpool(strpool **hostlist, char **s, const char *end, int *ct)
{
char *p;
char *p=*s;
// advance until eol lowering all chars
for (p = *s; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
if (!StrPoolAddStrLen(hostlist, *s, p-*s))
// comment line
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\r' || *p == '\n')
{
StrPoolDestroy(hostlist);
*hostlist = NULL;
return false;
// advance until eol
for (; p<end && *p && *p!='\r' && *p != '\n'; p++);
}
else
{
// advance until eol lowering all chars
for (; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
if (!StrPoolAddStrLen(hostlist, *s, p-*s))
{
StrPoolDestroy(hostlist);
*hostlist = NULL;
return false;
}
(*ct)++;
}
// advance to the next line
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
@@ -22,7 +32,7 @@ static bool addpool(strpool **hostlist, char **s, const char *end)
return true;
}
bool AppendHostList(strpool **hostlist, char *filename)
bool AppendHostList(strpool **hostlist, const char *filename)
{
char *p, *e, s[256], *zbuf;
size_t zsize;
@@ -50,14 +60,12 @@ bool AppendHostList(strpool **hostlist, char *filename)
e = zbuf + zsize;
while(p<e)
{
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue;
if (!addpool(hostlist,&p,e))
if (!addpool(hostlist,&p,e,&ct))
{
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
free(zbuf);
return false;
}
ct++;
}
free(zbuf);
}
@@ -71,17 +79,15 @@ bool AppendHostList(strpool **hostlist, char *filename)
{
DLOG_CONDUP("loading plain text list\n");
while (fgets(s, 256, F))
while (fgets(s, sizeof(s), F))
{
p = s;
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue;
if (!addpool(hostlist,&p,p+strlen(p)))
if (!addpool(hostlist,&p,p+strlen(p),&ct))
{
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
fclose(F);
return false;
}
ct++;
}
fclose(F);
}
@@ -168,7 +174,7 @@ static bool LoadIncludeHostListsForProfile(struct desync_profile *dp)
// return : true = apply fooling, false = do not apply
bool HostlistCheck(struct desync_profile *dp, const char *host, bool *excluded)
{
DLOG("* Hostlist check for profile %d\n",dp->n);
DLOG("* hostlist check for profile %d\n",dp->n);
if (*dp->hostlist_auto_filename)
{
time_t t = file_mod_time(dp->hostlist_auto_filename);

View File

@@ -4,7 +4,7 @@
#include "pools.h"
#include "params.h"
bool AppendHostList(strpool **hostlist, char *filename);
bool AppendHostList(strpool **hostlist, const char *filename);
bool LoadHostLists(strpool **hostlist, struct str_list_head *file_list);
bool LoadIncludeHostLists();
bool LoadExcludeHostLists();

195
nfq/ipset.c Normal file
View File

@@ -0,0 +1,195 @@
#include <stdio.h>
#include "ipset.h"
#include "gzip.h"
#include "helpers.h"
// inplace tolower() and add to pool
static bool addpool(ipset *ips, char **s, const char *end, int *ct)
{
char *p, cidr[128];
size_t l;
struct cidr4 c4;
struct cidr6 c6;
// advance until eol
for (p=*s; p<end && *p && *p!='\r' && *p != '\n'; p++);
// comment line
if (!(**s == '#' || **s == ';' || **s == '/' || **s == '\r' || **s == '\n' ))
{
l = p-*s;
if (l>=sizeof(cidr)) l=sizeof(cidr)-1;
memcpy(cidr,*s,l);
cidr[l]=0;
rtrim(cidr);
if (parse_cidr4(cidr,&c4))
{
if (!ipset4AddCidr(&ips->ips4, &c4))
{
ipsetDestroy(ips);
return false;
}
(*ct)++;
}
else if (parse_cidr6(cidr,&c6))
{
if (!ipset6AddCidr(&ips->ips6, &c6))
{
ipsetDestroy(ips);
return false;
}
(*ct)++;
}
else
DLOG_ERR("bad ip or subnet : %s\n",cidr);
}
// advance to the next line
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
*s = p;
return true;
}
static bool AppendIpset(ipset *ips, const char *filename)
{
char *p, *e, s[256], *zbuf;
size_t zsize;
int ct = 0;
FILE *F;
int r;
DLOG_CONDUP("Loading ipset %s\n",filename);
if (!(F = fopen(filename, "rb")))
{
DLOG_ERR("Could not open %s\n", filename);
return false;
}
if (is_gzip(F))
{
r = z_readfile(F,&zbuf,&zsize);
fclose(F);
if (r==Z_OK)
{
DLOG_CONDUP("zlib compression detected. uncompressed size : %zu\n", zsize);
p = zbuf;
e = zbuf + zsize;
while(p<e)
{
if (!addpool(ips,&p,e,&ct))
{
DLOG_ERR("Not enough memory to store ipset : %s\n", filename);
free(zbuf);
return false;
}
}
free(zbuf);
}
else
{
DLOG_ERR("zlib decompression failed : result %d\n",r);
return false;
}
}
else
{
DLOG_CONDUP("loading plain text list\n");
while (fgets(s, sizeof(s)-1, F))
{
p = s;
if (!addpool(ips,&p,p+strlen(p),&ct))
{
DLOG_ERR("Not enough memory to store ipset : %s\n", filename);
fclose(F);
return false;
}
}
fclose(F);
}
DLOG_CONDUP("Loaded %d ip/subnets from %s\n", ct, filename);
return true;
}
static bool LoadIpsets(ipset *ips, struct str_list_head *file_list)
{
struct str_list *file;
ipsetDestroy(ips);
LIST_FOREACH(file, file_list, next)
{
if (!AppendIpset(ips, file->str)) return false;
}
return true;
}
bool LoadIncludeIpsets()
{
struct desync_profile_list *dpl;
LIST_FOREACH(dpl, &params.desync_profiles, next)
if (!LoadIpsets(&dpl->dp.ips, &dpl->dp.ipset_files))
return false;
return true;
}
bool LoadExcludeIpsets()
{
struct desync_profile_list *dpl;
LIST_FOREACH(dpl, &params.desync_profiles, next)
if (!LoadIpsets(&dpl->dp.ips_exclude, &dpl->dp.ipset_exclude_files))
return false;
return true;
}
bool SearchIpset(const ipset *ips, const struct in_addr *ipv4, const struct in6_addr *ipv6)
{
char s_ip[40];
bool bInSet=false;
if (!!ipv4 != !!ipv6)
{
*s_ip=0;
if (ipv4)
{
if (params.debug) inet_ntop(AF_INET, ipv4, s_ip, sizeof(s_ip));
if (ips->ips4) bInSet = ipset4Check(ips->ips4, ipv4, 32);
}
if (ipv6)
{
if (params.debug) inet_ntop(AF_INET6, ipv6, s_ip, sizeof(s_ip));
if (ips->ips6) bInSet = ipset6Check(ips->ips6, ipv6, 128);
}
DLOG("ipset check for %s : %s\n", s_ip, bInSet ? "positive" : "negative");
}
else
// ipv4 and ipv6 are both empty or non-empty
DLOG("ipset check error !!!!!!!! ipv4=%p ipv6=%p\n",ipv4,ipv6);
return bInSet;
}
static bool IpsetCheck_(const ipset *ips, const ipset *ips_exclude, const struct in_addr *ipv4, const struct in6_addr *ipv6)
{
if (!IPSET_EMPTY(ips_exclude))
{
DLOG("exclude ");
if (SearchIpset(ips_exclude, ipv4, ipv6))
return false;
}
if (!IPSET_EMPTY(ips))
{
DLOG("include ");
return SearchIpset(ips, ipv4, ipv6);
}
return true;
}
bool IpsetCheck(struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6)
{
if (!PROFILE_IPSETS_EMPTY(dp)) DLOG("* ipset check for profile %d\n",dp->n);
return IpsetCheck_(&dp->ips,&dp->ips_exclude,ipv4,ipv6);
}

11
nfq/ipset.h Normal file
View File

@@ -0,0 +1,11 @@
#pragma once
#include <stdbool.h>
#include <arpa/inet.h>
#include "params.h"
#include "pools.h"
bool LoadIncludeIpsets();
bool LoadExcludeIpsets();
bool SearchIpset(const ipset *ips, const struct in_addr *ipv4, const struct in6_addr *ipv6);
bool IpsetCheck(struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6);

View File

@@ -8,6 +8,7 @@
#include "params.h"
#include "protocol.h"
#include "hostlist.h"
#include "ipset.h"
#include "gzip.h"
#include "pools.h"
@@ -54,7 +55,7 @@ static bool bHup = false;
static void onhup(int sig)
{
printf("HUP received !\n");
printf("Will reload hostlist on next request (if any)\n");
printf("Will reload hostlists and ipsets on next request (if any)\n");
bHup = true;
}
// should be called in normal execution
@@ -62,7 +63,7 @@ static void dohup(void)
{
if (bHup)
{
if (!LoadIncludeHostLists() || !LoadExcludeHostLists())
if (!LoadIncludeHostLists() || !LoadExcludeHostLists() || !LoadIncludeIpsets() || !LoadExcludeIpsets())
{
// what will we do without hostlist ?? sure, gonna die
exit(1);
@@ -490,6 +491,7 @@ static int win_main(const char *windivert_filter)
win_dark_deinit();
return w_win32_error;
}
*ifout=0;
if (wa.Outbound) snprintf(ifout,sizeof(ifout),"%u.%u", wa.Network.IfIdx, wa.Network.SubIfIdx);
DLOG("packet: id=%u len=%zu %s IPv6=%u IPChecksum=%u TCPChecksum=%u UDPChecksum=%u IfIdx=%u.%u\n", id, len, wa.Outbound ? "outbound" : "inbound", wa.IPv6, wa.IPChecksum, wa.TCPChecksum, wa.UDPChecksum, wa.Network.IfIdx, wa.Network.SubIfIdx);
@@ -505,6 +507,8 @@ static int win_main(const char *windivert_filter)
}
else
{
dohup();
mark=0;
// pseudo interface id IfIdx.SubIfIdx
verdict = processPacketData(&mark, ifout, packet, &len);
@@ -621,7 +625,7 @@ static void load_file_or_exit(const char *filename, void *buf, size_t *size)
}
}
bool parse_autottl(const char *s, autottl *t)
static bool parse_autottl(const char *s, autottl *t)
{
unsigned int delta,min,max;
AUTOTTL_SET_DEFAULT(*t);
@@ -647,6 +651,42 @@ bool parse_autottl(const char *s, autottl *t)
return true;
}
static bool parse_l7_list(char *opt, uint32_t *l7)
{
char *e,*p,c;
for (p=opt,*l7=0 ; p ; )
{
if ((e = strchr(p,',')))
{
c=*e;
*e=0;
}
if (!strcmp(p,"http"))
*l7 |= L7_PROTO_HTTP;
else if (!strcmp(p,"tls"))
*l7 |= L7_PROTO_TLS;
else if (!strcmp(p,"quic"))
*l7 |= L7_PROTO_QUIC;
else if (!strcmp(p,"wireguard"))
*l7 |= L7_PROTO_WIREGUARD;
else if (!strcmp(p,"dht"))
*l7 |= L7_PROTO_DHT;
else if (!strcmp(p,"unknown"))
*l7 |= L7_PROTO_UNKNOWN;
else return false;
if (e)
{
*e++=c;
}
p = e;
}
return true;
}
static bool wf_make_l3(char *opt, bool *ipv4, bool *ipv6)
{
char *e,*p,c;
@@ -673,6 +713,7 @@ static bool wf_make_l3(char *opt, bool *ipv4, bool *ipv6)
}
return true;
}
#ifdef __CYGWIN__
static bool wf_make_pf(char *opt, const char *l4, const char *portname, char *buf, size_t len)
{
@@ -831,6 +872,9 @@ static void exithelp(void)
" --filter-l3=ipv4|ipv6\t\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n"
" --filter-tcp=[~]port1[-port2]\t\t\t; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp.\n"
" --filter-udp=[~]port1[-port2]\t\t\t; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp.\n"
" --filter-l7=[http|tls|quic|wireguard|dht|unknown] ; L6-L7 protocol filter. multiple comma separated values allowed.\n"
" --ipset=<filename>\t\t\t\t; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n"
" --ipset-exclude=<filename>\t\t\t; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n"
"\nHOSTLIST FILTER:\n"
" --hostlist=<filename>\t\t\t\t; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n"
" --hostlist-exclude=<filename>\t\t\t; do not apply dpi desync to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n"
@@ -945,6 +989,7 @@ int main(int argc, char **argv)
#endif
srandom(time(NULL));
mask_from_preflen6_prepare();
memset(&params, 0, sizeof(params));
*pidfile = 0;
@@ -1056,19 +1101,22 @@ int main(int argc, char **argv)
{"filter-l3",required_argument,0,0}, // optidx=53
{"filter-tcp",required_argument,0,0}, // optidx=54
{"filter-udp",required_argument,0,0}, // optidx=55
{"filter-l7",required_argument,0,0}, // optidx=56
{"ipset",required_argument,0,0}, // optidx=57
{"ipset-exclude",required_argument,0,0},// optidx=58
#ifdef __linux__
{"bind-fix4",no_argument,0,0}, // optidx=56
{"bind-fix6",no_argument,0,0}, // optidx=57
{"bind-fix4",no_argument,0,0}, // optidx=59
{"bind-fix6",no_argument,0,0}, // optidx=60
#elif defined(__CYGWIN__)
{"wf-iface",required_argument,0,0}, // optidx=56
{"wf-l3",required_argument,0,0}, // optidx=57
{"wf-tcp",required_argument,0,0}, // optidx=58
{"wf-udp",required_argument,0,0}, // optidx=59
{"wf-raw",required_argument,0,0}, // optidx=60
{"wf-save",required_argument,0,0}, // optidx=61
{"ssid-filter",required_argument,0,0}, // optidx=62
{"nlm-filter",required_argument,0,0}, // optidx=63
{"nlm-list",optional_argument,0,0}, // optidx=64
{"wf-iface",required_argument,0,0}, // optidx=59
{"wf-l3",required_argument,0,0}, // optidx=60
{"wf-tcp",required_argument,0,0}, // optidx=61
{"wf-udp",required_argument,0,0}, // optidx=62
{"wf-raw",required_argument,0,0}, // optidx=63
{"wf-save",required_argument,0,0}, // optidx=64
{"ssid-filter",required_argument,0,0}, // optidx=65
{"nlm-filter",required_argument,0,0}, // optidx=66
{"nlm-list",optional_argument,0,0}, // optidx=67
#endif
{NULL,0,NULL,0}
};
@@ -1596,30 +1644,53 @@ int main(int argc, char **argv)
// deny tcp if not set
if (pf_is_empty(&dp->pf_tcp)) dp->pf_tcp.neg=true;
break;
case 56: /* filter-l7 */
if (!parse_l7_list(optarg,&dp->filter_l7))
{
DLOG_ERR("Invalid l7 filter : %s\n",optarg);
exit_clean(1);
}
break;
case 57: /* ipset */
if (!strlist_add(&dp->ipset_files, optarg))
{
DLOG_ERR("strlist_add failed\n");
exit_clean(1);
}
break;
case 58: /* ipset-exclude */
if (!strlist_add(&dp->ipset_exclude_files, optarg))
{
DLOG_ERR("strlist_add failed\n");
exit_clean(1);
}
break;
#ifdef __linux__
case 56: /* bind-fix4 */
case 59: /* bind-fix4 */
params.bind_fix4 = true;
break;
case 57: /* bind-fix6 */
case 60: /* bind-fix6 */
params.bind_fix6 = true;
break;
#elif defined(__CYGWIN__)
case 56: /* wf-iface */
case 59: /* wf-iface */
if (!sscanf(optarg,"%u.%u",&IfIdx,&SubIfIdx))
{
DLOG_ERR("bad value for --wf-iface\n");
exit_clean(1);
}
break;
case 57: /* wf-l3 */
case 60: /* wf-l3 */
if (!wf_make_l3(optarg,&wf_ipv4,&wf_ipv6))
{
DLOG_ERR("bad value for --wf-l3\n");
exit_clean(1);
}
break;
case 58: /* wf-tcp */
case 61: /* wf-tcp */
hash_wf_tcp=hash_jen(optarg,strlen(optarg));
if (!wf_make_pf(optarg,"tcp","SrcPort",wf_pf_tcp_src,sizeof(wf_pf_tcp_src)) ||
!wf_make_pf(optarg,"tcp","DstPort",wf_pf_tcp_dst,sizeof(wf_pf_tcp_dst)))
@@ -1628,7 +1699,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 59: /* wf-udp */
case 62: /* wf-udp */
hash_wf_udp=hash_jen(optarg,strlen(optarg));
if (!wf_make_pf(optarg,"udp","SrcPort",wf_pf_udp_src,sizeof(wf_pf_udp_src)) ||
!wf_make_pf(optarg,"udp","DstPort",wf_pf_udp_dst,sizeof(wf_pf_udp_dst)))
@@ -1637,7 +1708,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 60: /* wf-raw */
case 63: /* wf-raw */
hash_wf_raw=hash_jen(optarg,strlen(optarg));
if (optarg[0]=='@')
{
@@ -1651,11 +1722,11 @@ int main(int argc, char **argv)
windivert_filter[sizeof(windivert_filter) - 1] = '\0';
}
break;
case 61: /* wf-save */
case 64: /* wf-save */
strncpy(wf_save_file, optarg, sizeof(wf_save_file));
wf_save_file[sizeof(wf_save_file) - 1] = '\0';
break;
case 62: /* ssid-filter */
case 65: /* ssid-filter */
hash_ssid_filter=hash_jen(optarg,strlen(optarg));
{
char *e,*p = optarg;
@@ -1673,7 +1744,7 @@ int main(int argc, char **argv)
}
}
break;
case 63: /* nlm-filter */
case 66: /* nlm-filter */
hash_nlm_filter=hash_jen(optarg,strlen(optarg));
{
char *e,*p = optarg;
@@ -1691,7 +1762,7 @@ int main(int argc, char **argv)
}
}
break;
case 64: /* nlm-list */
case 67: /* nlm-list */
if (!nlm_list(optarg && !strcmp(optarg,"all")))
{
DLOG_ERR("could not get list of NLM networks\n");
@@ -1776,9 +1847,9 @@ int main(int argc, char **argv)
if (dp->desync_ttl6 == 0xFF) dp->desync_ttl6=dp->desync_ttl;
if (!AUTOTTL_ENABLED(dp->desync_autottl6)) dp->desync_autottl6 = dp->desync_autottl;
if (AUTOTTL_ENABLED(dp->desync_autottl))
DLOG("[profile %d] autottl ipv4 %u:%u-%u\n",v,dp->desync_autottl.delta,dp->desync_autottl.min,dp->desync_autottl.max);
DLOG("[profile %d] autottl ipv4 %u:%u-%u\n",dp->n,dp->desync_autottl.delta,dp->desync_autottl.min,dp->desync_autottl.max);
if (AUTOTTL_ENABLED(dp->desync_autottl6))
DLOG("[profile %d] autottl ipv6 %u:%u-%u\n",v,dp->desync_autottl6.delta,dp->desync_autottl6.min,dp->desync_autottl6.max);
DLOG("[profile %d] autottl ipv6 %u:%u-%u\n",dp->n,dp->desync_autottl6.delta,dp->desync_autottl6.min,dp->desync_autottl6.max);
if (dp->desync_split_tls==tlspos_none && dp->desync_split_pos) dp->desync_split_tls=tlspos_pos;
if (dp->desync_split_http_req==httpreqpos_none && dp->desync_split_pos) dp->desync_split_http_req=httpreqpos_pos;
}
@@ -1793,6 +1864,16 @@ int main(int argc, char **argv)
DLOG_ERR("Exclude hostlists load failed\n");
exit_clean(1);
}
if (!LoadIncludeIpsets())
{
DLOG_ERR("Include ipset load failed\n");
exit_clean(1);
}
if (!LoadExcludeIpsets())
{
DLOG_ERR("Exclude ipset load failed\n");
exit_clean(1);
}
if (daemon) daemonize();

View File

@@ -207,8 +207,12 @@ static void dp_entry_destroy(struct desync_profile_list *entry)
{
strlist_destroy(&entry->dp.hostlist_files);
strlist_destroy(&entry->dp.hostlist_exclude_files);
strlist_destroy(&entry->dp.ipset_files);
strlist_destroy(&entry->dp.ipset_exclude_files);
StrPoolDestroy(&entry->dp.hostlist_exclude);
StrPoolDestroy(&entry->dp.hostlist);
ipsetDestroy(&entry->dp.ips);
ipsetDestroy(&entry->dp.ips_exclude);
HostFailPoolDestroy(&entry->dp.hostlist_auto_fail_counters);
free(entry);
}

View File

@@ -66,6 +66,10 @@ struct desync_profile
bool filter_ipv4,filter_ipv6;
port_filter pf_tcp,pf_udp;
uint32_t filter_l7; // L7_PROTO_* bits
ipset ips,ips_exclude;
struct str_list_head ipset_files, ipset_exclude_files;
strpool *hostlist, *hostlist_exclude;
struct str_list_head hostlist_files, hostlist_exclude_files;
char hostlist_auto_filename[PATH_MAX];
@@ -74,6 +78,8 @@ struct desync_profile
hostfail_pool *hostlist_auto_fail_counters;
};
#define PROFILE_IPSETS_EMPTY(dp) (IPSET_EMPTY(&dp->ips) && IPSET_EMPTY(&dp->ips_exclude))
struct desync_profile_list {
struct desync_profile dp;
LIST_ENTRY(desync_profile_list) next;

View File

@@ -151,3 +151,127 @@ void strlist_destroy(struct str_list_head *head)
strlist_entry_destroy(entry);
}
}
void ipset4Destroy(ipset4 **ipset)
{
ipset4 *elem, *tmp;
HASH_ITER(hh, *ipset, elem, tmp)
{
HASH_DEL(*ipset, elem);
free(elem);
}
}
bool ipset4Check(ipset4 *ipset, const struct in_addr *a, uint8_t preflen)
{
uint32_t ip = ntohl(a->s_addr);
struct cidr4 cidr;
ipset4 *ips_found;
// zero alignment bytes
memset(&cidr,0,sizeof(cidr));
cidr.preflen = preflen+1;
do
{
cidr.preflen--;
cidr.addr.s_addr = htonl(ip & mask_from_preflen(cidr.preflen));
HASH_FIND(hh, ipset, &cidr, sizeof(cidr), ips_found);
if (ips_found) return true;
} while(cidr.preflen);
return false;
}
bool ipset4Add(ipset4 **ipset, const struct in_addr *a, uint8_t preflen)
{
if (preflen>32) return false;
// avoid dups
if (ipset4Check(*ipset, a, preflen)) return true; // already included
struct ipset4 *entry = calloc(1,sizeof(ipset4));
if (!entry) return false;
entry->cidr.addr.s_addr = htonl(ntohl(a->s_addr) & mask_from_preflen(preflen));
entry->cidr.preflen = preflen;
oom = false;
HASH_ADD(hh, *ipset, cidr, sizeof(entry->cidr), entry);
if (oom) { free(entry); return false; }
return true;
}
void ipset4Print(ipset4 *ipset)
{
ipset4 *ips, *tmp;
HASH_ITER(hh, ipset , ips, tmp)
{
print_cidr4(&ips->cidr);
printf("\n");
}
}
void ipset6Destroy(ipset6 **ipset)
{
ipset6 *elem, *tmp;
HASH_ITER(hh, *ipset, elem, tmp)
{
HASH_DEL(*ipset, elem);
free(elem);
}
}
bool ipset6Check(ipset6 *ipset, const struct in6_addr *a, uint8_t preflen)
{
struct cidr6 cidr;
ipset6 *ips_found;
// zero alignment bytes
memset(&cidr,0,sizeof(cidr));
cidr.preflen = preflen+1;
do
{
cidr.preflen--;
ip6_and(a, mask_from_preflen6(cidr.preflen), &cidr.addr);
HASH_FIND(hh, ipset, &cidr, sizeof(cidr), ips_found);
if (ips_found) return true;
} while(cidr.preflen);
return false;
}
bool ipset6Add(ipset6 **ipset, const struct in6_addr *a, uint8_t preflen)
{
if (preflen>128) return false;
// avoid dups
if (ipset6Check(*ipset, a, preflen)) return true; // already included
struct ipset6 *entry = calloc(1,sizeof(ipset6));
if (!entry) return false;
ip6_and(a, mask_from_preflen6(preflen), &entry->cidr.addr);
entry->cidr.preflen = preflen;
oom = false;
HASH_ADD(hh, *ipset, cidr, sizeof(entry->cidr), entry);
if (oom) { free(entry); return false; }
return true;
}
void ipset6Print(ipset6 *ipset)
{
ipset6 *ips, *tmp;
HASH_ITER(hh, ipset , ips, tmp)
{
print_cidr6(&ips->cidr);
printf("\n");
}
}
void ipsetDestroy(ipset *ipset)
{
ipset4Destroy(&ipset->ips4);
ipset6Destroy(&ipset->ips6);
}
void ipsetPrint(ipset *ipset)
{
ipset4Print(ipset->ips4);
ipset6Print(ipset->ips6);
}

View File

@@ -5,6 +5,8 @@
#include <sys/queue.h>
#include <time.h>
#include "helpers.h"
//#define HASH_BLOOM 20
#define HASH_NONFATAL_OOM 1
#define HASH_FUNCTION HASH_BER
@@ -43,3 +45,41 @@ void HostFailPoolDump(hostfail_pool *p);
bool strlist_add(struct str_list_head *head, const char *filename);
void strlist_destroy(struct str_list_head *head);
typedef struct ipset4 {
struct cidr4 cidr; /* key */
UT_hash_handle hh; /* makes this structure hashable */
} ipset4;
typedef struct ipset6 {
struct cidr6 cidr; /* key */
UT_hash_handle hh; /* makes this structure hashable */
} ipset6;
// combined ipset ipv4 and ipv6
typedef struct ipset {
ipset4 *ips4;
ipset6 *ips6;
} ipset;
#define IPSET_EMPTY(ips) (!(ips)->ips4 && !(ips)->ips6)
void ipset4Destroy(ipset4 **ipset);
bool ipset4Add(ipset4 **ipset, const struct in_addr *a, uint8_t preflen);
static inline bool ipset4AddCidr(ipset4 **ipset, const struct cidr4 *cidr)
{
return ipset4Add(ipset,&cidr->addr,cidr->preflen);
}
bool ipset4Check(ipset4 *ipset, const struct in_addr *a, uint8_t preflen);
void ipset4Print(ipset4 *ipset);
void ipset6Destroy(ipset6 **ipset);
bool ipset6Add(ipset6 **ipset, const struct in6_addr *a, uint8_t preflen);
static inline bool ipset6AddCidr(ipset6 **ipset, const struct cidr6 *cidr)
{
return ipset6Add(ipset,&cidr->addr,cidr->preflen);
}
bool ipset6Check(ipset6 *ipset, const struct in6_addr *a, uint8_t preflen);
void ipset6Print(ipset6 *ipset);
void ipsetDestroy(ipset *ipset);
void ipsetPrint(ipset *ipset);

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -11,6 +11,12 @@
#include <time.h>
#include <sys/stat.h>
void rtrim(char *s)
{
if (s)
for (char *p = s + strlen(s) - 1; p >= s && (*p == '\n' || *p == '\r'); p--) *p = '\0';
}
char *strncasestr(const char *s,const char *find, size_t slen)
{
char c, sc;
@@ -81,7 +87,6 @@ void print_sockaddr(const struct sockaddr *sa)
printf("%s",ip_port);
}
// -1 = error, 0 = not local, 1 = local
bool check_local_ip(const struct sockaddr *saddr)
{
@@ -178,6 +183,10 @@ void sacopy(struct sockaddr_storage *sa_dest, const struct sockaddr *sa)
sa_dest->ss_family = 0;
}
}
void sa46copy(sockaddr_in46 *sa_dest, const struct sockaddr *sa)
{
sacopy((struct sockaddr_storage*)sa_dest, sa);
}
bool is_localnet(const struct sockaddr *a)
{
@@ -287,3 +296,97 @@ bool pf_is_empty(const port_filter *pf)
{
return !pf->neg && !pf->from && !pf->to;
}
static void mask_from_preflen6_make(uint8_t plen, struct in6_addr *a)
{
if (plen >= 128)
memset(a->s6_addr,0xFF,16);
else
{
uint8_t n = plen >> 3;
memset(a->s6_addr,0xFF,n);
memset(a->s6_addr+n,0x00,16-n);
a->s6_addr[n] = (uint8_t)(0xFF00 >> (plen & 7));
}
}
struct in6_addr ip6_mask[129];
void mask_from_preflen6_prepare(void)
{
for (int plen=0;plen<=128;plen++) mask_from_preflen6_make(plen, ip6_mask+plen);
}
#if defined(__GNUC__) && !defined(__llvm__)
__attribute__((optimize ("no-strict-aliasing")))
#endif
void ip6_and(const struct in6_addr * restrict a, const struct in6_addr * restrict b, struct in6_addr * restrict result)
{
// int 128 can cause alignment segfaults because sin6_addr in struct sockaddr_in6 is 8-byte aligned, not 16-byte
((uint64_t*)result->s6_addr)[0] = ((uint64_t*)a->s6_addr)[0] & ((uint64_t*)b->s6_addr)[0];
((uint64_t*)result->s6_addr)[1] = ((uint64_t*)a->s6_addr)[1] & ((uint64_t*)b->s6_addr)[1];
}
void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr)
{
char s_ip[16];
*s_ip=0;
inet_ntop(AF_INET, &cidr->addr, s_ip, sizeof(s_ip));
snprintf(s,s_len,cidr->preflen<32 ? "%s/%u" : "%s", s_ip, cidr->preflen);
}
void print_cidr4(const struct cidr4 *cidr)
{
char s[19];
str_cidr4(s,sizeof(s),cidr);
printf("%s",s);
}
void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr)
{
char s_ip[40];
*s_ip=0;
inet_ntop(AF_INET6, &cidr->addr, s_ip, sizeof(s_ip));
snprintf(s,s_len,cidr->preflen<128 ? "%s/%u" : "%s", s_ip, cidr->preflen);
}
void print_cidr6(const struct cidr6 *cidr)
{
char s[44];
str_cidr6(s,sizeof(s),cidr);
printf("%s",s);
}
bool parse_cidr4(char *s, struct cidr4 *cidr)
{
char *p,d;
bool b;
unsigned int plen;
if ((p = strchr(s, '/')))
{
if (sscanf(p + 1, "%u", &plen)!=1 || plen>32)
return false;
cidr->preflen = (uint8_t)plen;
d=*p; *p=0; // backup char
}
else
cidr->preflen = 32;
b = (inet_pton(AF_INET, s, &cidr->addr)==1);
if (p) *p=d; // restore char
return b;
}
bool parse_cidr6(char *s, struct cidr6 *cidr)
{
char *p,d;
bool b;
unsigned int plen;
if ((p = strchr(s, '/')))
{
if (sscanf(p + 1, "%u", &plen)!=1 || plen>128)
return false;
cidr->preflen = (uint8_t)plen;
d=*p; *p=0; // backup char
}
else
cidr->preflen = 128;
b = (inet_pton(AF_INET6, s, &cidr->addr)==1);
if (p) *p=d; // restore char
return b;
}

View File

@@ -8,6 +8,14 @@
#include <stdio.h>
#include <time.h>
// this saves memory. sockaddr_storage is larger than required. it can be 128 bytes. sockaddr_in6 is 28 bytes.
typedef union
{
struct sockaddr_in sa4; // size 16
struct sockaddr_in6 sa6; // size 28
} sockaddr_in46;
void rtrim(char *s);
char *strncasestr(const char *s,const char *find, size_t slen);
bool append_to_list_file(const char *filename, const char *s);
@@ -26,6 +34,7 @@ uint16_t saport(const struct sockaddr *sa);
bool saconvmapped(struct sockaddr_storage *a);
void sacopy(struct sockaddr_storage *sa_dest, const struct sockaddr *sa);
void sa46copy(sockaddr_in46 *sa_dest, const struct sockaddr *sa);
bool is_localnet(const struct sockaddr *a);
bool is_linklocal(const struct sockaddr_in6* a);
@@ -71,3 +80,33 @@ bool pf_is_empty(const port_filter *pf);
#else
#define IN6_EXTRACT_MAP4(a) (((const uint32_t *) (a))[3])
#endif
struct cidr4
{
struct in_addr addr;
uint8_t preflen;
};
struct cidr6
{
struct in6_addr addr;
uint8_t preflen;
};
void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr);
void print_cidr4(const struct cidr4 *cidr);
void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr);
void print_cidr6(const struct cidr6 *cidr);
bool parse_cidr4(char *s, struct cidr4 *cidr);
bool parse_cidr6(char *s, struct cidr6 *cidr);
static inline uint32_t mask_from_preflen(uint32_t preflen)
{
return preflen ? preflen<32 ? ~((1 << (32-preflen)) - 1) : 0xFFFFFFFF : 0;
}
void ip6_and(const struct in6_addr * restrict a, const struct in6_addr * restrict b, struct in6_addr * restrict result);
extern struct in6_addr ip6_mask[129];
void mask_from_preflen6_prepare(void);
static inline const struct in6_addr *mask_from_preflen6(uint8_t preflen)
{
return ip6_mask+preflen;
}

View File

@@ -5,17 +5,27 @@
#include "helpers.h"
// inplace tolower() and add to pool
static bool addpool(strpool **hostlist, char **s, const char *end)
static bool addpool(strpool **hostlist, char **s, const char *end, int *ct)
{
char *p;
char *p=*s;
// advance until eol lowering all chars
for (p = *s; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
if (!StrPoolAddStrLen(hostlist, *s, p-*s))
// comment line
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\r' || *p == '\n')
{
StrPoolDestroy(hostlist);
*hostlist = NULL;
return false;
// advance until eol
for (; p<end && *p && *p!='\r' && *p != '\n'; p++);
}
else
{
// advance until eol lowering all chars
for (; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
if (!StrPoolAddStrLen(hostlist, *s, p-*s))
{
StrPoolDestroy(hostlist);
*hostlist = NULL;
return false;
}
(*ct)++;
}
// advance to the next line
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
@@ -23,7 +33,7 @@ static bool addpool(strpool **hostlist, char **s, const char *end)
return true;
}
bool AppendHostList(strpool **hostlist, char *filename)
bool AppendHostList(strpool **hostlist, const char *filename)
{
char *p, *e, s[256], *zbuf;
size_t zsize;
@@ -51,14 +61,12 @@ bool AppendHostList(strpool **hostlist, char *filename)
e = zbuf + zsize;
while(p<e)
{
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue;
if (!addpool(hostlist,&p,e))
if (!addpool(hostlist,&p,e,&ct))
{
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
free(zbuf);
return false;
}
ct++;
}
free(zbuf);
}
@@ -72,17 +80,15 @@ bool AppendHostList(strpool **hostlist, char *filename)
{
DLOG_CONDUP("loading plain text list\n");
while (fgets(s, 256, F))
while (fgets(s, sizeof(s), F))
{
p = s;
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue;
if (!addpool(hostlist,&p,p+strlen(p)))
if (!addpool(hostlist,&p,p+strlen(p),&ct))
{
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
fclose(F);
return false;
}
ct++;
}
fclose(F);
}
@@ -166,10 +172,9 @@ static bool LoadIncludeHostListsForProfile(struct desync_profile *dp)
return true;
}
// return : true = apply fooling, false = do not apply
bool HostlistCheck(struct desync_profile *dp, const char *host, bool *excluded)
{
VPRINT("* Hostlist check for profile %d\n",dp->n);
VPRINT("* hostlist check for profile %d\n",dp->n);
if (*dp->hostlist_auto_filename)
{
time_t t = file_mod_time(dp->hostlist_auto_filename);

View File

@@ -4,7 +4,7 @@
#include "pools.h"
#include "params.h"
bool AppendHostList(strpool **hostlist, char *filename);
bool AppendHostList(strpool **hostlist, const char *filename);
bool LoadHostLists(strpool **hostlist, struct str_list_head *file_list);
bool LoadIncludeHostLists();
bool LoadExcludeHostLists();

195
tpws/ipset.c Normal file
View File

@@ -0,0 +1,195 @@
#include <stdio.h>
#include "ipset.h"
#include "gzip.h"
#include "helpers.h"
// inplace tolower() and add to pool
static bool addpool(ipset *ips, char **s, const char *end, int *ct)
{
char *p, cidr[128];
size_t l;
struct cidr4 c4;
struct cidr6 c6;
// advance until eol
for (p=*s; p<end && *p && *p!='\r' && *p != '\n'; p++);
// comment line
if (!(**s == '#' || **s == ';' || **s == '/' || **s == '\r' || **s == '\n' ))
{
l = p-*s;
if (l>=sizeof(cidr)) l=sizeof(cidr)-1;
memcpy(cidr,*s,l);
cidr[l]=0;
rtrim(cidr);
if (parse_cidr4(cidr,&c4))
{
if (!ipset4AddCidr(&ips->ips4, &c4))
{
ipsetDestroy(ips);
return false;
}
(*ct)++;
}
else if (parse_cidr6(cidr,&c6))
{
if (!ipset6AddCidr(&ips->ips6, &c6))
{
ipsetDestroy(ips);
return false;
}
(*ct)++;
}
else
DLOG_ERR("bad ip or subnet : %s\n",cidr);
}
// advance to the next line
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
*s = p;
return true;
}
static bool AppendIpset(ipset *ips, const char *filename)
{
char *p, *e, s[256], *zbuf;
size_t zsize;
int ct = 0;
FILE *F;
int r;
DLOG_CONDUP("Loading ipset %s\n",filename);
if (!(F = fopen(filename, "rb")))
{
DLOG_ERR("Could not open %s\n", filename);
return false;
}
if (is_gzip(F))
{
r = z_readfile(F,&zbuf,&zsize);
fclose(F);
if (r==Z_OK)
{
DLOG_CONDUP("zlib compression detected. uncompressed size : %zu\n", zsize);
p = zbuf;
e = zbuf + zsize;
while(p<e)
{
if (!addpool(ips,&p,e,&ct))
{
DLOG_ERR("Not enough memory to store ipset : %s\n", filename);
free(zbuf);
return false;
}
}
free(zbuf);
}
else
{
DLOG_ERR("zlib decompression failed : result %d\n",r);
return false;
}
}
else
{
DLOG_CONDUP("loading plain text list\n");
while (fgets(s, sizeof(s)-1, F))
{
p = s;
if (!addpool(ips,&p,p+strlen(p),&ct))
{
DLOG_ERR("Not enough memory to store ipset : %s\n", filename);
fclose(F);
return false;
}
}
fclose(F);
}
DLOG_CONDUP("Loaded %d ip/subnets from %s\n", ct, filename);
return true;
}
static bool LoadIpsets(ipset *ips, struct str_list_head *file_list)
{
struct str_list *file;
ipsetDestroy(ips);
LIST_FOREACH(file, file_list, next)
{
if (!AppendIpset(ips, file->str)) return false;
}
return true;
}
bool LoadIncludeIpsets()
{
struct desync_profile_list *dpl;
LIST_FOREACH(dpl, &params.desync_profiles, next)
if (!LoadIpsets(&dpl->dp.ips, &dpl->dp.ipset_files))
return false;
return true;
}
bool LoadExcludeIpsets()
{
struct desync_profile_list *dpl;
LIST_FOREACH(dpl, &params.desync_profiles, next)
if (!LoadIpsets(&dpl->dp.ips_exclude, &dpl->dp.ipset_exclude_files))
return false;
return true;
}
bool SearchIpset(const ipset *ips, const struct in_addr *ipv4, const struct in6_addr *ipv6)
{
char s_ip[40];
bool bInSet=false;
if (!!ipv4 != !!ipv6)
{
*s_ip=0;
if (ipv4)
{
if (params.debug) inet_ntop(AF_INET, ipv4, s_ip, sizeof(s_ip));
if (ips->ips4) bInSet = ipset4Check(ips->ips4, ipv4, 32);
}
if (ipv6)
{
if (params.debug) inet_ntop(AF_INET6, ipv6, s_ip, sizeof(s_ip));
if (ips->ips6) bInSet = ipset6Check(ips->ips6, ipv6, 128);
}
VPRINT("ipset check for %s : %s\n", s_ip, bInSet ? "positive" : "negative");
}
else
// ipv4 and ipv6 are both empty or non-empty
VPRINT("ipset check error !!!!!!!! ipv4=%p ipv6=%p\n",ipv4,ipv6);
return bInSet;
}
static bool IpsetCheck_(const ipset *ips, const ipset *ips_exclude, const struct in_addr *ipv4, const struct in6_addr *ipv6)
{
if (!IPSET_EMPTY(ips_exclude))
{
VPRINT("exclude ");
if (SearchIpset(ips_exclude, ipv4, ipv6))
return false;
}
if (!IPSET_EMPTY(ips))
{
VPRINT("include ");
return SearchIpset(ips, ipv4, ipv6);
}
return true;
}
bool IpsetCheck(struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6)
{
if (!PROFILE_IPSETS_EMPTY(dp)) VPRINT("* ipset check for profile %d\n",dp->n);
return IpsetCheck_(&dp->ips,&dp->ips_exclude,ipv4,ipv6);
}

11
tpws/ipset.h Normal file
View File

@@ -0,0 +1,11 @@
#pragma once
#include <stdbool.h>
#include <arpa/inet.h>
#include "params.h"
#include "pools.h"
bool LoadIncludeIpsets();
bool LoadExcludeIpsets();
bool SearchIpset(const ipset *ips, const struct in_addr *ipv4, const struct in6_addr *ipv6);
bool IpsetCheck(struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6);

View File

@@ -169,8 +169,12 @@ static void dp_entry_destroy(struct desync_profile_list *entry)
{
strlist_destroy(&entry->dp.hostlist_files);
strlist_destroy(&entry->dp.hostlist_exclude_files);
strlist_destroy(&entry->dp.ipset_files);
strlist_destroy(&entry->dp.ipset_exclude_files);
StrPoolDestroy(&entry->dp.hostlist_exclude);
StrPoolDestroy(&entry->dp.hostlist);
ipsetDestroy(&entry->dp.ips);
ipsetDestroy(&entry->dp.ips_exclude);
HostFailPoolDestroy(&entry->dp.hostlist_auto_fail_counters);
free(entry);
}

View File

@@ -51,6 +51,9 @@ struct desync_profile
bool filter_ipv4,filter_ipv6;
port_filter pf_tcp;
uint32_t filter_l7; // L7_PROTO_* bits
ipset ips,ips_exclude;
struct str_list_head ipset_files, ipset_exclude_files;
strpool *hostlist, *hostlist_exclude;
struct str_list_head hostlist_files, hostlist_exclude_files;
@@ -60,6 +63,8 @@ struct desync_profile
hostfail_pool *hostlist_auto_fail_counters;
};
#define PROFILE_IPSETS_EMPTY(dp) (IPSET_EMPTY(&dp->ips) && IPSET_EMPTY(&dp->ips_exclude))
struct desync_profile_list {
struct desync_profile dp;
LIST_ENTRY(desync_profile_list) next;

View File

@@ -52,6 +52,12 @@ bool StrPoolAddStr(strpool **pp, const char *s)
{
return StrPoolAddStrLen(pp, s, strlen(s));
}
bool StrPoolAddUniqueStr(strpool **pp,const char *s)
{
if (StrPoolCheckStr(*pp,s))
return true;
return StrPoolAddStr(pp,s);
}
bool StrPoolCheckStr(strpool *p, const char *s)
{
@@ -151,3 +157,127 @@ void strlist_destroy(struct str_list_head *head)
strlist_entry_destroy(entry);
}
}
void ipset4Destroy(ipset4 **ipset)
{
ipset4 *elem, *tmp;
HASH_ITER(hh, *ipset, elem, tmp)
{
HASH_DEL(*ipset, elem);
free(elem);
}
}
bool ipset4Check(ipset4 *ipset, const struct in_addr *a, uint8_t preflen)
{
uint32_t ip = ntohl(a->s_addr);
struct cidr4 cidr;
ipset4 *ips_found;
// zero alignment bytes
memset(&cidr,0,sizeof(cidr));
cidr.preflen = preflen+1;
do
{
cidr.preflen--;
cidr.addr.s_addr = htonl(ip & mask_from_preflen(cidr.preflen));
HASH_FIND(hh, ipset, &cidr, sizeof(cidr), ips_found);
if (ips_found) return true;
} while(cidr.preflen);
return false;
}
bool ipset4Add(ipset4 **ipset, const struct in_addr *a, uint8_t preflen)
{
if (preflen>32) return false;
// avoid dups
if (ipset4Check(*ipset, a, preflen)) return true; // already included
struct ipset4 *entry = calloc(1,sizeof(ipset4));
if (!entry) return false;
entry->cidr.addr.s_addr = htonl(ntohl(a->s_addr) & mask_from_preflen(preflen));
entry->cidr.preflen = preflen;
oom = false;
HASH_ADD(hh, *ipset, cidr, sizeof(entry->cidr), entry);
if (oom) { free(entry); return false; }
return true;
}
void ipset4Print(ipset4 *ipset)
{
ipset4 *ips, *tmp;
HASH_ITER(hh, ipset , ips, tmp)
{
print_cidr4(&ips->cidr);
printf("\n");
}
}
void ipset6Destroy(ipset6 **ipset)
{
ipset6 *elem, *tmp;
HASH_ITER(hh, *ipset, elem, tmp)
{
HASH_DEL(*ipset, elem);
free(elem);
}
}
bool ipset6Check(ipset6 *ipset, const struct in6_addr *a, uint8_t preflen)
{
struct cidr6 cidr;
ipset6 *ips_found;
// zero alignment bytes
memset(&cidr,0,sizeof(cidr));
cidr.preflen = preflen+1;
do
{
cidr.preflen--;
ip6_and(a, mask_from_preflen6(cidr.preflen), &cidr.addr);
HASH_FIND(hh, ipset, &cidr, sizeof(cidr), ips_found);
if (ips_found) return true;
} while(cidr.preflen);
return false;
}
bool ipset6Add(ipset6 **ipset, const struct in6_addr *a, uint8_t preflen)
{
if (preflen>128) return false;
// avoid dups
if (ipset6Check(*ipset, a, preflen)) return true; // already included
struct ipset6 *entry = calloc(1,sizeof(ipset6));
if (!entry) return false;
ip6_and(a, mask_from_preflen6(preflen), &entry->cidr.addr);
entry->cidr.preflen = preflen;
oom = false;
HASH_ADD(hh, *ipset, cidr, sizeof(entry->cidr), entry);
if (oom) { free(entry); return false; }
return true;
}
void ipset6Print(ipset6 *ipset)
{
ipset6 *ips, *tmp;
HASH_ITER(hh, ipset , ips, tmp)
{
print_cidr6(&ips->cidr);
printf("\n");
}
}
void ipsetDestroy(ipset *ipset)
{
ipset4Destroy(&ipset->ips4);
ipset6Destroy(&ipset->ips6);
}
void ipsetPrint(ipset *ipset)
{
ipset4Print(ipset->ips4);
ipset6Print(ipset->ips6);
}

View File

@@ -5,6 +5,8 @@
#include <sys/queue.h>
#include <time.h>
#include "helpers.h"
//#define HASH_BLOOM 20
#define HASH_NONFATAL_OOM 1
#define HASH_FUNCTION HASH_BER
@@ -17,6 +19,7 @@ typedef struct strpool {
void StrPoolDestroy(strpool **pp);
bool StrPoolAddStr(strpool **pp,const char *s);
bool StrPoolAddUniqueStr(strpool **pp,const char *s);
bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen);
bool StrPoolCheckStr(strpool *p,const char *s);
@@ -44,3 +47,41 @@ void HostFailPoolDump(hostfail_pool *p);
bool strlist_add(struct str_list_head *head, const char *filename);
void strlist_destroy(struct str_list_head *head);
typedef struct ipset4 {
struct cidr4 cidr; /* key */
UT_hash_handle hh; /* makes this structure hashable */
} ipset4;
typedef struct ipset6 {
struct cidr6 cidr; /* key */
UT_hash_handle hh; /* makes this structure hashable */
} ipset6;
// combined ipset ipv4 and ipv6
typedef struct ipset {
ipset4 *ips4;
ipset6 *ips6;
} ipset;
#define IPSET_EMPTY(ips) (!(ips)->ips4 && !(ips)->ips6)
void ipset4Destroy(ipset4 **ipset);
bool ipset4Add(ipset4 **ipset, const struct in_addr *a, uint8_t preflen);
static inline bool ipset4AddCidr(ipset4 **ipset, const struct cidr4 *cidr)
{
return ipset4Add(ipset,&cidr->addr,cidr->preflen);
}
bool ipset4Check(ipset4 *ipset, const struct in_addr *a, uint8_t preflen);
void ipset4Print(ipset4 *ipset);
void ipset6Destroy(ipset6 **ipset);
bool ipset6Add(ipset6 **ipset, const struct in6_addr *a, uint8_t preflen);
static inline bool ipset6AddCidr(ipset6 **ipset, const struct cidr6 *cidr)
{
return ipset6Add(ipset,&cidr->addr,cidr->preflen);
}
bool ipset6Check(ipset6 *ipset, const struct in6_addr *a, uint8_t preflen);
void ipset6Print(ipset6 *ipset);
void ipsetDestroy(ipset *ipset);
void ipsetPrint(ipset *ipset);

View File

@@ -103,7 +103,13 @@ static void *resolver_thread(void *arg)
ri->ga_res = getaddrinfo(ri->dom,sport,&hints,&ai);
if (!ri->ga_res)
{
memcpy(&ri->ss, ai->ai_addr, ai->ai_addrlen);
if (ai->ai_addrlen>sizeof(ri->ss))
{
DLOG_ERR("getaddrinfo returned too large address\n");
ri->ga_res = EAI_FAIL;
}
else
memcpy(&ri->ss, ai->ai_addr, ai->ai_addrlen);
freeaddrinfo(ai);
}
//printf("THREAD %d END JOB %s FIRST=%p\n", syscall(SYS_gettid), ri->dom, TAILQ_FIRST(&resolver.resolve_list));

View File

@@ -6,10 +6,12 @@
#include <sys/socket.h>
#include <netdb.h>
#include "helpers.h"
struct resolve_item
{
char dom[256]; // request dom
struct sockaddr_storage ss; // resolve result
sockaddr_in46 ss; // resolve result
int ga_res; // getaddrinfo result code
uint16_t port; // request port
void *ptr;

View File

@@ -1,22 +1,50 @@
#define _GNU_SOURCE
#include "tamper.h"
#include "hostlist.h"
#include "protocol.h"
#include "helpers.h"
#include <string.h>
#include <stdio.h>
#include "tamper.h"
#include "hostlist.h"
#include "ipset.h"
#include "protocol.h"
#include "helpers.h"
static bool dp_match_l3l4(struct desync_profile *dp, bool ipv6, uint16_t tcp_port)
const char *l7proto_str(t_l7proto l7)
{
return \
((!ipv6 && dp->filter_ipv4) || (ipv6 && dp->filter_ipv6)) &&
(!tcp_port || pf_in_range(tcp_port,&dp->pf_tcp));
}
static bool dp_match(struct desync_profile *dp, bool ipv6, uint16_t tcp_port, const char *hostname)
{
if (dp_match_l3l4(dp,ipv6,tcp_port))
switch(l7)
{
case HTTP: return "http";
case TLS: return "tls";
default: return "unknown";
}
}
static bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7)
{
return (l7proto==UNKNOWN && (filter_l7 & L7_PROTO_UNKNOWN)) ||
(l7proto==HTTP && (filter_l7 & L7_PROTO_HTTP)) ||
(l7proto==TLS && (filter_l7 & L7_PROTO_TLS));
}
static bool dp_match_l3l4(struct desync_profile *dp, const struct sockaddr *dest)
{
return ((dest->sa_family==AF_INET && dp->filter_ipv4) || (dest->sa_family==AF_INET6 && dp->filter_ipv6)) &&
pf_in_range(saport(dest), &dp->pf_tcp) &&
IpsetCheck(dp, dest->sa_family==AF_INET ? &((struct sockaddr_in*)dest)->sin_addr : NULL, dest->sa_family==AF_INET6 ? &((struct sockaddr_in6*)dest)->sin6_addr : NULL);
}
static bool dp_impossible(struct desync_profile *dp, const char *hostname, t_l7proto l7proto)
{
return !PROFILE_IPSETS_EMPTY(dp) &&
((dp->filter_l7 && !l7_proto_match(l7proto, dp->filter_l7)) || (!*dp->hostlist_auto_filename && !hostname && (dp->hostlist || dp->hostlist_exclude)));
}
static bool dp_match(struct desync_profile *dp, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto)
{
// impossible case, hard filter
// impossible check avoids relatively slow ipset search
if (!dp_impossible(dp,hostname,l7proto) && dp_match_l3l4(dp,dest))
{
// soft filter
if (dp->filter_l7 && !l7_proto_match(l7proto, dp->filter_l7))
return false;
// autohostlist profile matching l3/l4 filter always win
if (*dp->hostlist_auto_filename) return true;
@@ -32,13 +60,18 @@ static bool dp_match(struct desync_profile *dp, bool ipv6, uint16_t tcp_port, co
}
return false;
}
static struct desync_profile *dp_find(struct desync_profile_list_head *head, bool ipv6, uint16_t tcp_port, const char *hostname)
static struct desync_profile *dp_find(struct desync_profile_list_head *head, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto)
{
struct desync_profile_list *dpl;
VPRINT("desync profile search for hostname='%s' ipv6=%u tcp_port=%u\n", hostname ? hostname : "", ipv6, tcp_port);
if (params.debug)
{
char ip_port[48];
ntop46_port(dest, ip_port,sizeof(ip_port));
VPRINT("desync profile search for tcp target=%s l7proto=%s hostname='%s'\n", ip_port, l7proto_str(l7proto), hostname ? hostname : "");
}
LIST_FOREACH(dpl, head, next)
{
if (dp_match(&dpl->dp,ipv6,tcp_port,hostname))
if (dp_match(&dpl->dp,dest,hostname,l7proto))
{
VPRINT("desync profile %d matches\n",dpl->dp.n);
return &dpl->dp;
@@ -49,7 +82,7 @@ static struct desync_profile *dp_find(struct desync_profile_list_head *head, boo
}
void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest)
{
ctrack->dp = dp_find(&params.desync_profiles, dest->sa_family==AF_INET6, saport(dest), ctrack->hostname);
ctrack->dp = dp_find(&params.desync_profiles, dest, ctrack->hostname, ctrack->l7proto);
}
@@ -114,33 +147,49 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
l7proto = UNKNOWN;
}
if (ctrack->l7proto==UNKNOWN) ctrack->l7proto=l7proto;
if (bHaveHost)
{
VPRINT("request hostname: %s\n", Host);
if (!ctrack->hostname)
{
if (!(ctrack->hostname=strdup(Host)))
{
DLOG_ERR("strdup hostname : out of memory\n");
return;
}
if (ctrack->b_not_act)
{
VPRINT("Not acting on this request\n");
return;
}
struct desync_profile *dp_prev = ctrack->dp;
apply_desync_profile(ctrack, dest);
if (ctrack->dp!=dp_prev)
VPRINT("desync profile changed by revealed hostname !\n");
else if (*ctrack->dp->hostlist_auto_filename)
{
bool bHostExcluded;
if (!HostlistCheck(ctrack->dp, Host, &bHostExcluded))
{
ctrack->b_ah_check = !bHostExcluded;
VPRINT("Not acting on this request\n");
return;
}
}
bool bDiscoveredL7 = ctrack->l7proto==UNKNOWN && l7proto!=UNKNOWN;
if (bDiscoveredL7)
{
VPRINT("discovered l7 protocol\n");
ctrack->l7proto=l7proto;
}
bool bDiscoveredHostname = bHaveHost && !ctrack->hostname;
if (bDiscoveredHostname)
{
VPRINT("discovered hostname\n");
if (!(ctrack->hostname=strdup(Host)))
{
DLOG_ERR("strdup hostname : out of memory\n");
return;
}
}
if (bDiscoveredL7 || bDiscoveredHostname)
{
struct desync_profile *dp_prev = ctrack->dp;
apply_desync_profile(ctrack, dest);
if (ctrack->dp!=dp_prev)
VPRINT("desync profile changed by revealed l7 protocol or hostname !\n");
}
if (bDiscoveredHostname && *ctrack->dp->hostlist_auto_filename)
{
bool bHostExcluded;
if (!HostlistCheck(ctrack->dp, Host, &bHostExcluded))
{
ctrack->b_ah_check = !bHostExcluded;
VPRINT("Not acting on this request\n");
ctrack->b_not_act = true;
return;
}
}
@@ -326,7 +375,7 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
if (ctrack->dp->oob) *split_flags |= SPLIT_FLAG_OOB;
}
static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const char *hostname)
static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const char *hostname, const char *client_ip_port, t_l7proto l7proto)
{
if (hostname)
{
@@ -337,12 +386,12 @@ static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const ch
{
HostFailPoolDel(&dp->hostlist_auto_fail_counters, fail_counter);
VPRINT("auto hostlist (profile %d) : %s : fail counter reset. website is working.\n", dp->n, hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : fail counter reset. website is working.", hostname, dp->n);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : fail counter reset. website is working.", hostname, dp->n, client_ip_port, l7proto_str(l7proto));
}
}
}
static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname)
static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname, const char *client_ip_port, t_l7proto l7proto)
{
hostfail_pool *fail_counter;
@@ -358,7 +407,7 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
}
fail_counter->counter++;
VPRINT("auto hostlist (profile %d) : %s : fail counter %d/%d\n", dp->n , hostname, fail_counter->counter, dp->hostlist_auto_fail_threshold);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : fail counter %d/%d", hostname, dp->n, fail_counter->counter, dp->hostlist_auto_fail_threshold);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : fail counter %d/%d", hostname, dp->n, client_ip_port, l7proto_str(l7proto), fail_counter->counter, dp->hostlist_auto_fail_threshold);
if (fail_counter->counter >= dp->hostlist_auto_fail_threshold)
{
VPRINT("auto hostlist (profile %d) : fail threshold reached. adding %s to auto hostlist\n", dp->n , hostname);
@@ -369,7 +418,7 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
if (!HostlistCheck(dp, hostname, &bExcluded) && !bExcluded)
{
VPRINT("auto hostlist (profile %d) : adding %s to %s\n", dp->n, hostname, dp->hostlist_auto_filename);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : adding to %s", hostname, dp->n, dp->hostlist_auto_filename);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : adding to %s", hostname, dp->n, client_ip_port, l7proto_str(l7proto), dp->hostlist_auto_filename);
if (!StrPoolAddStr(&dp->hostlist, hostname))
{
DLOG_ERR("StrPoolAddStr out of memory\n");
@@ -385,16 +434,22 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
else
{
VPRINT("auto hostlist (profile %d) : NOT adding %s\n", dp->n, hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : NOT adding, duplicate detected", hostname, dp->n);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : NOT adding, duplicate detected", hostname, dp->n, client_ip_port, l7proto_str(l7proto));
}
}
}
void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size)
void tamper_in(t_ctrack *ctrack, const struct sockaddr *client, uint8_t *segment,size_t segment_buffer_size,size_t *size)
{
DBGPRINT("tamper_in hostname=%s\n", ctrack->hostname);
bool bFail=false;
DBGPRINT("tamper_in hostname=%s\n", ctrack->hostname);
char client_ip_port[48];
if (*params.hostlist_auto_debuglog)
ntop46_port((struct sockaddr*)client,client_ip_port,sizeof(client_ip_port));
else
*client_ip_port=0;
if (ctrack->dp && ctrack->b_ah_check)
{
@@ -409,7 +464,7 @@ void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,siz
if (bFail)
{
VPRINT("redirect to another domain detected. possibly DPI redirect.\n");
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : redirect to another domain", ctrack->hostname, ctrack->dp->n);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : redirect to another domain", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(ctrack->l7proto));
}
else
VPRINT("local or in-domain redirect detected. it's not a DPI redirect.\n");
@@ -419,17 +474,23 @@ void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,siz
// received not http reply. do not monitor this connection anymore
VPRINT("incoming unknown HTTP data detected for hostname %s\n", ctrack->hostname);
}
if (bFail) auto_hostlist_failed(ctrack->dp, ctrack->hostname);
if (bFail) auto_hostlist_failed(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
}
if (!bFail) auto_hostlist_reset_fail_counter(ctrack->dp, ctrack->hostname);
if (!bFail) auto_hostlist_reset_fail_counter(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
}
ctrack->bTamperInCutoff = true;
}
void rst_in(t_ctrack *ctrack)
void rst_in(t_ctrack *ctrack, const struct sockaddr *client)
{
DBGPRINT("rst_in hostname=%s\n", ctrack->hostname);
char client_ip_port[48];
if (*params.hostlist_auto_debuglog)
ntop46_port((struct sockaddr*)client,client_ip_port,sizeof(client_ip_port));
else
*client_ip_port=0;
if (ctrack->dp && ctrack->b_ah_check)
{
HostFailPoolPurgeRateLimited(&ctrack->dp->hostlist_auto_fail_counters);
@@ -437,15 +498,21 @@ void rst_in(t_ctrack *ctrack)
if (!ctrack->bTamperInCutoff && ctrack->hostname)
{
VPRINT("incoming RST detected for hostname %s\n", ctrack->hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : incoming RST", ctrack->hostname, ctrack->dp->n);
auto_hostlist_failed(ctrack->dp, ctrack->hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : incoming RST", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(ctrack->l7proto));
auto_hostlist_failed(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
}
}
}
void hup_out(t_ctrack *ctrack)
void hup_out(t_ctrack *ctrack, const struct sockaddr *client)
{
DBGPRINT("hup_out hostname=%s\n", ctrack->hostname);
char client_ip_port[48];
if (*params.hostlist_auto_debuglog)
ntop46_port((struct sockaddr*)client,client_ip_port,sizeof(client_ip_port));
else
*client_ip_port=0;
if (ctrack->dp && ctrack->b_ah_check)
{
HostFailPoolPurgeRateLimited(&ctrack->dp->hostlist_auto_fail_counters);
@@ -454,8 +521,8 @@ void hup_out(t_ctrack *ctrack)
{
// local leg dropped connection after first request. probably due to timeout.
VPRINT("local leg closed connection after first request (timeout ?). hostname: %s\n", ctrack->hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client closed connection without server reply", ctrack->hostname, ctrack->dp->n);
auto_hostlist_failed(ctrack->dp, ctrack->hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : client closed connection without server reply", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(ctrack->l7proto));
auto_hostlist_failed(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
}
}
}

View File

@@ -10,13 +10,18 @@
#define SPLIT_FLAG_OOB 0x02
typedef enum {UNKNOWN=0, HTTP, TLS} t_l7proto;
#define L7_PROTO_HTTP 1
#define L7_PROTO_TLS 2
#define L7_PROTO_UNKNOWN 0x80000000
const char *l7proto_str(t_l7proto l7);
typedef struct
{
// common state
t_l7proto l7proto;
bool bFirstReplyChecked;
bool bTamperInCutoff;
bool b_ah_check;
bool b_not_act;
char *hostname;
struct desync_profile *dp; // desync profile cache
} t_ctrack;
@@ -24,8 +29,8 @@ typedef struct
void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest);
void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *split_pos, uint8_t *split_flags);
void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size);
void tamper_in(t_ctrack *ctrack, const struct sockaddr *client, uint8_t *segment,size_t segment_buffer_size,size_t *size);
// connection reset by remote leg
void rst_in(t_ctrack *ctrack);
void rst_in(t_ctrack *ctrack, const struct sockaddr *client);
// local leg closed connection (timeout waiting response ?)
void hup_out(t_ctrack *ctrack);
void hup_out(t_ctrack *ctrack, const struct sockaddr *client);

View File

@@ -33,6 +33,7 @@
#include "tpws_conn.h"
#include "hostlist.h"
#include "ipset.h"
#include "params.h"
#include "sec.h"
#include "redirect.h"
@@ -46,7 +47,7 @@ bool bHup = false;
static void onhup(int sig)
{
printf("HUP received !\n");
printf("Will reload hostlist on next request (if any)\n");
printf("Will reload hostlists and ipsets on next request (if any)\n");
bHup = true;
}
// should be called in normal execution
@@ -54,9 +55,9 @@ void dohup(void)
{
if (bHup)
{
if (!LoadIncludeHostLists() || !LoadExcludeHostLists())
if (!LoadIncludeHostLists() || !LoadExcludeHostLists() || !LoadIncludeIpsets() || !LoadExcludeIpsets())
{
// what will we do without hostlist ?? sure, gonna die
// what will we do without hostlist or ipset ?? sure, gonna die
exit(1);
}
bHup = false;
@@ -180,6 +181,9 @@ static void exithelp(void)
" --new\t\t\t\t\t; begin new strategy\n"
" --filter-l3=ipv4|ipv6\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n"
" --filter-tcp=[~]port1[-port2]\t\t; TCP port filter. ~ means negation\n"
" --filter-l7=[http|tls|unknown]\t\t; L6-L7 protocol filter. multiple comma separated values allowed.\n"
" --ipset=<filename>\t\t\t; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n"
" --ipset-exclude=<filename>\t\t; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n"
"\nHOSTLIST FILTER:\n"
" --hostlist=<filename>\t\t\t; only act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n"
" --hostlist-exclude=<filename>\t\t; do not act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n"
@@ -317,6 +321,35 @@ static bool wf_make_l3(char *opt, bool *ipv4, bool *ipv6)
return true;
}
static bool parse_l7_list(char *opt, uint32_t *l7)
{
char *e,*p,c;
for (p=opt,*l7=0 ; p ; )
{
if ((e = strchr(p,',')))
{
c=*e;
*e=0;
}
if (!strcmp(p,"http"))
*l7 |= L7_PROTO_HTTP;
else if (!strcmp(p,"tls"))
*l7 |= L7_PROTO_TLS;
else if (!strcmp(p,"unknown"))
*l7 |= L7_PROTO_UNKNOWN;
else return false;
if (e)
{
*e++=c;
}
p = e;
}
return true;
}
void parse_params(int argc, char *argv[])
{
int option_index = 0;
@@ -409,21 +442,24 @@ void parse_params(int argc, char *argv[])
{ "tamper-cutoff",required_argument,0,0 },// optidx=54
{ "connect-bind-addr",required_argument,0,0 },// optidx=55
{ "new",no_argument,0,0 }, // optidx=56
{ "filter-l3",required_argument,0,0 }, // optidx=57
{ "filter-tcp",required_argument,0,0 }, // optidx=58
{ "new",no_argument,0,0 }, // optidx=56
{ "filter-l3",required_argument,0,0 }, // optidx=57
{ "filter-tcp",required_argument,0,0 }, // optidx=58
{ "filter-l7",required_argument,0,0 }, // optidx=59
{ "ipset",required_argument,0,0 }, // optidx=60
{ "ipset-exclude",required_argument,0,0 }, // optidx=61
#if defined(__FreeBSD__)
{ "enable-pf",no_argument,0,0 },// optidx=59
{ "enable-pf",no_argument,0,0 },// optidx=62
#elif defined(__APPLE__)
{ "local-tcp-user-timeout",required_argument,0,0 },// optidx=59
{ "remote-tcp-user-timeout",required_argument,0,0 },// optidx=60
{ "local-tcp-user-timeout",required_argument,0,0 }, // optidx=62
{ "remote-tcp-user-timeout",required_argument,0,0 }, // optidx=63
#elif defined(__linux__)
{ "local-tcp-user-timeout",required_argument,0,0 },// optidx=59
{ "remote-tcp-user-timeout",required_argument,0,0 },// optidx=60
{ "mss",required_argument,0,0 },// optidx=61
{ "local-tcp-user-timeout",required_argument,0,0 }, // optidx=62
{ "remote-tcp-user-timeout",required_argument,0,0 }, // optidx=63
{ "mss",required_argument,0,0 }, // optidx=64
#ifdef SPLICE_PRESENT
{ "nosplice",no_argument,0,0 },// optidx=62
{ "nosplice",no_argument,0,0 }, // optidx=65
#endif
#endif
{ "hostlist-auto-retrans-threshold",optional_argument,0,0}, // ignored. for nfqws command line compatibility
@@ -935,13 +971,36 @@ void parse_params(int argc, char *argv[])
exit_clean(1);
}
break;
case 59: /* filter-l7 */
if (!parse_l7_list(optarg,&dp->filter_l7))
{
DLOG_ERR("Invalid l7 filter : %s\n",optarg);
exit_clean(1);
}
break;
case 60: /* ipset */
if (!strlist_add(&dp->ipset_files, optarg))
{
DLOG_ERR("strlist_add failed\n");
exit_clean(1);
}
params.tamper = true;
break;
case 61: /* ipset-exclude */
if (!strlist_add(&dp->ipset_exclude_files, optarg))
{
DLOG_ERR("strlist_add failed\n");
exit_clean(1);
}
params.tamper = true;
break;
#if defined(__FreeBSD__)
case 59: /* enable-pf */
case 62: /* enable-pf */
params.pf_enable = true;
break;
#elif defined(__linux__) || defined(__APPLE__)
case 59: /* local-tcp-user-timeout */
case 62: /* local-tcp-user-timeout */
params.tcp_user_timeout_local = atoi(optarg);
if (params.tcp_user_timeout_local<0 || params.tcp_user_timeout_local>86400)
{
@@ -949,7 +1008,7 @@ void parse_params(int argc, char *argv[])
exit_clean(1);
}
break;
case 60: /* remote-tcp-user-timeout */
case 63: /* remote-tcp-user-timeout */
params.tcp_user_timeout_remote = atoi(optarg);
if (params.tcp_user_timeout_remote<0 || params.tcp_user_timeout_remote>86400)
{
@@ -960,7 +1019,7 @@ void parse_params(int argc, char *argv[])
#endif
#if defined(__linux__)
case 61: /* mss */
case 64: /* mss */
// this option does not work in any BSD and MacOS. OS may accept but it changes nothing
dp->mss = atoi(optarg);
if (dp->mss<88 || dp->mss>32767)
@@ -970,7 +1029,7 @@ void parse_params(int argc, char *argv[])
}
break;
#ifdef SPLICE_PRESENT
case 62: /* nosplice */
case 65: /* nosplice */
params.nosplice = true;
break;
#endif
@@ -1021,6 +1080,16 @@ void parse_params(int argc, char *argv[])
DLOG_ERR("Exclude hostlist load failed\n");
exit_clean(1);
}
if (!LoadIncludeIpsets())
{
DLOG_ERR("Include ipset load failed\n");
exit_clean(1);
}
if (!LoadExcludeIpsets())
{
DLOG_ERR("Exclude ipset load failed\n");
exit_clean(1);
}
}
@@ -1087,7 +1156,7 @@ static bool read_system_maxfiles(rlim_t *maxfile)
return false;
n=fscanf(F,"%ju",&um);
fclose(F);
if (!n) return false;
if (n != 1) return false;
*maxfile = (rlim_t)um;
return true;
#elif defined(BSD)
@@ -1132,7 +1201,7 @@ static bool set_ulimit(void)
// additional 1/2 for unpaired remote legs sending buffers
// 16 for listen_fd, epoll, hostlist, ...
#ifdef SPLICE_PRESENT
fdmax = (params.nosplice ? 2 : (params.tamper && !params.tamper_lim ? 4 : 6)) * params.maxconn;
fdmax = (rlim_t)(params.nosplice ? 2 : (params.tamper && !params.tamper_lim ? 4 : 6)) * (rlim_t)params.maxconn;
#else
fdmax = 2 * params.maxconn;
#endif
@@ -1177,6 +1246,8 @@ int main(int argc, char *argv[])
char ip_port[48];
srand(time(NULL));
mask_from_preflen6_prepare();
parse_params(argc, argv);
if (params.daemon) daemonize();

View File

@@ -569,7 +569,6 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int
{
struct sockaddr_storage orig_dst;
tproxy_conn_t *conn;
int remote_fd=0;
if (proxy_type==CONN_TYPE_TRANSPARENT)
{
@@ -597,19 +596,8 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int
return 0;
}
if (proxy_type==CONN_TYPE_TRANSPARENT)
{
if ((remote_fd = connect_remote((struct sockaddr *)&orig_dst, 0)) < 0)
{
DLOG_ERR("Failed to connect\n");
close(local_fd);
return NULL;
}
}
if(!(conn = new_conn(local_fd, false)))
{
if (remote_fd) close(remote_fd);
close(local_fd);
return NULL;
}
@@ -617,18 +605,33 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int
conn->state = CONN_AVAILABLE; // accepted connection is immediately available
conn->efd = efd;
socklen_t salen=sizeof(conn->client);
getpeername(conn->fd,(struct sockaddr *)&conn->client,&salen);
if (proxy_type==CONN_TYPE_TRANSPARENT)
{
sacopy(&conn->dest, (struct sockaddr *)&orig_dst);
sa46copy(&conn->dest, (struct sockaddr *)&orig_dst);
if(!(conn->partner = new_conn(remote_fd, true)))
if(!(conn->partner = new_conn(0, true)))
{
free_conn(conn);
close(remote_fd);
return NULL;
}
conn->partner->partner = conn;
conn->partner->efd = efd;
conn->partner->client = conn->client;
conn->partner->dest = conn->dest;
apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest);
if ((conn->partner->fd = connect_remote((struct sockaddr *)&orig_dst, conn->track.dp ? conn->track.dp->mss : 0)) < 0)
{
DLOG_ERR("Failed to connect\n");
free_conn(conn->partner);
free_conn(conn);
return NULL;
}
//remote_fd is connecting. Non-blocking connects are signaled as done by
//socket being marked as ready for writing
@@ -663,9 +666,6 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int
legs_remote++;
}
if (proxy_type==CONN_TYPE_TRANSPARENT)
apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest);
return conn;
}
@@ -693,7 +693,7 @@ static bool check_connection_attempt(tproxy_conn_t *conn, int efd)
{
if (params.debug>=1)
{
struct sockaddr_storage sa;
sockaddr_in46 sa;
socklen_t salen=sizeof(sa);
char ip_port[48];
@@ -815,6 +815,8 @@ static bool proxy_mode_connect_remote(tproxy_conn_t *conn, struct tailhead *conn
}
conn->partner->partner = conn;
conn->partner->efd = conn->efd;
conn->partner->client = conn->client;
conn->partner->dest = conn->dest;
if (!epoll_set(conn->partner, EPOLLOUT))
{
DLOG_ERR("socks epoll_set error %d\n", errno);
@@ -920,7 +922,7 @@ static bool handle_proxy_mode(tproxy_conn_t *conn, struct tailhead *conn_list)
socks4_send_rep(conn->fd, S4_REP_FAILED);
return false;
}
conn->dest.ss_family = AF_INET;
((struct sockaddr_in*)&conn->dest)->sin_family = AF_INET;
((struct sockaddr_in*)&conn->dest)->sin_port = m->port;
((struct sockaddr_in*)&conn->dest)->sin_addr.s_addr = m->ip;
return proxy_mode_connect_remote(conn, conn_list);
@@ -952,12 +954,12 @@ static bool handle_proxy_mode(tproxy_conn_t *conn, struct tailhead *conn_list)
switch(m->atyp)
{
case S5_ATYP_IP4:
conn->dest.ss_family = AF_INET;
((struct sockaddr_in*)&conn->dest)->sin_family = AF_INET;
((struct sockaddr_in*)&conn->dest)->sin_port = m->d4.port;
((struct sockaddr_in*)&conn->dest)->sin_addr = m->d4.addr;
break;
case S5_ATYP_IP6:
conn->dest.ss_family = AF_INET6;
((struct sockaddr_in6*)&conn->dest)->sin6_family = AF_INET6;
((struct sockaddr_in6*)&conn->dest)->sin6_port = m->d6.port;
((struct sockaddr_in6*)&conn->dest)->sin6_addr = m->d6.addr;
((struct sockaddr_in6*)&conn->dest)->sin6_flowinfo = 0;
@@ -1037,7 +1039,7 @@ static bool resolve_complete(struct resolve_item *ri, struct tailhead *conn_list
DBGPRINT("resolve_complete put hostname : %s\n", ri->dom);
conn->track.hostname = strdup(ri->dom);
}
sacopy(&conn->dest, (struct sockaddr *)&ri->ss);
sa46copy(&conn->dest, (struct sockaddr *)&ri->ss);
return proxy_mode_connect_remote(conn,conn_list);
}
}
@@ -1074,7 +1076,7 @@ static void tamper(tproxy_conn_t *conn, uint8_t *segment, size_t segment_buffer_
if (conn->remote)
{
if (conn_partner_alive(conn) && !conn->partner->track.bTamperInCutoff)
tamper_in(&conn->partner->track,segment,segment_buffer_size,segment_size);
tamper_in(&conn->partner->track,(struct sockaddr*)&conn->partner->client,segment,segment_buffer_size,segment_size);
}
else
{
@@ -1527,15 +1529,8 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
if (params.debug>=1)
{
struct sockaddr_storage sa;
socklen_t salen=sizeof(sa);
char ip_port[48];
if (getpeername(conn->fd,(struct sockaddr *)&sa,&salen))
*ip_port=0;
else
ntop46_port((struct sockaddr*)&sa,ip_port,sizeof(ip_port));
ntop46_port((struct sockaddr*)&conn->client,ip_port,sizeof(ip_port));
VPRINT("Socket fd=%d (local) connected from %s\n", conn->fd, ip_port);
}
set_user_timeout(conn->fd, params.tcp_user_timeout_local);
@@ -1563,7 +1558,7 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
read_all_and_buffer(conn,3);
if (errn==ECONNRESET && conn_partner_alive(conn))
{
if (conn->remote && params.tamper) rst_in(&conn->partner->track);
if (conn->remote && params.tamper) rst_in(&conn->partner->track,(struct sockaddr*)&conn->partner->client);
struct linger lin;
lin.l_onoff=1;
@@ -1588,7 +1583,7 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct)
{
DBGPRINT("EPOLLRDHUP\n");
read_all_and_buffer(conn,2);
if (!conn->remote && params.tamper) hup_out(&conn->track);
if (!conn->remote && params.tamper) hup_out(&conn->track,(struct sockaddr*)&conn->client);
conn->state = CONN_RDHUP; // only writes. do not receive RDHUP anymore
if (conn_has_unsent(conn))

View File

@@ -54,7 +54,7 @@ struct tproxy_conn
int splice_pipe[2];
conn_state_t state;
conn_type_t conn_type;
struct sockaddr_storage dest;
sockaddr_in46 client, dest; // ip:port of client, ip:port of target
struct tproxy_conn *partner; // other leg
time_t orphan_since;