@@ -1380,13 +1380,15 @@ def pre_dissect(self, s):
13801380
13811381
13821382@conf .commands .register
1383- def dns_resolve (qname , qtype = "A" , raw = False , verbose = 1 , timeout = 3 , ** kwargs ):
1383+ def dns_resolve (qname , qtype = "A" , raw = False , tcp = False , verbose = 1 , timeout = 3 , ** kwargs ):
13841384 """
13851385 Perform a simple DNS resolution using conf.nameservers with caching
13861386
13871387 :param qname: the name to query
13881388 :param qtype: the type to query (default A)
13891389 :param raw: return the whole DNS packet (default False)
1390+ :param tcp: whether to use directly TCP instead of UDP. If truncated is received,
1391+ UDP automatically retries in TCP. (default: False)
13901392 :param verbose: show verbose errors
13911393 :param timeout: seconds until timeout (per server)
13921394 :raise TimeoutError: if no DNS servers were reached in time.
@@ -1409,8 +1411,11 @@ def dns_resolve(qname, qtype="A", raw=False, verbose=1, timeout=3, **kwargs):
14091411 for nameserver in conf .nameservers :
14101412 # Try all nameservers
14111413 try :
1412- # Spawn a UDP socket, connect to the nameserver on port 53
1413- sock = socket .socket (socket .AF_INET , socket .SOCK_DGRAM )
1414+ # Spawn a socket, connect to the nameserver on port 53
1415+ if tcp :
1416+ sock = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
1417+ else :
1418+ sock = socket .socket (socket .AF_INET , socket .SOCK_DGRAM )
14141419 sock .settimeout (kwargs ["timeout" ])
14151420 sock .connect ((nameserver , 53 ))
14161421 # Connected. Wrap it with DNS
@@ -1428,6 +1433,21 @@ def dns_resolve(qname, qtype="A", raw=False, verbose=1, timeout=3, **kwargs):
14281433 sock .close ()
14291434 if res :
14301435 # We have a response ! Check for failure
1436+ if res [DNS ].tc == 1 : # truncated !
1437+ if not tcp :
1438+ # Retry using TCP
1439+ return dns_resolve (
1440+ qname = qname ,
1441+ qtype = qtype ,
1442+ raw = raw ,
1443+ tcp = True ,
1444+ verbose = verbose ,
1445+ timeout = timeout ,
1446+ ** kwargs ,
1447+ )
1448+ elif verbose :
1449+ log_runtime .info ("DNS answer is truncated !" )
1450+
14311451 if res [DNS ].rcode == 2 : # server failure
14321452 res = None
14331453 if verbose :
0 commit comments