├── README.md ├── getlocation.py └── requirements.txt /README.md: -------------------------------------------------------------------------------- 1 | # ip-location-map 2 | 3 | Here are some python scripts you can use to plot ip-addresses on a map 4 | 5 | If you don't have a non-free email account and can't get an API key, see the [freegeoip branch](https://github.com/tuxmascot/ip-location-map/tree/freegeoip). 6 | 7 | ### Dependencies: 8 | 9 | * [matplotlib basemap](http://matplotlib.org/basemap/) 10 | * [pyipinfodb](https://github.com/mossberg/pyipinfodb) 11 | 12 | 13 | You can install pyipinfodb very easily with the requirements.txt file: 14 | 15 | pip install -r requirements.txt 16 | 17 | This will satisfy the pyipinfodb dependency, but, as of the current release, you will still need to install matplotlib basemap manually. 18 | 19 | ### Short usage guide: 20 | 21 | * First, you need to get an API key for [ipinfodb](http://ipinfodb.com/) 22 | 23 | * Put your IP-addresses in a file called **ips.txt**, with one IP on each line. (Note: only tested with IPv4) 24 | 25 | * Run the **getlocation.py** script, like so: `python getlocation.py < ips.txt > geo.txt` It will create a file called **geo.txt**, which contains coordinates on each line. 26 | 27 | * Finally, run the **generatemap.py** script, like so: `python generatemap.py < geo.txt` It will create an image file called map.png. 28 | 29 | You can play around with the settings in **generatemap.py**, to use different map projections, different colors and so on. 30 | 31 | 32 | I used this to plot refused SSH connections on my linux machine. I used the following command to fill ips.txt: 33 | 34 | grep "refused" /var/log/auth.log | awk '{ print $9 }' | sort | uniq > ips.txt 35 | 36 | You can also run the whole process as a single pipeline: 37 | 38 | grep "refused" /var/log/auth.log | awk '{ print $9 }' | sort | uniq | python getlocation.py | python generatemap.py 39 | 40 | Note that I grep for lines with "refused". These are connections refused because of rules in /etc/hosts.deny and /etc/hosts.allow. You may need to change the command to suit your configuration. 41 | -------------------------------------------------------------------------------- /getlocation.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | from argparse import ArgumentParser 4 | from contextlib import contextmanager 5 | from pyipinfodb import pyipinfodb 6 | from mpl_toolkits.basemap import Basemap 7 | import matplotlib.pyplot as plt 8 | from sys import stdin, stdout, stderr 9 | import numpy as np 10 | 11 | 12 | def plot_locations(locations, output_filename): 13 | ip_map = Basemap(projection='robin', lon_0=0, resolution='c') 14 | 15 | for line in locations: 16 | srclong, srclat = map(float, line.split(',')) 17 | x, y = ip_map(srclong, srclat) 18 | plt.plot(x,y, 'o', color='#ff0000', ms=2.7, markeredgewidth=0.5) 19 | 20 | 21 | ip_map.drawcountries(color='#ffffff') 22 | ip_map.fillcontinents(color='#cccccc',lake_color='#ffffff') 23 | 24 | plt.savefig(output_filename, dpi=600) 25 | 26 | def memoize(func): 27 | ''' 28 | Decorator for a function which caches results. Based on 29 | http://code.activestate.com/recipes/578231-probably-the-fastest-memoization-decorator-in-the-/ 30 | ''' 31 | class memodict(dict): 32 | def __missing__(self, key): 33 | ret = self[key] = func(*key) 34 | return ret 35 | def __call__(self, *args): 36 | return self[args] 37 | 38 | return memodict() 39 | 40 | 41 | @memoize 42 | def get_location(ip_lookup, ip): 43 | print('Getting location for', ip, file=stderr) 44 | ip_data = ip_lookup.get_city(ip) 45 | yield ip_data['longitude'], ip_data['latitude'] 46 | 47 | 48 | @contextmanager 49 | def smart_open(file_or_filename, *args, **kwargs): 50 | try: 51 | f = open(file_or_filename, *args, **kwargs) 52 | except TypeError: 53 | yield file_or_filename 54 | else: 55 | with f: 56 | yield f 57 | 58 | 59 | def main(): 60 | parser = ArgumentParser() 61 | parser.add_argument('--input', '-i', default=stdin) 62 | parser.add_argument('--output', '-o', default=stdout) 63 | parser.add_argument('--gen-map', '-G', action='store_true') 64 | parser.add_argument('API_KEY') 65 | args = parser.parse_args() 66 | 67 | ip_lookup = pyipinfodb.IPInfo(args.API_KEY) 68 | 69 | with smart_open(args.input) as istr: 70 | with smart_open(args.output, 'w') as ostr: 71 | if args.gen_map: 72 | for ip in istr: 73 | plot_locations(*(get_location(ip_lookup, ip), "ip_map.png")) 74 | else: 75 | for ip in istr: 76 | print(*get_location(ip_lookup, ip), sep=",", file=ostr) 77 | 78 | if __name__ == '__main__': 79 | main() 80 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | -e git+git://github.com/markmossberg/pyipinfodb.git#egg=pyipinfodb 2 | --------------------------------------------------------------------------------