Permalink
Browse files

Initial public release

  • Loading branch information...
1 parent 208d7fd commit cac72833c53ccd14bae5737d006dc87201dbf5f5 @ioerror committed Dec 25, 2009
Showing with 279 additions and 0 deletions.
  1. +3 −0 CHANGELOG
  2. +20 −0 LICENSE
  3. +21 −0 README
  4. +17 −0 TODO
  5. +218 −0 blockfinder
View
@@ -0,0 +1,3 @@
+Changes in version 3.1 - 2009-12-25
+ o Initial public release
+ - Published on github
View
20 LICENSE
@@ -0,0 +1,20 @@
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
View
21 README
@@ -0,0 +1,21 @@
+blockfinder by Jacob Appelbaum <jacob@appelbaum.net>
+
+This is a simple tool that returns a list of netblocks for a given country.
+It does this by fetching the following lists of allocations:
+
+ ftp://ftp.arin.net/pub/stats/arin/delegated-arin-latest
+ ftp://ftp.ripe.net/ripe/stats/delegated-ripencc-latest
+ ftp://ftp.afrinic.net/pub/stats/afrinic/delegated-afrinic-latest
+ ftp://ftp.apnic.net/pub/stats/apnic/delegated-apnic-latest
+ ftp://ftp.lacnic.net/pub/stats/lacnic/delegated-lacnic-latest
+
+The list of ISO codes is ISO 3166-1 as found here:
+
+ http://www.iso.org/iso/list-en1-semic-3.txt
+ http://en.wikipedia.org/wiki/ISO_3166-1
+
+blockfinder has two methods of operation:
+
+ Update the lists of network object allocations
+ Returning a list of all netblocks (or asn, etc) for a given country
+
View
17 TODO
@@ -0,0 +1,17 @@
+Add GeoIP support
+ Include the free database (and an update feature)
+ Optionally allow for an arbitrary custom database
+Add geoip database inversion
+ Optionally combine the results with delegation information to produce more
+ accurate netblocks
+Add country name support
+ eg: "Burma" or "mm"
+Add support to list all country codes with possible results
+Add support for proxies during updating/fetching
+Add support for a custom "User Agent:" during updating/fetching
+Add usage information
+Add CIDR information for all returned netblocks
+
+Refactor the argument parsing to make it reasonable
+ Required arguments should be postional, etc
+Refactor updating/fetching animation
View
@@ -0,0 +1,218 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# For the people of Smubworld!
+#
+import urllib2
+import os
+import time
+import getopt
+import sys
+
+__program__ = 'blockfinder'
+__url__ = 'http://github.com/ioerror/blockfinder/'
+__author__ = 'Jacob Appelbaum <jacob@appelbaum.net>'
+__copyright__ = 'Copyright (c) 2009'
+__license__ = 'See LICENSE for licensing information'
+__version__ = '3.1'
+
+try:
+ from future import antigravity
+except ImportError:
+ antigravity = None
+
+verbose = False
+
+# XXX TODO: Set the user agent and allow the use of a proxy
+# Set up a proper Request object, set the user agent and if desired, a proxy
+def fetch_delegation(delegation_url):
+ rows, columns = os.popen('stty size', 'r').read().split()
+ fetcher = urllib2.urlopen(delegation_url)
+ length = int(fetcher.headers.get("content-length"))
+ print "Fetching " + str(length) + " bytes"
+ chunk = int(int(length)/(int(columns) -4))
+ counter = 0
+ page = ""
+ # XXX TODO: we need to redraw the screen entirely, each run
+ # XXX TODO: Currently, if the user changes the screen, we draw incorrectly
+ sys.stdout.write("[" + "." * (int(columns) - 2) + "]")
+ sys.stdout.flush()
+ sys.stdout.write('\b' * (int(columns) - 2))
+ while 1:
+ page += fetcher.read(chunk)
+ counter += chunk
+ sys.stdout.write('\b')
+ sys.stdout.write("=")
+ sys.stdout.write(">")
+ sys.stdout.flush()
+ if counter >= length:
+ sys.stdout.write('\n')
+ sys.stdout.flush()
+ break
+ if length == len(page):
+ return page
+ else:
+ print "We're having an error fetching the right number of bytes!"
+ return page
+
+def cache_delegation(delegation_url, cache_dir):
+ try:
+ delegation = ""
+ print "Fetching " + delegation_url
+ delegation = fetch_delegation(delegation_url)
+ tmp = delegation_url.split('/')
+ delegation_file = str(cache_dir) + str(tmp[-1])
+ f = open(delegation_file, 'w')
+ f.write(delegation)
+ f.close()
+ except:
+ print "Unable to fetch or cache delegation"
+
+# This returns true of the cache is older than 24 hours
+def cache_age_check(cache_dir, cached_files):
+ for file in cached_files.split(","):
+ fstat = os.stat(cache_dir + file)
+ if (time.time() - fstat.st_ctime) > 86400:
+ return True
+
+def update_delegation_cache(delegation_urls, cache_dir):
+ print "Updating delegation cache"
+ for url in delegation_urls.split():
+ try:
+ cache_delegation(url, cache_dir)
+ except:
+ print "Unable to update delegation for " + url
+
+def load_delegation(delegation_file):
+ keys = "rir,cc,type,n,nn,asn,status"
+ try:
+ os.stat(delegation_file)
+ f = open(delegation_file, "r")
+ # if not line.startswith("#"):
+ delegations = [ dict((k,v) for k,v in zip(keys.split(","), line.split("|")))
+ for line in f.readlines()if not line.startswith("#")]
+ return delegations
+ except:
+ print "It appears that we are missing " + delegation_file
+
+def load_all_delegations(cache_dir, delegation_urls):
+ delegations = []
+ if verbose:
+ print "Attempting to load the following urls: \n" + delegation_urls
+ for url in delegation_urls.split():
+ filename = url.rpartition('/')
+ if verbose:
+ print "Attempting to load delegation file: " + filename[-1]
+ delegations.append(load_delegation(cache_dir + filename[-1]))
+ return delegations
+
+def lookup_country(cc, delegation):
+ return [d for d in delegation if d['cc'] == cc]
+
+def lookup_type(type, delegation):
+ return [d for d in delegation if d['type'] == type]
+
+def usage():
+ print >> sys.stderr, "rtfm?"
+
+def main():
+ try:
+ opts, args = getopt.getopt(sys.argv[1:],
+ "vhc:u:pso:46at:i",
+ ["verbose", "help", "cachedir=", "useragent=", "progress",
+ "silent", "output=", "ipv4", "ipv6", "asn", "country=",
+ "initialize-delegation"])
+ except getopt.GetoptError, err:
+ print str(err)
+ usage()
+ sys.exit(2)
+
+ output = None
+ verbose = False
+ silent = True
+ cache_dir = "/var/tmp/delegation-data/"
+ update_delegations = False
+ delegation_urls="""
+ ftp://ftp.arin.net/pub/stats/arin/delegated-arin-latest
+ ftp://ftp.ripe.net/ripe/stats/delegated-ripencc-latest
+ ftp://ftp.afrinic.net/pub/stats/afrinic/delegated-afrinic-latest
+ ftp://ftp.apnic.net/pub/stats/apnic/delegated-apnic-latest
+ ftp://ftp.lacnic.net/pub/stats/lacnic/delegated-lacnic-latest
+ """
+ delegation_files=""
+ for url in delegation_urls.split():
+ filename = url.rpartition('/')
+ delegation_files += filename[-1] + ","
+ delegation_fmt="rir,cc,type,n,nn,asn,status"
+ iso_codes="http://www.iso.org/iso/list-en1-semic-3.txt"
+ user_agent = "blockfinder"
+ update_delegations = False
+ requests = []
+ country = ""
+ for o, a in opts:
+ if o == "-v":
+ verbose = True
+ elif o in ("-h", "--help"):
+ usage()
+ sys.exit()
+ elif o in ("-c", "--cachedir"):
+ cache_dir = a
+ elif o in ("-u", "--useragent"):
+ pass
+ elif o in ("-p", "--progress"):
+ progress = True
+ elif o in ("-s", "--silent"):
+ silent = True
+ elif o in ("-o", "--output"):
+ output = a
+ elif o in ("-4", "--ipv4"):
+ requests.append("ipv4")
+ elif o in ("-6", "--ipv6"):
+ requests.append("ipv6")
+ elif o in ("-a", "--asn"):
+ requests.append("asn")
+ # XXX TODO: This should be a positional argument as it's the only manditory one...
+ elif o in ("-t", "--nation-state"):
+ country = a.upper()
+ elif o in ("-i", "--initialize-delegations"):
+ update_delegations = True
+ else:
+ assert False, "Unhandled option; Sorry!"
+
+ # Update and quit of requested
+ if update_delegations:
+ update_delegation_cache(delegation_urls, cache_dir)
+ sys.exit(0)
+ if not requests:
+ print "Nothing to do. Have you requested anything?"
+ sys.exit(1)
+ # Check our cache age and warn if it's aged
+ total_delegations = 0
+ if cache_age_check(cache_dir, delegation_files) and verbose:
+ print "Your delegation cache is older than 24 hours; you probably want to update it."
+ delegations = load_all_delegations(cache_dir, delegation_urls)
+ for delegation in delegations:
+ total_delegations += len(delegation)
+ if verbose:
+ print "We have %d entries in our delegation cache." % total_delegations
+ tmp = []
+ resultnum = 0
+ matchnum = 0
+ for delegation in delegations:
+ try:
+ results = lookup_country(country, delegation)
+ resultnum += len(results)
+ for result in results:
+ for request in requests:
+ if result['type'] == request:
+ matchnum += 1
+ print result['n']
+ except:
+ print sys.exc_info()
+ pass
+ if verbose:
+ print "We found approx possible %d entries in our delegation cache." % resultnum
+ print "We found %d matching entries in our delegation cache." % matchnum
+
+if __name__ == "__main__":
+ main()

0 comments on commit cac7283

Please sign in to comment.