The Domain Name System (DNS) is one of the most critical services of modern networked applications. Python DNS Lookups are super simple using the standard socket library. This helps find the IP address associated with a hostname.
Python provides access to lower-level network tools through the standard Socket library. There are other libraries available such as the DNS resolver for python, but we’ll be sticking to the standard library here.
Python DNS Lookups via Socket
In computer networking terms, sockets are software constructs that map processes between end systems. Aptly named, the socket library in Python provides a plethora of networking tools. Among them: the
getaddrinfo() methods. Each of these can perform a DNS lookup such that it returns an IP address for a host.
Each of the two mentioned methods will provide detailed information about a host. For those seeking a simple DNS
host:ip lookup, the
gethostbyname method is fairly straight-forward. Consider the following example:
import socket # Get the IP of the TLD socket.gethostbyname("alpharithms.com") >>> 220.127.116.11 # Get the IP of the www sub-domain socket.gethostbyname("www.alpharithms.com") >>> 18.104.22.168
Note that for this website, the
non-www versions of the website return the same IP address. That’s because the www is canonical (CNAME) to the alpharithms.com domain name. Effectively, the DNS records are configured such that the two are functionally equivalent. Let’s consider another example:
import socket # Get the IP of the TLD socket.gethostbyname("google.com") >>> 22.214.171.124 # Get the IP of the www sub-domain socket.gethostbyname("www.google.com") >>> 126.96.36.199
Here it’s evident that
www and tld domain IP addresses do not have to be the same. For a domain, any number of subdomains can be configured with any number of IP addresses. Depending on the type of DNS record configured these entries could be canonical, authoritative, or aliases.
This method provides the same core IP information as the prior method but offers much greater granularity. For example, one can specify port, family, and protocol to help narrow down DNS resolution. The return structure is a bit more complex here as well. Consider the following:
socket.getaddrinfo("google.com") >>> TypeError: getaddrinfo() missing 1 required positional argument: 'port'
Clearly, this method doesn’t operate in the same fashion. Where the
gethostbyname method requires only the hostname this one requires a port specification as well. Let’s try it with port 80 which is reserved for HTTP requests:
import socket # Lookup hostname + port socket.getaddrinfo("google.com", 80) >>> [(<AddressFamily.AF_INET: 2>, 0, 0, '', ('188.8.131.52', 80)), (<AddressFamily.AF_INET: 2>, 0, 0, '', ('184.108.40.206', 80)), (<AddressFamily.AF_INET: 2>, 0, 0, '', ('220.127.116.11', 80)), (<AddressFamily.AF_INET: 2>, 0, 0, '', ('18.104.22.168', 80)), (<AddressFamily.AF_INET: 2>, 0, 0, '', ('22.214.171.124', 80)), (<AddressFamily.AF_INET: 2>, 0, 0, '', ('126.96.36.199', 80))]
Yikes. That’s a lot messier than the previous Python DNS lookup approach. This returns a list of IP addresses, as tuple objects, associated with the queried host—
google.com in this case.
This implies that Google has six IP addresses associated with its top-level domain. This is an example of load distribution (a.k.a load balancing) and helps ensure Google’s servers don’t get bogged down. For more information, read about Round Robin DNS techniques.
The extra parameters allowed with the
getaddrinfo method can be used to filter the results for a specific protocol, family, and type of service.
An extension of the first example provides the same plethora of IP addresses for a host but doesn’t require any additional arguments such as port. An example of this method is as follows:
import socket # Get extended hostname info socket.gethostbyname_ex('google.com') >>> ('google.com', , ['188.8.131.52', '184.108.40.206', '220.127.116.11', '18.104.22.168', '22.214.171.124', '126.96.36.199'])
You’ll note here that the same number of IP addresses were returned, albeit in a more simplified format. The second value in the returned tuple (empty in this case) is for any aliases associated with the hostname. For example:
import socket socket.gethostbyname_ex('www.alpharithms.com') >>> ('alpharithms.com', ['www.alpharithms.com'], ['188.8.131.52'])
Socket programming is one of the most hands-on ways to learn how Internet Protocol works. The Python language abstracts low-level OS network modules within the socket library. This library provides deep access to the underpinnings of socket-based networking. For more information check out the Python Socket documentation.