Advertisement
CSenshi

CN - HW2 (DNS)

Oct 10th, 2019
558
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 27.26 KB | None | 0 0
  1. import threading
  2. import socket
  3. import sys
  4. import os
  5. from struct import *
  6. import ipaddress
  7. import random
  8. from pprint import pprint
  9. from easyzone import easyzone
  10. from datetime import datetime, timedelta
  11.  
  12. # Hard Coded DNS Root Servers
  13. DNS_root_servers = [
  14.     ['A.ROOT-SERVERS.NET.', '3600000', 'A', '198.41.0.4'],
  15.     ['B.ROOT-SERVERS.NET.', '3600000', 'A', '192.228.79.201'],
  16.     ['C.ROOT-SERVERS.NET.', '3600000', 'A', '192.33.4.12'],
  17.     ['D.ROOT-SERVERS.NET.', '3600000', 'A', '199.7.91.13'],
  18.     ['E.ROOT-SERVERS.NET.', '3600000', 'A', '192.203.230.10'],
  19.     ['F.ROOT-SERVERS.NET.', '3600000', 'A', '192.5.5.241'],
  20.     ['G.ROOT-SERVERS.NET.', '3600000', 'A', '192.112.36.4'],
  21.     ['H.ROOT-SERVERS.NET.', '3600000', 'A', '128.63.2.53'],
  22.     ['I.ROOT-SERVERS.NET.', '3600000', 'A', '192.36.148.17'],
  23.     ['J.ROOT-SERVERS.NET.', '3600000', 'A', '192.58.128.30'],
  24.     ['K.ROOT-SERVERS.NET.', '3600000', 'A', '193.0.14.129'],
  25.     ['L.ROOT-SERVERS.NET.', '3600000', 'A', '199.7.83.42'],
  26.     ['M.ROOT-SERVERS.NET.', '3600000', 'A', '202.12.27.33']
  27. ]
  28.  
  29. # Server Configurations
  30. DNS_IP = '127.0.0.1'
  31. Local_DNS_Port = 5353
  32. DNS_Port = 53
  33. MAX_BUFFER_SIZE = 4096
  34. SOCKET_TIMEOUT = 0.3
  35.  
  36. # Cache structures
  37. server_ip_dict = {}
  38. request_response_dict = {}
  39.  
  40.  
  41. class PrintColors:
  42.     WAITING = '\033[5m'
  43.     HEADER = '\033[95m'
  44.     OKBLUE = '\033[94m'
  45.     OKGREEN = '\033[92m'
  46.     WARNING = '\033[93m'
  47.     FAIL = '\033[91m'
  48.     ENDC = '\033[0m'
  49.     BOLD = '\033[1m'
  50.     UNDERLINE = '\033[4m'
  51.  
  52.  
  53. class DnsWorker(threading.Thread):
  54.     def __init__(self, request, addr, sock, config_path):
  55.         super(DnsWorker, self).__init__()
  56.         self.config_path = config_path
  57.         self.sock = sock
  58.         self.request = request
  59.         self.addr = addr
  60.  
  61.     def run(self):
  62.         ans, resp = self.find_dns(self.request, 1)
  63.         if ans:
  64.             self.sock.sendto(resp, self.addr)
  65.             print(PrintColors.WAITING + PrintColors.OKGREEN + "Found Given Domain" + PrintColors.ENDC)
  66.         else:
  67.             question = {'total_questions': 1}
  68.             off = self.process_question(question, 12, self.request)
  69.             error_message = self.request
  70.  
  71.             # Change Flags
  72.             error_message = error_message[:2] + self.generate_error(self.request) + \
  73.                             error_message[12:off]
  74.             headers = self.process_request(self.request)
  75.  
  76.             self.save_response_in_cache(error_message, str(headers['questions'][0]))
  77.             self.sock.sendto(error_message, self.addr)
  78.             print(PrintColors.WAITING + PrintColors.FAIL + "Given Domain Data not Found!" + PrintColors.ENDC)
  79.  
  80.     def find_dns(self, request, depth):
  81.         headers = self.process_request(request)
  82.         domain_name = headers['questions'][0]['q_name']
  83.  
  84.         if self.config_contains(domain_name):
  85.             zone_file = self.read_config(domain_name)
  86.             ans, generated_data = self.generate_data_from_zone(zone_file, request, headers)
  87.             print(PrintColors.OKBLUE + PrintColors.BOLD + "Found Domain for {} In Configurations".format(
  88.                 domain_name.decode()[:-1]) + PrintColors.ENDC)
  89.             return ans, generated_data
  90.         elif self.check_for_valid_cache(str(headers['questions'][0])):
  91.             print(PrintColors.BOLD + "Found Data From Cache for domain {}".format(
  92.                 domain_name.decode()[:-1]) + PrintColors.ENDC)
  93.             res = request_response_dict[str(headers['questions'][0])][0]
  94.             if res[1] & 3:
  95.                 return False, self.generate_resonse_from_cache(str(headers['questions'][0]), request)
  96.             else:
  97.                 return True, self.generate_resonse_from_cache(str(headers['questions'][0]), request)
  98.         else:
  99.             ans, resp = self.dns_root_search(request, depth)
  100.             if ans:
  101.                 resp_headers = self.process_request(resp)
  102.                 self.save_response_in_cache(resp, str(headers['questions'][0]), resp_headers['answers'][0]['TTL'])
  103.             return ans, resp
  104.  
  105.     def check_for_valid_cache(self, dom_name):
  106.         if dom_name in request_response_dict:
  107.             cur_ans = request_response_dict[dom_name]
  108.             entry_date = cur_ans[1]
  109.             cur_date = datetime.now()
  110.             ttl = cur_ans[2]
  111.             if entry_date + timedelta(seconds=ttl) < cur_date:
  112.                 del request_response_dict[dom_name]
  113.                 return False
  114.             else:
  115.                 return True
  116.         else:
  117.             return False
  118.  
  119.     def generate_resonse_from_cache(self, key, request):
  120.         data = request[:2]
  121.         data += request_response_dict[key][0]
  122.         return data
  123.  
  124.     def generate_data_from_zone(self, zone_file, request, request_headers):
  125.         data = request[:2]
  126.         data += pack("!B", (request[2] | (1 << 7)))
  127.         data += pack("!B", request[3])
  128.         question = {'total_questions': 1}
  129.         off = self.process_question(question, 12, request)
  130.         q_type = request_headers['questions'][0]['q_type']
  131.         data += pack('!H', 1)
  132.  
  133.         ttl = 900
  134.         if q_type == 1 and zone_file.root.records('A'):
  135.             data += pack('!H', len(zone_file.root.records('A').items))
  136.             data += pack('!I', 0)
  137.             data += request[12:off]
  138.             for ans in zone_file.root.records('A').items:
  139.                 data += pack('!BB', (1 << 7) + (1 << 6), 12)
  140.  
  141.                 data += pack('!H', 1)
  142.                 data += pack('!H', 1)
  143.                 data += pack("!I", ttl)
  144.                 data += pack('!H', 4)
  145.                 ans = ans.split('.')
  146.                 for i in ans:
  147.                     data += pack('!B', int(i))
  148.         elif q_type == 2 and zone_file.root.records('NS'):
  149.             data += pack('!H', len(zone_file.root.records('NS').items))
  150.             data += pack('!I', 0)
  151.             data += request[12:off]
  152.             for aut in zone_file.root.records('NS').items:
  153.                 data += pack('!BB', (1 << 7) + (1 << 6), 12)
  154.  
  155.                 data += pack('!H', 2)
  156.                 data += pack('!H', 1)
  157.                 data += pack("!I", ttl)
  158.                 data += pack('!H', len(aut) + 1)
  159.                 data += self.build_domain_name(aut).encode()
  160.         elif q_type == 5 and zone_file.root.records('CNAME'):
  161.             data += pack('!H', len(zone_file.root.records('CNAME').items))
  162.             data += pack('!I', 0)
  163.             data += request[12:off]
  164.             for aut in zone_file.root.records('NS').items:
  165.                 data += pack('!BB', (1 << 7) + (1 << 6), 12)
  166.  
  167.                 data += pack('!H', 5)
  168.                 data += pack('!H', 1)
  169.                 data += pack("!I", ttl)
  170.                 data += pack('!H', len(aut) + 1)
  171.                 data += self.build_domain_name(aut).encode()
  172.         elif q_type == 15 and zone_file.root.records('MX'):
  173.             data += pack('!H', len(zone_file.root.records('MX').items))
  174.             data += pack('!I', 0)
  175.             data += request[12:off]
  176.             for pref, mx in zone_file.root.records('MX').items:
  177.                 data += pack('!BB', (1 << 7) + (1 << 6), 12)
  178.  
  179.                 data += pack('!H', 15)
  180.                 data += pack('!H', 1)
  181.                 data += pack("!I", ttl)
  182.                 data += pack('!H', len(mx) + 3)
  183.                 data += pack('!H', pref)
  184.                 data += self.build_domain_name(mx).encode()
  185.         elif q_type == 16 and zone_file.root.records('TXT'):
  186.             data += pack('!H', len(zone_file.root.records('TXT').items))
  187.             data += pack('!I', 0)
  188.             data += request[12:off]
  189.             for text in zone_file.root.records('TXT').items:
  190.                 data += pack('!BB', (1 << 7) + (1 << 6), 12)
  191.  
  192.                 data += pack('!H', 16)
  193.                 data += pack('!H', 1)
  194.                 data += pack("!I", ttl)
  195.                 data += pack('!H', len(text) - 1)
  196.                 data += pack('!B', len(text) - 2)
  197.                 data += text[1:-1].encode()
  198.         elif q_type == 28 and zone_file.root.records('AAAA'):
  199.             data += pack('!H', len(zone_file.root.records('AAAA').items))
  200.             data += pack('!I', 0)
  201.             data += request[12:off]
  202.             for ans in zone_file.root.records('AAAA').items:
  203.                 data += pack('!BB', (1 << 7) + (1 << 6), 12)
  204.  
  205.                 data += pack('!H', 28)
  206.                 data += pack('!H', 1)
  207.                 data += pack("!I", ttl)
  208.                 data += pack('!H', 16)
  209.                 ip_v6 = ipaddress.ip_address(ans)
  210.                 ip_v6 = ip_v6.exploded.split(':')
  211.                 print(ip_v6)
  212.                 for bit2 in ip_v6:
  213.                     hex_int = int(bit2, 16)
  214.                     data += pack('!H', hex_int)
  215.         elif q_type == 6 and zone_file.root.records('SOA'):
  216.             data += pack('!H', len(zone_file.root.records('SOA').items))
  217.             data += pack('!I', 0)
  218.             data += request[12:off]
  219.             for soa in zone_file.root.records('SOA').items:
  220.                 soa = soa.split(' ')
  221.                 data += pack('!BB', (1 << 7) + (1 << 6), 12)
  222.  
  223.                 data += pack('!H', 6)
  224.                 data += pack('!H', 1)
  225.                 data += pack("!I", ttl)
  226.                 data += pack('!H', 20 + len(soa[0]) + 2 + len(soa[1]))
  227.                 data += self.build_domain_name(soa[0]).encode()
  228.                 data += self.build_domain_name(soa[1]).encode()
  229.                 data += pack('!I', int(soa[2]))
  230.                 data += pack('!I', int(soa[3]))
  231.                 data += pack('!I', int(soa[4]))
  232.                 data += pack('!I', int(soa[5]))
  233.                 data += pack('!I', int(soa[6]))
  234.         else:
  235.             question = {'total_questions': 1}
  236.             error_message = request
  237.  
  238.             # Change Flags
  239.             error_message = error_message[:2] + self.generate_error(request) + \
  240.                             error_message[12:off]
  241.             return False, error_message
  242.  
  243.         return True, data
  244.  
  245.     def process_request(self, data):
  246.         res = {}
  247.         offset: int = 0
  248.  
  249.         # Headers
  250.         offset = self.process_header(res, offset, data)
  251.  
  252.         # Questions
  253.         offset = self.process_question(res, offset, data)
  254.  
  255.         # Answers
  256.         offset = self.process_answer(res, offset, data)
  257.  
  258.         # Authority
  259.         offset = self.process_authority(res, offset, data)
  260.  
  261.         # Additional
  262.         self.process_additional(res, offset, data)
  263.         return res
  264.  
  265.     def parse_flags(self, flag_bytes):
  266.         flags = {}
  267.         # first byte
  268.         flags['QR'] = (flag_bytes[0] & 0x80) >> 7  # 0x80 = 10000000
  269.         flags['Opcode'] = (flag_bytes[0] & 0x78) >> 3  # 0x78 = 01111000
  270.         flags['AA'] = (flag_bytes[0] & 0x04) >> 2  # 0x04 = 00000100
  271.         flags['TC'] = (flag_bytes[0] & 0x02) >> 1  # 0x02 = 00000010
  272.         flags['RD'] = (flag_bytes[0] & 0x01)  # 0x01 = 00000001
  273.  
  274.         # second byte
  275.         flags['RA'] = (flag_bytes[1] & 0x80) >> 7  # 0x80 = 10000000
  276.         flags['Z'] = (flag_bytes[1] & 0x40) >> 6  # 0x70  = 01000000
  277.         flags['AD'] = (flag_bytes[1] & 0x20) >> 5  # 0x70  = 00100000
  278.         flags['CD'] = (flag_bytes[1] & 0x10) >> 4  # 0x70  = 00010000
  279.         flags['RCODE'] = (flag_bytes[1] & 0x0f)  # 0x20  = 00001111
  280.  
  281.         return flags
  282.  
  283.     # Parsing Section 1 (Header)
  284.     def process_header(self, res, offset, data):
  285.         # Transaction ID
  286.         transaction_id = unpack('!H', data[offset: offset + 2])[0]
  287.         res['ID'] = transaction_id
  288.  
  289.         # Flags
  290.         offset += 2
  291.         flags = self.parse_flags(data[offset: offset + 2])
  292.         res['flags'] = flags
  293.  
  294.         # QDCOUNT
  295.         offset += 2
  296.         qd_count = unpack('!H', data[offset: offset + 2])[0]
  297.         res['total_questions'] = qd_count
  298.  
  299.         # ANCOUNT
  300.         offset += 2
  301.         an_count = unpack('!H', data[offset: offset + 2])[0]
  302.         res['total_answers'] = an_count
  303.  
  304.         # NSCOUNT
  305.         offset += 2
  306.         ns_count = unpack('!H', data[offset: offset + 2])[0]
  307.         res['total_authoritys'] = ns_count
  308.  
  309.         # ARCOUNT
  310.         offset += 2
  311.         ar_count = unpack('!H', data[offset: offset + 2])[0]
  312.         res['total_additional'] = ar_count
  313.  
  314.         return offset + 2
  315.  
  316.     # Parsing Section 2 (Question)
  317.     def process_question(self, res, offset, data):
  318.         # QNAME
  319.         res['questions'] = []
  320.         for i in range(res['total_questions']):
  321.             cur_question = {}
  322.  
  323.             # QNAME
  324.             q_name, offset = self.get_domain_rec(data, offset)
  325.             q_name = q_name
  326.             cur_question['q_name'] = q_name
  327.  
  328.             # QTYPE
  329.             q_type = unpack('!H', data[offset: offset + 2])[0]
  330.             cur_question['q_type'] = q_type
  331.  
  332.             # QCLASS
  333.             offset += 2
  334.             q_class = unpack('!H', data[offset: offset + 2])[0]
  335.             cur_question['q_class'] = q_class
  336.             res['questions'].append(cur_question)
  337.         return offset + 2
  338.  
  339.     # Parsing Section 3 (Answer)
  340.     def process_answer(self, res, offset, data):
  341.         res['answers'] = []
  342.         for i in range(res['total_answers']):
  343.             cur_answer = {}
  344.  
  345.             # NAME
  346.             name, offset = self.get_domain_rec(data, offset)
  347.             name = name
  348.             cur_answer['name'] = name
  349.  
  350.             # QTYPE
  351.             q_type = unpack('!H', data[offset: offset + 2])[0]
  352.             cur_answer['type'] = q_type
  353.  
  354.             # QCLASS
  355.             offset += 2
  356.             q_class = unpack('!H', data[offset: offset + 2])[0]
  357.             cur_answer['class'] = q_class
  358.  
  359.             offset += 2
  360.             ttl = unpack('!I', data[offset: offset + 4])[0]
  361.             cur_answer['TTL'] = ttl
  362.  
  363.             offset += 4
  364.             rd_length = unpack('!H', data[offset: offset + 2])[0]
  365.             cur_answer['rd_length'] = rd_length
  366.  
  367.             offset += 2
  368.             self.read_response_data(data, offset, cur_answer)
  369.  
  370.             offset += rd_length
  371.  
  372.             res['answers'].append(cur_answer)
  373.  
  374.         return offset
  375.  
  376.     # Parsing Section 4 (Authority)
  377.     def process_authority(self, res, offset, data):
  378.         res['authority'] = []
  379.         for i in range(res['total_authoritys']):
  380.             cur_authority = {}
  381.  
  382.             # NAME
  383.             name, offset = self.get_domain_rec(data, offset)
  384.             name = name
  385.             cur_authority['name'] = name
  386.  
  387.             # QTYPE
  388.             q_type = unpack('!H', data[offset: offset + 2])[0]
  389.             cur_authority['type'] = q_type
  390.  
  391.             # QCLASS
  392.             offset += 2
  393.             q_class = unpack('!H', data[offset: offset + 2])[0]
  394.             cur_authority['class'] = q_class
  395.  
  396.             offset += 2
  397.             ttl = unpack('!I', data[offset: offset + 4])[0]
  398.             cur_authority['TTL'] = ttl
  399.  
  400.             offset += 4
  401.             rd_length = unpack('!H', data[offset: offset + 2])[0]
  402.             cur_authority['rd_length'] = rd_length
  403.  
  404.             offset += 2
  405.             self.read_response_data(data, offset, cur_authority)
  406.  
  407.             offset += rd_length
  408.  
  409.             res['authority'].append(cur_authority)
  410.  
  411.         return offset
  412.  
  413.     # parsing Section 5 (Additional)
  414.     def process_additional(self, res, offset, data):
  415.         res['additional'] = []
  416.         for i in range(res['total_additional']):
  417.             cur_additional = {}
  418.  
  419.             # NAME
  420.             name, offset = self.get_domain_rec(data, offset)
  421.             name = name
  422.             cur_additional['name'] = name
  423.  
  424.             # QTYPE
  425.             q_type = unpack('!H', data[offset: offset + 2])[0]
  426.             cur_additional['type'] = q_type
  427.  
  428.             # QCLASS
  429.             offset += 2
  430.             q_class = unpack('!H', data[offset: offset + 2])[0]
  431.             cur_additional['class'] = q_class
  432.  
  433.             offset += 2
  434.             ttl = unpack('!I', data[offset: offset + 4])[0]
  435.             cur_additional['TTL'] = ttl
  436.  
  437.             offset += 4
  438.             rd_length = unpack('!H', data[offset: offset + 2])[0]
  439.             cur_additional['rd_length'] = rd_length
  440.  
  441.             offset += 2
  442.             self.read_response_data(data, offset, cur_additional)
  443.  
  444.             offset += rd_length
  445.             res['additional'].append(cur_additional)
  446.  
  447.     def read_response_data(self, data, offset, res):
  448.         data_type = res['type']
  449.         data_length: int = res['rd_length']
  450.  
  451.         if data_type == 1:  # type A
  452.             res['data'] = ipaddress.IPv4Address(data[offset:offset + 4])
  453.         elif data_type == 28:  # type AAAA
  454.             res['data'] = ipaddress.IPv6Address(data[offset:offset + 16])
  455.         elif data_type == 2:  # type NS
  456.             res['data'] = self.get_domain_rec(data, offset)[0]
  457.         elif data_type == 5:  # type CNAME
  458.             res['data'] = self.get_domain_rec(data, offset)[0]
  459.         elif data_type == 16:  # type TXT
  460.             res['data'] = data[offset:offset + data_length]
  461.         elif data_type == 15:  # type MX
  462.             mx = {'preferences': unpack('!H', data[offset: offset + 2])[0],
  463.                   'mx': self.get_domain_rec(data, offset + 2)}
  464.             res['data'] = mx
  465.         elif data_type == 6:  # type SOA
  466.             soa = {}
  467.             soa['primary_ns'], offset = self.get_domain_rec(data, offset)
  468.             soa['resp_mx'], offset = self.get_domain_rec(data, offset)
  469.             soa['serial'], soa['refresh'], soa['retry'], soa['expire'], soa['min_ttl'] = \
  470.                 unpack('!5I', data[offset: offset + 20])
  471.             res['data'] = soa
  472.         else:
  473.             res['data'] = None
  474.  
  475.     def get_domain_rec(self, data, offset):
  476.         if not data[offset]:
  477.             return b'', offset + 1
  478.  
  479.         if (data[offset]) >> 6 == 3:
  480.             name_offset = unpack('!H', data[offset: offset + 2])[0]
  481.             name_offset = name_offset & ((1 << 14) - 1)
  482.             return self.get_domain_rec(data, name_offset)[0], offset + 2
  483.  
  484.         length = data[offset]
  485.         offset += 1
  486.         label = (data[offset: offset + length]) + b'.'
  487.         rec = self.get_domain_rec(data, offset + length)
  488.         label += rec[0]
  489.         return label, rec[1]
  490.  
  491.     def dns_root_search(self, request, depth):
  492.         sock_root_dns = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  493.         sock_root_dns.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  494.         question = {'total_questions': 1}
  495.         self.process_question(question, 12, request)
  496.         i = 1
  497.         for server in DNS_root_servers:
  498.             print(PrintColors.BOLD + self.count(depth) + "Searching Data In Root Server No {}, {} -> {} , Domain : {}".
  499.                   format(i, server[0], server[3], question['questions'][0]['q_name'].decode()[:-1] + PrintColors.ENDC))
  500.             resp = None
  501.             for j in range(3):
  502.                 sock_root_dns.settimeout(SOCKET_TIMEOUT)
  503.                 try:
  504.                     sock_root_dns.sendto(request, (server[3], DNS_Port))
  505.                     resp = sock_root_dns.recv(MAX_BUFFER_SIZE)
  506.                     break
  507.                 except:
  508.                     continue
  509.             if resp:
  510.                 ans, root_resp = self.find_recursively(resp, sock_root_dns, request, depth, [])
  511.                 if ans:
  512.                     header = self.process_request(root_resp)
  513.                     print(
  514.                         PrintColors.BOLD + self.count(
  515.                             depth) + 'Found Data From Root  Server  No {}, {} -> {} , Domain : {}'.
  516.                         format(i, server[0], server[3],
  517.                                question['questions'][0]['q_name'].decode()[:-1]) + PrintColors.ENDC)
  518.                     self.save_response_in_cache(root_resp, str(question['questions'][0]), header['answers'][0]['TTL'])
  519.                     return ans, root_resp
  520.                 else:
  521.                     return False, None
  522.             i += 1
  523.  
  524.         return False, None
  525.  
  526.     def find_recursively(self, p_resp, root_socket, request, depth, visited_ip):
  527.         dic = self.process_request(p_resp)
  528.         # n = input()
  529.         if dic['total_answers']:
  530.             for answer in dic['answers']:
  531.                 if answer['type'] == 1:
  532.                     server_ip_dict[dic['questions'][0]['q_name'].decode()[:-1]] = answer['data']
  533.                 return True, p_resp
  534.  
  535.         # First Check in Additional Section for IPv4
  536.         visited_ns = []
  537.         for additional_record in dic['additional']:
  538.             if additional_record['type'] != 1:  # Check if it is IpV4
  539.                 continue
  540.             visited_ns += [additional_record['name']]
  541.             server = additional_record['name'].decode()[:-1]
  542.             domain = dic['questions'][0]['q_name'].decode()[:-1]
  543.             ip = additional_record['data']
  544.             code = str(ip) + "#" + domain
  545.             if code in visited_ip:
  546.                 continue
  547.             visited_ip += [code]
  548.             print(self.count(depth, False) + "Asking {} for {}".format(server, domain))
  549.             ans, final_resp = self.send_new_request(ip, root_socket, request, depth + 1, visited_ip)
  550.             if ans:
  551.                 print(
  552.                     self.count(depth, False) + "Server {} found Data for {}".format(server, domain))
  553.  
  554.                 return ans, final_resp
  555.  
  556.         # After that Find all Name Servers
  557.         for authority_record in dic['authority']:
  558.             if authority_record['data'] in visited_ns:
  559.                 continue
  560.             if authority_record['type'] != 2:
  561.                 continue
  562.             new_request = self.build_request(authority_record['data'])
  563.             request_domain = dic['questions'][0]['q_name'].decode()[:-1]
  564.             domain_needed = authority_record['data'].decode()[:-1]
  565.             print(self.count(depth, False) + "Asking {} for {}".format(domain_needed,
  566.                                                                        request_domain))
  567.             if domain_needed in server_ip_dict:
  568.                 code = str(server_ip_dict[domain_needed]) + '#' + dic['questions'][0]['q_name'].decode()[:-1]
  569.                 if code in visited_ip:
  570.                     continue
  571.                 visited_ip += [code]
  572.                 print(PrintColors.BOLD + self.count(depth) + "Found IP Address From Cache for domain {} : {}".format(
  573.                     domain_needed,
  574.                     server_ip_dict[
  575.                         domain_needed]) + PrintColors.ENDC)
  576.                 ans, final_resp = self.send_new_request(server_ip_dict[domain_needed], root_socket, request, depth,
  577.                                                         visited_ip)
  578.                 if ans:
  579.                     print(self.count(depth, False) + "Asking {} for {}".format(domain_needed, request_domain))
  580.                     return ans, final_resp
  581.             else:
  582.                 ans, auth_resp = self.find_dns(new_request, depth + 1)
  583.                 if ans:
  584.                     resp_headers = self.process_request(auth_resp)
  585.                     for answer in resp_headers['answers']:
  586.                         if answer['type'] == 1:
  587.                             server_ip_dict[domain_needed] = answer['data']
  588.                             code = str(answer['data']) + '#' + dic['questions'][0]['q_name'].decode()[:-1]
  589.                             if code in visited_ip:
  590.                                 continue
  591.                             visited_ip += [code]
  592.                             ans, final_resp = self.send_new_request(answer['data'], root_socket, request, depth + 1,
  593.                                                                     visited_ip)
  594.                             if ans:
  595.                                 print(
  596.                                     self.count(depth, False) + "Asking {} for {}".format(domain_needed, request_domain))
  597.  
  598.                                 return ans, final_resp
  599.         return False, None
  600.  
  601.     def send_new_request(self, ip, root_socket, request, depth, visited_ip):
  602.         ipv4_address = str(ip)
  603.         root_resp = None
  604.         for i in range(3):
  605.             root_socket.settimeout(SOCKET_TIMEOUT)
  606.             try:
  607.                 root_socket.sendto(request, (ipv4_address, DNS_Port))
  608.                 root_resp = root_socket.recv(MAX_BUFFER_SIZE)
  609.                 break
  610.             except:
  611.                 pprint("Exception: Lost Data or Server Unreachable, Trying again...")
  612.                 # continue
  613.  
  614.         if root_resp:
  615.             ans, new_resp = self.find_recursively(root_resp, root_socket, request, depth, visited_ip)
  616.             if ans:
  617.                 return True, new_resp
  618.             else:
  619.                 return False, None
  620.         return False, None
  621.  
  622.     def build_request(self, domain_name):
  623.         req = b''
  624.         transaction_id = pack('!H', random.getrandbits(16))
  625.         req += transaction_id
  626.  
  627.         flags = self.request[2:4]
  628.         req += flags
  629.  
  630.         qd_count = pack('!H', 1)
  631.         req += qd_count
  632.  
  633.         an_count = pack('!H', 0)
  634.         req += an_count
  635.  
  636.         ns_count = pack('!H', 0)
  637.         req += ns_count
  638.  
  639.         ar_count = pack('!H', 0)
  640.         req += ar_count
  641.  
  642.         domain_name = self.build_domain_name(domain_name.decode())
  643.         req += domain_name.encode()
  644.  
  645.         q_type = pack('!H', 1)
  646.         req += q_type
  647.  
  648.         q_class = pack('!H', 1)
  649.         req += q_class
  650.  
  651.         return req
  652.  
  653.     def build_domain_name(self, domain_name):
  654.         labels = domain_name.split('.')
  655.         res = ''.join([chr(len(label)) + label for label in labels])
  656.         return res
  657.  
  658.     def config_contains(self, domain_name):
  659.         config_list = os.listdir(self.config_path)
  660.         return domain_name.decode() + 'conf' in config_list
  661.  
  662.     def read_config(self, domain_name):
  663.         os.chdir(self.config_path)
  664.         domain_name = domain_name.decode()
  665.         path = domain_name + 'conf'
  666.         z = easyzone.zone_from_file(domain_name[:-1], path)
  667.         os.chdir('..')
  668.         return z
  669.  
  670.     def generate_error(self, req):
  671.         flag = 0x8183
  672.         bytes = pack("!H", flag)
  673.  
  674.         que_count = req[4:6]
  675.         bytes += que_count
  676.  
  677.         ans_count = 0
  678.         bytes += pack("!H", ans_count)
  679.  
  680.         aut_count = 0
  681.         bytes += pack("!H", aut_count)
  682.  
  683.         add_count = 0
  684.         bytes += pack("!H", add_count)
  685.  
  686.         return bytes
  687.  
  688.     def count(self, depth, print_type=True):
  689.         if print_type:
  690.             return "-" * depth
  691.         else:
  692.             return "|" * depth
  693.  
  694.     def save_response_in_cache(self, root_resp, question, ttl=300):
  695.         to_save_value = root_resp[2:]
  696.         request_response_dict[question] = [to_save_value, datetime.now(), ttl]
  697.  
  698.  
  699. def run_dns_server(config_path):
  700.     print(PrintColors.HEADER + 'Starting DNS Server on {}:{}'.format(DNS_IP, DNS_Port) + PrintColors.ENDC)
  701.  
  702.     try:
  703.         sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  704.         sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  705.         sock.bind(('127.0.0.1', Local_DNS_Port))
  706.  
  707.         while True:
  708.             print()
  709.             print("Waiting for Request...")
  710.             request, address = sock.recvfrom(MAX_BUFFER_SIZE)
  711.             print("Received Request")
  712.             DnsWorker(request, address, sock, config_path).run()  # Change to start()
  713.             print("Current Cache ")
  714.             pprint(server_ip_dict)
  715.     except socket.error as e:
  716.         print(str(e))
  717.     print("Closing DNS Server!")
  718.  
  719.  
  720. # do not change!
  721. if __name__ == '__main__':
  722.     configpath = sys.argv[1]
  723.     run_dns_server(configpath)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement