diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3ecb8fc --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "[python]": { + "editor.defaultFormatter": "ms-python.autopep8" + }, + "python.formatting.provider": "none" +} diff --git a/client/clientconf.yaml b/client/clientconf.yaml deleted file mode 100644 index e69de29..0000000 diff --git a/client/dnssender.py b/client/dnssender.py deleted file mode 100644 index 2df59c0..0000000 --- a/client/dnssender.py +++ /dev/null @@ -1,24 +0,0 @@ -import dns.resolver - - -def resolver(domain): - # 构造 DNS 查询请求 - qtype = 'A' - - # 发送 DNS 查询请求 - resolver = dns.resolver.Resolver() - resolver.nameservers = ["127.0.0.1"] - - try: - ip = resolver.resolve(domain, qtype)[0] - return ip - except dns.resolver.NXDOMAIN: - print("can't find IP") - - - - -if __name__ == "__main__": - domain = 'mamahaha.work' - ip = resolver(domain) - print(ip) \ No newline at end of file diff --git a/client/main.py b/client/main.py deleted file mode 100644 index cba3dde..0000000 --- a/client/main.py +++ /dev/null @@ -1,66 +0,0 @@ -from cryptography.hazmat.primitives.asymmetric import rsa, padding -from cryptography.hazmat.primitives import serialization, hashes -import base64 -import random - -# 生产随机域名 - - -def generate_domain() -> str: - domain = random.getrandbits(64) - domain = hex(domain)[2:] - return domain + ".xiaomian" - - -def generate_key(): - - # Generate a new RSA key pair - private_key = rsa.generate_private_key( - public_exponent=65537, - key_size=2048 - ) - public_key = private_key.public_key() - - # Convert keys to bytes - private_key_bytes = private_key.private_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PrivateFormat.PKCS8, - encryption_algorithm=serialization.NoEncryption() - ) - public_key_bytes = public_key.public_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PublicFormat.SubjectPublicKeyInfo - ) - - # Encode bytes as base64 - private_key_base64 = base64.b64encode(private_key_bytes).decode('utf-8') - public_key_base64 = base64.b64encode(public_key_bytes).decode('utf-8') - - return private_key_base64, public_key_base64 - - -# # Encrypt a message using the public key -# message = b"Hello World" -# encrypted_message = public_key.encrypt( -# message, -# padding.OAEP( -# mgf=padding.MGF1(algorithm=hashes.SHA256()), -# algorithm=hashes.SHA256(), -# label=None -# ) -# ) - -# # Decrypt the message using the private key -# decrypted_message = private_key.decrypt( -# encrypted_message, -# padding.OAEP( -# mgf=padding.MGF1(algorithm=hashes.SHA256()), -# algorithm=hashes.SHA256(), -# label=None -# ) -# ) -# print(decrypted_message) -if __name__ == '__main__': - print("Welcome to my xiaomiao tor network") - domain = generate_domain() - private_key_base64, public_key_base64 = generate_key() diff --git a/database/initdb.py b/database/initdb.py index 8e1f7fe..0a22853 100644 --- a/database/initdb.py +++ b/database/initdb.py @@ -1,13 +1,13 @@ import sqlite3 +# 用于创建 db_file = 'database/dns.db' if __name__ == '__main__': conn = sqlite3.connect(db_file) cursor = conn.cursor() try: cursor.execute( - '''CREATE TABLE xiaomiandns(domain TEXT PRIMARY KEY, ip TEXT, pubkey TEXT, nodetype TEXT,timestamp DATETIME)''') - # node type contain 3 types: client, node, server + '''CREATE TABLE xiaomiandns(domain TEXT PRIMARY KEY, ip TEXT,timestamp DATETIME)''') except sqlite3.OperationalError: print("table xiaomiandns already exists") conn.commit() diff --git a/database/test.py b/database/test.py deleted file mode 100644 index 60921ea..0000000 --- a/database/test.py +++ /dev/null @@ -1,23 +0,0 @@ -import sqlite3 - -db_file = 'database/dns.db' -if __name__ == '__main__': - conn = sqlite3.connect(db_file) - cursor = conn.cursor() - domain = 'mamahaha.wor12' - ip = "1.1.1.11" - pubkey = "asdfasdfadfsdf" - cursor.execute("SELECT * FROM xiaomiandns WHERE domain = ? OR ip = ? OR pubkey = ?", - (domain, ip, pubkey)) - existing_data = cursor.fetchall() - if existing_data: - print("qqqqqq") - else: - # Insert the new data - cursor.execute( - "INSERT INTO xiaomiandns (domain, ip, pubkey) VALUES (?, ?, ?)", (domain, ip, pubkey)) - print("Data inserted successfully") - - conn.commit() - cursor.close() - conn.close() diff --git a/node/main.py b/node/main.py deleted file mode 100644 index 31e56f0..0000000 --- a/node/main.py +++ /dev/null @@ -1,2 +0,0 @@ -import yaml - diff --git a/node/nodeconf.yaml b/node/nodeconf.yaml deleted file mode 100644 index e69de29..0000000 diff --git a/node/proxy.py b/node/proxy.py deleted file mode 100644 index a7e2b90..0000000 --- a/node/proxy.py +++ /dev/null @@ -1,55 +0,0 @@ -import socket -import socketserver -import struct -import select - -class ThreadingTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): - pass - -class Socks5Handler(socketserver.BaseRequestHandler): - VERSION = 5 - - def handle(self): - # 客户端发送版本和方法 - version, nmethods = struct.unpack('!BB', self.request.recv(2)) - self.request.recv(nmethods) - - # 发送版本和方法响应 - self.request.sendall(struct.pack('!BB', self.VERSION, 0)) - - # 获取请求详情 - version, cmd, _, address_type = struct.unpack('!BBBB', self.request.recv(4)) - if address_type == 1: # IPv4 - address = socket.inet_ntoa(self.request.recv(4)) - else: - raise NotImplementedError('Only IPv4 is supported.') - port = struct.unpack('!H', self.request.recv(2))[0] - - # 发送响应 - self.request.sendall(struct.pack('!BBBBIH', self.VERSION, 0, 0, 1, - int(socket.inet_aton('0.0.0.0').hex(), 16), 0)) - - # 建立连接 - if cmd == 1: # CONNECT - remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - remote.connect((address, port)) - self.exchange_loop(self.request, remote) - else: - raise NotImplementedError('Only CONNECT is supported.') - - def exchange_loop(self, client, remote): - while True: - # Simple data exchange between client and remote - rlist, _, _ = select.select([client, remote], [], []) - if client in rlist: - data = client.recv(4096) - if remote.send(data) <= 0: - break - if remote in rlist: - data = remote.recv(4096) - if client.send(data) <= 0: - break - -if __name__ == '__main__': - with ThreadingTCPServer(('0.0.0.0', 1080), Socks5Handler) as server: - server.serve_forever() diff --git a/server/xiaomiandns.py b/server/xiaomiandns.py index aa0c16d..baf5c58 100644 --- a/server/xiaomiandns.py +++ b/server/xiaomiandns.py @@ -13,10 +13,12 @@ import re import base64 from cryptography.hazmat.primitives.asymmetric import rsa, padding from cryptography.hazmat.primitives import serialization, hashes +import yaml class DNSServer: + def __init__(self, hostname, port, db_file): self.hostname = hostname self.port = port @@ -90,12 +92,14 @@ class DNSServer: class DNSAPI: - # usage: use POST method - # /add - # data: domian=xxxx&ip=xx.xx.xx.xx&pubkey=xxxxx&nodetype=xxxx - # /delete - # data: domian=xxxx&ip=xx.xx.xx.xx&prikey=xxxxx&nodetype=xxxx - + """ + usage: use POST method + /add + data: domian=xxxx&ip=xx.xx.xx.xx + /delete + data: domian=xxxx&ip=xx.xx.xx.xx + """ + def __init__(self, hostname, port, db_file): self.hostname = hostname self.port = port @@ -131,7 +135,7 @@ class DNSAPI: data = request.split('\r\n')[-1] response = self.handle_post_request(url, data) else: - response = self.handle_error_request() + response = self.handle_error_request(url) return response @@ -195,9 +199,9 @@ class DNSAPI: def add_data(self, data): # parse and check validation - domain, ip, pubkey, nodetype = self.parse_data(data) + domain, ip = self.parse_data(data) - if not self.check_data(domain,ip,nodetype): + if not self.check_data(domain,ip): return 400 # connect db @@ -206,10 +210,10 @@ class DNSAPI: # Check if the data already exists c.execute( - "SELECT * FROM xiaomiandns WHERE domain = ? OR ip = ? OR pubkey = ? OR nodetype = ?", (domain, ip, pubkey, nodetype)) + "SELECT * FROM xiaomiandns WHERE domain = ? OR ip = ?", (domain, ip)) existing_data = c.fetchall() - cursor.close() + c.close() conn.close() if existing_data: @@ -217,102 +221,70 @@ class DNSAPI: else: # Insert the new data c.execute( - "INSERT INTO xiaomiandns (domain,ip,pubkey,nodetype,timestamp) VALUES (?,?,?,?,DATETIME('now'))", (domain, ip, pubkey, nodetype)) + "INSERT INTO xiaomiandns (domain,ip,timestamp) VALUES (?,?,DATETIME('now'))", (domain, ip)) return 200 - def delete_data(self, data): - + def delete_data(self, data:str) -> int: # parse and check validation - domain, ip, private_key_base64, nodetype = self.parse_data(data) + domain, ip = self.parse_data(data) - if not self.check_data(domain, ip ,nodetype): + if not self.check_data(domain, ip): return 400 # connect db + conn = sqlite3.connect(self.db_file) c = conn.cursor() c.execute( - "SELECT pubkey FROM xiaomiandns WHERE domain = ? AND ip = ? AND nodetype = ?", (domain, ip, nodetype)) - public_key_base64 = c.fetchone() - cursor.close() + "DELETE FROM xiaomiandns WHERE domain = ? AND ip = ?", (domain, ip)) + c.close() conn.close() + return 200 - if public_key_base64 != None: - public_key_base64 = public_key_base64[0] - else: - return 400 + def parse_data(self, data:str) -> str : + """parse data form post data - private_key_bytes = base64.b64decode( - private_key_base64).decode("utf-8") - - private_key = serialization.load_pem_private_key( - private_key_bytes, - password=None - ) - - gen_public_key = private_key.public_key() - gen_public_key_bytes = gen_public_key.public_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PublicFormat.SubjectPublicKeyInfo - ) - gen_public_key_base64 = base64.b64encode(gen_public_key_bytes).decode('utf-8') - - if gen_public_key_base64 == public_key_base64: - conn = sqlite3.connect(self.db_file) - c = conn.cursor() - c.execute( - "DELETE FROM xiaomiandns WHERE domain = ? AND ip = ? AND nodetype = ?", (domain, ip, nodetype)) - cursor.close() - conn.close() - return 200 - else: - return 400 - - def parse_data(self, data): + Args: + data (str): post data + Returns: + domain: domain name + ip: ip + """ domain = re.search(r'domain=([^&]+)', data) ip = re.search(r'ip=([^&]+)', data) - pubkey = re.search(r'pubkey=([^&]+)', data) - privkey = re.search(r'privkey=([^&]+)', data) - nodetype = re.search(r'nodetype=([^]+)', data) - if domain and ip and nodetype: + if domain and ip: domain = domain.group(1) ip = ip.group(1) - nodetype = nodetype.group(1) - if bool(pubkey) != bool(privkey): - if pubkey: - key = pubkey.group(1) - else: - key = privkey.group(1) - return domain, ip, key, nodetype + + return domain, ip - def check_data(self, domain, ip, nodetype): + def check_data(self, domain, ip): + """_summary_ + Args: + domain (_type_): _description_ + ip (_type_): _description_ + + Returns: + _type_: _description_ + """ # check domain - pattern = r'^[a-z0-9]{16}\.xiaomian$' - - if re.match(pattern, domain): - return True - else: - return False - + domain_pattern = r'^[a-z0-9]+\.xiaomian$' # check ip - pattern = r'^(\d{1,3}\.){3}\d{1,3}$' - if re.match(pattern, ip): + ip_pattern = r'^(\d{1,3}\.){3}\d{1,3}$' + if re.match(domain_pattern, domain) and re.match(ip_pattern, ip) : octets = ip.split('.') if all(int(octet) < 256 for octet in octets): return True - return False + else: + return False - # check nodetype - if nodetype in {"server", "client", "node"}: - return True - else: - return False if __name__ == '__main__': + with open('serverconf.yaml', 'r') as f: config = yaml.safe_load(f) db_file = config['database']['db_file'] @@ -321,16 +293,6 @@ if __name__ == '__main__': API_port = config['API']['port'] API_listen_host = config['API']['listen_host'] - - - - - - - - - - # start dns server server = DNSServer(API_listen_host, DNS_port, db_file) server.run()