Skip to content

mbahnizen/whoisdig

Repository files navigation

WHOISDIG

WHOISDIG

Intelligent WHOIS, RDAP & DNS Lookup Engine
A fast, hybrid domain intelligence tool with IP geolocation, circuit breakers, and smart caching.

🚀 Live Demo: https://whoisdig.web.app

PHP Version License Status RDAP Google Cloud Run Firebase Hosting


✨ Features

Feature Description
Hybrid Resolution WHOIS (Port 43) + RDAP (REST/JSON) with automatic fallback
IANA Server Discovery Dynamically resolves authoritative WHOIS/RDAP servers per TLD
Referral Chaining Follows WHOIS referrals up to 2 levels deep for accurate results
IP Intelligence RDAP network data + GeoIP enrichment (location, ASN, ISP, proxy detection)
Circuit Breaker Automatic fault isolation — prevents cascading failures from slow WHOIS servers
Smart Cache (SWR) Stale-While-Revalidate file cache with file locking for high concurrency
Bulk Processing Process up to 500 domains/IPs with progressive real-time UI updates
Public Suffix List Accurate multi-level TLD resolution via Mozilla's PSL (auto-updated)
DNS Dig Full DNS record lookup — A, AAAA, MX, NS, CNAME, TXT, SOA, SRV, PTR
Rate Limiting File-based sliding window rate limiter with automatic garbage collection
DNSSEC Detection Real-time DNSSEC status (Signed/Unsigned) with visual badges
TLD Availability Check Instantly check alternative TLD availability (.com, .net, .org, .id, etc.) in one click
Copy Summary Extract perfectly aligned monospaced summaries of domains and IPs for clean sharing
Dark / Light Mode Responsive, glassmorphism UI built with Tailwind CSS

📸 Screenshots

Click to hide screenshots

Domain WHOIS Lookup (Expanded)

WHOIS Lookup Expanded

IP Intelligence (Expanded Details)

IP Details

DNS Dig

DNS Dig


🚀 Quick Start

Requirements

  • PHP >= 7.4
  • Extensions: curl, json, intl (for IDN support)
  • Apache or Nginx with mod_rewrite (optional)

Installation

# Clone the repository
git clone https://github.com/mbahnizen/whoisdig.git
cd whoisdig

# Ensure storage directories are writable
chmod -R 755 storage/

# Point your web server document root to the public/ directory
# For quick local testing:
php -S localhost:8000 -t public/

Open http://localhost:8000 in your browser.


📡 API Usage

All endpoints are served from public/api.php.

Domain WHOIS Lookup

GET /api.php?action=whois-single&domain=google.com
Example Response
{
  "success": true,
  "domain": "google.com",
  "tld": "com",
  "registrar": "MarkMonitor Inc.",
  "whois_server": "whois.markmonitor.com",
  "created": "1997-09-15T04:00:00+0000",
  "updated": "2019-09-09T15:39:04+0000",
  "expires": "2028-09-13T07:00:00+0000",
  "status": ["clientDeleteProhibited", "clientTransferProhibited", "clientUpdateProhibited", "serverDeleteProhibited", "serverTransferProhibited", "serverUpdateProhibited"],
  "nameservers": ["ns1.google.com", "ns2.google.com", "ns3.google.com", "ns4.google.com"],
  "lifecycle": {
    "age_days": 10077,
    "days_until_expiry": 880
  },
  "raw": "<base64-encoded raw WHOIS output>"
}

IP Intelligence

GET /api.php?action=whois-single&domain=8.8.8.8
Example Response
{
  "success": true,
  "is_ip": true,
  "domain": "8.8.8.8",
  "organization": "Google LLC",
  "country": "US",
  "network_name": "GOGL",
  "cidr": "8.8.8.0/24",
  "ip_version": "v4",
  "asn": "AS15169",
  "asn_name": "GOOGLE",
  "hostname": "dns.google",
  "geo": {
    "country_name": "United States",
    "region": "Virginia",
    "city": "Ashburn",
    "isp": "Google LLC",
    "is_proxy": false,
    "is_hosting": true,
    "is_mobile": false
  },
  "ip_decimal": "134744072",
  "ip_hex": "08.08.08.08"
}

Bulk WHOIS

POST /api.php?action=whois-bulk
Content-Type: application/json

{
  "domains": ["google.com", "github.com", "8.8.8.8"],
  "refresh": false
}

DNS Dig

GET /api.php?action=dig&domain=google.com&type=MX
Example Response
{
  "success": true,
  "domain": "google.com",
  "record_type": "MX",
  "results": ["10 smtp.google.com", "20 smtp2.google.com"]
}

Force Refresh (bypass cache)

GET /api.php?action=whois-single&domain=example.com&refresh=1

☁️ Deployment

WHOISDIG is natively designed to be deployed in a high-performance serverless environment using Google Cloud Run (for dynamic PHP processing) and Firebase Hosting (as an edge CDN and proxy gateway).

1. Local Development (Docker Compose)

To run the entire stack locally in a containerized environment:

# Start the containers
docker compose up --build

This starts the application at http://localhost:8080 with auto-reloading and persists your caching and metrics logging locally.


2. Deploying to Google Cloud Run

Google Cloud Run offers a generous free tier (2 million requests/month) and complete outbound TCP port 43 access required for legacy WHOIS lookups.

Manual CLI Deployment:

If you have the Google Cloud SDK installed, you can build and deploy directly:

