EN 
06.12.2025 Mikuláš WELCOME IN MY WORLD

This website is originally written in the Czech language. Most content is machine (AI) translated into English. The translation may not be exact and may contain errors.

Tento článek si můžete zobrazit v originální české verzi. You can view this article in the original Czech version.
Zjištění MAC adresy zařízení na portu switche pomocí SNMP a PHP

Discovering the MAC address of the device on the switch port using SNMP and PHP

| Petr Bouška - Samuraj |
In previous articles I described how to find out basic information about the ports on the switch. And how to complete the information by assigning the port to a VLAN. In this episode, I'll cover another interesting extension, finding out the MAC address of the device that is connected to the port. This can come in handy in a number of situations, for example a computer starts communicating on our network and we need to find out where it is physically located. I tested the procedure on Cisco Catalyst 2960, 3750, 6500 switches, but it should be applicable to other brands as well.
displayed: 29 345x (28 069 CZ, 1 276 EN) | Comments [5]

Similar to determining the port's VLAN assignment, finding the MAC address on the port is not entirely straightforward. The way a switch works is that it creates a table of port and MAC address assignments, and then sends data at the second layer (OSI model layer 2) based on this table. Moreover, it maintains these tables independently for each VLAN. This means that we need to download this table from the switch. This table is referred to as the CAM table (Content Addressable Memory) or simply the MAC address table.

The general procedure looks like this:

  1. create a list of ports with basic information
  2. assign to the ports whether they are in trunk mode or not
  3. create a list of VLANs
  4. go through the VLANs and create a MAC address and port table for each one
  5. go through the MAC address tables and based on the port, add the MAC address to the port list where the port is not a trunk

Note: In the example, I assume that only an end device is connected to the port, so a maximum of one address will be found for the port. Or that the port is a trunk that connects it to another switch, and then I'm not interested in the MAC addresses. If a switch/hub or, for example, an IP phone to which a PC is connected is connected somewhere, I will get multiple MAC addresses for one port and would have to create an array.

Creating a List of Ports/Interfaces

This step was resolved in the article Switch port information using SNMP and PHP.

Determining Trunk Ports

This step was addressed in the article Port to VLAN information for Cisco Switches using SNMP and PHP.

List of VLANs

This step was addressed in the article Port to VLAN information for Cisco Switches using SNMP and PHP.

Iterating Through VLANs and Loading CAM Tables

To download the MAC address and port table, we will use the BRIDGE-MIB MIB file. In it, there is .iso.org.dod.internet.mgmt.mib-2.dot1dBridge.dot1dTp.dot1dTpFdbTable with OID = 1.3.6.1.2.1.17.4.3, and we are interested in the following OIDs:

Name OID Description
dot1dTpFdbAddress .1.3.6.1.2.1.17.4.3.1.1 list of MAC addresses for which the switch has forward information
dot1dTpFdbPort .1.3.6.1.2.1.17.4.3.1.2 port number on which the given MAC address was learned
dot1dTpFdbStatus .1.3.6.1.2.1.17.4.3.1.3 record status, we're interested in 3 = learned

To access these values, the hybrid community string is used again (Cisco calls this method community string indexing), because there is only one instance in the MIB and we need to get the values for each VLAN. We append @VLAN to the community string, so for example public@30 to load the values from VLAN 30. If we don't use this extension, the values from VLAN 1 are returned.

Using snmpwalk, we go through the OID for dot1dTpFdbAddress, which gives us a list of MAC addresses. The OID is supplemented with several numeric indices after its number. One returned record may look like this:

[17.4.3.1.1.0.11.205.197.114.60] =>  Hex: 00 0B CD C5 72 3C

In the same way, we go through dot1dTpFdbStatus and determine whether to count this MAC address.

[17.4.3.1.1.0.11.205.197.114.60] =>  3

And using dot1dTpFdbPort, we get the corresponding port numbers.

[17.4.3.1.1.0.11.205.197.114.60] => 54

By combining the values with the same index, in this case 0.11.205.197.114.60, we get that the MAC address 00:0B:CD:C5:72:3C is on port 54. However, we work with port indices (IfIndex), so we still need to find the assignment of the index to the port number (we have already used this OID for VLANs).

Name OID Description
dot1dBasePortIfIndex .1.3.6.1.2.1.17.1.4.1.2 returns the interface index for the given port number

Here, the index is given by the last value, which is the port number for which we are looking for the `ifIndex`.

[17.1.4.1.2.54] => 10202

Implementation in PHP

The following code contains only the function for obtaining MAC addresses and builds on the code from the previous parts.

