Skip to content

Commit 4716eee

Browse files
committed
DNS over TCP: support dns_resolve
1 parent c7aa3e9 commit 4716eee

File tree

2 files changed

+21
-12
lines changed

2 files changed

+21
-12
lines changed

scapy/layers/dns.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,9 +1271,10 @@ def __getattr__(self, attr):
12711271

12721272
class DNS(DNSCompressedPacket):
12731273
name = "DNS"
1274+
FORCE_TCP = False
12741275
fields_desc = [
12751276
ConditionalField(ShortField("length", None),
1276-
lambda p: isinstance(p.underlayer, TCP)),
1277+
lambda p: p.FORCE_TCP or isinstance(p.underlayer, TCP)),
12771278
ShortField("id", 0),
12781279
BitField("qr", 0, 1),
12791280
BitEnumField("opcode", 0, 4, {0: "QUERY", 1: "IQUERY", 2: "STATUS"}),
@@ -1300,7 +1301,7 @@ class DNS(DNSCompressedPacket):
13001301

13011302
def get_full(self):
13021303
# Required for DNSCompressedPacket
1303-
if isinstance(self.underlayer, TCP):
1304+
if isinstance(self.underlayer, TCP) or self.FORCE_TCP:
13041305
return self.original[2:]
13051306
else:
13061307
return self.original
@@ -1332,7 +1333,10 @@ def mysummary(self):
13321333
)
13331334

13341335
def post_build(self, pkt, pay):
1335-
if isinstance(self.underlayer, TCP) and self.length is None:
1336+
if (
1337+
(isinstance(self.underlayer, TCP) or self.FORCE_TCP) and
1338+
self.length is None
1339+
):
13361340
pkt = struct.pack("!H", len(pkt) - 2) + pkt[2:]
13371341
return pkt + pay
13381342

@@ -1363,6 +1367,14 @@ def pre_dissect(self, s):
13631367
return s
13641368

13651369

1370+
class DNSTCP(DNS):
1371+
"""
1372+
A DNS packet that is always under TCP
1373+
"""
1374+
FORCE_TCP = True
1375+
match_subclass = True
1376+
1377+
13661378
bind_layers(UDP, DNS, dport=5353)
13671379
bind_layers(UDP, DNS, sport=5353)
13681380
bind_layers(UDP, DNS, dport=53)
@@ -1413,16 +1425,18 @@ def dns_resolve(qname, qtype="A", raw=False, tcp=False, verbose=1, timeout=3, **
14131425
try:
14141426
# Spawn a socket, connect to the nameserver on port 53
14151427
if tcp:
1428+
cls = DNSTCP
14161429
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
14171430
else:
1431+
cls = DNS
14181432
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
14191433
sock.settimeout(kwargs["timeout"])
14201434
sock.connect((nameserver, 53))
14211435
# Connected. Wrap it with DNS
1422-
sock = StreamSocket(sock, DNS)
1436+
sock = StreamSocket(sock, cls)
14231437
# I/O
14241438
res = sock.sr1(
1425-
DNS(qd=[DNSQR(qname=qname, qtype=qtype)], id=RandShort()),
1439+
cls(qd=[DNSQR(qname=qname, qtype=qtype)], id=RandShort()),
14261440
**kwargs,
14271441
)
14281442
except IOError as ex:

test/regression.uts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3500,16 +3500,11 @@ import socket
35003500
sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
35013501
sck.connect(("8.8.8.8", 53))
35023502

3503-
class DNSTCP(Packet):
3504-
name = "DNS over TCP"
3505-
fields_desc = [ FieldLenField("len", None, fmt="!H", length_of="dns"),
3506-
PacketLenField("dns", 0, DNS, length_from=lambda p: p.len)]
3507-
35083503
ssck = StreamSocket(sck, DNSTCP)
35093504

3510-
r = ssck.sr1(DNSTCP(dns=DNS(rd=1, qd=DNSQR(qname="www.example.com"))), timeout=3)
3505+
r = ssck.sr1(DNSTCP(rd=1, qd=DNSQR(qname="www.example.com")), timeout=3)
35113506
sck.close()
3512-
assert DNSTCP in r and len(r.dns.an)
3507+
assert DNSTCP in r and len(r.an)
35133508

35143509
############
35153510
+ Tests of SSLStreamContext

0 commit comments

Comments
 (0)