Let’s explore Python DNS Lookup IPv4 IPv6 in 4 Ways. Let’s go! 🔥🔥🔥
A DNS lookup is a process used to translate a domain name, like google.com, into its corresponding IP address, which is required for network communication. When you enter a website’s URL into your browser, your computer performs a DNS lookup to retrieve the IP address associated with that domain name. This is done through a series of queries to DNS servers: first to a recursive DNS server (typically provided by your internet service provider), which may then forward the request to other DNS servers, such as root, top-level domain (TLD), and authoritative name servers, each playing a role in decomposing the domain name hierarchy.
There are several ways to perform DNS lookups in Python. Here are some of the common methods:
1. Using the socket Library
The socket library is a standard Python library used for network interactions. You can use the gethostbyname() or gethostbyaddr() functions for DNS resolutions. The below code will return the IPv4 address for a given domain name.
import socket
ip_address = socket.gethostbyname('google.com')
print(ip_address)
2. Using dnspython Library
The dnspython library is a powerful and flexible DNS toolkit for Python. It provides more extensive features for DNS lookups compared to the standard library. This is our second way to do a python dns lookup.
Make sure to install the module first with the pip3 install dnspython or pip install dnspython depending on your system configuration. The below code will return an IPv4 Address:
import dns.resolver
answers = dns.resolver.resolve('google.com', 'A')
for rdata in answers:
print(rdata.address)
Within the try block, the resolve function from the dns.resolver module is called with two arguments: the domain name and the type of DNS record to query for (‘A’). ‘A’ records are used for mapping domain names to IPv4 addresses and ‘AAAA’ records do the same for IPv6 addresses. The function returns a response object which contains the DNS query results.
We can do something similar to return an IPv6 address by using the ‘AAAA’ record:
import dns.resolver
answers = dns.resolver.resolve('google.com', 'AAAA')
for rdata in answers:
print(rdata.address)
3. Using socket.getaddrinfo()
This function provides a more flexible interface for network address resolution. It can handle both IPv4 and IPv6 addresses and allows specifying the port and protocol type. This is the third way to do a python dns lookup.
We can resolve an IPv4 address for the domain google.com on port 80 (commonly used for HTTP) using the TCP protocol by doing the following:
import socket
hostname = 'google.com'
port = 80 # HTTP port
# The address family is set to socket.AF_INET for IPv4.
# The socket type is set to socket.SOCK_STREAM for TCP protocol.
try:
info = socket.getaddrinfo(hostname, port, socket.AF_INET, socket.SOCK_STREAM)
for addr in info:
print(f"IPv4 Address: {addr[4][0]}")
except Exception as e:
print(f"Error occurred: {e}")
We can do something similar to resolve an IPv6 address for the same domain on port 443 (commonly used for HTTPS) using the same protocol:
import socket
hostname = 'example.com'
port = 443 # HTTPS port
# The address family is set to socket.AF_INET6 for IPv6.
# The socket type is set to socket.SOCK_STREAM for TCP protocol.
try:
info = socket.getaddrinfo(hostname, port, socket.AF_INET6, socket.SOCK_STREAM)
for addr in info:
print(f"IPv6 Address: {addr[4][0]}")
except Exception as e:
print(f"Error occurred: {e}")
4. Using scapy library
Scapy is a powerful Python-based interactive packet manipulation program and library. It can be used for more advanced DNS queries. Make sure you install scapy with pip install scapy or pip3 install scapy.
Depending on your system configuration you may need elevated permissions to run the below Python code.
from scapy.all import sr1, IP, UDP, DNS, DNSQR
# Sending the DNS query
response = sr1(IP(dst="8.8.8.8")/UDP()/DNS(rd=1,qd=DNSQR(qname="medium.com")), verbose=0)
# Checking if a response was received
if response and response.haslayer(DNS) and response.getlayer(DNS).ancount > 0:
# Extracting the DNS answers
answers = response[DNS].an
# Iterating over the answers
for i in range(response[DNS].ancount):
answer = answers[i]
# Printing the data based on the type of the record
if answer.type == 1: # A record
print(f"IP: {answer.rdata}")
elif answer.type == 5: # CNAME record
print(f"CNAME: {answer.rdata}")
# Add additional record types as needed
else:
print("No DNS response or no answer found.")
Let’s explain what is happening here:
- from scapy.all import sr1, IP, UDP, DNS, DNSQR
- sr1: A function used to send a packet and receive the first response (if any).
- IP: A class to create IP packets.
- UDP: A class to create UDP datagrams.
- DNS: A class to create DNS request and response packets.
- DNSQR: A class to create a DNS query record (used in DNS requests).
- response = sr1(IP(dst=”8.8.8.8″)/UDP()/DNS(rd=1,qd=DNSQR(qname=”medium.com”)), verbose=0)
- This line is where the DNS query is constructed and sent, and the response is captured:
- IP(dst=”8.8.8.8″): Creates an IP packet with the destination address set to “8.8.8.8” (which is a Google DNS server).
- UDP(): Creates a UDP packet. This is used because DNS queries are typically sent over UDP. The source and destination ports are default values (source port is chosen randomly by Scapy, and the destination port is 53, the standard for DNS).
- DNS(rd=1, qd=DNSQR(qname=”medium.com”)): Constructs the DNS query.
- rd=1: Sets the “recursion desired” flag to 1, asking the DNS server to perform a recursive query.
- qd=DNSQR(qname=”medium.com”): Creates a DNS query record. qname=”medium.com” sets the domain name for which we are querying.
- This line is where the DNS query is constructed and sent, and the response is captured:
- The / operator is used by Scapy to stack these layers (IP/UDP/DNS) into a single packet.
- sr1(…): Sends the constructed packet to the destination and waits for a single response. The response is then stored in the variable response.
- The script checks if there are any answer records (ancount > 0) in the response.
- If there are answer records, it iterates through them, looking for records of type 1 (the type number for ‘A’ records) and prints the IPv4 addresses found.
The above code may print one or more IPv4 address depending on how the domain is configured. Some domains use a CDN (like CloudFlare), a load balancer or some other service and these IP addresses may be return.
We can do the same for an IPv6 address:
from scapy.all import sr1, IP, UDP, DNS, DNSQR
# Sending the DNS query for an AAAA record
response = sr1(IP(dst="8.8.8.8")/UDP()/DNS(rd=1, qd=DNSQR(qname="google.com", qtype="AAAA")), verbose=0)
# Checking if a response was received
if response and response.haslayer(DNS) and response.getlayer(DNS).ancount > 0:
# Extracting the DNS answers
answers = response[DNS].an
# Iterating over the answers
for i in range(response[DNS].ancount):
answer = answers[i]
if answer.type == 28: # AAAA record
print(f"IPv6: {answer.rdata}")
else:
print("No DNS response or no AAAA answer found.")
The DNSQR (DNS Query Record) is constructed with qtype=”AAAA” to specify that we are looking for ‘AAAA’ records i.e. IPv6 address. If there are answer records, it iterates through them, looking for records of type 28 (the type number for ‘AAAA’ records) and prints the IPv6 addresses found.
So there you have it: 4 ways to do a Python DNS Lookup IPv4 IPv6. A Reverse DNS Lookup does the opposite of the DNS lookup. Thanks for reading! 👌🏻👌🏻👌🏻