From d5edf9e18b6aa6749559c5d81ac3f234f61ab3cb Mon Sep 17 00:00:00 2001 From: amammad Date: Fri, 19 May 2023 05:16:05 -0700 Subject: [PATCH 1/5] Update dns.py when we use subdomains as registered domain like `dns.domain.com` there is a logical error, i try to fix it very simply. the reason of using three level domain name is that: dns.domain.com has a ns record to dnsfookupServerIP.domain.com which any subdomain of *.dns.domain.com will ask their records from dnsfookupServerIP.domain.com, so it is easily possible with this commit to only with having one domain we use dnsfookup as a production/publicly available server --- BE/dns.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/BE/dns.py b/BE/dns.py index 74d6ca2f..86bdbe47 100644 --- a/BE/dns.py +++ b/BE/dns.py @@ -117,6 +117,7 @@ def buildResponse(d, ADDR, PORT): data = DNSRecord.parse(d) qtype = QTYPE[data.q.qtype] domain = str(data.q.qname).split('.') + domain_not_splited = str(data.q.qname).strip(". ") rtype = 1 # A reply = DNSRecord(DNSHeader(id=data.header.id, qr=1, aa=1, ra=1), q=data.q) fail_reply = reply if USE_FAILURE else gen_nxdomain_reply(data) @@ -128,7 +129,7 @@ def buildResponse(d, ADDR, PORT): Request format: dig some.random.subdomains.{uuid}.gel0.space """ - if '.'.join(domain[-3:-1]) != host_domain and use_fail_ns: + if not domain_not_splited.endswith(host_domain) and use_fail_ns: print(f'{str(datetime.now())} - {ADDR}:{PORT} {".".join(domain[-3:-1])} is not my thing NS => {fail_ns}') fail_reply.add_answer(RR(rname = '.'.join(domain), rtype = 2, rclass = 1, rdata = NS(fail_ns))) return fail_reply.pack() @@ -138,8 +139,9 @@ def buildResponse(d, ADDR, PORT): fail_reply.add_answer(RR(rname = '.'.join(domain), rtype = rtype, rclass = 1, rdata = A(FAILURE_IP))) if USE_FAILURE else 0 return fail_reply.pack() - subs = domain[:-3] - uuid = subs[-1] + subs = domain_not_splited.removesuffix(host_domain).strip(". ") + subs_splited = subs.split(".") + uuid = subs_splited[-1] """ Check for uuid in redis From 88392cf033f522968a20eb49269dd1fb9d4bdeed Mon Sep 17 00:00:00 2001 From: amammad Date: Fri, 19 May 2023 05:29:07 -0700 Subject: [PATCH 2/5] Update dns.py maybe the users set host_domain like `domain.com.` which an additional . or extra space character is added, we want to sure that there isn't any further problem about this. --- BE/dns.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BE/dns.py b/BE/dns.py index 86bdbe47..1a1ff50d 100644 --- a/BE/dns.py +++ b/BE/dns.py @@ -21,7 +21,7 @@ USE_FAILURE = config['dns']['use_failure_ip'] FAILURE_IP = config['dns']['failure_ip'] -host_domain = config['dns']['domain'] +host_domain = config['dns']['domain'].strip(". ") use_fail_ns = config['dns']['use_fail_ns'] fail_ns = config['dns']['fail_ns'] From 9a7fe20e4cceb69fbca0205b9e51496675ee0712 Mon Sep 17 00:00:00 2001 From: amammad Date: Fri, 19 May 2023 07:20:35 -0700 Subject: [PATCH 3/5] Update dns.py revert last commit --- BE/dns.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BE/dns.py b/BE/dns.py index 1a1ff50d..86bdbe47 100644 --- a/BE/dns.py +++ b/BE/dns.py @@ -21,7 +21,7 @@ USE_FAILURE = config['dns']['use_failure_ip'] FAILURE_IP = config['dns']['failure_ip'] -host_domain = config['dns']['domain'].strip(". ") +host_domain = config['dns']['domain'] use_fail_ns = config['dns']['use_fail_ns'] fail_ns = config['dns']['fail_ns'] From 03f8ceba0d672b2589d50dc4279ce3c8967ffb21 Mon Sep 17 00:00:00 2001 From: amammad Date: Fri, 19 May 2023 07:40:09 -0700 Subject: [PATCH 4/5] Update dns.py --- BE/dns.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/BE/dns.py b/BE/dns.py index 86bdbe47..f548786e 100644 --- a/BE/dns.py +++ b/BE/dns.py @@ -139,8 +139,14 @@ def buildResponse(d, ADDR, PORT): fail_reply.add_answer(RR(rname = '.'.join(domain), rtype = rtype, rclass = 1, rdata = A(FAILURE_IP))) if USE_FAILURE else 0 return fail_reply.pack() - subs = domain_not_splited.removesuffix(host_domain).strip(". ") - subs_splited = subs.split(".") + """ + e.g. host_domain is a.b.c.com and domain_not_splited(received dns query qname) is d.org.uuid.a.b.c.com + first we have d.org.uuid after removesuffix method + then we strip "." and " " + then we have ["d","org","uuid"] + so in this way we can reach uuid + """ + subs_splited = domain_not_splited.removesuffix(host_domain).strip(". ").split(".") uuid = subs_splited[-1] """ From e809dc87f0b923b14fd21369368eef14fe8ec1ac Mon Sep 17 00:00:00 2001 From: amammad Date: Mon, 22 May 2023 08:45:34 +0200 Subject: [PATCH 5/5] pack up by function for better documentation --- .gitignore | 1 + BE/dns.py | 75 ++++++++++++++++++++++++++++----------------- BE/requirements.txt | 27 ++++++++-------- RunBE.sh | 6 ++++ 4 files changed, 67 insertions(+), 42 deletions(-) create mode 100644 RunBE.sh diff --git a/.gitignore b/.gitignore index a388edd5..e3d72608 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ FE/node_modules */__pycache__ .DS_Store +.idea/* \ No newline at end of file diff --git a/BE/dns.py b/BE/dns.py index f548786e..4e3179e6 100644 --- a/BE/dns.py +++ b/BE/dns.py @@ -1,5 +1,4 @@ import sys -import time import threading import traceback import socketserver as SocketServer @@ -26,12 +25,12 @@ fail_ns = config['dns']['fail_ns'] redis_config = { - 'host': config['redis']['host'], - 'port': config['redis']['port'], - 'password': config['redis']['password'] + 'host': config['redis']['host'], + 'port': config['redis']['port'], + 'password': config['redis']['password'] } -REDIS_EXP = config['redis']['expiration'] #seconds -redis = StrictRedis(socket_connect_timeout = config['redis']['timeout'],**redis_config) +REDIS_EXP = config['redis']['expiration'] # seconds +redis = StrictRedis(socket_connect_timeout=config['redis']['timeout'], **redis_config) """ *** CONFIG *** @@ -83,12 +82,14 @@ def save_to_db(self): setJson = lambda uid, data: redis.setex(uid, REDIS_EXP, json.dumps(data)) getJson = lambda uid: json.loads(redis.get(uid)) + def gen_nxdomain_reply(request): - # Stolen from https://github.com/major1201/dns-router/blob/master/dns-router.py + # Stolen from https://github.com/major1201/dns-router/blob/master/dns-router.py + + reply = request.reply() + reply.header.rcode = getattr(RCODE, 'NXDOMAIN') + return reply - reply = request.reply() - reply.header.rcode = getattr(RCODE, 'NXDOMAIN') - return reply def getResType(type): """ @@ -102,11 +103,25 @@ def getResType(type): except: pass """ types = { - "A": (1,A), + "A": (1, A), "AAAA": (28, AAAA), "CNAME": (5, CNAME) } - return(types[type]) + return (types[type]) + + +""" +e.g. host_domain is a.b.c.com and domain_not_splited(received dns query qname) is d.org.uuid.a.b.c.com +first we have d.org.uuid after removesuffix method +then we strip "." and " " +then we have ["d","org","uuid"] +so in this way we can reach uuid +""" + + +def GetUuid(Domain): + return Domain.removesuffix(host_domain).strip(". ").split(".")[-1] + def buildResponse(d, ADDR, PORT): """ @@ -118,7 +133,7 @@ def buildResponse(d, ADDR, PORT): qtype = QTYPE[data.q.qtype] domain = str(data.q.qname).split('.') domain_not_splited = str(data.q.qname).strip(". ") - rtype = 1 # A + rtype = 1 # A reply = DNSRecord(DNSHeader(id=data.header.id, qr=1, aa=1, ra=1), q=data.q) fail_reply = reply if USE_FAILURE else gen_nxdomain_reply(data) """ @@ -131,23 +146,24 @@ def buildResponse(d, ADDR, PORT): if not domain_not_splited.endswith(host_domain) and use_fail_ns: print(f'{str(datetime.now())} - {ADDR}:{PORT} {".".join(domain[-3:-1])} is not my thing NS => {fail_ns}') - fail_reply.add_answer(RR(rname = '.'.join(domain), rtype = 2, rclass = 1, rdata = NS(fail_ns))) + fail_reply.add_answer(RR(rname='.'.join(domain), rtype=2, rclass=1, rdata=NS(fail_ns))) return fail_reply.pack() if len(domain) < 4: - print(f'{str(datetime.now())} - {ADDR}:{PORT} {".".join(domain[:-1])} => No subdomain, no fun => {FAILURE_IP if USE_FAILURE else "NXDOMAIN"}') + print( + f'{str(datetime.now())} - {ADDR}:{PORT} {".".join(domain[:-1])} => No subdomain, no fun => {FAILURE_IP if USE_FAILURE else "NXDOMAIN"}') + fail_reply.add_answer( + RR(rname='.'.join(domain), rtype=rtype, rclass=1, rdata=A(FAILURE_IP))) if USE_FAILURE else 0 + return fail_reply.pack() - fail_reply.add_answer(RR(rname = '.'.join(domain), rtype = rtype, rclass = 1, rdata = A(FAILURE_IP))) if USE_FAILURE else 0 + uuid = GetUuid(domain_not_splited) + # this can help to performance as we don't need to request for invalid uuid to redis + if len(uuid) != 32: + print( + f'{str(datetime.now())} - {ADDR}:{PORT} {".".join(domain[:-1])} => No UUID, no fun => {FAILURE_IP if USE_FAILURE else "NXDOMAIN"}') + fail_reply.add_answer( + RR(rname='.'.join(domain), rtype=rtype, rclass=1, rdata=A(FAILURE_IP))) if USE_FAILURE else 0 return fail_reply.pack() - """ - e.g. host_domain is a.b.c.com and domain_not_splited(received dns query qname) is d.org.uuid.a.b.c.com - first we have d.org.uuid after removesuffix method - then we strip "." and " " - then we have ["d","org","uuid"] - so in this way we can reach uuid - """ - subs_splited = domain_not_splited.removesuffix(host_domain).strip(". ").split(".") - uuid = subs_splited[-1] """ Check for uuid in redis @@ -161,8 +177,10 @@ def buildResponse(d, ADDR, PORT): props = DnsModel.get_props(uuid)["props"] setJson(uuid, json.loads(props)) except: - print(f'{str(datetime.now())} - {ADDR}:{PORT} {".".join(domain)[:-1]} (doesn\'t exist) => {FAILURE_IP if USE_FAILURE else "NXDOMAIN"}') - fail_reply.add_answer(RR(rname = '.'.join(domain), rtype = rtype, rclass = 1, rdata = A(FAILURE_IP))) if USE_FAILURE else 0 + print( + f'{str(datetime.now())} - {ADDR}:{PORT} {".".join(domain)[:-1]} (doesn\'t exist) => {FAILURE_IP if USE_FAILURE else "NXDOMAIN"}') + fail_reply.add_answer( + RR(rname='.'.join(domain), rtype=rtype, rclass=1, rdata=A(FAILURE_IP))) if USE_FAILURE else 0 return fail_reply.pack() """ @@ -226,9 +244,10 @@ def buildResponse(d, ADDR, PORT): new_log.save_to_db() print(resolve_to) - reply.add_answer(RR(rname = '.'.join(domain), rtype = rtype, rclass = 1, rdata = rfunc(resolve_to))) + reply.add_answer(RR(rname='.'.join(domain), rtype=rtype, rclass=1, rdata=rfunc(resolve_to))) return reply.pack() + # Stolen: # https://gist.github.com/andreif/6069838 diff --git a/BE/requirements.txt b/BE/requirements.txt index 7ad49654..29ba27cc 100644 --- a/BE/requirements.txt +++ b/BE/requirements.txt @@ -1,17 +1,16 @@ -dnslib -validators -redis -jsonschema -uuid +dnslib==0.9.23 +validators==0.20.0 +redis==4.5.5 +jsonschema==3.2.0 +uuid==1.30 flask_jwt_extended==3.25.1 -flask_restful -datetime -passlib -sqlalchemy -flask_cors -dnslib -Flask-SQLAlchemy -psycopg2-binary -redis +flask_restful==0.3.9 +datetime==5.1 +passlib==1.7.4 +sqlalchemy==1.4.31 +flask_cors==3.0.10 +Flask-SQLAlchemy==2.5.1 +psycopg2-binary==2.9.6 flask==1.1.4 MarkupSafe==2.0.1 +pyyaml==6.0 \ No newline at end of file diff --git a/RunBE.sh b/RunBE.sh new file mode 100644 index 00000000..41bff5a5 --- /dev/null +++ b/RunBE.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +python3 -m venv venv +source venv/bin/activate +pip3 install -r BE/requirements.txt +python3 BE/dns.py & +flask BE/run -h 0.0.0.0 \ No newline at end of file