├── .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 | 7 | 8 | 10 | 16 | 17 | 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 |
11 |
12 |
13 | 23 |
24 |
25 | 26 |
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 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------