--- /dev/null
+#!/usr/bin/perl
+
+# Simple Nagios-compatible checker for BIRD protocols.
+
+# SPDX-License-Identifier: GPL-3.0-or-later
+# Copyright (C) 2016-2023 Simon Ruderich
+
+
+use strict;
+use warnings;
+use autodie;
+
+use Monitoring::Plugin;
+use IO::Socket::UNIX ();
+
+
+my $np = Monitoring::Plugin->new(
+ usage => "usage: %s [-s <socket>] <proto>..",
+);
+$np->add_arg(
+ spec => 'socket|s=s',
+ help => 'Path to bird UNIX control socket.',
+ default => '/run/bird/bird.ctl',
+);
+$np->getopts;
+
+if (@ARGV == 0) {
+ $np->plugin_exit(OK, 'no protocols specified');
+}
+
+alarm $np->opts->timeout; # handler already set by Monitoring::Plugin
+
+
+my $bird = IO::Socket::UNIX->new(
+ Type => IO::Socket::UNIX::SOCK_STREAM,
+ Peer => $np->opts->socket,
+) or $np->plugin_exit(CRITICAL, "failed to open '" . $np->opts->socket . "'");
+
+$_ = <$bird> // $np->plugin_exit(CRITICAL, 'failed to read hello');
+/^0001 / or $np->plugin_exit(CRITICAL, 'invalid hello');
+
+
+sub bird_command {
+ my ($cmd) = @_;
+
+ $bird->send("$cmd\n")
+ // $np->plugin_exit(CRITICAL, "failed to send command '$cmd'");
+
+ my @result;
+ while (<$bird>) {
+ next if /^\+/; # ignore spontaneous printout
+ chomp;
+
+ if (/^8/ or /^9/) {
+ $np->plugin_exit(CRITICAL,
+ "error while running command '$cmd': $_");
+ }
+
+ push @result, $_;
+ return @result if /^\d{4} /;
+ }
+ $np->plugin_exit(CRITICAL, "incomplete output for command '$cmd'");
+}
+
+foreach my $name (@ARGV) {
+ foreach (bird_command("show protocols $name")) {
+ next unless /^1002-/;
+ s/\s+$//;
+
+ my @data = split /\s+/, $_, 6;
+
+ my $proto = $data[1];
+ my $status = $data[3];
+ my $info = $data[5] // '';
+ # Hacky workaround for "timeformat protocol iso long"
+ $info =~ s/^\d{2}:\d{2}:\d{2}\s+//;
+
+ # Administratively disabled.
+ if ($status ne 'up') {
+ $np->add_message(CRITICAL, "protocol '$name' not up");
+ }
+ # Not running.
+ my $failed = 0;
+ if ($proto eq 'BGP') {
+ $failed = 1 if $info ne 'Established';
+ } elsif ($proto eq 'OSPF') {
+ $failed = 1 if $info ne 'Running';
+ } else {
+ $np->add_message(WARNING, "unknown protocol '$proto', "
+ . 'please file a bug report');
+ }
+ if ($failed) {
+ $np->add_message(CRITICAL, "protocol '$name' not running: '$info'");
+ }
+ }
+}
+
+$np->plugin_exit($np->check_messages(join => ', '));