Skip to content

Instantly share code, notes, and snippets.

@ZEROF
Created March 20, 2026 08:46
Show Gist options
  • Select an option

  • Save ZEROF/8a7b6bf0181adc2628639a3779158f07 to your computer and use it in GitHub Desktop.

Select an option

Save ZEROF/8a7b6bf0181adc2628639a3779158f07 to your computer and use it in GitHub Desktop.
Shodan GeoPing Tool

Shodan GeoPing – Quick‑Start Guide

image

What it does

Runs a Shodan GeoPing query against a domain, collects RTT and packet‑loss data from many global locations, and prints a concise, tabulated report.


1. Prerequisites

  • Python 3.8+
  • pip (or uv)
pip install requests tabulate

2. Install / Run

# Create a virtual environment (optional but recommended)
uv venv shodangeoping
source shodangeoping/bin/activate

# Install dependencies
uv pip install requests tabulate

# Save the script below as shodangeoping.py
# Make it executable
chmod +x shodangeoping.py

# Run it
./shodangeoping.py -d example.com

3. Usage

./shodangeoping.py -d <domain>
  • -d, --domain – Target domain (e.g., example.com).
  • -h, --help – Show help.

4. Example Output

Shodan GeoPing Performance Tester
============================================================
Test started at: 2026-03-20 09:43:57
============================================================

[*] Testing performance for domain: example.com
[*] Querying Shodan GeoPing API...

=== GLOBAL PERFORMANCE OVERVIEW ===
+---------------+-----------------------+------------------+----------+----------------+----------------+----------------+----------------+--------------------+-------------------+
| IP            | Location              | Coordinates      | Status   |   Min RTT (ms) |   Avg RTT (ms) |   Max RTT (ms) |   Packets Sent |   Packets Received | Packet Loss (%)   |
+===============+=======================+==================+==========+================+================+================+================+====================+===================+
| 104.18.27.120 | Clifton, US           | 40.8584,-74.1638 | Alive    |          1.693 |          2.311 |          3.525 |              3 |                  3 | 0.0%              |
+---------------+-----------------------+------------------+----------+----------------+----------------+----------------+----------------+--------------------+-------------------+
| 104.18.27.120 | London, GB            | 51.5085,-0.1257  | Alive    |          2.463 |          2.689 |          2.942 |              3 |                  3 | 0.0%              |
+---------------+-----------------------+------------------+----------+----------------+----------------+----------------+----------------+--------------------+-------------------+
| 104.18.27.120 | Amsterdam, NL         | 52.3740,4.8897   | Alive    |          1.06  |          1.353 |          1.909 |              3 |                  3 | 0.0%              |
+---------------+-----------------------+------------------+----------+----------------+----------------+----------------+----------------+--------------------+-------------------+
| 104.18.26.120 | Frankfurt am Main, DE | 50.1155,8.6842   | Alive    |          1.045 |          1.39  |          2.019 |              3 |                  3 | 0.0%              |
+---------------+-----------------------+------------------+----------+----------------+----------------+----------------+----------------+--------------------+-------------------+
| 104.18.26.120 | Singapore, SG         | 1.3215,103.6957  | Alive    |          1.2   |          1.5   |          2.011 |              3 |                  3 | 0.0%              |
+---------------+-----------------------+------------------+----------+----------------+----------------+----------------+----------------+--------------------+-------------------+

=== PERFORMANCE ANALYSIS ===

Target Domain: example.com
Total Locations Tested: 5
Average RTT Across All Locations: 1.849 ms
Highest RTT: 3.525 ms
Lowest RTT: 1.045 ms
Average Packet Loss: 0.0%

[+] Test completed successfully
[+] Test ended at: 2026-03-20 09:44:00
============================================================


5. The Script (shodangeoping.py)

#!/usr/bin/env python3
import sys
import argparse
import requests
from datetime import datetime
from tabulate import tabulate