# Configure gcloud active project
gcloud config set project whoisdig

# Enable dynamic APIs
gcloud services enable run.googleapis.com artifactregistry.googleapis.com

# Create the Artifact Registry repository
gcloud artifacts repositories create whoisdig-repo --repository-format=docker --location=asia-southeast2

# Build & Deploy to Cloud Run
gcloud run deploy whoisdig \
  --source . \
  --region asia-southeast2 \
  --allow-unauthenticated \
  --port 8080

3. Deploying to Firebase Hosting (Custom Domain Routing)

Firebase Hosting acts as the front gateway to map your custom domain (like whoisdig.web.app) and automatically proxy dynamic requests to your Cloud Run service.

Deployment Steps:

  1. Log in to your Firebase account via the CLI:
    npx firebase login
  2. Deploy the hosting configuration (defined in firebase.json):
    npx firebase deploy --only hosting --project=whoisdig

4. Continuous Integration & Deployment (CI/CD via GitHub Actions)

Every push to the main or master branch will trigger an automated deployment using .github/workflows/deploy-cloudrun.yml.

Repository Setup:

  1. Under your GitHub Repository Settings -> Secrets and variables -> Actions, add the following repository secrets:
    • GCP_PROJECT_ID: Set to whoisdig.
    • GCP_SA_KEY: Set to the entire JSON private key of a Google IAM Service Account with least-privilege deployment roles (run.admin, artifactregistry.writer, iam.serviceAccountUser, and iam.serviceAccountTokenCreator).
  2. Push to GitHub! The runner will build, tag, push your Docker container to Artifact Registry, and rollout a clean, zero-downtime revision to Cloud Run.

🏗️ Architecture

public/
├── index.html          # Frontend SPA
├── api.php             # API router (single entry point)
├── js/app.js           # Frontend logic (progressive loading)
└── css/app.css         # Styles (glassmorphism, dark/light)

config/
└── app.php             # Global config, autoloader, rate limiting

src/
├── Clients/
│   ├── WhoisClient.php     # Raw WHOIS (Port 43) with retry + circuit breaker
│   ├── RdapClient.php      # RDAP REST client with circuit breaker
│   └── GeoIpClient.php     # GeoIP enrichment (multi-provider fallback)
├── Parsers/
│   ├── WhoisParser.php     # Regex-based WHOIS response parser
│   ├── RdapParser.php      # Structured RDAP JSON parser
│   └── ReferralParser.php  # WHOIS referral server extractor
├── Resolvers/
│   ├── WhoisService.php    # Core orchestrator (hybrid resolution engine)
│   ├── WHOISChecker.php    # Public facade / entry point
│   ├── DigChecker.php      # DNS record resolver
│   ├── IanaResolver.php    # IANA WHOIS/RDAP server discovery
│   └── TldResolver.php     # TLD detection via Mozilla PSL
└── Utils/
    ├── Cache.php           # File-based SWR cache with flock()
    ├── CircuitBreaker.php  # Fault isolation for external services
    └── Metrics.php         # JSONL performance logging

storage/
├── cache/              # Cached WHOIS/RDAP/GeoIP results
└── logs/               # Activity logs, metrics, rate-limit data

How a lookup works

Browser → api.php → WHOISChecker → WhoisService
                                       ├── Is IP? → RDAP /ip → GeoIP enrichment → merge
                                       └── Is Domain? → TLD resolve → IANA discover
                                              ├── WHOIS Port 43 → referral chain → parse
                                              └── Fallback → RDAP /domain → parse
                                       Cache ←→ (all steps)
                                       CircuitBreaker ←→ (all external calls)

⚙️ Design Philosophy

Why hybrid resolution?

Legacy WHOIS (Port 43) has the widest coverage, but modern TLDs (.dev, .app, .page) only support RDAP. WHOISDIG uses RDAP-first for modern TLDs and WHOIS-first for legacy TLDs, with automatic fallback in both directions.

Why Stale-While-Revalidate cache?

WHOIS servers are slow (500ms–7s) and rate-limited. SWR ensures:

  • Instant responses from cache for repeat queries
  • Background revalidation when cache is stale
  • No thundering herd — file locking prevents duplicate fetches

Why circuit breakers?

External WHOIS/RDAP servers can be unreliable. The circuit breaker:

  • Tracks failures per server
  • Temporarily blocks requests to failing servers (cooldown period)
  • Automatically recovers when the server comes back online

🔒 Security

  • Input Sanitization — All input is cleaned before processing (trim + lowercase)
  • Output Encoding — HTML escaping at the display layer prevents XSS
  • Rate Limiting — Sliding window (120 req/hour per IP) with Retry-After support
  • Storage Protection.htaccess blocks direct access to cache/logs
  • CORS — Configurable via WHOISDIG_CORS_ORIGIN environment variable
  • Error Isolation — Internal errors are logged; clients receive generic messages

🗺️ Roadmap

  • IPv6 PTR lookup support
  • WHOIS response diffing (track changes over time)
  • Webhook notifications for domain expiry
  • REST API authentication (API keys)
  • Docker image & Container support (with local docker-compose and Cloud Run deployment)
  • Export results (CSV / JSON)
  • Batch upload via file (CSV/TXT)

🤝 Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Please ensure your code:

  • Follows the existing code structure
  • Includes appropriate error handling
  • Does not introduce new external dependencies without discussion

📄 License

This project is licensed under the MIT License — see the LICENSE file for details.


Built with ❤️ for the domain intelligence community