#!/usr/bin/env python3
"""Lightweight DNS server for gnet.com zone on Tailscale IP."""

import socket
import struct
import sys

TAILSCALE_IP = "100.82.180.56"
PORT = 5353
TARGET_IP = TAILSCALE_IP  # nexus.gnet.com resolves to GHQMaster's tailnet IP
DOMAIN = "nexus.gnet.com"
TTL = 300

def build_response(query_data, qname, qtype):
    """Build a minimal DNS response."""
    tid = query_data[:2]
    flags = struct.pack("!H", 0x8580)  # Standard response, no error
    flags_no_rec = struct.pack("!H", 0x8580)  # Same for our non-recursive server

    # Question section (echo back)
    qsection = b''
    labels = qname.split('.')
    for label in labels:
        encoded = label.encode('ascii')
        qsection += bytes([len(encoded)]) + encoded
    qsection += b'\x00'
    qsection += struct.pack("!HH", qtype, 1)  # type + class IN

    # Answer section
    asection = b''
    if qtype in (1, 255):  # A or ANY
        # Name compression: pointer to beginning of question labels
        asection += b'\xc0\x0c'
        asection += struct.pack("!HHIH", 1, 1, TTL, 4)  # A, IN, TTL, len=4
        asection += socket.inet_aton(TARGET_IP)

    total = tid + flags + b'\x00\x01' + b'\x00\x01' + b'\x00\x00' + b'\x00\x00'
    total += qsection
    total += asection

    return total

def parse_query(data):
    """Extract qname and qtype from DNS query."""
    offset = 12  # Skip header
    qname_parts = []
    while True:
        length = data[offset]
        if length == 0:
            offset += 1
            break
        qname_parts.append(data[offset+1:offset+1+length].decode('ascii'))
        offset += length + 1
    qname = '.'.join(qname_parts)
    qtype = struct.unpack("!H", data[offset:offset+2])[0]
    return qname, qtype

def start():
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind((TAILSCALE_IP, PORT))
    print(f"DNS server listening on {TAILSCALE_IP}:{PORT} for {DOMAIN}")

    while True:
        try:
            data, addr = sock.recvfrom(512)
            qname, qtype = parse_query(data)
            if qname.endswith(DOMAIN) or qname == DOMAIN:
                response = build_response(data, qname, qtype)
                sock.sendto(response, addr)
                print(f"  {qname} → {TARGET_IP}  (from {addr[0]})", flush=True)
            # For non-nexus.gnet.com queries, silently drop
        except Exception as e:
            print(f"  error: {e}", flush=True)

if __name__ == "__main__":
    start()
