Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dns server #5

Open
melaxon opened this issue Apr 29, 2020 · 12 comments
Open

dns server #5

melaxon opened this issue Apr 29, 2020 · 12 comments

Comments

@melaxon
Copy link

melaxon commented Apr 29, 2020

try {
    $isTor = TorDNSEL::IpPort(
        $_SERVER['SERVER_ADDR'],
        $_SERVER['SERVER_PORT'],
        $_SERVER['REMOTE_ADDR']
    );
    var_dump($isTor);
 } catch (\Exception $ex) {
     echo $ex->getMessage() . "\n";
 }

This will always result in error:

Warning: fsockopen(): unable to connect to udp://exitlist.torproject.org:53 (php_network_getaddresses: getaddrinfo failed: Name or service not known) in /var/www/html/project/vendor/dapphp/torutils/src/TorDNSEL.php on line 183
Failed to send DNS request. Error 0: php_network_getaddresses: getaddrinfo failed: Name or service not known 

It seems like DNS server exitlist.torproject.org has changed. Will you please advice how to fix this

@dapphp
Copy link
Owner

dapphp commented Apr 29, 2020

Hi Thanks for opening this issue! It looks like I missed https://lists.torproject.org/pipermail/tor-project/2020-March/002759.html

TLDR; the TorDNSEL service is retired and replaced with a simpler and better service.

I will release a new version this evening or tomorrow morning with the fix for this.

@dapphp dapphp closed this as completed in 7d2bc43 Apr 30, 2020
@dapphp dapphp reopened this Apr 30, 2020
@dapphp
Copy link
Owner

dapphp commented Apr 30, 2020

The last commit introduces a backwards compatible fix with the current interface so it will work.

In an upcoming release the interface will be simplified and add TXT support for getting relay fingerprints.

@melaxon
Copy link
Author

melaxon commented Apr 30, 2020

Thanks for quick response!
Another issue one may face when the server works under Cloudflare:
$_SERVER shows sometimes (not always!) HTTP_X_FORWARDED_FOR in IPV6 format, while REMOTE_ADDR is Cloudflare's ip

@dapphp
Copy link
Owner

dapphp commented Apr 30, 2020

When I was working on it last night I was thinking about IPv6 too and noticing the "Tor bulk exit list" still does not contain any IPv6 addresses.

I'm going to add IPv6 support to my code for when the lists contain IPv6. This assumes the DNSBL will use the same 1-digit hex representation like other DNSBL services.

So right now you still cannot use the DNSBL for checking against IPv6 clients. I also publish my own exit lists (just derived from the "Exit" flag) so it is not based on observation like Onionoo but at least you might be able to get some basic IPv6 checking with that.

@melaxon
Copy link
Author

melaxon commented May 1, 2020

About Cloudflare: they return real IP in the header parameter HTTP_CF_CONNECTING_IP, which may contain IPv6 as well.
One man from Cloudflare community suggested a solution:
to detect visitor country using IP geolocation.
Indeed they also return HTTP_CF_IPCOUNTRY parameter that in case of Tor is always set to T1 independant on IPv4 or IPv6.
I believe it is quite reliable. What do you think?

@dapphp
Copy link
Owner

dapphp commented May 3, 2020

If your site is using Cloudflare then you can simply rely on the HTTP_CF_IPCOUNTRY being T1 to check for Tor, otherwise, you can fall back to TorDNSEL or some other list. Given CF's history with detecting/blocking Tor and their wide range of skills there's no reason to think their matching would be any more or less accurate. The added benefit now is they work with IPv6 which the new Tor DNSEL still does not.

