#!/bin/sh
#
#	$Id: IPaddr,v 1.8.2.1 2001/10/04 02:46:08 alan Exp $
#
#	This script manages IP alias IP addresses
#
#	It can add an IP alias, or remove one.
#
#	usage: $0 ip-address {start|stop|status}
#
#	The "start" arg adds an IP alias.
#
#	Surprisingly, the "stop" arg removes one.	:-)
#
#

LC_ALL=en; export LC_ALL # Make ifconfig work in France for David Jules :-)
LANGUAGE=en; export LANGUAGE # Make ifconfig work in France for Fabrice :-)

. /etc/ha.d/shellfuncs

IFCONFIG=/sbin/ifconfig
ROUTE=/sbin/route
SENDARP=$HA_BIN/send_arp
FINDIF=$HA_BIN/findif
USAGE="usage: $0 ip-address {start|stop|status}";

#
#	Find out which alias serves the given IP address
#	The argument is an IP address, and its output
#	is an aliased interface name (e.g., "eth0:0").
#
find_interface() {

  ipaddr=$1;
  $IFCONFIG |
  while read ifname linkstuff
  do
    read inet addr junk
    while
      read line && [ "X$line" != "X" ]
    do
      : Nothing
    done
    case $ifname in
      *:*)	;;
      *)	continue;;
    esac
    case $addr in
      addr:$ipaddr)	echo $ifname; return 0;;
    esac
  done
  return 1
}


#
#	Remove the IP alias for the requested IP address...
#	
ip_stop() {
  BASEIP=`echo $1 | sed s'%/.*%%'`
  IF=`find_interface $BASEIP`
  if
    [ -z "$IF" ]
  then
    : Requested interface not in use
    exit 0
  fi

  if
    [ -x $HA_RCDIR/local_giveip ]
  then
    $HA_RCDIR/local_giveip $*
  fi

#
#	The next bit of code is borrowed from Horms' fake code...
#	and can be inferred from the IP-Aliasing mini-HOWTO
#

  $ROUTE del -host $BASEIP
  $IFCONFIG $IF down
  ha_log "info: IP Address $BASEIP released"
}


#
#	Find an unused interface/alias name for us to use for new IP alias
#	The argument is an IP address, and the output
#	is an aliased interface name (e.g., "eth0:0").
#
find_free_interface() {
  ipaddr=$1;
  if
    NICINFO=`$FINDIF $ipaddr`
  then
    : OK
  else
    lrc=$?
    ha_log "ERROR: unable to find an interface for $ipaddr"
    return $lrc
  fi
  nicname=`echo "$NICINFO" | cut -f1`
  nicinfo=`echo "$NICINFO" | cut -f2-`
  if
    [ $nicname = "" ]
  then
    ha_log "ERROR: no interface found for $ipaddr"
    return 1;
  fi

  IFLIST=`$IFCONFIG | grep "^$nicname:[0-9]" | sed 's% .*%%'`
  IFLIST=" `echo $IFLIST` "

  j=0

  while
    [ $j -lt 512 ]
  do
    case $IFLIST in
      *" "$nicname:$j" "*)	;;
      *)			echo "$nicname:$j	$nicinfo"
      				return 0;;
    esac
    j=`expr $j + 1`
  done
  return 1
}


#
#	Add an IP alias for the requested IP address...
#
#	It could be that we already have taken it, in which case it should
#	do nothing.
#

ip_start() {
#
#	Do we already service this IP address?
#
  if
    $IFCONFIG | grep "inet addr:$1 " >/dev/null 2>&1
  then
    exit 0	# We already own this IP address
  fi

  if
    IFINFO=`find_free_interface $1`
  then
    : OK got interface [$IFINFO] for $1
  else
    exit 1
  fi
  IF=`echo "$IFINFO" | cut -f1`
  IFEXTRA=`echo "$IFINFO" | cut -f2-`
  BASEIP=`echo $1 | sed s'%/.*%%'`

  if
    [ -x $HA_RCDIR/local_takeip ]
  then
    $HA_RCDIR/local_takeip $*
  fi
  
#
#	The remaining code in this function taken from FAKE, by horms
#

  ha_log "info: ifconfig $IF $BASEIP $IFEXTRA"
  $IFCONFIG $IF $BASEIP $IFEXTRA

  $ROUTE add -host $BASEIP dev $IF

  TARGET_INTERFACE=`echo $IF | sed 's%:.*%%'`

  MACADDR=$($IFCONFIG $TARGET_INTERFACE  | \
      fgrep $TARGET_INTERFACE | \
      sed \
      's/^.*HWaddr \(..\):\(..\):\(..\):\(..\):\(..\):\(..\).*$/\1\2\3\4\5\6/')
  
  if [ "${MACADDR:=NULL}" = "NULL" ]; then
      ha_log "ERROR: Could not locate obtain hardware address for $TARGET_INTERFACE"
  fi
 
  ha_log "info: Sending Gratuitous Arp for $BASEIP on $IF [$TARGET_INTERFACE]"

  for j in 1 2 3 4 5
  do
   $SENDARP $TARGET_INTERFACE ${BASEIP} ${MACADDR} ${BASEIP} ffffffffffff \
     || ha_log "ERROR: Could not send gratuitous arp"
     sleep 2
  done &
}

