Author: arma Date: 2013-08-09 15:24:27 +0000 (Fri, 09 Aug 2013) New Revision: 26291
Added: check/trunk/cgi-bin/TorCheck-off.py Log: fork torcheck to make a (much faster) version that doesn't actually check
Copied: check/trunk/cgi-bin/TorCheck-off.py (from rev 26290, check/trunk/cgi-bin/TorCheck.py) =================================================================== --- check/trunk/cgi-bin/TorCheck-off.py (rev 0) +++ check/trunk/cgi-bin/TorCheck-off.py 2013-08-09 15:24:27 UTC (rev 26291) @@ -0,0 +1,351 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +""" + TorCheck.py + + https://check.torproject.org - originally in perl, rewritten in python + + By Jacob Appelbaum jacob@appelbaum.net + Written at ToorCon Seattle 2008 (Thanks for the great time h1kari!) + Thanks to Crispen for a power outlet :-) + + Additional python suggestions from nickm + + Best used with the Debian packages: + python-dns + libapache2-mod-python + locales-all + +""" + +__program__ = 'TorCheck.py' +__version__ = '20100429.01' +__url__ = 'https://svn.torproject.org/svn/check/' +__author__ = 'Jacob Appelbaum jacob@appelbaum.net' +__copyright__ = 'Copyright (c) 2008, Jacob Appelbaum' +__license__ = 'See LICENSE for licensing information' + +try: + from future import antigravity +except ImportError: + antigravity = None + +import cgi +import DNS +from DNS import DNSError +# This is pydns and can be downloaded from http://pydns.sourceforge.net/ +# Or use the Debian package listed above +import cgitb; cgitb.enable() +import gettext +import locale +import os + +#os.environ['LOCPATH']='/usr/share/locale:/srv/check.torproject.org/trunk/i18n/locale' +localedir ='/srv/check.torproject.org/trunk/i18n/locale' + +# We could also explictly query the remote EL server +# This is not as good as using a cache for obvious reasons +DNS.DiscoverNameServers() + +def isUsingTor(clientIp, ELPort): + # This is the exit node ip address + # This is where we want to dynamically recieve this from Apache + splitIp = clientIp.split('.') + splitIp.reverse() + ELExitNode = ".".join(splitIp) + + # We'll attempt to reach this port on the Target host + # ELPort is now set by the caller + + # We'll try to reach this host + ElTarget = "38.229.70.31" + + # This is the ExitList DNS server we want to query + ELHost = "ip-port.exitlist.torproject.org" + + # Prepare the question as an A record request + ELQuestion = ELExitNode + "." + ELPort + "." + ElTarget + "." + ELHost + request = DNS.DnsRequest(name=ELQuestion,qtype='A') + + # Ask the question and load the data into our answer + try: + answer=request.req() + except DNSError: + return 2 + + # Parse the answer and decide if it's allowing exits + # 127.0.0.2 is an exit and NXDOMAIN is not + if answer.header['status'] == "NXDOMAIN": + # We're not exiting from a Tor exit + return 1 + else: + if not answer.answers: + # We're getting unexpected data - fail closed + return 2 + for a in answer.answers: + if a['data'] != "127.0.0.2": + return 2 + # If we're here, we've had a positive exit answer + return 0 + + +def isUpToDate(queryString): + """ + determine if TBB is aware of newer versions + """ + if 'uptodate=1' in queryString.lower(): + return True + if 'uptodate=0' in queryString.lower(): + return False + # This will be true until Torbutton 1.4.4 is released + if 'small=1' in queryString.lower(): + return False + + # The default case; No update information to provide + return True + + +def getLocales(): + locale_descriptions = { + 'ar' : 'عربية (Arabiya)', + 'bms' : 'Burmese', + 'cs' : 'česky', + 'da' : 'dansk', + 'de' : 'Deutsch', + 'el' : 'Ελληνικά (Ellinika)', + 'en_US' : 'English', + 'es' : 'español', + 'et' : 'Estonian', + 'fa_IR' : 'فارسی (Fārsī)', + 'fr' : 'français', + 'it_IT' : 'Italiano', + 'ja' : '日本語 (Nihongo)', + 'nb' : 'norsk (bokmål)', + 'nl' : 'Nederlands', + 'pl' : 'polski', + 'pt' : 'Português', + 'pt_BR' : 'Português do Brasil', + 'ro' : 'română', + 'fi' : 'suomi', + 'ru' : 'Русский (Russkij)', + 'th' : 'Thai', + 'tr' : 'Türkçe', + 'uk' : 'українська (ukrajins'ka)', + 'vi' : 'Vietnamese', + 'zh_CN' : '中文(简)' } + return locale_descriptions + +def getLocaleName(lang): + # If the user passes in a locale that matches what we support, good + # However, anything that we don't support will result in us using a default locale + # + # Important! lang is tainted data, don't forget this! + # + + default_locale = "en_US" + + # We'd really like these additional locales to be translated: + # locales = ( 'ar', 'fr', 'nl', 'pt-PT', 'ru' ) + + # Make sure we have a valid language + if not lang: + return default_locale + + # This is to deal with Mozilla and Debian having different ideas about + # what it means to be a locale + lang = lang.replace("-", "_") + + # Do a case insensitive match + lang = lang.lower() + + # Check for an exact match of language_country + for item in getLocales().keys(): + if item.lower() == lang: + return item + + # Check for just the language + lang = lang.split("_", 1)[0] + for item in getLocales().keys(): + if item.lower().startswith(lang): + return item + + # Fall back to default + return default_locale + +def showLogo(formSubmission): + # By default, we'll show a logo + show_logo = True + hide_logo = formSubmission.getfirst("small", None) + # hide_logo isn't cleaned - do not use it for anything else + if hide_logo: + return False + return show_logo + +def parseLang(formSubmission): + user_supplied_lang = formSubmission.getfirst("lang", None) + + # Find the best match for the requested language + locale = getLocaleName(user_supplied_lang) + + # i18n with Unicode! + # Ensure you have properly installed TorCheck.{po,pot,mo} files + lang = gettext.translation('TorCheck', localedir=localedir, languages=[locale], fallback=True) + lang.install() + +def printTorButton(req, UsingTor): + req.write('<html xmlns="http://www.w3.org/1999/xhtml"><body>') + if UsingTor == 0: + req.write('<a id="TorCheckResult" target="success" href="/"></a>') + elif UsingTor == 1: + req.write('<a id="TorCheckResult" target="failure" href="/"></a>\n') + else: + req.write('<a id="TorCheckResult" target="unknown" href="/"></a>\n') + req.write('</body></html>') + +# Now that we know everything we need, lets print the website +def handler(req, environ, start_response): + # Make a DNS request to the EL and decide what to tell the user + UsingTor = isUsingTor(environ['REMOTE_ADDR'], "80") + # Try to hit a cornercase where the user can exit to 443 but not 80 + if UsingTor != 0: + UsingTor = isUsingTor(environ['REMOTE_ADDR'], "443") + + # figure out if the client passed uptodate=0 or uptodate=1 + # defaults to 1 if uptodate was not present in the query string + UpToDate = isUpToDate(environ['QUERY_STRING']) + + response_headers = [('Content-type', 'text/html; charset=utf-8')] + start_response('200 OK', response_headers) + + # We want to catch TorButton queries so they don't output overhead + # This is to make all the data fit into one cell + formSubmission = cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ) + if formSubmission.getfirst("TorButton", None): + printTorButton(req, UsingTor) + return + + # First lets construct the simple webpage: + req.write('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" '\ + '"http://www.w3.org/TR/REC-html40/loose.dtd">\n') + req.write('<html>\n') + req.write('<head>\n') + req.write('<meta http-equiv="content-type" content="text/html; '\ + 'charset=utf-8">\n') + req.write('<title>Are you using Tor?</title>\n') + req.write('<link rel="shortcut icon" type="image/x-icon" '\ + 'href="./favicon.ico">\n') + req.write('<style type="text/css">\n') + req.write('img,acronym {\n') + req.write(' border: 0;') + req.write(' text-decoration: none;') + req.write('}') + req.write('</style>') + req.write('</head>\n') + req.write('<body>\n') + + parseLang(formSubmission) + hideLogo = showLogo(formSubmission) + + req.write('<center>\n') + + if UsingTor == 0: + if UpToDate: + req.write('\n') + if hideLogo: + req.write('<img alt="' + _("Congratulations. Your browser is configured to use Tor.") + \ + '" src="/images/tor-on.png">\n<br>') + req.write('<h1 style="color: #0A0">\n') + req.write(_('Congratulations. Your browser is configured to use Tor.')) + req.write('<br>\n<br>\n') + req.write('</h1>\n') + req.write(_('Please refer to the <a href="https://www.torproject.org/">Tor website</a> for further information about using Tor safely. You are now free to browse the Internet anonymously.')) + req.write('<br>\n<br>\n') + else: + req.write('\n') + if hideLogo: + req.write('<img alt="' + _("Congratulations. Your browser is configured to use Tor.") + \ + '" src="/images/tor-on.png">\n<br>') + req.write('<h1 style="color: #0A0">\n') + req.write(_('Congratulations. Your browser is configured to use Tor.')) + req.write('<br>\n<br>\n') + req.write('</h1>\n') + req.write('<h1 style="color: #FA0">\n') + req.write(_('There is a security update available for the Tor Browser Bundle.')) + req.write('<br>\n<br>\n') + req.write(_('<a href="https://www.torproject.org/download/download-easy.html">Click here to go to the download page</a>')) + req.write('<br>\n<br>\n') + req.write('</h1>\n') + req.write(_('Please refer to the <a href="https://www.torproject.org/">Tor website</a> for further information about using Tor safely. You are now free to browse the Internet anonymously.')) + req.write('<br>\n<br>\n') + + # This is the case where we have an NXDOMAIN and they aren't using Tor + elif UsingTor == 1: + req.write('\n') + if hideLogo: + req.write('<img alt="' + _("Sorry. You are not using Tor.") + '" '\ + 'src="/images/tor-off.png">\n<br>') + req.write('<h1 style="color: #A00">') + req.write(_('Sorry. You are not using Tor.')) + req.write('<br>\n<br>\n') + req.write('</h1>') + req.write(_('If you are attempting to use a Tor client, please refer to the <a href="https://www.torproject.org/">Tor website</a> and specifically the <a href="https://www.torproject.org/docs/faq#DoesntWork">instructions for configuring your Tor client</a>.')) + req.write('<br>\n<br>\n') + + # This means we have some strange data response we don't understand + # It's better that we fail closed and let the user know everything went wrong + elif UsingTor == 2: + req.write('\n') + req.write('<img alt="' + _("Sorry, your query failed or an unexpected response was received.") + '" '\ + 'src="/images/tor-off.png">\n<br>') + req.write('<h1 style="color: #A00">\n') + req.write(_('Sorry, your query failed or an unexpected response was received.')) + req.write('<br>\n') + req.write('</h1>') + req.write(_('A temporary service outage prevents us from determining if your source IP address is a <a href="https://www.torproject.org/">Tor</a> node.')) + req.write('<br>\n<br>\n') + + # Now we'll close up this html rat hole + req.write('\n') + req.write('<br>\n'); + req.write(_('Your IP address appears to be: ')) + req.write('<b>%s</b><br>\n' % environ['REMOTE_ADDR'] ) + req.write('<small>\n') + req.write('<tt>') +# req.write(_('Additional information: ')) +# req.write('<br>\n') +# req.write(_('This small script is powered by <a href="http://exitlist.torproject.org/">tordnsel</a>')) +# req.write('<br>') +# req.write(_('You may also be interested in the <a href="/cgi-bin/TorBulkExitList.py">Tor Bulk Exit List Exporter</a>')) +# req.write('<br><br>') +# req.write(_('This server does not log <i>any</i> information about visitors.')) + req.write('<br>\n<br>\n') + # We want to display little pretty images so users can choose their language + locales = getLocales() + + req.write('<p>This page is also available in the following languages:') + req.write('</p><p>') + for item in sorted(locales.keys()): + req.write('<a href="?lang=%s" ' % item ) + req.write('hreflang="%s" ' % item ) + req.write('lang="%s" rel="alternate">' % item ) + req.write('%s</a> ' % locales[item] ) + req.write('</p>') + req.write('</tt>') + req.write('</small>') + req.write('</center>\n') + req.write('</body>') + req.write('</html>') + + +class FakeReq(list): + def write(self, str): + self.append(str) + +def application(environ, start_response): + req = FakeReq() + handler(req, environ, start_response) + return req + +# vim:set ts=4: +# vim:set et: +# vim:set shiftwidth=4:
tor-commits@lists.torproject.org