O autorovi:
Autorem tohoto článku je Petr Macek, kterého můžete kontaktovat na e-mailu petr.macek@kostax.cz.
Popis CDP protokolu
CDP (Cisco Discovery Protocol) je jedním z několika dnes používaných discovery protokolů. Jedná se o protokol druhé (linkové vrstvy), který byl vyvinut firmou Cisco. Ač se jedná o proprietární protokol této firmy, někteří další výrobci ho začali používat, např. Mikrotik nebo HP. Protokol slouží k nalezení přímo připojených zařízení ke switchi nebo routeru. Když se takto doptáme všech switchů v síti, můžeme získat kompletní mapu sítě.
Princip protokolu je jednoduchý. Switch periodicky (výchozí hodnota je 60 vteřin) odesílá tzv. CDP oznámení (CDP announcements). To je multicastový rámec s cílovou adresou 01-00-0c-cc-cc-cc
. V tomto rámci jsou informace o typu zařízení, verzi OS, portu, kterým byl rámec odeslán, IP adresa a další. Když takový rámec zachytí jiný switch s podporou CDP, uloží si tyto informace do tabulky. Každý záznam má nastaven hold time (výchozí stav je 180 vteřin) - čas, po který je v tabulce záznam udržován. Pokud přijde po minutě stejné CDP oznámení, pouze se znovu nastaví max. holdtime a záznam zůstává v tabulce. Když dojde k rozpojení kabelu, nepřichází oznámení a po vypršení holdtime se záznam z tabulky odstraní.
Získávání informací
Jak obsah tabulky vypadá, můžeme zjistit následujícím příkazem
3750_stack# show cdp neighbors Capability Codes: R - Router, T - Trans Bridge, B - Source Route Bridge S - Switch, H - Host, I - IGMP, r - Repeater, P - Phone, D - Remote, C - CVTA, M - Two-port Mac Relay Device ID Local Intrfce Holdtme Capability Platform Port ID 2960_horni_nopoe Gig 2/0/26 131 S I WS-C2960S Gig 1/0/50 2960_horni_nopoe Gig 1/0/26 131 S I WS-C2960S Gig 1/0/49 2960_horni_poe Gig 2/0/25 153 S I WS-C2960S Gig 1/0/50 2960_horni_poe Gig 1/0/25 153 S I WS-C2960S Gig 1/0/49
Pokud použijeme příkaz show cdp neighbors detail
, získáme podstatně více informací. Tyto informace jsou dostupné také přes SNMP (Simple Network Management Protocol) protokol.
pm@router ~ $ snmpwalk -On -v1 -c public 192.168.99.100 1.3.6.1.4.1.9.9.23.1.2.1.1 .1.3.6.1.4.1.9.9.23.1.2.1.1.3.10120.29 = INTEGER: 1 .1.3.6.1.4.1.9.9.23.1.2.1.1.3.10121.5 = INTEGER: 1 .1.3.6.1.4.1.9.9.23.1.2.1.1.3.10122.6 = INTEGER: 1 .1.3.6.1.4.1.9.9.23.1.2.1.1.4.10120.29 = Hex-STRING: C0 A8 63 5E .1.3.6.1.4.1.9.9.23.1.2.1.1.4.10121.5 = Hex-STRING: C0 A8 63 62 .1.3.6.1.4.1.9.9.23.1.2.1.1.4.10122.6 = Hex-STRING: C0 A8 63 61 .1.3.6.1.4.1.9.9.23.1.2.1.1.7.10120.29 = STRING: "GigabitEthernet1/0/23" .1.3.6.1.4.1.9.9.23.1.2.1.1.7.10121.5 = STRING: "GigabitEthernet1/0/48" .1.3.6.1.4.1.9.9.23.1.2.1.1.7.10122.6 = STRING: "GigabitEthernet1/0/48" ...
Důležité OID je 1.3.6.1.2.1.17.1.1.0, kde je uvedena nejnižší MAC adresa zařízení (to platí i pro další protokoly, jako je LLDP, STP). Tento údaj nám pomůže při identifikaci.
OID 1.3.6.1.4.1.9.9.23.1.2.1.1 je tabulka nazývaná CDPCacheTable, která obsahuje vše, co potřebujeme. Nás konkrétně zajímají hodnoty
- OID 1.3.6.1.4.1.9.9.23.1.2.1.1.3 - typ adresy (1=ip, 20=ipv6). Nás tedy budou zajímat položky, kde typ = 1, tedy IPv4.
- OID 1.3.6.1.4.1.9.9.23.1.2.1.1.7 - název vzdáleného portu (GigabitEthernet1/0/23).
- OID 1.3.6.1.4.1.9.9.23.1.2.1.1.4 - IP zapsaná v šestnáctkové soustavě
Pokud tuto tabulku čteme pomocí snmprealwalk, tak předposlední část vráceného OID je index portu, ke kterému se záznam vztahuje. Pomocí poslední části pak informace o portu, IP a další, spojíme.
Jak tedy konkrétně v PHP postupovat?
$local_switch_id = snmpget($host,$community,"1.3.6.1.2.1.17.1.1.0"); // nacteni hodnot do poli $adresy = snmprealwalk($host,$community,"1.3.6.1.4.1.9.9.23.1.2.1.1.3"); $porty = snmprealwalk($host,$community,"1.3.6.1.4.1.9.9.23.1.2.1.1.7"); $ip = snmprealwalk($host,$community,"1.3.6.1.4.1.9.9.23.1.2.1.1.4"); // vytvoreni pole, kdy indexem je index portu. Znovu data oindexovvavat neni // zcela nutne, zalezi na tom, co s daty dal chceme delat foreach($adresy as $key=>$value) { $pos = strrpos ($key,"."); $index= substr ($key,-(strlen($key)-$pos-1)); $xindexy[$index] = $value; } // stejne tak pro vzdalene porty foreach($porty as $key=>$value) { $pos = strrpos($key,"."); $index = substr($key,-(strlen($key)-$pos-1)); $xporty[$index] = substr($value,1,-1); } // stejne tak pro IP, kde jeste navic prepocitame adresu z sestnactkove soustavy do desitkove foreach($ip as $key=>$value) { $pos = strrpos($key,"."); $index= substr($key,-(strlen($key)-$pos-1)); unset($adresa_hex,$adresa_dec); $value = trim(substr($value, strpos($value," "))); $adresa_hex = explode(" ", $value); foreach($adresa_hex as $key=>$val) { $adresa_dec .= hexdec($val) . "."; } $adresa_dec = substr($adresa_dec,0,-1); $xip[$index] = $adresa_dec; } // a vypiseme vysledek, v tomto pripade vypisuji pouze switche s IPv4 adresou foreach($xindexy as $key=>$value) { if($value == "INTEGER: 1") { // jednoduchym dotazem se muzeme jeste doptat na lokalni jmeno portu // staci snmpget 1.3.6.1.2.1.2.2.1.2.$key echo "Local switch id: $local_switch_id | \n"; echo "Index lokalniho portu: $key | \n"; echo "Port protistrany: $xporty[$key] | \n"; echo "IP adresa protistrany: $xip[$key] <br/>\n"; } }
PHP kód není kompletní, bylo by nutné se stejným způsobem zeptat všech nalezených aktivních prvků a dle spojů nakreslit topologii. Toto platí pro síť postavenou na Cisco zařízeních se zapnutým CDP protokolem. V případě sítě postavené na různých výrobcích je nutné doptávat se na další protokoly jako je LLDP (Link Layer Discovery Protocol) nebo STP.
Zatím zde nejsou žádné komentáře.