Even though this code may no longer be too relevant for you (that's ok!) here is the newer interface I came up with in case you had any feedback. I don't like the static interface anymore but it keeps this really simple (for users) and keeps the existing code backwards compatible.

// The old deprecated method, works again and now ignores $ip, $port and only uses $remoteIp
public static TorDNSEL::IpPort($ip, $port, $remoteIp, $dnsServer = 'check-01.torproject.org');

/**
 * Query the Tor DNSEL service to check if $remoteAddr is a Tor exit relay.
 * 
 * @param $remoteAddr The remote IP address, (e.g. $_SERVER['REMOTE_ADDR'])
 * @param null $dnsServer The DNS resolver to query against (if null it will use check-01.torproject.or)
 *  Consider using a local, caching resolver for DNSEL queries!
 * @return bool true if the visitor's IP address is a Tor exit relay, false if it is not
 * @throws \Exception
 */
public static TorDNSEL::isTor($remoteAddr, $dnsServer = null);

/**
 * Query the Tor DNS Exit List service for a list of relay fingerprints that belong to the supplied IP address.
 * If $remoteAddr is not a Tor exit relay, an empty array is returned.
 * 
 * @param $remoteAddr The Tor exit relay IP address (IPv4 or IPv6) - Note: IPv6 is not currently supported by TorDNSEL
 * @param null $dnsServer The DNS resolver to query against (if null it will use check-01.torproject.or)
 *  Consider using a local, caching resolver for DNSEL queries!
 * @return array An array of Tor relay fingerprints, if the IP address is a Tor exit relay
 * @throws \Exception If there is a network error or the DNS query fails
 */
public static TorDNSEL::getFingerprints($remoteAddr, $dnsServer = null);

Example usage:

<?php

$isTor = false;
$fingerprints = [];
$remoteIP = $_SERVER['REMOTE_ADDR'];
$dnsServer = null; // null to query check-01.torproject.org, or set to your local, caching resolver

try {
    $isTor = TorDNSEL::isTor($remoteIP, $dnsServer);
    if ($isTor) {
        $fingerprints = TorDNSEL::getFingerprints($remoteIP, $dnsServer); // not necessary, for demonstration purposes.
    }
} catch (\Exception $ex) {
    error_log("TorDNSEL query failed: " . $ex->getMessage());
}

Thank you again!

@melaxon
Copy link
Author

melaxon commented May 3, 2020

This Tor detecting became a real nightmare for me. I noticed that a quite sufficient part of TOR user IPs return a particular country code rather than T1. For example 2a0b:f4c1::8 returns DE.
But its whois states in remarks that it is one of Tor exit node addresses. CF also provides an option called Pseudo IPv4. When it's on it sends corresponding IPv4 along with IPv6. But they are not in Tor exit list of course and their whois says it is reserved for future use or even is not available. E.g. 240.172.240.82

Will you please advice where and how these methods are implemented:
TorDNSEL::isTor($remoteIP, $dnsServer) and TorDNSEL::getFingerprints($remoteIP, $dnsServer) ? Sorry to be so pain and for my carelessness if I missed something

@dapphp
Copy link
Owner

dapphp commented May 3, 2020

That is unfortunate. Maybe CF's Tor detection for IPv6 is also lacking.

As stated earlier, the new TorDNSEL service also doesn't support IPv6 so this class won't help yet.

Regarding the new method signatures I posted above, I haven't actually pushed those changes yet (which include IPv6 readiness but not support since the underlying service doesn't yet either.

Sadly, this may require even more code.

The Tor exit lists that I maintain and publish (updated every 10 minutes from live Tor directory consensus) do contain the IP you reference, 2a0b:f4c1::8, so perhaps a combination of DNSEL for IPv4 and list lookup for IPv6 is the interim solution (which sucks).

I will push the changes to master in a moment, and you may need to do something to download and cache these lists so you can do an IPv6 lookup.

dapphp added a commit that referenced this issue May 3, 2020
…EL::getFingerprints(); IPv6 readiness for when the Tor DNSEL service supports IPv6
@dapphp
Copy link
Owner

dapphp commented May 3, 2020

I have to run for a bit but the new code is pushed to master (referenced in above commit).

This TorUtils library doesn't have any code for dealing with my exit lists but in the mean time feel free to check out my Wordpress plugin https://wordpress.org/plugins/vigilantor/ which has code that downloads the lists and checks (works with IPv6).

We can discuss further if you have ideas and maybe it makes sense to add a new class to this code that can check against Onionoo lists, Tor DNSEL, my exit lists, and perhaps others' too.

@melaxon
Copy link
Author

melaxon commented May 4, 2020

Check this:
onionoo call described here can help (I hope)
https://metrics.torproject.org/onionoo.html#summary

Let's say I'm interesting in this address 2a0b:f4c1::8, so I can curl to https://onionoo.torproject.org/summary?search=2a0b:f4c1::8 and receive json response containing both IPv6 I requested and corresponding IPv4. If I receive it I can conclude that this IP is from Tor network

I actually am not sure if this format https://onionoo.torproject.org/summary?search=... is documented and will be supported tomorrow

@dapphp
Copy link
Owner

dapphp commented May 4, 2020

The parameters described here are the documentation on how to use Onionoo. These have been stable for quite some time but I'm not sure this service is really suitable for real-time lookups.

For example you could shorten your search to https://onionoo.torproject.org/summary?search=2a0b:f4c1::8&fields=nickname&limit=1 (limit 1, only return 1 field). Right now I'm getting response times around 0.8 seconds looking up random IP's (some Tor some not).

Non-cached Tor DNSEL responses are at least 2.5x faster, and if you use a close & fast caching resolver they go down to virtually 0 once cached.

The mailing list post https://lists.torproject.org/pipermail/tor-project/2020-March/002759.html mentions some changes to how the Bulk Exit List is created (based on observations and not only "Exit" flags set on relays) so I'm not entirely sure what the source(s) of that list are anymore.

The fastest and more reliable way to run these checks is to download lists periodically and stoe them locally and perform lookups against these lists.As of last night I am having good luck combining https://check.torproject.org/torbulkexitlist and https://www2.openinternet.io/tor/tor-exit-list.txt and removing dupes and searching a sorted list with binary search (for speed).

@melaxon
Copy link
Author

melaxon commented May 7, 2020

Yes, you are right! Cached file is simple and fast solution. I update it each hour, I guess it is quite sufficient for practical use. If the file is not updated for a while (e.g. onionoo service ceased to exist) then the script tries to fetch from onionoo link then if failed it calls TorDNSEL.
Just wanted to notice that limit=1 (see your previous post) is not enough as such an address 2a03:e600:100::1 will match 2a03:e600:100::10, 2a03:e600:100::11, ... as well.
Thanks a lot for your help!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants