From: Anders Kaseorg Date: Sun, 25 Apr 2010 02:27:46 +0000 (-0400) Subject: Initial commit of routeradvert-scan. X-Git-Url: http://andersk.mit.edu/gitweb/routeradvert-scan.git/commitdiff_plain/cde4019ac2e7acfb981cae4a85a1fc7e2f23dd3a Initial commit of routeradvert-scan. Signed-off-by: Anders Kaseorg --- cde4019ac2e7acfb981cae4a85a1fc7e2f23dd3a diff --git a/routeradvert-scan.py b/routeradvert-scan.py new file mode 100755 index 0000000..c499484 --- /dev/null +++ b/routeradvert-scan.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# routeradvert-scan.py: Scan for rogue IPv6 router advertisements. +# +# Copyright © 2010 Anders Kaseorg +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the “Software”), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import errno +import math +import os +import re +import signal +import socket +import subprocess +import sys +import time + +# configuration +interface = 'eth1' +timeout = 30 +zclass = 'andersk-auto' +zinstance = '6to4' +zsig = '%s on %s' % (sys.argv[0], socket.gethostname()) +# end configuration + +mac_re = re.compile(r'^(?:[0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$') + +seen_macs = {} + +def msg(m): + os.spawnlp(os.P_WAIT, 'zwrite', 'zwrite', '-q', '-d', '-c', zclass, '-i', zinstance, '-s', zsig, '-m', m) + +def check_gone(): + now = time.time() + next = None + for (mac, t) in seen_macs.items(): + if t < now: + del seen_macs[mac] + msg('Gone 6to4 router: %s\nCurrent 6to4 routers: %s' % (mac, seen_macs.keys())) + elif next is None or next > t: + next = t + if next is None: + signal.alarm(0) + else: + signal.alarm(int(math.ceil(next - now))) + +signal.signal(signal.SIGALRM, lambda signum, frame: check_gone()) + +p = subprocess.Popen(['tcpdump', '-elnp', '-i', interface, 'icmp6 and (ip6[40] = 134)'], stdout=subprocess.PIPE) +while True: + check_gone() + while True: + try: + line = p.stdout.readline() + except IOError, (e, s): + if e == errno.EINTR: + continue + break + signal.alarm(0) + if line == '': + break + words = line.split() + if len(words) >= 2 and mac_re.match(words[1]): + mac = words[1] + t = time.time() + timeout + if mac in seen_macs: + seen_macs[mac] = t + else: + seen_macs[mac] = t + msg('New 6to4 router: %s\n%s\nCurrent 6to4 routers: %s' % (mac, line.rstrip('\n'), seen_macs.keys())) + else: + print >>sys.stderr, 'Unrecognized line: ', line.rstrip('\n')