Using ifstated to watch an egress link
Table of Contents
While developing my own OpenBSD router, I stumbled across a built-in service called ifstated. Previously, I was using a cronjob to run a script every five minutes to check the status of pppoe0. However, ifstated is able to do everything that my script could, in a more powerful way.
The inspiration for this configuration file originated heavily from calomel's tutorial. I did modify a handful of items though, to better tailor it to my own router's design.
The egress_check.sh script is used to run extra steps, such as email the admin if the egress IP has changed.
/etc/ifstated.conf
init-state start
# Check if external link is up.
link_up = '( "ifconfig egress | grep -q \"status: active\"" every 10 )'
# Check to see if egress is working
ping_check = '( "ifconfig egress | grep -q \"inet *.*.*.* netmask\" && ping -c 3 -w 5 8.8.8.8 >/dev/null" every 20 )'
# Check if this router is using pppoe to connect
pppoe_check = '( "ifconfig | grep -q pppoe" every 5 )'
state start {
init {
run "logger \"Starting ifstated\""
run "touch /tmp/.ifstated.start"
}
if $link_up {
if $ping_check {
set-state online
}
if ! $ping_check {
set-state offline
}
}
if ! $link_up {
set-state egress_down
}
}
state online {
# This will look at the IP currently on egress, and notify admin via email if it has been changed
init {
run "test ! -e /tmp/.ifstated.start && /home/admin/bin/egress_check.sh || rm /tmp/.ifstated.start"
}
if ! $ping_check {
set-state offline
}
}
state offline {
init {
run "logger \"Egress is active, but we cannot ping 8.8.8.8\""
run "echo -e \"Router egress is online, but cannot ping out\"\n $(ifconfig egress) | mail -s \"$(hostname -s) is offline\" $myemail@email.com"
if $pppoe_check {
run "ifconfig pppoe0 up"
}
if ! $pppoe_check {
run "ifconfig em0 up"
}
}
if ! $link_up {
set-state egress_down
}
if $ping_check {
set-state online
}
}
state egress_down {
init {
run "logger \"Egress is disconnected\""
run "echo \"$(date; ifconfig egress)\" | mail -s \"$(hostname -s) Egress is disconnected\" $myemail@email.com"
}
if $link_up {
if $ping_check {
set-state online
}
if ! $ping_check {
set-state offline
}
}
}
This the the egress script that gets called when the router/server changes into the online state. I run a pppoe connection at home, and would like to be notified when the link goes down, or if my external IP is changed.
egress_check.sh
#!/usr/bin/env bash
egress_file=/tmp/ifstated_egress
egress_ip=$(ifconfig egress | grep -m1 inet | awk '{print $2}')
admin_email=$myemail@mail.com
#
# If the egress file exists, read it. If not, create a new one with the current egress ip.
# Since OpenBSD clears /tmp on reboot, assume this is a new boot
if [[ ! -e $egress_file ]]; then
echo $egress_ip > $egress_file
logger "Egress log absent, creating"
exit 0
fi
#
# Compare the egress log to the current egress ip. If they differ, email admin
egress_old=$(cat $egress_file)
if [[ $egress_ip != $egress_old ]]; then
logger "IP has changed to $egress_ip"
echo $egress_ip > $egress_file
if [[ -n $admin_email ]]; then
echo "IP has changed $(uptime) $(ifconfig egress)" | mail -s "$(hostname -s) IP has changed" $admin_email
fi
exit 0
fi
#
# We only got this far if there was an egress log, and the IP had not changed. Therefore, the link must have dropped
if [[ -n $admin_email ]]; then
echo "$(uptime) $(ifconfig egress)" | mail -s "$(hostname -s) is online" $admin_email
fi