2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008 Herbert Haas
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License version 2 as published by the
7 * Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
19 /////////////////////////////////////////////////////////////////////
23 /////////////////////////////////////////////////////////////////////
31 "| CDP type: Send arbitrary CDP packets.\n" \
33 "| - The Ethernet dst and src MAC addresses can be specified but can be also 'rand'.\n" \
34 "| - If dst and src are NOT specified then practical defaults are used (src=own MAC, dst=01:00:0C:CC:CC:CC).\n" \
36 "| ARGUMENT SYNTAX: -t cdp [arguments]\n" \
40 "| version ...... 0-255, default: 2\n" \
41 "| ttl ...... 0-255, default: 180 s\n" \
42 "| sum ...... 0000-ffff, default: automatically computed\n" \
44 "| TLVs: Description: Example:\n" \
46 "| tlv_id ....... Device ID Mausezahn station\n" \
47 "| tlv_address ....... Sending interface address 10.1.1.2\n" \
48 "| tlv_portid ....... Port Identifier 2/23\n" \
49 "| tlv_cap ....... Capabilities (hex<7f) 2a\n" \
50 "| tlv_version ....... Software Version ver3.0\n" \
51 "| tlv_platform ....... Hardware Platform WS-C6509-E\n" \
52 "| tlv_vtpdomain ....... VTP Management Domain MyVTPdomain\n" \
53 "| tlv_native ....... Native VLAN number (0-4095) 42\n" \
54 "| tlv_duplex ....... Full or half duplex full\n" \
55 "| tlv_mgmt ....... Management IP address 192.168.1.2\n" \
57 "| tlv .......... Create ANY TLV using the format: tlv=<type>/<value>, such as tlv=42/mausezahn\n" \
58 "| Note: Currently you must omit spaces within <value>! Use underscore instead.\n" \
59 "| tlvhex .......... Create ANY TLV and specify the value in hexformat, such as tlv=42/ca:fe:ba:be\n" \
60 "| payload|p .......... Optional additional TLVs or any other bytes specified in hex\n" \
62 "| When the tlv* arguments are used, the TLV length parameter is automatically set.\n" \
64 "| The capability flags from MSB to LSB are:\n" \
65 "| 0 - Repeater - IGMP - Host - Switch - SrcRouteBrdg - TranspBrdg - Router\n" \
67 "| Optionally the keyword 'change' will create a different System name TLV every time a CDP\n" \
68 "| packet is sent. This can be used to fill up a CDP database with different test values.\n" \
69 "| Additionally use the '-a rand' command to use different source MAC addresses.\n" \
73 "| Announce Device ID 'Espresso3000', Capabilities: Router, native VLAN 301:\n" \
74 "| mz eth0 -t cdp \"tlv_id=Espresso3000, tlv_cap=01, tlv_native=301\"\n" \
76 "| Create another TLV using the payload interface (here voice VLAN 400):\n" \
77 "| mz eth0 -t cdp p=00:0e:00:07:01:01:90\n"
83 u_int16_t
checksum16 (u_int16_t len
, u_int8_t buff
[])
90 // make 16 bit words out of every two adjacent 8 bit words in the packet and add them up
91 for (i
=0; i
<len
; i
=i
+2)
93 word16
=((buff
[i
]<<8)&0xFF00)+(buff
[i
+1]&0xFF);
94 sum
= sum
+ (u_int32_t
) word16
;
97 // take only 16 bits out of the 32 bit sum and add up the carries
99 sum
= (sum
& 0xFFFF)+(sum
>> 16);
101 // one's complement the result
104 return ((u_int16_t
) sum
);
108 // Creates a TLV and returns the whole length of the TLV
109 unsigned int create_tlv (u_int16_t type
, // The 16-bit TYPE number
110 u_int8_t
*value
, // The VALUE as prepared hex-array
111 unsigned int value_len
, // needed because VALUE maybe not \0 terminated
112 u_int8_t
*target
) // the RESULT i. e. the complete TLV
117 x
= (u_int8_t
*) &type
; // set TYPE
121 tlvlen
= value_len
+ 4; // set VALUE
122 x
= (u_int8_t
*) &tlvlen
;
127 memcpy((void*) target
, (void*) value
, (size_t) value_len
);
135 // NOTE: The Length field indicates the total length, in bytes, of the type, length, and value fields!
142 // 0003 Port ID such as 2/22
143 // 0004 Capabilities (Len=8, consists of flags only: Router, TBrdg, SRBrdgm, Switch, Host, IGMP, Repeater)
147 // 000a Native VLAN, e.g. 00:0a 00:06 01:2d identifies native VLAN number 301 (=01:2d)
149 // 000e VoIP VLAN, e.g. 00:0e 00:07 01 01:90 identifies DATA (=01) and VLAN 400 (=01:90)
151 // 0013 Untrusted Port CoS
152 // 0014 System Name (!!!)
153 // 0015 System Object Identifier
154 // 0016 Management Address (!!!), e.g. 0016 0011(=len 17) 00-00-00-01(=one IP only) 01-01-cc-00-04-90-fe-f8-10(=144.254.248.16)
156 // 001a Unknown (???)
158 // The IP address format is a bit strange as 0016 for example demonstrates...
167 errbuf
[LIBNET_ERRBUF_SIZE
],
171 packet
[MAX_PAYLOAD_SIZE
], // this one will finally contain the whole cdp packet (without LLC/SNAP!)
173 value
[1024], // USE THIS FOR ANYTHING YOU LIKE !!!
174 value1
[1024], // This one is reserved for some code - Don't use it again!
175 value2
[1024], // This one is reserved for some code - Don't use it again!
177 default_id
[15] = "Mausezahn rules",
180 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x0c, 0x20, 0x00
195 next_pbyte
=0, // points to the next free byte in tx.cdp_payload
203 unsigned int i
=0, count
, delay
;
212 fprintf(stderr
," Note: CDP mode does not support 802.1Q builder.\n");
218 fprintf(stderr
," Note: CDP mode does not support MPLS builder.\n");
223 if (getarg(tx
.arg_string
,"help", NULL
)==1)
227 cli_print(gcli
, "%s", MZ_CDP_HELP
);
234 "\n%s", MZ_CDP_HELP
);
240 ///////////////////////////////////////////////////////////////////////
242 if (tx
.cdp_ttl
==0) tx
.cdp_ttl
=0xb4; // 180 seconds
244 if (tx
.cdp_version
==0) tx
.cdp_version
= 0x02;
246 // The ID is the only required TLV
247 // If another function already specified it then it must also set the lenght:
248 if (tx
.cdp_tlv_id_len
==0) // not set
250 memcpy((void*) tx
.cdp_tlv_id
, (void*) default_id
, 15);
251 tx
.cdp_tlv_id_len
=15;
257 ///////////////////////////////////////////////////////////////////////
259 // Now check for user arguments:
262 if ( (getarg(tx
.arg_string
,"version", argval
)==1) || (getarg(tx
.arg_string
,"ver", argval
)==1) )
264 if (str2int(argval
)>255)
266 fprintf(stderr
," mz/send_cdp: version range exceeded, adjusted to max value.\n");
267 tx
.cdp_version
= 0xff;
271 tx
.cdp_version
= (u_int8_t
) str2int(argval
);
276 if (getarg(tx
.arg_string
,"ttl", argval
)==1)
278 if (str2int(argval
)>255)
280 fprintf(stderr
," mz/send_cdp: TTL range exceeded, adjusted to max value.\n");
285 tx
.cdp_ttl
= (u_int8_t
) str2int(argval
);
289 if (getarg(tx
.arg_string
,"sum", argval
)==1)
292 if (strtol(argval
,NULL
,16)>65535)
294 fprintf(stderr
," mz/send_cdp: checksum range exceeded, adjusted to max value.\n");
299 tx
.cdp_sum
= (u_int16_t
) strtol(argval
,NULL
,16);
305 // Provide a basic interface for the most important TLVs:
308 if (getarg(tx
.arg_string
,"tlv_id", argval
)==1)
310 // simply overwrite current content in tx.cdp_tlv_id
311 tx
.cdp_tlv_id
[0] = '\0';
312 strncpy((char*) tx
.cdp_tlv_id
, argval
,2048);
313 tx
.cdp_tlv_id_len
= strlen ((char*)tx
.cdp_tlv_id
);
318 // This is something ugly ;-)
321 if (getarg(tx
.arg_string
,"change", NULL
)==1)
323 memcpy((void*) tx
.cdp_tlv_id
, (void*) "Mausezahn 00000000000", 21);
324 tx
.cdp_tlv_id_len
=21;
330 // NOW write the ID-TLV; this is the only REQUIRED TLV !!!
331 // and this TLV should be the FIRST one - that's why we
332 // write it immediately here now:
334 tlv_len
= create_tlv (1, tx
.cdp_tlv_id
, tx
.cdp_tlv_id_len
, tlv
);
335 memcpy((void*) tx
.cdp_payload
+next_pbyte
, (void*) tlv
, tlv_len
);
336 next_pbyte
+= tlv_len
;
339 // Now the other TLVs may follow:
342 // Format: Type=2, Len=17, NrOfAddr=00:00:00:01, Protocol=01:01:cc:00, AddrLen=4, IP_Address
343 // Example: tlv_address = 192.168.1.10
344 // Note: currently only one address supported
345 if (getarg(tx
.arg_string
,"tlv_address", argval
)==1)
347 dummy32
= str2ip32 (argval
);
348 x
= (u_int8_t
*) &dummy32
;
349 value
[0] = 0x00; // NrOfAddr
354 value
[4] = 0x01; // Protocol
359 value
[8] = 0x04; // AddrLen
366 tlv_len
= create_tlv (2, value
, 13, tlv
);
367 memcpy((void*) tx
.cdp_payload
+next_pbyte
, (void*) tlv
, tlv_len
);
368 next_pbyte
+= tlv_len
;
374 // Example: tlv_portid = 2/23
376 if (getarg(tx
.arg_string
,"tlv_portid", argval
)==1)
378 tlv_len
= create_tlv (3, (u_int8_t
*) argval
, strlen(argval
), tlv
);
379 memcpy((void*) tx
.cdp_payload
+next_pbyte
, (void*) tlv
, tlv_len
);
380 next_pbyte
+= tlv_len
;
384 // Example: "tlv_cap = 2a" (= 0010 1010)
385 // Flags: MSB=0 - Repeater - IGMP - Host - Switch - SrcRouteBrdg - TranspBrdg - Router(LSB)
386 if (getarg(tx
.arg_string
,"tlv_cap", argval
)==1)
388 if (strlen(argval
)>2)
390 fprintf(stderr
," mz/send_cdp: Capability value must be specified as a two-digit hexadecimal value!\n");
395 str2hex(argval
, value
+3, 1020);
398 fprintf(stderr
," mz/send_cdp: Capability value must not exceed 7F(hex)\n");
406 tlv_len
= create_tlv (4, value
, 4, tlv
);
407 memcpy((void*) tx
.cdp_payload
+next_pbyte
, (void*) tlv
, tlv_len
);
408 next_pbyte
+= tlv_len
;
413 // Example: tlv_version = Mausezahn_version_xyz
414 // Note: Avoid spaces, use underscore instead
415 if (getarg(tx
.arg_string
,"tlv_version", argval
)==1)
417 tlv_len
= create_tlv (5, (u_int8_t
*) argval
, strlen(argval
), tlv
);
418 memcpy((void*) tx
.cdp_payload
+next_pbyte
, (void*) tlv
, tlv_len
);
419 next_pbyte
+= tlv_len
;
424 // Example: tlv_platform = WS-C6509-E
426 if (getarg(tx
.arg_string
,"tlv_platform", argval
)==1)
428 tlv_len
= create_tlv (6, (u_int8_t
*) argval
, strlen(argval
), tlv
);
429 memcpy((void*) tx
.cdp_payload
+next_pbyte
, (void*) tlv
, tlv_len
);
430 next_pbyte
+= tlv_len
;
434 // Example: tlv_vtpdomain = MyVTPdomain
436 if (getarg(tx
.arg_string
,"tlv_vtpdomain", argval
)==1)
438 tlv_len
= create_tlv (9, (u_int8_t
*) argval
, strlen(argval
), tlv
);
439 memcpy((void*) tx
.cdp_payload
+next_pbyte
, (void*) tlv
, tlv_len
);
440 next_pbyte
+= tlv_len
;
444 // Format: Type=10, Len=17
445 // Example: tlv_native = 100
447 if (getarg(tx
.arg_string
,"tlv_native", argval
)==1)
449 dummy16
= (u_int16_t
) str2int(argval
);
452 fprintf(stderr
," mz/WARNING: native VLAN value exceeds max value (4095) - hope you know what you do!\n");
455 x
= (u_int8_t
*) &dummy16
;
458 tlv_len
= create_tlv (10, value
, 2, tlv
);
459 memcpy((void*) tx
.cdp_payload
+next_pbyte
, (void*) tlv
, tlv_len
);
460 next_pbyte
+= tlv_len
;
464 // Example: tlv_duplex = full | half
466 if (getarg(tx
.arg_string
,"tlv_duplex", argval
)==1)
468 if (strncmp(argval
,"full",10)==0)
472 else if (strncmp(argval
,"half",10)==0)
478 value
[0]=(u_int8_t
) str2int(argval
);
481 fprintf(stderr
," mz/Warning: Only keywords 'half' or 'full' supported."
482 " Will interprete input as integer.\n");
487 tlv_len
= create_tlv (11, value
, 1, tlv
);
488 memcpy((void*) tx
.cdp_payload
+next_pbyte
, (void*) tlv
, tlv_len
);
489 next_pbyte
+= tlv_len
;
492 // Format: Type=22, Len=17, NrOfAddr=00:00:00:01, Protocol=01:01:cc:00, AddrLen=4, IP_Address
493 // Example: tlv_mgmt = 10.1.1.99
494 // Note: Same format as tlv_address
495 if (getarg(tx
.arg_string
,"tlv_mgmt", argval
)==1)
497 dummy32
= str2ip32 (argval
);
498 x
= (u_int8_t
*) &dummy32
;
499 value
[0] = 0x00; // NrOfAddr
504 value
[4] = 0x01; // Protocol
509 value
[8] = 0x04; // AddrLen
516 tlv_len
= create_tlv (22, value
, 13, tlv
);
517 memcpy((void*) tx
.cdp_payload
+next_pbyte
, (void*) tlv
, tlv_len
);
518 next_pbyte
+= tlv_len
;
525 // Eventually there are two generic TLV interfaces: tlv and tlvhex
528 if (getarg(tx
.arg_string
,"tlv", argval
)==1)
530 // split in TYPE and VALUE
531 sscanf(argval
, "%u/%s", &type1
, value1
);
532 len1
= strlen((const char*) value1
);
536 if (getarg(tx
.arg_string
,"tlvhex", argval
)==1)
538 // split in TYPE and VALUE
539 sscanf(argval
, "%u/%s", &type2
, pld
);
540 len2
= str2hex(pld
, value2
, 1023);
545 // Finally the optional payload interface allows to specify subsequent TLVs or any other bytes:
547 if ( (getarg(tx
.arg_string
,"payload", argval
)==1) || (getarg(tx
.arg_string
,"p", argval
)==1))
549 len
= str2hex (argval
, value
, 1023);
550 memcpy((void*) tx
.cdp_payload
+next_pbyte
, (void*) value
, len
);
556 ///////////////////////////////////////////////////////////////
560 // Write other TLVs: First the ASCII specified:
563 tlv_len
= create_tlv (type1
, value1
, len1
, tlv
);
564 memcpy((void*) tx
.cdp_payload
+next_pbyte
, (void*) tlv
, tlv_len
);
565 next_pbyte
+= tlv_len
;
568 // Write other TLVs: Then the HEX specified:
571 tlv_len
= create_tlv (type2
, value2
, len2
, tlv
);
572 memcpy((void*) tx
.cdp_payload
+next_pbyte
, (void*) tlv
, tlv_len
);
573 next_pbyte
+= tlv_len
;
577 tx
.cdp_payload_s
= next_pbyte
;
580 // bs2str(tx.cdp_payload, pld, tx.cdp_payload_s);
581 // printf("PAYLOAD= %s\n",pld);
584 ////////////////////////////
587 // Open the link - for the intermediate CDP/LLC frame
588 l
= libnet_init(LIBNET_LINK_ADV
, tx
.device
, errbuf
);
592 fprintf(stderr
, "%s", errbuf
);
596 if (check_eth_mac_txt(ETH_DST
)) // if '1' then user did not set MAC address (or problem occurred)
598 str2hex("01:00:0C:CC:CC:CC", tx
.eth_dst
, 6);
601 if (check_eth_mac_txt(ETH_SRC
)) // if '1' then user did not set MAC address (or problem occurred)
603 // own mac per default (see init.c)
607 eth_src_rand
= tx
.eth_src_rand
;
610 // ---------------------------------------------------
611 // If you want to change CDP fields during a LOOP then
612 // START the loop from HERE:
615 ////////////////////////////////////
616 // Now create the whole CDP packet:
618 packet
[0] = tx
.cdp_version
; // VERSION
619 packet
[1] = tx
.cdp_ttl
; // TTL
620 packet
[2] = 0x00; // CHECKSUM
624 memcpy ((void*) packet
+4, (void*) tx
.cdp_payload
, tx
.cdp_payload_s
);
625 packet_s
= tx
.cdp_payload_s
+ 4;
627 // Check whether packet is an even length (i.e. is a multiple of 16 bits = 2 bytes);
630 packet
[packet_s
++]=0x00;
631 packet
[packet_s
++]=0x17;
632 packet
[packet_s
++]=0x00;
633 packet
[packet_s
++]=0x05;
634 packet
[packet_s
++]=0x00;
638 // Now update the checksum:
639 if (tx
.cdp_sum
== 0) // Otherwise user specified the checksum (usually a wrong one ;-))
641 tx
.cdp_sum
= checksum16(packet_s
, packet
);
643 x
= (u_int8_t
*) &tx
.cdp_sum
;
647 // CHECK the CDP packet
648 //bs2str(packet, pld, packet_s);
649 //printf("CDP= %s\n",pld);
652 // printf("Len = %u Checksum = %04x \n", packet_s-8, tx.cdp_sum);
655 ///////////////////////////////////////////////////////////////
656 // Now create the whole tx.eth_payload = LLC/SNAP + CDP packet
657 // First the LLC/SNAP header:
658 memcpy ((void*) tx
.eth_payload
, (void*) llcsnap
, 8);
659 memcpy ((void*) tx
.eth_payload
+8, (void*) packet
, packet_s
);
660 tx
.eth_payload_s
= packet_s
+8;
663 // CHECK the whole 802.3 payload
664 // bs2str(tx.eth_payload, pld, tx.eth_payload_s);
665 // printf("PACKET = %s\n",pld);
668 t
= libnet_build_802_3 (tx
.eth_dst
,
678 // this is for the statistics:
682 if (!count
) goto AGAIN
;
684 for (i
=0; i
<count
; i
++)
690 tx
.eth_src
[0] = (u_int8_t
) ( ((float) rand()/RAND_MAX
)*256) & 0xFE; // keeps bcast-bit zero
691 tx
.eth_src
[1] = (u_int8_t
) ( ((float) rand()/RAND_MAX
)*256);
692 tx
.eth_src
[2] = (u_int8_t
) ( ((float) rand()/RAND_MAX
)*256);
693 tx
.eth_src
[3] = (u_int8_t
) ( ((float) rand()/RAND_MAX
)*256);
694 tx
.eth_src
[4] = (u_int8_t
) ( ((float) rand()/RAND_MAX
)*256);
695 tx
.eth_src
[5] = (u_int8_t
) ( ((float) rand()/RAND_MAX
)*256);
697 t
= libnet_build_802_3 (tx
.eth_dst
,
712 bs2str(tx
.eth_payload
+8, pld
, tx
.eth_payload_s
-8);
713 fprintf(stderr
," Sent CDP: (Ver=%u, TTL=%u) %s\n", tx
.cdp_version
, tx
.cdp_ttl
, pld
);
716 if (delay
) SLEEP (delay
);
720 // Note: this only works when default_id has been used
721 // because otherwise the TLV with the ID might be too short!!!
723 // Offset 26-36 contains 00000000000 (of the default id)
724 // ASCII 0x30-0x39 contain numbers 0-9
726 tx
.eth_payload
[26] = (u_int8_t
) (0x30+ ((float) rand()/RAND_MAX
)*10);
727 tx
.eth_payload
[27] = (u_int8_t
) (0x30+ ((float) rand()/RAND_MAX
)*10);
728 tx
.eth_payload
[28] = (u_int8_t
) (0x30+ ((float) rand()/RAND_MAX
)*10);
729 tx
.eth_payload
[29] = (u_int8_t
) (0x30+ ((float) rand()/RAND_MAX
)*10);
730 tx
.eth_payload
[30] = (u_int8_t
) (0x30+ ((float) rand()/RAND_MAX
)*10);
731 tx
.eth_payload
[31] = (u_int8_t
) (0x30+ ((float) rand()/RAND_MAX
)*10);
732 tx
.eth_payload
[32] = (u_int8_t
) (0x30+ ((float) rand()/RAND_MAX
)*10);
733 tx
.eth_payload
[33] = (u_int8_t
) (0x30+ ((float) rand()/RAND_MAX
)*10);
734 tx
.eth_payload
[34] = (u_int8_t
) (0x30+ ((float) rand()/RAND_MAX
)*10);
735 tx
.eth_payload
[35] = (u_int8_t
) (0x30+ ((float) rand()/RAND_MAX
)*10);
736 tx
.eth_payload
[36] = (u_int8_t
) (0x30+ ((float) rand()/RAND_MAX
)*10);
738 tx
.eth_payload
[10] = 0x00; // reset the checksum
739 tx
.eth_payload
[11] = 0x00;
740 tx
.cdp_sum
= checksum16(tx
.eth_payload_s
-8, tx
.eth_payload
+8);
741 x
= (u_int8_t
*) &tx
.cdp_sum
;
742 tx
.eth_payload
[10] = *(x
+1);
743 tx
.eth_payload
[11] = *(x
);
745 t
= libnet_build_802_3 (tx
.eth_dst
,
757 if (!count
) goto AGAIN
;