Validate Tor IP Address in Go

Tor Network

Tor is a free and open-source software that enables anonymous communication. It directs Internet traffic through a free, worldwide, volunteer overlay network to conceal a user’s location and usage from anyone conducting network surveillance or traffic analysis. It has helped protect the personal privacy of its users and enabled the ability to conduct confidential communication by keeping their Internet activities unmonitored.

Tor protect’s a user’s privacy, but does not hide the fact that someone is using Tor. Some bad actors use Tor’s anonymity feature to abuse services. For example, Wikipedia blocks attempts by Tor users to edit articles unless special permission is sought. So then how can service providers figure out if a user is using Tor network when using a service?

Tor Exit List service

The Tor Exit List service maintains a list of IP addresses used by all exit relays in the Tor network. Service providers may find it useful to know if users are coming from the Tor network, as they may wish to provide their users with an onion service. Tor Project also uses this information to help maintain a healthy network and to perform troubleshooting.

A service provider can utilize this service to figure out if a user’s IP address belongs to the Tor network. Let me show how this is done here.

For instance, let’s say a user’s IP address is 195.176.3.19. If the reverse octet of this IP address suffixed by .dnsel.torproject.org resolves to 127.0.0.2, then the IP address belongs to the Tor network.

For example, if 195.176.3.19 is the user’s IP address, the reverse octets is 19.3.176.195.

$ host 19.3.176.195.dnsel.torproject.org
19.3.176.195.dnsel.torproject.org has address 127.0.0.2

Complete Go source code.

package main

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

func main() {
	userIP := "195.176.3.19"
	fmt.Printf("Does `%s` belong to the Tor network? %t\n", userIP, validateTor(userIP))
}

func validateTor(clientIP string) bool {
	torExt := fmt.Sprintf(torDNSEL, reverseOctets(clientIP))

	addrs, _ := net.LookupHost(torExt)
	for _, addr := range addrs {
		if addr == torValidationAddr {
			return true
		}
    }

	return false
}

func reverseOctets(ip string) string {
	oct := strings.Split(ip, ".")
	for i := len(oct)/2 - 1; i >= 0; i-- {
		opp := len(oct) - 1 - i
		oct[i], oct[opp] = oct[opp], oct[i]
	}
	return strings.Join(oct, ".")
}

const (
	torValidationAddr = "127.0.0.2"
	torDNSEL          = "%s.dnsel.torproject.org"
)

References

In case you would like to get notified about more articles like this, please subscribe to my substack.



Comments

comments powered by Disqus