def genError(rcode, data): #------------------------------------------------------------------------------- ## generate header packet = pbf.BitField(12) packet[:2] = data[:2] packet[2] = 0x81 packet[3] = 0x80 | rcode return packet
def genCNAME(name): #------------------------------------------------------------------------------- msg = pbf.BitField([]) for lbl in name.split('.'): msg.append(len(lbl)) ## set length of this label msg.extend(bytes(lbl)) ## add the label msg.append(0) ## add the zero length root label return msg
def main(argv): #------------------------------------------------------------------------------- args, opts = oss.gopt(argv[1:], [], []) # # set up database creating reverse mappings and some aliases # db = dict(DNS_DATABASE) for name, addr in DNS_DATABASE.items(): a, b, c, d = addr.split('.') db[d + '.' + c + '.' + b + '.' + a + '.in-addr.arpa.'] = (name + '.work.', 1) db[name + '.work.'] = (addr, 0) db['m' + d + '.work.'] = (addr, 0) db['h' + d + '.work.'] = (addr, 0) pprint.pprint(db) print() ## start server udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) udps.bind(('', 53)) try: while 1: data, addr = udps.recvfrom(1024) data = pbf.BitField(data) opcode, query = getQuery(data) query = unicode(query) print('---\nQuery: ', opcode, '-> "%s"' % query) if opcode != 0: udps.sendto(genError(4, data), addr) continue if query in db: ip_name, ptr = db[query] resp = genResponse(ip_name, ptr, data) udps.sendto(resp, addr) print('Response: %s -> %s' % (query, ip_name)) else: err, aa, addrs, aliases = dns.sendDNSQuery( query[:-1], '192.168.1.1') if err == 0: resp = genResponse(addrs[0], 0, data) udps.sendto(resp, addr) print('Response: %s -> %s' % (query, addrs[0])) else: udps.sendto(genError(3, data), addr) except KeyboardInterrupt: udps.close() oss.exit(0)
def genResponse(ip_name, ptrRec, data): #------------------------------------------------------------------------------- packet = pbf.BitField(12) aRec = not ptrRec ## generate header packet[:2] = data[:2] packet[2] = 0x84 packet[3] = 0x80 packet.setM(4, 2, 1) packet.setM(6, 2, 1) ## copy original question packet.extend(data[12:]) ## create answer packet.append(0xc0) # use pointer packet.append(0x0c) # to domain name in question packet.append(0) # root if aRec: packet.append(1) # response type - A record else: packet.append(12) # response type - PTR record packet.addM(2, 1) # class (IN) packet.addM(4, 0xa5a5a5a5) # ttl if aRec: packet.addM(2, 4) # rdata_length packet.extend([int(x) for x in ip_name.split('.')]) else: name = dns.genCNAME(ip_name) packet.addM(2, len(name)) # rdata_length packet.extend(dns.genCNAME(ip_name)) return packet
def sendDNSQuery(name, nameServerIPAddr, dump=False): #------------------------------------------------------------------------------- id = random.randint(0, 2**16 - 1) msg = pbf.BitField(12) msg.setM(0, 2, id) ## set the id msg.setBit(2, 0, 1) ## set recursion request msg.setM(4, 2, 1) ## set query count to 1 for lbl in name.split('.'): msg.append(len(lbl)) ## set length of this label msg.extend(bytes(lbl)) ## add the label msg.append(0) ## add the zero length root label msg.addM(2, 1) ## set qtype msg.addM(2, 1) ## set qclass if dump: print('Sent packet:') msg.hexDump() print() ## send packet udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) udps.sendto(msg, (nameServerIPAddr, 53)) ## get packet data = pbf.BitField(udps.recv(1024)) ## ensure it is the correct request if id == data.getM(0, 2): if dump: print('Recved packet:') pbf.hexDump(data) print() #print('QR:', data.getBit(2, 7)) AA = data.getBit(2, 2) #print('AA:', data.getBit(2, 2)) #print('RD:', data.getBit(2, 0)) #print('RA:', data.getBit(3, 7)) #print('Opcode:', data.getBits(3, 3, 6)) rcode = data.getBits(3, 0, 3) #print('RCODE:', rcode) if dump: print('Q records:', data.getM(4, 2)) print('A records:', data.getM(6, 2)) print('NS records:', data.getM(8, 2)) print('Additional records:', data.getM(10, 2)) if rcode != 0: return rcode, 0, [], [] ## get question records for i in range(data.getM(4, 2)): idx, name = getCNAME(12, data) idx += 5 ## get answers idx, ipaddrs, aliases = getAnswerRecords(idx, data) if dump: print() pbf.hexDump(data[idx:]) print() for i in range(data.getM(8, 2)): idx, name = getCNAME(idx, data) print('NS:', name) print() pbf.hexDump(data[idx:]) print() return 0, AA, ipaddrs, aliases