I want to extract the domain name from DNS packets (request/response) from .pcapng file. the following code what I used
def extract_domain_name(pkt):
try:
if pkt.dns.qry_name:
#print (pkt.ip.src, pkt.dns.qry_name)
return pkt.dns.qry_name
except AttributeError as e:
#ignore packets that aren't DNS Request
pass
try:
if pkt.dns.resp_name:
print (pkt.ip.src, pkt.dns.resp_name)
return pkt.dns.resp_name
except AttributeError as e:
#ignore packets that aren't DNS Response
pass
def process_pcapng_file(filename):
# Open the pcapng file
cap = pyshark.FileCapture(filename)
# Extract the domain names from the DNS packets
domains = set()
for pkt in cap:
#print (pkt)
if 'DNS' in pkt:
#domain = pkt.dns.qry_name
domain = extract_domain_name(pkt)
if domain is not None:
domains.add(domain)
it only extract the domain name from query packets not from query and response. what could the problem? However,
I tried to use if pkt.dns.resp_name:
without try:
and I got AttributeError
Thanks for posting the sample capture; that helps.
I think the reason your code works for me but not for you is that in your sample capture, the only replies are SERVFAIL messages:
$ tcpdump -nn -r sample.pcap port domain | awk '{print $7}' | sort | uniq -c
38365 A?
38393 ServFail
It looks like for SERVFAIL messages, pkt.dns
will not have a resp_name
attribute.
it only extract the domain name from query packets not from query and response
Just to be explicit: in your sample capture, there are no valid query responses, so pkt.dns.resp_name
is never defined.
There are a couple of things to think about here:
If your logic is effectively:
if pkt.dns.qry_name:
return pkt.dns.qry_name
if pkt.dns.resp_name:
return pkt.dns.resp_name
You will never reach the second if
statement because a query response also includes the original query (so you will always return pkt.dns.qry_name
).
Do you really care about resp_name
? In all cases, either pkt.dns.resp_name
will match pkt.dns.qry_name
, or it won't exist.
It seems to me you could simplify your code to:
def process_pcapng_file(filename):
cap = pyshark.FileCapture(filename)
return set(
pkt.dns.qry_name
for pkt in cap
if pkt.highest_layer == "DNS" and pkt.dns.qry_name
)
But if you want to use your existing extract_domain_name
function, you'll need to reverse the checks for resp_name
and qry_name
:
def extract_domain_name(pkt):
try:
if pkt.dns.resp_name:
return pkt.dns.resp_name
except AttributeError:
pass
try:
if pkt.dns.qry_name:
return pkt.dns.qry_name
except AttributeError:
pass
You can make that a little shorter by replacing the exception handling with hasattr
:
def extract_domain_name(pkt):
if hasattr(pkt.dns, "resp_name") and pkt.dns.resp_name:
return pkt.dns.resp_name
if hasattr(pkt.dns, "qry_name") and pkt.dns.qry_name:
return pkt.dns.qry_name