/* * Mausezahn - A fast versatile traffic generator * Copyright (C) 2008 Herbert Haas * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 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, see http://www.gnu.org/licenses/gpl-2.0.html * */ ///////////////////////////////////////////////////////////////////// // // Send CDP packets // ///////////////////////////////////////////////////////////////////// #include "mz.h" #include "cli.h" #define MZ_CDP_HELP \ "| CDP type: Send arbitrary CDP packets.\n" \ "| Note:\n" \ "| - The Ethernet dst and src MAC addresses can be specified but can be also 'rand'.\n" \ "| - If dst and src are NOT specified then practical defaults are used (src=own MAC, dst=01:00:0C:CC:CC:CC).\n" \ "|\n" \ "| ARGUMENT SYNTAX: -t cdp [arguments]\n" \ "|\n" \ "| ARGUMENTS:\n" \ "|\n" \ "| version ...... 0-255, default: 2\n" \ "| ttl ...... 0-255, default: 180 s\n" \ "| sum ...... 0000-ffff, default: automatically computed\n" \ "|\n" \ "| TLVs: Description: Example:\n" \ "|\n" \ "| tlv_id ....... Device ID Mausezahn station\n" \ "| tlv_address ....... Sending interface address 10.1.1.2\n" \ "| tlv_portid ....... Port Identifier 2/23\n" \ "| tlv_cap ....... Capabilities (hex<7f) 2a\n" \ "| tlv_version ....... Software Version ver3.0\n" \ "| tlv_platform ....... Hardware Platform WS-C6509-E\n" \ "| tlv_vtpdomain ....... VTP Management Domain MyVTPdomain\n" \ "| tlv_native ....... Native VLAN number (0-4095) 42\n" \ "| tlv_duplex ....... Full or half duplex full\n" \ "| tlv_mgmt ....... Management IP address 192.168.1.2\n" \ "|\n" \ "| tlv .......... Create ANY TLV using the format: tlv=/, such as tlv=42/mausezahn\n" \ "| Note: Currently you must omit spaces within ! Use underscore instead.\n" \ "| tlvhex .......... Create ANY TLV and specify the value in hexformat, such as tlv=42/ca:fe:ba:be\n" \ "| payload|p .......... Optional additional TLVs or any other bytes specified in hex\n" \ "|\n" \ "| When the tlv* arguments are used, the TLV length parameter is automatically set.\n" \ "|\n" \ "| The capability flags from MSB to LSB are:\n" \ "| 0 - Repeater - IGMP - Host - Switch - SrcRouteBrdg - TranspBrdg - Router\n" \ "|\n" \ "| Optionally the keyword 'change' will create a different System name TLV every time a CDP\n" \ "| packet is sent. This can be used to fill up a CDP database with different test values.\n" \ "| Additionally use the '-a rand' command to use different source MAC addresses.\n" \ "|\n" \ "| EXAMPLES:\n" \ "|\n" \ "| Announce Device ID 'Espresso3000', Capabilities: Router, native VLAN 301:\n" \ "| mz eth0 -t cdp \"tlv_id=Espresso3000, tlv_cap=01, tlv_native=301\"\n" \ "|\n" \ "| Create another TLV using the payload interface (here voice VLAN 400):\n" \ "| mz eth0 -t cdp p=00:0e:00:07:01:01:90\n" u_int16_t checksum16 (u_int16_t len, u_int8_t buff[]) { u_int16_t word16; u_int32_t sum=0; u_int16_t i; // make 16 bit words out of every two adjacent 8 bit words in the packet and add them up for (i=0; i>16) sum = (sum & 0xFFFF)+(sum >> 16); // one's complement the result sum = ~sum; return ((u_int16_t) sum); } // Creates a TLV and returns the whole length of the TLV unsigned int create_tlv (u_int16_t type, // The 16-bit TYPE number u_int8_t *value, // The VALUE as prepared hex-array unsigned int value_len, // needed because VALUE maybe not \0 terminated u_int8_t *target) // the RESULT i. e. the complete TLV { unsigned int tlvlen; u_int8_t *x; x = (u_int8_t*) &type; // set TYPE target[0] = *(x+1); target[1] = *(x); tlvlen = value_len + 4; // set VALUE x = (u_int8_t*) &tlvlen; target[2] = *(x+1); target[3] = *(x); target+=4; memcpy((void*) target, (void*) value, (size_t) value_len); return tlvlen; } // NOTE: The Length field indicates the total length, in bytes, of the type, length, and value fields! // // Interesting TLVs: // // TYPE VALUE // 0001 Device-ID // 0002 IP Addresses // 0003 Port ID such as 2/22 // 0004 Capabilities (Len=8, consists of flags only: Router, TBrdg, SRBrdgm, Switch, Host, IGMP, Repeater) // 0005 SW Version // 0006 Platform // 0009 VTP Domain // 000a Native VLAN, e.g. 00:0a 00:06 01:2d identifies native VLAN number 301 (=01:2d) // 000b Duplex // 000e VoIP VLAN, e.g. 00:0e 00:07 01 01:90 identifies DATA (=01) and VLAN 400 (=01:90) // 0012 Trust Bitmap // 0013 Untrusted Port CoS // 0014 System Name (!!!) // 0015 System Object Identifier // 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) // 0017 Location // 001a Unknown (???) // // The IP address format is a bit strange as 0016 for example demonstrates... int send_cdp(void) { libnet_t *l; libnet_ptag_t t; char errbuf[LIBNET_ERRBUF_SIZE], argval[1024]; u_int8_t packet[MAX_PAYLOAD_SIZE], // this one will finally contain the whole cdp packet (without LLC/SNAP!) *x, value[1024], // USE THIS FOR ANYTHING YOU LIKE !!! value1[1024], // This one is reserved for some code - Don't use it again! value2[1024], // This one is reserved for some code - Don't use it again! tlv[1024], default_id[15] = "Mausezahn rules", llcsnap[8]= { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x0c, 0x20, 0x00 }; unsigned int len=0, len1=0, len2=0, type1, type2; u_int16_t dummy16=0, tlv_len=0; u_int32_t next_pbyte=0, // points to the next free byte in tx.cdp_payload dummy32=0, packet_s; char pld[2048]; unsigned int i=0, count, delay; int eth_src_rand=0, change_value=0; long int j=0; if (tx.dot1Q) { fprintf(stderr," Note: CDP mode does not support 802.1Q builder.\n"); exit(1); } if (tx.mpls) { fprintf(stderr," Note: CDP mode does not support MPLS builder.\n"); exit(1); } if (getarg(tx.arg_string,"help", NULL)==1) { if (mz_port) { cli_print(gcli, "%s", MZ_CDP_HELP); return -1; } else { fprintf(stderr,"\n" MAUSEZAHN_VERSION "\n%s", MZ_CDP_HELP); exit(0); } } /////////////////////////////////////////////////////////////////////// // initial defaults: if (tx.cdp_ttl==0) tx.cdp_ttl=0xb4; // 180 seconds if (tx.cdp_version==0) tx.cdp_version = 0x02; // The ID is the only required TLV // If another function already specified it then it must also set the lenght: if (tx.cdp_tlv_id_len==0) // not set { memcpy((void*) tx.cdp_tlv_id, (void*) default_id, 15); tx.cdp_tlv_id_len=15; } /////////////////////////////////////////////////////////////////////// // // Now check for user arguments: if ( (getarg(tx.arg_string,"version", argval)==1) || (getarg(tx.arg_string,"ver", argval)==1) ) { if (str2int(argval)>255) { fprintf(stderr," mz/send_cdp: version range exceeded, adjusted to max value.\n"); tx.cdp_version = 0xff; } else { tx.cdp_version = (u_int8_t) str2int(argval); } } if (getarg(tx.arg_string,"ttl", argval)==1) { if (str2int(argval)>255) { fprintf(stderr," mz/send_cdp: TTL range exceeded, adjusted to max value.\n"); tx.cdp_ttl = 0xff; } else { tx.cdp_ttl = (u_int8_t) str2int(argval); } } if (getarg(tx.arg_string,"sum", argval)==1) { if (strtol(argval,NULL,16)>65535) { fprintf(stderr," mz/send_cdp: checksum range exceeded, adjusted to max value.\n"); tx.cdp_sum = 0xffff; } else { tx.cdp_sum = (u_int16_t) strtol(argval,NULL,16); } } //////// // // Provide a basic interface for the most important TLVs: // if (getarg(tx.arg_string,"tlv_id", argval)==1) { // simply overwrite current content in tx.cdp_tlv_id tx.cdp_tlv_id[0] = '\0'; strncpy((char*) tx.cdp_tlv_id, argval,2048); tx.cdp_tlv_id_len = strlen ((char*)tx.cdp_tlv_id); } // // This is something ugly ;-) // if (getarg(tx.arg_string,"change", NULL)==1) { memcpy((void*) tx.cdp_tlv_id, (void*) "Mausezahn 00000000000", 21); tx.cdp_tlv_id_len=21; change_value = 1; } // // NOW write the ID-TLV; this is the only REQUIRED TLV !!! // and this TLV should be the FIRST one - that's why we // write it immediately here now: // tlv_len = create_tlv (1, tx.cdp_tlv_id, tx.cdp_tlv_id_len, tlv); memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len); next_pbyte += tlv_len; // // Now the other TLVs may follow: // // Format: Type=2, Len=17, NrOfAddr=00:00:00:01, Protocol=01:01:cc:00, AddrLen=4, IP_Address // Example: tlv_address = 192.168.1.10 // Note: currently only one address supported if (getarg(tx.arg_string,"tlv_address", argval)==1) { dummy32 = str2ip32 (argval); x = (u_int8_t*) &dummy32; value[0] = 0x00; // NrOfAddr value[1] = 0x00; value[2] = 0x00; value[3] = 0x01; value[4] = 0x01; // Protocol value[5] = 0x01; value[6] = 0xcc; value[7] = 0x00; value[8] = 0x04; // AddrLen value[9] = *(x+3); value[10] = *(x+2); value[11] = *(x+1); value[12] = *(x); tlv_len = create_tlv (2, value, 13, tlv); memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len); next_pbyte += tlv_len; } // Format: Type=3 // Example: tlv_portid = 2/23 // Note: if (getarg(tx.arg_string,"tlv_portid", argval)==1) { tlv_len = create_tlv (3, (u_int8_t*) argval, strlen(argval), tlv); memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len); next_pbyte += tlv_len; } // Format: Type=4 // Example: "tlv_cap = 2a" (= 0010 1010) // Flags: MSB=0 - Repeater - IGMP - Host - Switch - SrcRouteBrdg - TranspBrdg - Router(LSB) if (getarg(tx.arg_string,"tlv_cap", argval)==1) { if (strlen(argval)>2) { fprintf(stderr," mz/send_cdp: Capability value must be specified as a two-digit hexadecimal value!\n"); exit(1); } else { str2hex(argval, value+3, 1020); if (value[3]>0x7f) { fprintf(stderr," mz/send_cdp: Capability value must not exceed 7F(hex)\n"); exit(1); } } value[0]=0x00; value[1]=0x00; value[2]=0x00; tlv_len = create_tlv (4, value, 4, tlv); memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len); next_pbyte += tlv_len; } // Format: Type=5 // Example: tlv_version = Mausezahn_version_xyz // Note: Avoid spaces, use underscore instead if (getarg(tx.arg_string,"tlv_version", argval)==1) { tlv_len = create_tlv (5, (u_int8_t*) argval, strlen(argval), tlv); memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len); next_pbyte += tlv_len; } // Format: Type=6 // Example: tlv_platform = WS-C6509-E // Note: if (getarg(tx.arg_string,"tlv_platform", argval)==1) { tlv_len = create_tlv (6, (u_int8_t*) argval, strlen(argval), tlv); memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len); next_pbyte += tlv_len; } // Format: Type=9 // Example: tlv_vtpdomain = MyVTPdomain // Note: if (getarg(tx.arg_string,"tlv_vtpdomain", argval)==1) { tlv_len = create_tlv (9, (u_int8_t*) argval, strlen(argval), tlv); memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len); next_pbyte += tlv_len; } // Format: Type=10, Len=17 // Example: tlv_native = 100 // Note: if (getarg(tx.arg_string,"tlv_native", argval)==1) { dummy16 = (u_int16_t) str2int(argval); if (dummy16>4095) { fprintf(stderr," mz/WARNING: native VLAN value exceeds max value (4095) - hope you know what you do!\n"); } x = (u_int8_t*) &dummy16; value[0] = *(x+1); value[1] = *(x); tlv_len = create_tlv (10, value, 2, tlv); memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len); next_pbyte += tlv_len; } // Format: Type=11 // Example: tlv_duplex = full | half // Note: if (getarg(tx.arg_string,"tlv_duplex", argval)==1) { if (strncmp(argval,"full",10)==0) { value[0]=0x01; } else if (strncmp(argval,"half",10)==0) { value[0]=0x00; } else { value[0]=(u_int8_t) str2int(argval); if (!quiet) { fprintf(stderr," mz/Warning: Only keywords 'half' or 'full' supported." " Will interprete input as integer.\n"); } } tlv_len = create_tlv (11, value, 1, tlv); memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len); next_pbyte += tlv_len; } // Format: Type=22, Len=17, NrOfAddr=00:00:00:01, Protocol=01:01:cc:00, AddrLen=4, IP_Address // Example: tlv_mgmt = 10.1.1.99 // Note: Same format as tlv_address if (getarg(tx.arg_string,"tlv_mgmt", argval)==1) { dummy32 = str2ip32 (argval); x = (u_int8_t*) &dummy32; value[0] = 0x00; // NrOfAddr value[1] = 0x00; value[2] = 0x00; value[3] = 0x01; value[4] = 0x01; // Protocol value[5] = 0x01; value[6] = 0xcc; value[7] = 0x00; value[8] = 0x04; // AddrLen value[9] = *(x+3); value[10] = *(x+2); value[11] = *(x+1); value[12] = *(x); tlv_len = create_tlv (22, value, 13, tlv); memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len); next_pbyte += tlv_len; } // // Eventually there are two generic TLV interfaces: tlv and tlvhex // if (getarg(tx.arg_string,"tlv", argval)==1) { // split in TYPE and VALUE sscanf(argval, "%u/%s", &type1, value1); len1 = strlen((const char*) value1); } if (getarg(tx.arg_string,"tlvhex", argval)==1) { // split in TYPE and VALUE sscanf(argval, "%u/%s", &type2, pld); len2 = str2hex(pld, value2, 1023); } // // Finally the optional payload interface allows to specify subsequent TLVs or any other bytes: // if ( (getarg(tx.arg_string,"payload", argval)==1) || (getarg(tx.arg_string,"p", argval)==1)) { len = str2hex (argval, value, 1023); memcpy((void*) tx.cdp_payload+next_pbyte, (void*) value, len); next_pbyte += len; } /////////////////////////////////////////////////////////////// // Write other TLVs: First the ASCII specified: if (len1) { tlv_len = create_tlv (type1, value1, len1 , tlv); memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len); next_pbyte += tlv_len; } // Write other TLVs: Then the HEX specified: if (len2) { tlv_len = create_tlv (type2, value2, len2 , tlv); memcpy((void*) tx.cdp_payload+next_pbyte, (void*) tlv, tlv_len); next_pbyte += tlv_len; } tx.cdp_payload_s = next_pbyte; // CHECK: // bs2str(tx.cdp_payload, pld, tx.cdp_payload_s); // printf("PAYLOAD= %s\n",pld); //////////////////////////// // // Open the link - for the intermediate CDP/LLC frame l = libnet_init(LIBNET_LINK_ADV, tx.device, errbuf); if (l == NULL) { fprintf(stderr, "%s", errbuf); exit(EXIT_FAILURE); } if (check_eth_mac_txt(ETH_DST)) // if '1' then user did not set MAC address (or problem occurred) { str2hex("01:00:0C:CC:CC:CC", tx.eth_dst, 6); } if (check_eth_mac_txt(ETH_SRC)) // if '1' then user did not set MAC address (or problem occurred) { // own mac per default (see init.c) } count = tx.count; eth_src_rand = tx.eth_src_rand; delay = tx.delay; // --------------------------------------------------- // If you want to change CDP fields during a LOOP then // START the loop from HERE: // //////////////////////////////////// // Now create the whole CDP packet: packet[0] = tx.cdp_version; // VERSION packet[1] = tx.cdp_ttl; // TTL packet[2] = 0x00; // CHECKSUM packet[3] = 0x00; // Now add the TLVs memcpy ((void*) packet+4, (void*) tx.cdp_payload, tx.cdp_payload_s); packet_s = tx.cdp_payload_s + 4; // Check whether packet is an even length (i.e. is a multiple of 16 bits = 2 bytes); if (packet_s%2>0) { packet[packet_s++]=0x00; packet[packet_s++]=0x17; packet[packet_s++]=0x00; packet[packet_s++]=0x05; packet[packet_s++]=0x00; } // Now update the checksum: if (tx.cdp_sum == 0) // Otherwise user specified the checksum (usually a wrong one ;-)) { tx.cdp_sum = checksum16(packet_s, packet); } x = (u_int8_t *) &tx.cdp_sum; packet[2] = *(x+1); packet[3] = *(x); // CHECK the CDP packet //bs2str(packet, pld, packet_s); //printf("CDP= %s\n",pld); // printf("Len = %u Checksum = %04x \n", packet_s-8, tx.cdp_sum); /////////////////////////////////////////////////////////////// // Now create the whole tx.eth_payload = LLC/SNAP + CDP packet // First the LLC/SNAP header: memcpy ((void*) tx.eth_payload, (void*) llcsnap, 8); memcpy ((void*) tx.eth_payload+8, (void*) packet, packet_s); tx.eth_payload_s = packet_s +8; // CHECK the whole 802.3 payload // bs2str(tx.eth_payload, pld, tx.eth_payload_s); // printf("PACKET = %s\n",pld); t = libnet_build_802_3 (tx.eth_dst, tx.eth_src, tx.eth_payload_s, tx.eth_payload, tx.eth_payload_s, l, 0); // this is for the statistics: mz_start = clock(); total_d = tx.count; if (!count) goto AGAIN; for (i=0; i