ip_status() {
  BASEIP=`echo $1 | sed s'%/.*%%'`
  if
    $IFCONFIG | grep "inet addr:$BASEIP " >/dev/null 2>&1
  then
    echo "running"
  else
    echo "stopped"
  fi
}

#
#	Determine if this IP address is really being served, or not.
#	Note that we don't distinguish if *we're* serving it locally...
#
ip_monitor() {
  BASEIP=`echo $1 | sed s'%/.*%%'`
  OPTS=" -c 1 -w 2 -q"
  for j in 1 2 3
  do 
    if
      ping $OPTS $BASEIP >/dev/null 2>&1
    then
      echo "OK"
      return 0
    fi
  done
  echo "down"
  return 1
}

usage() {
  echo $USAGE >&2
}

#
#	Add or remove IP alias for the given IP address...
#

if
  [ $# -eq 1 ]
then
  case $1 in
    info)	cat <<-!INFO
	Abstract=IP address takeover
	Argument=IP address OR IP address/broadcast address OR IP address/broadcast address/netmaskbits
	Description:
	An IPaddr resource is an IP address which is to be taken over by \\
	the owning node.  An argument is required, and is of this form:
	    nnn.nnn.nnn.nnn/bbb.bbb.bbb.bbb
	Where nnn.nnn.nnn.nnn is the IP address to be taken over, and\\
	bbb.bbb.bbb.bbb is the broadcast address to be used with this address.

	Since IPaddr is the "default" resource type, it is not necessary\\
	to prefix the IP address by "IPaddr::".
	This allows IPaddr::192.2.4.63 to be abbreviated as 192.2.4.63.
	!INFO
	exit 0;;
  esac
fi
if
  [ $# -ne 2 ]
then
  usage
  exit 1
fi

case $2 in
  start)	ip_start $1;;
  stop)		ip_stop $1;;
  status)	ip_status $1;;
  monitor)	ip_monitor $1;;
  *)		usage
  		exit 1
		;;
esac
#
#
# $Log: IPaddr,v $
# Revision 1.8.2.1  2001/10/04 02:46:08  alan
# Added a workaround for a bug in some versions of Mandrake firewall
# locale handline.  Harmless to everyone else, and simple to put in.
#
# Revision 1.8  2001/02/05 21:43:38  alan
# Added "monitor" action to IPaddr.
#
# Revision 1.7  2000/11/07 14:15:04  alan
# Made the takeover of IP addresses go faster.
# Removed the limit on 8 aliases per interface.
#
# Revision 1.6  2000/06/12 06:11:09  alan
# Changed resource takeover order to left-to-right
# Added new version of nice_failback.  Hopefully it works wonderfully!
# Regularized some error messages
# Print the version of heartbeat when starting
# Hosts now have three statuses {down, up, active}
# SuSE compatability due to Friedrich Lobenstock and alanr
# Other minor tweaks, too numerous to mention.
#
# Revision 1.5  1999/12/30 03:18:50  alan
# Put Stefan Salzer's fix on the place he put it in :-)  The same bug appeared
# twice in the code.  I fixed it in one place, and so did he.  Now
# it looks like they're both fixed.
#
# Revision 1.4  1999/12/23 03:28:21  alan
# Put in Stefan Salzer's fix to IPaddr to make it not confuse
# x.y.z.1 with x.y.z.11 or similar...
#
# Revision 1.3  1999/11/16 04:36:53  alan
# Added fix from David Jules to make IPaddr work in France.
# The problem is that various commands that IPaddr invokes (notably ifconfig)
# produce different output in other locales than they do in LC_ALL=en
# so the output wasn't recognized by IPaddr.  The fix is much simpler than
# this explanation :-)
#
# Revision 1.2  1999/11/10 20:33:04  alan
# Deleted /proc/ha directory from build list
# Added #!/bin/sh to lots (all?) of the scripts...
#
# Revision 1.1.1.1  1999/09/23 15:31:24  alanr
# High-Availability Linux
#
# Revision 1.11  1999/09/12 06:56:53  alanr
# Fixed the bugs that kept addresses w/netmasks and broadcast addresses from working.
#
# Revision 1.10  1999/09/08 03:47:18  alanr
# fixed things up so that send_arp doesn't just assume eth0 as the ethernet interface...
#
# Revision 1.9  1999/08/22 04:49:42  alanr
# Fixed a stupid syntax error.  Wonder how it got in here?
#
# Revision 1.8  1999/08/21 05:43:38  alanr
# added "info" argument to support GUI help screens, etc.
#
# Revision 1.7  1999/08/17 18:09:16  alanr
# More message changes.
#
# Revision 1.6  1999/08/17 18:04:31  alanr
# Minor message changes for Thomas' code.
#
# Revision 1.5  1999/08/17 17:57:07  alanr
# Put in Thomas Hepper's fix to make it obey netmasks and broadcast addrs
# from base interface.
#
# Revision 1.4  1999/08/17 05:00:44  alanr
# added a dumb extra #
#
# Revision 1.3  1999/08/17 04:57:57  alanr
# Added RCS keywords, and bug fix from Thomas Hepper
# th@ant.han.de to fix some kind of problem associated with PPP configs.
#
#
#
