/* * 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 "ScanDHCP.h" #include "ScanThread.h" #include "ScanAgent.h" #include "NetworkDevice.h" #include "AnalysisManager.h" #include "Debug.h" //--------------------------------------------------------------------------- #pragma pack(push, 1) typedef struct { unsigned char Operation; unsigned char HardwareType; unsigned char HardwareAddrLen; unsigned char Hops; unsigned int TransactionID; unsigned short SecondsElapsed; unsigned short Flags; unsigned int ClientIPAddress; unsigned int YourIPAddress; unsigned int NextServerIPAddress; unsigned int RelayIPAddress; unsigned char MacAddress[6]; unsigned char UnusedHWAddr[10]; unsigned char ServerName[64]; unsigned char File[128]; unsigned int Cookie; } TDHCPHeader; #pragma pack(pop) /* * BOOTP and DHCP constants. */ #define BOOTP_OPERATION_REQUEST 0x01 #define BOOTP_ADDRESS_ETHERNET 0x01 #define DHCP_COOKIE 0x63825363 #define DHCP_OPTION_PAD 0 #define DHCP_OPTION_END 255 #define DHCP_OPTION_VENDOR_CLASS 60 #define DHCP_OPTION_HOST_NAME 12 #define DHCP_OPTION_PARAM_REQUEST_LIST 55 static string SanitizeString(string S) { char *NewS; NewS = EscapeString((unsigned char *)S.c_str(), S.length()); S = string(NewS); free(NewS); return S; } //--------------------------------------------------------------------------- void ProcessIPv4DHCPPacket(TPacket *Pkt) { DEBUG_MESSAGE(DEBUG_SCANDHCP, ("DHCP: received packet")); if (Pkt->Payload == NULL || (unsigned int)Pkt->Payload + sizeof(TDHCPHeader) - (unsigned int)Pkt->GetData() > Pkt->GetCaptureLength() || sizeof(TEthHeader) + Pkt->IPLength < Pkt->GetCaptureLength()) { /* Packet is too short. */ DEBUG_MESSAGE(DEBUG_SCANDHCP, ("DHCP: ignoring packet: too short")); return; } TDHCPHeader *Hdr = (TDHCPHeader*)Pkt->Payload; unsigned int UDPHeaderLength = Pkt->Payload - Pkt->GetData(); unsigned int OptionsLength = Pkt->IPLength - (UDPHeaderLength + sizeof(TDHCPHeader)); if (UDPHeaderLength + sizeof(TDHCPHeader) + OptionsLength > Pkt->GetCaptureLength()) { /* Options too long. */ DEBUG_MESSAGE(DEBUG_SCANDHCP, ("DHCP: ignoring packet: options too long")); return; } if (Hdr->Operation != BOOTP_OPERATION_REQUEST) { /* Unhandled operation type. */ DEBUG_MESSAGE(DEBUG_SCANDHCP, ("DHCP: ignoring packet: unhandled operation type")); return; } if (Hdr->HardwareType != BOOTP_ADDRESS_ETHERNET) { /* We only handle Ethernet devices. */ DEBUG_MESSAGE(DEBUG_SCANDHCP, ("DHCP: ignoring packet: not an ethernet device")); return; } if (ntohl(Hdr->Cookie) != DHCP_COOKIE) { /* Not a DHCP packet. */ DEBUG_MESSAGE(DEBUG_SCANDHCP, ("DHCP: ignoring packet: not a DHCP packet (is BOOTP)")); return; } TMacAddress MacAddr(Hdr->MacAddress); if (MacAddr.Valid()) { unsigned int OptionIndex = 0; const unsigned char *Options = Pkt->Payload + sizeof(TDHCPHeader); TIPAddress ClientIP(ntohl(Hdr->ClientIPAddress)); /* * Process the options. */ string VendorClass, HostName, ParamRequestList; while (OptionIndex < OptionsLength) { unsigned char Option = Options[OptionIndex++]; int OptionLen = 0; if (Option != DHCP_OPTION_PAD && Option != DHCP_OPTION_END) { if (OptionIndex < OptionsLength) { OptionLen = Options[OptionIndex++]; if (OptionIndex + OptionLen > OptionsLength) { /* Option length is longer than remaining space. */ break; } } else { /* Not enough space to read option length. */ break; } } switch (Option) { case DHCP_OPTION_PAD: break; case DHCP_OPTION_END: OptionIndex = OptionsLength; break; case DHCP_OPTION_VENDOR_CLASS: VendorClass = string((char*)&Options[OptionIndex], OptionLen); OptionIndex += OptionLen; break; case DHCP_OPTION_HOST_NAME: HostName = string((char*)&Options[OptionIndex], OptionLen); OptionIndex += OptionLen; break; case DHCP_OPTION_PARAM_REQUEST_LIST: /* * Translate the params to a list of integers. */ for (int i = 0; i < OptionLen; i++) { if (ParamRequestList.length() > 0) { ParamRequestList += ","; } char Buf[20]; sprintf(Buf, "%d", Options[OptionIndex + i]); ParamRequestList += Buf; } OptionIndex += OptionLen; break; default: /* * An unknown option, skip the content. */ OptionIndex += OptionLen; } } /* * Now find the appropriate device and add the evidence. */ TNetworkDevice *NetDev = _AnalysisMgr->LookupOrCreateDevice(MacAddr); if (NetDev) { DEBUG_MESSAGE(DEBUG_SCANDHCP, ("DHCP: Adding evidence to %s: VendorClass=%s HostName=%s ParamRequestList=%s", MacAddr.Print().c_str(), VendorClass.c_str(), HostName.c_str(), ParamRequestList.c_str())); TDHCPData Data(SanitizeString(VendorClass), SanitizeString(HostName), ParamRequestList); NetDev->AddEvidence(Data); /* * Set the IP address if we have better information now. */ if (!NetDev->GetIPAddress().Valid() && ClientIP.Valid()) { NetDev->SetIPAddress(ClientIP); } } } } //---------------------------------------------------------------------------