Quick Tip: Python DNS Lookup

python dns lookup

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.

TL;DR socket.gethostbyname("alpharithms.com")

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 gethostbyname() and getaddrinfo() methods. Each of these can perform a DNS lookup such that it returns an IP address for a host.

gethostbyname

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")
>>> 151.101.194.159

# Get the IP of the www sub-domain
socket.gethostbyname("www.alpharithms.com")
>>> 151.101.194.159

Note that for this website, the www and 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") 
>>> 108.177.122.101

# Get the IP of the www sub-domain
socket.gethostbyname("www.google.com") 
>>> 74.125.136.106

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.

getaddrinfo

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, '', ('108.177.122.100', 80)), (<AddressFamily.AF_INET: 2>, 0, 0, '', ('108.177.122.113', 80)), (<AddressFamily.AF_INET: 2>, 0, 0, '', ('108.177.122.101', 80)), (<AddressFamily.AF_INET: 2>, 0, 0, '', ('108.177.122.139', 80)), (<AddressFamily.AF_INET: 2>, 0, 0, '', ('108.177.122.138', 80)), (<AddressFamily.AF_INET: 2>, 0, 0, '', ('108.177.122.102', 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.

gethostbyname_ex

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', [], ['108.177.122.101', '108.177.122.139', '108.177.122.138', '108.177.122.113', '108.177.122.102', '108.177.122.100'])

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'], ['151.101.194.159'])

Discussion

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.

Zαck West
Full-Stack Software Engineer with 10+ years of experience. Expertise in developing distributed systems, implementing object-oriented models with a focus on semantic clarity, driving development with TDD, enhancing interfaces through thoughtful visual design, and developing deep learning agents.