#!/usr/bin/perl -w ## ## This script was developed to be used against people who broadcast ## unwanted router advertisements from their 6to4-enabled IPv6 hosts. ## We identify 6to4 prefixes and the associated routers, and remove ## them after logging the IPv4 and MAC addresses corresponding to the ## perpetrators. ## use strict; sub find_2002_announcers (); sub diagnose_ipv4 ($ ); my @announcers = find_2002_announcers (); foreach my $announcer (@announcers) { my ($ipv6, $ipv4, $dev) = @{$announcer}; warn "IPv4 address: $ipv4\n"; my ($mac, $ll) = diagnose_ipv4 ($ipv4); system ("/sbin/ip", "-6", "addr", "del", $ipv6."/64", "dev", $dev); if (defined $ll) { warn "LL: $ll\n"; system ("/sbin/ip", "-6", "route", "del", "default", "dev", $dev, "via", $ll); system ("/sbin/ip6tables", "-A", "INPUT", "-s", $ll, "--protocol", "ipv6-icmp", "--icmpv6-type", "router-advertisement", "-j", "DROP"); } } 1; sub find_2002_announcers () { my @result = (); my $dev; open (IPAL, "/sbin/ip -6 a l|") or die "cannot start ip -6 a l: $!"; while () { if (/^(\d+): ([^:]+):/) { $dev = $2; } else { next unless /^\s*inet6 (2002:[0-9a-f:]+)\/64 scope global dynamic\s*$/; my ($addr) = ($1); warn "found 6to4 address: $addr\n"; my ($ipv4_h, $ipv4_l) = ($addr =~ /2002:([0-9a-f]*):([0-9a-f]*):.*/) or die "malformed 6to4 address $addr\n"; $ipv4_h = hex $ipv4_h; $ipv4_l = hex $ipv4_l; my $ipv4 = join (".", (unpack ("CC", pack ("n", $ipv4_h)), unpack ("CC", pack ("n", $ipv4_l)))); push @result, [$addr, $ipv4, $dev]; } } close IPAL or die "ip -6 a l: $!"; return @result; } sub diagnose_ipv4 ($ ) { my ($ipv4) = @_; my ($mac, $eui64, $ll); # system "ping", "-c", "1", "$ipv4"; system "ping -c 1 $ipv4 >/dev/null"; open (ARP, "/sbin/ip neigh show to $ipv4|") or die "arp: $!"; while () { my $mac; next unless ($mac) = /^$ipv4 dev .* lladdr ([0-9a-f:]+) .*$/; warn "$ipv4: $mac\n"; # # We should go one step further and find the corresponding # EUI-64 address, and then the corresponding link-local address, # so that we can explicitly get rid of the bogus default route. # # e.g. $mac == "00:0c:f1:34:45:c0" # -> EUI-64 == "20c:f1ff:fe34:45c0" # -> link-local == "fe80::20c:f1ff:fe34:45c0" # my @mac_octets = map hex, split (":", $mac); my @eui64_octets = ($mac_octets[0] ^ 0x02, @mac_octets[1..2], 0xff, 0xfe, @mac_octets[3..5]); $mac = pack ("CCCCCC", @mac_octets); $ll = sprintf ("fe80::%x:%x:%x:%x", unpack ("nnnn", pack ("CCCCCCCC", @eui64_octets))); } close ARP or die "arp: $!"; return ($mac, $ll); }