summaryrefslogtreecommitdiffstats
path: root/net_if
blob: 702de79af9566c5cc07d96fd4de10b71fe0ea5e5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/usr/bin/perl -T

use warnings;
use strict;
use Nagios::Plugin;

$ENV{'PATH'} = '/bin:/usr/bin:/sbin:/usr/sbin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

my $n = Nagios::Plugin->new;

# Check the status of the given network interface and return
# three lists of the interfaces sorted by status (all, down, error).
# This does resolves interfaces groups automaticaly and returns
# the member interfaces.
#
# parameter:
#     list of interfaces
sub get_if_status (@) {
    my (@all, @down, @error);

    while (@_) {
        # untaint interface name
        my $if = shift @_;
        next unless ($if =~ m/^([-\w]+)$/);
        $if = $1;

        # We are doing an two step process. First we do a fork and
        # after that we exec the ifconfig child process. This is
        # necessary to pipe stderr of the child process away, while
        # using the list syntax for open and exec.
        my $pid = open(IFCONFIG, "-|");
        $n->nagois_exit(CRITICAL, "fork: $!") unless defined $pid;

        if ($pid == 0) {
            # redirect stderr
            open(STDERR, ">", "/dev/null");
            exec("ifconfig", $if)
        }

        while (<IFCONFIG>) {
            # parse ifconfig output:
            if ($_ =~ m/^([-a-v0-9]+): flags=([0-9]+)</) {
                push(@all, $1);
                push(@down, $1) unless ($2 & 1);
            }
        }

        close(IFCONFIG) or push(@error, $if);
    }

    return (\@all, \@down, \@error);
}

# Get the byte conters for incomming and outgoing packages.
#
# parameter:
#     interface name
sub get_if_stats ($) {
    my $if = shift;
    my $stats = {};

    open(PFCTL, "-|", "pfctl", "-vvsI", "-i", $if);
    while (<PFCTL>) {
        if ($_ =~ m{In4/Pass.*Bytes: ([0-9]+)}) {
            $stats->{'in4'} = $1;
        }
        elsif ($_ =~ m{Out4/Pass.*Bytes: ([0-9]+)}) {
            $stats->{'out4'} = $1;
        }
        elsif ($_ =~ m{In6/Pass.*Bytes: ([0-9]+)}) {
            $stats->{'in6'} = $1;
        }
        elsif ($_ =~ m{Out6/Pass.*Bytes: ([0-9]+)}) {
            $stats->{'out6'} = $1;
        }
    }
    close(PFCTL);

    return $stats;
}

# Print nagios compatible message containing the number of interfaces
# and performance data containing the byte counter for the interfaces.
#
# parameter:
#     nagios status code
#     additional message
#     interface statistics
sub print_stats ($$$) {
    my $status = shift;
    my $msg = shift;
    my $stats = shift;
    my ($count, $perfdata);

    $count = keys %$stats;
    $perfdata = "";
    for my $if (keys %$stats) {
        for (qw( in4 out4 in6 out6 )) {
            $perfdata = "$perfdata $if-$_=$stats->{$if}->{$_};";
        }
    }

    $n->nagios_exit($status, "$count interfaces$msg |$perfdata");
}

# This function generate a nagios status code and an additional
# message, based on the counts of the interfaces, that are down
# or does not exist.
#
# parameter:
#     list of down interfaces
#     list of interfaces, that does not exists
# returns:
#     (status, msg) for nagios
sub get_status ($$) {
    my $down = shift;
    my $error = shift;
    my ($status, $msg) = (OK, '');

    # Order matters! LAST MATCH WINS.
    if (@$down) {
        # Chech whether some interfaces are down and we have to
        # issue a warning.
        my $count = @$down;
        $down = join ", ", @$down;

        $status = WARNING;
        $msg = ", $count interface(s) are down ($down)";
    }

    if (@$error) {
        # Chech whether some interface or interface group, specified
        # on the command line, does not exists and we should return a
        # critical error.
        my $count = @$error;
        $error = join ", ", @$error;

        $status = CRITICAL;
        $msg = ", $count interface(s) does not exists ($error)";
    }

    return ($status, $msg);
}


my ($interfaces, $down, $error) = get_if_status(@ARGV);
my ($status, $msg) = get_status($down, $error);

my $stats = {};
for my $if (@$interfaces) {
    $stats->{$if} = get_if_stats($if);
}

print_stats($status, $msg, $stats);
$n->nagios_exit(CRITICAL, "End of script");