DNS 服务器没有响应

DNS Server doesnt response

如果我这样做,dns 不起作用,它给出了这个错误,我不知道这是怎么回事,它只是给我这个错误:

Traceback (most recent call last):
  File "c:\Users\engin\Downloads\All files\dns.py", line 160, in <module>
    r = buildresponse(data)
  File "c:\Users\engin\Downloads\All files\dns.py", line 155, in buildresponse
    dnsbody += rectobytes(domainname, rectype, record["ttl"], record["value"])
TypeError: string indices must be integers

我确实为我的 DNS 服务器编写了这段代码:

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((ip, port))

def load_zone():
    jsonzone = {}
    zonefiles = glob.glob('zones/*.zone')
    
    
    for zone in zonefiles:
        with open(zone) as zonedata:
            data = json.load(zonedata)
            zonename = data["$origin"]
            jsonzone[zonename] = data
    return jsonzone

zonedata = load_zone()

def getFlags(flags):
    byte1 = bytes(flags[:1])
    byte2 = bytes(flags[1:2])

    rflags = ''

    QR = '1'

    OPCODE = ''

    for bit in range(1,5):
        OPCODE += str(ord(byte1) & (1<<bit))
    
    AA = '1'

    TC = '0'

    RD = '0'

    RA = '0'

    Z= '000'

    RCODE = '0000'

    return(int(QR + OPCODE + AA + TC + RD, 2).to_bytes(1, byteorder='big') + int(RA + Z + RCODE, 2).to_bytes(1, byteorder='big'))

def getquestiondomain(data):
    state = 0
    expectedlenght = 0
    domainsting = ''
    domainparts = []
    x = 0
    y = 0

    for byte in data:
        if state == 1:
            if byte != 0:
                domainsting += chr(byte)
            x += 1
            if x == expectedlenght:
                domainparts.append(domainsting)
                domainsting = ''
                state = 0
                x = 0
            if byte == 0:
                domainparts.append(domainsting)
                break
        else:
            state = 1
            expectedlenght = byte
        # x += 1
        y += 1

    questiontype = data[y + 1 : y + 3]
            
    return(domainparts, questiontype)

def getzone(domain):
    global zonedata
    zone_name = '.'.join(domain)
    return zonedata[zone_name]

def getrecs(data):
    domain, questiontype = getquestiondomain(data)
    qt = ''

    if questiontype == b'\x00\x01':
        qt = 'a'
    
    zone = getzone(domain)

    return (zone, qt, domain)

def rectobytes(domainname, rectype, recttl, recval):
    rbytes = b'\xc0\x0c'
    if rectype == 'a':
        rbytes = rbytes + bytes([0]) + bytes([1])
    
    rbytes = rbytes + bytes([0]) + bytes([1])

    rbytes += int(recttl).to_bytes(4, byteorder='big')

    if rectype == 'a':
        rbytes = rbytes + bytes([0]) + bytes([4])

        for part in recval.split('.'):
            rbytes += bytes([int(part)])
    return rbytes

def buildquestion(domainname, rectype):
    qbytes = b''

    for part in domainname:
        lenght = len (part)
        qbytes += bytes([lenght])

        for char in part:
            qbytes += ord(char).to_bytes(1, byteorder='big')
        if rectype == 'a':
            qbytes += (1).to_bytes(2, byteorder='big')
        qbytes += (1).to_bytes(2, byteorder='big')
    return qbytes

def buildresponse(data):
    TransactionID = data[:2]
    
    # TID = ''
    # for byte in TransactionID:
        # TID += hex(byte)
    
    Flags = getFlags(data[2:4])

    QDCOUNT = b'\x00\x01'

    # getquestiondomain(data[12:])

    ANCOUNT = len(getrecs(data[12:])[0]).to_bytes(2, byteorder='big')

    NSCOUNT = (0).to_bytes(2, byteorder='big')

    ARCOUNT = (0).to_bytes(2, byteorder='big')

    dnsheader = TransactionID + Flags + QDCOUNT + ANCOUNT + NSCOUNT + ARCOUNT
    
    dnsbody = b''

    records, rectype, domainname = getrecs(data[12:])

    dnsquestion = buildquestion(domainname, rectype)

    for record in records:
        dnsbody += rectobytes(domainname, rectype, record["ttl"], record["value"])
    return dnsheader + dnsquestion + dnsbody

while 1:
    data, addr = sock.recvfrom(512)
    r = buildresponse(data)
    sock.sendto(r, addr)

这个值记录在 buildresponse 最底部的 for 中,它只是打印出来 @origin 不知道是什么问题,然后我创建了这个 Post 并请帮助。

请帮忙!

好的,现在您已经证明您的 records 值是以下字典:

records =  {'$origin': 'status.minecraft.de.', '$ttl': 3600, 'soa': {'mname': 'ns1.status.minecraft.de.', 'rname': 'admin.status.minecraft.de.', 'serial': '{time}', 'refresh': 3600, 'retry': 600, 'expire': 604800, 'minimum': 86400}, 'ns': [{'host': 'ns1.status.minecraft.de.'}, {'host': 'ns2.status.minecraft.de.'}], 'a': [{'name': '@', 'ttl': 400, 'value': '255.255.255.255'}, {'name': '@', 'ttl': 400, 'value': '127.0.0.1'}, {'name': '@', 'ttl': 400, 'value': '127.0.0.1'}]}

这意味着,如果您按照当前的方式遍历它 - for record in records - 我们知道,因为它是一个字典,所以每个 record 都将是该字典的一个键(如每 this)。所以,下面的代码:

for record in records:
    print(record)
    print(type(record))

给出以下输出 - 这只是字典中的所有键:

$origin
<class 'str'>
$ttl
<class 'str'>
soa
<class 'str'>
ns
<class 'str'>
a
<class 'str'>

因此,这意味着如果您尝试访问 record["ttl"]record["value"],因为 record 是一个字符串,这就像尝试执行类似 "$ttl"["ttl"],这会给出错误 string indices must be integers.

但是,将 record 替换为 records 并不能解决问题,因为 records 对象没有 "value""ttl"钥匙。看来您实际上是在尝试遍历 records 字典中 "a" 键中的每个值,因为它的值是一个包含 "ttl" 和 [= 的字典数组26=]键:

[{'name': '@', 'ttl': 400, 'value': '255.255.255.255'}, {'name': '@', 'ttl': 400, 'value': '127.0.0.1'}, {'name': '@', 'ttl': 400, 'value': '127.0.0.1'}]

因此,您的解决方法很简单:

for record in records["a"]:
    dnsbody += rectobytes(domainname, rectype, record["ttl"], record["value"])