1 /*
2 * CDPSnarf CDP packet sniffer
3 * Copyright (C) 2006-2010 Anastasios "Zapotek" Laskos
4 * <tasos.laskos@gmail.com>
5 * <zapotek@segfault.gr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 /**
23 * @author: Zapotek <zapotek@segfault.gr>
24 * @description:
25 * CDPSnarf is a network sniffer exclusively written to extract
26 * information from CDP packets.
27 * It provides all the information a "show cdp neighbors detail"
28 * command would return on a Cisco router and even more.
29 *
30 * Example output:
31 * -----------------------------------------------------------
32 * CDPSnarf v0.1.5 initiated.
33 * Author: Zapotek <zapotek@segfault.gr>
34 * Website: http://www.segfault.gr
35
36 * Waiting for a CDP packet...
37 *
38 * [#1] Sniffed CDP advertisement with a size of 406 bytes.
39 * 0 seconds since last advertisement.
40 * -------------------------------------------------------
41 * Source MAC address: 0x00:0x0D:0xED:0x42:0xCD:0x02
42 *
43 * CDP Version: 2
44 * TTL: 180 ms
45 * Checksum: 0x2033
46 *
47 * Device ID: cisco-router-1.lab
48 *
49 * Addresses:
50 * Address #: 1
51 * Protocol type: [1] NLPID format
52 * Protocol: IP
53 * Address: 192.168.0.20
54 *
55 *
56 * Address #: 2
57 * Protocol type: [2] 802.2 format
58 * Protocol: IPv6
59 * Address: FE80:0000:0000:0000:0250:56FF:FEC0:000700
60 *
61 *
62 * Port ID: FastEthernet1/2
63 *
64 * Capabilities:
65 * [0x08] Switch
66 * [0x20] IGMP
67 *
68 * Software version: Cisco Internetwork Operating System Software
69 * IOS (tm) C2950 Software (C2950-I6Q4L2-M), Version 12.1(19)EA1a, RELEASE SOFTWARE (fc1)
70 * Copyright (c) 1986-2003 by cisco Systems, Inc.
71 * Compiled Tue 09-Dec-03 00:12 by yenanh
72 *
73 * Platform: cisco WS-C2950-12
74 *
75 * Protocol Hello:
76 * OUI: Cisco
77 * Protocol ID: Cluster Management
78 * Cluster Master IP address: 0.0.0.0
79 * Unknown (IP address?): 255.255.255.255
80 * Version: 1
81 * Sub Version: 2
82 * Status: 0x21
83 * Unknown: 0xFF
84 * Cluster Commander MAC address: 0x00:0x00:0x00:0x00:0x00:0x00
85 * Switch's MAC address: 0x00:0x0D:0xDF:0x67:0x00:0xCD
86 * Unknown: 0xFF
87 * Management VLAN: 0
88 *
89 *
90 * VTP Management Domain:
91 *
92 * Native VLAN: 279
93 *
94 * Duplex: [0x01] Full
95 *
96 * Trust Bitmap: 0
97 *
98 * Untrusted Port CoS: 0
99 *
100 * Management Address:
101 * Address #: 1
102 * Protocol type: [0] NLPID format
103 * Protocol: IP
104 * Address: 192.168.0.20
105 * -----------------------------------------------------------
106 *
107 * In the absence of a Makefile compile with:
108 * gcc -lm -lpcap cdpsnarf.c -o cdpsnarf
109 */
110
111 /*
112 * CDP packet format from Cisco:
113 * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm#xtocid12
114 *
115 * Additional info from Cisco:
116 * http://www.cisco.com/en/US/products/hw/switches/ps663/products_tech_note09186a0080094713.shtml#cdp
117 *
118 * Wireshark ouput:
119 * http://wiki.wireshark.org/CDP
120 *
121 */
122
123 #include <pcap.h>
124 #include <stdio.h>
125 #include <stdlib.h>
126 #include <ctype.h>
127 #include <errno.h>
128 #include <string.h>
129 #include <math.h>
130 #include <time.h>
131 #include <unistd.h>
132 #include <netinet/in.h>
133 #include "cdpsnarf.h"
134
135 #define VERSION "v0.1.6"
136 #define SVN_REV "$Rev: 797 $"
137
138 void tlv_parse( const u_char* , int );
139 int tlv_get_number( const u_char*, int );
140 u_char* tlv_get_text( const u_char* , int );
141
142 void print_cdp_addresses( const u_char *, int, int );
143 void print_ipv6_address( const u_char *, int );
144 void print_ipv4_address( int );
145 void print_ip_prefixes( const u_char *, int );
146 void print_capabilities( int );
147 void print_protoname( int );
148 void print_help( char ** );
149 void print_bin( int );
150 void payload2hex( const u_char *, int, char * );
151
152 int* hex2ipv4( int );
153 char* get_assoc_value( int, assoc_array * );
154 //int compute_checksum( const u_char *, int );
155
156 int debug = 0;
157
main(int argc,char * argv[])158 int main( int argc, char *argv[] ) {
159
160 // PCAP session handler
161 pcap_t *handle = 0;
162 // PCAP dumper pointer
163 pcap_dumper_t *dumper = 0;
164
165 // the compiled pcap filter
166 struct bpf_program fp;
167 // header structure returned by PCAP
168 struct pcap_pkthdr *header;
169
170 // expression filter for CDP packets
171 char filter_exp[] = "ether[12:2] <= 1500 && ether[14:2] == 0xAAAA"
172 " && ether[16:1] == 0x03 && ether[17:2] == 0x0000"
173 " && ether[19:1] == 0x0C && ether[20:2] == 0x2000"
174 " && ether host 01:00:0C:CC:CC:CC";
175 // device to sniff on
176 char *dev = NULL;
177 // error buffer
178 char errbuf[ PCAP_ERRBUF_SIZE ];
179
180 // our netmask
181 bpf_u_int32 mask = 0;
182 // our IP address
183 bpf_u_int32 net = 0;
184
185 // pcap_next_ex()'s return value
186 int pcap_packet = 1;
187 // captured packet's payload
188 u_char *data;
189
190 time_t timer = 0;
191
192 char *dumpfile = NULL;
193 int c;
194 int i = 0;
195
196 printf( "CDPSnarf %s [%s] initiated.\n", VERSION, SVN_REV );
197
198 // get command line arguments
199 while( ( c = getopt( argc, argv, "i:dhw:r:" ) ) != -1 ) {
200 switch( c ) {
201 case 'i':
202 dev = optarg;
203 handle = pcap_open_live( dev, BUFSIZ, 1, 269000, errbuf );
204
205 if( handle == NULL ) {
206 fprintf( stderr, "Couldn't open device %s: %s\n", dev, errbuf );
207 return( 2 );
208 }
209
210 // get device properties
211 if( pcap_lookupnet( dev, &net, &mask, errbuf ) == -1 ) {
212 fprintf( stderr, "Couldn't get netmask for device %s: %s\n",
213 dev, errbuf );
214 net = 0;
215 mask = 0;
216 }
217 break;
218
219 case 'd':
220 debug = 1;
221 break;
222
223 case 'r':
224 dumpfile = optarg;
225 handle = pcap_open_offline( dumpfile, errbuf );
226 if( !handle ){
227 fprintf( stderr, "Couldn't open file %s: %s\n",
228 dumpfile, errbuf );
229 return( 2 );
230 }
231
232 net = 0;
233 mask = 0;
234 break;
235
236 case 'w':
237 dumper = pcap_dump_open( handle, optarg );
238 if( !dumper ){
239 fprintf( stderr, "Couldn't write to file %s: %s\n",
240 optarg, errbuf );
241 }
242 break;
243
244 case '?':
245 if( optopt == 'd' || optopt == 'w' ) {
246 fprintf( stderr, "Option -%c requires an argument.\n",
247 optopt );
248 } else if( isprint ( optopt ) ) {
249 fprintf( stderr, "Unknown option `-%c'.\n", optopt );
250 } else {
251 fprintf( stderr, "Unknown option character `\\x%x'.\n",
252 optopt );
253 }
254 return 1;
255
256 case 'h':
257 default:
258 print_help( argv );
259 return( 0 );
260
261 }
262 }
263
264 if( !dev && !dumpfile ) {
265 print_help( argv );
266 return( 0 );
267 }
268
269 // compile filter
270 if( pcap_compile( handle, &fp, filter_exp, 0, mask ) < 0 ) {
271 fprintf( stderr, "Couldn't parse filter %s: %s\n", filter_exp,
272 pcap_geterr( handle ) );
273 return( 2 );
274 }
275
276 // apply compiled filter
277 if( pcap_setfilter( handle, &fp ) < 0 ) {
278 fprintf( stderr, "Couldn't install filter %s: %s\n", filter_exp,
279 pcap_geterr( handle ) );
280 return( 2 );
281 }
282
283 printf( "Reading packets from %s.\n", ( dev ) ? dev : dumpfile );
284 printf( "Waiting for a CDP packet...\n\n" );
285
286 // loop forever
287 while( pcap_packet == 1 ) {
288
289 // grab a packet
290 pcap_packet =
291 pcap_next_ex( handle, &header, (const u_char **) &data );
292
293 // write each packet to the dumpfile as soon as it arrives
294 if( dumper ){
295 pcap_dump( (u_char *)dumper, header, data );
296 pcap_dump_flush( dumper );
297 }
298
299 // handle error cases
300 switch( pcap_packet ){
301 // EOF
302 case -2:
303 printf( "End of file reached.\nNo more packets to analyze.\n" );
304 return( 0 );
305
306 // unexpected error
307 case -1:
308 fprintf( stderr, "An error occured while capturing packet.\n" );
309 return( 2 );
310
311 // timeout
312 case 0:
313 fprintf( stderr, "Timeout waiting for CDP packet.\n" );
314 // who cares, just keep waiting...
315 pcap_packet = 1;
316 continue;
317 }
318
319
320 // tell user we grabed a packet and it's length
321 printf( "[#%d] Sniffed CDP advertisement with a size of %d bytes.\n",
322 i++, header->len );
323
324 // if this is not our first packet display time delta
325 if( i > 1 ) {
326 printf( " %.0f seconds since last advertisement.\n",
327 difftime( time( 0 ), timer ) );
328 }
329
330 printf( "-------------------------------------------------------" );
331
332 // start timer
333 timer = time( 0 );
334
335 // parse TLV tree
336 tlv_parse( data, header->len );
337
338 printf( "\n" );
339 }
340
341 // close session
342 pcap_close( handle );
343
344 return( 0 );
345 }
346
347 /**
348 * Function for Type/Length/Value structure parsing (like CDP frames)
349 * It traverses the TLV structure and prints out CDP data.
350 *
351 * @param const u_char* payload the packet data
352 * @param int length the packet length
353 *
354 */
tlv_parse(const u_char * payload,int length)355 void tlv_parse( const u_char* payload, int length ) {
356
357 // the next "Type" field
358 int tlv_type;
359 // the next "Length" field
360 int tlv_length;
361 int addresses_num, duplex;
362 int offset = 0;
363 int tmp = 0;
364 u_char* value;
365 // unsigned short our_checksum;
366
367 printf( "\nSource MAC address: " );
368 payload2hex( payload + MAC_OFFSET, 6, ":" );
369
370 // compute_checksum( payload, length );
371
372 // set payload pointer right after Ethernet and LLC data
373 payload += ENCAP_OFFSET;
374
375 // get CDP version
376 printf( "\nCDP Version: %d\n", *(payload++) );
377
378 // get CDP time-to-live
379 printf( "TTL: %d ms\n", *(payload++) );
380
381 // get checksum
382 tmp = tlv_get_number( payload, 2 );
383 printf( "Checksum: 0x%02X ", tmp );
384 payload += 2;
385
386 // our_checksum = crc16_checksum( payload, length - ENCAP_OFFSET - 4 );
387
388 // printf( "\n---------------\n" );
389 // payload2hex( payload, length - ENCAP_OFFSET - 4, " 0x" );
390 // printf( "\n---------------\n" );
391
392 // if( our_checksum == tmp ) {
393 // printf( "[Correct, 0x%02X]", our_checksum );
394 // } else {
395 // printf( "[Invalid, should be 0x%02X]", our_checksum );
396 // }
397
398 printf( "\n\n" );
399
400 // subtract Ethernet & LLC encapsulation
401 length -= ENCAP_OFFSET + 4;
402 // parse TLV until we reach the end of packet data
403 while( length ) {
404
405 // get next Type
406 tlv_type = tlv_get_number( payload, TLV_TYPE_SIZE );
407 if( debug ) printf( "[TLV type: 0x%02X]\n", tlv_type );
408 // appropriately forward the pointer
409 payload += TLV_TYPE_SIZE;
410
411 // get next Length
412 tlv_length = tlv_get_number( payload, TLV_LENGTH_SIZE );
413 if( debug ) printf( "[TLV length: %d bytes]\n", tlv_length );
414 /*
415 * subtract the length of the Type field and the Length field to
416 * accurately get the length of the Value field
417 */
418 tlv_length -= TLV_TYPE_SIZE + TLV_LENGTH_SIZE;
419 // appropriately forward the pointer
420 payload += TLV_LENGTH_SIZE;
421
422 // print current type name
423 printf( "%s: ", TYPE_NAMES[tlv_type] );
424
425 switch( tlv_type ) {
426
427 // addresses are special because the require further parsing
428 case TYPE_ADDRESS:
429 case TYPE_MANAGEMENT_ADDR:
430 // get the number of addresses included in the packet
431 addresses_num = tlv_get_number( payload, 4 );
432 // parse addresses into the addresses struct
433 print_cdp_addresses( payload, addresses_num, tlv_length );
434 break;
435
436 // capabilities require bitmask matching
437 case TYPE_CAPABILITIES:
438 printf( "\n" );
439 print_capabilities( tlv_get_number( payload, tlv_length ) );
440 break;
441
442 // nothing special about duplex, just requires a bit more logic
443 case TYPE_DUPLEX:
444 duplex = tlv_get_number( payload, tlv_length );
445
446 printf( "[0x%02x] %s\n", duplex,
447 ( duplex ) ? "Full" : "Half" );
448 break;
449
450 case TYPE_PROTOCOL_HELLO:
451 printf( "\n" );
452
453 tmp = tlv_get_number( payload, 3 );
454
455 printf( " OUI: %s\n", get_assoc_value( tmp, OUI_NAMES ) );
456 offset += 3;
457
458 tmp = tlv_get_number( payload + offset, 2 );
459
460 printf( " Protocol ID: %s\n",
461 get_assoc_value( tmp, type_hello_vals ) );
462
463 if( tmp == TYPE_HELLO_CLUSTER_MGMT ){
464 offset += 2;
465
466 printf( " Cluster Master IP address: " );
467 tmp = tlv_get_number( payload + offset, 4 );
468 print_ipv4_address( tmp );
469 offset += 4;
470
471 printf( "\n Unknown (IP address?): " );
472 tmp = tlv_get_number( payload + offset, 4 );
473 print_ipv4_address( tmp );
474 offset += 4;
475
476 printf( "\n Version: %d\n",
477 tlv_get_number( payload + offset, 1 ) );
478 offset += 1;
479
480 printf( " Sub Version: %d\n",
481 tlv_get_number( payload + offset, 1 ) );
482 offset += 1;
483
484 printf( " Status: 0x%02X\n",
485 tlv_get_number( payload + offset, 1 ) );
486 offset += 1;
487
488 printf( " Unknown: 0x%02X\n",
489 tlv_get_number( payload + offset, 1 ) );
490 offset += 1;
491
492 printf( " Cluster Commander MAC address: " );
493 payload2hex( payload + offset, 6, ":" );
494 offset += 6;
495
496 printf( " Switch's MAC address: " );
497 payload2hex( payload + offset, 6, ":" );
498 offset += 6;
499
500 printf( " Unknown: 0x%02X\n",
501 tlv_get_number( payload + offset, 1 ) );
502 offset += 1;
503
504 printf( " Management VLAN: %d\n",
505 tlv_get_number( payload + offset, 1 ) );
506 offset += 1;
507 }
508
509 printf( "\n" );
510 break;
511
512 case TYPE_POWER_AVAILABLE:
513 printf( "\n" );
514 printf( " Request ID: %u(?)\n",
515 tlv_get_number( payload, 4 ) );
516 offset += 4;
517
518 printf( " Management ID: %u(?)\n",
519 tlv_get_number( payload + offset, 4 ) );
520 offset += 4;
521
522 tmp = tlv_get_number( payload + offset, TLV_LENGTH_SIZE );
523 printf( " Power Available: %u mW(?)\n",
524 tlv_get_number( payload + offset, 2 ) );
525
526 break;
527
528 case TYPE_TRUST_BITMAP:
529 tmp = tlv_get_number( payload, 2 );
530 printf( "0x%02X", tmp );
531 if( tmp ) {
532 printf( "[" );
533 print_bin( tmp );
534 printf( "]" );
535 }
536 printf( "\n" );
537 break;
538
539 case TYPE_IP_PREFIX:
540 printf( "\n" );
541 print_ip_prefixes( payload, tlv_length );
542 break;
543
544 case TYPE_MTU:
545 case TYPE_NATIVE_VLAN:
546 case TYPE_UNTRUSTED_COS:
547 printf( "%u\n", tlv_get_number( payload, 2 ) );
548 break;
549
550 // the rest type values are just text, so print the text
551 default:
552 value = tlv_get_text( payload, tlv_length );
553 printf( "%s\n", value );
554 free( value );
555 break;
556 }
557
558 tmp = 0;
559 offset = 0;
560 // forward pointer to the next TLV
561 payload += tlv_length;
562 // lessen the length variable
563 length -= tlv_length + TLV_TYPE_SIZE + TLV_LENGTH_SIZE;
564
565 printf( "\n" );
566
567 }
568
569 }
570
571 /**
572 * Function for getting a number residing in the next "length" bytes
573 * of the payload
574 *
575 * @param const u_char* payload the payload
576 * @param int length the aforementioned length
577 *
578 * @return int the aforementioned number
579 */
tlv_get_number(const u_char * payload,int length)580 int tlv_get_number( const u_char* payload, int length ) {
581 int z, tl;
582 long div;
583
584 tl = 0x0;
585 for( div = pow( 0x100, length - 1 ), z = 0;
586 z < length;
587 div /= 0x100, z++ )
588 {
589 tl += ( div ) ? *payload++ * div : *payload++ ;
590 }
591
592 return tl;
593 }
594
595 /**
596 * Function for getting a string residing in the next "length" bytes
597 * of the payload
598 *
599 * @param const u_char* payload the payload
600 * @param int length the aforementioned length
601 *
602 * @return const u_char* the aforementioned string
603 */
tlv_get_text(const u_char * payload,int length)604 u_char* tlv_get_text( const u_char* payload, int length ) {
605 u_char* value;
606
607 value = malloc( length + 1);
608 memcpy( value, payload, length );
609 value[length] = '\0';
610
611 return value;
612 }
613
614 /**
615 * Function for parsing the Addresses field of the CDP packet into
616 * addresses struct
617 *
618 * @param const u_char *payload payload pointer located right
619 * before the addresses field
620 *
621 * @param int address_num the number of included addresses
622 * @param int address_len the length of the field
623 *
624 */
print_cdp_addresses(const u_char * payload,int address_num,int address_len)625 void print_cdp_addresses( const u_char *payload, int address_num,
626 int address_len )
627 {
628 int i;
629
630 payload += 4;
631
632 // save enough space for all included addresses
633 addresses = calloc( address_num, address_len );
634 /*
635 * loop thought all the addresses harvesting data and storing them
636 * into the appropriate members of addresses
637 */
638 for( i = 0; i < address_num; addresses++, i++ ) {
639 printf( "\n Address #: %d\n", i + 1 );
640 addresses->proto_type = *payload++;
641
642 if( debug )
643 printf( "[Protocol type: 0x%04X]\n", addresses->proto_type );
644
645 printf( " Protocol type: [%d] %s format\n",
646 addresses->proto_type,
647 PROTO_TYPES[addresses->proto_type] );
648
649 addresses->proto_len = *payload++;
650 if( debug )
651 printf( "[Protocol length: %d bytes]\n", addresses->proto_len );
652
653 /*
654 * The cool thing with protocols other than IP and ISO CLNS
655 * (whose protocol length is 1 byte)
656 * is that they all have a suffix of 0xaaaa03000000 so we can
657 * ignore it and store only the 2 last hex values (ex. 86dd for IPv6)
658 *
659 */
660 if( addresses->proto_len == 8 ) {
661 addresses->proto =
662 tlv_get_number( payload + (addresses->proto_len - 2), 2 );
663 } else {
664 addresses->proto =
665 tlv_get_number( payload, addresses->proto_len );
666 }
667
668 if( debug )
669 printf( "[Address protocol: 0x%04X]\n", addresses->proto );
670
671 printf( " Protocol: " );
672 print_protoname( addresses->proto );
673 printf( " \n" );
674
675 payload += addresses->proto_len;
676
677 addresses->address_len =
678 tlv_get_number( payload, TLV_LENGTH_SIZE );
679
680 if( debug )
681 printf( "[Address length: %d bytes]\n", addresses->address_len );
682
683 payload += TLV_LENGTH_SIZE;
684
685 printf( " Address: " );
686 if( addresses->address_len <= 4 ) {
687 print_ipv4_address( tlv_get_number( payload, addresses->address_len ) );
688 } else {
689 print_ipv6_address( tlv_get_text( payload, addresses->address_len ),
690 addresses->address_len );
691 }
692 printf( "\n\n" );
693
694 payload += addresses->address_len;
695 }
696
697 addresses -= i;
698
699 free( addresses );
700 }
701
702 /**
703 * Function for convertng hexadecimal IP addresses to decimal parts
704 * ( ex. 0xC0A80014 to 192.168.0.20 )
705 *
706 * @param int hex hexadecimal format of IP address
707 *
708 * @return array with 4 entries holding each IP address decimal value
709 */
hex2ipv4(int hex)710 int* hex2ipv4( int hex ) {
711 int *ip_address;
712
713 ip_address = calloc( 4, sizeof(int) );
714
715 ip_address[3] = hex & 0xff;
716 ip_address[2] = (hex & 0xff00) / 0x100;
717 ip_address[1] = (hex & 0xff0000) / 0x10000;
718 ip_address[0] = (hex & 0xff000000) / 0x1000000;
719
720 return ip_address;
721 }
722
723 /**
724 * Print IPv4 address based on a hexadecimal value
725 *
726 * @param int hex hex version of the IP address
727 *
728 */
print_ipv4_address(int hex)729 void print_ipv4_address( int hex ) {
730 int *ip_address;
731
732 ip_address = hex2ipv4( hex );
733 printf( "%u.%u.%u.%u",
734 ip_address[0],
735 ip_address[1],
736 ip_address[2],
737 ip_address[3] );
738
739 free( ip_address );
740 }
741
742 /**
743 * Print IPv6 address based on a hexadecimal string
744 *
745 * @param const u_char *payload hex string of the IP address
746 * @param int length length of the IP address
747 *
748 */
print_ipv6_address(const u_char * payload,int length)749 void print_ipv6_address( const u_char *payload, int length ) {
750 do {
751 printf( "%02X", *payload++ );
752 if( length != 1 && length % 2 ) printf( ":" );
753 } while( length-- );
754 }
755
756 /**
757 * Prints IPv4 prefixes
758 *
759 * @param const u_char *payload payload right before the IP prefixes
760 * @param int length length of the IP prefixes
761 *
762 */
print_ip_prefixes(const u_char * payload,int length)763 void print_ip_prefixes( const u_char *payload, int length ) {
764 int iterations, offset = 0, i = 1;
765
766 for( iterations = length / 5; iterations; iterations--, offset += 5 ) {
767 printf( " [%d] ", i++ );
768 print_ipv4_address( tlv_get_number( payload + offset, 4 ) );
769 printf( "/%d\n", tlv_get_number( payload + 4 + offset, 1 ) );
770 }
771
772 }
773
774 /**
775 * Print help message
776 *
777 * @param char *argv[] program command line arguments
778 *
779 */
print_help(char * argv[])780 void print_help( char *argv[] ) {
781 printf( "%s -i <dev> [-h] [-w savefile] [-r dumpfile] [-d]\n\n", argv[0] );
782 printf( " -i define the interface to sniff on\n" );
783 printf( " -w write packets to PCAP dump file\n" );
784 printf( " -r read packets from PCAP dump file\n" );
785 printf( " -d show debugging information\n" );
786 printf( " -h show help message and exit\n\n" );
787 }
788
789 /**
790 * Function for printing device's capabilities
791 *
792 * @param int bitmask hexadecimal capabilities' bitmask
793 *
794 */
print_capabilities(int bitmask)795 void print_capabilities( int bitmask ) {
796 int i;
797
798 // loop through all capability bitmasks searching for matches
799 for( i = 0; i < sizeof CAPABILITIES / sizeof (int); i++ ) {
800 // print match
801 if( CAPABILITIES[i] & bitmask )
802 printf( " [0x%02X]\t%s\n", CAPABILITIES[i],
803 CAPABILITIES_NAMES[i] );
804 }
805 }
806
807 /**
808 * Function for printing protocol in use
809 *
810 * @param int hex hexadecimal protocol ID
811 *
812 */
print_protoname(int hex)813 void print_protoname( int hex ) {
814 int i;
815
816 for( i = 0; i < sizeof PROTO_NAMES / sizeof (char); i++ ) {
817 if( PROTO[i] == hex ) {
818 printf( "%s", PROTO_NAMES[i] );
819 return;
820 }
821
822 }
823 printf( "Uknown" );
824 }
825
826 /**
827 * Simple debugging function for printing a given payload as a
828 * sequence of hexadecimal values
829 *
830 * @param const u_char *payload the payload
831 * @param int length how much of the payload to print
832 * @param char *delim delimiter between hex values
833 *
834 */
payload2hex(const u_char * payload,int length,char * delim)835 void payload2hex( const u_char *payload, int length, char *delim ) {
836
837 while( length-- ) {
838 printf( "%02X", *payload++ );
839 if( length != 0 ) printf( "%s", delim );
840 }
841 printf( "\n" );
842
843 }
844
845 /**
846 * Function used with the "_assoc_array" struct in order to get
847 * stored strings based on the stored values
848 *
849 * @param int value the value to look for
850 * @param assoc_array *aray the struct
851 *
852 * @return char *
853 */
get_assoc_value(int value,assoc_array * array)854 char* get_assoc_value( int value, assoc_array *array ){
855 int i = 0;
856 while( array[i].string ){
857 if( array[i].value == value ) return (char *) array[i].string;
858 i++;
859 }
860 return 0;
861 }
862
863 /**
864 * Print binary representation of a number
865 *
866 * @param int num number to convert to binary
867 */
print_bin(int number)868 void print_bin( int number ) {
869 int remainder;
870
871 if( number <= 1 ) {
872 printf( "%d", number );
873 return;
874 }
875
876 remainder = number % 2;
877 print_bin( number >> 1 );
878 printf( "%d", remainder );
879 }
880
881 //int compute_checksum( const u_char *payload, int length ) {
882 // u_char *data;
883 //
884 // data = malloc( length + 20 );
885 //
886 // memcpy( data, payload, ENCAP_OFFSET + 2 );
887 // data += ENCAP_OFFSET + 2;
888 // memcpy( data, payload + ENCAP_OFFSET + 4, length - 2 );
889 // data -= ENCAP_OFFSET + 2;
890 //
891 // payload2hex( payload, length, " 0x" );
892 // printf( "\n-----------------\n" );
893 // payload2hex( data, length - 2, " 0x" );
894 //
895 // printf( "\n:::: 0x%04X ::::\n", crc16_checksum( data, length - 2 ) );
896 // printf( ":::: 0x%04X ::::\n", crc16_checksum( payload, length ) );
897 //
898 // free( data );
899 //
900 // return( 1 );
901 //}
902