Added reverse lookup
This commit is contained in:
parent
664b36ff59
commit
d2c210df62
|
@ -1,6 +1,6 @@
|
||||||
#! /usr/bin/env python
|
#! /usr/bin/env python
|
||||||
|
|
||||||
"""Print the long name of an Internet domain.
|
"""Print mappings between country names and DNS country codes.
|
||||||
|
|
||||||
This script will take an Internet address and print out where in the
|
This script will take an Internet address and print out where in the
|
||||||
world that message originated from, based on the top-level domain code
|
world that message originated from, based on the top-level domain code
|
||||||
|
@ -10,8 +10,22 @@ found in the address. Addresses can be in any of the following forms:
|
||||||
host.domain.xx -- any Internet host or network name
|
host.domain.xx -- any Internet host or network name
|
||||||
somebody@where.xx -- an Internet email address
|
somebody@where.xx -- an Internet email address
|
||||||
|
|
||||||
|
If the country code is not recognizable, it will attempt a reverse lookup,
|
||||||
|
searching for the country name and printing a list of matching country codes.
|
||||||
|
You can force reverse mappings with the `-r' flag (see below).
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
% world tz us
|
||||||
|
tz originated from Tanzania, United Republic of
|
||||||
|
us originated from United States
|
||||||
|
|
||||||
|
% world united
|
||||||
|
|
||||||
|
|
||||||
Country codes are maintained by the RIPE Network Coordination Centre,
|
Country codes are maintained by the RIPE Network Coordination Centre,
|
||||||
in coordination with the ISO 3166 Maintenance Agency at DIN Berlin.
|
in coordination with the ISO 3166 Maintenance Agency at DIN Berlin. The
|
||||||
|
authoritative source of counry code mappings is:
|
||||||
|
|
||||||
<url:ftp://info.ripe.net/iso3166-countrycodes>
|
<url:ftp://info.ripe.net/iso3166-countrycodes>
|
||||||
|
|
||||||
|
@ -28,22 +42,33 @@ Usage: %s [-d] [-p|-P file] [-h] addr [addr ...]
|
||||||
Print mapping of all top-level domains.
|
Print mapping of all top-level domains.
|
||||||
|
|
||||||
--parse file
|
--parse file
|
||||||
--p file
|
-p file
|
||||||
--P file
|
Parse an iso3166-countrycodes file extracting the two letter country
|
||||||
--Parse file
|
code followed by the country name. Note that the three leter country
|
||||||
Parse an iso3166-countrycodes file (given as the argument).
|
code and number, which are also provided in the standard format file,
|
||||||
This first the two letter country code (it ignores the three
|
are ignored.
|
||||||
letter code), followed by the country name. With -P option,
|
|
||||||
output is in the form of a Python dictionary, and country
|
--outputdict
|
||||||
names are normalized w.r.t. capitalization. This makes it
|
-o
|
||||||
appropriate for cutting and pasting back into this file.
|
With used in conjunction with the `-p' option, output is in the form
|
||||||
|
of a Python dictionary, and country names are normalized
|
||||||
|
w.r.t. capitalization. This makes it appropriate for cutting and
|
||||||
|
pasting back into this file.
|
||||||
|
|
||||||
|
--reverse
|
||||||
|
-r
|
||||||
|
Force reverse lookup. In this mode the address can be any Python
|
||||||
|
regular expression; this is matched against all country names and a
|
||||||
|
list of matching mappings is printed. In normal mode (e.g. without
|
||||||
|
this flag), reverse lookup is performed on addresses if no matching
|
||||||
|
country code is found.
|
||||||
|
|
||||||
-h
|
-h
|
||||||
--help
|
--help
|
||||||
Print this message.
|
Print this message.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
__version__ = '2.0'
|
__version__ = '3.0'
|
||||||
__author__ = 'Barry Warsaw <bwarsaw@python.org>'
|
__author__ = 'Barry Warsaw <bwarsaw@python.org>'
|
||||||
__source__ = '<url:http://www.python.org/~bwarsaw/pyware/>'
|
__source__ = '<url:http://www.python.org/~bwarsaw/pyware/>'
|
||||||
|
|
||||||
|
@ -51,6 +76,12 @@ __source__ = '<url:http://www.python.org/~bwarsaw/pyware/>'
|
||||||
import sys
|
import sys
|
||||||
import string
|
import string
|
||||||
import getopt
|
import getopt
|
||||||
|
try:
|
||||||
|
import re
|
||||||
|
except ImportError:
|
||||||
|
print sys.argv[0], 'requires Python 1.5'
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,28 +90,48 @@ def usage(status=0):
|
||||||
sys.exit(status)
|
sys.exit(status)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def resolve(rawaddr):
|
def resolve(rawaddr):
|
||||||
parts = string.splitfields(rawaddr, '.')
|
parts = string.splitfields(rawaddr, '.')
|
||||||
if not len(parts):
|
if not len(parts):
|
||||||
print 'No top-level domain in:', rawaddr
|
# no top level domain found, bounce it to the next step
|
||||||
return
|
return rawaddr
|
||||||
addr = parts[-1]
|
addr = parts[-1]
|
||||||
if nameorg.has_key(addr):
|
if nameorgs.has_key(addr):
|
||||||
print rawaddr, 'is from a', nameorg[addr], 'organization'
|
print rawaddr, 'is from a', nameorgs[addr], 'organization'
|
||||||
elif country.has_key(addr):
|
return None
|
||||||
print rawaddr, 'originated from', country[addr]
|
elif countries.has_key(addr):
|
||||||
|
print rawaddr, 'originated from', countries[addr]
|
||||||
|
return None
|
||||||
else:
|
else:
|
||||||
print 'Where in the world is %s?' % rawaddr
|
# Not resolved, bounce it to the next step
|
||||||
|
return rawaddr
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def reverse(regexp):
|
||||||
|
matches = []
|
||||||
|
cre = re.compile(regexp, re.IGNORECASE)
|
||||||
|
for code, country in all.items():
|
||||||
|
mo = cre.search(country)
|
||||||
|
if mo:
|
||||||
|
matches.append(code)
|
||||||
|
# print results
|
||||||
|
if not matches:
|
||||||
|
# not resolved, bounce it to the next step
|
||||||
|
return regexp
|
||||||
|
if len(matches) == 1:
|
||||||
|
code = matches[0]
|
||||||
|
print regexp, "matches code `%s', %s" % (code, all[code])
|
||||||
|
else:
|
||||||
|
print regexp, 'matches %d countries:' % len(matches)
|
||||||
|
for code in matches:
|
||||||
|
print " %s: %s" % (code, all[code])
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def parse(file, normalize):
|
def parse(file, normalize):
|
||||||
try:
|
|
||||||
import re
|
|
||||||
except ImportError:
|
|
||||||
print 'Parsing requires Python 1.5'
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
fp = open(file)
|
fp = open(file)
|
||||||
except IOError, (err, msg):
|
except IOError, (err, msg):
|
||||||
|
@ -149,10 +200,12 @@ def main():
|
||||||
dump = 0
|
dump = 0
|
||||||
parsefile = None
|
parsefile = None
|
||||||
normalize = 0
|
normalize = 0
|
||||||
|
forcerev = 0
|
||||||
|
|
||||||
opts, args = getopt.getopt(sys.argv[1:],
|
opts, args = getopt.getopt(
|
||||||
'p:P:hd',
|
sys.argv[1:],
|
||||||
['parse', 'Parse', 'PARSE', 'help', 'dump'])
|
'p:rohd',
|
||||||
|
['parse', 'reverse', 'outputdict', 'help', 'dump'])
|
||||||
for arg, val in opts:
|
for arg, val in opts:
|
||||||
if arg in ('-h', '--help'):
|
if arg in ('-h', '--help'):
|
||||||
help = 1
|
help = 1
|
||||||
|
@ -160,9 +213,10 @@ def main():
|
||||||
dump = 1
|
dump = 1
|
||||||
elif arg in ('-p', '--parse'):
|
elif arg in ('-p', '--parse'):
|
||||||
parsefile = val
|
parsefile = val
|
||||||
elif arg in ('-P', '--Parse', '--PARSE'):
|
elif arg in ('-o', '--output'):
|
||||||
parsefile = val
|
|
||||||
normalize = 1
|
normalize = 1
|
||||||
|
elif arg in ('-r', '--reverse'):
|
||||||
|
forcerev = 1
|
||||||
|
|
||||||
if help:
|
if help:
|
||||||
usage(status)
|
usage(status)
|
||||||
|
@ -182,12 +236,16 @@ def main():
|
||||||
elif parsefile:
|
elif parsefile:
|
||||||
parse(parsefile, normalize)
|
parse(parsefile, normalize)
|
||||||
else:
|
else:
|
||||||
map(resolve, args)
|
if not forcerev:
|
||||||
|
args = filter(None, map(resolve, args))
|
||||||
|
args = filter(None, map(reverse, args))
|
||||||
|
for arg in args:
|
||||||
|
print 'Where in the world is %s?' % arg
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# The mappings
|
# The mappings
|
||||||
nameorg = {
|
nameorgs = {
|
||||||
"arpa": "Arpanet",
|
"arpa": "Arpanet",
|
||||||
"com": "commercial",
|
"com": "commercial",
|
||||||
"edu": "educational",
|
"edu": "educational",
|
||||||
|
@ -200,7 +258,7 @@ nameorg = {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
country = {
|
countries = {
|
||||||
"af": "Afghanistan",
|
"af": "Afghanistan",
|
||||||
"al": "Albania",
|
"al": "Albania",
|
||||||
"dz": "Algeria",
|
"dz": "Algeria",
|
||||||
|
@ -442,6 +500,9 @@ country = {
|
||||||
"zw": "Zimbabwe",
|
"zw": "Zimbabwe",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
all = nameorgs.copy()
|
||||||
|
all.update(countries)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Reference in New Issue