Sunday, June 9, 2013

Find Device Connected to Switch via Mac Address OUI

One of the task that we routinely have to do is to find out the devices connected to a particular switch or a group of switches. A good starting point is to query by the Mac OUI to find out the vendor of the Mac address (http://en.wikipedia.org/wiki/MAC_address). The reason it is only a starting point is you have to take into account vendors who make NIC for both end host and switches (i.e. D-Link), and company mergers and acquisition (i.e. Avaya and Tenovis GmbH & Co KG). But many times you can just knowing the OUI is enough (Cisco, Avaya, Polycom).

So the question becomes, how to do this programmatically? You can query it manually via IEEE, http://standards.ieee.org/develop/regauth/oui/public.html, but doing that for 1 host if fine, imagine doing that for a switch stack with hundreds of ports. Luckily, macvendors.com provides a nice API page to do just that, http://www.macvendors.com/api (note. please consider donating to their cause if you have some extra money http://www.macvendors.com/about :) ).

Trying this out in interactive prompt couldn't be easier:

>>> import urllib2
>>> url = "http://api.macvendors.com/"
>>> macOUI = "00:00:0c"
>>> urllib2.urlopen(url+macOUI).read()
'CISCO SYSTEMS, INC.'
>>>

A switch 'show mac address-table' output typically looks something like this (vlan, mac, learning, port). Note that this is a fake list with the host portion being ff.ffff.

$cat mac_list_fake.txt
  3    0004.0ff.ffff    DYNAMIC     Fa4/0/23
  2    000d.56ff.ffff    DYNAMIC     Fa3/0/30
  2    0012.3fff.ffff    DYNAMIC     Fa2/0/6
  2    0012.3fff.ffff   DYNAMIC     Fa2/0/40
$

If you put that in a text file, here is a script that splits that output and builds a dictionary with the key being the port and the value a list of (mac, vendor):

** start of script **

#!/usr/bin/env python

import sys, urllib2

url = "http://api.macvendors.com/"
fileName = sys.argv[1]

macFile = open(fileName, 'r')
portMap = {} #builds a dictionary of port: (mac, vendor)
for line in macFile.readlines():
    line = line.strip()
    vlan, mac, method, port = line.split()
    macOUI = mac[:7]
    response = urllib2.urlopen(url+macOUI).read()
    portMap[port] = (mac, response)

#pretty print
for key in portMap.keys():
    print "Port: %s, Mac Address: %s, Vendor: %s" % (key, portMap[key][0], portMap[key][1])

** end of script **

Executing the script will yield you the result you want:

$./macLookup.py mac_list_fake.txt
Port: Fa2/0/6, Mac Address: 0012.3fff.ffff, Vendor: Dell Inc
Port: Fa3/0/30, Mac Address: 000d.56ff.ffff, Vendor: Dell PCBA Test
Port: Fa2/0/40, Mac Address: 0012.3fff.ffff, Vendor: Dell Inc
Port: Fa4/0/23, Mac Address: 0004.0ff.ffff, Vendor: Asus Network Technologies, Inc.
$

I want to mention that Wireshark and IEEE provides a list that is a flat file so you can choose to build your own mapping without using the API if you dont want to depend on Internet connectivity for this.

http://anonsvn.wireshark.org/wireshark/trunk/manuf

Happy coding :).





1 comment: