chiark / gitweb /
polypath: Provide Linux interface monitor
[secnet.git] / polypath-interface-monitor-linux
1 #!/usr/bin/perl -w
2 use strict;
3 use IO::Handle;
4
5 my $us = $0;
6 $us =~ s{.*/}{};
7
8 die "$us: no arguments permitted\n" if @ARGV;
9
10 our $monh;
11 our %reported;
12 # no entry: not reported, does not exist
13 # ry+: reported, entry exists
14 # r: reported, may not still exist (during processing only)
15 # y+: not reported, entry exists
16
17 my $restart;
18
19 for (;;) {
20     my $o;
21     eval {
22         if (!$monh) {
23             $monh = new IO::File;
24             open $monh, "-|", qw(ip -o monitor addr)
25                 or die "spawn monitor: $!\n";
26             sleep(1) if $restart++;
27         } else {
28             my $discard;
29             my $got = sysread $monh, $discard, 4096;
30             die "read monitor: $!\n" unless defined $got;
31             die "monitor failed\n" unless $got;
32         }
33 #use Data::Dumper;
34 #print STDERR "entering", Dumper \%reported;
35         $_='r' foreach values %reported;
36 #print STDERR "cleaned", Dumper \%reported;
37         foreach my $ip (qw(4 6)) {
38             my $addrh = new IO::File;
39             open $addrh, "-|", qw(ip -o), "-$ip", qw(addr show)
40                 or die "spawn addr $ip show: $!\n";
41             my $afstr = $ip==4 ? 'inet' : $ip==6 ? 'inet6' : die;
42             while (<$addrh>) {
43                 if (m{^\d+\:\s*(\S+)\s+$afstr\s+([0-9a-z.:]+)(?:/\d+)?\s}) {
44                     my $outline = "$ip $1 $2";
45                     $reported{$outline} .= "y";
46                 } else {
47                     chomp;
48                     warn "unexpected output from addr $ip show: $_\n";
49                 }
50             }
51             my $r = close $addrh;
52             die "addr $ip show failed $!\n" unless $r;
53             $o = '';
54         }
55 #print STDERR "acquired", Dumper \%reported;
56         foreach my $k (keys %reported) {
57             local $_ = $reported{$k};
58             if (m/^r$/) {
59                 $o .= "-$k\n";
60                 delete $reported{$k};
61             } elsif (m/^y/) {
62                 $o .= "+$k\n";
63             }
64         }
65     };
66     if ($@) {
67         print STDERR "$us: $@";
68         sleep 5;
69         next;
70     }
71     print $o or die $!;
72     STDOUT->flush or die $!;
73 }