ipasis
Blog/Technical Guide

Programmatically Identifying Tor Exit Nodes: A Technical Guide

December 15, 20256 min read

Tor (The Onion Router) is vital for privacy, yet it represents a significant vector for automated abuse, credential stuffing, and application-layer DDoS attacks. For security engineers and CTOs, the ability to distinguish between a legitimate privacy-conscious user and a malicious bot routing through Tor is critical.

This guide outlines three distinct methodologies for identifying Tor exit nodes programmatically: parsing the official bulk exit list, utilizing the DNS Exit List (DNSEL), and leveraging real-time IP Intelligence APIs.

Method 1: Parsing the Official Tor Bulk Exit List

The Tor Project maintains a plain-text list of IP addresses that are currently running as exit nodes. This is the most direct method for 'offline' validation, where you maintain a local database of blocked IPs.

The Mechanism

  1. Fetch the list from https://check.torproject.org/torbulkexitlist.
  2. Parse the IP addresses.
  3. Cache the results in an in-memory data store (Redis/Memcached) for O(1) lookup access.

Warning: Do not fetch this list on every incoming HTTP request. The latency overhead is unacceptable, and you will be rate-limited by the Tor Project. Update your local cache asynchronously (e.g., via a cron job every 30 minutes).

Python Implementation

import requests
import redis

# Configuration
TOR_LIST_URL = "https://check.torproject.org/torbulkexitlist"
REDIS_HOST = "localhost"
REDIS_PORT = 6379

def refresh_tor_cache():
    try:
        r = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, db=0)
        response = requests.get(TOR_LIST_URL, timeout=5)
        
        if response.status_code == 200:
            ips = response.text.strip().splitlines()
            
            # Use a pipeline for atomic operations
            pipe = r.pipeline()
            pipe.delete("tor_exit_nodes")
            if ips:
                pipe.sadd("tor_exit_nodes", *ips)
            pipe.execute()
            
            print(f"Updated cache with {len(ips)} Tor exit nodes.")
        else:
            print(f"Failed to fetch list: {response.status_code}")
            
    except Exception as e:
        print(f"Error updating Tor cache: {str(e)}")

if __name__ == "__main__":
    refresh_tor_cache()

Method 2: The DNS Exit List (DNSEL)

If maintaining a local database is not feasible, the Tor Project provides a DNS-based query service. This allows you to check if a specific IP address is a Tor exit node capable of reaching your specific server IP and port.

The query format requires reversing the octets of the client IP.

Go Implementation

package main

import (
	"fmt"
	"net"
	"strings"
)

// reverseIP takes "1.2.3.4" and returns "4.3.2.1"
func reverseIP(ip string) string {
	parts := strings.Split(ip, ".")
	for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
		parts[i], parts[j] = parts[j], parts[i]
	}
	return strings.Join(parts, ".")
}

func isTorExitNode(clientIP, serverIP, serverPort string) bool {
	// Format: {reverse_client}.{port}.{reverse_server}.ip-port.exitlist.torproject.org
	query := fmt.Sprintf("%s.%s.%s.ip-port.exitlist.torproject.org", 
		reverseIP(clientIP), 
		serverPort, 
		reverseIP(serverIP))

	ips, err := net.LookupIP(query)
	if err != nil {
		// NXDOMAIN usually means it's not an exit node
		return false
	}

	for _, ip := range ips {
		if ip.String() == "127.0.0.2" {
			return true
		}
	}
	return false
}

func main() {
	client := "192.0.2.1" // Replace with actual incoming request IP
	server := "203.0.113.1" // Your server's public IP
	port := "80"

	if isTorExitNode(client, server, port) {
		fmt.Println("Traffic detected from Tor Exit Node")
	} else {
		fmt.Println("Traffic is clear")
	}
}

Method 3: Using an IP Intelligence API (Recommended)

While manual list parsing and DNS lookups work, they introduce maintenance overhead and potential latency. Manual lists can be stale by the time you download them, and DNS lookups add RTT to every request.

For production environments requiring high availability and zero-latency context, a dedicated IP intelligence API is the industry standard. This approach delegates the maintenance of the exit node topology to a specialized provider.

Node.js Implementation with IPASIS

const axios = require('axios');

async function checkReputation(ipAddress) {
  try {
    // Replace YOUR_API_KEY with your IPASIS credentials
    const response = await axios.get(`https://api.ipasis.com/v1/${ipAddress}?key=YOUR_API_KEY`);
    
    const data = response.data;

    if (data.security.is_tor) {
      console.warn(`BLOCK: ${ipAddress} is a confirmed Tor exit node.`);
      return false;
    }

    if (data.security.is_proxy || data.security.is_vpn) {
        console.warn(`FLAG: ${ipAddress} is using a VPN or Proxy.`);
        // Implement step-up authentication logic here
    }

    return true;
    
  } catch (error) {
    console.error("API Lookup failed, failing open:", error.message);
    return true;
  }
}

// usage
checkReputation('185.220.101.5');

FAQ

Q: Should I block all Tor traffic? A: Not necessarily. It depends on your threat model. For a banking application, likely yes. For a news site or blog, blocking Tor may infringe on user privacy. Consider using CAPTCHAs or 2FA for Tor users instead of a hard block.

Q: How often does the Tor exit list change? A: Tor is dynamic. Relays join and leave the network constantly. The official list is updated hourly, but real-time APIs often capture changes faster.

Q: What is the difference between a Relay and an Exit Node? A: A Relay passes traffic inside the Tor network. An Exit Node is the final hop where traffic leaves Tor to reach the public internet. Your server will only see the IP of the Exit Node.

Q: Does DNSEL support IPv6? A: As of the current specification, the official Tor DNSEL is primarily designed for IPv4. For IPv6 support, parsing the bulk list or using an API like IPASIS is recommended.

Secure Your Perimeter with IPASIS

Building your own detection infrastructure requires constant maintenance. IPASIS provides enterprise-grade IP intelligence, offering real-time detection of Tor exit nodes, proxies, and VPNs with sub-millisecond latency.

Stop malicious automation at the door. Get your free API key today.

Start detecting VPNs and Bots today.

Identify anonymized traffic instantly with IPASIS.

Get API Key