chiark / gitweb /
test-example: Test not specifying a port
[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,$monchild);
11
12 our %reported;
13 #  no entry: not reported, does not exist
14 #  /ry+/: reported, entry exists
15 # during processing only:
16 #  /r/: reported, may not still exist
17 #  /y+/: not reported, entry exists
18
19 sub killmonitor () {
20     return unless $monchild;
21     kill 9, $monchild
22         or warn "$us: cannot kill monitor child [$monchild]: $!\n";
23     $monchild=undef;
24     close $monh;
25 }
26
27 END { killmonitor(); }
28
29 my $restart;
30
31 for (;;) {
32     my $o;
33     eval {
34         if (!$monh) {
35             killmonitor();
36             $monh = new IO::File;
37             $monchild = open $monh, "-|", qw(ip -o monitor addr)
38                 or die "spawn monitor: $!\n";
39             sleep(1) if $restart++;
40         } else {
41             my $discard;
42             my $got = sysread $monh, $discard, 4096;
43             die "read monitor: $!\n" unless defined $got;
44             die "monitor failed\n" unless $got;
45         }
46         $_='r' foreach values %reported;
47         foreach my $ip (qw(4 6)) {
48             my $addrh = new IO::File;
49             open $addrh, "-|", qw(ip -o), "-$ip", qw(addr show)
50                 or die "spawn addr $ip show: $!\n";
51             my $afstr = $ip==4 ? 'inet' : $ip==6 ? 'inet6' : die;
52             while (<$addrh>) {
53                 if (m{^\d+\:\s*(\S+)\s+$afstr\s+([0-9a-z.:]+)(?:/\d+)?\s}) {
54                     my $outline = "$ip $1 $2";
55                     $reported{$outline} .= "y";
56                 } else {
57                     chomp;
58                     warn "unexpected output from addr $ip show: $_\n";
59                 }
60             }
61             my $r = close $addrh;
62             die "addr $ip show failed $!\n" unless $r;
63             $o = '';
64         }
65         foreach my $k (keys %reported) {
66             local $_ = $reported{$k};
67             if (m/^r$/) {
68                 $o .= "-$k\n";
69                 delete $reported{$k};
70             } elsif (m/^y/) {
71                 $o .= "+$k\n";
72             }
73         }
74     };
75     if ($@) {
76         print STDERR "$us: $@";
77         sleep 5;
78         next;
79     }
80     print $o or die $!;
81     STDOUT->flush or die $!;
82 }