BANNER = r"""
  ██████   ██░ ██  ▒█████  ▓█████▄  ▄▄▄      ███▄    █        ▄████  ▓█████ ▒█████       ██▓███    ██▓ ███▄    █  ▄████
▒██    ▒ ▒▓██░ ██ ▒██▒  ██▒▒██▀ ██▌▒████▄    ██ ▀█   █     ▒ ██▒ ▀█▒ ▓█   ▀▒██▒  ██▒    ▓██░  ██ ▒▓██▒ ██ ▀█   █  ██▒ ▀█
░ ▓██▄   ░▒██▀▀██ ▒██░  ██▒░██   █▌▒██  ▀█▄ ▓██  ▀█ ██▒    ░▒██░▄▄▄░ ▒███  ▒██░  ██▒    ▓██░ ██▓▒▒▒██▒▓██  ▀█ ██▒▒██░▄▄▄
  ▒   ██▒ ░▓█ ░██ ▒██   ██░░▓█▄   ▌░██▄▄▄▄██▓██▒  ▐▌██▒    ░░▓█  ██▓ ▒▓█  ▄▒██   ██░    ▒██▄█▓▒ ▒░░██░▓██▒  ▐▌██▒░▓█  ██
▒██████▒▒ ░▓█▒░██▓░ ████▓▒░░▒████▓ ▒▓█   ▓██▒▓██▒   ▐▌██▒    ░ ▓█   █░▒▓█  █▓████▓░   ░█████▒   ████▒  █████▒ ░███
"""

def print_banner():
    print("=" * 60)
    print("Shodan GeoPing Performance Tester")
    print(f"Test started at: {datetime.now():%Y-%m-%d %H:%M:%S}")
    print("=" * 60)

def get_performance_data(domain: str):
    url = f"https://api.shodan.io/shodan/geo?host={domain}"
    resp = requests.get(url, timeout=10)
    resp.raise_for_status()
    return resp.json()

def process_data(raw):
    return [
        {
            "ip": item["ip"],
            "location": f'{item["location"]["city"]}, {item["location"]["country"]}',
            "coordinates": f'{item["location"]["latitude"]},{item["location"]["longitude"]}',
            "status": "Alive" if item.get("status", "").lower() == "alive" else "Lost",
            "min_rtt": f'{item["stats"]["rtt_min"]:.3f}',
            "avg_rtt": f'{item["stats"]["rtt_avg"]:.3f}',
            "max_rtt": f'{item["stats"]["rtt_max"]:.3f}',
            "packets_sent": item["stats"]["sent"],
            "packets_recv": item["stats"]["recv"],
            "packet_loss": f'{item["stats"]["packet_loss"]:.1f}%',
        }
        for item in raw
    ]

def display_results(data, domain):
    table = [
        [
            d["ip"],
            d["location"],
            d["coordinates"],
            d["status"],
            d["min_rtt"],
            d["avg_rtt"],
            d["max_rtt"],
            d["packets_sent"],
            d["packets_recv"],
            d["packet_loss"],
        ]
        for d in data
    ]
    print("\n=== GLOBAL PERFORMANCE OVERVIEW ===")
    print(tabulate(table, headers=[
        "IP", "Location", "Coordinates", "Status",
        "Min RTT (ms)", "Avg RTT (ms)", "Max RTT (ms)",
        "Packets Sent", "Packets Received", "Packet Loss (%)",
    ], tablefmt="grid"))

    avg_rtt = sum(float(d["avg_rtt"]) for d in data) / len(data)
    max_rtt = max(float(d["max_rtt"]) for d in data)
    min_rtt = min(float(d["min_rtt"]) for d in data)
    avg_loss = sum(float(d["packet_loss"].rstrip("%")) for d in data) / len(data)

    print("\n=== PERFORMANCE ANALYSIS ===")
    print(f"\nTarget Domain: {domain}")
    print(f"Total Locations Tested: {len(data)}")
    print(f"Average RTT Across All Locations: {avg_rtt:.3f} ms")
    print(f"Highest RTT: {max_rtt:.3f} ms")
    print(f"Lowest RTT: {min_rtt:.3f} ms")
    print(f"Average Packet Loss: {avg_loss:.1f}%")

def main():
    parser = argparse.ArgumentParser(
        description="Run a Shodan GeoPing query and display RTT/packet‑loss stats.",
        formatter_class=argparse.RawTextHelpFormatter,
    )
    parser.add_argument('-d', '--domain', required=True, help='Target domain (e.g., example.com)')
    args = parser.parse_args()

    print_banner()
    print(f"\n[*] Testing performance for domain: {args.domain}")
    print("\n[*] Querying Shodan GeoPing API...")

    data = get_performance_data(args.domain)
    processed = process_data(data)
    display_results(processed, args.domain)

    print("\n[+] Test completed successfully")
    print(f"[+] Test ended at: {datetime.now():%Y-%m-%d %H:%M:%S}")
    print("=" * 60)

if __name__ == "__main__":
    main()

Note: The script assumes the public Shodan GeoPing endpoint is reachable. If you encounter rate limits or API key requirements, refer to Shodan’s documentation for the correct query URL and authentication.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment