Build a Python Network Intelligence CLI
Build a Python CLI that combines DNS, WHOIS, and REST IP enrichment.
Introduction
30 Second Summary
A web address looks simple in your browser, but the systems behind it leave clues in several different places. Piecing those clues together by hand quickly turns into a trail of separate searches.
In this project, you will build a Python command-line tool that investigates a public domain or IP address in one run. The finished report combines DNS resolution, authoritative WHOIS data, and IP context from a REST API.
What You'll Build
Run your CLI against example.com to see resolved addresses, an authoritative WHOIS preview, and a labeled location and ASN report appear in one terminal session.
By the end of this project, you'll have:
- Target resolution: Enter a public domain or IP address to see its unique IPv4 and IPv6 addresses.
- A referral-aware WHOIS lookup that shows a real request crossing TCP port 43. You will see IANA's refer: clue lead to the authoritative server.
- A combined investigation report with location, coordinates, ASN, organization, and proxy status. Readable timeout and network errors keep failures understandable.
- Secret Mission: Process several targets from targets.txt with paced lookups. Export one result or error per target to network_report.csv.
Are there any prerequisites?
You need basic Python experience, Python 3.10 or newer on Windows, and Visual Studio Code.
Your internet connection must allow outbound HTTPS plus TCP port 43, with no account, API key, or paid service required.
Before We Start
A clear target gives every result in this project a real investigation purpose. Before the hands-on work begins, choose the public domain or IP address you want to inspect.
Set Up Your Windows Workspace
Your first network lookup depends on a compatible Python interpreter. It also depends on a workspace where every command runs against the right file.
You will open the python-network-intel folder in Visual Studio Code. You will verify the interpreter from its PowerShell terminal.
In this step, get ready to:
- Prepare the python-network-intel workspace in Visual Studio Code.
- Verify Python 3.10 or newer from PowerShell.
- Run network_intel.py to confirm the workspace works.
Open the workspace in Visual Studio Code
A workspace anchors the file sidebar to one folder. Its integrated terminal starts from the same location.
- Press the Windows key to open Windows search.
- Enter Visual Studio Code in the search field.
- Press Enter to launch Visual Studio Code.
- Select the folder-opening option on the Visual Studio Code welcome screen.
- Move the folder picker to your Desktop.
- Use the folder picker's new-folder control to create python-network-intel.
- Select the python-network-intel folder.
- Confirm the folder selection to open the workspace.
Why Does the Workspace Folder Matter?
Visual Studio Code uses the open folder as the shared location for your files plus terminal commands. This keeps network_intel.py within reach when PowerShell runs it.
- Select Terminal from the top menu.
- Select New Terminal.
The terminal prompt shows python-network-intel as its current folder. The terminal profile identifies PowerShell.
Is Another Shell Open?
- Use the terminal profile selector to choose PowerShell.
- Select New Terminal from the Terminal menu.
Ask for help if the terminal still starts in the wrong folder. Help me open PowerShell at my Visual Studio Code workspace folder.
Verify Python 3.10 or newer
The version check confirms that PowerShell can find Python. It also confirms that the interpreter meets this project's baseline.
- Check the Python version by running this command:
python -V
What Does This Command Check?
- The python command selects the interpreter available to PowerShell.
- The -V option prints its version.
PowerShell prints a version or reports that the command is unavailable. Choose the tab that matches your result.
✔️ I see the required version
Your interpreter is ready when the version is 3.10 or newer. You have cleared the runtime check.
- Continue to the starter script once the required version appears.
ⓧ I see an older version
A Windows permission prompt can look serious. It only authorizes the official installer to add Python to your computer.
- Visit the official Python downloads page.
- Download Python 3.14.7 for Windows.
- Run the downloaded installer.
- Select the installer option that makes python available in PowerShell.
- Complete the installation.
- Close the existing terminal in Visual Studio Code.
- Select Terminal from the top menu.
- Select New Terminal.
- Repeat the version check by running this command:
python -V
What Should the New Terminal Show?
The new terminal loads the command changes made by the installer. PowerShell should now print Python 3.10 or newer.
ⓧ Command not found
A Windows permission prompt can look serious. It only authorizes the official installer to add Python to your computer.
- Visit the official Python downloads page.
- Download Python 3.14.7 for Windows.
- Run the downloaded installer.
- Select the installer option that makes python available in PowerShell.
- Complete the installation.
- Close the existing terminal in Visual Studio Code.
- Select Terminal from the top menu.
- Select New Terminal.
- Check the installation by running this command:
python -V
What Should the New Terminal Show?
The new terminal loads the command changes made by the installer. PowerShell should now print Python 3.10 or newer.
Still Unable to Verify Python?
- Close every terminal that was open before the installation.
- Create a new PowerShell terminal from the Terminal menu.
- Confirm that the installer option for making python available in PowerShell was selected.
If the version still does not appear, help me diagnose the Python command.
Create and run the starter script
A temporary startup message proves that PowerShell can find your script. It gives you a working baseline before networking code enters the project.
- Select the new-file control in the Visual Studio Code file sidebar.
- Enter network_intel.py as the file name.
- Add the readiness message by entering this code:
print("Network Intelligence CLI ready")
What Does This Code Do?
- The print() call writes a message to PowerShell.
- The message confirms that Python reached the code inside network_intel.py.
- Save network_intel.py.
- Confirm that network_intel.py remains listed in the file sidebar.
✔️ Awesome, I've got everything!
Great. Your saved file contains the workspace check.
ⓧ I'd like to double check the full code
Compare network_intel.py with this complete file.
print("Network Intelligence CLI ready")
What Should the File Contain?
The file contains one print() call. Its text matches the readiness message exactly.
Before you run the final check, which result do you expect PowerShell to print first?
- Verify the interpreter plus the starter script by running these commands:
python -V
python network_intel.py
What Does the Final Check Prove?
- The first command prints the Python version used by PowerShell.
- The second command executes network_intel.py from the current workspace.
You will see Python 3.10 or newer first. You will then see Network Intelligence CLI ready.
That is your first working result: PowerShell can now run the exact file in your workspace.
Does the Starter Script Fail?
- Return to the matching version tab if PowerShell reports an older Python version.
- Confirm that the terminal prompt points to the python-network-intel folder if the script cannot be found.
- Compare network_intel.py with the full-code tab if the readiness message does not appear.
- Save network_intel.py before repeating the final check.
If the script still fails, help me diagnose the workspace check.
Your Windows workspace is ready. Next, you will turn the starter script into a resolver for the public target you chose.
Resolve Targets to IP Addresses
Python already runs inside your Visual Studio Code workspace. The temporary message in network_intel.py proves the file starts successfully.
A network investigation needs concrete addresses before it can enrich a target or connect to its services. DNS resolution turns a domain into the unique IPv4 or IPv6 addresses that the rest of the CLI can use.
In this step, get ready to:
- Replace the temporary message with a target resolver.
- Prompt for a domain or IP address.
- Compare successful resolution with a DNS failure.
Build the resolver function
The socket module asks the operating system to resolve a domain or IP address. A set removes duplicate results before sorted() arranges them consistently.
- Select network_intel.py from the file list on the left.
- Find the temporary print("Network Intelligence CLI ready") line.
- Replace that line with the resolver code below:
import socket
def resolve_target(target):
results = socket.getaddrinfo(target, None, type=socket.SOCK_STREAM)
return sorted({result[4][0] for result in results})
What Does This Code Do?
- The socket.getaddrinfo() function asks the operating system for addresses associated with the target.
- The socket.SOCK_STREAM value limits the results to addresses usable by stream sockets.
- The result[4][0] expression selects the address from each result.
- The set comprehension removes duplicates. The sorted() function gives the addresses a stable order.
- Save network_intel.py.
- Confirm that import socket appears above resolve_target().
Does the Resolver Look Incorrect?
Confirm that the results line plus the return line are indented inside resolve_target().
Check that socket.SOCK_STREAM uses capital letters. Python identifiers are case-sensitive.
Help me check my resolver function.
Prompt for the target and print addresses
The main() function collects one target from the terminal. It passes that value to resolve_target() before printing each returned address.
- Place your cursor on the blank line below resolve_target().
- Add the program workflow with the code below:
def main():
print("Python Network Intelligence CLI")
target = input("Domain or IP address: ").strip()
if not target:
print("Enter a public domain or IP address.")
return
addresses = resolve_target(target)
print("Resolved addresses:")
for address in addresses:
print(f" - {address}")
if __name__ == "__main__":
main()
What Does This Code Do?
- The input() function pauses the program until you enter a domain or IP address.
- The empty-target check stops the workflow when no value was entered.
- The addresses variable holds the unique results returned by resolve_target().
- The for loop prints one resolved address per line.
- The final guard calls main() when you run this file as a script.
- Save network_intel.py.
Before you run the resolver, how many addresses do you think one domain can return?
- Switch back to the PowerShell terminal from earlier.
- Start the resolver by running this command:
python network_intel.py
What Does This Command Do?
This command runs the saved network_intel.py script from your workspace. The script pauses at its input prompt so you can choose a target.
- Enter example.com at the Domain or IP address: prompt.
You should see Resolved addresses: followed by at least one unique address. Good progress. Your CLI now turns a public domain into concrete network addresses.
Do You See a Resolution Error?
Confirm that your computer has an internet connection. Check that you entered example.com without spaces inside the name.
Confirm that the target value is passed directly into resolve_target().
Help me diagnose my DNS resolution test.
✔️ Awesome, I've got everything!
Your saved resolver now accepts a target and prints its unique addresses.
ⓧ I'd like to double check the full code
The full network_intel.py file should match this reference.
import socket
def resolve_target(target):
results = socket.getaddrinfo(target, None, type=socket.SOCK_STREAM)
return sorted({result[4][0] for result in results})
def main():
print("Python Network Intelligence CLI")
target = input("Domain or IP address: ").strip()
if not target:
print("Enter a public domain or IP address.")
return
addresses = resolve_target(target)
print("Resolved addresses:")
for address in addresses:
print(f" - {address}")
if __name__ == "__main__":
main()
Observe a DNS failure
A second input reveals how the current resolver behaves when DNS cannot find a target. Before you test it, do you think the script returns a clean message or stops with Python error details?
- Start a second lookup by running this command:
python network_intel.py
Why Run the Script Again?
The same program can receive a different target each time it runs. Repeating the command lets you test the failure path without changing the code.
- Enter a deliberately misspelled version of your chosen domain at the prompt.
You will see the script stop with a DNS failure. The traceback identifies socket.gaierror as the address-related exception.
This Failure Is Intentional
The resolver currently leaves DNS exceptions unhandled. This result proves that invalid targets reach the network code before the program stops.
Your CLI now resolves public targets into unique addresses. Next, you will send its first raw TCP WHOIS query to IANA.
Query IANA with a TCP Socket
Your resolver already turns a public target into unique IPv4 or IPv6 addresses. Ownership plus delegation remain beyond that first DNS result.
The investigation now starts with IANA WHOIS at the root registry. A raw TCP query reveals whether IANA holds the complete record or directs the investigation elsewhere.
In this step, get ready to:
- Configure the IANA WHOIS server plus its TCP port.
- Send a WHOIS query through a raw socket.
- Filter the registry response into a readable preview.
Set the WHOIS destination
A socket client needs a hostname plus a port before it can connect. IANA serves WHOIS queries from whois.iana.org on TCP port 43.
- Select network_intel.py in the VS Code Explorer sidebar.
- Add these constants below import socket:
IANA_WHOIS_SERVER = "whois.iana.org"
WHOIS_PORT = 43
What Do These Constants Store?
- The IANA_WHOIS_SERVER constant keeps the destination hostname in one reusable place.
- The WHOIS_PORT constant records the standard TCP port used by the WHOIS service.
- Save network_intel.py.
- Confirm the script still runs by using this command in PowerShell:
python network_intel.py
What Does This Command Run?
The command asks Python to execute network_intel.py from the current VS Code workspace.
- Enter example.com at the prompt.
You will see the resolved addresses again. This confirms that the new connection settings leave the existing resolver runnable.
Seeing a Syntax Error?
Confirm that both constants sit below import socket with no indentation. Check that the hostname keeps both quotation marks.
Ask for help with the constants.
Build the TCP query function
A WHOIS request sends plain text through an open TCP connection. The server closes that connection when its response is complete.
- Find the end of resolve_target() in network_intel.py.
- Add the new query function below resolve_target():
def whois_query(server, query):
chunks = []
with socket.create_connection((server, WHOIS_PORT), timeout=5) as connection:
connection.sendall((query + "\r\n").encode("ascii"))
while True:
chunk = connection.recv(4096)
if not chunk:
break
chunks.append(chunk)
return b"".join(chunks).decode("utf-8", errors="replace")
What Does This Code Do?
- The chunks list holds each block of bytes received from the server.
- The socket.create_connection() call opens the TCP connection with a five-second timeout.
- The sendall() call sends the query as ASCII text ending with "\r\n".
- The receive loop collects 4096 bytes at a time until the server closes the connection.
- The return statement joins the byte chunks into one response.
- The final decode converts the response to UTF-8 text while replacing invalid byte sequences.
- Save network_intel.py.
- Check that the expanded script remains runnable by using this command:
python network_intel.py
What Does This Check Prove?
Python loads the new function before it starts main(). Reaching the target prompt confirms that the function has valid Python syntax.
- Enter example.com at the prompt.
You will see the resolved addresses. The complete file now loads successfully with the socket client defined.
Does Python Stop Before the Prompt?
Check that whois_query() begins at the left edge of the file. Confirm that every line inside the function uses consistent indentation.
Help me check the function structure.
Reveal IANA's response
IANA responses include useful registry fields plus comment lines that begin with %. A short preview keeps the first useful lines visible in PowerShell.
- Find the end of whois_query() in network_intel.py.
- Add the preview function below whois_query():
def whois_preview(response_text, limit=12):
lines = []
for line in response_text.splitlines():
cleaned = line.strip()
if cleaned and not cleaned.startswith("%"):
lines.append(cleaned)
return lines[:limit]
How Does the Preview Stay Readable?
- The splitlines() call separates the WHOIS response into individual lines.
- The strip() call removes surrounding whitespace from each line.
- The condition skips empty lines plus IANA comment lines.
- The final slice returns up to 12 useful lines by default.
- Save network_intel.py.
- Check the new filtering function by running the script again:
python network_intel.py
What Does This Check Confirm?
Python loads whois_preview() before starting the prompt. Reaching the resolved-address output confirms that the filtering function has valid syntax.
- Enter example.com at the prompt.
You will see the resolved addresses. The script now contains both parts required to collect plus filter the IANA response.
- Scroll to the existing address output inside main().
- Find this block:
addresses = resolve_target(target)
print("Resolved addresses:")
for address in addresses:
print(f" - {address}")
What Does the Current Block Show?
This block resolves the target before printing each unique address. It does not call the new socket client.
- Replace the current address output block with this expanded block:
addresses = resolve_target(target)
iana_response = whois_query(IANA_WHOIS_SERVER, target)
print("Resolved addresses:")
for address in addresses:
print(f" - {address}")
print("IANA WHOIS preview:")
for line in whois_preview(iana_response):
print(f" {line}")
How Does the Workflow Change?
- The iana_response variable stores the text returned by the socket client.
- The first loop preserves the resolved-address output from the previous step.
- The second loop prints each useful line selected by whois_preview().
- Save network_intel.py.
✔️ Awesome, I've got everything!
Great. Your saved script now resolves a target before querying IANA through a TCP socket.
ⓧ I'd like to double check the full code
Compare your saved network_intel.py file with this complete version.
import socket
IANA_WHOIS_SERVER = "whois.iana.org"
WHOIS_PORT = 43
def resolve_target(target):
results = socket.getaddrinfo(target, None, type=socket.SOCK_STREAM)
return sorted({result[4][0] for result in results})
def whois_query(server, query):
chunks = []
with socket.create_connection((server, WHOIS_PORT), timeout=5) as connection:
connection.sendall((query + "\r\n").encode("ascii"))
while True:
chunk = connection.recv(4096)
if not chunk:
break
chunks.append(chunk)
return b"".join(chunks).decode("utf-8", errors="replace")
def whois_preview(response_text, limit=12):
lines = []
for line in response_text.splitlines():
cleaned = line.strip()
if cleaned and not cleaned.startswith("%"):
lines.append(cleaned)
return lines[:limit]
def main():
print("Python Network Intelligence CLI")
target = input("Domain or IP address: ").strip()
if not target:
print("Enter a public domain or IP address.")
return
addresses = resolve_target(target)
iana_response = whois_query(IANA_WHOIS_SERVER, target)
print("Resolved addresses:")
for address in addresses:
print(f" - {address}")
print("IANA WHOIS preview:")
for line in whois_preview(iana_response):
print(f" {line}")
if __name__ == "__main__":
main()
What Should Match?
Confirm that the constants appear before resolve_target(). Confirm that both WHOIS functions appear before main().
Before you run the finished check, do you think IANA will return a complete registration record or direct you to another WHOIS server?
- Query IANA by running the completed script:
python network_intel.py
What Happens When This Runs?
The command starts the resolver plus the new socket workflow. The target prompt supplies the text sent to IANA.
- Enter example.com at the prompt.
You will see at least one address under Resolved addresses. You will then see an IANA WHOIS preview containing a refer: line for whois.verisign-grs.com.
That referral is the intended shortfall. IANA provides registry-level information plus the destination of a more authoritative server.
Does the WHOIS Query Fail?
- Confirm that IANA_WHOIS_SERVER contains whois.iana.org.
- Check whether your network permits outbound TCP traffic on port 43.
- Try another internet connection if the socket waits until the timeout.
Help me diagnose the socket query.
You have sent a real WHOIS request through a raw TCP socket. Next, you will turn IANA's referral into a second query for the more specific record.
Follow WHOIS Referrals
Your raw TCP WHOIS client now reaches IANA. Its response exposes a refer: line that points to a more authoritative server.
A regular expression can capture the referral value from the unstructured response. The captured server becomes the destination for a second query.
IANA remains the fallback when no referral exists.
In this step, get ready to:
- Extract the referred WHOIS server with a regular expression.
- Query the referred server when IANA provides one.
- Compare the authoritative response with the registry-level response.
Extract the referral with regex
IANA formats each field as a key plus a value. The referral helper searches each line for the refer: key.
- Select network_intel.py in the Explorer sidebar of Visual Studio Code.
- Find the existing import socket line.
- Replace the existing import with this import group:
import re
import socket
Why Add This Import?
The re module provides Python's regular expression tools. The existing socket module continues to handle DNS resolution plus WHOIS connections.
- Save network_intel.py.
You should see import re directly above import socket at the top of the file.
- Find the whois_preview() function.
- Add the referral helper directly above whois_preview():
def extract_referral(response_text):
match = re.search(
r"^refer:\s*(\S+)\s*$",
response_text,
re.IGNORECASE | re.MULTILINE,
)
return match.group(1) if match else None
What Does This Code Do?
- The re.search() call scans the WHOIS response for the first matching referral line.
- The ^refer: section anchors the match to the start of a line.
- The captured \S+ value holds the referred server hostname.
- The flags allow different letter casing across multiple response lines.
- The final expression returns the captured hostname when a match exists. It returns None when IANA provides no referral.
- Save network_intel.py.
- Confirm extract_referral() appears between whois_query() plus whois_preview().
Seeing a Problem in the Helper?
Check that the regex begins with r before its opening quote. Confirm that the closing parenthesis aligns with match = re.search(.
Make sure return remains indented inside extract_referral().
Help me check my referral helper.
Query the referred server
The current workflow always prints IANA's response. The next edit turns the extracted referral into the destination for a second WHOIS query.
- Find this block inside main() in network_intel.py:
addresses = resolve_target(target)
iana_response = whois_query(IANA_WHOIS_SERVER, target)
print("Resolved addresses:")
for address in addresses:
print(f" - {address}")
print("IANA WHOIS preview:")
for line in whois_preview(iana_response):
print(f" {line}")
What Does the Current Block Do?
This block resolves the target before querying IANA. It prints the registry-level response without using the referral.
- Replace the current block with this referral-aware workflow:
addresses = resolve_target(target)
iana_response = whois_query(IANA_WHOIS_SERVER, target)
referral = extract_referral(iana_response)
whois_server = referral or IANA_WHOIS_SERVER
authoritative_response = iana_response
if referral:
authoritative_response = whois_query(referral, target)
print("Resolved addresses:")
for address in addresses:
print(f" - {address}")
print(f"Authoritative WHOIS server: {whois_server}")
print("WHOIS preview:")
for line in whois_preview(authoritative_response):
print(f" {line}")
How Does the Referral Flow Work?
- The iana_response variable preserves the original registry-level response.
- The referral variable holds the extracted server hostname or None.
- The whois_server variable selects the referral when one exists. It selects IANA as the fallback otherwise.
- The authoritative_response variable starts with IANA's response. A referral replaces it with the result of the second query.
- The output now identifies the selected server before printing its filtered response.
- Save network_intel.py.
- Confirm the new referral logic remains inside main().
✔️ Awesome, I've got everything!
Great. Your saved script can now extract a referral before choosing the WHOIS server.
ⓧ I'd like to double check the full code
import re
import socket
IANA_WHOIS_SERVER = "whois.iana.org"
WHOIS_PORT = 43
def resolve_target(target):
results = socket.getaddrinfo(target, None, type=socket.SOCK_STREAM)
return sorted({result[4][0] for result in results})
def whois_query(server, query):
chunks = []
with socket.create_connection((server, WHOIS_PORT), timeout=5) as connection:
connection.sendall((query + "\r\n").encode("ascii"))
while True:
chunk = connection.recv(4096)
if not chunk:
break
chunks.append(chunk)
return b"".join(chunks).decode("utf-8", errors="replace")
def extract_referral(response_text):
match = re.search(
r"^refer:\s*(\S+)\s*$",
response_text,
re.IGNORECASE | re.MULTILINE,
)
return match.group(1) if match else None
def whois_preview(response_text, limit=12):
lines = []
for line in response_text.splitlines():
cleaned = line.strip()
if cleaned and not cleaned.startswith("%"):
lines.append(cleaned)
return lines[:limit]
def main():
print("Python Network Intelligence CLI")
target = input("Domain or IP address: ").strip()
if not target:
print("Enter a public domain or IP address.")
return
addresses = resolve_target(target)
iana_response = whois_query(IANA_WHOIS_SERVER, target)
referral = extract_referral(iana_response)
whois_server = referral or IANA_WHOIS_SERVER
authoritative_response = iana_response
if referral:
authoritative_response = whois_query(referral, target)
print("Resolved addresses:")
for address in addresses:
print(f" - {address}")
print(f"Authoritative WHOIS server: {whois_server}")
print("WHOIS preview:")
for line in whois_preview(authoritative_response):
print(f" {line}")
if __name__ == "__main__":
main()
Run the authoritative query
Before you run the updated tool, do you expect the preview to stop at IANA or come from the referred server?
- Return to PowerShell from earlier.
- Launch the updated network intelligence tool by running this command:
python network_intel.py
What Does This Command Do?
This command runs the saved network_intel.py script. The script pauses at its target prompt before starting the lookup.
- Enter example.com at the prompt.
You should see whois.verisign-grs.com after Authoritative WHOIS server:. The preview now contains the more specific response returned by that server.
- Compare the new WHOIS preview with the IANA preview from the previous step.
You have closed the referral gap. Your CLI now turns IANA's registry-level pointer into a second WHOIS query.
Does the Second Query Fail?
Some networks filter outbound TCP port 43. Try another home connection if the referred query times out repeatedly.
Check that extract_referral() returns only the hostname. Extra spaces can prevent the connection from reaching the referred server.
Help me diagnose my referred WHOIS query.
Your tool now follows WHOIS referrals to a more specific response. Next, you will enrich the resolved address with structured REST data plus readable error handling.
Enrich and Handle Network Errors
Following IANA's referral gives you ownership plus delegation text from WHOIS. The report still needs structured REST data for location plus network context.
The Free IP API returns JSON over HTTPS for one resolved address. Specific error handling keeps DNS failures readable.
In this step, get ready to:
- Enrich the first resolved address with structured IP data.
- Assemble the DNS results plus WHOIS details into one report.
- Handle network failures without showing a traceback.
Fetch structured IP details
The Python standard library can send the HTTPS request. It can decode the returned JSON without another package.
- Switch back to network_intel.py in Visual Studio Code.
- Select the import block plus the two constants through WHOIS_PORT = 43.
- Replace the selected block with this code:
import json
import re
import socket
import urllib.request
IANA_WHOIS_SERVER = "whois.iana.org"
WHOIS_PORT = 43
FREE_IP_API = "https://free.freeipapi.com/api/v1/json/{}"
What Does This Setup Add?
- The json module decodes the API response into Python data.
- The urllib.request module opens the HTTPS connection.
- The FREE_IP_API template leaves a slot for the resolved IP address.
- Find return lines[:limit] at the end of whois_preview().
- Add this function directly below whois_preview():
def fetch_ip_details(ip_address):
url = FREE_IP_API.format(ip_address)
with urllib.request.urlopen(url, timeout=5) as response:
return json.load(response)
What Does This Function Do?
- The ip_address argument fills the address slot in the endpoint template.
- The five-second timeout prevents the HTTPS request from waiting forever.
- The json.load() call parses the response stream into a dictionary.
- Save network_intel.py.
- Switch back to the PowerShell terminal from earlier.
- Press the Up Arrow key to recall your previous script command.
- Press Enter to run the script.
- Enter example.com at the prompt.
PowerShell prints the resolved addresses plus the authoritative WHOIS preview. This successful run confirms that the new imports plus function are valid Python.
Seeing an Import or Syntax Error?
Confirm that import json appears above import re. Confirm that import urllib.request appears below import socket.
Check that fetch_ip_details() starts at the left edge of the file. Its three body lines need four spaces of indentation.
Help me fix the enrichment setup.
Assemble the final report
A report dictionary gives every output function one predictable data shape. It keeps collection separate from presentation.
- Find the end of fetch_ip_details().
- Add this report builder directly below the function:
def build_report(target):
addresses = resolve_target(target)
iana_response = whois_query(IANA_WHOIS_SERVER, target)
referral = extract_referral(iana_response)
whois_server = referral or IANA_WHOIS_SERVER
authoritative_response = iana_response
if referral:
authoritative_response = whois_query(referral, target)
ip_address = addresses[0]
ip_data = fetch_ip_details(ip_address)
return {
"target": target,
"addresses": addresses,
"ip_address": ip_address,
"whois_server": whois_server,
"whois_preview": whois_preview(authoritative_response),
"ip_data": ip_data,
}
How Does the Report Come Together?
- The function resolves the target before repeating the two-stage WHOIS workflow.
- The first sorted address becomes ip_address for enrichment.
- The returned dictionary stores every value needed by the final printer.
- Find def main(): near the bottom of network_intel.py.
- Add the first part of print_report() directly above main():
def print_report(report):
ip_data = report["ip_data"]
location_parts = [
ip_data.get("cityName"),
ip_data.get("regionName"),
ip_data.get("countryName"),
]
location = ", ".join(part for part in location_parts if part)
print("\nNetwork Intelligence Report")
print("=" * 27)
print(f"Target: {report['target']}")
print("Resolved addresses:")
for address in report["addresses"]:
print(f" - {address}")
print(f"IP used for enrichment: {report['ip_address']}")
print(f"Authoritative WHOIS server: {report['whois_server']}")
What Does the First Report Section Show?
- The API fields form one readable location from the available city plus region plus country values.
- The report begins with the original target plus every resolved address.
- The report identifies the address used for enrichment plus the authoritative WHOIS server.
- Save network_intel.py.
- Switch back to the PowerShell terminal.
- Press the Up Arrow key to recall the script command.
- Press Enter to run it.
- Enter example.com at the prompt.
PowerShell prints the existing WHOIS results without a syntax error. Your report builder plus the first printer section now load successfully.
- Return to print_report() in network_intel.py.
- Place the cursor directly after the authoritative WHOIS server line.
- Add the remaining report fields at the same indentation level:
print(f"Location: {location or 'Not provided'}")
print(
"Coordinates: "
f"{ip_data.get('latitude', 'Not provided')}, "
f"{ip_data.get('longitude', 'Not provided')}"
)
print(f"ASN: {ip_data.get('asn', 'Not provided')}")
print(
"ASN organization: "
f"{ip_data.get('asnOrganization', 'Not provided')}"
)
print(f"Proxy detected: {ip_data.get('isProxy', 'Not provided')}")
print("WHOIS preview:")
for line in report["whois_preview"]:
print(f" {line}")
What Does the Completed Printer Add?
- The location plus coordinate lines turn geographic fields into readable output.
- The ASN lines identify the network number plus its organization.
- The proxy field plus WHOIS preview complete the investigation report.
- Save network_intel.py.
- Switch back to the PowerShell terminal.
- Press the Up Arrow key to recall the script command.
- Press Enter to run it.
- Enter example.com at the prompt.
PowerShell prints the existing WHOIS results again. This run confirms that the completed printer has valid syntax.
Does the File Stop with a Syntax Error?
Check that both sections of print_report() use four spaces for their main body. The lines inside each loop plus multi-line print call need another four spaces.
Confirm that each opening parenthesis has a matching closing parenthesis. Check the coordinate plus ASN organization sections first.
Help me repair the report printer.
Handle failures and verify the CLI
The final workflow sends each known failure to a specific message. Successful runs pass the completed dictionary to print_report().
- Select the existing main() function from def main(): through its final WHOIS preview loop.
- Replace the selected function with this version:
def main():
print("Python Network Intelligence CLI")
target = input("Domain or IP address: ").strip()
if not target:
print("Enter a public domain or IP address.")
return
try:
report = build_report(target)
except socket.gaierror as error:
print(f"DNS resolution failed: {error}")
except TimeoutError:
print("A network request timed out. TCP port 43 may be blocked.")
except (OSError, UnicodeError, json.JSONDecodeError) as error:
print(f"Network data could not be collected: {error}")
else:
print_report(report)
How Does the Error Handling Work?
- The try block runs the complete DNS plus WHOIS plus enrichment workflow.
- The socket.gaierror branch gives DNS failures their own message.
- The TimeoutError branch explains when a network request exceeds its limit.
- The grouped branch catches operating system plus decoding plus invalid JSON failures.
- The else branch prints the report only after collection succeeds.
- Save network_intel.py.
Prediction check: which sections will the finished report add to the WHOIS output.
- Return to the PowerShell terminal from earlier.
- Run the completed CLI with this command:
python network_intel.py
What Does This Command Run?
The command starts network_intel.py with the verified Python interpreter. The script then waits for your investigation target.
- Enter example.com at the domain or IP address prompt.
You will see resolved addresses plus whois.verisign-grs.com as the authoritative server. The final report also shows location plus coordinates plus ASN plus ASN organization plus proxy status plus WHOIS text.
Prediction check: will a misspelled target produce a traceback or a readable message.
- Press the Up Arrow key to recall the script command.
- Press Enter to start another lookup.
- Change one letter in your public domain target.
- Press Enter to submit the misspelled target.
You will see a message beginning with DNS resolution failed:. PowerShell does not show a traceback.
Does the Valid Lookup Fail?
A timeout can mean that your network blocks outbound TCP port 43. Try the lookup on a home connection that permits WHOIS traffic.
An HTTPS failure can stop the enrichment request after WHOIS succeeds. Confirm that your internet connection can reach the Free IP API.
Help me diagnose the failed lookup.
That is the complete investigation loop working. Your CLI now turns a public target into a structured report while keeping network failures readable.
✔️ Awesome, I've got everything!
Great work. Your saved CLI now combines DNS resolution plus authoritative WHOIS plus REST enrichment plus readable error handling.
ⓧ I'd like to double check the full code
import json
import re
import socket
import urllib.request
IANA_WHOIS_SERVER = "whois.iana.org"
WHOIS_PORT = 43
FREE_IP_API = "https://free.freeipapi.com/api/v1/json/{}"
def resolve_target(target):
results = socket.getaddrinfo(target, None, type=socket.SOCK_STREAM)
return sorted({result[4][0] for result in results})
def whois_query(server, query):
chunks = []
with socket.create_connection((server, WHOIS_PORT), timeout=5) as connection:
connection.sendall((query + "\r\n").encode("ascii"))
while True:
chunk = connection.recv(4096)
if not chunk:
break
chunks.append(chunk)
return b"".join(chunks).decode("utf-8", errors="replace")
def extract_referral(response_text):
match = re.search(
r"^refer:\s*(\S+)\s*$",
response_text,
re.IGNORECASE | re.MULTILINE,
)
return match.group(1) if match else None
def whois_preview(response_text, limit=12):
lines = []
for line in response_text.splitlines():
cleaned = line.strip()
if cleaned and not cleaned.startswith("%"):
lines.append(cleaned)
return lines[:limit]
def fetch_ip_details(ip_address):
url = FREE_IP_API.format(ip_address)
with urllib.request.urlopen(url, timeout=5) as response:
return json.load(response)
def build_report(target):
addresses = resolve_target(target)
iana_response = whois_query(IANA_WHOIS_SERVER, target)
referral = extract_referral(iana_response)
whois_server = referral or IANA_WHOIS_SERVER
authoritative_response = iana_response
if referral:
authoritative_response = whois_query(referral, target)
ip_address = addresses[0]
ip_data = fetch_ip_details(ip_address)
return {
"target": target,
"addresses": addresses,
"ip_address": ip_address,
"whois_server": whois_server,
"whois_preview": whois_preview(authoritative_response),
"ip_data": ip_data,
}
def print_report(report):
ip_data = report["ip_data"]
location_parts = [
ip_data.get("cityName"),
ip_data.get("regionName"),
ip_data.get("countryName"),
]
location = ", ".join(part for part in location_parts if part)
print("\nNetwork Intelligence Report")
print("=" * 27)
print(f"Target: {report['target']}")
print("Resolved addresses:")
for address in report["addresses"]:
print(f" - {address}")
print(f"IP used for enrichment: {report['ip_address']}")
print(f"Authoritative WHOIS server: {report['whois_server']}")
print(f"Location: {location or 'Not provided'}")
print(
"Coordinates: "
f"{ip_data.get('latitude', 'Not provided')}, "
f"{ip_data.get('longitude', 'Not provided')}"
)
print(f"ASN: {ip_data.get('asn', 'Not provided')}")
print(
"ASN organization: "
f"{ip_data.get('asnOrganization', 'Not provided')}"
)
print(f"Proxy detected: {ip_data.get('isProxy', 'Not provided')}")
print("WHOIS preview:")
for line in report["whois_preview"]:
print(f" {line}")
def main():
print("Python Network Intelligence CLI")
target = input("Domain or IP address: ").strip()
if not target:
print("Enter a public domain or IP address.")
return
try:
report = build_report(target)
except socket.gaierror as error:
print(f"DNS resolution failed: {error}")
except TimeoutError:
print("A network request timed out. TCP port 43 may be blocked.")
except (OSError, UnicodeError, json.JSONDecodeError) as error:
print(f"Network data could not be collected: {error}")
else:
print_report(report)
if __name__ == "__main__":
main()
How to Use This Reference
This reference shows the exact final order of every import plus constant plus function in network_intel.py.
Secret mission
Automate Batch Lookups to CSV
Turn your single-target CLI into reusable batch automation. Read three targets from a file, preserve failures in a CSV report, and pace the API requests.
Clean Up Your Resources
Clean Up Your Resources
Everything you created stays inside the local python-network-intel folder. Keeping that folder costs $0 because the project created no remote resource or background service.
Resources you used:
- The local python-network-intel folder containing network_intel.py, batch_lookup.py, targets.txt, and network_report.csv.
Keep everything running
Keeping the folder requires no action. Choose this option if you plan to test more public targets.
- Leave the python-network-intel folder in its current location.
Pause - I'll come back to this later
The scripts have already finished. No background process remains active.
- Close Visual Studio Code to close the PowerShell terminal.
- Keep the python-network-intel folder in its current location.
Your scripts, target list, and CSV report stay ready for your next session.
Delete - I don't want to use this again
Deleting the folder is permanent. Choose this option only when you no longer need the scripts or CSV report.
- Close Visual Studio Code.
- Navigate to the parent location of the python-network-intel folder in Windows File Explorer.
- Delete the python-network-intel folder.
You should no longer see the python-network-intel folder in its parent location. No remote cleanup is required.
Nice Work!
Nice Work!
You made it! Your Python project now turns a public target into a readable network intelligence report.
What you can now do:
- Use DNS resolution to find unique IPv4 and IPv6 addresses for a public target.
- Expose IANA's incomplete registry response with a raw WHOIS query over TCP port 43. Extract its referral with a regular expression to reach the authoritative server.
- Add REST enrichment from an HTTPS JSON API to report structured network context. Catch expected failures without a traceback.
- Secret Mission: Turn the single-target tool into a rate-limited CSV batch runner that exports network_report.csv. Preserve failures in the error column so later targets still run.
Ready to quiz yourself?