In today’s digital landscape, understanding the infrastructure behind websites is crucial for developers, cybersecurity experts, and even curious tech enthusiasts. One powerful tool in your arsenal is the ability to perform a reverse IP lookup. This technique allows you to discover which domains are hosted on a specific IP address, providing valuable insights into server usage and potential security vulnerabilities.
Have you ever wondered what kind of connections lie behind an IP address? Today, you’ll learn how to perform a reverse IP lookup using Python, leveraging popular APIs like Hackertarget and ViewDNS. We’ll guide you through building a simple yet effective tool with a Tkinter-based GUI, where you can type in an IP address and instantly reveal all the domains hosted on a single server.
This approach not only enhances your Python skills but also makes the process interactive and user-friendly, turning a complex task into a smooth, effortless experience. So, let’s get started!
Table of Contents
- Disclaimer
- Getting Started
- Imports
- Performing Reverse IP Lookup with Hackertarget
- Performing Reverse IP Lookup with ViewDNS
- Handling Lookup and Displaying Results
- Configuring the Main Window and Its Components
- Example
- Full Code
Disclaimer
Please note: This tutorial is intended for educational use only. Please use the tools and techniques discussed responsibly and legally. We’re not liable for any misuse or unintended consequences that may arise from applying the information provided. Always respect privacy and adhere to relevant laws.
Getting Started
For the code to function properly, install these libraries by running the following commands:
$ pip install requests
$ pip install tk
Next up, let’s get your API key for those times when you need multiple attempts. The free plan gives you 250 tries, which is usually enough to get started. Just head over to ViewDNS to choose the plan that fits your needs, and once you’ve got your API key, simply plug it into this part of the code.
# Your API key from viewdns.info (you need to register and get one)
VIEWDNS_API_KEY = "ENTER_YOUR_API_KEY"
If you’re looking for another option, Hackertarget has you covered. They offer a fun deal: one free lookup every day, for life! Just use the general URL: https://api.hackertarget.com/reverseiplookup/?q={ip}
. It’s a handy choice if you’re just doing occasional lookups. Both options are solid, so pick the one that works best for you!
Imports
import requests
import tkinter as tk
from tkinter import ttk, messagebox
Like any coder, we start by gathering our tools since they are the pillars of our script. So, let’s dive in:
- First, we import
requests
: This library allows us to send HTTP requests to web servers or APIs and receive responses. - Then, we import
tkinter
: This module helps us create a graphical user interface (GUI). Withttk
, we can use themed widgets, andmessagebox
lets us display information through pop-up messages.
Performing Reverse IP Lookup with Hackertarget
Let’s start with the reverse_ip_lookup_hackertarget()
function. This function begins by forming a URL, where the entered IP address is added to the endpoint of the free API.
url = f"https://api.hackertarget.com/reverseiplookup/?q={ip}"
Once the URL is ready, the function sends an HTTP GET request to it, storing the response in the response
object.
response = requests.get(url)
Next, the function checks if the request was successful using response.raise_for_status()
. If everything goes smoothly and the status code is 200, the response is processed. But if there’s an issue, say the request fails, the function will raise an exception with requests.RequestException
to catch any errors, printing them in a message for you to see.
try:
response.raise_for_status()
except requests.RequestException as e:
print(f"Error fetching data from hackertarget.com: {e}")
return None
There’s also a scenario where no response comes back from the server, like if the API quota is exceeded. In that case, the function will print a message to inform you about the exceeded quota.
if "API count exceeded" in response.text:
print("Hackertarget API quota exceeded.")
return None
However, if the response is successful and contains a list of domains, it gets processed using response.text.strip().splitlines()
. This removes any unnecessary whitespace and splits the response text into a list of domains.
domains = response.text.strip().splitlines()
Finally, the function returns this list, whether it’s empty (if the response failed) or filled with domains (if the response was successful), so it can be used later in your script.
if domains:
return domains
else:
return None
Performing Reverse IP Lookup with ViewDNS
Now, if you don’t want to be confined to one try a day, the reverse_ip_lookup_viewdns()
function is for you. This function takes the API Key you stored at the beginning and uses it to form the URL.
url = f"https://api.viewdns.info/reverseip/?host={ip}&apikey={VIEWDNS_API_KEY}&output=json"
It then sends an HTTP GET request to the URL using requests.get(url)
.
response = requests.get(url)
Once the response is received, it transforms the JSON data into a Python dictionary using response.json()
.
data = response.json()
Next, the function checks whether there’s a list of domains in the response. If there is, it returns that list to be used later; otherwise, it returns None
.
if "response" in data and "domains" in data["response"]:
return data["response"]["domains"]
else:
return None
If there’s an issue with the request, the function will raise an exception using requests.RequestException
to catch any errors and print them in a message.
except requests.RequestException as e:
print(f"Error fetching data from viewdns.info: {e}")
return None
Handling Lookup and Displaying Results
This part of the script is the core, as it manages everything. The lookup_domains()
function begins by retrieving the IP address entered by the user and strips it of any whitespace or trailing spaces using ip_entry.get().strip()
. If the user hasn’t entered an IP address, it prompts them to provide one with an error message.
ip = ip_entry.get().strip()
if not ip:
messagebox.showerror("Input Error", "Please enter an IP address.")
return
Next, it sets the output text widget to a normal state so it can be edited and then clears it of any pre-existing content with output_text.delete()
. After that, it informs the user that the lookup is being performed through output_text.insert()
, displaying the message. Once this is done, it reverts the output text widget to a disabled state so it can’t be edited.
output_text.config(state='normal')
output_text.delete(1.0, tk.END)
output_text.insert(tk.END, f"Performing lookup for IP: {ip}\n")
output_text.config(state='disabled')
The function then gets to the main task of performing the lookup. To do that, it needs to know which function to call. It uses if api_choice.get()
to determine which function to use, either the reverse_ip_lookup_hackertarget()
or reverse_ip_lookup_viewdns()
function, based on the radio button selected by the user.
if api_choice.get() == "hackertarget":
results = reverse_ip_lookup_hackertarget(ip)
if not results:
output_text.config(state='normal')
output_text.insert(tk.END, "Hackertarget API returned no results or exceeded quota.\n")
output_text.config(state='disabled')
elif api_choice.get() == "viewdns":
results = reverse_ip_lookup_viewdns(ip)
if not results:
output_text.config(state='normal')
output_text.insert(tk.END, "ViewDNS API returned no results or an error occurred.\n")
output_text.config(state='disabled')
Lastly, it moves to the final step: displaying the results. It starts by configuring the output_text
widget to set its state to normal so it can be edited. If the response was successful and there is a list of domains, it displays them in the output_text
widget using output_text.insert()
.
Otherwise, it shows an error message or informs the user that the API quota has been exceeded. Once that’s done, the output_text
widget is reverted to its disabled state.
# Display results
output_text.config(state='normal')
if results:
output_text.insert(tk.END, f"Domains hosted on the same server as IP {ip}:\n")
for domain in results:
output_text.insert(tk.END, f"{domain}\n")
else:
output_text.insert(tk.END, f"No valid domains found for IP {ip} or an error occurred.\n")
output_text.config(state='disabled')
Configuring the Main Window and Its Components
At this stage, it’s time to build our central command. We start by creating the main window using tk.Tk()
, setting its title with app.title()
and defining its size with app.geometry()
.
app = tk.Tk()
app.title("Reverse IP Lookup Tool - The Pycodes")
app.geometry("600x450")
After that, we create the input frame, which will hold the IP entry box. We add a placeholder text to indicate what the user should input. Then, we create the “Lookup” button that will call the lookup_domains()
function when clicked.
input_frame = ttk.Frame(app)
input_frame.pack(pady=10)
ip_entry = ttk.Entry(input_frame, width=50)
ip_entry.pack(side=tk.LEFT, padx=5)
ip_entry.insert(0, "Enter IP address")
lookup_button = ttk.Button(input_frame, text="Lookup", command=lookup_domains)
lookup_button.pack(side=tk.LEFT, padx=5)
Next, we set up the API Choice Frame, which will hold two radio buttons. These are linked to a StringVar
that stores the selected API, allowing the script to determine whether to call reverse_ip_lookup_hackertarget()
or reverse_ip_lookup_viewdns()
based on the user’s selection.
api_frame = ttk.LabelFrame(app, text="Choose API")
api_frame.pack(pady=10, fill=tk.X)
api_choice = tk.StringVar(value="hackertarget")
hackertarget_radio = ttk.Radiobutton(api_frame, text="Hackertarget.com API", variable=api_choice, value="hackertarget")
hackertarget_radio.pack(side=tk.LEFT, padx=5, pady=5)
viewdns_radio = ttk.Radiobutton(api_frame, text="ViewDNS.info API", variable=api_choice, value="viewdns")
viewdns_radio.pack(side=tk.LEFT, padx=5, pady=5)
Following that, we create the output frame, which will hold the output_text
widget along with a scrollbar to display the results. This ensures that the output is easily scrollable for the user.
output_frame = ttk.Frame(app)
output_frame.pack(pady=10, fill=tk.BOTH, expand=True)
scrollbar = ttk.Scrollbar(output_frame)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
output_text = tk.Text(output_frame, wrap=tk.WORD, state='disabled', yscrollcommand=scrollbar.set)
output_text.pack(pady=10, fill=tk.BOTH, expand=True)
scrollbar.config(command=output_text.yview)
Finally, we ensure that this script can only be run directly and not imported as a module by using the if __name__ == "__main__":
condition. We then start the main event loop with app.mainloop()
to keep the main window running and responsive to user interactions.
if __name__ == "__main__":
app.mainloop()
Example
Full Code
import requests
import tkinter as tk
from tkinter import ttk, messagebox
# Your API key from viewdns.info (you need to register and get one)
VIEWDNS_API_KEY = "ENTER_YOUR_API_KEY"
# Function to perform reverse IP lookup using hackertarget.com API
def reverse_ip_lookup_hackertarget(ip):
url = f"https://api.hackertarget.com/reverseiplookup/?q={ip}"
try:
response = requests.get(url)
response.raise_for_status()
if "API count exceeded" in response.text:
print("Hackertarget API quota exceeded.")
return None
domains = response.text.strip().splitlines()
if domains:
return domains
else:
return None
except requests.RequestException as e:
print(f"Error fetching data from hackertarget.com: {e}")
return None
# Function to perform reverse IP lookup using viewdns.info API
def reverse_ip_lookup_viewdns(ip):
url = f"https://api.viewdns.info/reverseip/?host={ip}&apikey={VIEWDNS_API_KEY}&output=json"
try:
response = requests.get(url)
response.raise_for_status()
data = response.json()
if "response" in data and "domains" in data["response"]:
return data["response"]["domains"]
else:
return None
except requests.RequestException as e:
print(f"Error fetching data from viewdns.info: {e}")
return None
# Function to handle the lookup process and display results
def lookup_domains():
ip = ip_entry.get().strip()
if not ip:
messagebox.showerror("Input Error", "Please enter an IP address.")
return
output_text.config(state='normal')
output_text.delete(1.0, tk.END)
output_text.insert(tk.END, f"Performing lookup for IP: {ip}\n")
output_text.config(state='disabled')
# Determine which API to use based on the selected option
if api_choice.get() == "hackertarget":
results = reverse_ip_lookup_hackertarget(ip)
if not results:
output_text.config(state='normal')
output_text.insert(tk.END, "Hackertarget API returned no results or exceeded quota.\n")
output_text.config(state='disabled')
elif api_choice.get() == "viewdns":
results = reverse_ip_lookup_viewdns(ip)
if not results:
output_text.config(state='normal')
output_text.insert(tk.END, "ViewDNS API returned no results or an error occurred.\n")
output_text.config(state='disabled')
# Display results
output_text.config(state='normal')
if results:
output_text.insert(tk.END, f"Domains hosted on the same server as IP {ip}:\n")
for domain in results:
output_text.insert(tk.END, f"{domain}\n")
else:
output_text.insert(tk.END, f"No valid domains found for IP {ip} or an error occurred.\n")
output_text.config(state='disabled')
# Setup Tkinter GUI
app = tk.Tk()
app.title("Reverse IP Lookup Tool - The Pycodes")
app.geometry("600x450")
# Input Frame
input_frame = ttk.Frame(app)
input_frame.pack(pady=10)
ip_entry = ttk.Entry(input_frame, width=50)
ip_entry.pack(side=tk.LEFT, padx=5)
ip_entry.insert(0, "Enter IP address")
lookup_button = ttk.Button(input_frame, text="Lookup", command=lookup_domains)
lookup_button.pack(side=tk.LEFT, padx=5)
# API Choice Frame
api_frame = ttk.LabelFrame(app, text="Choose API")
api_frame.pack(pady=10, fill=tk.X)
api_choice = tk.StringVar(value="hackertarget")
hackertarget_radio = ttk.Radiobutton(api_frame, text="Hackertarget.com API", variable=api_choice, value="hackertarget")
hackertarget_radio.pack(side=tk.LEFT, padx=5, pady=5)
viewdns_radio = ttk.Radiobutton(api_frame, text="ViewDNS.info API", variable=api_choice, value="viewdns")
viewdns_radio.pack(side=tk.LEFT, padx=5, pady=5)
# Output Frame with Scrollbar
output_frame = ttk.Frame(app)
output_frame.pack(pady=10, fill=tk.BOTH, expand=True)
scrollbar = ttk.Scrollbar(output_frame)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
output_text = tk.Text(output_frame, wrap=tk.WORD, state='disabled', yscrollcommand=scrollbar.set)
output_text.pack(pady=10, fill=tk.BOTH, expand=True)
scrollbar.config(command=output_text.yview)
if __name__ == "__main__":
app.mainloop()
Happy Coding!