Python – IP Location and Subnet Scanner

This script was developed to address a specific scenario where vendors provide a range of IP subnets to be whitelisted. In environments where geolocation-based blocking is implemented, verifying the geographic origins of these IP addresses is crucial.

The aim is to ensure that none of the IP addresses within the provided subnets originate from countries that are intended to be blocked as per our security policies. It is important to note that an IP block provided by a vendor may not necessarily correspond to a single geographic location. Even though it might appear as a single network block, it could contain subnets assigned to various countries.

Therefore, by simply testing the first available IP address in the vendor-provided block, we might not get an accurate representation of the entire range. Other subnets within that block could be assigned to different countries. This is why we’ve built this script, to verify each relevant subnet within the provided IP block, ensuring that none originate from our list of blocked countries. This helps maintain the integrity of our geolocation-based security measures.

# Author: Kerry Cordero
# Version: 1.0.0
# Description: This script prompt for the IP Address and then the SubnetMask/CIDR.  It will output the IP, Country, Country Code, Region, City, Latitude, Longitude.

import requests
from prettytable import PrettyTable
import ipaddress

api_key = "da4fd73c8e152f70bdf56547a008785edd27f34e6862bde308e215ac"

def get_ip_location(ip):
    url = f"https://api.ipdata.co/{ip}?api-key={api_key}"
    response = requests.get(url)
    data = response.json()

    if "message" in data:
        print("Error:", data["message"])
        return None
    else:
        return {
            "IP": data["ip"],
            "Country": data["country_name"],
            "Country Code": data["country_code"],
            "Region": data["region"],
            "City": data["city"],
            "Latitude": data["latitude"],
            "Longitude": data["longitude"]
        }

def subnet_calculation(ip_address, subnet):
    # Convert the IP address to IPv4Network object
    network = ipaddress.IPv4Network(f"{ip_address}/{subnet}", strict=False)

    # Create a PrettyTable instance
    table = PrettyTable()
    
    # Set the field names
    table.field_names = ["IP", "Country", "Country Code", "Region", "City", "Latitude", "Longitude"]

    # Create a list to hold /24 subnets
    subnet_list = [ip for ip in network.subnets(new_prefix=24)]

    # Iterate over each subnet and get location info for the first IP
    for subnet in subnet_list:
        first_ip = next(subnet.hosts())
        location = get_ip_location(first_ip)

        if location is not None:
            # Add row
            table.add_row([
                location["IP"],
                location["Country"],
                location["Country Code"],
                location["Region"],
                location["City"],
                location["Latitude"],
                location["Longitude"]
            ])
            
    # Print the table
    print(table)

# Prompt the user for the IP address
ip_address = input("Enter the IP address: ")

# Prompt the user for the subnet
subnet_input = input("Enter the subnet (in CIDR notation or full write out): ")

# Extract the subnet prefix length from the input
if "/" in subnet_input:
    subnet = int(subnet_input.split("/")[1])
else:
    # Use the subnet mask to generate a dummy IPv4Interface object, then get its network's prefix length
    dummy_interface = ipaddress.IPv4Interface(f"0.0.0.0/{subnet_input}")
    subnet = dummy_interface.network.prefixlen

# Call the subnet_calculation function
subnet_calculation(ip_address, subnet)