Re: how to discover MAC address?

James E Robinson (jerobins@unity.ncsu.edu)
Wed, 16 Jul 1997 07:15:54 -0400

On Tue, Jul 15, 1997 at 06:42:14PM -0500, afarrior@vc.cc.tx.us wrote:
> At 06:14 PM 7/14/97 -0500, you wrote:
> >
> >i'd like to determine the hardware address for given a host IP address and
> >the appropriate router IP address.
> >
>
> ok, i made a VERY crude script if anyone is interested.
>

The following walks the routing tables to find the router to which an IP
address should be attached, then querries that router for the hardware
address of the given IP. It's a single Tcl script that essentially
impliments: ping - traceroute - query router

The following code is incomplete since it uses several supporting
wrapper functions...that can be trivially implimented or replaced with
the corresponding TNM library functions.

Enjoy, your mileage may vary...
James

# comments/questions about the following code will be read, but not
# replied to.....sorry, we're in the summer crunch time.
#
# A "better" _nts_cisco_int_find procedure needs to be written badly. I
# threw it together quickly and only tested it in our environment.

proc do_lookup { hostip } {

# ping the host so the hardware will show up in the routers
# ARP table.
icmp echo $hostip;

# oh where, oh where, might the interface be?
set int_info [_nts_cisco_int_find $hostip];
set cisco [lindex $int_info 0];
set int [lindex $int_info 1];

set hardware [_nts_cisco_get_hwdr_addr $cisco $int $hostip];

puts "$hostip has hardware address $hardware."
puts "$hostip found on router $cisco."
}

#-----------------------------------------------------------------------
# Function: _nts_cisco_int_find
#
# Accepts: ip address of host
# cisco hostname (for start of search only, optional)
#
# Returns: cisco hostname and interface index number
# where host is connected
# 0 - failure
#
# Notes: This function is *really* ugly and needs cleaning up bad.
#
#-----------------------------------------------------------------------
proc _nts_cisco_int_find { searchname {cisconame mydefault} } {

# clear the msg var in case we don't find it.
set msg 0;

# fix the names up
set cisco_ip [_nts_resolve_ip $cisconame];

if { $cisco_ip == 0 } {
return 0;
}

set search_ip [_nts_resolve_ip $searchname];

# be sure we are working with valid data
if { $search_ip == 0 } {
return 0;
}

set s [_nts_snmp_open $cisco_ip];

# mark where we begin
set prevhop $cisco_ip;

# split up the ip - like {152} {1} {157} {9}
set search_sub [split $search_ip "."];

# grab the 4th digit - like {9}
set node_num [lindex $search_sub 3];

# replace 4th with zero - leaves {152} {1} {157} {0}
set classc [lreplace $search_sub 3 3 "0"];

# replace 3rd with zero - leaves {152} {1} {0} {0}
set classb [lreplace $classc 2 2 "0"];

# make subnet number - like "152.1.157.0"
set search_net [join $classc "."];

# grab first 3 digits only - like "152.1.157"
set search_sub [lrange $classc 0 2];

# make an initial guess that we are on a standard class c net
# and try to get the real netmask

set rc 0;

while { $rc < 2 } {
# get the mask of the route
catch { set mask [$s get ipRouteMask.$search_net] } error_text;

if { [_nts_verify_snmp_connect $error_text] > 0 } {
incr rc;

# ok, it wasn't class c, try b
# make subnet number - like "152.1.0.0"

set search_net [join $classb "."];
set search_sub [lrange $classb 0 2];

continue;
} else {
break;
}
}
if { $rc == 2} {
# "SNMP Error: $error_text";
_nts_snmp_close $s;
return 0;
}

# ah, the real mask
set mask [lindex [lindex $mask 0] 2];

if { [string compare $mask "255.255.255.192"] == 0 } {
set net_num [expr $node_num & 192];
lappend search_sub $net_num;
} elseif { [string compare $mask "255.255.255.0"] == 0 } {
lappend search_sub 0;
} elseif { [string compare $mask "255.255.0.0"] == 0 } {
lappend search_sub 0;
} else {
# "Error: unknown netmask - $mask";
return 0;
}

set search_sub [join $search_sub "."];

set hop_cnt 0;

# don't loop forever
while { $hop_cnt < 8 } {
incr hop_cnt;

# get the router
catch { set nexthop [$s get ipRouteNextHop.$search_sub] } error_text;

if { [_nts_verify_snmp_connect $error_text] > 0 } {
# "SNMP Error: $error_text";
_nts_snmp_close $s;
return 0;
}
set nexthop [lindex [lindex $nexthop 0] 2];
if { [string compare $nexthop $prevhop] == 0 } {
# found it!
break;
} else {
set prevhop $nexthop;
$s configure -address $nexthop;
}
}

# be sure we didn't bounce around forever
if { $hop_cnt == 8 } {
# Not Found
_nts_snmp_close $s;
return 0;
}

# get the interface index
catch { set int [$s get ipRouteIfIndex.$search_sub] } error_text;

if { [_nts_verify_snmp_connect $error_text] > 0 } {
# "SNMP Error: $error_text";
_nts_snmp_close $s;
return 0;
}

set int [lindex [lindex $int 0] 2];

set cisconame [_nts_resolve_name $nexthop];

set msg [list $cisconame $int];

if { [_nts_verify_snmp_connect $error_text] > 0 } {
# "SNMP Error: $error_text";
set msg 0;
}

# clean-up...destroy the handle
_nts_snmp_close $s;

return $msg;
}

#-----------------------------------------------------------------------
# Function: _nts_cisco_get_hwdr_addr
#
# Accepts: name of cisco
# interface index number
# host ip
# optional community
#
# Returns: hardware address
# 0 - failure
#
#-----------------------------------------------------------------------
proc _nts_cisco_get_hwdr_addr { cisconame int_index ip {community public}} {

# this is the mib oid for ip and hwdr address
# format: ipNetToMediaPhysAddress.int_index.ip_addr: hardware_address
#
set oid "ipNetToMediaPhysAddress";

set hwdr_addr [_nts_snmp_get $cisconame $oid.$int_index.$ip $community];

return $hwdr_addr;
}

-- 
James E. Robinson, III | james@ncstate.net | Lead Systems Programmer
NC State University    |    NCState.Net    | http://www.ncstate.net/
Information Technology | PGP key at http://www.ncstate.net/james/pgp/
--
!! This message is brought to you via the `tkined & scotty' mailing list.
!! Please do not reply to this message to unsubscribe. To subscribe or
!! unsubscribe, send a mail message to <tkined-request@ibr.cs.tu-bs.de>.
!! See http://wwwsnmp.cs.utwente.nl/~schoenw/scotty/ for more information.