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