@@ -1072,13 +1072,13 @@ def mysummary(self):
10721072 name = ""
10731073 if self .qr :
10741074 type = "Ans"
1075- if self .an and isinstance (self .an , DNSRR ):
1076- name = ' "%s" ' % self .an [0 ].rdata
1075+ if self .an and isinstance (self .an [ 0 ] , DNSRR ):
1076+ name = ' %s ' % self .an [0 ].rdata
10771077 else :
10781078 type = "Qry"
1079- if self .qd and isinstance (self .qd , DNSQR ):
1080- name = ' "%s" ' % self .qd [0 ].qname
1081- return 'DNS %s%s ' % (type , name )
1079+ if self .qd and isinstance (self .qd [ 0 ] , DNSQR ):
1080+ name = ' %s ' % self .qd [0 ].qname
1081+ return 'DNS %s%s' % (type , name )
10821082
10831083 def post_build (self , pkt , pay ):
10841084 if isinstance (self .underlayer , TCP ) and self .length is None :
@@ -1129,13 +1129,16 @@ def pre_dissect(self, s):
11291129
11301130
11311131@conf .commands .register
1132- def dns_resolve (qname , qtype = "A" , raw = False , verbose = 1 , ** kwargs ):
1132+ def dns_resolve (qname , qtype = "A" , raw = False , verbose = 1 , timeout = 3 , ** kwargs ):
11331133 """
11341134 Perform a simple DNS resolution using conf.nameservers with caching
11351135
11361136 :param qname: the name to query
11371137 :param qtype: the type to query (default A)
11381138 :param raw: return the whole DNS packet (default False)
1139+ :param verbose: show verbose errors
1140+ :param timeout: seconds until timeout (per server)
1141+ :raise TimeoutError: if no DNS servers were reached in time.
11391142 """
11401143 # Unify types
11411144 qtype = DNSQR .qtype .any2i_one (None , qtype )
@@ -1149,7 +1152,7 @@ def dns_resolve(qname, qtype="A", raw=False, verbose=1, **kwargs):
11491152 if answer :
11501153 return answer
11511154
1152- kwargs .setdefault ("timeout" , 3 )
1155+ kwargs .setdefault ("timeout" , timeout )
11531156 kwargs .setdefault ("verbose" , 0 )
11541157 res = None
11551158 for nameserver in conf .nameservers :
@@ -1203,7 +1206,8 @@ def dns_resolve(qname, qtype="A", raw=False, verbose=1, **kwargs):
12031206 # Cache it
12041207 _dns_cache [cache_ident ] = answer
12051208 return answer
1206- return None
1209+ else :
1210+ raise TimeoutError
12071211
12081212
12091213@conf .commands .register
@@ -1247,14 +1251,15 @@ def dyndns_del(nameserver, name, type="ALL", ttl=10):
12471251
12481252
12491253class DNS_am (AnsweringMachine ):
1250- function_name = "dns_spoof "
1254+ function_name = "dnsd "
12511255 filter = "udp port 53"
1252- cls = DNS # We use this automaton for llmnr_spoof
1256+ cls = DNS # We also use this automaton for llmnrd
12531257
12541258 def parse_options (self , joker = None ,
12551259 match = None ,
12561260 srvmatch = None ,
12571261 joker6 = False ,
1262+ relay = False ,
12581263 from_ip = None ,
12591264 from_ip6 = None ,
12601265 src_ip = None ,
@@ -1265,40 +1270,50 @@ def parse_options(self, joker=None,
12651270 Set to False to disable, None to mirror the interface's IP.
12661271 :param joker6: default IPv6 for unresolved domains (Default: False)
12671272 set to False to disable, None to mirror the interface's IPv6.
1273+ :param relay: relay unresolved domains to conf.nameservers (Default: False).
12681274 :param match: a dictionary of {name: val} where name is a string representing
12691275 a domain name (A, AAAA) and val is a tuple of 2 elements, each
1270- representing an IP or a list of IPs
1276+ representing an IP or a list of IPs. If val is a single element,
1277+ (A, None) is assumed.
12711278 :param srvmatch: a dictionary of {name: (port, target)} used for SRV
12721279 :param from_ip: an source IP to filter. Can contain a netmask
12731280 :param from_ip6: an source IPv6 to filter. Can contain a netmask
12741281 :param ttl: the DNS time to live (in seconds)
1275- :param src_ip:
1282+ :param src_ip: override the source IP
12761283 :param src_ip6:
12771284
12781285 Example:
12791286
1280- >>> dns_spoof(joker="192.168.0.2", iface="eth0")
1281- >>> dns_spoof(match={
1287+ $ sudo iptables -I OUTPUT -p icmp --icmp-type 3/3 -j DROP
1288+ >>> dnsd(match={"google.com": "1.1.1.1"}, joker="192.168.0.2", iface="eth0")
1289+ >>> dnsd(srvmatch={
12821290 ... "_ldap._tcp.dc._msdcs.DOMAIN.LOCAL.": (389, "srv1.domain.local")
12831291 ... })
12841292 """
1293+ def normv (v ):
1294+ if isinstance (v , (tuple , list )) and len (v ) == 2 :
1295+ return v
1296+ elif isinstance (v , str ):
1297+ return (v , None )
1298+ else :
1299+ raise ValueError ("Bad match value: '%s'" % repr (v ))
1300+
1301+ def normk (k ):
1302+ k = bytes_encode (k ).lower ()
1303+ if not k .endswith (b"." ):
1304+ k += b"."
1305+ return k
12851306 if match is None :
12861307 self .match = {}
12871308 else :
1288- assert all (isinstance (x , (tuple , list )) for x in match .values ()), (
1289- "'match' values must be a tuple of 2 elements: ('<ipv4>', '<ipv6>')"
1290- ". They can be None"
1291- )
1292- self .match = {bytes_encode (k ): v for k , v in match .items ()}
1309+ self .match = {normk (k ): normv (v ) for k , v in match .items ()}
12931310 if srvmatch is None :
12941311 self .srvmatch = {}
12951312 else :
1296- assert all (isinstance (x , (tuple , list )) for x in srvmatch .values ()), (
1297- "'srvmatch' values must be a tuple of 2 elements: (port, 'target')"
1298- )
1299- self .srvmatch = {bytes_encode (k ): v for k , v in srvmatch .items ()}
1313+ self .srvmatch = {normk (k ): normv (v ) for k , v in srvmatch .items ()}
13001314 self .joker = joker
13011315 self .joker6 = joker6
1316+ self .relay = relay
13021317 if isinstance (from_ip , str ):
13031318 self .from_ip = Net (from_ip )
13041319 else :
@@ -1341,51 +1356,65 @@ def make_reply(self, req):
13411356 if rq .qtype == 28 :
13421357 # AAAA
13431358 try :
1344- rdata = self .match [rq .qname ][1 ]
1359+ rdata = self .match [rq .qname . lower () ][1 ]
13451360 except KeyError :
1346- if self .joker6 is False :
1347- return
1348- rdata = self .joker6 or get_if_addr6 (
1349- self .optsniff .get ("iface" , conf .iface )
1350- )
1361+ if self .relay or self .joker6 is False :
1362+ rdata = None
1363+ else :
1364+ rdata = self .joker6 or get_if_addr6 (
1365+ self .optsniff .get ("iface" , conf .iface )
1366+ )
13511367 elif rq .qtype == 1 :
13521368 # A
13531369 try :
1354- rdata = self .match [rq .qname ][0 ]
1370+ rdata = self .match [rq .qname . lower () ][0 ]
13551371 except KeyError :
1356- if self .joker is False :
1357- return
1358- rdata = self . joker or get_if_addr (
1359- self .optsniff . get ( "iface" , conf . iface )
1360- )
1361- if rdata is None :
1362- # Ignore None
1363- return
1364- # Common A and AAAA
1365- if not isinstance ( rdata , list ):
1366- rdata = [ rdata ]
1367- ans . extend ([
1368- DNSRR ( rrname = rq . qname , ttl = self . ttl , rdata = x , type = rq . qtype )
1369- for x in rdata
1370- ])
1372+ if self .relay or self . joker is False :
1373+ rdata = None
1374+ else :
1375+ rdata = self .joker or get_if_addr (
1376+ self . optsniff . get ( "iface" , conf . iface )
1377+ )
1378+ if rdata is not None :
1379+ # Common A and AAAA
1380+ if not isinstance ( rdata , list ):
1381+ rdata = [ rdata ]
1382+ ans . extend ([
1383+ DNSRR ( rrname = rq . qname , ttl = self . ttl , rdata = x , type = rq . qtype )
1384+ for x in rdata
1385+ ])
1386+ continue # next
13711387 elif rq .qtype == 33 :
13721388 # SRV
13731389 try :
1374- port , target = self .srvmatch [rq .qname ]
1390+ port , target = self .srvmatch [rq .qname .lower ()]
1391+ ans .append (DNSRRSRV (
1392+ rrname = rq .qname ,
1393+ port = port ,
1394+ target = target ,
1395+ weight = 100 ,
1396+ ttl = self .ttl
1397+ ))
1398+ continue # next
13751399 except KeyError :
1376- return
1377- ans .append (DNSRRSRV (
1378- rrname = rq .qname ,
1379- port = port ,
1380- target = target ,
1381- weight = 100 ,
1382- ttl = self .ttl
1383- ))
1384- else :
1385- # Not handled
1386- continue
1387- # Common: All
1388- if not ans :
1389- return
1390- resp /= self .cls (id = req .id , qr = 1 , qd = req .qd , an = ans )
1400+ # No result
1401+ pass
1402+ # It it arrives here, there is currently no answer
1403+ if self .relay :
1404+ # Relay mode ?
1405+ try :
1406+ _rslv = dns_resolve (rq .qname , qtype = rq .qtype )
1407+ if _rslv is not None :
1408+ ans .append (_rslv )
1409+ continue # next
1410+ except TimeoutError :
1411+ pass
1412+ # Error
1413+ break
1414+ else :
1415+ # All rq were answered
1416+ resp /= self .cls (id = req .id , qr = 1 , qd = req .qd , an = ans )
1417+ return resp
1418+ # An error happened
1419+ resp /= self .cls (id = req .id , qr = 1 , qd = req .qd , rcode = 3 )
13911420 return resp
0 commit comments