/* * Paglo Crawler * Copyright (C) 2006-2008 Paglo Labs Inc. All rights reserved. * www.paglo.com * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //--------------------------------------------------------------------------- #include "ParseCDP.h" #include "NetworkDevice.h" #include "ScanAgentUtils.h" #include "AnalysisManager.h" //--------------------------------------------------------------------------- void ParseCDP(TPacket *Pkt) { /* * Don't parse past this! */ const unsigned char *PktEnd = Pkt->GetData() + Pkt->GetCaptureLength(); /* * Make sure we have a CDP payload in the packet. If we do, then perform some * sanity checks. */ if (Pkt->CDPPayload) { TCDPHeader *CDPHdr = (TCDPHeader *)Pkt->CDPPayload; /* * I haven't seen examples of v.1, so we don't want to assume it's close * enough to try parsing it. */ if (CDPHdr->Version != 2) { return; } /* * Maybe verify the checksum here? */ /* * Go through the payload's elements. */ TCDPElement *Element = (TCDPElement *)((unsigned char *)CDPHdr + sizeof(TCDPHeader)); TDiscoveryProtoData CDPData; CDPData.ProtoType = DISCOVERY_PROTO_CDP; char *EscapedVersion = NULL; int DataLength = 0; unsigned char *ElementData = NULL; unsigned long CapabilitiesVec; string::iterator StrIterator; unsigned long NumAddresses = 0; TCDPAddressElement *AddrElement = NULL; unsigned long *AddressPtr = NULL; TIPAddress IPAddress; while (Element && (unsigned char *)Element < PktEnd) { DataLength = ntohs(Element->Length) - sizeof(TCDPElement); ElementData = (unsigned char *)Element + sizeof(TCDPElement); /* * SANITY CHECK: Make sure we won't access anything past the end of * the packet even if Element doesn't point past the end. */ if ((ElementData > PktEnd) || ((ElementData + DataLength) > PktEnd)) { break; } switch (ntohs(Element->Type)) { case CDP_ELEMENT_DEVICE_ID: CDPData.DeviceId = string((char *)ElementData, DataLength); break; case CDP_ELEMENT_ADDRESSES: NumAddresses = ntohl(*(unsigned long *)ElementData); AddrElement = (TCDPAddressElement *)(ElementData + sizeof(unsigned long)); for (unsigned int i = 0; i < NumAddresses && (unsigned char *)AddrElement < PktEnd; i++) { if (AddrElement->Protocol == 0xCC && ntohs(AddrElement->AddressLength) == 0x0004) { AddressPtr = (unsigned long *)((unsigned char *)AddrElement + sizeof(TCDPAddressElement)); if ((unsigned char *)AddressPtr > PktEnd) { break; } IPAddress = TIPAddress(ntohl(*AddressPtr)); } AddrElement = AddrElement + sizeof(TCDPAddressElement) + ntohs(AddrElement->AddressLength); } break; case CDP_ELEMENT_PORT_ID: CDPData.RemotePort = string((char *)ElementData, DataLength); break; case CDP_ELEMENT_CAPABILITIES: CapabilitiesVec = ntohl(*(unsigned long *)ElementData); if (CapabilitiesVec > 0x7F) { char HexStr[11]; snprintf(HexStr, 11, "0x%08lX", CapabilitiesVec); CDPData.Capabilities = HexStr; } else { if (CapabilitiesVec & CDP_CAP_ROUTER) { CDPData.Capabilities += "CDP_CAP_ROUTER,"; } if (CapabilitiesVec & CDP_CAP_TRANSPARENT_BRIDGE) { CDPData.Capabilities += "CDP_CAP_TRANSPARENT_BRIDGE,"; } if (CapabilitiesVec & CDP_CAP_SOURCE_BRIDGE) { CDPData.Capabilities += "CDP_CAP_SOURCE_BRIDGE,"; } if (CapabilitiesVec & CDP_CAP_SWITCH) { CDPData.Capabilities += "CDP_CAP_SWITCH,"; } if (CapabilitiesVec & CDP_CAP_HOST) { CDPData.Capabilities += "CDP_CAP_HOST,"; } if (CapabilitiesVec & CDP_CAP_IGMP) { CDPData.Capabilities += "CDP_CAP_IGMP,"; } if (CapabilitiesVec & CDP_CAP_REPEATER) { CDPData.Capabilities += "CDP_CAP_REPEATER,"; } StrIterator = CDPData.Capabilities.end(); StrIterator--; if (*StrIterator == ',') { CDPData.Capabilities.erase(StrIterator); } } break; case CDP_ELEMENT_VERSION: EscapedVersion = EscapeString(ElementData, DataLength); CDPData.Version = EscapedVersion; free(EscapedVersion); break; case CDP_ELEMENT_PLATFORM: CDPData.Platform = string((char *)ElementData, DataLength); break; case CDP_ELEMENT_REMOTE_VLAN: CDPData.RemoteVlan = ntohs(*(unsigned short *)ElementData); break; } /* * The Length field takes itself and the Type field, and the data into account. */ Element = (TCDPElement *)((unsigned char *)Element + ntohs(Element->Length)); } if (IPAddress.Valid()) { TNetworkDevice *NetDev = _AnalysisMgr->LookupOrCreateDevice(IPAddress); if (NetDev) { NetDev->AddEvidence(CDPData); } } } } //---------------------------------------------------------------------------