: ########################################################################## # Title : collectethers - create database of ethernet addresses # Author : Heiner Steven # Date : 1998-11-25 # Requires : arp # Category : System Administration # SCCS-Id. : @(#) collectethers 1.4 04/02/18 ########################################################################## # Description # ########################################################################## PN=`basename "$0"` # Program name VER='1.4' # Search PATH for a new AWK (or GNU AWK) for path in `echo "$PATH" | sed 's/^:/.:/;s/:$/:./;s/:/ /g'` do [ -x "$path/gawk" ] && : ${NAWK=$path/gawk} [ -x "$path/nawk" ] && : ${NAWK=$path/nawk} done : ${NAWK=awk} ARP="arp -a" PrettyPrint=no Interval=60 HostPattern= Ethers=ethers.list Usage () { echo >&2 "$PN - collect ethernet addresses, $VER usage: $PN [-i interval] [-m hostmatch] [filename] or: $PN -p [filename ...] -i: update interval (default is $Interval, 0 means \"run once\") -m: string to match hostname part of \"$ARP\" output (default: domainname) The first usage periodically calls the command "$ARP", and collects ethernet addresses in a file (the default is \"$Ethers\"). The second usage pretty prints ethernet addresses." exit 1 } Msg () { for MsgLine do echo "$PN: $MsgLine" >&2 done } Fatal () { Msg "$@"; exit 1; } Tmp=${TMPDIR:=/tmp}/$PN.$$ set -- `getopt hi:p "$@"` [ $# -lt 1 ] && Usage # "getopt" detected an error while [ $# -gt 0 ] do case "$1" in -m) HostPattern="$2"; shift;; -i) Interval="$2"; shift;; -p) PrettyPrint=yes;; --) shift; break;; -h) Usage;; -*) Usage;; *) break;; # First file name esac shift done if [ $PrettyPrint = yes ] then # Input example: : ' 00:60:08:22:e9:d9 host.dev.null.de 8:0:20:95:eb:78 lorenz ' exec $NAWK ' { for ( i=1; i<=NF; ++i ) { if ( $i ~ /^[0-9a-fA-F][0-9a-fA-F]*:/ ) { addr = $i k = split (addr, a, ":") newaddr = "" for ( j=1; j<=k; ++j ) { if ( newaddr != "" ) newaddr = newaddr ":" part = a [j] if ( length (part) == 1 ) { newaddr = newaddr "0" part } else { newaddr = newaddr part } } $i = newaddr } } print } ' "$@" # NOT REACHED fi [ $# -lt 1 ] && set -- "$Ethers" [ $# -ne 1 ] && Fatal "please specify excactly one file name" Ethers="$1" # Ethers database must already exist [ -f "$Ethers" ] || > "$Ethers" || exit 1 : ${HostPattern:=224.0.0.0} : ${HostPattern:=`domainname`} [ -z "$HostPattern" ] && Fatal "please specify host string" # Determine the columns in the "arp" output for hostname # and ethernet address eval `$ARP | $NAWK ' BEGIN { namecol=0; addrcol=0; } { for ( i=1; i<=NF; ++i ) { field = $i if ( !namecol && field ~ /'"$HostPattern"'/ ) namecol = i if ( !addrcol && field ~ /^[0-9a-fA-F][0-9a-fA-F]*:/ ) addrcol = i if ( namecol && addrcol ) exit (0) } } END { print "namecol=" namecol print "addrcol=" addrcol } '` : ${namecol:=2} : ${addrcol:=4} trap 'rm -f "$Tmp" >/dev/null 2>&1' 0 trap "exit 2" 1 2 3 13 15 while : do $ARP | $NAWK ' BEGIN { Ethers = "'"$Ethers"'" while ( getline < Ethers ) { nameof [$1] = $2 } close (Ethers) } $addrcol ~ /^[0-9a-fA-F][0-9a-fA-F]*:/ { addr = $addrcol name = $namecol if ( nameof [addr] != "" ) { if ( nameof [addr] != name ) { print "WARNING: IP address for mac address " addr \ " changed from " name " to " nameof [addr] \ | "cat >&2" } } nameof [addr] = name } END { for ( addr in nameof ) { print addr, nameof [addr] } } ' namecol=$namecol addrcol=$addrcol > "$Tmp" && mv "$Tmp" "$Ethers" || exit [ "$Interval" = "0" ] && exit 0 sleep $Interval || exit done