mirror of
https://bitbucket.org/anticensority/antizapret-pac-generator-light.git
synced 2024-11-23 21:56:04 +03:00
Implement NXDOMAIN resolving and filtering
This commit is contained in:
parent
57b9569800
commit
9a4f0bced8
@ -5,7 +5,7 @@ Russian PAC file generator, light version
|
|||||||
|
|
||||||
Данный набор скриптов создаёт файл [автоконфигурации прокси](https://en.wikipedia.org/wiki/Proxy_auto-config) со списком сайтов, заблокированных на территории Российской Федерации Роскомнадзором и другими государственными органами, который можно использовать в браузерах, для автоматического проксирования заблокированных ресурсов.
|
Данный набор скриптов создаёт файл [автоконфигурации прокси](https://en.wikipedia.org/wiki/Proxy_auto-config) со списком сайтов, заблокированных на территории Российской Федерации Роскомнадзором и другими государственными органами, который можно использовать в браузерах, для автоматического проксирования заблокированных ресурсов.
|
||||||
|
|
||||||
Помимо основного назнчения скрипта (генерации PAC-файла), он также умеет создавать:
|
Помимо основного назначения скрипта (генерации PAC-файла), он также умеет создавать:
|
||||||
|
|
||||||
* Файл клиентской конфигурации (client-config, CCD) с заблокированными диапазонами IP-адресов для OpenVPN;
|
* Файл клиентской конфигурации (client-config, CCD) с заблокированными диапазонами IP-адресов для OpenVPN;
|
||||||
* Файл с заблокированными доменными зонами для Squid;
|
* Файл с заблокированными доменными зонами для Squid;
|
||||||
@ -19,15 +19,16 @@ Russian PAC file generator, light version
|
|||||||
* GNU AWK (gawk)
|
* GNU AWK (gawk)
|
||||||
* sipcalc
|
* sipcalc
|
||||||
* idn
|
* idn
|
||||||
* Python 3.4+
|
* Python 3.6+
|
||||||
|
* dnspython 2.0.0+
|
||||||
|
|
||||||
### Конфигурационные файлы
|
### Конфигурационные файлы
|
||||||
|
|
||||||
* **{in,ex}clude-{hosts,ips}-dist** — конфигурация дистрибутива, предназначена для изменения автором репозитория;
|
* **{in,ex}clude-{hosts,ips}-dist** — конфигурация дистрибутива, предназначена для изменения автором репозитория;
|
||||||
* **{in,ex}clude-{hosts,ips}-custom** — пользовательская конфигурация, предназначена для изменения конечным пользователем скрипта;
|
* **{in,ex}clude-{hosts,ips}-custom** — пользовательская конфигурация, предназначена для изменения конечным пользователем скрипта;
|
||||||
* **exclude-regexp-dist.awk** — файл с различным заблокированным «мусором», раздувающим PAC-файл: зеркалами сайтов, неработающими сайтами, и т.д.
|
* **exclude-regexp-dist.awk** — файл с различным заблокированным «мусором», раздувающим PAC-файл: зеркалами сайтов, неработающими сайтами, и т.д.
|
||||||
* **config.sh** — файл с адресами прокси.
|
* **config.sh** — файл с адресами прокси и прочей конфигурацией.
|
||||||
|
|
||||||
### Установка и запуск
|
### Установка и запуск
|
||||||
|
|
||||||
Склонируйте git-репозиторий, отредактируйте **doall.sh** и **process.sh** под собственные нужды, запустите **doall.sh**.
|
Склонируйте git-репозиторий, отредактируйте **config/config.sh**, **doall.sh** и **process.sh** под собственные нужды, запустите **doall.sh**.
|
||||||
|
@ -8,3 +8,6 @@ PACPROXYHOST='proxy-nossl.antizapret.prostovpn.org:29976'
|
|||||||
|
|
||||||
PACFILE="result/proxy-host-ssl.pac"
|
PACFILE="result/proxy-host-ssl.pac"
|
||||||
PACFILE_NOSSL="result/proxy-host-nossl.pac"
|
PACFILE_NOSSL="result/proxy-host-nossl.pac"
|
||||||
|
|
||||||
|
# Perform DNS resolving to detect and filter non-existent domains
|
||||||
|
RESOLVE_NXDOMAIN="yes"
|
||||||
|
8
parse.sh
8
parse.sh
@ -1,6 +1,8 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
source config/config.sh
|
||||||
|
|
||||||
HERE="$(dirname "$(readlink -f "${0}")")"
|
HERE="$(dirname "$(readlink -f "${0}")")"
|
||||||
cd "$HERE"
|
cd "$HERE"
|
||||||
|
|
||||||
@ -19,6 +21,12 @@ sort -u temp/include-hosts.txt result/hostlist_original.txt > temp/hostlist_orig
|
|||||||
|
|
||||||
awk -f scripts/getzones.awk temp/hostlist_original_with_include.txt | grep -v -F -x -f temp/exclude-hosts.txt | sort -u > result/hostlist_zones.txt
|
awk -f scripts/getzones.awk temp/hostlist_original_with_include.txt | grep -v -F -x -f temp/exclude-hosts.txt | sort -u > result/hostlist_zones.txt
|
||||||
|
|
||||||
|
if [[ "$RESOLVE_NXDOMAIN" == "yes" ]];
|
||||||
|
then
|
||||||
|
scripts/resolve-dns-nxdomain.py result/hostlist_zones.txt >> temp/exclude-hosts.txt
|
||||||
|
awk -f scripts/getzones.awk temp/hostlist_original_with_include.txt | grep -v -F -x -f temp/exclude-hosts.txt | sort -u > result/hostlist_zones.txt
|
||||||
|
fi
|
||||||
|
|
||||||
# Generate a list of IP addresses
|
# Generate a list of IP addresses
|
||||||
awk -F';' '$1 ~ /\// {print $1}' temp/list.csv | grep -P '([0-9]{1,3}\.){3}[0-9]{1,3}\/[0-9]{1,2}' -o | sort -Vu > result/iplist_special_range.txt
|
awk -F';' '$1 ~ /\// {print $1}' temp/list.csv | grep -P '([0-9]{1,3}\.){3}[0-9]{1,3}\/[0-9]{1,2}' -o | sort -Vu > result/iplist_special_range.txt
|
||||||
|
|
||||||
|
124
scripts/resolve-dns-nxdomain.py
Executable file
124
scripts/resolve-dns-nxdomain.py
Executable file
@ -0,0 +1,124 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import asyncio
|
||||||
|
import dns.resolver
|
||||||
|
import dns.asyncresolver
|
||||||
|
import dns.exception
|
||||||
|
import dns._asyncio_backend
|
||||||
|
|
||||||
|
# DNS timeout (in seconds) for the initial DNS resolving pass
|
||||||
|
INITIAL_PASS_TIMEOUT = 3
|
||||||
|
# Number of concurrent resolving 'threads' for initial pass
|
||||||
|
INITIAL_PASS_CONCURRENCY = 100
|
||||||
|
|
||||||
|
# DNS timeout (in seconds) for the final (second) DNS resolving pass
|
||||||
|
FINAL_PASS_TIMEOUT = 10
|
||||||
|
# Number of concurrent resolving 'threads' for final pass
|
||||||
|
FINAL_PASS_CONCURRENCY = 35
|
||||||
|
|
||||||
|
|
||||||
|
class AZResolver(dns.asyncresolver.Resolver):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.limitConcurrency(25) # default limit
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def limitConcurrency(self, count):
|
||||||
|
self.limitingsemaphore = asyncio.Semaphore(count)
|
||||||
|
|
||||||
|
async def nxresolve(self, domain):
|
||||||
|
async with self.limitingsemaphore:
|
||||||
|
try:
|
||||||
|
#print(domain, file=sys.stderr)
|
||||||
|
await self.resolve(domain)
|
||||||
|
|
||||||
|
except (dns.exception.Timeout, dns.resolver.NXDOMAIN,
|
||||||
|
dns.resolver.YXDOMAIN, dns.resolver.NoAnswer,
|
||||||
|
dns.resolver.NoNameservers):
|
||||||
|
return domain
|
||||||
|
|
||||||
|
async def runTasksWithProgress(tasks):
|
||||||
|
progress = 0
|
||||||
|
old_progress = 0
|
||||||
|
ret = []
|
||||||
|
|
||||||
|
for task in asyncio.as_completed(tasks):
|
||||||
|
ret.append(await task)
|
||||||
|
progress = int(len(ret) / len(tasks) * 100)
|
||||||
|
if old_progress < progress:
|
||||||
|
print("{}%...".format(progress), end='\r', file=sys.stderr, flush=True)
|
||||||
|
old_progress = progress
|
||||||
|
print(file=sys.stderr)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
print("Incorrect arguments!")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
r = AZResolver()
|
||||||
|
r.limitConcurrency(INITIAL_PASS_CONCURRENCY)
|
||||||
|
r.timeout = INITIAL_PASS_TIMEOUT
|
||||||
|
r.lifetime = INITIAL_PASS_TIMEOUT
|
||||||
|
|
||||||
|
# Load domain file list and schedule resolving
|
||||||
|
tasks = []
|
||||||
|
try:
|
||||||
|
with open(sys.argv[1], 'rb') as domainlist:
|
||||||
|
for domain in domainlist:
|
||||||
|
tasks.append(asyncio.ensure_future(r.nxresolve(domain.decode().strip())))
|
||||||
|
except OSError as e:
|
||||||
|
print("Can't open file", sys.argv[1], e, file=sys.stderr)
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
print("Loaded list of {} elements, resolving NXDOMAINS".format(len(tasks)), file=sys.stderr)
|
||||||
|
#sys.exit(0)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Resolve domains, first try
|
||||||
|
nxresolved_first = await runTasksWithProgress(tasks)
|
||||||
|
nxresolved_first = list(filter(None, nxresolved_first))
|
||||||
|
|
||||||
|
print("Got {} broken domains, trying to resolve them again "
|
||||||
|
"to make sure".format(len(nxresolved_first)), file=sys.stderr)
|
||||||
|
|
||||||
|
# Second try
|
||||||
|
tasks = []
|
||||||
|
r.limitConcurrency(FINAL_PASS_CONCURRENCY)
|
||||||
|
r.timeout = FINAL_PASS_TIMEOUT
|
||||||
|
r.lifetime = FINAL_PASS_TIMEOUT
|
||||||
|
|
||||||
|
for domain in nxresolved_first:
|
||||||
|
tasks.append(asyncio.ensure_future(r.nxresolve(domain)))
|
||||||
|
nxresolved_second = await runTasksWithProgress(tasks)
|
||||||
|
nxresolved_second = list(filter(None, nxresolved_second))
|
||||||
|
|
||||||
|
print("Finally, got {} broken domains".format(len(nxresolved_second)), file=sys.stderr)
|
||||||
|
for domain in nxresolved_second:
|
||||||
|
print(domain)
|
||||||
|
|
||||||
|
except (SystemExit, KeyboardInterrupt):
|
||||||
|
for task in tasks:
|
||||||
|
task.cancel()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
if dns.__version__ == '2.0.0':
|
||||||
|
# Monkey-patch dnspython 2.0.0 bug #572
|
||||||
|
# https://github.com/rthalley/dnspython/issues/572
|
||||||
|
class monkeypatched_DatagramProtocol(dns._asyncio_backend._DatagramProtocol):
|
||||||
|
def error_received(self, exc): # pragma: no cover
|
||||||
|
if self.recvfrom and not self.recvfrom.done():
|
||||||
|
self.recvfrom.set_exception(exc)
|
||||||
|
|
||||||
|
def connection_lost(self, exc):
|
||||||
|
if self.recvfrom and not self.recvfrom.done():
|
||||||
|
self.recvfrom.set_exception(exc)
|
||||||
|
|
||||||
|
dns._asyncio_backend._DatagramProtocol = monkeypatched_DatagramProtocol
|
||||||
|
|
||||||
|
try:
|
||||||
|
asyncio.run(main())
|
||||||
|
except (SystemExit, KeyboardInterrupt):
|
||||||
|
sys.exit(3)
|
Loading…
Reference in New Issue
Block a user