├── .github
└── workflows
│ ├── build.yml
│ └── publish.yml
├── .gitignore
├── LICENSE.md
├── README.md
├── docker-compose.override.sample.yml
├── docker-compose.yml
├── docs
├── guide_Keenetic.md
├── guide_Keenetic_RU.md
└── guide_OpenWrt.md
├── scripts
└── docker-build.sh
└── services
├── antizapret
├── .dockerignore
├── Dockerfile
├── api
│ ├── go.mod
│ └── main.go
├── docker-compose.yml
├── etc
│ ├── ferm
│ │ └── ferm.conf
│ ├── sysctl.d
│ │ ├── 10-conntrack.conf
│ │ └── 20-network.conf
│ └── systemd
│ │ ├── journald.conf
│ │ ├── network
│ │ ├── eth.network
│ │ └── host.network
│ │ └── system
│ │ ├── adguardhome.service
│ │ ├── antizapret-api.service
│ │ ├── antizapret-update.service
│ │ ├── antizapret-update.timer
│ │ ├── dnsmap.service
│ │ ├── iperf3-server@.service
│ │ └── systemd-networkd-wait-online.service.d
│ │ └── override.conf
├── init.sh
├── root
│ ├── adguardhome
│ │ ├── AdGuardHome.yaml
│ │ └── upstream_dns_file_basis
│ └── antizapret
│ │ ├── config
│ │ ├── custom
│ │ │ ├── exclude-hosts-custom.txt
│ │ │ ├── exclude-ips-custom.txt
│ │ │ ├── exclude-regexp-custom.txt
│ │ │ ├── include-hosts-custom.txt
│ │ │ └── include-ips-custom.txt
│ │ ├── exclude-hosts-by-ips-dist.txt
│ │ ├── exclude-hosts-dist.txt
│ │ ├── exclude-ips-dist.txt
│ │ ├── exclude-regexp-dist.txt
│ │ ├── include-hosts-dist.txt
│ │ └── include-ips-dist.txt
│ │ ├── dnsmap.py
│ │ ├── doall.sh
│ │ ├── parse.sh
│ │ ├── process.sh
│ │ ├── result
│ │ └── .gitkeep
│ │ ├── scripts
│ │ ├── getzones.awk
│ │ ├── resolve-dns-nxdomain.py
│ │ └── sanitize-lists.awk
│ │ ├── temp
│ │ └── .gitkeep
│ │ └── update.sh
└── routes.sh
├── cloak
├── .dockerignore
├── Dockerfile
├── docker-compose.yml
└── init.sh
├── dashboard
├── .dockerignore
├── Dockerfile
├── docker-compose.yml
└── files
│ ├── entrypoint.sh
│ ├── init.sh
│ └── www
│ ├── github.svg
│ ├── icon.svg
│ ├── index.css
│ ├── index.html
│ └── index.js
├── filebrowser
├── .dockerignore
├── Dockerfile
├── branding
│ ├── custom.css
│ └── img
│ │ ├── icons
│ │ └── favicon-16x16.png
│ │ └── logo.svg
├── docker-compose.yml
├── hooks
│ └── doall.sh
└── init.sh
├── ipsec
├── .dockerignore
├── Dockerfile
├── docker-compose.yml
└── init.sh
├── openvpn
├── .dockerignore
├── Dockerfile
├── Dockerfile.ui
├── docker-compose.yml
├── easy-rsa.vars
├── files-ui
│ ├── init.db
│ ├── restart.sh
│ └── ui-start.sh
└── files
│ ├── checkpsw.sh
│ ├── fw-rules.sh
│ ├── server-start.sh
│ └── socket.patch
├── proxy
├── .dockerignore
├── Dockerfile
├── docker-compose.yml
└── files
│ ├── entrypoint.sh
│ └── init.sh
└── wireguard
├── .dockerignore
├── Dockerfile
├── docker-compose.yml
└── init.sh
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | - dev
8 | paths:
9 | - .github
10 | - ../../adguard
11 | - Dockerfile
12 |
13 | concurrency:
14 | group: antizapret
15 |
16 | jobs:
17 | build:
18 | name: Build
19 | runs-on: ubuntu-latest
20 | steps:
21 | - name: Checkout Repository
22 | uses: actions/checkout@v4
23 |
24 | - name: Setup Docker Buildx
25 | uses: docker/setup-buildx-action@v3
26 |
27 | - name: Build Image
28 | uses: docker/build-push-action@v6
29 | with:
30 | context: .
31 | platforms: linux/amd64,linux/arm64
32 | cache-from: type=gha
33 | cache-to: type=gha,mode=max
34 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish
2 |
3 | on:
4 | release:
5 | types:
6 | - released
7 |
8 | concurrency:
9 | group: antizapret
10 |
11 | jobs:
12 | publish:
13 | name: Publish
14 | runs-on: ubuntu-latest
15 | steps:
16 | - name: Checkout Repository
17 | uses: actions/checkout@v4
18 |
19 | - name: Setup Docker Buildx
20 | uses: docker/setup-buildx-action@v3
21 |
22 | - name: Login to Docker Hub
23 | uses: docker/login-action@v3
24 | with:
25 | username: xtrime
26 | password: ${{ secrets.DOCKER_TOKEN }}
27 |
28 | - name: Login to GitHub Container Registry
29 | uses: docker/login-action@v3
30 | with:
31 | registry: ghcr.io
32 | username: ${{ github.actor }}
33 | password: ${{ secrets.GH_TOKEN }}
34 |
35 | - name: Get Version
36 | uses: jannemattila/get-version-from-tag@v3
37 | id: version
38 |
39 | - name: Extract Metadata
40 | id: meta
41 | uses: docker/metadata-action@v5
42 | with:
43 | images: |
44 | xtrime/antizapret-vpn
45 | ghcr.io/${{ github.repository }}
46 | tags: |
47 | type=raw,value=latest,${{ steps.version.outputs.version }}
48 |
49 | - name: Build Image
50 | uses: docker/build-push-action@v6
51 | with:
52 | context: .
53 | platforms: linux/amd64,linux/arm64
54 | cache-from: type=gha
55 | cache-to: type=gha,mode=max
56 | push: true
57 | tags: ${{ steps.meta.outputs.tags }}
58 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .*
2 | **/*.env
3 | !.gitkeep
4 | !.dockerignore
5 | /docker-compose.override.yml
6 | /config/
7 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Alexander Pankratov
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AntiZapret VPN in Docker
2 |
3 | Antizapret created to redirect only blocked domains to VPN tunnel. Its called split tunneling.
4 | This repo is based on idea from original [AntiZapret LXD image](https://bitbucket.org/anticensority/antizapret-vpn-container/src/master/)
5 |
6 | # Support and discussions group:
7 | https://t.me/antizapret_support
8 |
9 | # How works?
10 |
11 | 1) List of blocked domains downloaded from open registry.
12 | 2) List parsed and rules for dns resolver (adguardhome) created.
13 | 3) Adguardhome resend requests for blocked domains to python script dnsmap.py.
14 | 4) Python script:
15 | a) resolve real address for domain
16 | b) create fake address from 10.244.0.0/15 subnet
17 | c) create iptables rule to forward all packets from fake ip to real ip.
18 | 5) Fake IP is sent in DNS response to client
19 | 6) All vpn tunnels configured with split tunneling. Only traffic to 10.244.0.0/15 subnet is routed through VPN.
20 |
21 | # Features
22 |
23 | - [openvpn-dco](https://openvpn.net/as-docs/tutorials/tutorial--turn-on-openvpn-dco.html) - a kernel extension for improving performance of OpenVPN
24 | - Multiple VPN transports: Wireguard, OpenVPN, IPsec/XAuth ("Cisco IPsec")
25 | - Adguard as main DNS resolver
26 | - filebrowser as web viewer & editor for `*-custom.txt` files
27 | - Unified dashboard
28 | - Optional built-in reverse proxy based on caddy
29 |
30 |
31 | # Installation
32 |
33 | 0. Install [Docker Engine](https://docs.docker.com/engine/install/):
34 | ```bash
35 | curl -fsSL https://get.docker.com -o get-docker.sh
36 | sudo sh get-docker.sh
37 | ```
38 | 1. Clone repository and start container:
39 | ```bash
40 | git clone https://github.com/xtrime-ru/antizapret-vpn-docker.git antizapret
41 | cd antizapret
42 | ```
43 | 2. Create docker-compose.override.yml with services you need. Minimal example with only wireguard:
44 | ```yml
45 | services:
46 | antizapret:
47 | environment:
48 | - ADGUARDHOME_PASSWORD=somestrongpassword
49 | wireguard:
50 | environment:
51 | - WIREGUARD_PASSWORD=somestrongpassword
52 | extends:
53 | file: services/wireguard/docker-compose.yml
54 | service: wireguard
55 | depends_on:
56 | - antizapret
57 | ```
58 | Find full example in [docker-compose.override.sample.yml](./docker-compose.override.sample.yml)
59 |
60 | 3. Start services:
61 | ```shell
62 | docker compose pull
63 | docker compose build
64 | docker compose up -d
65 | docker system prune -f
66 | ```
67 |
68 | ## Access admin panels:
69 |
70 | ### HTTP:
71 | By default panels have following http ports exposed to internet:
72 | - dashboard: no exposed port
73 | - adguard: 3000
74 | - filebrowser: 2000
75 | - openvpn: 8080
76 | - wireguard: 51821
77 | - wireguard-amnezia: 51831
78 |
79 | If you do not wish to expose ports to internet override them in `docker-compose.override.yml`.
80 | In this example adguard and wireguard admin panels are removed from internet, and wireguard udp server is exposed:
81 | ```yml
82 | services:
83 | antizapret:
84 | environment:
85 | - ADGUARDHOME_USERNAME=admin
86 | - ADGUARDHOME_PASSWORD=password
87 | ports: !reset []
88 |
89 | wireguard:
90 | extends:
91 | file: services/wireguard/docker-compose.yml
92 | service: wireguard
93 | environment:
94 | - WIREGUARD_PASSWORD=password
95 | ports: !override
96 | - 51820:51820/udp
97 | ```
98 |
99 | ### HTTPS
100 | To enable https server and create self-signed certificates - add `proxy` container to `docker-compose.override.yml`
101 | When `proxy` container is started, access services with https at following ports at your host ip:
102 | - dashboard: 443
103 | - adguard: 1443
104 | - filebrowser: 2443
105 | - openvpn: 3443
106 | - wireguard: 4443
107 | - wireguard-amnezia: 5443
108 |
109 | `proxy` container is optional.
110 |
111 | ### Local network
112 | When you connected to VPN, you can access containers without exposing ports to internet:
113 | - http://core.antizapret:3000
114 | - http://dashboard.antizapret:80
115 | - http://wireguard-amnezia.antizapret:51821
116 | - http://wireguard.antizapret:51821
117 | - http://openvpn-ui.antizapret:8080
118 | - http://filebrowser.antizapret:80
119 |
120 | ## Update
121 |
122 | ```shell
123 | git pull
124 | docker compose pull
125 | docker compose build
126 | docker compose down --remove-orphans && docker compose up -d --remove-orphans
127 | ```
128 |
129 | ### Upgrade from v3
130 | **Only WireGuard/Amnezia configs can be moved**, please make backup WireGuard files (from `./.etc_wireguard` or `./.etc_wireguard_amnezia`) and put them in `./config/wireguard` or `./config/wireguard_amnezia` accordingly after steps below.
131 |
132 | Recommended to perform full remove of old version:
133 | ```shell
134 | docker compose down --remove-orphans
135 | docker system prune -af
136 | cd ../
137 | rm -rf antizapret/
138 | ```
139 |
140 | Then follow installation steps from this README.
141 |
142 | ## Reset:
143 | Remove all settings, vpn configs and return initial state of service:
144 | ```shell
145 | docker compose down
146 | rm -rf config/*
147 | docker compose up -d
148 | ```
149 |
150 | # Documentation
151 |
152 | ## Adding Domains/IPs
153 | Any domains or IPs can be added or excluded from routing with config files from `./config/antizapret/custom` directory.
154 | These lists are added/excluded to/from automatically generated lists of domains and IP's.
155 | Reboot container and wait few minutes for applying changes.
156 | Here is rules for lists: https://github.com/AdguardTeam/AdGuardHome/wiki/Configuration#upstreams
157 |
158 | Examples:
159 | ```
160 | subdomain.host.com
161 | *.host.com
162 | host.com
163 | de
164 | ```
165 |
166 | ## Environment Variables
167 |
168 | You can define these variables in docker-compose.override.yml file for your needs:
169 |
170 | Antizapret:
171 | - `SKIP_UPDATE_FROM_ZAPRET=true` - do not download and use list of all blocked domains from internet.
172 | Will reduce RAM consumption. Need to manually fill domains in `*-custom.txt` files.
173 | - `UPDATE_TIMER=1d` - blocked domains update interval
174 | - `ADGUARDHOME_PORT=3000`
175 | - `ADGUARDHOME_USERNAME=admin`
176 | - `ADGUARDHOME_PASSWORD=`
177 | - `ADGUARDHOME_PASSWORD_HASH=` - hashed password, taken from the AdGuardHome.yaml file after the first run using `ADGUARDHOME_PASSWORD`
178 | - `DNS=8.8.8.8` - Upstream DNS for resolving blocked sites
179 | - `ROUTES` - list of VPN containers and their virtual addresses. Needed for uniq client addresses in adguard logs
180 | - `LISTS` - list of urls to get blocked domains lists
181 | - `IP_LIST` - main url to get list of blocked ips and domains. Override with blank value to disable download of this list.
182 |
183 | Filebrowser:
184 | - `FILEBROWSER_PORT=admin`
185 | - `FILEBROWSER_PASSWORD=password`
186 |
187 | Proxy:
188 | - `PROXY_DOMAIN=` - create lets-encrypt https certificate for domain. If not set host ip is used for self-signed certificate.
189 | - `PROXY_EMAIL=` - email for letsecnrypt certificate.
190 |
191 | Openvpn
192 | - `OBFUSCATE_TYPE=0` - custom obfuscation level of openvpn protocol.
193 | 0 - disable.Act as regular openvpn client, support by all clients.
194 | 1 - light obfuscation, works with microtics
195 | 2 - strong obfuscation, works with some clients: openvpn gui client, asuswrt client...
196 | - `ANTIZAPRET_SUBNET=10.224.0.0/15` - subnet for virtual blocked ips
197 | - `OPENVPN_DNS=10.1.165.1` - DNS address for clients. Must be in `ANTIZAPRET_SUBNET`
198 |
199 | Openvpn-ui
200 | - `OPENVPN_ADMIN_PASSWORD=` — will be used as a server address in .ovpn profiles upon keys generation (default: your server's IP)
201 |
202 | Wireguard/Wireguard Amnezia
203 | - `WIREGUARD_PASSWORD=` - password for admin panel
204 | - `WIREGUARD_PASSWORD_HASH=` - [hashed password](https://github.com/wg-easy/wg-easy/blob/master/How_to_generate_an_bcrypt_hash.md) for admin panel
205 | - `ANTIZAPRET_SUBNET=10.224.0.0/15` - subnet for virtual blocked ips
206 | - `WG_DEFAULT_DNS=10.224.0.1` - DNS address for clients. Must be in `ANTIZAPRET_SUBNET`
207 | - `WG_PERSISTENT_KEEPALIVE=25`
208 | - `PORT=51821` - admin panel port
209 | - `WG_PORT=51820` - wireguard server port
210 | - `WG_DEVICE=eth0`
211 |
212 | Wireguard, Wireguard Amnezia, Openvpn:
213 | - `FORCE_FORWARD_DNS=true` - Redirects UDP traffic on port 53 to AntiZapret DNS (default: false)
214 | - `FORCE_FORWARD_DNS_PORTS="53 5353"` - Parameter can be used to change port 53 for FORCE_FORWARD_DNS to one or more, separated by a space (default: 53)
215 | - For other environment variables, see the original manual [Wireguard Amnezia](https://github.com/w0rng/amnezia-wg-easy) or [Wireguard](https://github.com/wg-easy/wg-easy).
216 |
217 | ## DNS
218 | ### Adguard Upstream DNS
219 | Adguard uses Google DNS and Quad9 DNS to resolve unblocked domains. This upstreams support ECS requests (more info below).
220 | Cloudflare DNS do not support ECS and is not recommended for use.
221 |
222 | Source code: [Adguard upstream DNS](./antizapret/root/adguardhome/upstream_dns_file_basis)
223 | After container is started working copy is located here: `./config/adguard/conf/upstream_dns_file_basis`
224 |
225 | ### CDN + ECS
226 | Some domains can resolve differently, depending on subnet (geoip) of client. In this case using of DNS located on remote server will break some services.
227 | ECS allow to provide client IP in DNS requests to upstream server and get correct results.
228 | Its enabled by default in Adguard and client ip is pointed to Moscow (Yandex Subnet).
229 |
230 | If you located in other region, you need to replace `77.88.8.8` with your real ip address on this page `http://your-server-ip:3000/#dns`
231 |
232 |
233 |
234 | ## OpenVpn
235 | ### Create client certificates:
236 | https://github.com/d3vilh/openvpn-ui?tab=readme-ov-file#generating-ovpn-client-profiles
237 | 1) go to `http://%your_ip%:8080/certificates`
238 | 2) click "create certificate"
239 | 3) enter unique name. Leave all other fields empty
240 | 4) click create
241 | 5) click on certificate name in list to download ovpn file.
242 |
243 | ### Enable OpenVPN Data Channel Offload (DCO)
244 | [OpenVPN Data Channel Offload (DCO)](https://openvpn.net/as-docs/openvpn-dco.html) provides performance improvements by moving the data channel handling to the kernel space, where it can be handled more efficiently and with multi-threading.
245 | **tl;dr** it increases speed and reduces CPU usage on a server.
246 |
247 | Kernel extensions can be installed only on a host machine, not in a container.
248 |
249 | #### Ubuntu 24.04
250 | ```bash
251 | sudo apt update
252 | sudo apt upgrade
253 | echo "#### Please reboot your system after upgrade ###" && sleep 100
254 | sudo apt install -y efivar
255 | sudo apt install -y openvpn-dco-dkms
256 | ```
257 |
258 | #### Ubuntu 20.04, 22.04
259 | ```bash
260 | sudo apt update
261 | sudo apt upgrade
262 | echo "#### Please reboot your system after upgrade ###" && sleep 100
263 | deb=openvpn-dco-dkms_0.0+git20231103-1_all.deb
264 | sudo apt install -y efivar dkms linux-headers-$(uname -r)
265 | wget http://archive.ubuntu.com/ubuntu/pool/universe/o/openvpn-dco-dkms/$deb
266 | sudo dpkg -i $deb
267 | ```
268 |
269 | ### Enable Amnezia Wireguard Kernel Extension
270 |
271 | https://github.com/amnezia-vpn/amneziawg-linux-kernel-module?tab=readme-ov-file#ubuntu
272 |
273 | 1. Edit `vi /etc/apt/sources.list` and uncomment `deb-src http://archive.ubuntu.com/ubuntu ... main restricted`
274 | 2. `sudo apt update`
275 | 3. `sudo apt install -y software-properties-common python3-launchpadlib gnupg2 linux-headers-$(uname -r)`
276 | 4. install source for kernel `sudo apt-get source linux-image-$(uname -r)`
277 | 5. `sudo add-apt-repository ppa:amnezia/ppa`
278 | 6. `sudo apt-get install -y amneziawg`
279 | 7. restart server or `docker compose restart wireguard-amnezia`
280 |
281 | ### Legacy clients support
282 | If your clients do not have GCM ciphers support you can use legacy CBC ciphers.
283 | DCO is incompatible with legacy ciphers and will be disabled. This is also increase CPU load.
284 |
285 | ### OpenVPN block
286 | Most providers now block openvpn to foreign IPs. Obfuscation not always fix the issue.
287 | For stable openvpn operation you can buy VPS inside of your country and then proxy all traffic to foreign server.
288 | Here is example of startup script.
289 | Replace X.X.X.X with IP address of your server and run it on fresh VPS (ubuntu 24.04 is recommended):
290 |
291 | ```shell
292 | #!/bin/sh
293 |
294 | # Fill with your foreign server ip
295 | export VPN_IP=X.X.X.X
296 |
297 | echo "net.ipv4.ip_forward=1" >> /etc/sysctl.d/99-sysctl.conf
298 | sysctl -w net.ipv4.ip_forward=1
299 |
300 | # DNAT rules
301 | iptables -t nat -A PREROUTING -p tcp ! --dport 22 -j DNAT --to-destination "$VPN_IP"
302 | iptables -t nat -A PREROUTING -p udp ! --dport 22 -j DNAT --to-destination "$VPN_IP"
303 | # MASQUERADE rules
304 | iptables -t nat -A POSTROUTING -p tcp -d "$VPN_IP" -j MASQUERADE
305 | iptables -t nat -A POSTROUTING -p udp -d "$VPN_IP" -j MASQUERADE
306 |
307 | echo iptables-persistent iptables-persistent/autosave_v4 boolean true | sudo debconf-set-selections
308 | echo iptables-persistent iptables-persistent/autosave_v6 boolean false | sudo debconf-set-selections
309 | apt install -y iptables-persistent
310 |
311 | ```
312 |
313 | ## Extra information
314 | - [OpenWrt setup guide](./docs/guide_OpenWrt.md) - how to setup OpenWrt router with this solution to keep LAN clients happy.
315 | - [Keenetic setup guide](./docs/guide_Keenetic.md) - instructions for configuring the server and connecting Keenetic routers to it [(на русском языке)](./docs/guide_Keenetic_RU.md)
316 |
317 | ## Test speed with iperf3
318 | iperf3 server is included in antizapret-vpn container.
319 | 1. Connect to VPN
320 | 2. Use iperf3 client on your phone or computer to check upload/download speed.
321 | Example 10 threads for 10 seconds and report result every second:
322 | ```shell
323 | iperf3 -c 10.224.0.1 -i1 -t10 -P10
324 | iperf3 -c 10.224.0.1 -i1 -t10 -P10 -R
325 | ```
326 |
327 | ## IPsec/XAuth (Cisco IPsec) server
328 | **Important notice**: not all clients support tunnel-split (send only part of traffic via VPN).
329 | For example **Apple** devices **will not** be able **to connect** to this server.
330 |
331 | **Recommended to use OpenVPN or Wireguard/Amnezia instead.**
332 |
333 | 1. Create settings file:
334 | ```shell
335 | cp ipsec/ipsec.env.example ipsec/ipsec.env
336 | ```
337 | 2. Fill your creditentials in `ipsec/ipsec.env`
338 | 3. Start
339 | ```shell
340 | docker compose down
341 | docker compose -f docker-compose.ipsec.yml up -d
342 | ```
343 | 4. Setup your clients: https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-xauth.md
344 |
345 | # Credits
346 | - [ProstoVPN](https://antizapret.prostovpn.org) — the original project
347 | - [AntiZapret VPN Container](https://bitbucket.org/anticensority/antizapret-vpn-container/src/master/) — source code of the LXD-based container
348 | - [AntiZapret PAC Generator](https://bitbucket.org/anticensority/antizapret-pac-generator-light/src/master/) — proxy auto-configuration generator to bypass censorship of Russian Federation
349 | - [Amnezia WireGuard VPN](https://github.com/w0rng/amnezia-wg-easy) — used for Amnezia Wireguard integration
350 | - [WireGuard VPN](https://github.com/wg-easy/wg-easy) — used for Wireguard integration
351 | - [OpenVPN](https://github.com/d3vilh/openvpn-ui) - used for OpenVPN integration
352 | - [IPsec VPN](https://github.com/hwdsl2/docker-ipsec-vpn-server) — used for IPsec integration
353 | - [AdGuardHome](https://github.com/AdguardTeam/AdGuardHome) - DNS resolver
354 | - [filebrowser](https://github.com/filebrowser/filebrowser) - web file browser & editor
355 | - [lighttpd](https://github.com/lighttpd/lighttpd1.4) - web server for unified dashboard
356 | - [caddy](https://github.com/caddyserver/caddy) - reverse proxy
357 | - [No Thought Is a Crime](https://ntc.party) — a forum about technical, political and economical aspects of internet censorship in different countries
358 |
--------------------------------------------------------------------------------
/docker-compose.override.sample.yml:
--------------------------------------------------------------------------------
1 | services:
2 | antizapret:
3 | environment:
4 | - ADGUARDHOME_USERNAME=admin
5 | - ADGUARDHOME_PASSWORD=password
6 |
7 | # cloak:
8 | # extends:
9 | # file: services/cloak/docker-compose.yml
10 | # service: cloak
11 |
12 | dashboard:
13 | extends:
14 | file: services/dashboard/docker-compose.yml
15 | service: dashboard
16 | environment:
17 | - DASHBOARD_USERNAME=admin
18 | - DASHBOARD_PASSWORD=password
19 |
20 | filebrowser:
21 | extends:
22 | file: services/filebrowser/docker-compose.yml
23 | service: filebrowser
24 | environment:
25 | - FILEBROWSER_USERNAME=admin
26 | - FILEBROWSER_PASSWORD=password
27 |
28 | # ipsec:
29 | # extends:
30 | # file: services/ipsec/docker-compose.yml
31 | # service: ipsec
32 |
33 | openvpn:
34 | extends:
35 | file: services/openvpn/docker-compose.yml
36 | service: openvpn
37 | depends_on:
38 | - openvpn-ui
39 |
40 | openvpn-ui:
41 | extends:
42 | file: services/openvpn/docker-compose.yml
43 | service: openvpn-ui
44 | environment:
45 | - OPENVPN_ADMIN_PASSWORD=password
46 |
47 | wireguard:
48 | extends:
49 | file: services/wireguard/docker-compose.yml
50 | service: wireguard
51 | environment:
52 | - WIREGUARD_PASSWORD=password
53 |
54 | wireguard-amnezia:
55 | extends:
56 | file: services/wireguard/docker-compose.yml
57 | service: wireguard-amnezia
58 | ports: !override
59 | - 51830:51820/udp
60 | - 51831:51821/tcp
61 | environment:
62 | - WIREGUARD_PASSWORD=password
63 | - PORT=51821
64 | - WG_PORT=51820
65 | - WG_CONFIG_PORT=51830
66 |
67 | proxy:
68 | extends:
69 | file: services/proxy/docker-compose.yml
70 | service: proxy
71 | environment:
72 | # If not set, will be created and used self-signed certificate
73 | - PROXY_DOMAIN=
74 | # If not set, will be created and used self-signed certificate
75 | - PROXY_EMAIL=
76 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | networks:
2 | default:
3 | driver: bridge
4 | ipam:
5 | config:
6 | - subnet: 10.200.0.0/24
7 |
8 | services:
9 | antizapret:
10 | extends:
11 | file: services/antizapret/docker-compose.yml
12 | service: antizapret
13 |
--------------------------------------------------------------------------------
/docs/guide_Keenetic.md:
--------------------------------------------------------------------------------
1 | # Keenetic router manual:
2 | - [Keenetic router manual:](#keenetic-router-manual)
3 | - [OpenVPN](#openvpn)
4 | - [OpenVPN server part](#openvpn-server-part)
5 | - [OpenVPN client part](#openvpn-client-part)
6 | - [WireGuard](#wireguard)
7 | - [WireGuard server part](#wireguard-server-part)
8 | - [WireGuard client part](#wireguard-client-part)
9 | - [IPsec](#ipsec)
10 | - [IPsec server side](#ipsec-server-side)
11 | - [IPsec client side](#ipsec-client-side)
12 |
13 | ## OpenVPN
14 |
15 | This is most usable and reliable way to bypass blockings.
16 |
17 | For better OpenVPN performance, new Keenetic routers with fast processors (from 1 GHz) and large amounts of RAM (from 256 MB) are recommended: Peak (KN-2710), Giga (KN-1012), Hopper (KN-3811/3812), Sprinter (KN-3711/3712), Challenger SE (KN-3911) и Ultra (KN-1811). **Give attention the model number.**
18 |
19 | For example: on old City KN-1511 bandwidth speed through server is limited at 6-8 Mbps, but on new Hopper KN-3811 speed reaches 55-60 Mbit/s
20 |
21 | Detailed information about the different models and OpenVPN speeds you can found at [manufacturer's website](https://help.keenetic.com/hc/en-us/articles/115005342025-VPN-types-in-Keenetic-routers).
22 |
23 | ### OpenVPN server part
24 | No special steps are required, follow [instructions](https://github.com/xtrime-ru/antizapret-vpn-docker?tab=readme-ov-file#installation). Also, you need [create client certificate](https://github.com/xtrime-ru/antizapret-vpn-docker?tab=readme-ov-file#create-client-certificates).
25 |
26 | ### OpenVPN client part
27 | 1. Install [OpenVPN client](https://help.keenetic.com/hc/en-us/articles/360000632239-OpenVPN-client)
28 | 2. In the OpenVPN configuration file, add the lines:
29 | ```
30 | pull-filter ignore block-outside-dns
31 | route 77.88.8.8
32 | ```
33 | 3. Add an OpenVPN connection under `Internet` > `Other Connections` > `VPN Connections` > `Create Connection`.
34 | 1. Use for accessing the Internet: `NO`.
35 | 2. Connection name: `AntiZapret`.
36 | 3. Type (protocol): `OpenVPN`.
37 | 4. Obtain routes from the remote side: `YES`.
38 | 5. OpenVPN configuration: `Content file from item 2`.
39 | 6. `Save`.
40 | 4. `Network Rules` > `Internet Safety`.
41 | 1. `DNS Configuration` > `Add Profile`.
42 | 1. Profile name: `AntiZapret`.
43 | 2. Transit requests: `NO`.
44 | 3. `Save`.
45 | 4. `Add Server`.
46 | 1. DNS server type: `Default`.
47 | 2. DNS server address: `77.88.8.8`.
48 | 3. `Save`.
49 | 2. `Content Filter`.
50 | 1. Filtering mode: `Public DNS resolvers`.
51 | 2. Default Content Filtering Profiles (`guest` and `home`): `AntiZapret`.
52 | 5. Under `Internet` > `Other Connections` enable `AntiZapret` connection.
53 |
54 | **Done!**
55 |
56 | ## WireGuard
57 | > [!WARNING]
58 | > Amnezia WireGuard requires firmware version **4.2+** to work.
59 | > For firmware lower than 4.2 you can use regular WireGuard on port 443.
60 | > But it may not work for everyone, I recommend using Amnezia.
61 |
62 | ### WireGuard server part
63 | 1. Install [Docker Engine](https://docs.docker.com/engine/install/):
64 | ```shell
65 | curl -fsSL https://get.docker.com -o get-docker.sh
66 | sudo sh get-docker.sh
67 | ```
68 | 2. Clone the repository:
69 | ```shell
70 | git clone https://github.com/xtrime-ru/antizapret-vpn-docker.git antizapret
71 | cd antizapret
72 | ```
73 | 3. Create a file `docker-compose.override.yml` with the following content:
74 | > Pay attention to WireGuard's assigned port! 443 bypasses blocking better, but may be considered by your hoster as an attempted DDoS attack on your server. If you experience any lags or connection failures, change 443 to another port first!
75 | ```yaml
76 | services:
77 | antizapret:
78 | environment:
79 | # Username for AdGuard Home (set yours!)
80 | - ADGUARDHOME_USERNAME=user
81 | # Password for AdGuard Home (set yours!)
82 | - ADGUARDHOME_PASSWORD=somestrongpassword
83 | # For Amnezia, replace with
84 | # wireguard-amnezia
85 | wireguard:
86 | environment:
87 | # Password for WireGuard control panel (set yours!)
88 | - WIREGUARD_PASSWORD=somestrongpassword
89 | # Allow routing of all IP addresses, routes are manually added to the router anyway
90 | # This way you can use the connection for a full VPN
91 | - WG_ALLOWED_IPS=0.0.0.0.0/0
92 | # Forced redirection of all DNS (udp 53) to antizapret
93 | # In keenetic, route 77.88.8.8.8 (or any other DNS) to WG gateway (Add automatically)
94 | # When WG goes down, DNS works directly.
95 | - FORCE_FORWARD_DNS=true
96 | # Language
97 | - LANG=en
98 | # Port for WireGuard control panel
99 | - PORT=51821
100 | # WireGuard port
101 | - WG_PORT=443
102 | ports:
103 | # Port for WireGuard control panel
104 | - "51821:51821/tcp"
105 | # WireGuard port
106 | - "443:443/udp"
107 | extends:
108 | # For Amnezia, replace with
109 | # file: docker-compose.wireguard-amnezia.yml
110 | file: docker-compose.wireguard.yml
111 | # For Amnezia, replace with
112 | # service: wireguard-amnezia
113 | service: wireguard
114 | ```
115 | 4. Assemble the container:
116 | ```shell
117 | docker compose pull
118 | docker compose build
119 | docker compose up -d
120 | ```
121 | 5. Create a profile in WireGuard: `http://:6843`.
122 | 6. Download the profile and go to the client part
123 |
124 | > [!NOTE]
125 | > You can change additional settings in AdGuard Home Control Panel: `http://:3000`
126 |
127 | ### WireGuard client part
128 | 1. [Install the "WireGuard VPN" component](https://help.keenetic.com/hc/en-us/articles/360010592379-WireGuard-VPN)
129 | 2. Load the profile downloaded from the panel `Internet` > `Other Connections` > `WireGuard` > `Import from a file`.
130 | 3. Open imported connection and check `Use for accessing the Internet`, change the name to `Antizapret` (optional).
131 | 4. `Network Rules` > `Routing`.
132 | 1. `Create route`.
133 | 1. Route type: `Route to host`.
134 | 2. Description: `AntiZapretDNS`.
135 | 3. Destination host address: `77.88.8.8`
136 | 4. Gateway IP: `empty`.
137 | 5. Interface: `Antizapret` (if you did not change the name, by file name)
138 | 6. Enable checkbox `Add automatically`
139 | 2. `Create Route`.
140 | 1. Route type: `Route to network`.
141 | 2. Description: `AntiZapret`.
142 | 3. Destination network address: `10.224.0.0`
143 | 4. Subnet mask: `255.254.0.0.0/15`.
144 | 5. Gateway IP: `blank`.
145 | 6. Interface: `Antizapret` (if you did not change the name, then by file name)
146 | 5. `Network Rules` > `Internet Safety`.
147 | 1. `DNS Configuration` > `Add Profile`.
148 | 1. Profile name: `AntiZapret`.
149 | 2. Transit requests: `NO`.
150 | 3. `Save`.
151 | 4. `Add Server`.
152 | 1. DNS server type: `Default`.
153 | 2. DNS server address: `77.88.8.8`.
154 | 3. `Save`.
155 | 2. `Content Filter`.
156 | 1. Filtering mode: `Public DNS resolvers`.
157 | 2. Default Content Filtering Profiles (`guest` and `home`): `AntiZapret`.
158 | 6. `Internet` > `Ethernet Cable`
159 | 1. Find your active ISP connect:
160 | 1. Enable checkbox `Ignore DNSv4 from ISP`
161 | 2. Enable checkbox `Ignore DNSv6 from ISP`
162 |
163 | > [!NOTE]
164 | > If using Amnezia Wireguard, there are a few more steps to follow
165 | [instructions](https://docs.amnezia.org/documentation/instructions/keenetic-os-awg)
166 | starting at step 20. I'll briefly duplicate it here.
167 |
168 | 1. Go to settings, click on the gear image in the upper right corner of the web page, and click on `Command Line` link.
169 | 2. Send a request: `show interface`.
170 | 3. Now we need to find out the name of the desired interface, by the name of the previously created connection. To do this, open a search on the page (you can do this by pressing two keys simultaneously, Ctrl+F). Enter for the search, the name of the previously created connection. In this example, it is `AntiZapret` . One unique name should be found in the `description` field. And next to it there will be another field, `interface-name`, which displays the name of the desired interface. In this example, it is `Wireguard1`.
171 | 4. Now, knowing the interface name and the values of the asc parameters from the .conf file we saved earlier. We need to replace all the template values in brackets with your values, and delete the brackets themselves.
172 |
173 | `interface {name} wireguard asc {jc} {jmin} {jmax} {s1} {s2} {h1} {h2} {h3} {h4}`
174 |
175 | To give an example, you get a string like this:
176 |
177 | `interface Wireguard1 wireguard asc 8 50 1000 30 32 1811016522 1196729875 457766807 1765857463`.
178 |
179 | The resulting string should be pasted into the web version of the router's command line, and the "Send Request" button should be clicked.
180 | 5. Send the request: `system configuration save`.
181 |
182 | In the `Internet` > `Other Connections` section, enable the `AntiZapret` connection.
183 |
184 | **Done!**
185 |
186 | ## IPsec
187 | ### IPsec server side
188 | In the process of writing
189 |
190 | ### IPsec client side
191 | In progress
192 |
--------------------------------------------------------------------------------
/docs/guide_Keenetic_RU.md:
--------------------------------------------------------------------------------
1 | # Инструкция для маршрутизаторов Keenetic:
2 | - [Инструкция для маршрутизаторов Keenetic:](#инструкция-для-маршрутизаторов-keenetic)
3 | - [OpenVPN](#openvpn)
4 | - [OpenVPN серверная часть](#openvpn-серверная-часть)
5 | - [OpenVPN клиентская часть](#openvpn-клиентская-часть)
6 | - [WireGuard](#wireguard)
7 | - [WireGuard серверная часть](#wireguard-серверная-часть)
8 | - [WireGuard клиентская часть](#wireguard-клиентская-часть)
9 | - [IPsec](#ipsec)
10 | - [IPsec серверная часть](#ipsec-серверная-часть)
11 | - [IPsec клиентская часть](#ipsec-клиентская-часть)
12 |
13 | ## OpenVPN
14 |
15 | Это самый удобный и надёжный способ обхода блокировок.
16 |
17 | Для более качественной работы OpenVPN рекомендуются новые роутеры Keenetic с быстрыми процессорами (от 1 ГГц) и большим объёмом оперативной памяти (от 256 Мб): Peak (KN-2710), Giga (KN-1012), Hopper (KN-3811/3812), Sprinter (KN-3711/3712), Challenger SE (KN-3911) и Ultra (KN-1811). **Обращайте внимание на номер модели**
18 |
19 | Если на старом City KN-1511 скорость канала с контейнером ограничена 6-8 Мбит/с, то на новом Hopper KN-3811 скорость достигает 55-60 Мбит/с
20 |
21 | Подробную информацию о различных моделях и скорости работы OpenVPN на них можно найти на [сайте производителя](https://help.keenetic.com/hc/ru/articles/115005342025-Типы-VPN-соединений-в-Keenetic).
22 |
23 | ### OpenVPN серверная часть
24 | Особых действий не требуется, действовать по [инструкции](https://github.com/xtrime-ru/antizapret-vpn-docker?tab=readme-ov-file#installation). А так же необходимо [выпустить сертификат](https://github.com/xtrime-ru/antizapret-vpn-docker?tab=readme-ov-file#create-client-certificates).
25 |
26 | ### OpenVPN клиентская часть
27 | 1. [Установить компонент "Клиент и сервер OpenVPN"](https://help.keenetic.com/hc/ru/articles/360000880359-%D0%9A%D0%BB%D0%B8%D0%B5%D0%BD%D1%82-%D0%B8-%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80-OpenVPN)
28 | 2. В файл конфигурации OpenVPN добавить строки:
29 | ```
30 | pull-filter ignore block-outside-dns
31 | route 77.88.8.8
32 | ```
33 | 3. Добавить подключение OpenVPN в разделе `Интернет` > `Другие подключения` > `VPN-подключения` > `Добавить подключение`
34 | 1. Использовать для выхода в интернет: `НЕТ`
35 | 2. Имя подключения: `AntiZapret`
36 | 3. Тип (протокол): `OpenVPN`
37 | 4. Получать маршруты от удаленной стороны: `ДА`
38 | 5. Конфигурация OpenVPN: `Содержимое файла из пункта 2`
39 | 6. `Сохранить`
40 | 4. `Сетевые правила` > `Интернет фильтры`
41 | 1. `Настройка DNS` > `Добавить профиль`
42 | 1. Имя профиля: `AntiZapret`
43 | 2. Транзит запросов: `НЕТ`
44 | 3. `Сохранить`
45 | 4. `Добавить сервер`
46 | 1. Тип сервера DNS: `По умолчанию`
47 | 2. IP-адрес: `77.88.8.8`
48 | 3. `Сохранить`
49 | 2. `Контентный фильтр`
50 | 1. Режим фильтрации: `Публичные DNS-резолверы`
51 | 2. Профили контентной фильтрации по умолчанию (`гостевая` и `домашняя`):`AntiZapret`
52 | 5. В разделе `Интернет` > `Другие подключения` включаем подключение `AntiZapret`
53 |
54 | **Готово!**
55 |
56 | ## WireGuard
57 | > [!WARNING]
58 | > Для работы Amnezia WireGuard необходима прошивка версии **4.2+**.
59 | > До 4.2 можно использовать обычный WireGuard на порту 443.
60 | > Но сработать может не у всех, рекомендую все таки вариант с Amnezia.
61 |
62 | ### WireGuard серверная часть
63 | 1. Устанавливаем [Docker Engine](https://docs.docker.com/engine/install/):
64 | ```bash
65 | curl -fsSL https://get.docker.com -o get-docker.sh
66 | sudo sh get-docker.sh
67 | ```
68 | 2. Клонируем репозиторий:
69 | ```
70 | git clone https://github.com/xtrime-ru/antizapret-vpn-docker.git antizapret
71 | cd antizapret
72 | ```
73 | 3. Создаем файл `docker-compose.override.yml` со следующим содержанием:
74 | > Обратите внимание на назначаемый порт WireGuard! 443 лучше обходит блокировки, но может быть расценен вашим хостером как попытка DDoS атаки на ваш сервер. Если возникнут какие-либо лаги или отвалы соединения первым делом смените 443 на какой-либо другой порт!
75 | ```yaml
76 | services:
77 | antizapret:
78 | environment:
79 | # Имя пользователя AdGuard Home (задайте свой!)
80 | - ADGUARDHOME_USERNAME=user
81 | # Пароль AdGuard Home (задайте свой!)
82 | - ADGUARDHOME_PASSWORD=somestrongpassword
83 | # Для Amnezia замените на
84 | # wireguard-amnezia
85 | wireguard:
86 | environment:
87 | # Пароль панели управления WireGuard (задайте свой!)
88 | - WIREGUARD_PASSWORD=somestrongpassword
89 | # Разрешить маршрутизацию всех IP адресов, в маршрутизатор в любом случае в ручном режиме добавляются маршруты
90 | # Таким образом можно использовать подключение для полноценного VPN
91 | - WG_ALLOWED_IPS=0.0.0.0/0
92 | # Принудительное перенаправление всех DNS (udp 53) на antizapret
93 | # В keenetic прописываем маршрут 77.88.8.8 (или любой другой DNS) на шлюз WG (добавление автоматически)
94 | # При падении WG, DNS работают напрямую
95 | - FORCE_FORWARD_DNS=true
96 | # Язык
97 | - LANG=ru
98 | # Порт для панели управления WireGuard
99 | - PORT=51821
100 | # Порт WireGuard
101 | - WG_PORT=443
102 | ports:
103 | # Порт для панели управления WireGuard
104 | - "51821:51821/tcp"
105 | # Порт WireGuard
106 | - "443:443/udp"
107 | extends:
108 | # Для Amnezia замените на
109 | # file: docker-compose.wireguard-amnezia.yml
110 | file: docker-compose.wireguard.yml
111 | # Для Amnezia замените на
112 | # service: wireguard-amnezia
113 | service: wireguard
114 | ```
115 | 4. Собираем контейнер:
116 | ```
117 | docker compose pull
118 | docker compose build
119 | docker compose up -d
120 | ```
121 | 5. Создаем профиль в WireGuard: `http://:51821`
122 | 6. Скачиваем профиль и переходим к клиентской части
123 |
124 | > [!NOTE]
125 | > Можно сделать дополнительные настройки в панели управления AdGuard Home: `http://:3000`
126 |
127 | ### WireGuard клиентская часть
128 | 1. [Установить компонент "WireGuard VPN"](https://help.keenetic.com/hc/ru/articles/360010592379-WireGuard-VPN)
129 | 2. Загрузить профиль скачанный с панели `Интернет` > `Другие подключения` > `Wireguard` > `Загрузить из файла`
130 | 3. Открываем загруженное подключение и ставим галочку на `Использовать для выхода в интернет`, меняем имя на `Antizapret` (необязательно)
131 | 4. `Сетевые правила` > `Маршрутизация`
132 | 1. `Добавить маршрут`
133 | 1. Тип маршрута: `Маршрут до узла`
134 | 2. Описание: `AntiZapretDNS`
135 | 3. Адрес узла назначения: `77.88.8.8`
136 | 4. Адрес шлюза: `пусто`
137 | 5. Интерфейс: `Antizapret` (если не меняли имя, то по имени файла)
138 | 6. Поставить галку `Добавлять автоматически`
139 | 2. `Добавить маршрут`
140 | 1. Тип маршрута: `Маршрут до сети`
141 | 2. Описание: `AntiZapret`
142 | 3. Адрес сети назначения: `10.224.0.0`
143 | 4. Маска подсети: `255.254.0.0/15`
144 | 5. Адрес шлюза: `пусто`
145 | 6. Интерфейс: `Antizapret` (если не меняли имя, то по имени файла)
146 | 5. `Сетевые правила` > `Интернет фильтры`
147 | 1. `Настройка DNS` > `Добавить профиль`
148 | 1. Имя профиля: `AntiZapret`
149 | 2. Транзит запросов: `НЕТ`
150 | 3. `Сохранить`
151 | 4. `Добавить сервер`
152 | 1. Тип сервера DNS: `По умолчанию`
153 | 2. IP-адрес: `77.88.8.8`
154 | 3. `Сохранить`
155 | 2. `Контентный фильтр`
156 | 1. Режим фильтрации: `Публичные DNS-резолверы`
157 | 2. Профили контентной фильтрации по умолчанию (`гостевая` и `домашняя`): `AntiZapret`
158 | 6. `Интернет` > `Ethernet`
159 | 1. Найти активное интернет подключение
160 | 1. Поставить галку `Игнорировать DNSv4 интернет-провайдера`
161 | 2. Поставить галку `Игнорировать DNSv6 интернет-провайдера`
162 |
163 | > [!NOTE]
164 | > Если используете Amnezia Wireguard, необходимо выполнить еще несколько действий
165 | [инструкции](https://docs.amnezia.org/ru/documentation/instructions/keenetic-os-awg)
166 | начиная с шага 20. Кратко продублирую тут.
167 |
168 | 1. Переходим в настройки, нажимаем на изображение шестеренки, в правом верхнем углу веб-страницы, и переходим по ссылке `Командная строка`.
169 | 2. Отправляем запрос: `show interface`
170 | 3. Теперь нужно узнать имя нужного интерфейса, по названию созданного ранее подключения. Для этого, откройте поиск по странице (это можно сделать, одновременно нажав две клавиши, Ctrl+F). Введите для поиска, название созданного ранее подключения. В данном примере, это `AntiZapret` . Должно быть найдено одно уникальное название в поле `description`. А рядом с ним будет находиться другое поле, `interface-name`, в котором отображается имя нужного интерфейса. В данном примере, это `Wireguard1`.
171 | 4. Теперь, зная имя интерфейса и значения параметров asc из файла в формате .conf который мы сохранили ранее. Нужно заменить все значения шаблона в скобках, Вашими значениями, а сами скобки удалить.
172 |
173 | `interface {name} wireguard asc {jc} {jmin} {jmax} {s1} {s2} {h1} {h2} {h3} {h4}`
174 |
175 | Для примера, получается вот такая строка:
176 | `interface Wireguard1 wireguard asc 8 50 1000 30 32 1811016522 1196729875 457766807 1765857463`
177 |
178 | Получившуюся строку, нужно вставить в вэб-версии командной строки роутера, и нажать кнопку "Отправить запрос".
179 | 5. Отправляем запрос: `system configuration save`
180 |
181 | В разделе `Интернет` > `Другие подключения` включаем подключение `AntiZapret`
182 |
183 | **Готово!**
184 |
185 | ## IPsec
186 | ### IPsec серверная часть
187 | В процессе написания
188 |
189 | ### IPsec клиентская часть
190 | В процессе написания
191 |
--------------------------------------------------------------------------------
/docs/guide_OpenWrt.md:
--------------------------------------------------------------------------------
1 | [OpenWRT](https://openwrt.org/) guide:
2 |
3 | 1. [Install needed packages](https://openwrt.org/docs/guide-user/services/vpn/openvpn/client-luci#install_needed_packages)
4 | 2. [Upload an OpenVPN config file](https://openwrt.org/docs/guide-user/services/vpn/openvpn/client-luci#b_upload_a_openvpn_config_file)
5 |
6 | **NOTE:** Change `dev tun` to a dedicated interface name like `dev tun1`.
7 |
8 | 3. Add the `antizapret` interface to `/etc/config/network`:
9 | ```
10 | config interface 'antizapret'
11 | option proto 'none'
12 | option device 'tun1'
13 | option defaultroute '0'
14 | option delegate '0'
15 | ```
16 | NOTE: tun1 - your TUN interface from [Step 2].
17 |
18 | 4. Add `antizapret` firewall zones configuration to `/etc/config/firewall`:
19 | ```
20 | config zone
21 | option name 'antizapret'
22 | option input 'REJECT'
23 | option output 'ACCEPT'
24 | option forward 'ACCEPT'
25 | list network 'antizapret'
26 | option mtu_fix '1'
27 | option masq '1'
28 |
29 | config forwarding
30 | option src 'lan'
31 | option dest 'antizapret'
32 |
33 | config forwarding
34 | option src 'antizapret'
35 | option dest 'wan'
36 | ```
37 |
38 | 5. Add the DNS intercept rule to `/etc/config/firewall`:
39 | ```
40 | config redirect 'dns_int'
41 | option name 'Intercept-DNS'
42 | option proto 'tcp udp'
43 | option src 'lan'
44 | option src_dport '53'
45 | option src_ip '!192.168.4.3'
46 | option target 'DNAT'
47 | option dest_ip '192.168.4.3'
48 | option dest 'lan'
49 | ```
50 |
51 | **NOTE:** `192.168.4.3` is your DNS server IP address.
52 |
53 | It may be a router address if you don't have any dedicated DNS resolvers (something like PiHole) in your network.
54 |
55 | 6. Add the DoT disable rule to `/etc/config/firewall`:
56 | ```
57 | config rule 'dot_deny'
58 | option name 'Deny-DoT'
59 | option src 'lan'
60 | option dest 'wan'
61 | option dest_port '853'
62 | option proto 'tcp udp'
63 | option target 'REJECT'
64 | option enabled '0'
65 | ```
66 | NOTE: Those 2 rules may make your clients angry, because this is a real DNS hijack.
67 |
68 | But it's on good purpose for now)
69 |
70 | See the obsolete [DNS hijacking](https://openwrt.org/docs/guide-user/firewall/fw3_configurations/intercept_dns#dns_hijacking) wiki for details.
71 |
72 | 7. Add the IPv6 rule to `/etc/config/firewall`:
73 | ```
74 | config rule
75 | option name 'Reject-IPv6'
76 | option family 'ipv6'
77 | list proto 'all'
78 | option src '*'
79 | option dest '*'
80 | option target 'REJECT'
81 | ```
82 | NOTE: This should completely disable IPv6 traffic forwarding to prevent DNS and traffic leaks because [the current solution](https://github.com/xtrime-ru/antizapret-vpn-docker) does not support IPv6.
83 |
84 | Feel free to disable IPv6 on individual interfaces too.
85 |
86 | 8. Disable DNS Rebind Protection in `/etc/config/dhcp`:
87 | ```
88 | config dnsmasq
89 | option rebind_protection '0'
90 | ```
91 |
92 | 9. Configure your upstream resolver to use antizapret DNS:
93 |
94 | * **Bare OpenWRT:**
95 | Set server in `/etc/config/dhcp`:
96 | ```
97 | config dnsmasq
98 | list server '192.168.100.1'
99 | ```
100 |
101 | * **PiHole:**
102 | CLI: Set server in `/etc/pihole/setupVars.conf`:
103 | ```
104 | PIHOLE_DNS_1=192.168.100.1
105 | ```
106 | Make sure there are no other PIHOLE_DNS_* records
107 |
108 | GUI: Go to [PiHole Admin](http://192.168.4.3/admin/settings.php?tab=dns), disable all predefined "Upstream DNS Servers," and set "Custom 1 (IPv4)" to `192.168.100.1`.
109 |
110 | * **Other resolvers:**
111 | Check your resolver manual.
112 |
--------------------------------------------------------------------------------
/scripts/docker-build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && cd ../services/antizapret && pwd )";
4 |
5 | exec docker buildx build --platform linux/amd64,linux/arm64 -t xtrime/antizapret-vpn:latest "$@" --build-arg DIST='1' --push "$SCRIPT_DIR"
6 |
--------------------------------------------------------------------------------
/services/antizapret/.dockerignore:
--------------------------------------------------------------------------------
1 | .dockerignore
2 | docker-compose.*
3 | Dockerfile*
4 |
--------------------------------------------------------------------------------
/services/antizapret/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.23 AS builder-api
2 | WORKDIR /app
3 | COPY ./api .
4 | RUN go build -o app main.go
5 |
6 |
7 | FROM ubuntu:24.04
8 |
9 | WORKDIR /root
10 |
11 | RUN <<-"EOT" bash -ex
12 | APT_LISTCHANGES_FRONTEND=none
13 | DEBIAN_FRONTEND=noninteractive
14 |
15 | apt-get update -q
16 | apt-get dist-upgrade -qy
17 | apt-get install -qqy --no-install-suggests --no-install-recommends \
18 | bsdmainutils \
19 | ca-certificates \
20 | iperf3 \
21 | curl \
22 | dnsutils \
23 | ferm \
24 | gawk \
25 | host \
26 | idn \
27 | inetutils-ping \
28 | ipcalc \
29 | ipcalc-ng \
30 | iptables \
31 | iproute2 \
32 | moreutils \
33 | nano \
34 | openssl \
35 | patch \
36 | procps \
37 | python3-dnslib \
38 | sipcalc \
39 | systemd-sysv \
40 | vim-tiny \
41 | apache2-utils \
42 | wget
43 | apt-get clean
44 | rm -frv /var/lib/apt/lists/*
45 | EOT
46 |
47 | COPY . /
48 |
49 | COPY --from=mikefarah/yq:4.45.1 /usr/bin/yq /usr/bin/yq
50 | COPY --from=adguard/adguardhome:v0.107.62 /opt/adguardhome /opt/adguardhome
51 | COPY --from=builder-api /app/app /opt/api/app
52 |
53 | RUN <<-"EOF" bash -ex
54 | cp /root/adguardhome/* /opt/adguardhome/conf
55 | EOF
56 |
57 | RUN <<-"EOF" bash -ex
58 | systemctl enable \
59 | antizapret-update.service \
60 | antizapret-update.timer \
61 | dnsmap \
62 | systemd-networkd \
63 | iperf3-server@1 \
64 | adguardhome \
65 | antizapret-api
66 |
67 | for list in antizapret/config/*-dist.txt; do
68 | sed -E '/^(#.*)?[[:space:]]*$/d' $list | sort | uniq | sponge $list
69 | done
70 |
71 | for list in antizapret/config/*-custom.txt; do rm -f $list; done
72 |
73 | ln -sf /root/antizapret/doall.sh /usr/bin/doall
74 | ln -sf /root/antizapret/dnsmap.py /usr/bin/dnsmap
75 |
76 | rm -frv /tmp/*
77 | EOF
78 |
79 | ARG DIST=false
80 | RUN <<-"EOF" bash -ex
81 | [ "$DIST" == false ] && exit 0
82 | export SKIP_UPDATE_FROM_ZAPRET=false
83 | export IP_LIST=https://raw.githubusercontent.com/zapret-info/z-i/master/dump.csv.gz
84 | export LISTS='
85 | https://raw.githubusercontent.com/zapret-info/z-i/master/nxdomain.txt;
86 | https://antifilter.download/list/domains.lst;
87 | ';
88 |
89 | (STAGE_1=true STAGE_2=true STAGE_3=false /root/antizapret/doall.sh)
90 | mkdir /root/antizapret/result_dist/
91 | mv /root/antizapret/result/* /root/antizapret/result_dist/
92 | EOF
93 |
94 | ENTRYPOINT ["/init.sh"]
95 |
--------------------------------------------------------------------------------
/services/antizapret/api/go.mod:
--------------------------------------------------------------------------------
1 | module antizapret-api
2 |
3 | go 1.23
4 |
--------------------------------------------------------------------------------
/services/antizapret/api/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "log"
7 | "net/http"
8 | "os"
9 | "os/exec"
10 | "sync"
11 | )
12 |
13 | var isScriptRunning bool
14 | var mu sync.Mutex
15 |
16 |
17 | type DoAllRequest struct {
18 | Stage1 bool `json:"stage_1"`
19 | Stage2 bool `json:"stage_2"`
20 | Stage3 bool `json:"stage_3"`
21 | }
22 |
23 | func doallHandler(w http.ResponseWriter, r *http.Request) {
24 | if r.Method != http.MethodPost {
25 | http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
26 | return
27 | }
28 |
29 | mu.Lock()
30 | if isScriptRunning {
31 | mu.Unlock()
32 | http.Error(w, "Script is still running", http.StatusTooEarly)
33 | return
34 | }
35 | isScriptRunning = true
36 | mu.Unlock()
37 |
38 | defer func() {
39 | mu.Lock()
40 | isScriptRunning = false
41 | mu.Unlock()
42 | }()
43 |
44 | var req DoAllRequest
45 | if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
46 | http.Error(w, "Invalid request body", http.StatusBadRequest)
47 | return
48 | }
49 |
50 | env := os.Environ()
51 | env = append(env, fmt.Sprintf("STAGE_1=%t", req.Stage1))
52 | env = append(env, fmt.Sprintf("STAGE_2=%t", req.Stage2))
53 | env = append(env, fmt.Sprintf("STAGE_3=%t", req.Stage3))
54 |
55 | cmd := exec.Command("/root/antizapret/doall.sh")
56 | cmd.Env = env
57 |
58 | output, err := cmd.CombinedOutput()
59 |
60 | if err != nil {
61 | http.Error(w, fmt.Sprintf("Failed to execute script: %s", err.Error()), http.StatusInternalServerError)
62 | return
63 | }
64 |
65 | w.WriteHeader(http.StatusOK)
66 | _, _ = w.Write(output)
67 | }
68 |
69 | func main() {
70 | http.HandleFunc("/doall", doallHandler)
71 |
72 | fmt.Println("Starting server on http://localhost:8080")
73 | log.Fatal(http.ListenAndServe(":8080", nil))
74 | }
--------------------------------------------------------------------------------
/services/antizapret/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | antizapret:
3 | image: xtrime/antizapret-vpn
4 | hostname: core.antizapret
5 | restart: unless-stopped
6 | stop_signal: SIGRTMIN+4
7 | privileged: true
8 | build: .
9 | logging:
10 | driver: json-file
11 | options:
12 | max-size: 100k
13 | max-file: 2
14 | volumes:
15 | - /etc/localtime:/etc/localtime:ro
16 | - $PWD/config/antizapret/custom:/root/antizapret/config/custom
17 | - $PWD/config/antizapret/result:/root/antizapret/result
18 | - $PWD/config/adguard/conf:/opt/adguardhome/conf
19 | - $PWD/config/adguard/work:/opt/adguardhome/work
20 | # dns:
21 | # - 8.8.8.8
22 | ports:
23 | - 3000:3000/tcp
24 | environment:
25 | - |
26 | ROUTES=
27 | openvpn:10.1.165.0/24;
28 | wireguard-amnezia:10.1.166.0/24;
29 | wireguard:10.1.166.0/24;
30 | ipsec:10.1.163.0/24;
31 | ipsec:10.1.162.0/24
32 | - |
33 | LISTS=
34 | https://raw.githubusercontent.com/zapret-info/z-i/master/nxdomain.txt;
35 | https://antifilter.download/list/domains.lst;
36 | - IP_LIST=https://raw.githubusercontent.com/zapret-info/z-i/master/dump.csv.gz
37 | - SKIP_UPDATE_FROM_ZAPRET
38 | - ADGUARDHOME_PORT
39 | - ADGUARDHOME_USERNAME
40 | - ADGUARDHOME_PASSWORD
41 | - DNS
42 |
--------------------------------------------------------------------------------
/services/antizapret/etc/ferm/ferm.conf:
--------------------------------------------------------------------------------
1 | domain (ip ip6) {
2 | table filter {
3 | chain (DOCKER DOCKER-INGRESS DOCKER-ISOLATION-STAGE-1 DOCKER-ISOLATION-STAGE-2 FORWARD) @preserve;
4 | }
5 |
6 | table nat {
7 | chain (DOCKER DOCKER_OUTPUT DOCKER_POSTROUTING DOCKER-INGRESS PREROUTING OUTPUT POSTROUTING) @preserve;
8 | }
9 | }
10 |
11 | @def $DOCKER_RANGE = 172.0.0.0/8;
12 | @def $DNSMAP_RANGE = 10.224.0.0/15;
13 | @def $VIRUAL_HOST = 10.224.0.1/32;
14 |
15 | table nat {
16 | chain dnsmap {}
17 | chain POSTROUTING {
18 | # MASQUERADE network to internet
19 | outerface eth0 MASQUERADE;
20 | }
21 | chain (PREROUTING OUTPUT) {
22 | # Redirect VIRUAL_HOST to self
23 | daddr $VIRUAL_HOST REDIRECT;
24 |
25 | # Redirect from DOCKER_RANGE to DNSMAP_RANGE via dnsmap chain
26 | daddr $DNSMAP_RANGE jump dnsmap;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/services/antizapret/etc/sysctl.d/10-conntrack.conf:
--------------------------------------------------------------------------------
1 | net.netfilter.nf_conntrack_max=102400
2 |
3 | net.netfilter.nf_conntrack_generic_timeout = 600
4 | net.netfilter.nf_conntrack_icmp_timeout = 30
5 | net.netfilter.nf_conntrack_tcp_timeout_close = 10
6 | net.netfilter.nf_conntrack_tcp_timeout_close_wait = 60
7 | net.netfilter.nf_conntrack_tcp_timeout_established = 1800
8 | net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 120
9 | net.netfilter.nf_conntrack_tcp_timeout_last_ack = 30
10 | net.netfilter.nf_conntrack_tcp_timeout_max_retrans = 300
11 | net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 60
12 | net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 120
13 | net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120
14 | net.netfilter.nf_conntrack_tcp_timeout_unacknowledged = 300
15 | net.netfilter.nf_conntrack_udp_timeout = 120
16 | net.netfilter.nf_conntrack_udp_timeout_stream = 180
17 |
--------------------------------------------------------------------------------
/services/antizapret/etc/sysctl.d/20-network.conf:
--------------------------------------------------------------------------------
1 | net.ipv4.ip_forward=1
2 | net.ipv4.tcp_slow_start_after_idle = 0
3 | net.ipv4.tcp_fastopen = 3
4 | net.ipv4.tcp_rmem = 4096 262143 4194304
5 | net.core.rmem_max = 4194304
6 | net.core.rmem_default = 262143
7 | net.ipv4.tcp_wmem = 4096 262143 4194304
8 | net.core.wmem_max = 4194304
9 | net.core.wmem_default = 262143
10 |
11 | net.ipv4.tcp_keepalive_time = 600
12 | net.ipv4.tcp_keepalive_intvl = 120
13 | net.ipv4.tcp_keepalive_probes = 3
14 |
15 | net.ipv4.tcp_fin_timeout = 10
16 | net.ipv4.tcp_retries2 = 5
17 |
18 | net.ipv4.tcp_congestion_control = bbr
19 | net.ipv4.conf.default.route_localnet=1
--------------------------------------------------------------------------------
/services/antizapret/etc/systemd/journald.conf:
--------------------------------------------------------------------------------
1 | # This file is part of systemd.
2 | #
3 | # systemd is free software; you can redistribute it and/or modify it
4 | # under the terms of the GNU Lesser General Public License as published by
5 | # the Free Software Foundation; either version 2.1 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # Entries in this file show the compile time defaults.
9 | # You can change settings by editing this file.
10 | # Defaults can be restored by simply deleting this file.
11 | #
12 | # See journald.conf(5) for details.
13 |
14 | [Journal]
15 | Storage=volatile
16 | #Compress=yes
17 | #Seal=yes
18 | #SplitMode=uid
19 | #SyncIntervalSec=5m
20 | #RateLimitIntervalSec=30s
21 | #RateLimitBurst=1000
22 | SystemMaxUse=16M
23 | #SystemKeepFree=
24 | #SystemMaxFileSize=
25 | #SystemMaxFiles=100
26 | RuntimeMaxUse=8M
27 | #RuntimeKeepFree=
28 | #RuntimeMaxFileSize=
29 | #RuntimeMaxFiles=100
30 | #MaxRetentionSec=
31 | #MaxFileSec=1month
32 | #ForwardToSyslog=yes
33 | #ForwardToKMsg=no
34 | #ForwardToConsole=no
35 | #ForwardToWall=yes
36 | #TTYPath=/dev/console
37 | #MaxLevelStore=debug
38 | #MaxLevelSyslog=debug
39 | #MaxLevelKMsg=notice
40 | #MaxLevelConsole=info
41 | #MaxLevelWall=emerg
--------------------------------------------------------------------------------
/services/antizapret/etc/systemd/network/eth.network:
--------------------------------------------------------------------------------
1 | [Match]
2 | Name=eth*
3 |
4 | [Network]
5 | DHCP=yes
6 |
--------------------------------------------------------------------------------
/services/antizapret/etc/systemd/network/host.network:
--------------------------------------------------------------------------------
1 | [Match]
2 | Name=host*
3 |
4 | [Network]
5 | DHCP=yes
6 |
--------------------------------------------------------------------------------
/services/antizapret/etc/systemd/system/adguardhome.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Adguard
3 | After=network-online.target
4 | Wants=network-online.target
5 | StartLimitIntervalSec=0
6 |
7 | [Service]
8 | WorkingDirectory=/opt/adguardhome/work
9 | ExecStart=/opt/adguardhome/AdGuardHome -w /opt/adguardhome/work -c /opt/adguardhome/conf/AdGuardHome.yaml
10 | EnvironmentFile=/etc/default/antizapret
11 | User=root
12 | Restart=always
13 | RestartSec=1
14 |
15 | [Install]
16 | WantedBy=multi-user.target
17 |
--------------------------------------------------------------------------------
/services/antizapret/etc/systemd/system/antizapret-api.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=AntiZapret API Service
3 | After=network.target
4 |
5 | [Service]
6 | Type=simple
7 | WorkingDirectory=/opt/api
8 | ExecStart=/opt/api/app
9 | Restart=always
10 | RestartSec=1
11 |
12 | [Install]
13 | WantedBy=multi-user.target
14 |
--------------------------------------------------------------------------------
/services/antizapret/etc/systemd/system/antizapret-update.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=antizapret-vpn update
3 | After=network-online.target
4 | Wants=network-online.target
5 |
6 | [Service]
7 | WorkingDirectory=/root/antizapret
8 | ExecStart=/usr/bin/doall
9 | EnvironmentFile=/etc/default/antizapret
10 |
11 | [Install]
12 | WantedBy=multi-user.target
13 |
--------------------------------------------------------------------------------
/services/antizapret/etc/systemd/system/antizapret-update.timer:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Run antizapret-vpn update every 6h
3 |
4 | [Timer]
5 | OnUnitActiveSec=6h
6 |
7 | [Install]
8 | WantedBy=timers.target
--------------------------------------------------------------------------------
/services/antizapret/etc/systemd/system/dnsmap.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=dnsmap
3 | After=network.target
4 |
5 | [Service]
6 | ExecStart=/usr/bin/dnsmap -a 127.0.0.4 --iprange 10.224.0.0/15
7 | EnvironmentFile=/etc/default/antizapret
8 |
9 | [Install]
10 | WantedBy=multi-user.target
--------------------------------------------------------------------------------
/services/antizapret/etc/systemd/system/iperf3-server@.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=iperf3 server
3 | After=syslog.target network.target
4 |
5 | [Service]
6 | ExecStart=/usr/bin/iperf3 -s -1
7 | Restart=always
8 | RuntimeMaxSec=3600
9 |
10 | [Install]
11 | WantedBy=multi-user.target
12 | DefaultInstance=5201
--------------------------------------------------------------------------------
/services/antizapret/etc/systemd/system/systemd-networkd-wait-online.service.d/override.conf:
--------------------------------------------------------------------------------
1 | [Service]
2 | ExecStart=
3 | ExecStart=sleep 0.1
4 |
--------------------------------------------------------------------------------
/services/antizapret/init.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 | set -x
5 |
6 | # run commands after systemd initialization
7 | function postrun () {
8 | local waiter="until ps -p 1 | grep -q systemd; do sleep 0.1; done"
9 | nohup bash -c "$waiter; $@" &
10 | }
11 |
12 |
13 | # resolve domain address to ip address
14 | function resolve () {
15 | # $1 domain/ip address, $2 fallback ip address
16 | ipcalc () { ipcalc-ng --no-decorate -o $1 2> /dev/null; }
17 | echo "$(ipcalc $1 || echo $2)"
18 | }
19 |
20 |
21 | ADGUARDHOME_USERNAME=${ADGUARDHOME_USERNAME:-"admin"}
22 | if [[ -n $ADGUARDHOME_PASSWORD ]]; then
23 | ADGUARDHOME_PASSWORD_HASH=$(htpasswd -B -C 10 -n -b "$ADGUARDHOME_USERNAME" "$ADGUARDHOME_PASSWORD")
24 | ADGUARDHOME_PASSWORD_HASH=${ADGUARDHOME_PASSWORD_HASH#*:}
25 | fi
26 |
27 |
28 | # save DNS variables to /etc/default/antizapret
29 | # in order to systemd services can access them
30 | cat << EOF | sponge /etc/default/antizapret
31 | PYTHONUNBUFFERED=1
32 | SELF_IP=$(hostname -i)
33 | DOCKER_SUBNET=$(ip r | awk '/default/ {dev=$5} !/default/ && $0 ~ dev {print $1}')
34 | SKIP_UPDATE_FROM_ZAPRET=${SKIP_UPDATE_FROM_ZAPRET:-false}
35 | UPDATE_TIMER=${UPDATE_TIMER:-"6h"}
36 | ROUTES='${ROUTES:-""}'
37 | IP_LIST='${IP_LIST:-""}'
38 | LISTS='${LISTS:-""}'
39 | ADGUARDHOME_PORT=${ADGUARDHOME_PORT:-"3000"}
40 | ADGUARDHOME_USERNAME='${ADGUARDHOME_USERNAME}'
41 | ADGUARDHOME_PASSWORD_HASH='${ADGUARDHOME_PASSWORD_HASH}'
42 | DNS=${DNS:-"8.8.8.8"}
43 | LC_ALL=C.UTF-8
44 | EOF
45 | source /etc/default/antizapret
46 | # autoload vars when logging in into shell with 'bash -l'
47 | ln -sf /etc/default/antizapret /etc/profile.d/antizapret.sh
48 |
49 |
50 | # creating custom hosts files if they have not yet been initialized
51 | for file in $(echo {exclude,include}-{hosts,ips,regexp}-custom.txt); do
52 | path=/root/antizapret/config/custom/$file
53 | [ ! -f $path ] && touch $path
54 | done
55 |
56 | rm /root/antizapret/config/custom/include-regexp-custom.txt
57 |
58 | # add routes from env ROUTES
59 | postrun 'while true; do /routes.sh; sleep 10; done'
60 |
61 | # output systemd logs to docker logs since container boot
62 | postrun 'until [[ "$(systemctl is-active systemd-journald)" == "active" ]]; do sleep 1; done; journalctl --boot --follow --lines=all --no-hostname'
63 |
64 | # AdGuard initialization
65 | /bin/cp --update=none /root/adguardhome/* /opt/adguardhome/conf/
66 | [ -d /root/antizapret/result_dist ] && /bin/cp --update=none /root/antizapret/result_dist/* /root/antizapret/result/
67 | [ -f /root/antizapret/result/adguard_upstream_dns_file ] && /bin/cp --update=none /root/antizapret/result/adguard_upstream_dns_file /opt/adguardhome/conf/upstream_dns_file
68 |
69 | yq -i '
70 | .http.address="0.0.0.0:'$ADGUARDHOME_PORT'" |
71 | .users[0].name="'$ADGUARDHOME_USERNAME'" |
72 | .users[0].password="'$ADGUARDHOME_PASSWORD_HASH'" |
73 | .dns.bind_hosts=["127.0.0.1","'$SELF_IP'"]
74 | ' /opt/adguardhome/conf/AdGuardHome.yaml
75 |
76 | # systemd init
77 | exec /usr/sbin/init
78 |
--------------------------------------------------------------------------------
/services/antizapret/root/adguardhome/AdGuardHome.yaml:
--------------------------------------------------------------------------------
1 | http:
2 | pprof:
3 | port: 6060
4 | enabled: false
5 | address: 0.0.0.0:300
6 | session_ttl: 720h
7 | users:
8 | - name: admin
9 | password: ""
10 | auth_attempts: 5
11 | block_auth_min: 15
12 | http_proxy: ""
13 | language: ""
14 | theme: auto
15 | dns:
16 | bind_hosts:
17 | - 127.0.0.1
18 | - 10.224.0.1
19 | port: 53
20 | anonymize_client_ip: false
21 | ratelimit: 0
22 | ratelimit_subnet_len_ipv4: 24
23 | ratelimit_subnet_len_ipv6: 56
24 | ratelimit_whitelist: []
25 | refuse_any: true
26 | upstream_dns:
27 | upstream_dns_file: /opt/adguardhome/conf/upstream_dns_file
28 | bootstrap_dns:
29 | - 8.8.8.8
30 | - 9.9.9.10
31 | - 149.112.112.10
32 | - 2620:fe::10
33 | - 2620:fe::fe:10
34 | fallback_dns:
35 | - tcp://77.88.8.8
36 | - tcp://8.8.8.8
37 | - tcp://1.1.1.1
38 | upstream_mode: load_balance
39 | fastest_timeout: 1s
40 | allowed_clients: []
41 | disallowed_clients: []
42 | blocked_hosts:
43 | - version.bind
44 | - id.server
45 | - hostname.bind
46 | trusted_proxies:
47 | - 127.0.0.0/8
48 | - ::1/128
49 | cache_size: 4194304
50 | cache_ttl_min: 0
51 | cache_ttl_max: 0
52 | cache_optimistic: true
53 | bogus_nxdomain: []
54 | aaaa_disabled: true
55 | enable_dnssec: false
56 | edns_client_subnet:
57 | custom_ip: "77.88.8.8"
58 | enabled: true
59 | use_custom: true
60 | max_goroutines: 300
61 | handle_ddr: true
62 | ipset: []
63 | ipset_file: ""
64 | bootstrap_prefer_ipv6: false
65 | upstream_timeout: 1s
66 | private_networks: []
67 | use_private_ptr_resolvers: false
68 | local_ptr_upstreams: []
69 | use_dns64: false
70 | dns64_prefixes: []
71 | serve_http3: false
72 | use_http3_upstreams: false
73 | serve_plain_dns: true
74 | hostsfile_enabled: true
75 | tls:
76 | enabled: false
77 | server_name: ""
78 | force_https: false
79 | port_https: 443
80 | port_dns_over_tls: 853
81 | port_dns_over_quic: 853
82 | port_dnscrypt: 0
83 | dnscrypt_config_file: ""
84 | allow_unencrypted_doh: false
85 | certificate_chain: ""
86 | private_key: ""
87 | certificate_path: ""
88 | private_key_path: ""
89 | strict_sni_check: false
90 | querylog:
91 | dir_path: ""
92 | ignored: []
93 | interval: 24h
94 | size_memory: 1000
95 | enabled: true
96 | file_enabled: true
97 | statistics:
98 | dir_path: ""
99 | ignored: []
100 | interval: 24h
101 | enabled: true
102 | filters:
103 | - enabled: true
104 | url: https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt
105 | name: AdGuard DNS filter
106 | id: 1
107 | - enabled: false
108 | url: https://adguardteam.github.io/HostlistsRegistry/assets/filter_2.txt
109 | name: AdAway Default Blocklist
110 | id: 2
111 | whitelist_filters: []
112 | user_rules:
113 | - '#||*^$dnstype=HTTPS'
114 | dhcp:
115 | enabled: false
116 | interface_name: ""
117 | local_domain_name: lan
118 | dhcpv4:
119 | gateway_ip: ""
120 | subnet_mask: ""
121 | range_start: ""
122 | range_end: ""
123 | lease_duration: 86400
124 | icmp_timeout_msec: 1000
125 | options: []
126 | dhcpv6:
127 | range_start: ""
128 | lease_duration: 86400
129 | ra_slaac_only: false
130 | ra_allow_slaac: false
131 | filtering:
132 | blocking_ipv4: ""
133 | blocking_ipv6: ""
134 | blocked_services:
135 | schedule:
136 | time_zone: Local
137 | ids: []
138 | protection_disabled_until: null
139 | safe_search:
140 | enabled: false
141 | bing: true
142 | duckduckgo: true
143 | ecosia: true
144 | google: true
145 | pixabay: true
146 | yandex: true
147 | youtube: true
148 | blocking_mode: default
149 | parental_block_host: family-block.dns.adguard.com
150 | safebrowsing_block_host: standard-block.dns.adguard.com
151 | rewrites: []
152 | safe_fs_patterns:
153 | - /opt/adguardhome/work/userfilters/*
154 | safebrowsing_cache_size: 1048576
155 | safesearch_cache_size: 1048576
156 | parental_cache_size: 1048576
157 | cache_time: 30
158 | filters_update_interval: 24
159 | blocked_response_ttl: 10
160 | filtering_enabled: true
161 | parental_enabled: false
162 | safebrowsing_enabled: false
163 | protection_enabled: true
164 | clients:
165 | runtime_sources:
166 | whois: true
167 | arp: true
168 | rdns: true
169 | dhcp: true
170 | hosts: true
171 | persistent: []
172 | log:
173 | enabled: true
174 | file: ""
175 | max_backups: 0
176 | max_size: 100
177 | max_age: 3
178 | compress: false
179 | local_time: false
180 | verbose: false
181 | os:
182 | group: ""
183 | user: ""
184 | rlimit_nofile: 0
185 | schema_version: 28
186 |
--------------------------------------------------------------------------------
/services/antizapret/root/adguardhome/upstream_dns_file_basis:
--------------------------------------------------------------------------------
1 | 8.8.8.8
2 | 8.8.4.4
3 | 9.9.9.11
4 | 149.112.112.11
5 |
6 | [/akamai.net/akamaiedge.net/akadns.net/microsoft.com/ru/su/xn--p1ai/]77.88.8.8
7 | [/*.antizapret/]127.0.0.11
8 | [/themoviedb.org/tmdb.org/tmdb-image-prod.b-cdn.net/]1.1.1.1
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/config/custom/exclude-hosts-custom.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtrime-ru/antizapret-vpn-docker/667094a1cb4413f99a916c08a0224dd224364604/services/antizapret/root/antizapret/config/custom/exclude-hosts-custom.txt
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/config/custom/exclude-ips-custom.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtrime-ru/antizapret-vpn-docker/667094a1cb4413f99a916c08a0224dd224364604/services/antizapret/root/antizapret/config/custom/exclude-ips-custom.txt
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/config/custom/exclude-regexp-custom.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtrime-ru/antizapret-vpn-docker/667094a1cb4413f99a916c08a0224dd224364604/services/antizapret/root/antizapret/config/custom/exclude-regexp-custom.txt
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/config/custom/include-hosts-custom.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtrime-ru/antizapret-vpn-docker/667094a1cb4413f99a916c08a0224dd224364604/services/antizapret/root/antizapret/config/custom/include-hosts-custom.txt
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/config/custom/include-ips-custom.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtrime-ru/antizapret-vpn-docker/667094a1cb4413f99a916c08a0224dd224364604/services/antizapret/root/antizapret/config/custom/include-ips-custom.txt
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/config/exclude-hosts-by-ips-dist.txt:
--------------------------------------------------------------------------------
1 | ^81\.91\.178\.252;
2 | ^37\.48\.77\.229;
3 | ^178\.208\.90\.38;
4 | ^213\.13\.30\.100;
5 | ^52\.169\.125\.34;
6 | ^81\.91\.178\.242;
7 | ^5\.61\.58\.119;
8 | ^45\.81\.227\.72;
9 | ^209\.99\.40\.222;
10 | ^95\.211\.189\.202;
11 | ^34\.252\.217\.230;
12 | ^103\.224\.212\.222;
13 |
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/config/exclude-hosts-dist.txt:
--------------------------------------------------------------------------------
1 | themoviedb.org
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/config/exclude-ips-dist.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtrime-ru/antizapret-vpn-docker/667094a1cb4413f99a916c08a0224dd224364604/services/antizapret/root/antizapret/config/exclude-ips-dist.txt
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/config/exclude-regexp-dist.txt:
--------------------------------------------------------------------------------
1 | duckdns
2 | linode\.com
3 | upcloud\.com
4 | \.sl\.pt
5 | \.biz\.ski
6 | \.sloat\.biz
7 | \.new-rutor\.org
8 | \.traderc\.biz
9 | \.o-q\.biz
10 | \.dcge\.biz
11 | zigzag
12 | winline
13 | paripartners
14 | parimatch
15 | ligastavok
16 | liga-stavok
17 | baltplay
18 | azino777
19 | azino.*777
20 | 777.*azino
21 | vulkan
22 | ru\.leon
23 | ru\.adleon
24 | leonaccess
25 | leon-[0-9]{3}
26 | pm-[0-9]{2,3}\.
27 | mf-[0-9]{2,3}\.online
28 | fon-[0-9]{2,3}\.
29 | most.{3}\.
30 | bcity\-
31 | 1x\-
32 | 1xmob
33 | bk\-info
34 | bkinfo
35 | marathon
36 | gaminator
37 | #/joycasino
38 | goldenstar
39 | marafon
40 | olimp
41 | kasino
42 | depozit
43 | kazino
44 | #/777
45 | cas1no
46 | casino
47 | cassino
48 | caseno
49 | cazino
50 | admiral
51 | zerkala
52 | avtomat
53 | igrat
54 | azart
55 | sloty
56 | ^bk-
57 | ^bkr
58 | bkinf0
59 | bukmeker
60 | ruletka
61 | vulcan
62 | vylkan
63 | wulcan
64 | wulkan
65 | vullkan
66 | volcan
67 | ^vlc
68 | ^vlk
69 | eldorado
70 | lotto
71 | lottery
72 | fbmetrix
73 | ^diplom-
74 | ^dosug-
75 | ^dosug[0-9]{2}
76 | ^hydra[0-9]{2}
77 | ^intim[0-9]{2}
78 | ^livetv[0-9]{2}
79 | marafon
80 | #/^melb
81 | ^melm
82 | ^mf-[0-9]{2}
83 | ^most
84 | #/^new-
85 | ^pari-
86 | ^pokerdom
87 | prostitutki
88 | spravka
89 | mossst
90 | diplom
91 | pharaon
92 | fortuna
93 | ^rotate
94 | ^ref.{5}\.
95 | play\-
96 | ^1w.{3,4}\.
97 | ^mylove[0-9]{2,3}\.
98 | #/^1x.{3,4}\.
99 | ^mirror[0-9]{2,3}\.
100 | ^mob.{3,4}\.
101 | #/^777
102 | hydra
103 | spravok
104 | spravka
105 | zenit
106 | zakladki
107 | vullcan
108 | vulslots
109 | slots
110 | traffaccess
111 | tide24
112 | swleon
113 | sportingbull
114 | sokol-24
115 | silmag
116 | faraon
117 | joycazino
118 | joy-cazino
119 | jackpot
120 | semyanich
121 | semenarnia
122 | prostitutki
123 | shishkin-semena
124 | vulkanstavka
125 | bukvaved
126 | rastarasha
127 | errors-seeds
128 | #/casino-x
129 | kinogb
130 | vulkanstars
131 | vlk-slots
132 | rutorg
133 | parimatch
134 | azartplay
135 | bbplay2017
136 | baltplay2017
137 | hiwager
138 | seedbanda
139 | #/gidonline
140 | ^alco
141 | multikland\.net
142 | synchroncode\.com
143 | placehere\.link
144 | delivembed\.cc
145 | svetacdn\.in
146 | ^a[bdfk]-[0-9]{5}
147 | ^azimob[0-9]{5}
148 | ^goldfishka[0-9]{2,3}\.
149 | ^kinovod[0-9]{2,3}\.cc
150 | ^lite-1x
151 | ^livetv[0-9]{2,3}.me
152 | ^ox-[0-9]{5}
153 | ^partypoker[0-9]{3,5}\.com
154 | ^pin-up[0-9]{2,3}\.
155 | ^pinup[0-9]{2,3}\.
156 | ^pinupbk[0-9]{2,3}\.
157 | ^zfilm-hd-[0-9]{3,4}\.
158 | appspot\.online
159 | alko.*[0-9]{2,3}\.
160 | alco.*[0-9]{2,3}\.
161 | wylkan
162 | wull[kc]an
163 | wlnstar
164 | wlnsport
165 | vigronn
166 | viagravnn
167 | vegas-grand
168 | ^vavada
169 |
170 | te[hx]osmotr
171 | udostoverenie
172 | tabak
173 | swissking
174 | sverhestestvennoe
175 | ^super
176 | ^study-
177 | ^stream
178 | strahov
179 | st-official
180 | stavk[ia]
181 | sprav
182 | ^sslkn
183 | spt-trejd-
184 | sporligtv
185 | ^spirt-
186 | ^sol-
187 | ^solaris
188 | ^sofosbuvir-
189 | ^slottica
190 | ^slotozal-
191 | ^semenacanabis
192 | ^selektor
193 | ^selector
194 | ^seedbaza
195 | ^ru-steroid
196 | ^refpa
197 | ^putlocker
198 | ^prava-
199 | ^onex
200 | ^omgomgomg5
201 | ^official-
202 | ^livetv[0-9]*\.
203 | ^leon-official
204 | ^leon-registration
205 | ^kupit
206 | ^kinovod[0-9]*\.
207 | ^eldo
208 | ^bkin-
209 | ^bitstar
210 | ^bestpharma
211 | ^balashiha-grand
212 | ^apl[0-9]*\.
213 | dot-xenon-antonym
214 | ^zfilm-
215 | 1-{0,1}xredir
216 | 1-{0,1}slot
217 | 1-{0,1}sport
218 | apteka
219 | do[ck]tor
220 | ^booi
221 | ^brill
222 | goldfishka
223 | ^777
224 | ^888
225 | ^apl[0-9]
226 | ^aviator
227 | ^azimut
228 | ^azino
229 | ^bestseeds-
230 | ^bitstarz
231 | ^blacksprut
232 | ^bongacams[0-9]
233 | ^bublik
234 | ^cabura
235 | ^champion-
236 | ^fort-prav
237 | ^fortprav
238 | ^g-trade
239 | ^indi[0-9]
240 | ^intimp[0-9]
241 | ^izzi-
242 | zfilm-hd
243 | zfilm[0-9]
244 | zhahach
245 | zeralo-v-a-v-a-d-a
246 | vavada
247 | wawada
248 | zaliv-
249 | zakon-kamennyh-dzhungley
250 | zakis-
251 | ^zakis
252 | ^zagon
253 | zarabot
254 | ^vzlom
255 | ^v[uy][l1][ck]
256 | ^vuzinfo
257 | ^up-x
258 | ^up[0-9]
259 | ^u[0-9][^0-9]
260 | ^trade
261 | rastishki
262 | rasta-
263 | quantum
264 | ^prava
265 | 1-xred
266 | 1xslo
267 | ^202[0123]
268 | ^apl
269 | ^apparat
270 | ^avalon
271 | ^azino
272 | ^azzino
273 | ^bank[^\.]
274 | ^bbrrigght
275 | ^beer
276 | ^belochka
277 | ^bonus
278 |
279 | # 25.07.2024
280 | ^100
281 | ^1xb
282 | ^1-xb
283 | ^7k-
284 | ^adm
285 | ^advokat
286 | ^agent
287 | ^aitfin
288 | ^ai-
289 | ^alepox
290 | ^alextra
291 | ^alletoper
292 | ^allserial
293 | ^allsteroid
294 | ^allxrtgof
295 | ^alrafiofs
296 | ^amarket
297 | ^anomiks
298 | ^answer
299 | ^apl.*\.me$
300 | ^aqua
301 | ^argo
302 | ^arteif
303 | ^ashoo
304 | ^astellia
305 | ^athletic
306 | ^binarium
307 | ^bitstar
308 | ^bkleon
309 | ^block4
310 | ^bo11y
311 | ^bollywood
312 | ^bomdogmas
313 | ^bomobd
314 | ^bs2
315 | ^crystal
316 | ^daclatasvir
317 | ^djplom
318 | ^drag
319 | ^drift
320 | ^fairspin
321 | ^go-game
322 | ^klub
323 | ^kraken
324 | ^livetv[0-9]*\.me$
325 | ^megamarket
326 | ^moskva-prava
327 | ^pinup
328 | ^pin-up
329 | ^ramen
330 | ^salon
331 | ^sam-poehal
332 | ^schetchik
333 |
334 | \.bet$
335 | \.win$
336 | lordfilm
337 | webtrader
338 |
339 | ^[0-9\-]+\.
340 |
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/config/include-hosts-dist.txt:
--------------------------------------------------------------------------------
1 | # root domains
2 | com.ua
3 | ua
4 |
5 |
6 | # global
7 | acf.international
8 | adguard.com
9 | amazfitwatchfaces.com
10 | bbci.co.uk
11 | buymeacoffee.com
12 | cdninstagram.com
13 | cloudflare.com
14 | cloudfront.net
15 | deezer.com
16 | fanatical.com
17 | game-debate.com
18 | getoutline.com
19 | intercomcdn.com
20 | lib.ru
21 | licdn.com
22 | lostfilm.tv
23 | pravdabeslana.ru
24 | radiojar.com
25 | readybot.io
26 | rebrand.ly
27 | redgifs.com
28 | seekvectorlogo.net
29 | simsync.io
30 | spotify.com
31 | strava.com
32 | swagger.io
33 | theins.ru
34 | wixmp.com
35 | reverb.com
36 | viber.com
37 |
38 | # youtube
39 | youtube.com
40 | youtu.be
41 | ytimg.com
42 | ggpht.com
43 | googleusercontent.com
44 | googlevideo.com
45 | youtubei.googleapis.com
46 |
47 |
48 | # google
49 | news.google.com
50 | chrome.google.com
51 |
52 | # gemini
53 | gemini.google.com
54 | proactivebackend-pa.googleapis.com
55 |
56 |
57 | # google play and android
58 | play.google.com
59 | google-analytics.com
60 | googleusercontent.com
61 | *gstatic.com
62 | *.gvt1.com
63 | *.ggpht.com
64 | dl.google.com
65 | dl-ssl.google.com
66 | android.com
67 | androidify.com
68 | android.apis.google.com
69 | android.clients.google.com
70 | *.gvt2.com
71 | *.gvt3.com
72 | googleplay.com
73 | play-fe.googleapis.com
74 | play-games.googleusercontent.com
75 | play-lh.googleusercontent.com
76 | play.googleapis.com
77 |
78 |
79 | # microsoft
80 | bing.com
81 | bing.net
82 | microsoft.com
83 | msn.com
84 | live.com
85 | microsoftonline.com
86 | bingapis.com
87 | cloud.microsoft
88 | office.com
89 |
90 |
91 | # facebook
92 | fbcdn.net
93 | messenger.com
94 | fb.com
95 |
96 |
97 | # twitter
98 | t.co
99 | twimg.com
100 | x.com
101 |
102 |
103 | # signal
104 | signal.org
105 |
106 |
107 | # smartbear
108 | smartbear.co
109 | smartbear.com
110 |
111 |
112 | # openai
113 | chatgpt.com
114 | oaistatic.com
115 | oaiusercontent.com
116 | openai.com
117 |
118 |
119 | # rutracker
120 | t-ru.org
121 | rutracker.org
122 | rutracker.cc
123 | rutrk.org
124 |
125 |
126 | # nnmclub
127 | nnm-club.ws
128 | nnmclub.ch
129 |
130 | # developer tools
131 | docker.com
132 | mongodb.com
133 | mongodb-cdn.com
134 | mongodb.net
135 | jetbrains.com
136 | code.org
137 | veeam.com
138 | digitalocean.com
139 | hashicorp.com
140 | terraform.io
141 | githubcopilot.com
142 | mbed.com
143 | analog.com
144 | microchip.com
145 | digikey.com
146 | te.com
147 | nxp.com
148 | brightcove.com
149 | brightcove.net
150 | schemaapp.com
151 | zencdn.net
152 | octopart-clicks.com
153 | octopart.com
154 | octostatic.com
155 | dell.com
156 | dellcdn.com
157 | ti.com
158 | mouser.com
159 | qualcomm.com
160 | usablenet.com
161 | recraft.ai
162 | hetzner.com
163 |
164 | #discord
165 | discord.com
166 | discord.gg
167 | discordapp.net
168 | discordapp.com
169 | discord.media
170 | discord-attachments-uploads-prd.storage.googleapis.com
171 |
172 | netflix.com
173 |
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/config/include-ips-dist.txt:
--------------------------------------------------------------------------------
1 | 104.109.143.0/24
2 | 66.22.192.0/18
3 | 35.192.0.0/11
4 | 34.0.192.0/18
5 |
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/dnsmap.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env -S python3 -u
2 | # -*- coding: utf-8 -*-
3 |
4 | from __future__ import print_function
5 |
6 | import socket, struct, subprocess
7 |
8 | from collections import deque
9 | from ipaddress import IPv4Network
10 |
11 | from dnslib import DNSRecord, RCODE, QTYPE, A
12 | from dnslib.server import DNSServer, DNSHandler, BaseResolver, DNSLogger
13 |
14 |
15 | class ProxyResolver(BaseResolver):
16 | """
17 | Proxy resolver - passes all requests to upstream DNS server and
18 | returns response
19 |
20 | Note that the request/response will be each be decoded/re-encoded
21 | twice:
22 |
23 | a) Request packet received by DNSHandler and parsed into DNSRecord
24 | b) DNSRecord passed to ProxyResolver, serialised back into packet
25 | and sent to upstream DNS server
26 | c) Upstream DNS server returns response packet which is parsed into
27 | DNSRecord
28 | d) ProxyResolver returns DNSRecord to DNSHandler which re-serialises
29 | this into packet and returns to client
30 |
31 | In practice this is actually fairly useful for testing but for a
32 | 'real' transparent proxy option the DNSHandler logic needs to be
33 | modified (see PassthroughDNSHandler)
34 |
35 | """
36 |
37 | def __init__(self,address,port,timeout,iprange,tablename='dnsmap'):
38 | self.address = address
39 | self.port = port
40 | self.timeout = timeout
41 | self.unassigned_addresses = deque([str(x) for x in IPv4Network(iprange).hosts()])
42 | # preserve first address from range for DNS
43 | del self.unassigned_addresses[0]
44 |
45 | self.ipmap = {}
46 | self.tablename = tablename
47 |
48 | # Load existing mappings
49 | get_mappings = "iptables-legacy -w -t nat -nL dnsmap | awk '{if (NR<3) {next}; sub(/to:/, \"\", $6); print $5,$6}'"
50 | output = subprocess.check_output(get_mappings, shell=True, encoding='utf-8')
51 | for mapped in output.split("\n"):
52 | if mapped:
53 | fake_addr, real_addr = mapped.split(' ')
54 | self.add_mapping(real_addr, fake_addr) or sys.exit(1)
55 | #self.unassigned_addresses.remove()
56 |
57 | def get_mapping(self, real_addr):
58 | return self.ipmap.get(real_addr)
59 |
60 | def add_mapping(self, real_addr, fake_addr=None):
61 | if self.get_mapping(real_addr):
62 | # Real addr is already mapped
63 | print("Real addr {} is already mapped".format(real_addr))
64 | return False
65 |
66 | if fake_addr:
67 | try:
68 | self.unassigned_addresses.remove(fake_addr)
69 | self.ipmap[real_addr]=fake_addr
70 | print('Mapping {} to {}'.format(fake_addr, real_addr))
71 | except ValueError:
72 | print("Fake addr {} not in unassigned addresses list".format(fake_addr))
73 | return False
74 | else:
75 | try:
76 | fake_addr = self.unassigned_addresses.popleft()
77 | except IndexError:
78 | print("ERROR: No IP addresses left!!!")
79 | return False
80 | print('Mapping {} to {}'.format(fake_addr, real_addr))
81 | self.ipmap[real_addr]=fake_addr
82 | set_mappings = f"iptables-legacy -w -t nat -A dnsmap -d '{fake_addr}' -j DNAT --to '{real_addr}'"
83 | subprocess.call(set_mappings, shell=True, encoding='utf-8')
84 | return fake_addr
85 | return True
86 |
87 | def resolve(self,request,handler):
88 | try:
89 | if handler.protocol == 'udp':
90 | proxy_r = request.send(self.address,self.port,
91 | timeout=self.timeout)
92 | else:
93 | proxy_r = request.send(self.address,self.port,
94 | tcp=True,timeout=self.timeout)
95 | reply = DNSRecord.parse(proxy_r)
96 |
97 | if request.q.qtype == QTYPE.AAAA or request.q.qtype == QTYPE.HTTPS:
98 | print('GOT AAAA or HTTPS')
99 | reply = request.reply()
100 | return reply
101 |
102 | if request.q.qtype == QTYPE.A:
103 | print('GOT A')
104 |
105 | newrr = []
106 | for record in reply.rr:
107 | if record.rtype == QTYPE.CNAME:
108 | continue
109 | newrr.append(record)
110 | reply.rr = newrr
111 |
112 | for record in reply.rr:
113 | if record.rtype != QTYPE.A:
114 | continue
115 |
116 | # print(dir(record))
117 | # print(type(record.rdata))
118 |
119 | real_addr = str(record.rdata)
120 | fake_addr = self.get_mapping(real_addr)
121 | if not fake_addr:
122 | fake_addr = self.add_mapping(real_addr)
123 | if not fake_addr:
124 | print("No fake_addr, something went wrong!")
125 | reply = request.reply()
126 | reply.header.rcode = getattr(RCODE,'SERVFAIL')
127 | return reply
128 |
129 | record.rdata = A(fake_addr)
130 | record.rname = request.q.qname
131 | record.ttl = 300
132 | # print(a.rdata)
133 | return reply
134 |
135 | # print(reply)
136 | except socket.timeout:
137 | reply = request.reply()
138 | reply.header.rcode = getattr(RCODE,'NXDOMAIN')
139 |
140 | return reply
141 |
142 |
143 | class PassthroughDNSHandler(DNSHandler):
144 | """
145 | Modify DNSHandler logic (get_reply method) to send directly to
146 | upstream DNS server rather then decoding/encoding packet and
147 | passing to Resolver (The request/response packets are still
148 | parsed and logged but this is not inline)
149 | """
150 | def get_reply(self,data):
151 | host,port = self.server.resolver.address,self.server.resolver.port
152 |
153 | request = DNSRecord.parse(data)
154 | self.log_request(request)
155 |
156 | if self.protocol == 'tcp':
157 | data = struct.pack("!H",len(data)) + data
158 | response = send_tcp(data,host,port)
159 | response = response[2:]
160 | else:
161 | response = send_udp(data,host,port)
162 |
163 | reply = DNSRecord.parse(response)
164 | self.log_reply(reply)
165 |
166 | return response
167 |
168 |
169 | def send_tcp(data,host,port):
170 | """
171 | Helper function to send/receive DNS TCP request
172 | (in/out packets will have prepended TCP length header)
173 | """
174 | sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
175 | sock.connect((host,port))
176 | sock.sendall(data)
177 | response = sock.recv(8192)
178 | length = struct.unpack("!H",bytes(response[:2]))[0]
179 | while len(response) - 2 < length:
180 | response += sock.recv(8192)
181 | sock.close()
182 | return response
183 |
184 |
185 | def send_udp(data,host,port):
186 | """
187 | Helper function to send/receive DNS UDP request
188 | """
189 | sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
190 | sock.sendto(data,(host,port))
191 | response,server = sock.recvfrom(8192)
192 | sock.close()
193 | return response
194 |
195 |
196 | if __name__ == '__main__':
197 |
198 | import argparse, time, os, sys
199 |
200 | dns = os.getenv('DNS', '8.8.8.8') + ':53'
201 |
202 | p = argparse.ArgumentParser(description="DNS Proxy")
203 |
204 | p.add_argument("--port", "-p", type=int, default=53,
205 | metavar="",
206 | help="Local proxy port (default: 53)")
207 | p.add_argument("--address","-a", default="",
208 | metavar="",
209 | help="Local proxy listen address (default: all)")
210 | p.add_argument("--upstream","-u", default=dns,
211 | metavar="",
212 | help=f"Upstream DNS server:port (default: {dns})")
213 | p.add_argument("--tcp", action='store_true', default=False,
214 | help="TCP proxy (default: UDP only)")
215 | p.add_argument("--timeout","-o", type=float, default=5,
216 | metavar="",
217 | help="Upstream timeout (default: 5s)")
218 | p.add_argument("--passthrough", action='store_true', default=False,
219 | help="Dont decode/re-encode request/response (default: off)")
220 | p.add_argument("--log", default="request,reply,truncated,error",
221 | help="Log hooks to enable (default: +request,+reply,+truncated,+error,-recv,-send,-data)")
222 | p.add_argument("--log-prefix", action='store_true', default=False,
223 | help="Log prefix (timestamp/handler/resolver) (default: False)")
224 | p.add_argument("--iprange", default="10.224.0.0/24",
225 | metavar="",
226 | help="Fake IP range (default: 10.224.0.0/24)")
227 | args = p.parse_args()
228 |
229 | args.dns,_,args.dns_port = args.upstream.partition(':')
230 | args.dns_port = int(args.dns_port or 53)
231 |
232 | print("Starting Proxy Resolver (%s:%d -> %s:%d) [%s]" % (
233 | args.address or "*",args.port,
234 | args.dns,args.dns_port,
235 | "UDP/TCP" if args.tcp else "UDP"))
236 |
237 | resolver = ProxyResolver(args.dns,args.dns_port,args.timeout,args.iprange)
238 | handler = PassthroughDNSHandler if args.passthrough else DNSHandler
239 | logger = DNSLogger(args.log,args.log_prefix)
240 | udp_server = DNSServer(resolver,
241 | port=args.port,
242 | address=args.address,
243 | logger=logger,
244 | handler=handler)
245 | udp_server.start_thread()
246 |
247 | if args.tcp:
248 | tcp_server = DNSServer(resolver,
249 | port=args.port,
250 | address=args.address,
251 | tcp=True,
252 | logger=logger,
253 | handler=handler)
254 | tcp_server.start_thread()
255 |
256 | while udp_server.isAlive():
257 | time.sleep(1)
258 |
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/doall.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | HERE="$(dirname "$(readlink -f "${0}")")"
4 | cd "$HERE"
5 |
6 | if [ -s /etc/default/antizapret ]; then
7 | set -a
8 | source /etc/default/antizapret
9 | set +a
10 | fi
11 |
12 | FORCE=${FORCE:-false}
13 |
14 | STAGE_1=${STAGE_1:-false}
15 | STAGE_2=${STAGE_2:-false}
16 | STAGE_3=${STAGE_3:-false}
17 |
18 | FILES=(
19 | temp/list.csv
20 | temp/nxdomain.txt
21 | result/adguard_upstream_dns_file
22 | )
23 |
24 |
25 | create_hash () {
26 | path="/root/antizapret/config/custom/*.txt /opt/adguardhome/conf/upstream_dns*"
27 | echo $(
28 | sed -E '/^(#.*)?[[:space:]]*$/d' $path | \
29 | sort -u | sha1sum | awk '{print $1}'
30 | )
31 | }
32 |
33 | diff_hashes () {
34 | path=./config/custom
35 | if [[ ! -f /root/.hash ]]; then
36 | create_hash > /root/.hash
37 | hash_1=
38 | else
39 | hash_1=$(cat /root/.hash)
40 | fi
41 | hash_2=$(create_hash)
42 |
43 | if [[ "$hash_1" != "$hash_2" ]]; then
44 | echo "Hashes are different: $hash_1 != $hash_2"
45 | return 1
46 | else
47 | echo "Hashes are the same: $hash_1 == $hash_2"
48 | return 0
49 | fi
50 | }
51 |
52 |
53 | # force update
54 | # FORCE=true ./doall.sh
55 | if [[ $FORCE == true ]]; then
56 | echo 'Force update detected!'
57 | ./update.sh
58 | ./parse.sh
59 | ./process.sh
60 | exit
61 | fi
62 |
63 |
64 | for file in "${FILES[@]}"; do
65 | if [ -f $file ]; then
66 | if test "$(find $file -mmin +300)"; then
67 | echo "$file is outdated!"
68 | STAGE_1=true; STAGE_2=true;
69 | fi
70 | else
71 | echo "$file is missing!"
72 | [[ $file =~ ^temp/(list.csv|nxdomain.txt)$ ]] && STAGE_1=true
73 | STAGE_2=true;
74 | fi
75 | done
76 |
77 |
78 | if ! diff_hashes; then create_hash > /root/.hash; STAGE_2=true; fi
79 |
80 | if [[ $STAGE_1 == true ]] || [[ $STAGE_2 == true ]]; then
81 | STAGE_3=true;
82 | fi
83 |
84 | [[ $STAGE_1 == true ]] && (echo "run update.sh" && ./update.sh || exit 1)
85 |
86 | [[ $STAGE_2 == true ]] && (echo "run parse.sh" && ./parse.sh || exit 2)
87 |
88 | [[ $STAGE_3 == true ]] && (echo "run process.sh" && ./process.sh 2> /dev/null || exit 3)
89 |
90 | echo "Rules updated"
91 | exit 0
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/parse.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -ex
3 |
4 | HERE="$(dirname "$(readlink -f "${0}")")"
5 | cd "$HERE"
6 | RESOLVE_NXDOMAIN="no"
7 | export LC_ALL=C.UTF-8
8 |
9 | echo "Size of temp/list.csv: $(cat temp/list.csv | wc -l) lines"
10 | echo "Size of temp/nxdomain.txt: $(cat temp/nxdomain.txt | wc -l) lines"
11 |
12 | # Extract domains from list
13 | if [[ "$SKIP_UPDATE_FROM_ZAPRET" == false ]] && [ -s temp/list.csv ]; then
14 | awk -F ';' '{print $2}' temp/list.csv | awk '/^$/ {next} /\\/ {next} /^[а-яА-Яa-zA-Z0-9\-_\.\*]*+$/ {gsub(/\*\./, ""); gsub(/\.$/, ""); print}' | grep -Fv 'bеllonа' > temp/hostlist_original.txt
15 | else
16 | echo -n > temp/hostlist_original.txt
17 | fi
18 |
19 | if [ -s temp/nxdomain.txt ]; then
20 | sort -o temp/hostlist_original.txt -u temp/hostlist_original.txt temp/nxdomain.txt
21 | fi
22 |
23 | for file in config/custom/{include,exclude}-{hosts,ips,regexp}-custom.txt; do
24 | [ ! -f "$file" ] && continue
25 | basename=$(basename $file | sed 's|-custom.txt||')
26 | (cat "$file"; echo ""; cat "config/${basename}-dist.txt") | awk -f scripts/sanitize-lists.awk > temp/${basename}.txt
27 | done
28 | sort -o temp/hostlist_original.txt -u temp/include-hosts.txt temp/hostlist_original.txt
29 |
30 | awk -F ';' '{split($1, a, /\|/); for (i in a) {print a[i]";"$2}}' temp/list.csv | \
31 | grep -f config/exclude-hosts-by-ips-dist.txt | awk -F ';' '{print $2}' >> temp/exclude-hosts.txt
32 |
33 | if [[ "$RESOLVE_NXDOMAIN" == "yes" ]];
34 | then
35 | timeout 2h scripts/resolve-dns-nxdomain.py result/hostlist_zones.txt > temp/nxdomain-exclude-hosts.txt
36 | sort -o temp/exclude-hosts.txt -u temp/nxdomain-exclude-hosts.txt temp/exclude-hosts.txt
37 | fi
38 |
39 | awk -f scripts/getzones.awk temp/hostlist_original.txt | grep -v -F -x -f temp/exclude-hosts.txt | grep -v -E -f temp/exclude-regexp.txt | CHARSET=UTF-8 idn --no-tld > temp/hostlist_zones.txt
40 | grep -E '^[^\.]+\.[^\.]+$' temp/hostlist_zones.txt > temp/hostlist_zones_2_level.txt
41 | grep -v -F -f temp/hostlist_zones_2_level.txt temp/hostlist_zones.txt > temp/hostlist_zones_without_2+_level.txt
42 | sort -u temp/hostlist_zones_2_level.txt temp/hostlist_zones_without_2+_level.txt > result/hostlist_zones.txt
43 |
44 | awk -F ';' '$1 ~ /\// {print $1}' temp/list.csv | (egrep -o '([0-9]{1,3}\.){3}[0-9]{1,3}\/[0-9]{1,2}' || echo -n) > result/blocked-ranges.txt
45 | sort -o result/blocked-ranges-with-include.txt -u temp/include-ips.txt result/blocked-ranges.txt
46 |
47 | if [ -n "$DOCKER_SUBNET" ]; then
48 | echo "$DOCKER_SUBNET" >> result/blocked-ranges-with-include.txt
49 | fi
50 |
51 | # Generate OpenVPN route file
52 | echo -n > result/openvpn-blocked-ranges.txt
53 | while read -r line
54 | do
55 | C_NET="$(echo $line | awk -F '/' '{print $1}')"
56 | C_NETMASK="$(sipcalc -- "$line" | awk '/Network mask/ {print $4; exit;}')"
57 | echo $"push \"route ${C_NET} ${C_NETMASK}\"" >> result/openvpn-blocked-ranges.txt
58 | done < result/blocked-ranges-with-include.txt
59 |
60 | # Generate adguardhome aliases
61 | /bin/cp --update=none /root/adguardhome/* /opt/adguardhome/conf
62 | /bin/cp -f /opt/adguardhome/conf/upstream_dns_file_basis result/adguard_upstream_dns_file
63 | echo "" >> result/adguard_upstream_dns_file
64 | sed -E -e 's~(.*)~[/\1/] 127.0.0.4~' result/hostlist_zones.txt >> result/adguard_upstream_dns_file
65 | /bin/cp -f result/adguard_upstream_dns_file /opt/adguardhome/conf/upstream_dns_file
66 |
67 | echo "Adguard config generated: $(cat /opt/adguardhome/conf/upstream_dns_file | wc -l) lines"
68 |
69 | rm temp/hostlist* temp/{include,exclude}*
70 |
71 | exit 0
72 |
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/process.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 |
4 | HERE="$(dirname "$(readlink -f "${0}")")"
5 | cd "$HERE"
6 |
7 | systemctl restart adguardhome
8 |
9 | exit 0
10 |
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/result/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/scripts/getzones.awk:
--------------------------------------------------------------------------------
1 | BEGIN {
2 | RS="\n|\r";
3 | IGNORECASE=1;
4 | }
5 |
6 | # Remove comments
7 | {sub(/#.*$/, "", $1)}
8 |
9 | #Strip spaces
10 | {sub(/\s/, "", $1)}
11 |
12 | #Strip double qoutes
13 | {sub(/"/, "", $1)}
14 |
15 | # Skipping empty strings
16 | (!$1) {next}
17 |
18 | # Skipping IP addresses
19 | (/^([0-9]{1,3}\.){3}[0-9]{1,3}$/) {next}
20 |
21 | # Removing leading "www."
22 | {sub(/^www\./, "", $1)}
23 |
24 | # Removing non letter symbols after domain
25 | {sub(/[^а-яА-Яa-zA-Z]+$/, "", $1)}
26 |
27 | {print $1}
28 |
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/scripts/resolve-dns-nxdomain.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import sys
4 | import os
5 | import asyncio
6 | import dns.resolver
7 | import dns.rdatatype
8 | import dns.asyncresolver
9 | import dns.exception
10 | import dns._asyncio_backend
11 | import itertools
12 |
13 | # DNS timeout (in seconds) for the initial DNS resolving pass
14 | INITIAL_PASS_TIMEOUT = 3
15 | # Number of concurrent resolving 'threads' for initial pass
16 | INITIAL_PASS_CONCURRENCY = 100
17 |
18 | # DNS timeout (in seconds) for the final (second) DNS resolving pass
19 | FINAL_PASS_TIMEOUT = 10
20 | # Number of concurrent resolving 'threads' for final pass
21 | FINAL_PASS_CONCURRENCY = 35
22 |
23 | # Multiplication number of asynchronous tasks to build for a single
24 | # resolver loop
25 | TASK_AMOUNT_MULTIPLIER = 5
26 |
27 | # Parked and expired domains NS record substrings
28 | NS_FILTER_SUBSTRINGS = ("parking", "expired", ".afternic.com", "parklogic", ".parktons.com",
29 | ".above.com", ".ztomy.com", ".notneiron.com", ".ibspark.com", ".bodis.com",
30 | ".example.com")
31 |
32 | class AZResolver(dns.asyncresolver.Resolver):
33 | def __init__(self, *args, **kwargs):
34 | self.limitConcurrency(25) # default limit
35 | super().__init__(*args, **kwargs)
36 |
37 | def limitConcurrency(self, count):
38 | self.limitingsemaphore = asyncio.Semaphore(count)
39 |
40 | async def nxresolve(self, domain):
41 | async with self.limitingsemaphore:
42 | try:
43 | #print(domain, file=sys.stderr)
44 | domain_nses = await self.resolve(domain, dns.rdatatype.NS)
45 | for ns in domain_nses:
46 | # Filter out expired and parked domains
47 | if any(filtered_substr in str(ns) for filtered_substr in NS_FILTER_SUBSTRINGS):
48 | return domain
49 |
50 | except (dns.exception.Timeout, dns.resolver.NXDOMAIN,
51 | dns.resolver.YXDOMAIN, dns.resolver.NoNameservers):
52 | return domain
53 | except dns.resolver.NoAnswer:
54 | # Do not thread domain as broken if the answer is empty,
55 | # but do if it's cloudfront subdomain
56 | if domain.endswith('.cloudfront.net'):
57 | return domain
58 |
59 |
60 | def tasksProvider(domainiter, resolver):
61 | for domain in domainiter:
62 | yield asyncio.ensure_future(resolver.nxresolve(domain.strip()))
63 |
64 | async def runTasksWithProgress(tasks, tasknumber, concurrent_tasks):
65 | progress = 0
66 | old_progress = 0
67 | ret = []
68 |
69 | # this line actually "runs" coroutine
70 | tasklist = list(itertools.islice(tasks, concurrent_tasks))
71 | tasklist_next = []
72 | while tasklist:
73 | for task in asyncio.as_completed(tasklist):
74 | ret.append(await task)
75 | progress = int(len(ret) / tasknumber * 100)
76 | if old_progress < progress:
77 | print("{}%...".format(progress), end='\r', file=sys.stderr, flush=True)
78 | old_progress = progress
79 |
80 | for newtask in tasks: # this line actually "runs" coroutine
81 | tasklist_next.append(newtask)
82 | break
83 | tasklist = tasklist_next
84 | tasklist_next = []
85 |
86 | print(file=sys.stderr)
87 | return ret
88 |
89 | async def main():
90 | if len(sys.argv) != 2:
91 | print("Incorrect arguments!")
92 | sys.exit(1)
93 |
94 | r = AZResolver()
95 | r.limitConcurrency(INITIAL_PASS_CONCURRENCY)
96 | r.timeout = INITIAL_PASS_TIMEOUT
97 | r.lifetime = INITIAL_PASS_TIMEOUT
98 |
99 | # Load domain file list and schedule resolving
100 | domaincount = 0
101 | try:
102 | with open(sys.argv[1], 'r') as domainlist:
103 | for domain in domainlist:
104 | domaincount += 1
105 | except OSError as e:
106 | print("Can't open file", sys.argv[1], e, file=sys.stderr)
107 | sys.exit(2)
108 |
109 | print("Loaded list of {} elements, resolving NXDOMAINS".format(domaincount), file=sys.stderr)
110 | #sys.exit(0)
111 |
112 | try:
113 | domainfile = open(sys.argv[1], 'r')
114 |
115 | # Resolve domains, first try
116 | nxresolved_first = await runTasksWithProgress(
117 | tasksProvider(domainfile, r), domaincount,
118 | INITIAL_PASS_CONCURRENCY * TASK_AMOUNT_MULTIPLIER
119 | )
120 | nxresolved_first = list(filter(None, nxresolved_first))
121 |
122 | print("Got {} broken domains, trying to resolve them again "
123 | "to make sure".format(len(nxresolved_first)), file=sys.stderr)
124 |
125 | # Second try
126 | r.limitConcurrency(FINAL_PASS_CONCURRENCY)
127 | r.timeout = FINAL_PASS_TIMEOUT
128 | r.lifetime = FINAL_PASS_TIMEOUT
129 |
130 | nxresolved_second = await runTasksWithProgress(
131 | tasksProvider(nxresolved_first, r), len(nxresolved_first),
132 | FINAL_PASS_CONCURRENCY * TASK_AMOUNT_MULTIPLIER
133 | )
134 | nxresolved_second = list(filter(None, nxresolved_second))
135 |
136 | print("Finally, got {} broken domains".format(len(nxresolved_second)), file=sys.stderr)
137 | for domain in nxresolved_second:
138 | print(domain)
139 |
140 | domainfile.close()
141 |
142 | except (SystemExit, KeyboardInterrupt):
143 | print("Exiting")
144 |
145 |
146 | if __name__ == '__main__':
147 | if dns.__version__ == '2.0.0':
148 | # Monkey-patch dnspython 2.0.0 bug #572
149 | # https://github.com/rthalley/dnspython/issues/572
150 | class monkeypatched_DatagramProtocol(dns._asyncio_backend._DatagramProtocol):
151 | def error_received(self, exc): # pragma: no cover
152 | if self.recvfrom and not self.recvfrom.done():
153 | self.recvfrom.set_exception(exc)
154 |
155 | def connection_lost(self, exc):
156 | if self.recvfrom and not self.recvfrom.done():
157 | self.recvfrom.set_exception(exc)
158 |
159 | dns._asyncio_backend._DatagramProtocol = monkeypatched_DatagramProtocol
160 |
161 | try:
162 | asyncio.run(main())
163 | except (SystemExit, KeyboardInterrupt):
164 | sys.exit(3)
165 |
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/scripts/sanitize-lists.awk:
--------------------------------------------------------------------------------
1 | BEGIN {
2 | RS="\n|\r";
3 | IGNORECASE=1;
4 | }
5 |
6 | # Remove comments
7 | {sub(/#.*$/, "", $1)}
8 |
9 | #Strip spaces
10 | {sub(/\s/, "", $1)}
11 |
12 | # Skipping empty strings
13 | (!$1) {next}
14 |
15 | {print $1}
16 |
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/temp/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/services/antizapret/root/antizapret/update.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | HERE="$(dirname "$(readlink -f "${0}")")"
5 | cd "$HERE"
6 |
7 | if [[ $SKIP_UPDATE_FROM_ZAPRET == true ]]; then
8 | echo "Skip download of lists"
9 | rm -f temp/list.csv temp/nxdomain.txt
10 | echo -n > temp/list.csv
11 | echo -n > temp/nxdomain.txt
12 | exit 0
13 | fi
14 |
15 | echo -n > temp/list.csv
16 | echo "Filling temp/list.csv"
17 | if [ -n "$IP_LIST" ]; then
18 | echo "Downloading ip list from $IP_LIST"
19 | timeout 30 curl -f --fail-early --compressed -o temp/list.csv.gz "$IP_LIST" || exit 1
20 | LISTSIZE="$(timeout 30 curl -sI "$IP_LIST"| awk 'BEGIN {IGNORECASE=1;} /content-length/ {sub(/[ \t\r\n]+$/, "", $2); print $2}')"
21 | [[ "$LISTSIZE" != "$(stat -c '%s' temp/list.csv.gz)" ]] && echo "List 1 size differs" && exit 2
22 | gunzip -fd temp/list.csv.gz || exit 3
23 | iconv -f cp1251 -t utf8 temp/list.csv | sponge temp/list.csv
24 | fi
25 |
26 | echo "Filling temp/nxdomain.txt"
27 | echo -n > temp/nxdomain.txt
28 | for NXDOMAINLINK in ${LISTS//;/ }; do
29 | echo "Downloading lists from $NXDOMAINLINK"
30 | timeout 30 curl -f --fail-early --compressed -o temp/nxdomain-temp.txt "$NXDOMAINLINK" || exit 1
31 | LISTSIZE="$(curl -sI "$NXDOMAINLINK" | awk 'BEGIN {IGNORECASE=1;} /content-length/ {sub(/[ \t\r\n]+$/, "", $2); print $2}')"
32 | [[ "$LISTSIZE" != "$(stat -c '%s' temp/nxdomain-temp.txt)" ]] && echo "List 2 size differs" && exit 2
33 | cat temp/nxdomain-temp.txt >> temp/nxdomain.txt
34 | rm temp/nxdomain-temp.txt
35 | done
36 |
37 | exit 0
--------------------------------------------------------------------------------
/services/antizapret/routes.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | source /etc/default/antizapret
4 |
5 | # resolve domain address to ip address
6 | function resolve () {
7 | # $1 domain/ip address, $2 fallback ip address
8 | ipcalc () { ipcalc-ng --no-decorate -o $1 2> /dev/null; }
9 | echo "$(ipcalc $1 || echo $2)"
10 | }
11 |
12 | ROUTES_EXISTING=$(ip route)
13 |
14 | for route in ${ROUTES//;/ }; do
15 | host_route=${route%:*}
16 | gateway=$(resolve $host_route '')
17 | echo "Checking route: $route; gateway: $gateway"
18 |
19 | if [ -z "$gateway" ] || [[ "$ROUTES_EXISTING" == *"$gateway"* ]]; then continue; fi
20 | subnet=${route#*:};
21 | ip route add $subnet via $gateway
22 | echo "Route add: $subnet via $gateway"
23 | done
--------------------------------------------------------------------------------
/services/cloak/.dockerignore:
--------------------------------------------------------------------------------
1 | .dockerignore
2 | docker-compose.*
3 | Dockerfile*
4 |
--------------------------------------------------------------------------------
/services/cloak/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:alpine as builder
2 | ARG CLOAK_VER=2.9.0
3 | WORKDIR /cloak
4 | RUN apk add -U --no-cache git curl make
5 | RUN curl -LO https://github.com/cbeuw/Cloak/archive/refs/tags/v${CLOAK_VER}.tar.gz && \
6 | tar -xzf v${CLOAK_VER}.tar.gz -C /cloak --strip-components=1
7 | RUN make server
8 |
9 | FROM alpine:edge
10 | RUN apk add -U --no-cache tini bash jo tzdata ca-certificates
11 | # Tune network
12 | RUN echo -e " \n\
13 | fs.file-max = 51200 \n\
14 | \n\
15 | net.core.rmem_max = 67108864 \n\
16 | net.core.wmem_max = 67108864 \n\
17 | net.core.netdev_max_backlog = 250000 \n\
18 | net.core.somaxconn = 4096 \n\
19 | \n\
20 | net.ipv4.tcp_syncookies = 1 \n\
21 | net.ipv4.tcp_tw_reuse = 1 \n\
22 | net.ipv4.tcp_tw_recycle = 0 \n\
23 | net.ipv4.tcp_fin_timeout = 30 \n\
24 | net.ipv4.tcp_keepalive_time = 1200 \n\
25 | net.ipv4.ip_local_port_range = 10000 65000 \n\
26 | net.ipv4.tcp_max_syn_backlog = 8192 \n\
27 | net.ipv4.tcp_max_tw_buckets = 5000 \n\
28 | net.ipv4.tcp_fastopen = 3 \n\
29 | net.ipv4.tcp_mem = 25600 51200 102400 \n\
30 | net.ipv4.tcp_rmem = 4096 87380 67108864 \n\
31 | net.ipv4.tcp_wmem = 4096 65536 67108864 \n\
32 | net.ipv4.tcp_mtu_probing = 1 \n\
33 | net.ipv4.tcp_congestion_control = hybla \n\
34 | # for low-latency network, use cubic instead \n\
35 | # net.ipv4.tcp_congestion_control = cubic \n\
36 | " | sed -e 's/^\s\+//g' | tee -a /etc/sysctl.conf && \
37 | mkdir -p /etc/security && \
38 | echo -e " \n\
39 | * soft nofile 51200 \n\
40 | * hard nofile 51200 \n\
41 | " | sed -e 's/^\s\+//g' | tee -a /etc/security/limits.conf
42 | COPY --from=builder /cloak/build/ck-server /usr/local/bin/ck-server
43 | COPY init.sh /
44 | RUN mkdir /opt/cloak && chown 1000:1000 /opt/cloak
45 | VOLUME [ "/opt/cloak" ]
46 | EXPOSE 443/tcp
47 | ENTRYPOINT ["/sbin/tini", "--"]
48 | CMD ["/init.sh"]
--------------------------------------------------------------------------------
/services/cloak/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | cloak:
3 | restart: unless-stopped
4 | stop_signal: SIGRTMIN+4
5 | build: .
6 | ports:
7 | - 443:443
8 | volumes:
9 | - /etc/timezone:/etc/timezone:ro
10 | - $PWD/config/cloak:/opt/cloak
11 | environment:
12 | - CK_PROXYBOOK_OPENVPN=udp://openvpn:1194 # Set upstream openvpn
13 | - CK_PRIVATEKEY # The static private key encoded in base64 (default: auto generation)
14 | - CK_PUBLICKEY # The static public key encoded in base64, if specified, it is displayed in the client configuration (default: auto generation)
15 | - CK_BYPASSUID # A list of unrestricted users UIDs, ',' (default: auto generation)
16 | - CK_ADMINUID # The UID of the admin user (default: auto generation)
17 | - CK_BINDADDR # A list of addresses Cloak will bind and listen, format ',' (default: 0.0.0.0:443)
18 | - CK_REDIRADDR # The redirection address when the incoming traffic is not from a Cloak client (default: bing.com)
19 | - CK_DATABASEPATH # The path to userinfo.db (default: /opt/cloak/userinfo.db)
20 | - CK_KEEPALIVE # The number of seconds to tell the OS to wait after no activity before sending TCP KeepAlive probes to the upstream proxy server (default: 0)
21 |
--------------------------------------------------------------------------------
/services/cloak/init.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Variables
4 | prefix="CK_PROXYBOOK_"
5 | ckserver="/usr/local/bin/ck-server"
6 | confDir="/opt/cloak"
7 | confFile="${confDir}/ckserver.json"
8 | envBackup="${confDir}/.env"
9 |
10 | # Load env
11 | if [ -e $envBackup ]; then
12 | while IFS= read -r -d $'\0' var
13 | do
14 | if [[ $var == CK_* ]]; then
15 | key=${var%%=*}
16 | if [ -z ${!key} ]; then
17 | export "$var"
18 | echo "Apply backup variable: ${var}";
19 | else
20 | echo "Skip backup variable: ${var}";
21 | fi
22 | fi
23 | done < $envBackup
24 | fi
25 |
26 | # Check environment variables
27 | _checkEnv() {
28 | if ! (env | grep -q ${prefix}); then
29 | echo "Error: not found environment variables \"${prefix}*\", exiting..."
30 | exit 1
31 | fi
32 |
33 | if [ -z "${CK_BINDADDR}" ]; then
34 | export CK_BINDADDR="0.0.0.0:443"
35 | fi
36 | if [ -z "${CK_REDIRADDR}" ]; then
37 | export CK_REDIRADDR="bing.com"
38 | fi
39 | if [ -z "${CK_KEEPALIVE}" ]; then
40 | export CK_KEEPALIVE="0"
41 | fi
42 | if [ -z "${CK_DATABASEPATH}" ]; then
43 | export CK_DATABASEPATH="${confDir}/userinfo.db"
44 | fi
45 | if [ -z "${CK_ADMINUID}" ]; then
46 | export CK_ADMINUID=$(${ckserver} -u)
47 | fi
48 | if [ -z "${CK_BYPASSUID}" ]; then
49 | export CK_BYPASSUID=$(${ckserver} -u)
50 | fi
51 | if [ -z "${CK_PRIVATEKEY}" ]; then
52 | keys=$(${ckserver} -k)
53 | export CK_PRIVATEKEY=$(echo ${keys} | cut -d , -f 2)
54 | export CK_PUBLICKEY=$(echo ${keys} | cut -d , -f 1)
55 | fi
56 | #save env
57 | env -0 > $envBackup
58 | }
59 |
60 | # Preparing system parameters
61 | _sysPrep() {
62 | if [ ! -d ${confDir} ]; then
63 | mkdir -p ${confDir}
64 | fi
65 | }
66 |
67 | # Creating config file from variables
68 | _configCreate() {
69 | proxyBook=""
70 | for pb in $(compgen -v ${prefix}); do
71 | # Environment variable is split into name (discarding the prefix) and value
72 | pbName=$(echo ${pb} | cut -d _ -f 3 | awk '{print tolower($0)}')
73 | pbValue=$(eval echo \$${pb})
74 |
75 | # Split into two parts by delimiter '://' and the first part is checked for the content of the protocol
76 | value=$(echo ${pbValue} | sed 's/:\/\//\n/g' | sed -n 1p)
77 | if [[ ${value} == "tcp" ]] || [[ ${value} == "udp" ]]; then
78 | proto=${value}
79 | # The protocol is removed and only the 'host:port' remains
80 | host=${pbValue##*://}
81 | else
82 | proto="tcp"
83 | host=${value}
84 | fi
85 |
86 | if [ ! -z ${proxyBook} ]; then
87 | proxyBook+=" "
88 | fi
89 |
90 | proxyBook+="${pbName}=$(jo -a "${proto}" "${host}")"
91 | done
92 |
93 | bindAddr=$(echo ${CK_BINDADDR/,/' '})
94 | bypassUID=$(echo ${CK_BYPASSUID/,/' '})
95 |
96 | jo -p BindAddr=$(jo -a ${bindAddr}) \
97 | RedirAddr=${CK_REDIRADDR} \
98 | ProxyBook=$(jo ${proxyBook}) \
99 | PrivateKey=${CK_PRIVATEKEY} \
100 | AdminUID=${CK_ADMINUID} \
101 | BypassUID=$(jo -a ${bypassUID}) \
102 | DatabasePath=${CK_DATABASEPATH} \
103 | KeepAlive=${CK_KEEPALIVE} > ${confFile}
104 | }
105 |
106 | # Print client config
107 | _printClientConfig() {
108 | if [ ! -z ${CK_PUBLICKEY} ]; then
109 | echo -e "\n#=== Clients Configs Start ===#"
110 | for proxyMethod in ${proxyBook}; do
111 | for uid in ${CK_BYPASSUID/,/' '}; do
112 | client_file_name="${confDir}/client-$(echo ${proxyMethod} | cut -d '=' -f 1)-${uid}.json"
113 | jo -p UID=${uid} \
114 | PublicKey=${CK_PUBLICKEY} \
115 | Transport=direct \
116 | ProxyMethod=$(echo ${proxyMethod} | cut -d '=' -f 1) \
117 | EncryptionMethod=plain \
118 | ServerName=${CK_REDIRADDR} \
119 | NumConn=4 \
120 | BrowserSig=chrome \
121 | StreamTimeout=300 > ${client_file_name}
122 | cat ${client_file_name}
123 | done
124 | done
125 | echo -e "#=== Clients Configs End ===#\n"
126 | fi
127 | }
128 |
129 | # Starting Cloak
130 | _startCloak() {
131 | exec /usr/local/bin/ck-server -c ${confFile}
132 | }
133 |
134 | _sysPrep
135 | _checkEnv
136 | _configCreate
137 | _printClientConfig
138 | _startCloak
--------------------------------------------------------------------------------
/services/dashboard/.dockerignore:
--------------------------------------------------------------------------------
1 | .dockerignore
2 | docker-compose.*
3 | Dockerfile*
4 |
--------------------------------------------------------------------------------
/services/dashboard/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM jitesoft/lighttpd
2 | RUN apk add apache2-utils jq
3 | RUN sed -i "/mimetype\.assign\s*=\s*(/a \ \".json\" => \"application/json\"," "/etc/lighttpd/conf.d/000-mime.conf"
4 | COPY files/www/. /var/www/html
5 | COPY files/init.sh /init.sh
6 | COPY files/entrypoint.sh /entrypoint.sh
7 | ENTRYPOINT [ "/entrypoint.sh" ]
--------------------------------------------------------------------------------
/services/dashboard/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | dashboard:
3 | hostname: dashboard.antizapret
4 | restart: unless-stopped
5 | build: .
6 | volumes:
7 | - /etc/timezone:/etc/timezone:ro
8 | environment:
9 | - DASHBOARD_USERNAME=admin
10 | - DASHBOARD_PASSWORD=password
11 |
12 | # DASHBOARD_SERVICE_N=name:external_port:internal_hostname:internal_port
13 | - DASHBOARD_SERVICE_1=AdGuard:1443:core.antizapret:3000
14 | - DASHBOARD_SERVICE_2=File Browser:2443:filebrowser.antizapret:80
15 | - DASHBOARD_SERVICE_3=OpenVPN UI:3443:openvpn-ui.antizapret:8080
16 | - DASHBOARD_SERVICE_4=WireGuard:4443:wireguard.antizapret:51821
17 | - DASHBOARD_SERVICE_5=WireGuard Amnezia:5443:wireguard-amnezia.antizapret:51821
18 | depends_on:
19 | - antizapret
--------------------------------------------------------------------------------
/services/dashboard/files/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | /init.sh
4 |
5 | lighttpd -D -f /etc/lighttpd/lighttpd.conf
--------------------------------------------------------------------------------
/services/dashboard/files/init.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | if [ -z "${SERVER_ROOT:-}" ]; then
4 | echo "[ERROR] SERVER_ROOT is not defined. Set SERVER_ROOT environment variable."
5 | exit 1
6 | fi
7 |
8 | CONFIG_JSON="$SERVER_ROOT/config.json"
9 | HTPASSWD_FILE="/etc/lighttpd/.htpasswd"
10 | AUTH_CONF_FILE="/etc/lighttpd/conf.d/010-auth.conf"
11 |
12 | create_auth() {
13 | if [ -z "$DASHBOARD_USERNAME" ] || [ -z "$DASHBOARD_PASSWORD" ]; then
14 | echo "[ERROR] DASHBOARD_USERNAME or DASHBOARD_PASSWORD environment variables are not set."
15 | echo "Example usage:"
16 | echo " export DASHBOARD_USERNAME=user"
17 | echo " export DASHBOARD_PASSWORD=secret"
18 | exit 1
19 | fi
20 |
21 | htpasswd -cb "$HTPASSWD_FILE" "$DASHBOARD_USERNAME" "$DASHBOARD_PASSWORD"
22 | echo "[INFO] The file $HTPASSWD_FILE has been successfully created."
23 |
24 | cat < "$AUTH_CONF_FILE"
25 | auth.backend = "htpasswd"
26 | auth.backend.htpasswd.userfile = "$HTPASSWD_FILE"
27 | auth.require = (
28 | "/" => (
29 | "method" => "basic",
30 | "realm" => "Restricted Area",
31 | "require" => "valid-user"
32 | )
33 | )
34 | EOL
35 | echo "[INFO] The file $AUTH_CONF_FILE has been successfully created."
36 | }
37 |
38 | is_host_resolved() {
39 | sleep 1s
40 | host=$1
41 | if getent hosts "$host" >/dev/null; then
42 | return 0
43 | else
44 | return 1
45 | fi
46 | }
47 |
48 | create_services_json() {
49 | services=""
50 | COUNTER=1
51 |
52 | while :; do
53 | service_var="DASHBOARD_SERVICE_$COUNTER"
54 | service_value=$(eval echo "\${$service_var:-}")
55 |
56 | if [ -z "$service_value" ]; then
57 | break
58 | fi
59 |
60 | name=$(echo "$service_value" | cut -d':' -f1)
61 | external_port=$(echo "$service_value" | cut -d':' -f2)
62 | internal_hostname=$(echo "$service_value" | cut -d':' -f3)
63 | internal_port=$(echo "$service_value" | cut -d':' -f4)
64 |
65 | if is_host_resolved "$internal_hostname"; then
66 | service_json=$(jq -n \
67 | --arg name "$name" \
68 | --arg externalPort "$external_port" \
69 | --arg internalHostname "$internal_hostname" \
70 | --arg internalPort "$internal_port" \
71 | '$ARGS.named')
72 |
73 | if [ -n "$services" ]; then
74 | services="$services,$service_json"
75 | else
76 | services="$service_json"
77 | fi
78 |
79 | echo "[INFO] Added service '$name' to JSON."
80 | else
81 | echo "[WARNING] Host '$internal_hostname' is not resolved and will be skipped."
82 | fi
83 |
84 | COUNTER=$((COUNTER + 1))
85 | done
86 |
87 | config=$(jq -n \
88 | --arg internalHostname "$(hostname)" \
89 | --argjson services "[$services]" \
90 | '{services: $services, internalHostname: $internalHostname}')
91 |
92 | echo "$config" > "$CONFIG_JSON"
93 | echo "[INFO] JSON file has been successfully created at: $CONFIG_JSON"
94 | }
95 |
96 | create_auth
97 | create_services_json
--------------------------------------------------------------------------------
/services/dashboard/files/www/github.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/services/dashboard/files/www/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
18 |
--------------------------------------------------------------------------------
/services/dashboard/files/www/index.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | margin: 0;
3 | padding: 0;
4 | height: 100%;
5 | background: #121212;
6 | color: #ffffff;
7 | }
8 |
9 | #pageWrapper {
10 | display: flex;
11 | flex-direction: column;
12 | height: 100vh;
13 | }
14 |
15 | #tabRow {
16 | display: flex;
17 | align-items: center;
18 | background-color: #2c2c2c;
19 | border-bottom: 1px solid #444;
20 | padding: 0 10px;
21 | flex: 0 0 auto;
22 | }
23 |
24 | .tab-container {
25 | display: flex;
26 | }
27 |
28 | .tab {
29 | cursor: pointer;
30 | padding: 14px 20px;
31 | border: none;
32 | background: transparent;
33 | color: #fff;
34 | font-size: 16px;
35 | transition: background-color 0.2s;
36 | border-right: 1px solid #444;
37 | text-decoration: none;
38 | font-family: monospace;
39 | }
40 |
41 | .tab:last-child {
42 | border-right: none;
43 | }
44 |
45 | .tab:hover {
46 | background-color: #3c3c3c;
47 | }
48 |
49 | .tab.active {
50 | background-color: #444;
51 | font-weight: bold;
52 | }
53 |
54 | .tab-ext-link {
55 | display: inline-block;
56 | margin-left: 8px;
57 | font-size: 14px;
58 | text-decoration: none;
59 | filter: grayscale(100%);
60 | transition: color 1s ease, filter 1s ease, text-shadow 1s ease;
61 | }
62 |
63 | .tab-ext-link:hover {
64 | filter: grayscale(0%);
65 | font-weight: bold;
66 | }
67 |
68 | #contentWrapper {
69 | position: relative;
70 | flex: 1 1 auto;
71 | overflow: hidden;
72 | }
73 |
74 | .content-container {
75 | position: absolute;
76 | top: 0; left: 0; right: 0; bottom: 0;
77 | visibility: hidden;
78 | }
79 |
80 | .content-container.active {
81 | visibility: visible;
82 | }
83 |
84 | iframe {
85 | width: 100%;
86 | height: 100%;
87 | border: none;
88 | }
89 |
90 | .page-title-link {
91 | text-decoration: none;
92 | color: inherit;
93 | display: flex;
94 | align-items: center;
95 | }
96 |
97 | #pageTitle {
98 | display: flex;
99 | align-items: center;
100 | margin-left: auto;
101 | font-size: 16px;
102 | font-weight: normal;
103 | opacity: 0.8;
104 | }
105 |
106 | #titleText {
107 | color: rgba(255, 255, 255, 0.3);
108 | font-weight: bold;
109 | font-size: 32px;
110 | text-transform: uppercase;
111 | font-family: Arial, Helvetica, sans-serif;
112 | }
113 |
114 | #titleText {
115 | margin-right: 16px;
116 | }
117 |
118 | .github-icon {
119 | height: 32px;
120 | width: 32px;
121 | vertical-align: middle;
122 | }
--------------------------------------------------------------------------------
/services/dashboard/files/www/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ANTIZAPRET
7 |
8 |
9 |
10 |
27 |
28 |
--------------------------------------------------------------------------------
/services/dashboard/files/www/index.js:
--------------------------------------------------------------------------------
1 | const servicesUrl= "/config.json"
2 |
3 | let currentHost = window.location.hostname;
4 | let tabContainer = document.getElementById('tabContainer');
5 | let contentWrapper = document.getElementById('contentWrapper');
6 |
7 | let allTabs = [];
8 | let allContents = [];
9 | let serviceHashes = [];
10 |
11 | function activateTab(index) {
12 | allTabs.forEach(tab => tab.classList.remove('active'));
13 | allContents.forEach(cont => cont.classList.remove('active'));
14 |
15 | if (index >= 0 && index < allTabs.length) {
16 | allTabs[index].classList.add('active');
17 | allContents[index].classList.add('active');
18 | window.location.hash = serviceHashes[index];
19 | }
20 | }
21 |
22 | function createTab(serviceName, serviceUrl, hashValue) {
23 | let tabEl = document.createElement('a');
24 | tabEl.className = 'tab';
25 | tabEl.textContent = serviceName;
26 | tabEl.href = '#' + encodeURIComponent(hashValue);
27 |
28 | let extLink = document.createElement('a');
29 | extLink.href = serviceUrl;
30 | extLink.title=`Открыть ${serviceName} во внешней вкладке`
31 | extLink.target = '_blank';
32 | extLink.textContent = '🔗';
33 | extLink.className = 'tab-ext-link';
34 |
35 | tabEl.appendChild(extLink);
36 |
37 | let contentEl = document.createElement('div');
38 | contentEl.className = 'content-container';
39 | let iframeEl = document.createElement('iframe');
40 | iframeEl.src = serviceUrl;
41 | contentEl.appendChild(iframeEl);
42 |
43 | tabContainer.appendChild(tabEl);
44 | contentWrapper.appendChild(contentEl);
45 |
46 | allTabs.push(tabEl);
47 | allContents.push(contentEl);
48 | }
49 |
50 |
51 | function tryActivateTabFromHash() {
52 | let rawHashValue = window.location.hash ? window.location.hash.substring(1) : '';
53 | let decodedHashValue = decodeURIComponent(rawHashValue);
54 | let idx = serviceHashes.indexOf(decodedHashValue);
55 | if (idx !== -1) {
56 | activateTab(idx);
57 | } else {
58 | activateTab(0);
59 | }
60 | }
61 |
62 | fetch(servicesUrl)
63 | .then(response => response.json())
64 | .then(config => {
65 | let internalHostname = config.internalHostname;
66 | let services = config.services;
67 |
68 | if (internalHostname === currentHost){
69 | services.forEach(service => {
70 | serviceHashes.push(service.internalHostname);
71 | let url = `http://${service.internalHostname}:${service.internalPort}`;
72 | createTab(service.name, url, service.internalHostname);
73 | });
74 | }
75 | else {
76 | services.forEach(service => {
77 | serviceHashes.push(service.internalHostname);
78 | let url = `https://${currentHost}:${service.externalPort}`;
79 | createTab(service.name, url, service.internalHostname);
80 | });
81 | }
82 |
83 | tryActivateTabFromHash();
84 | })
85 | .catch(err => {
86 | console.error(`Error fetching ${servicesUrl}:`, err);
87 | });
88 |
89 |
90 | window.addEventListener('hashchange', tryActivateTabFromHash);
91 |
--------------------------------------------------------------------------------
/services/filebrowser/.dockerignore:
--------------------------------------------------------------------------------
1 | .dockerignore
2 | docker-compose.*
3 | Dockerfile*
4 |
--------------------------------------------------------------------------------
/services/filebrowser/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM filebrowser/filebrowser
2 | COPY . .
3 | ENTRYPOINT [ "/init.sh" ]
--------------------------------------------------------------------------------
/services/filebrowser/branding/custom.css:
--------------------------------------------------------------------------------
1 | /* https://theme-park.dev/css/base/filebrowser/organizr.css */
2 |
3 | :root {
4 | --main-bg-color: #1f1f1f;
5 |
6 | --modal-bg-color: #333;
7 | --modal-header-color: #232323;
8 | --modal-footer-color: #232323;
9 |
10 | --drop-down-menu-bg: #1b1b1b;
11 |
12 | --button-color: #2cabe3;
13 | --button-color-hover: #298fbc;
14 | --button-text: #eee;
15 | --button-text-hover: #fff;
16 |
17 | --accent-color: 44, 171, 227;
18 | --accent-color-hover: rgb(var(--accent-color),.8);
19 | --link-color: #2cabe3;
20 | --link-color-hover: #3cc5ff;
21 | --label-text-color: #fff;
22 |
23 | --text:#96a2b4;
24 | --text-hover: #fff;
25 | --text-muted: #999;
26 |
27 | /*Specials*/
28 | --arr-queue-color: #2cabe3; /* Servarr apps + Bazarr*/
29 | --plex-poster-unwatched: #2cabe3;
30 | --petio-spinner: invert(65%) sepia(83%) saturate(2026%) hue-rotate(167deg) brightness(90%) contrast(97%);/* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
31 | --gitea-color-primary-dark-4: 44, 171, 227;
32 | --overseerr-gradient: linear-gradient(180deg, rgba(31, 31, 31, 0.17) 0%, rgba(31, 31, 31) 100%);
33 | }
34 | ::-webkit-input-placeholder{
35 | color:var(--text-muted)!important
36 | }
37 | :focus::-webkit-input-placeholder{
38 | color:var(--text-hover)!important
39 | }
40 | :-moz-placeholder{
41 | color:var(--text-muted)!important
42 | }
43 | :focus:-moz-placeholder{
44 | color:var(--text-hover)!important
45 | }
46 | ::-moz-placeholder{
47 | color:var(--text-muted)!important
48 | }
49 | :focus::-moz-placeholder{
50 | color:var(--text-hover)!important
51 | }
52 | :-ms-input-placeholder{
53 | color:var(--text-muted)!important
54 | }
55 | :focus:-ms-input-placeholder{
56 | color:var(--text-hover)!important
57 | }
58 | :root{
59 | --transparency-dark-05:rgba(0, 0, 0, .05);
60 | --transparency-dark-10:rgba(0, 0, 0, .10);
61 | --transparency-dark-15:rgba(0, 0, 0, .15);
62 | --transparency-dark-25:rgba(0, 0, 0, .25);
63 | --transparency-dark-35:rgba(0, 0, 0, .35);
64 | --transparency-dark-40:rgba(0, 0, 0, .40);
65 | --transparency-dark-45:rgba(0, 0, 0, .45);
66 | --transparency-dark-50:rgba(0, 0, 0, .50);
67 | --transparency-dark-55:rgba(0, 0, 0, .55);
68 | --transparency-dark-60:rgba(0, 0, 0, .60);
69 | --transparency-dark-65:rgba(0, 0, 0, .65);
70 | --transparency-dark-70:rgba(0, 0, 0, .70);
71 | --transparency-dark-75:rgba(0, 0, 0, .75);
72 | --transparency-dark-80:rgba(0, 0, 0, .80);
73 | --transparency-dark-85:rgba(0, 0, 0, .85);
74 | --transparency-dark-90:rgba(0, 0, 0, .90);
75 | --transparency-light-05:rgba(255, 255, 255, .05);
76 | --transparency-light-10:rgba(255, 255, 255, .10);
77 | --transparency-light-15:rgba(255, 255, 255, .15);
78 | --transparency-light-20:rgba(255, 255, 255, .20);
79 | --transparency-light-25:rgba(255, 255, 255, .25);
80 | --transparency-light-30:rgba(255, 255, 255, .30);
81 | --transparency-light-35:rgba(255, 255, 255, .35);
82 | --transparency-light-45:rgba(255, 255, 255, .45);
83 | --transparency-light-50:rgba(255, 255, 255, .50);
84 | --transparency-light-55:rgba(255, 255, 255, .55);
85 | --transparency-light-95:rgba(255, 255, 255, .95)
86 | }
87 | .message{
88 | color:var(--text-hover)
89 | }
90 | #login{
91 | min-height:100%;
92 | height:auto;
93 | background:var(--main-bg-color);
94 | background-repeat:repeat,no-repeat;
95 | background-attachment:fixed,fixed;
96 | background-position:center center,center center;
97 | background-size:auto,cover;
98 | -webkit-background-size:auto,cover;
99 | -moz-background-size:auto,cover;
100 | -o-background-size:auto,cover
101 | }
102 | body{
103 | color:var(--text);
104 | font-family:Open Sans Bold,Helvetica Neue,Helvetica,Arial,sans-serif
105 | }
106 | h1,h2,h3,h4,h5,h6,th{
107 | color:var(--text-hover)!important
108 | }
109 | #login input[type=password],#login input[type=text]{
110 | color:var(--text-hover)!important;
111 | background:var(--transparency-dark-15)!important;
112 | border:none
113 | }
114 | #loading{
115 | background:var(--main-bg-color);
116 | background-repeat:repeat,no-repeat;
117 | background-attachment:fixed,fixed;
118 | background-position:center center,center center;
119 | background-size:auto,cover;
120 | -webkit-background-size:auto,cover;
121 | -moz-background-size:auto,cover;
122 | -o-background-size:auto,cover
123 | }
124 | #loading .spinner *{
125 | background-color:#fff!important
126 | }
127 | html{
128 | min-height:100%;
129 | background:var(--main-bg-color);
130 | background-repeat:repeat,no-repeat;
131 | background-attachment:fixed,fixed;
132 | background-position:center center,center center;
133 | background-size:auto,cover;
134 | -webkit-background-size:auto,cover;
135 | -moz-background-size:auto,cover;
136 | -o-background-size:auto,cover
137 | }
138 | body{
139 | background:var(--main-bg-color);
140 | background-repeat:repeat,no-repeat;
141 | background-attachment:fixed,fixed;
142 | background-position:center center,center center;
143 | background-size:auto,cover;
144 | -webkit-background-size:auto,cover;
145 | -moz-background-size:auto,cover;
146 | -o-background-size:auto,cover
147 | }
148 | @media (max-width:736px){
149 | nav,nav.active{
150 | background:var(--modal-bg-color)!important
151 | }
152 | #dropdown.active{
153 | background:var(--drop-down-menu-bg)!important
154 | }
155 | }
156 | nav{
157 | background:var(--transparency-dark-45);
158 | height:100%;
159 | top:64px;
160 | width:240px
161 | }
162 | .overlay:not(nav){
163 | background-color:transparent
164 | }
165 | nav .action{
166 | color:var(--text);
167 | font-size:13px;
168 | font-family:Open Sans Semibold,Helvetica Neue,Helvetica,Arial,sans-serif;
169 | -webkit-font-smoothing:antialiased;
170 | -moz-osx-font-smoothing:grayscale;
171 | padding-top:0;
172 | padding-bottom:0
173 | }
174 | nav .action:hover{
175 | background:var(--transparency-light-05);
176 | color:rgb(var(--accent-color))
177 | }
178 | nav>div{
179 | border-top:none
180 | }
181 | header{
182 | background:var(--transparency-dark-25);
183 | background-repeat:repeat,no-repeat;
184 | background-attachment:fixed,fixed;
185 | background-position:center center,center center;
186 | background-size:auto,cover;
187 | -webkit-background-size:auto,cover;
188 | -moz-background-size:auto,cover;
189 | -o-background-size:auto,cover;
190 | border-bottom:transparent;
191 | box-shadow:0 3px 6px 0 rgba(0,0,0,.15)
192 | }
193 | header>div:first-child{
194 | height:60px
195 | }
196 | body{
197 | padding-top:60px
198 | }
199 | .shell{
200 | background:var(--modal-bg-color);
201 | background-repeat:repeat,no-repeat;
202 | background-attachment:fixed,fixed;
203 | background-position:center center,center center;
204 | background-size:auto,cover;
205 | -webkit-background-size:auto,cover;
206 | -moz-background-size:auto,cover;
207 | -o-background-size:auto,cover;
208 | color:rgb(var(--accent-color))
209 | }
210 | .shell__prompt i{
211 | color:rgb(var(--accent-color))
212 | }
213 | .action{
214 | color:var(--text-hover)
215 | }
216 | #listing.list .item{
217 | background:var(--transparency-dark-15);
218 | color:var(--text);
219 | border:none
220 | }
221 | #listing.list .item:hover{
222 | background:var(--transparency-light-10);
223 | color:var(--text-hover);
224 | border:none;
225 | transition:.4s
226 | }
227 | #listing.list .item.header{
228 | background:var(--transparency-dark-45);
229 | color:var(--text-hover);
230 | border-bottom:none;
231 | right:auto
232 | }
233 | .material-icons,.prompt .file-list ul li:before{
234 | color:rgb(var(--accent-color))
235 | }
236 | .action:hover{
237 | background-color:rgba(var(--accent-color),.1)
238 | }
239 | .action .counter{
240 | background:rgb(var(--accent-color));
241 | color:var(--label-text-color);
242 | border:2px solid var(--label-text-color)
243 | }
244 | .share__box{
245 | background:0 0
246 | }
247 | .share__box__info{
248 | background:var(--transparency-dark-25)
249 | }
250 | .share__box__download{
251 | background:rgb(var(--accent-color));
252 | color:var(--text-hover);
253 | border-bottom:1px solid rgb(var(--accent-color))
254 | }
255 | .share__box__element{
256 | border-top:1px solid rgb(255 255 255 / 10%)
257 | }
258 | svg{
259 | fill:rgb(var(--accent-color))!important
260 | }
261 | #listing.list .item div:first-of-type i{
262 | color:rgb(var(--accent-color))
263 | }
264 | #listing .item i{
265 | color:rgb(var(--accent-color))
266 | }
267 | #listing.mosaic:hover .item:hover i:hover{
268 | color:var(--accent-color-hover)
269 | }
270 | #listing .item[aria-selected=true]{
271 | background-color:rgba(255,255,255,.2)!important;
272 | color:var(--text-hover)!important
273 | }
274 | #listing h2{
275 | color:var(--text-hover)
276 | }
277 | #listing #multiple-selection{
278 | background:var(--modal-bg-color);
279 | background-repeat:repeat,no-repeat;
280 | background-attachment:fixed,fixed;
281 | background-position:center center,center center;
282 | background-size:auto,cover;
283 | -webkit-background-size:auto,cover;
284 | -moz-background-size:auto,cover;
285 | -o-background-size:auto,cover
286 | }
287 | #breadcrumbs span a{
288 | color:var(--text-hover)
289 | }
290 | #breadcrumbs{
291 | border-bottom:1px solid rgb(var(--accent-color))
292 | }
293 | #listing .item{
294 | background:var(--transparency-dark-15);
295 | color:var(--text);
296 | border:none
297 | }
298 | .input{
299 | background:var(--transparency-dark-25);
300 | color:var(--text-hover)
301 | }
302 | select>option{
303 | background:var(--drop-down-menu-bg)
304 | }
305 | #search #input{
306 | background:#fff;
307 | display:flex;
308 | padding:10px
309 | }
310 | #search #result{
311 | background:var(--modal-bg-color);
312 | background-repeat:repeat,no-repeat;
313 | background-attachment:fixed,fixed;
314 | background-position:center center,center center;
315 | background-size:auto,cover;
316 | -webkit-background-size:auto,cover;
317 | -moz-background-size:auto,cover;
318 | -o-background-size:auto,cover;
319 | color:var(--text-hover)
320 | }
321 | #search .boxes{
322 | background:var(--transparency-dark-15);
323 | padding:15px
324 | }
325 | #search .boxes h3{
326 | color:var(--text-hover)
327 | }
328 | #search .boxes>div>div{
329 | background:var(--transparency-dark-10)
330 | }
331 | #search .boxes>div>div:hover{
332 | background-color:var(--transparency-light-10)
333 | }
334 | #search.active #input{
335 | background:var(--main-bg-color);
336 | background-repeat:repeat,no-repeat;
337 | background-attachment:fixed,fixed;
338 | background-position:center center,center center;
339 | background-size:auto,cover;
340 | -webkit-background-size:auto,cover;
341 | -moz-background-size:auto,cover;
342 | -o-background-size:auto,cover;
343 | height:60px;
344 | color:#000
345 | }
346 | #search.active i,#search.active input{
347 | color:var(--text-hover)
348 | }
349 | #search #result>div>:first-child{
350 | margin-top:10px
351 | }
352 | .card{
353 | background:var(--transparency-dark-15)
354 | }
355 | .card h3{
356 | color:var(--text-hover)
357 | }
358 | .card#share ul li a{
359 | color:rgb(var(--accent-color))
360 | }
361 | select{
362 | color:var(--text-hover)
363 | }
364 | .card#share .input-group *{
365 | border:none;
366 | background:0 0
367 | }
368 | button,input,select,textarea{
369 | color:var(--text-hover)
370 | }
371 | .collapsible>label *{
372 | color:var(--text-hover)
373 | }
374 | .breadcrumbs,.breadcrumbs span,.breadcrumbs span a,.link,a{
375 | color:var(--link-color)
376 | }
377 | .breadcrumbs span a:hover,.link:hover,a:hover{
378 | color:var(--link-color-hover)
379 | }
380 | table th{
381 | color:var(--text-hover)
382 | }
383 | .card.floating{
384 | background:var(--modal-bg-color);
385 | background-repeat:repeat,no-repeat;
386 | background-attachment:fixed,fixed;
387 | background-position:center center,center center;
388 | background-size:auto,cover;
389 | -webkit-background-size:auto,cover;
390 | -moz-background-size:auto,cover;
391 | -o-background-size:auto,cover
392 | }
393 | #search #input{
394 | background:var(--transparency-light-10)
395 | }
396 | #listing.mosaic .item{
397 | box-shadow:none!important
398 | }
399 | #listing.mosaic .item:hover{
400 | box-shadow:none!important;
401 | background:var(--transparency-light-10)
402 | }
403 | .dashboard p label{
404 | color:var(--text-hover)
405 | }
406 | .dashboard #nav li.active{
407 | border-color:rgb(var(--accent-color))
408 | }
409 | .dashboard #nav ul li.active{
410 | border-color:rgb(var(--accent-color));
411 | color:rgb(var(--accent-color))
412 | }
413 | .dashboard #nav ul li.active:before{
414 | background:rgb(var(--accent-color));
415 | opacity:.08
416 | }
417 | .dashboard #nav ul li:hover{
418 | background:rgb(var(--accent-color),.15);
419 | color:rgb(var(--accent-color))
420 | }
421 | .dashboard #nav .wrapper{
422 | border-bottom:2px solid var(--accent-color-hover)
423 | }
424 | @media (min-width:1024px){
425 | main{
426 | margin-left:270px
427 | }
428 | }
429 | @media (max-width:1024px){
430 | nav{
431 | width:175px
432 | }
433 | }
434 | .button:not(.button--flat.button--red){
435 | background:var(--button-color);
436 | color:var(--button-text)
437 | }
438 | .button:active:not(.button--flat.button--red),.button:focus:not(.button--flat.button--red),.button:hover:not(.button--flat.button--red){
439 | background:var(--button-color-hover);
440 | color:var(--button-text-hover)
441 | }
442 | button:hover:not(.action),input[type=submit]:hover{
443 | color:var(--button-text-hover)
444 | }
445 | .button--flat{
446 | margin-left:5px
447 | }
448 | .button--flat:hover{
449 | background:var(--dark-red);
450 | color:var(--text-hover);
451 | margin-left:5px
452 | }
453 | #editor-container{
454 | background:var(--modal-bg-color)
455 | }
456 | .ace-chrome .ace_gutter{
457 | background:#282a36!important;
458 | color:#909194!important
459 | }
460 | .ace-chrome .ace_print-margin{
461 | width:1px;
462 | background:#44475a
463 | }
464 | .ace-chrome{
465 | background-color:#282a36;
466 | color:#f8f8f2
467 | }
468 | .ace-chrome .ace_cursor{
469 | color:#f8f8f0
470 | }
471 | .ace-chrome .ace_marker-layer .ace_selection{
472 | background:#44475a
473 | }
474 | .ace-chrome.ace_multiselect .ace_selection.ace_start{
475 | box-shadow:0 0 3px 0 #282a36;
476 | border-radius:2px
477 | }
478 | .ace-chrome .ace_marker-layer .ace_step{
479 | background:#c6dbae
480 | }
481 | .ace-chrome .ace_marker-layer .ace_bracket{
482 | margin:-1px 0 0 -1px;
483 | border:1px solid #a29709
484 | }
485 | .ace-chrome .ace_marker-layer .ace_active-line{
486 | background:#44475a
487 | }
488 | .ace-chrome .ace_gutter-active-line{
489 | background-color:#44475a
490 | }
491 | .ace-chrome .ace_marker-layer .ace_selected-word{
492 | box-shadow:0 0 0 1px #a29709;
493 | border-radius:3px
494 | }
495 | .ace-chrome .ace_fold{
496 | background-color:#50fa7b;
497 | border-color:#f8f8f2
498 | }
499 | .ace-chrome .ace_keyword{
500 | color:#ff79c6
501 | }
502 | .ace-chrome .ace_constant.ace_language{
503 | color:#bd93f9
504 | }
505 | .ace-chrome .ace_constant.ace_numeric{
506 | color:#bd93f9
507 | }
508 | .ace-chrome .ace_constant.ace_character{
509 | color:#bd93f9
510 | }
511 | .ace-chrome .ace_constant.ace_character.ace_escape{
512 | color:#ff79c6
513 | }
514 | .ace-chrome .ace_constant.ace_other{
515 | color:#bd93f9
516 | }
517 | .ace-chrome .ace_support.ace_function{
518 | color:#8be9fd
519 | }
520 | .ace-chrome .ace_support.ace_constant{
521 | color:#6be5fd
522 | }
523 | .ace-chrome .ace_support.ace_class{
524 | font-style:italic;
525 | color:#66d9ef
526 | }
527 | .ace-chrome .ace_support.ace_type{
528 | font-style:italic;
529 | color:#66d9ef
530 | }
531 | .ace-chrome .ace_storage{
532 | color:#ff79c6
533 | }
534 | .ace-chrome .ace_storage.ace_type{
535 | font-style:italic;
536 | color:#8be9fd
537 | }
538 | .ace-chrome .ace_invalid{
539 | color:#f8f8f0;
540 | background-color:#ff79c6
541 | }
542 | .ace-chrome .ace_invalid.ace_deprecated{
543 | color:#f8f8f0;
544 | background-color:#bd93f9
545 | }
546 | .ace-chrome .ace_string{
547 | color:#f1fa8c
548 | }
549 | .ace-chrome .ace_comment{
550 | color:#6272a4
551 | }
552 | .ace-chrome .ace_variable{
553 | color:#50fa7b
554 | }
555 | .ace-chrome .ace_variable.ace_parameter{
556 | font-style:italic;
557 | color:#ffb86c
558 | }
559 | .ace-chrome .ace_entity.ace_other.ace_attribute-name{
560 | color:#50fa7b
561 | }
562 | .ace-chrome .ace_entity.ace_name.ace_function{
563 | color:#50fa7b
564 | }
565 | .ace-chrome .ace_entity.ace_name.ace_tag{
566 | color:#ff79c6
567 | }
568 | .ace-chrome .ace_invisible{
569 | color:#626680
570 | }
571 | .ace-chrome .ace_indent-guide{
572 | background:url(data:image/png;
573 | base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYHB3d/8PAAOIAdULw8qMAAAAAElFTkSuQmCC) right repeat-y
574 | }
575 | .credits{
576 | color:var(--text-muted)
577 | }
578 |
--------------------------------------------------------------------------------
/services/filebrowser/branding/img/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtrime-ru/antizapret-vpn-docker/667094a1cb4413f99a916c08a0224dd224364604/services/filebrowser/branding/img/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/services/filebrowser/branding/img/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/services/filebrowser/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | filebrowser:
3 | hostname: filebrowser.antizapret
4 | restart: unless-stopped
5 | build: .
6 | logging:
7 | driver: json-file
8 | options:
9 | max-size: 100k
10 | max-file: 2
11 | ports:
12 | - 2000:80
13 | volumes:
14 | - /etc/timezone:/etc/timezone:ro
15 | - $PWD/config/antizapret/custom:/srv
16 | depends_on:
17 | - antizapret
18 |
--------------------------------------------------------------------------------
/services/filebrowser/hooks/doall.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | STAGE_1=false
4 | STAGE_2=true
5 | STAGE_3=true
6 |
7 | curl -X POST http://antizapret:8080/doall \
8 | -H "Content-Type: application/json" \
9 | -d '{ "stage_1": '"$STAGE_1"', "stage_2": '"$STAGE_2"', "stage_3": '"$STAGE_3"' }'
10 |
--------------------------------------------------------------------------------
/services/filebrowser/init.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env /bin/sh
2 |
3 | /filebrowser config init \
4 | --address="0.0.0.0" \
5 | --branding.disableExternal \
6 | --branding.files="/branding" \
7 | --branding.name="AntiBrowser" \
8 | --locale="ru" \
9 | --perm.create="false" \
10 | --perm.delete="false" \
11 | --perm.download="false" \
12 | --perm.execute="false" \
13 | --perm.modify="true" \
14 | --perm.rename="false" \
15 | --perm.share="false" \
16 | --port="80" \
17 | --root="/srv" \
18 | --shell="sh -c" \
19 | --singleClick
20 |
21 | /filebrowser cmds add after_save '/hooks/doall.sh'
22 |
23 | /filebrowser users add --lockPassword \
24 | ${FILEBROWSER_USERNAME:-"admin"} \
25 | ${FILEBROWSER_PASSWORD:-"password"}
26 |
27 | exec /filebrowser
--------------------------------------------------------------------------------
/services/ipsec/.dockerignore:
--------------------------------------------------------------------------------
1 | .dockerignore
2 | docker-compose.*
3 | Dockerfile*
4 |
--------------------------------------------------------------------------------
/services/ipsec/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM hwdsl2/ipsec-vpn-server:debian
2 |
3 | COPY init.sh /
4 |
5 | CMD ["/init.sh"]
6 |
--------------------------------------------------------------------------------
/services/ipsec/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | ipsec:
3 | hostname: ipsec
4 | restart: unless-stopped
5 | privileged: true
6 | build: .
7 | logging:
8 | driver: json-file
9 | options:
10 | max-size: 100k
11 | max-file: 2
12 | volumes:
13 | - /etc/timezone:/etc/timezone:ro
14 | ports:
15 | - 500:500/udp
16 | - 4500:4500/udp
17 | depends_on:
18 | - antizapret
19 | environment:
20 | - VPN_L2TP_NET=10.1.163.0/24
21 | - VPN_L2TP_LOCAL=10.1.163.1
22 | - VPN_L2TP_POOL=10.1.163.10-10.1.163.254
23 | - VPN_XAUTH_NET=10.1.162.0/24
24 | - VPN_XAUTH_POOL=10.1.162.10-10.1.162.254
25 | - VPN_DNS_SRV1=10.224.0.1
--------------------------------------------------------------------------------
/services/ipsec/init.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 |
4 | export TARGET_SCRIPT="/opt/src/run.sh"
5 | export ANTIZAPRET_IP=$(dig +short antizapret)
6 | export ANTIZAPRET_SUBNET=${ANTIZAPRET_SUBNET:-"10.224.0.0/15"}
7 |
8 |
9 | sed -i "s|leftsubnet=0.0.0.0/0|leftsubnet=${ANTIZAPRET_SUBNET}|g" $TARGET_SCRIPT
10 |
11 | nohup bash -c "
12 | until ps | grep -q xl2tpd; do sleep 0.1; done
13 | ip route add $ANTIZAPRET_SUBNET via $ANTIZAPRET_IP
14 | " &
15 |
16 |
17 | exec $TARGET_SCRIPT
18 |
--------------------------------------------------------------------------------
/services/openvpn/.dockerignore:
--------------------------------------------------------------------------------
1 | .dockerignore
2 | docker-compose.*
3 | Dockerfile*
4 |
--------------------------------------------------------------------------------
/services/openvpn/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM d3vilh/openvpn-server
2 |
3 | RUN apk add -U --no-cache grep moreutils && apk del openvpn
4 |
5 | ARG OPENVPN_VER=2.6.13
6 | ADD files/socket.patch /socket.patch
7 | # OpenVPN
8 | RUN <<-"EOT" bash -ex
9 | LIBS="libnl3-dev openssl-dev libcap-ng-dev lz4-dev"
10 | LIBS_TEMP="linux-headers patch pkgconf git gcc g++ make"
11 | apk add -U --no-cache $LIBS $LIBS_TEMP
12 | mkdir -p /opt/openvpn_install && cd /opt/openvpn_install
13 | wget "https://github.com/OpenVPN/openvpn/releases/download/v${OPENVPN_VER}/openvpn-${OPENVPN_VER}.tar.gz"
14 | tar xvf "openvpn-${OPENVPN_VER}.tar.gz"
15 | cd "openvpn-${OPENVPN_VER}"
16 |
17 | patch -p1 "/opt/openvpn_install/openvpn-$OPENVPN_VER/src/openvpn/socket.h" /socket.patch
18 | ./configure --enable-static=yes --enable-dco --enable-shared --enable-systemd=no --disable-lzo --disable-debug --disable-plugin-auth-pam --disable-dependency-tracking
19 | make -j$(nproc)
20 | make install
21 |
22 | rm /socket.patch
23 | cd /root
24 | rm -rf /opt/openvpn_install/
25 | apk del $LIBS_TEMP
26 | EOT
27 |
28 | COPY easy-rsa.vars /opt/app
29 | COPY files/fw-rules.sh /opt/app
30 | COPY files/checkpsw.sh /opt/app
31 | COPY files/server-start.sh /opt/app/docker-entrypoint.sh
--------------------------------------------------------------------------------
/services/openvpn/Dockerfile.ui:
--------------------------------------------------------------------------------
1 | FROM d3vilh/openvpn-ui
2 |
3 | RUN apk add -U --no-cache grep moreutils sqlite
4 |
5 | COPY easy-rsa.vars /usr/share/easy-rsa/var
6 | COPY files-ui/init.db /opt/openvpn-ui/init.db
7 | COPY files-ui/ui-start.sh /opt/start.sh
8 | COPY files-ui/restart.sh /opt/scripts/restart.sh
--------------------------------------------------------------------------------
/services/openvpn/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | openvpn:
3 | hostname: openvpn.antizapret
4 | restart: unless-stopped
5 | privileged: true
6 | build: .
7 | healthcheck:
8 | test: cmp /etc/openvpn/openvpn-blocked-ranges.txt /opt/antizapret/result/openvpn-blocked-ranges.txt || sh -c 'killall -INT -r openvpn && (sleep 5; killall -s 9 -r openvpn)'
9 | interval: 30s
10 | timeout: 10s
11 | retries: 1
12 | volumes:
13 | - /etc/timezone:/etc/timezone:ro
14 | - $PWD/config/openvpn:/etc/openvpn
15 | - $PWD/config/antizapret/result:/opt/antizapret/result
16 | ports:
17 | - "1194:1194/tcp"
18 | - "1194:1194/udp"
19 | depends_on:
20 | - openvpn-ui
21 | - antizapret
22 | environment:
23 | - OBFUSCATE_TYPE=0
24 |
25 | openvpn-ui:
26 | hostname: openvpn-ui.antizapret
27 | restart: unless-stopped
28 | privileged: true
29 | build:
30 | context: .
31 | dockerfile: Dockerfile.ui
32 | volumes:
33 | - /etc/timezone:/etc/timezone:ro
34 | - /var/run/docker.sock:/var/run/docker.sock:ro
35 | - $PWD/config/openvpn/db:/opt/openvpn-ui/db
36 | - $PWD/config/openvpn/pki:/usr/share/easy-rsa/pki
37 | - $PWD/config/openvpn:/etc/openvpn
38 | ports:
39 | - 8080:8080
40 | environment:
41 | - OPENVPN_ADMIN_USERNAME=admin
42 | - OPENVPN_ADMIN_PASSWORD=gagaZush
43 | depends_on:
44 | - antizapret
--------------------------------------------------------------------------------
/services/openvpn/easy-rsa.vars:
--------------------------------------------------------------------------------
1 | set_var EASYRSA_DN "cn_only"
2 | set_var EASYRSA_REQ_COUNTRY ""
3 | set_var EASYRSA_REQ_PROVINCE ""
4 | set_var EASYRSA_REQ_CITY ""
5 | set_var EASYRSA_REQ_ORG ""
6 | set_var EASYRSA_REQ_EMAIL ""
7 | set_var EASYRSA_REQ_OU ""
8 | set_var EASYRSA_REQ_CN "Antizapret"
9 | set_var EASYRSA_KEY_SIZE 2048
10 | set_var EASYRSA_CA_EXPIRE 3650
11 | set_var EASYRSA_CERT_EXPIRE 8250
12 | set_var EASYRSA_CERT_RENEW 30
13 | set_var EASYRSA_CRL_DAYS 180
14 | # Auto generated by OpenVPN-UI v.0.9.5.6
--------------------------------------------------------------------------------
/services/openvpn/files-ui/init.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtrime-ru/antizapret-vpn-docker/667094a1cb4413f99a916c08a0224dd224364604/services/openvpn/files-ui/init.db
--------------------------------------------------------------------------------
/services/openvpn/files-ui/restart.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Exit immediately if a command exits with a non-zero status
3 | set -e
4 |
5 | #Variables
6 | ACTION=$1 #passed via OpenVPN-UI GUI
7 |
8 | # if ACTION is not defined then define it as openvpn-server
9 | if [ -z "$ACTION" ]; then
10 | ACTION="openvpn-server"
11 | fi
12 |
13 | if [ "$ACTION" = "openvpn-server" ]; then # Restartnig openvpn server
14 | # Get the container ID for ^openvpn$
15 | CONTAINER_ID=$(curl --unix-socket /var/run/docker.sock "http://v1.40/containers/json?filters=%7B%22name%22%3A%5B%22%5Eantizapret-openvpn-%5B0-9%5D%2B%24%22%5D%7D" | grep '"Id":' | cut -d '"' -f 4)
16 | elif [ "$ACTION" = "openvpn-ui" ]; then # Restartnig openvpn-ui
17 | # Get the container ID for ^openvpn-ui$
18 | CONTAINER_ID=$(curl --unix-socket /var/run/docker.sock "http://v1.40/containers/json?filters=%7B%22name%22%3A%5B%22%5Eantizapret-openvpn-ui-%5B0-9%5D%2B%24%22%5D%7D" | grep '"Id":' | cut -d '"' -f 4)
19 | else
20 | echo "Invalid input argument: $ACTION Exiting..."
21 | exit 1
22 | fi
23 |
24 | if [ -z "$CONTAINER_ID" ]; then
25 | echo "Container not found"
26 | exit 2
27 | fi
28 | # Restart the container
29 | curl --unix-socket /var/run/docker.sock -X POST "http://v1.40/containers/$CONTAINER_ID/restart"
30 | # Print the restarted container ID
31 | echo "Restarted container $CONTAINER_ID"
--------------------------------------------------------------------------------
/services/openvpn/files-ui/ui-start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Exit immediately if a command exits with a non-zero status
3 | set -e
4 |
5 | # Directory where OpenVPN configuration files are stored
6 | OPENVPN_DIR=$(grep -E "^OpenVpnPath\s*=" openvpn-ui/conf/app.conf | cut -d= -f2 | tr -d '"' | tr -d '[:space:]')
7 | echo "Init. OVPN path: $OPENVPN_DIR"
8 |
9 | # Change to the /opt directory
10 | cd /opt/
11 |
12 | # If the provisioned file does not exist in the OpenVPN directory, prepare the certificates and create the provisioned file
13 | if [ ! -f $OPENVPN_DIR/.provisioned ]; then
14 | #echo "Preparing certificates"
15 | mkdir -p $OPENVPN_DIR
16 | mkdir -p $OPENVPN_DIR/log
17 |
18 | # Uncomment line below to generate CA and server certificates (should be done on the side of OpenVPN container or server however)
19 | #./scripts/generate_ca_and_server_certs.sh
20 |
21 | # Create the provisioned file
22 | touch $OPENVPN_DIR/.provisioned
23 |
24 | echo "First OpenVPN UI start."
25 | fi
26 |
27 | # Change to the OpenVPN GUI directory
28 | cd /opt/openvpn-ui
29 |
30 | # Create the database directory if it does not exist
31 | mkdir -p db
32 |
33 | cat << EOF | sponge /etc/environment
34 | OPENVPN_EXTERNAL_IP='${OPENVPN_EXTERNAL_IP:-$(curl -4 icanhazip.com)}'
35 | OPENVPN_LOCAL_IP_RANGE='${OPENVPN_LOCAL_IP_RANGE:-"10.1.165.0"}'
36 | OPENVPN_DNS='${OPENVPN_DNS:-"10.1.165.1"}'
37 | NIC='$(ip -4 route | grep default | grep -Po '(?<=dev )(\S+)' | head -1)'
38 | OVDIR='${OVDIR:-"/etc/openvpn"}'
39 | EOF
40 | source /etc/environment
41 | ln -sf /etc/environment /etc/profile.d/environment.sh
42 |
43 | if [ ! -f /opt/openvpn-ui/db/data.db ]; then
44 | cp /opt/openvpn-ui/init.db /opt/openvpn-ui/db/data.db
45 |
46 | sqlite3 /opt/openvpn-ui/db/data.db <> /etc/sysctl.conf;
68 | echo 'IP forwarding configuration now applied:'
69 | else
70 | echo 'IP forwarding configuration already applied:'
71 | fi
72 | sysctl -p /etc/sysctl.conf
73 |
74 | if [[ ! -s fw-rules.sh ]]; then
75 | echo "No additional firewall rules to apply."
76 | else
77 | echo "Applying firewall rules"
78 | ./fw-rules.sh
79 | echo 'Additional firewall rules applied.'
80 | fi
81 |
82 | mkdir -p $OPENVPN_DIR/clients
83 | mkdir -p $OPENVPN_DIR/staticclients
84 |
85 | echo 'Start openvpn process...'
86 | tail -f $OPENVPN_DIR/log/*.log &
87 | exec /usr/local/sbin/openvpn --cd $OPENVPN_DIR --script-security 2 --config $OPENVPN_DIR/server.conf
--------------------------------------------------------------------------------
/services/openvpn/files/socket.patch:
--------------------------------------------------------------------------------
1 | --- ./openvpn/socket.h 2025-01-12 22:59:54
2 | +++ ./openvpn/socket.h 2025-02-02 11:19:46
3 | @@ -1169,18 +1169,90 @@
4 | #endif /* ifdef _WIN32 */
5 |
6 | static inline size_t
7 | +
8 | +/* Patch to overcome DPI start (works only for UDP connections, taken from https://github.com/GubernievS/AntiZapret-VPN/blob/main/setup/root/patch-openvpn.sh */
9 | +#include // For std::getenv
10 | link_socket_write_udp(struct link_socket *sock,
11 | struct buffer *buf,
12 | struct link_socket_actual *to)
13 | {
14 | + const int OBFUSCATE = getenv("OBFUSCATE_TYPE") ? strtol(getenv("OBFUSCATE_TYPE"), NULL, 10) : 0;
15 | +
16 | + if (OBFUSCATE == 0) {
17 | #ifdef _WIN32
18 | - return link_socket_write_win32(sock, buf, to);
19 | + return link_socket_write_win32(sock, buf, to);
20 | #else
21 | - return link_socket_write_udp_posix(sock, buf, to);
22 | + return link_socket_write_udp_posix(sock, buf, to);
23 | +#endif
24 | + }
25 | +
26 | + uint16_t buffer_sent = 0;
27 | + uint8_t opcode = *BPTR(buf) >> 3;
28 | + if (opcode == 7 || opcode == 8 || opcode == 10)
29 | + {
30 | + if (OBFUSCATE == 2) {
31 | +#ifdef _WIN32
32 | + buffer_sent =+ link_socket_write_win32(sock, buf, to);
33 | +#else
34 | + buffer_sent =+ link_socket_write_udp_posix(sock, buf, to);
35 | +#endif
36 | + }
37 | +uint16_t buffer_len = BLEN(buf);
38 | + srand(time(NULL));
39 | + for (int i = 0; i < 2; i++) {
40 | + uint16_t data_len = rand() % 101 + buffer_len;
41 | + uint8_t data[data_len];
42 | + struct buffer data_buffer;
43 | + if (OBFUSCATE == 1) {
44 | + data_buffer = alloc_buf(data_len);
45 | + if (i == 0) {
46 | + data[0] = 1;
47 | + data[1] = 0;
48 | + data[2] = 0;
49 | + data[3] = 0;
50 | + data[4] = 1;
51 | + for (int k = 5; k < data_len; k++) {
52 | + data[k] = rand() % 256;
53 | + }
54 | + }
55 | + else {
56 | + for (int k = 0; k < data_len; k++) {
57 | + data[k] = rand() % 256;
58 | + }
59 | + }
60 | + }
61 | + else {
62 | + data_buffer = clone_buf(buf);
63 | + buf_read(&data_buffer, data, buffer_len);
64 | + buf_clear(&data_buffer);
65 | + data[0] = 40;
66 | + for (int k = buffer_len; k < data_len; k++) {
67 | + data[k] = rand() % 256;
68 | + }
69 | + }
70 | + buf_write(&data_buffer, data, data_len);
71 | + int data_repeat = rand() % 101 + 100;
72 | + for (int j = 0; j < data_repeat; j++) {
73 | +#ifdef _WIN32
74 | + buffer_sent =+ link_socket_write_win32(sock, &data_buffer, to);
75 | +#else
76 | + buffer_sent =+ link_socket_write_udp_posix(sock, &data_buffer, to);
77 | #endif
78 | + }
79 | + free_buf(&data_buffer);
80 | + usleep(data_repeat * 1000);
81 | + }
82 | }
83 | +#ifdef _WIN32
84 | + buffer_sent =+ link_socket_write_win32(sock, buf, to);
85 | +#else
86 | + buffer_sent =+ link_socket_write_udp_posix(sock, buf, to);
87 | +#endif
88 | + return buffer_sent;
89 | +}
90 |
91 | /* write a TCP or UDP packet to link */
92 | +
93 | static inline int
94 | link_socket_write(struct link_socket *sock,
95 | struct buffer *buf,
96 | \ No newline at end of file
97 |
--------------------------------------------------------------------------------
/services/proxy/.dockerignore:
--------------------------------------------------------------------------------
1 | docker-compose.yml
2 | Dockerfile
3 | /caddy_data
4 | /caddy_config
--------------------------------------------------------------------------------
/services/proxy/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM caddy:2
2 | RUN apk add openssl
3 | COPY files/entrypoint.sh /entrypoint.sh
4 | COPY files/init.sh /init.sh
5 | ENTRYPOINT [ "/entrypoint.sh" ]
--------------------------------------------------------------------------------
/services/proxy/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | proxy:
3 | restart: unless-stopped
4 | build: .
5 | ports:
6 | - "80:80"
7 | - "443:443"
8 | - "1443:1443"
9 | - "2443:2443"
10 | - "3443:3443"
11 | - "4443:4443"
12 | - "5443:5443"
13 | environment:
14 | # If not set, will be created and used self-signed certificate
15 | - PROXY_DOMAIN=
16 | # If not set, will be created and used self-signed certificate
17 | - PROXY_EMAIL=
18 | # PROXY_SERVICE_N=external_port:internal_hostname:internal_port
19 | - PROXY_SERVICE_1=Dashboard:443:dashboard.antizapret:80
20 | - PROXY_SERVICE_2=AdGuard:1443:core.antizapret:3000
21 | - PROXY_SERVICE_3=File Browser:2443:filebrowser.antizapret:80
22 | - PROXY_SERVICE_4=OpenVPN UI:3443:openvpn-ui.antizapret:8080
23 | - PROXY_SERVICE_5=WireGuard:4443:wireguard.antizapret:51821
24 | - PROXY_SERVICE_6=WireGuard Amnezia:5443:wireguard-amnezia.antizapret:51821
25 | volumes:
26 | - /etc/timezone:/etc/timezone:ro
27 | - $PWD/config/caddy/data:/data
28 | - $PWD/config/caddy/config:/config
29 | depends_on:
30 | - antizapret
--------------------------------------------------------------------------------
/services/proxy/files/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | /init.sh
4 |
5 | caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
--------------------------------------------------------------------------------
/services/proxy/files/init.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -eu
4 |
5 | CERT_DIR="/data/caddy/certificates/self-signed"
6 | CERT_CRT="$CERT_DIR/selfsigned.crt"
7 | CERT_KEY="$CERT_DIR/selfsigned.key"
8 | CONFIG_FILE="/etc/caddy/Caddyfile"
9 | REACHABLE_SERVICES=""
10 | IS_SELF_SIGNED=0
11 |
12 |
13 | is_host_resolved() {
14 | sleep 1s
15 | host=$1
16 | if getent hosts "$host" >/dev/null; then
17 | return 0
18 | else
19 | return 1
20 | fi
21 | }
22 |
23 | generate_certificate() {
24 | echo "[INFO] Generating or checking SSL certificates..."
25 |
26 | mkdir -p "$CERT_DIR"
27 | if [ ! -f "$CERT_KEY" ] || [ ! -f "$CERT_CRT" ]; then
28 | openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
29 | -keyout "$CERT_KEY" \
30 | -out "$CERT_CRT" \
31 | -subj "/O=ANTIZAPRET/OU=ANTIZAPRET/CN=ANTIZAPRET"
32 | echo "[INFO] Certificates have been generated."
33 | else
34 | echo "[INFO] Certificates already exist. Skipping generation."
35 | fi
36 | echo
37 | }
38 |
39 | get_services() {
40 | COUNTER=1
41 | while :; do
42 | service_var="PROXY_SERVICE_$COUNTER"
43 | service_value=$(eval echo "\${$service_var:-}")
44 |
45 | if [ -z "$service_value" ]; then
46 | break
47 | fi
48 |
49 | name=$(echo "$service_value" | cut -d':' -f1)
50 | external_port=$(echo "$service_value" | cut -d':' -f2)
51 | internal_host=$(echo "$service_value" | cut -d':' -f3)
52 | internal_port=$(echo "$service_value" | cut -d':' -f4)
53 |
54 | if [ -z "$name" ] || [ -z "$external_port" ] || [ -z "$internal_host" ] || [ -z "$internal_port" ]; then
55 | echo "[ERROR] $service_var has an invalid format. Expected: name:external_port:internal_hostname:internal_port"
56 | exit 1
57 | fi
58 |
59 | if is_host_resolved "$internal_host"; then
60 | REACHABLE_SERVICES=$(printf "%s\n%s" "$REACHABLE_SERVICES" "$service_value")
61 | echo "[INFO] Host $internal_host is reachable. Adding service: $service_value"
62 | else
63 | echo "[WARNING] Host $internal_host is not reachable. Skipping: $service_value"
64 | fi
65 |
66 | COUNTER=$((COUNTER + 1))
67 | done
68 | echo "[INFO] Services read successfully."
69 | }
70 |
71 | generate_global_config() {
72 | if [ "$IS_SELF_SIGNED" -eq 1 ]; then
73 | cat <>"$CONFIG_FILE"
74 | {
75 | auto_https disable_redirects
76 | }
77 | EOF
78 | else
79 | cat <>"$CONFIG_FILE"
80 | {
81 | email $PROXY_EMAIL
82 | auto_https disable_redirects
83 | }
84 | EOF
85 | fi
86 | echo "[INFO] Global configuration block created."
87 | }
88 |
89 | add_services_to_config() {
90 | echo "$REACHABLE_SERVICES" | while IFS= read -r service_value; do
91 |
92 | if [ -z "$service_value" ]; then
93 | continue
94 | fi
95 |
96 | name=$(echo "$service_value" | cut -d':' -f1)
97 | external_port=$(echo "$service_value" | cut -d':' -f2)
98 | internal_host=$(echo "$service_value" | cut -d':' -f3)
99 | internal_port=$(echo "$service_value" | cut -d':' -f4)
100 |
101 | if [ "$IS_SELF_SIGNED" -eq 1 ]; then
102 | cat <>"$CONFIG_FILE"
103 |
104 | #$name#
105 | :$external_port {
106 | tls $CERT_CRT $CERT_KEY
107 | reverse_proxy {
108 | to http://$internal_host:$internal_port
109 | }
110 | }
111 | EOF
112 | else
113 | cat <>"$CONFIG_FILE"
114 |
115 | #$name#
116 | https://$PROXY_DOMAIN:$external_port {
117 | reverse_proxy {
118 | to http://$internal_host:$internal_port
119 | }
120 | }
121 | EOF
122 | fi
123 | echo "[INFO] Service added: $external_port -> $internal_host:$internal_port"
124 | done
125 | }
126 |
127 | main() {
128 | : >"$CONFIG_FILE"
129 | get_services
130 |
131 | if [ -z "${PROXY_DOMAIN:-}" ] || [ -z "${PROXY_EMAIL:-}" ]; then
132 | IS_SELF_SIGNED=1
133 | generate_certificate
134 | generate_global_config
135 | else
136 | IS_SELF_SIGNED=0
137 | generate_global_config
138 | fi
139 |
140 | add_services_to_config
141 |
142 | echo
143 | echo "[INFO] Caddyfile has been successfully created at: $CONFIG_FILE"
144 | }
145 |
146 | main
147 |
--------------------------------------------------------------------------------
/services/wireguard/.dockerignore:
--------------------------------------------------------------------------------
1 | .dockerignore
2 | docker-compose.*
3 | Dockerfile*
4 |
--------------------------------------------------------------------------------
/services/wireguard/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG IMAGE
2 |
3 | FROM ${IMAGE}
4 |
5 | RUN apk add -U --no-cache curl bind-tools
6 |
7 | COPY init.sh /
8 |
9 | CMD ["/init.sh"]
--------------------------------------------------------------------------------
/services/wireguard/docker-compose.yml:
--------------------------------------------------------------------------------
1 | x-common: &common
2 | restart: unless-stopped
3 | logging:
4 | driver: json-file
5 | options:
6 | max-size: 100k
7 | max-file: 2
8 | healthcheck:
9 | test: cmp /app/blocked-ranges-with-include.txt /opt/antizapret/result/blocked-ranges-with-include.txt || sh -c 'kill -INT -1 && (sleep 5; kill -s 9 -1)'
10 | interval: 60s
11 | timeout: 30s
12 | retries: 1
13 | cap_add:
14 | - NET_ADMIN
15 | - SYS_MODULE
16 | sysctls:
17 | - net.ipv4.ip_forward=1
18 | - net.ipv4.conf.all.src_valid_mark=1
19 | ports:
20 | - 51820:51820/udp
21 | - 51821:51821/tcp
22 | depends_on:
23 | - antizapret
24 | environment:
25 | - PORT=51821
26 | - WG_PORT=51820
27 | - WG_DEFAULT_DNS=10.224.0.1
28 | - WG_PERSISTENT_KEEPALIVE=25
29 |
30 | services:
31 | wireguard:
32 | <<: *common
33 | hostname: wireguard.antizapret
34 | build:
35 | context: .
36 | args:
37 | - IMAGE=ghcr.io/wg-easy/wg-easy:14
38 | volumes:
39 | - /etc/localtime:/etc/localtime:ro
40 | - $PWD/config/wireguard:/etc/wireguard
41 | - $PWD/config/antizapret/result:/opt/antizapret/result
42 |
43 | wireguard-amnezia:
44 | <<: *common
45 | hostname: wireguard-amnezia.antizapret
46 | build:
47 | context: .
48 | args:
49 | - IMAGE=xtrime/amnezia-wg-easy:latest
50 | devices:
51 | - /dev/net/tun:/dev/net/tun
52 | volumes:
53 | - /etc/localtime:/etc/localtime:ro
54 | - $PWD/config/wireguard_amnezia:/etc/wireguard
55 | - $PWD/config/antizapret/result:/opt/antizapret/result
56 |
--------------------------------------------------------------------------------
/services/wireguard/init.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | if [ $(which dig | wc -l) -eq 0 ]; then
4 | apk add -U --no-cache bind-tools
5 | fi
6 | if [ $(which curl | wc -l) -eq 0 ]; then
7 | apk add -U --no-cache curl
8 | fi
9 |
10 | if [ -z "$WG_HOST" ]; then
11 | export WG_HOST=$(curl -4 icanhazip.com)
12 | fi
13 |
14 | export WG_DEFAULT_ADDRESS=${WG_DEFAULT_ADDRESS:-"10.1.166.x"}
15 | export WG_DEVICE=${WG_DEVICE:-"eth0"}
16 | export WG_PORT=${WG_PORT:-51820}
17 | export ANTIZAPRET_SUBNET=${ANTIZAPRET_SUBNET:-"10.224.0.0/15"}
18 |
19 | if [ -f "/opt/antizapret/result/blocked-ranges-with-include.txt" ]; then
20 | cp -f /opt/antizapret/result/blocked-ranges-with-include.txt /app/blocked-ranges-with-include.txt
21 | fi
22 |
23 | if [ -z "$WG_ALLOWED_IPS" ]; then
24 | export WG_ALLOWED_IPS="${WG_DEFAULT_ADDRESS/"x"/"0"}/24,$ANTIZAPRET_SUBNET"
25 | blocked_ranges=`tr '\n' ',' < /app/blocked-ranges-with-include.txt | sed 's/,$//g'`
26 | if [ -n "${blocked_ranges}" ]; then
27 | export WG_ALLOWED_IPS="${WG_ALLOWED_IPS},${blocked_ranges}"
28 | fi
29 | fi
30 |
31 | export DOCKER_SUBNET=$(ip r | awk '/default/ {dev=$5} !/default/ && $0 ~ dev {print $1}')
32 | export AZ_HOST=$(dig +short antizapret)
33 | while [ -z "${AZ_HOST}" ]; do
34 | echo "No route to antizapret container. Retrying..."
35 | export AZ_HOST=$(dig +short antizapret)
36 | sleep 1;
37 | done;
38 |
39 | export WG_POST_UP=$(tr '\n' ' ' << EOF
40 | iptables -t nat -N masq_not_local;
41 | iptables -t nat -A POSTROUTING -s ${WG_DEFAULT_ADDRESS/"x"/"0"}/24 -o ${WG_DEVICE} -j masq_not_local;
42 | iptables -t nat -A masq_not_local -d ${AZ_HOST} -j RETURN;
43 | iptables -t nat -A masq_not_local -d ${ANTIZAPRET_SUBNET} -j RETURN;
44 | iptables -t nat -A masq_not_local -j MASQUERADE;
45 | iptables -A FORWARD -i wg0 -j ACCEPT;
46 | iptables -A FORWARD -o wg0 -j ACCEPT;
47 | EOF
48 | )
49 |
50 | export WG_POST_DOWN=$(tr '\n' ' ' << EOF
51 | iptables -t nat -D POSTROUTING -s ${WG_DEFAULT_ADDRESS/"x"/"0"}/24 -o ${WG_DEVICE} -j masq_not_local;
52 | iptables -t nat -F masq_not_local;
53 | iptables -t nat -X masq_not_local;
54 | iptables -D FORWARD -i wg0 -j ACCEPT;
55 | iptables -D FORWARD -o wg0 -j ACCEPT;
56 | EOF
57 | )
58 |
59 |
60 | ip route add $ANTIZAPRET_SUBNET via $AZ_HOST
61 |
62 | if [[ ${FORCE_FORWARD_DNS:-true} == true ]]; then
63 | dnsPorts=${FORCE_FORWARD_DNS_PORTS:-"53"}
64 | for dnsPort in $dnsPorts; do
65 | iptables -t nat -A PREROUTING -p tcp --dport $dnsPort -j DNAT --to-destination $AZ_HOST
66 | iptables -t nat -A PREROUTING -p udp --dport $dnsPort -j DNAT --to-destination $AZ_HOST
67 | done
68 | fi
69 |
70 | if [ -n "$WIREGUARD_PASSWORD_HASH" ]; then
71 | PASSWORD_HASH="$WIREGUARD_PASSWORD_HASH"
72 | else
73 | PASSWORD_HASH="$(wgpw "$WIREGUARD_PASSWORD" | sed "s/'//g" | sed 's/PASSWORD_HASH=//g')"
74 | fi
75 | export PASSWORD_HASH
76 |
77 | exec /usr/bin/dumb-init node server.js
78 |
--------------------------------------------------------------------------------