#!/bin/bash # 1. Scan known networks for SNMP listeners (assumed to be switches) # # 2. Run snmpwalk on each switch to find out MAC addresses on each port # # 3. Convert MAC addresses to IPs and if possible hostnames # # 4. If a MAC address appears more than once in the list, there's a link between switches # - try to work out what's connected to what # # 5. Final outcome - list of MACs, IPs and hostnames plugged in to each switch port debug=0 tempfile=/tmp/switchscan.$$ required="nmap snmpwalk" for req in $required do if ! which $req &>/dev/null then echo "Sorry, but I need $req to be installed first." exit 1 fi done # Get a list of my local network connections, scan each in turn ip route list | grep -v default | cut -d' ' -f1,3 | while read network iface do [ "$debug" -ge "1" ] && echo "Scanning network $network on interface $iface for SNMP devices" >&2 # Find any SMNP managed switches (they'll be listening on UDP port 161) nmap -Pn -sU -p 161 $network 2>/dev/null | grep -B4 "161/udp open" | grep ^Nmap | rev | cut -d' ' -f1 | rev | tr -d '()' | while read IP do # Ask each switch what MAC addresses it has on each port snmpwalk -v2c -c public $IP .1.3.6.1.2.1.17.4.3.1.2 2>/dev/null | grep ^iso | cut -d'.' -f12- | grep -v ^1.128.194 | grep -v " = INTEGER: 0" | while read SNMPout # iso.3.6.1.2.1.17.4.3.1.2.56.234.167.167.63.123 = INTEGER: 5 do [ "$debug" -ge "2" ] && echo "SNMP response from $IP was $SNMPout" >&2 # Note the port number and convert each MAC address to hex MACdec=${SNMPout% = *} port=${SNMPout##* } MACh= for byte in `echo $MACdec | tr '.' ' '` do MACh=$MACh:`printf "%02x" $byte` done MAChex=${MACh#:} # Look up the MAC address in the arp table to see if we know its IP (and possibly hostname) rarp=`arp -a | grep $MAChex | tr -d '()' | cut -d' ' -f1,2,7 | tr -d '?'` subnet=${rarp##* } nameIP=${rarp% *} hostname=${rarp%% *} hostIP=${nameIP##* } echo "$IP port $port = ${subnet:--} $MAChex $hostIP $hostname" [ "$debug" -ge "2" ] && echo "$IP port $port = ${subnet:--} $MAChex $hostIP $hostname" >&2 done done # Send everything to a temp file so we can process later done >$tempfile.pass1 # What are our own interfaces' MAC addresses? ip route list | grep -v default | cut -d' ' -f3 | while read net do mac=`ifconfig $net | grep ether | tr -s ' ' | cut -d' ' -f3` if [ -n "$mac" ] then # If we find our own MAC address on a switch port, we're obviously connected (somehow) grep $mac $tempfile.pass1 | cut -d ' ' -f1-3 | while read swport do # Make sure we are the only thing on that port, otherwise it's an indirect connection [ `grep -c "^$swport " $tempfile.pass1` -eq 1 ] && echo "$swport is connected to my $net interface" done fi done echo # Get each switch's IP and see if other switches are plugged in to it cut -d' ' -f1 $tempfile.pass1 | sort -u | while read swIP do grep " $swIP " $tempfile.pass1 | cut -d' ' -f1-3 | while read conSW2 do if [ `grep -c " ${conSW2%% *} " $tempfile.pass1` -eq 1 ] then conSW1=`grep " ${conSW2%% *} " $tempfile.pass1 | cut -d ' ' -f1-3` # Output to another temporary file because we want the details later as well echo "$conSW1~$conSW2" fi done done >$tempfile.pass2 # Print the inter-switch connections to console cat $tempfile.pass2 | tr '~' ' ' | while read IP1 x1 port1 IP2 x2 port2 do echo "$IP1 port $port1 is connected to $IP2 port $port2" done | sort -nk3 echo # Look at the original results again but without the interconnected ports # This should just be the remaining client machines (sometimes more than one per port, due to unmanaged switches in between) cut -d' ' -f1 $tempfile.pass1 | sort -u | while read swIP do ( cat $tempfile.pass2 | tr '~' '\n'; ifconfig | grep HWaddr | tr -s ' ' | cut -d' ' -f5 ) | grep -vf - $tempfile.pass1 | grep "^$swIP " | while read s x1 port x2 net mac cIP cname do echo "$swIP port $port is connected to $mac $cIP ${cname:+($cname)}" done | sort -nk3 echo done # Tidy up temp files rm -f $tempfile.*