tails-restricted-network-detector 2.73 KB
Newer Older
1 2 3 4 5 6 7 8 9
#!/usr/bin/env perl

use strict;
use warnings;

#man{{{

=head1 NAME

10
tails-restricted-network-detector
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

=head1 VERSION

Version X.XX

=head1 AUTHOR

Tails dev team <tails@boum.org>
See https://tails.boum.org/.

=cut

#}}}

use File::Tail;
use Parse::Syslog;
27
use IPC::System::Simple qw(runx);
28
use Locale::gettext;
Tails developers's avatar
Tails developers committed
29 30
use I18N::Langinfo qw{langinfo CODESET};
use Encode qw{decode find_encoding};
31 32 33 34 35 36
use POSIX;

setlocale(LC_MESSAGES, "");
textdomain("tails");

sub notify_maybe_blocked {
Tails developers's avatar
Tails developers committed
37 38 39
    my $encoding = find_encoding(langinfo(CODESET()));
    my $summary  = $encoding->decode(gettext('Network connection blocked?'));
    my $body     = $encoding->decode(gettext(
40 41
        'It looks like you are blocked from the network. This may be ' .
        'related to the MAC spoofing feature. For more information, see the ' .
42 43 44
        '<a href=\"file:///usr/share/doc/tails/website/doc/first_steps/' .
        'startup_options/mac_spoofing.en.html#blocked\">MAC spoofing ' .
        'documentation</a>.'));
45 46 47
    # We can't use Desktop::Notify since this script is supposed to be run
    # as root (for access to syslog), started in an env without DESKTOP etc,
    # which also causes issues with opening links in the text body.
Tails developers's avatar
Tails developers committed
48
    # All this works fine with tails-notify-user.
49
    runx('/usr/local/sbin/tails-notify-user', ($summary, $body, '30000'));
50 51
}

52
my %state;
53 54 55 56 57 58 59 60 61 62 63
my $syslog = File::Tail->new(name => "/var/log/syslog",
                             maxinterval => 1,
                             interval => 1);
my $parser = Parse::Syslog->new($syslog, allow_future => 1);
while(my $sl = $parser->next) {
    next if !($sl->{program} eq "NetworkManager");
    my $text = $sl->{text};
    if ($text =~ /Activation \(([^)]+)\) starting connection/) {
        # The beginning of *all* (not only wireless) new
        # connections. We drop any previous state so it won't
        # interfere.
64
        $state{$1} = "";
65 66
    } elsif ($text =~ /\(([^)]+)\): supplicant (?:connection|interface) state: \S+ -> (\S+)/ ||
             $text =~ /\(([^)]+)\): device state change: \S+ -> (\S+)/) {
67 68 69 70 71 72
        # NetworkManager logs state transitions with the above
        # messages, but the really important part is that we
        # accurately log the state changes *to* and *from*
        # "associating" (for the next case). Hence the safest bet
        # seems to be to deal with all observed types of transitions
        # that NetworkManager logs.
73 74 75 76 77 78 79 80 81 82
        $state{$1} = $2;
    } elsif ($text =~ /Activation \(([^)]+)\/[^)]*\): association took too long/) {
        # Wireless connection failure. If it happens during
        # "associating" it *may* indicate that the AP is blocking the
        # MAC address in use.
        if ($state{$1} eq "associating") {
            notify_maybe_blocked();
        }
    }
}