// loads all values under the OID and returns them as an array, the index is the last number of the OID
function getInterPart2(&$interfaces, $ip, $comm, $oid) {
	$array = snmprealwalk($ip, $comm, $oid);
	foreach($array as $key => $val) {
		$index = ereg_replace('.*\.([0-9]+)$', "\\1", $key);
		$val = format_snmp_string($val);
		$interfaces[$index] = $val;
	}
}
// loads all values under the OID and returns them as an array, the index is composed of several last numbers of the OID
function getInterPart3(&$interfaces, $ip, $comm, $oid) {
	$array = snmprealwalk($ip, $comm, $oid);
	$oidl = strlen($oid) - 12;
	foreach($array as $key => $val) {
		$index = substr($key, $oidl);
		$val = format_snmp_string($val);
		$interfaces[$index] = $val;
	}
}
// fills the port array with the MAC address
function getMACs(&$interfaces, $ip, $comm) {
	$vlans = array();
	getInterPart($vlans, $ip, $comm, ".1.3.6.1.4.1.9.9.46.1.3.1.1.18", "Index");      // VLAN ifIndex 
	getInterPart($vlans, $ip, $comm, ".1.3.6.1.4.1.9.9.46.1.3.1.1.3", "Type");        // VLAN type, 1 - OK 
	foreach($vlans as $vlan_id => $vlan) 
		if($vlan["Type"] == 1) {
			$macs = array();
			getInterPart3($macs, $ip, $comm."@".$vlan_id, ".1.3.6.1.2.1.17.4.3.1.1");   // list of MAC addresses for the given VLAN
			$bridge = array(); 
			getInterPart3($bridge, $ip, $comm."@".$vlan_id, ".1.3.6.1.2.1.17.4.3.1.2"); // determine which bridge port the MAC address belongs to
			$ifI = array();
			getInterPart2($ifI, $ip, $comm."@".$vlan_id, ".1.3.6.1.2.1.17.1.4.1.2");    // determine the interface index for the bridge port
			foreach($macs as $id => $mac) {          // go through the list of MAC addresses
				$ifIndex = $ifI[$bridge[$id]];       // get the ifIndex from the record index, converted to port number and then to ifIndex
				if($interfaces[$ifIndex]["Trunk"] == 2) $interfaces[$ifIndex]["MAC"] = $mac;
				else $interfaces[$ifIndex]["MAC"] = "";
			}
		}
}
Author:

Related articles:

SNMP

Simple Network Management Protocol (SNMP) is very useful for managing a computer network.

If you want write something about this article use comments.

Comments
  1. [1] neco

    Mam prosbu.

    Jak mam zjistit fyzickou topologii?

    Resp chci detekovat i spoje mezi switchi, ktere spannig tree algoritmus "blokuje".

    S tim ze je i zakazan(neni podporovan) CDP.

    Moc dik za odpověďl

    Saturday, 08.11.2008 14:44 | answer
  2. [2] maka

    great post ;)

    my Czech is not that good so excuse me if you have pointed this out, but just to clarify - the numerical indexes after dot1dTpFdbAddress in the example are actually the decimal equivalents of the 6 hex tuples of the mac address ;)

    Friday, 22.03.2013 20:08 | answer
  3. [3] jimmy

    ve funkci getMACs je imho chybka, alespon u me to takhle nefungovalo. Konkretne se jedna o radek

    $ifI[$bridge[$id]]; // ifIndex dostaneme z indexu záznamu, převedený na číslo portu a pak na ifIndex

    ve kterem je predano $id, ale toto $id se musi v jednom cisle OID lisit. Da se to vyresit nasledovne:

    $ifI[$bridge[str_replace(".1.17.4.3.1.1", ".1.17.4.3.1.2", $id]];

    Tuesday, 20.08.2013 12:49 | answer
  4. [4] jimmy

    respond to [3]jimmy: jeste opravene TYPO

    $ifI[$bridge[str_replace(\".1.17.4.3.1.1\", \".1.17.4.3.1.2\", $id)]];

    Tuesday, 20.08.2013 12:50 | answer
  5. [5] Samuraj

    respond to [3]jimmy: Je to už hodně dlouho, co jsem se tomu věnoval, než bych si to osvěžil, tak by to zabralo moc času. Ale tak, jak je to v příkladu, to mám i v aplikaci, kterou stále používám, a vše funguje korektně.

    Tuesday, 27.08.2013 08:36 | answer
Add comment

Insert tag: strong em link

Help:
  • maximum length of comment is 2000 characters
  • HTML tags are not allowed (they will be removed), you can use only the special tags listed above the input field
  • new line (ENTER) ends paragraph and start new one
  • when you respond to a comment, put the original comment number in squar brackets at the beginning of the paragraph (line)