DNS nie działa, jeśli to zrobię, podaje ten błąd i idk, co sprawia, że daje mi to błąd:

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

I napisałem ten kod dla mojego serwera 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)

I ten rekord wartości na samym dole Buildresponse, wystarczy wydrukować @origin Idk Co jest problemem, a potem stworzyłem ten post i Pls.

Pls Pomóż!

0
Eiskalter Freund 20 listopad 2020, 23:02

1 odpowiedź

Najlepsza odpowiedź

Dobra, więc teraz pokazałeś, że wartość records jest następującym słownikiem:

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'}]}

Oznacza to, że jeśli miałbyś pętli przez niego, jak obecnie robisz - for record in records - Wiemy, że ponieważ jest to słownikiem, każdy record będzie kluczem tego słownika (zgodnie z This ). Więc następujący kod:

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

Daje następującą wypchnięć - czyli tylko wszystkie klucze w słowniku:

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

Oznacza to, że jeśli spróbujesz uzyskać dostęp do record["ttl"] lub record["value"], ponieważ record jest ciągiem, będzie to jak próba zrobienia czegoś takiego jak {x3}}, co dałoby błąd string indices must be integers.

Jednak problem nie zostanie rozwiązany, wystarczy wymianować record za pomocą records, ponieważ obiekt records ma nr "value" lub "ttl". Wygląda na to, że faktycznie próbujesz pętli przez każdą wartość w polu "a" w słowniku records, ponieważ jego wartość jest tablicą słowników, które mają zarówno "ttl", jak i "ttl" X8}} Klucz:

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

Dlatego twoja poprawka byłaby po prostu:

for record in records["a"]:
    dnsbody += rectobytes(domainname, rectype, record["ttl"], record["value"])
1
Random Davis 14 grudzień 2020, 16:00