File: //usr/share/sendmail/dynamic
#!/bin/sh
#------------------------------------------------------------------------
#
# $Sendmail: dynamic,v 8.15.2 2021-03-16 16:04:16 cowboy Exp $
#
# Shell functions to handle dynamic network updates.
# Supports ppp, dhcp, ifup/down, etc.
#
# Copyright (c) 2004-2010 Richard Nelson. All Rights Reserved.
#
# This script is called from the following places:
# /etc/ppp/ip-down.d/sendmail #\
# /etc/ppp/ip-up.d/sendmail # | These are deprecated
# /etc/dhcp3/dhclient-exit-hooks.d/sendmail #/
# /etc/network/if-down.d/sendmail #standard
# /etc/network/if-post-down.d/sendmail #standard
# /etc/network/if-up.d/sendmail #standard
# /etc/resolvconf/update-libc.d/sendmail #More or less useless :(
#
# The other half of the logic is in /etc/mail/sendmail.conf
#
# DAEMON_NETMODE="Dynamic"; Keyword SMTP network mode
# static: Do not monitor any network interfaces for changes
# dynamic: Monitor one or more interfaces for changes
#
# DAEMON_NETIF="eth0"; string SMTP interface(s)
# This parameter defines the network interface(s) that the daemon
# will monitor for status changes (via ppp, dhcp, ifup/down hooks).
#
# NOTES:
# 1) Only list more than one interfaces if they only used for fallback,
# otherwise the daemon will wind up ping-ponging between interfaces.
# 2) Do not use 'lo' unless your daemon only listens on the localhost.
#
# LOG_CMDS="No"; Binary command logging flag
# Will cause syslog entries for many of the sendmail related commands
# like runq, mailq, etc - you'll also see cron jobs (if enabled).
#
# HANDS_OFF="No"; Binary Do *NOT* touch the configuration
# Set this *ONLY* if you are going to be fully responsible for the entire
# setup of sendmail - the directories, permissions, databases, etc. With
# this variable set to "Yes", nothing will be done for you during
# updates.
#
# In other words, "The blood be upon your hands" if you set this...
# My ability to help with problems will be greatly reduced !
#
# "Well, a pet peeve of mine is people who directly edit the
# .cf file instead of using the m4 configuration files.
# Don't do it! [laughs] I treat the .cf file as a binary
# file - you should too."
# -- Eric Allman 1999/10/18
#
#------------------------------------------------------------------------
#
# The files we may alter
provider_m4='/etc/mail/m4/provider.m4';
dialup_m4='/etc/mail/m4/dialup.m4';
# Default values
SM_ignore=0; # Ignore any changes
SM_changed=0; # Something has changed, dunno what
SM_delay=0; # Expect another call soon, do work then
SM_interface=''; # The interface that changed
SM_state=''; # How the interface changed
SM_provider=''; # ISP/domain name/IPPARM/etc
SM_ip=''; # IP for the interface
SM_host=''; # Reverse FQDN of IP
SM_debug=1; # Of minimal value
# Path to other sendmail helpers
if [ -x ./update_sendmail ]; then
sm_path='.';
elif [ -x $(/usr/bin/dirname $0)/update_sendmail ]; then
sm_path=$(/usr/bin/dirname $0);
else
sm_path=/usr/share/sendmail;
fi;
# Bring in sendmail.conf for the network definitions
if [ ! -f /etc/mail/sendmail.conf ]; then
if [ -x $sm_path/update_conf ]; then
$sm_path/update_conf;
fi;
fi;
DAEMON_NETMODE='Static';
DAEMON_NETIF='';
HANDS_OFF='No';
LOG_CMDS='Yes';
if [ -f /etc/mail/sendmail.conf ]; then
. /etc/mail/sendmail.conf;
fi;
# Record information on an interface and its status
update_interface() {
SM_interface="$1";
SM_reason="$2";
# Translate DHCP style actions to a simple up/down
case "$SM_reason" in
DOWN|EXPIRE|FAIL|RELEASE|STOP) # and TIMEOUT too ???
SM_state='down';
;;
UP|BOUND|RENEW|REBIND|REBOOT|TIMEOUT) # why TIMEOUT here ???
SM_state='up';
if [ "$SM_reason" = "BOUND" ]; then
SM_changed=1;
fi;
;;
*)
SM_state='unknown';
;;
esac;
# Mark what we're doing...
local msg;
msg="$SM_interface $SM_state $SM_provider $SM_ip $SM_host";
if [ "$LOG_CMDS" != 'No' ]; then
/usr/bin/logger -i -p mail.debug -- "$0 (dynamic) update_interface: $msg";
fi;
# Do absolutely nothing if they say so...
if [ "$HANDS_OFF" != 'No' -o "$DAEMON_NETMODE" = 'Static' ]; then
SM_ignore=1;
fi;
if [ -z "$SM_interface" ]; then
SM_ignore=1;
fi;
# Check to see if we care about this interface
if [ $SM_ignore -eq 0 ]; then
SM_ignore=1;
for if in $DAEMON_NETIF; do
if [ "$if" = "$SM_interface" ]; then
SM_ignore=0;
break;
fi;
done;
fi;
if [ $SM_ignore -ne 0 ]; then
return;
fi;
};
# Record information about the upstream provider
update_provider() {
SM_provider="$1";
# Mark what we're doing...
local msg;
msg="$SM_interface $SM_state $SM_provider $SM_ip $SM_host";
if [ "$LOG_CMDS" != 'No' ]; then
/usr/bin/logger -i -p mail.debug -- "$0 (dynamic) update_provider: $msg";
fi;
# Do absolutely nothing if they say so...
if [ "$HANDS_OFF" != 'No' -o "$DAEMON_NETMODE" = 'Static' ]; then
SM_ignore=1;
fi;
if [ $SM_ignore -ne 0 ]; then
return;
fi;
# Add smarthost information (if any)...
# But not if provider.m4 is a link !
if [ -z "$SM_provider" ]; then
return;
fi;
if [ ! -e "/etc/mail/peers/$SM_provider" ]; then
SM_provider='default';
fi;
if [ -e "/etc/mail/peers/$SM_provider" ] \
&& [ ! -L "$provider_m4" ]; then
SM_changed=1;
cat <<-EOT > "$provider_m4";
LOCAL_CONFIG
#------------------------------------------------------------
#
# Dynamic provider updates from $0:
# Device=$SM_interface
# State=$SM_state
# Provider=$SM_provider
#
# NOTE: The following line *MUST* be in /etc/mail/sendmail.mc
#dnl include(\`/etc/mail/provider.m4')dnl
#
# You may also need to include this file in submit.mc !
#
# Provider information from /etc/mail/peers/$SM_provider
EOT
cat "/etc/mail/peers/$SM_provider" >> "$provider_m4";
cat <<-EOT >> "$provider_m4";
#------------------------------------------------------------
EOT
fi;
};
# Record information on an ip/host
update_host() {
SM_ip="$1";
# Mark what we're doing...
local msg;
msg="$SM_interface $SM_state $SM_provider $SM_ip $SM_host";
if [ "$LOG_CMDS" != 'No' ]; then
/usr/bin/logger -i -p mail.debug -- "$0 (dynamic) update_host: $msg";
fi;
# Do absolutely nothing if they say so...
if [ "$HANDS_OFF" != 'No' -o "$DAEMON_NETMODE" = 'Static' ]; then
SM_ignore=1;
fi;
if [ $SM_ignore -ne 0 ]; then
return;
fi;
if [ -z "$SM_ip" ]; then
return;
fi;
find_host;
if [ $SM_ignore -ne 0 ]; then
return;
fi;
# Add ip related information (if any)...
# But not if dialup.m4 is a link !
if [ ! -L "$dialup_m4" ]; then
SM_changed=1;
cat <<-EOT > "$dialup_m4";
LOCAL_CONFIG
#------------------------------------------------------------
#
# Dynamic host/ip updates from $0:
# Device=$SM_interface
# State=$SM_state
# Provider=$SM_provider
# IP=$SM_ip
# Host=$SM_host
#
# NOTE: The following line *MUST* be in /etc/mail/sendmail.mc
#dnl include(\`/etc/mail/dialup.m4')dnl
#
# This should *NOT* be included in submit.mc !
#
# Make sure we accept mail as this ip (for bounces, etc)
Cw$SM_ip
EOT
if [ -z "$SM_host" ]; then
cat <<-EOT >> "$dialup_m4";
#
# Rats... FQDN lookup failed, your kit is incomplete :(
EOT
else
cat <<-EOT >> "$dialup_m4";
#
# Define our true hostname (from our ISP) - becomes \$j
define(\`confDOMAIN_NAME', \`$SM_host')dnl
#
# Make sure we accept mail as this name (for bounces, etc)
Cw$SM_host
#
# Add our hostname to class G for genericstable support
CG$SM_host
#------------------------------------------------------------
EOT
fi;
fi;
};
# DNS support changed, we may (or may not) have a new name
# but in any case, we may have stale host info in the queue
update_resolv() {
# Mark what we're doing...
local msg;
msg="$SM_interface $SM_state $SM_provider $SM_ip $SM_host";
if [ "$LOG_CMDS" != 'No' ]; then
/usr/bin/logger -i -p mail.debug -- "$0 (dynamic) update_resolv: $msg";
fi;
# Do absolutely nothing if they say so...
if [ "$HANDS_OFF" != 'No' -o "$DAEMON_NETMODE" = 'Static' ]; then
SM_ignore=1;
fi;
if [ $SM_ignore -ne 0 ]; then
return;
fi;
# Ideally, we should re-check our IP if we didn't find the
# FQDN previously - but we need a state file to do that :(
#
# Hell, we don't even know what IF is, and if it is up or down :(
#SM_interface='?'; #\
#SM_state='up'; # \
#SM_provider='?'; # | Need to get these from somewhere !
#SM_ip='?'; # /
#SM_host='?'; #/
#find_host;
# Purge any latent host status that might cause us to *NOT* send mail
if [ -x /etc/init.d/sendmail ]; then
if [ "$SM_state" = 'up' ]; then
/etc/init.d/sendmail purgestat now;
fi;
fi;
# resolvconf is called as a DHCP pre-exit, so we'll defer any changes
SM_changed=0;
}
# Attempt to locate our FQDN
find_host() {
# Determine our fqdn from our ISP
maxloop=30;
cntr=0;
SM_host='';
until (test ! -z "$SM_host"); do
cntr=`expr $cntr + 1`;
if [ $cntr -gt $maxloop ]; then
SM_host='';
break;
fi;
rev=$(host $SM_ip);
SM_host=$(echo "$rev" | grep '^Name:' | awk '{print $2}');
if [ -z "$SM_host" ]; then
test=$(echo "$rev" | egrep -e 'not found:');
if [ -n "$test" ]; then
continue;
else
SM_host=${rev##*domain name pointer };
SM_host=${SM_host%.};
fi;
fi;
test=$(echo $SM_host | cut -d ' ' -f 1);
# continue scanning if we get this:
# ;; connection timed out; no servers could be reached
if [ "$test" = ";;" ]; then
SM_host='';
elif [ "$test" != "**" ]; then
break;
fi;
sleep 1s;
done;
# See if we actually found a host !
if [ -z "$SM_host" ]; then
# Drats, no host name :(
# We have a few choices - none pretty
# 1) Do not start sendmail
# 2) Use the info we have (ip) - but
# then we may not accept mail we should,
# accept mail we should not,
# and our ougoing name may be wrong
# 3) Use the last known hostname
# If it is not correct, we have the same
# exposurs as option 2 !
#
# For the nonce, I choose option 2
:
fi;
if [ $SM_debug -ne 0 ]; then
echo "addr=$SM_ip, name=$SM_host";
fi;
};
# If our state has changed in any way, update sendmail
update_sendmail() {
SM_caller="$1";
SM_opts="$2";
# Mark what we're doing...
local msg;
msg="$SM_interface $SM_state $SM_provider $SM_ip $SM_host";
if [ "$LOG_CMDS" != 'No' ]; then
/usr/bin/logger -i -p mail.debug -- "$0 (dynamic) update_sendmail: $msg";
fi;
# Do absolutely nothing if they say so...
if [ "$HANDS_OFF" != 'No' -o "$DAEMON_NETMODE" = 'Static' ]; then
SM_ignore=1;
fi;
if [ $SM_ignore -ne 0 ]; then
return;
fi;
# Check for a delayed restart (for DHCP/PPP)
case "$SM_opts" in
[Dd]*)
if [ "$SM_state" = 'up' ]; then
SM_delay=1;
fi;
;;
esac;
if [ "$SM_state" = 'down' ]; then
SM_changed=1;
cat <<-EOT > "$dialup_m4";
LOCAL_CONFIG
#------------------------------------------------------------
# Dynamic host/ip updates from $0:
# Device=$SM_interface
# State=$SM_state
# Provider=$SM_provider
# IP=$SM_ip
# Host=$SM_host
#
# NOTE: The following line *MUST* be in /etc/mail/sendmail.mc
#dnl include(\`/etc/mail/dialup.m4')dnl
# This should *NOT* be included in submit.mc !
#
# sendmail is to only queue messages until connected again
define(\`confDELIVERY_MODE', \`deferred')dnl
#
# Allow the queue to age without carping every four hours
define(\`confTO_QUEUEWARN',\`1d')dnl
#
# Don't keep host status while the network is down
define(\`confHOST_STATUS_DIRECTORY')dnl
#------------------------------------------------------------
EOT
fi;
if [ $SM_changed -eq 1 ]; then
# Build a new sendmail.cf from sendmail.mc, including our address.
/usr/bin/make -f /etc/mail/Makefile sendmail.cf;
/usr/bin/make -f /etc/mail/Makefile;
# Purge any latent host status that might cause us to *NOT* send mail
# Reload sendmail, IFF already running
if [ -x /etc/init.d/sendmail ]; then
if [ "$SM_state" = 'up' ]; then
/etc/init.d/sendmail purgestat now;
fi;
/etc/init.d/sendmail reload-if-running & # up, or down
fi;
fi;
# Process the sendmail queue
# (background so as to not defer other ip-up work)
# This can be fatal on IF ping-pongs :(
# runq &
};