diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..54e19e9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM python:3.11-slim-bookworm + +WORKDIR /app + +COPY main.py requirements.txt /app + +RUN pip3 install -r requirements.txt --no-cache-dir + +ENTRYPOINT ["python3", "main.py"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..6cff64f --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +### Build an image + +docker build . -t dns-watcher + +### Run a container + +docker run --rm --env DOMAINS_LIST_PATH=/app/domains.yaml --env DNS_SERVER=1.1.1.1 --env RESOLUTION_PROTOCOL=UDP --volume ./domains.yaml:/app/domains.yaml dns-watcher diff --git a/main.py b/main.py index b5ac065..67f787a 100644 --- a/main.py +++ b/main.py @@ -1,12 +1,65 @@ import sys import warnings import os +import dns.message +import dns.name +import dns.query +import dns.rdata +import dns.rrset import requests +import random from urllib.parse import urlparse +from urllib3.util import connection warnings.filterwarnings("ignore") domains_list_path = os.environ.get('DOMAINS_LIST_PATH', './domains.yaml') +dns_server = os.environ.get('DNS_SERVER', '1.1.1.1') +resolution_protocol = os.environ.get('RESOLUTION_PROTOCOL', 'UDP') +timeout = 5 + +def resolve(host): + ips = [] + hosts = [host] + while len(hosts) > 0: + next_host = hosts.pop() + try: + name = dns.name.from_text(next_host) + query = dns.message.make_query(name, dns.rdatatype.A) + match resolution_protocol: + case 'UDP': + response = dns.query.udp(query, dns_server, timeout) + case 'HTTPS': + response = dns.query.https(query, dns_server, timeout) + answers = response.answer + for answer in answers: + for record in answer: + address = record.to_text() + if address[len(address) - 1] != ".": + ips.append(record.to_text()) + else: + hosts.append(address) + except: + pass + print("debug: host '{0}' has been resolved via {1} using {2} into the following addresses: {3}".format(host, dns_server, resolution_protocol, ips)) + return ips + +create_connection_original = connection.create_connection + +def create_connection_patched(address, *args, **kwargs): + host, port = address + ips = resolve(host) + if len(ips) > 0: + ip = ips[random.randint(0, len(ips) - 1)] + print("debug: {0} will be used".format(ip)) + return create_connection_original((ip, port), *args, **kwargs) + else: + raise Exception() + +connection.create_connection = create_connection_patched + +session = requests.Session() +session.trust_env = False try: domains_list = open(domains_list_path, 'r') @@ -16,10 +69,9 @@ sys.exit(1) for domain in domains: - print(domain) try: - request = requests.get('https://' + domain, verify=False) - final_domain = urlparse(request.url).netloc - print("\t" + final_domain) + response = session.get('http://' + domain, verify=False) + final_domain = urlparse(response.url).netloc except: - print() + pass + print() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b922a4a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,14 @@ +anyio==4.3.0 +certifi==2024.2.2 +charset-normalizer==3.3.2 +dnspython==2.6.1 +h11==0.14.0 +h2==4.1.0 +hpack==4.0.0 +httpcore==1.0.5 +httpx==0.27.0 +hyperframe==6.0.1 +idna==3.6 +requests==2.31.0 +sniffio==1.3.1 +urllib3==2.2.1 \ No newline at end of file