2
* cdpr - Cisco Discovery Protocol Reporter
3
* Copyright (c) 2002-2006 MonkeyMental.com
5
* This program will show you which Cisco device your machine is
6
* connected to based on CDP packets received.
8
* This program is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU General Public License
10
* as published by the Free Software Foundation; either version 2
11
* of the License, or (at your option) any later version.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
* 1.0.0 LO 02-06-30 Initial Release
25
* 1.0.1 LO 02-07-01 ifdef/endif DLT types to deal with older bpf.h headers
26
* 1.0.2 LO 02-07-02 New filter to better identify CDP packets
27
* 1.0.3 LO 02-07-03 loop on pcap_next until a valid packet is received.
28
* (patch provided Martin Buck <martin.buck@ascom.ch>)
29
* 1.0.4 LO 02-07-10 Added 1ms timeout to pcap_open_live to fix *BSD
30
* 1.0.5 LO 02-07-14 Copy packet data to local struct to resolve Bus Errors
32
* 1.0.6 LO 02-07-15 More alignment fixes.
33
* 1.0.7 LO 02-10-29 Port to Win32, autodetection and list generation of
34
* PCAP capable devices.
35
* 1.0.8 LO 03-02-13 Port to arm processor (Zaurus) using a filter specific
36
* to arm processors to work around pcap bug
37
* 1.1.0 LO 03-04-25 Add central server reporting code
38
* 1.1.1 LO 03-04-26 Fix compile errors for Win32 on server code
39
* 1.1.2 LO 03-04-27 Add config file support
40
* 1.1.3 LO 03-04-28 Add location/description flag for extended info on server
41
* Split server code and conf file code into seperate source files
42
* Cleanup old server/config file code. Remove cond. compile for CDPRS
43
* Create cdpr.h for ext. functions and common defines.
44
* Add DNS support to the config file so you can specify a hostname
45
* 1.1.4 LO 03-06-20 Added -n flag to override hostname sent to server. Added error
46
* checking to the socket code.
47
* 1.1.5 LO 03-06-23 Fix bug where hostname would not be transmitted w/o location set
48
* 2.0.0 LO 03-06-25 Release - Major revision change due to server reporting code
49
* 2.0.1 LO 03-07-01 Add sys/types.h to the includes in conffile.c for BSD support
50
* 2.0.2 LO 03-08-03 Enable timeouts so that cdpr won't wait forever looking for a packet
51
* 2.0.3 LO 03-08-04 Better cleanup after aborting due to timeout.
52
* 2.0.4 LO 03-08-05 Timeout code that actually timesout. Set device to nonblocking
53
* mode and loop until packet or timeout. Before, pcap_next would
54
* block so the signal handler couldn't acutally exit.
55
* 2.0.5 LO 03-10-22 Went back to pcap_next() to get the packet, add a default timeout
56
* of 5 minutes. Got rid of pktcap.c and timeout.c as they are no
58
* 2.1.0 LO 03-11-08 Release - Got timeout code working on WIN32 port
59
* 2.2.0 LO 04-04-14 Added the ability specify the port to send the cdpr updates to.
60
* 2.2.1 LO 06-07-28 Fixed segfault when not providing port to a command line selected server (-s)
63
/*#include "pcap.h" */
81
dump_ip (const u_char *ip)
86
sprintf (switch_ip, "switch_ip=%d.%d.%d.%d",
87
(int) ip[0], (int) ip[1], (int) ip[2], (int) ip[3]);
88
cdprs_action(CDPRS_DATA, switch_ip, 0);
90
printf ("%d.%d.%d.%d",
91
(int) ip[0], (int) ip[1], (int) ip[2], (int) ip[3]);
95
dump_hex (const u_char *p, int len)
99
printf ("%02X ", *p++);
104
dump_ascii (const u_char *p, int len)
108
printf ("%c", (*p < ' ' || *p > '~') ? '.' : *p);
114
dump_data (const u_char *p, int len)
118
for (i = 0; i < len; i += 16, p += 16)
128
get_cdp_type (int type)
132
for (i = 0; type_vals[i].type != 0; ++i)
134
if (type == type_vals[i].type)
136
return type_vals[i].val;
139
return "Unknown type";
143
print_cdp_address (u_char *v, int verbose)
148
memcpy (&number, v, sizeof (number));
149
number = ntohl (number);
153
printf (" number: %d\n", number);
156
v += sizeof (u_int32_t);
157
for (i = 0; i < number; ++i)
159
u_char protocol = *v;
160
u_char protocol_len = *(v+1);
161
u_char *protocol_val = v+2;
162
/* int address_len = ntohs(*((u_int16_t *)(v+2+protocol_len)));*/
163
u_int16_t address_len;
164
u_char *address_val = v+2+protocol_len+2;
166
memcpy (&address_len, (v+2+protocol_len), sizeof(address_len));
167
address_len = ntohs(address_len);
172
printf (" protocol: %02x\n", protocol);
173
printf (" protocol len: %02x\n", protocol_len);
174
printf (" protocol val: ");
175
dump_hex (protocol_val, protocol_len);
178
printf (" address len: %02x\n", address_len);
179
printf (" address val: ");
185
if (protocol_len == 1 && *protocol_val == 0xCC && address_len == 4)
186
dump_ip (address_val);
188
dump_hex (address_val, address_len);
191
v += (2+protocol_len+2+address_len);
196
print_cdp_capabilities (u_char *v)
200
memcpy (&cap, v, sizeof (cap));
203
printf (" value: %08x\n", cap);
204
if (cap & 0x01) printf (" Performs level 3 routing for at least one network layer protocol.\n");
205
if (cap & 0x02) printf (" Performs level 2 transparent bridging.\n");
206
if (cap & 0x04) printf (" Performs level 2 source-route bridging.\n");
207
if (cap & 0x08) printf (" Performs level 2 switching.\n");
208
if (cap & 0x10) printf (" Sends and receives packets for at least one network layer protocol.\n");
209
if (cap & 0x20) printf (" The bridge or switch does not forward IGMP Report packets on nonrouter ports.\n");
210
if (cap & 0x40) printf (" Provides level 1 functionality.\n");
214
print_cdp_packet (const u_char *p, unsigned int plen, int verbose)
222
// dump_data (p, 128);
226
printf ("\ncdp packet:\n");
227
printf (" version: %02x\n", h->version);
228
printf (" time to live: %02x\n", h->time_to_live);
229
printf (" checksum: %04x\n", ntohs (h->checksum));
232
d = (CDP_DATA *) (p + sizeof (CDP_HDR));
233
plen -= sizeof (CDP_HDR);
235
while (plen > sizeof (CDP_DATA))
239
u_char *v; /* variable data */
240
int vlen; /* length of variable data */
243
memcpy (&data, d, sizeof (CDP_DATA));
244
type = ntohs (data.type);
245
length = ntohs (data.length);
246
v = (u_char *) d + sizeof (CDP_DATA);
247
vlen = length - sizeof (CDP_DATA);
251
printf ("\ncdp type/len/val:\n");
252
printf (" type: %04x - %s\n", type, get_cdp_type (type));
253
printf (" length: %04x\n", length);
258
printf ("%s\n", get_cdp_type (type));
259
printf (" value: %.*s\n", vlen, v);
263
printf ("%s\n", get_cdp_type (type));
264
print_cdp_address (v, verbose);
268
printf ("%s\n", get_cdp_type (type));
269
printf (" value: %.*s\n", vlen, v);
275
portval = urlencode(v, strlen(v), &portlen);
276
sprintf(port, "&port=%.*s", portlen, portval);
278
cdprs_action(CDPRS_DATA, port, verbose);
282
case TYPE_CAPABILITIES:
285
printf ("%s\n", get_cdp_type (type));
286
print_cdp_capabilities (v);
290
case TYPE_IOS_VERSION:
293
printf ("%s\n", get_cdp_type (type));
294
printf (" value: %.*s\n", vlen, v);
301
printf ("%s\n", get_cdp_type (type));
302
printf (" value: %.*s\n", vlen, v);
309
printf ("%s\n", get_cdp_type (type));
316
case TYPE_VTP_MGMT_DOMAIN:
319
printf ("%s\n", get_cdp_type (type));
320
printf (" value: %.*s\n", vlen, v);
324
case TYPE_NATIVE_VLAN:
327
printf ("%s\n", get_cdp_type (type));
337
printf ("%s\n", get_cdp_type (type));
347
printf ("%s\n", get_cdp_type (type));
355
d = (CDP_DATA *) ((u_char *) d + length);
361
print_dlt(pcap_t *handle)
365
/* Print the DLL Type*/
366
switch(type = pcap_datalink(handle))
370
printf("Data Link Type: BSD Loopback encapsulation.\n");
375
printf("Data Link Type: Ethernet (10MB, 100MB, 1000MB and up).\n");
380
printf("Data Link Type: IEEE 802.5 Token Ring.\n");
385
printf("Data Link Type: ARCNET.\n");
390
printf("Data Link Type: PPP (Point-to-Point Protocol).\n");
395
printf("Data Link Type: FDDI.\n");
398
#ifdef DLT_ATM_RFC1483
399
case DLT_ATM_RFC1483:
400
printf("Data Link Type: RFC 1483 LLC/SNAP-encapsulated ATM.\n");
405
printf("Data Link Type: raw IP.\n");
408
#ifdef DLT_PPP_SERIAL
410
printf("Data Link Type: PPP in HDLC-like framing.\n");
415
printf("Data Link Type: PPPoE.\n");
420
printf("Data Link Type: Cisco PPP with HDLC framing.\n");
423
#ifdef DLT_IEEE802_11
425
printf("Data Link Type: IEEE 802.11 wireless LAN.\n");
430
printf("Data Link Type: OpenBSD loopback encapsulation.\n");
435
printf("Data Link Type: Apple LocalTalk.\n");
439
printf("%d is an unknown Data Link Transport\n", type);
448
puts("d: Specify device to use (eth0, hme0, etc.)");
449
puts("h: Print this usage");
450
puts("t: time in seconds to abort waiting for a packet (should be > 60)");
451
puts("v[vv]: Set verbose mode");
452
puts("\n** Options dealing with server updates: **");
453
puts(" u: Send cdpr information to a cdpr server\n requires config file as arg");
454
puts(" l: Location/description of this port for use with -u or -s and -p");
455
puts(" n: Override the hostname reported to the server for use with -u or -s and -p");
456
puts(" s: Server to send information to specify port with a : after Server/IP\n Example: 192.168.1.20:88 (default: 80) requires -p (overridden by -u)");
457
puts(" p: Path of server script to send data to requires -s (overridden by -u)");
463
main(int argc, char *argv[])
472
char errbuf[PCAP_ERRBUF_SIZE];
473
struct bpf_program filter;
475
** Filter Expression: 01:00:0c:cc:cc:cc Multicast Mac Address
476
** This filter doesn't work on the arm, so use all multicast
477
** ether[20:2] = 0x2000: CDP signature in LLC
480
char filter_app[] = "ether multicast and ether[20:2] = 0x2000";
482
char filter_app[] = "ether host 01:00:0c:cc:cc:cc and ether[20:2] = 0x2000";
486
struct pcap_pkthdr header;
487
const u_char *packet;
488
char version[] = "2.2.1";
496
unsigned int seconds=300;
499
/* Zero out some global variables */
502
memset (errbuf, 0, sizeof (errbuf));
504
/* Print out header */
505
printf("cdpr - Cisco Discovery Protocol Reporter\nVersion %s\n", version);
506
printf("Copyright (c) 2002-2006 - MonkeyMental.com\n\n");
508
/* Check command-line options */
509
while((c = getopt(argc, argv, "d:t:vhu:l:n:s:p:")) !=EOF)
519
seconds = atoi(optarg);
520
printf("Timeout enabled for %u seconds\n", seconds);
528
puts("Overriding command line server arguments with config file\n");
531
cdprs_action(CDPRS_INIT, conf, 0);
545
puts("Config file overrides cmd line");
549
if(cdprs != 1) cdprs = 1;
557
puts("Config file overrides cmd line");
561
if(cdprs != 1) cdprs = 1;
572
** If we are using command line server paths, validate and buld
573
** build data structure using functions that are normally used
574
** when parsing the config file
576
if(cdprs && (cdprs_cmdline == 2))
578
cdprs_action(CDPRS_INIT, "", 0);
579
do_something_with(svr, path);
581
else if(cdprs && (cdprs_cmdline != 0))
583
puts("Error only -s or -p was specified but not both");
587
/* Get a pcap capable device */
595
/* The user didn't provide a packet source: Retrieve the device list */
596
if (pcap_findalldevs(&alldevs, errbuf) == -1)
598
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
603
for(d=alldevs; d; d=d->next)
605
printf("%d. %s", ++i, d->name);
607
printf(" (%s)\n", d->description);
609
printf(" (No description available)\n");
614
printf("\nNo interfaces found! Make sure pcap is installed.\n");
618
printf("Enter the interface number (1-%d):",i);
621
if(inum < 1 || inum > i)
623
printf("\nInterface number out of range.\n");
624
/* Free the device list */
625
pcap_freealldevs(alldevs);
629
/* Jump to the selected adapter */
630
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++)
638
printf("Using Device: %s\n", dev);
640
/* Get the network number and netmask */
641
pcap_lookupnet(dev, &net, &mask, errbuf);
643
/* Open the pcap device */
644
if((handle = pcap_open_live(dev, BUFSIZ, 1, 0, errbuf)) == NULL)
646
printf("Error opening device (%s)\n", errbuf);
649
else if (strlen(errbuf))
651
printf("Warning opening device (%s)\n", errbuf);
654
/* Compile the pcap filter */
655
pcap_compile(handle, &filter, filter_app, 0, net);
657
/* Activate the pcap filter */
658
pcap_setfilter(handle, &filter);
659
pcap_freecode(&filter);
661
/* Set non-blocking mode */
662
if(pcap_setnonblock(handle, 1, errbuf))
664
pcap_perror(handle, NULL);
667
/* Get the next packet that comes in, we only need one */
668
printf("Waiting for CDP advertisement:\n");
669
printf("(default config is to transmit CDP packets every 60 seconds)\n");
671
/* Get current time to check for timeout */
672
start_time = time(NULL);
675
packet = pcap_next(handle, &header);
681
} while ((!packet) && ( timeout=((start_time+seconds) > (unsigned int)time(NULL))) );
684
** timeout expired. clean up and exit
688
puts("Aborting due to timeout");
693
/* Print its length */
696
printf("Received a CDP packet, header length: %d\n", header.len);
699
// print cdp packet, 22 bytes into packet
700
print_cdp_packet (packet+22, header.len-22, verbose);
714
if(nameoverride >= 1)
716
get_hostname(nameoverride, name);
720
get_hostname(0, NULL);
723
cdprs_action(CDPRS_SEND, "", verbose);