]> andersk Git - routeradvert-scan.git/blame - routeradvert-scan.py
Move to -c rcc-auto.
[routeradvert-scan.git] / routeradvert-scan.py
CommitLineData
cde4019a
AK
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# routeradvert-scan.py: Scan for rogue IPv6 router advertisements.
5#
6# Copyright © 2010 Anders Kaseorg <andersk@mit.edu>
7#
8# Permission is hereby granted, free of charge, to any person
9# obtaining a copy of this software and associated documentation files
10# (the “Software”), to deal in the Software without restriction,
11# including without limitation the rights to use, copy, modify, merge,
12# publish, distribute, sublicense, and/or sell copies of the Software,
13# and to permit persons to whom the Software is furnished to do so,
14# subject to the following conditions:
15#
16# The above copyright notice and this permission notice shall be
17# included in all copies or substantial portions of the Software.
18#
19# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
20# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26# SOFTWARE.
27
cb363a3e 28import BeautifulSoup
cde4019a
AK
29import errno
30import math
cb363a3e 31import mechanize
cde4019a
AK
32import os
33import re
34import signal
35import socket
36import subprocess
37import sys
38import time
cb363a3e 39import urllib
cde4019a
AK
40
41# configuration
42interface = 'eth1'
599d33b8
AK
43timeout = 120
44zclass = 'rcc-auto'
cde4019a
AK
45zinstance = '6to4'
46zsig = '%s on %s' % (sys.argv[0], socket.gethostname())
599d33b8 47cert_file = os.path.join(os.path.dirname(__file__), 'sipbcert.pem')
cde4019a
AK
48# end configuration
49
50mac_re = re.compile(r'^(?:[0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$')
51
52seen_macs = {}
53
54def msg(m):
599d33b8 55 os.spawnlp(os.P_WAIT, 'zwrite', 'zwrite', '-q', '-d', '-c', zclass, '-i', zinstance, '-s', zsig, '-O', 'auto', '-m', m)
cde4019a 56
cb363a3e
AK
57br = mechanize.Browser()
58br.add_client_certificate("https://nic.mit.edu", cert_file, cert_file)
59
60def get_owner(mac):
61 for lookup in ('host', 'less'):
62 try:
63 data = urllib.urlencode({
64 'action': 'Lookup Host',
65 'lookup': lookup,
66 'mac': mac
67 })
68 br.open('https://nic.mit.edu/bin/dynareg',
69 data)
70 soup = BeautifulSoup.BeautifulSoup(br.response().read())
71 for tag in soup.findAll('td'):
72 if tag.string == 'owner:':
73 return tag.nextSibling.string or \
74 tag.nextSibling.contents[0]['value']
75 except:
76 pass
77 return None
78
79def show_mac(mac, (t, owner)):
80 return '%s (%s)' % (mac, 'unknown owner' if owner is None else owner)
81
82def show_macs():
83 return ', '.join(show_mac(mac, v) for mac, v in seen_macs.iteritems())
84
cde4019a
AK
85def check_gone():
86 now = time.time()
87 next = None
cb363a3e 88 for (mac, (t, owner)) in seen_macs.items():
cde4019a
AK
89 if t < now:
90 del seen_macs[mac]
cb363a3e
AK
91 msg('Gone 6to4 router: %s\nCurrent 6to4 routers: %s' %
92 (show_mac(mac, (t, owner)), show_macs()))
cde4019a
AK
93 elif next is None or next > t:
94 next = t
95 if next is None:
96 signal.alarm(0)
97 else:
98 signal.alarm(int(math.ceil(next - now)))
99
100signal.signal(signal.SIGALRM, lambda signum, frame: check_gone())
101
102p = subprocess.Popen(['tcpdump', '-elnp', '-i', interface, 'icmp6 and (ip6[40] = 134)'], stdout=subprocess.PIPE)
103while True:
104 check_gone()
105 while True:
106 try:
107 line = p.stdout.readline()
108 except IOError, (e, s):
109 if e == errno.EINTR:
110 continue
111 break
112 signal.alarm(0)
113 if line == '':
114 break
115 words = line.split()
116 if len(words) >= 2 and mac_re.match(words[1]):
117 mac = words[1]
118 t = time.time() + timeout
119 if mac in seen_macs:
cb363a3e 120 seen_macs[mac][0] = t
cde4019a 121 else:
cb363a3e
AK
122 seen_macs[mac] = [t, get_owner(mac)]
123 msg('New 6to4 router: %s\n%s\nCurrent 6to4 routers: %s' %
124 (show_mac(mac, seen_macs[mac]),
125 line.rstrip('\n'),
126 show_macs()))
cde4019a
AK
127 else:
128 print >>sys.stderr, 'Unrecognized line: ', line.rstrip('\n')
This page took 0.841228 seconds and 5 git commands to generate.