/* * DHCP toolkit * * Complicate frontend for crafting dhcp traffic * * Jon Hart * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the organization nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #define OPT_HELP 0 #define OPT_VERBOSE 1 #define OPT_INTERFACE 2 #define OPT_DHCPOP 3 #define OPT_SRCETHER 4 #define OPT_DSTETHER 5 #define OPT_HWADDR 6 #define OPT_DHCPMSG 7 #define OPT_SRCIP 8 #define OPT_DSTIP 9 #define OPT_OPTIONS 10 struct opt { char *name; /* name of this option */ int req; /* required? */ int set; /* Does it have a value? */ }; struct opt opts[] = { {"help", 0, 0}, {"verbose", 0, 0}, {"interface", 1, 0}, {"DHCP operation", 1, 0}, {"source ethernet address", 1, 0}, {"destination ethernet address", 1, 0}, {"hardware address", 1, 0}, {"DHCP message type", 1, 0}, {"source IP", 1, 0}, {"destination IP", 1, 0}, {"options", 1, 0} }; struct libnet_ether_addr *make_ether(char *in) { int i; u_int enet_val[6]; struct libnet_ether_addr *ether = (struct libnet_ether_addr *)malloc(sizeof(struct libnet_ether_addr *)); sscanf(in, "%2x:%2x:%2x:%2x:%2x:%2x", &enet_val[0], &enet_val[1], &enet_val[2], &enet_val[3], &enet_val[4], &enet_val[5]); for (i = 0; i < 6; i++) { ether->ether_addr_octet[i] = (u_char)enet_val[i]; } return ether; } int main(int argc, char *argv[]) { int c, i; libnet_t *libnet; libnet_ptag_t dhcp, udp, ipv4, ether; u_char *packet; u_long packet_s; u_short dhcp_op; u_char hw_type, hw_length, hop_count, dhcp_msg; u_short secs, flags; u_long client_ip, src_ip, dst_ip, your_ip, server_ip, gateway_ip, options_len; u_char trans_id, *boot_file, *server_name; u_char *options; /* The source and destination MAC addresses * for the ethernet level */ struct libnet_ether_addr *src_ether = (struct libnet_ether_addr *) malloc(sizeof(struct libnet_ether_addr *)); struct libnet_ether_addr *dst_ether = (struct libnet_ether_addr *) malloc(sizeof(struct libnet_ether_addr *)); struct libnet_ether_addr *hw_addr = (struct libnet_ether_addr *) malloc(sizeof(struct libnet_ether_addr *)); u_char broadcast[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; char *interface; char errbuf[LIBNET_ERRBUF_SIZE]; while ((c = getopt(argc, argv, "i:o:p:P:s:S:d:m:O:vh")) != EOF) { switch (c) { case 'h': exit(EXIT_SUCCESS); case 'v': opts[OPT_VERBOSE].set = 1; break; case 'O': options = optarg; options_len = strlen(optarg); opts[OPT_OPTIONS].set = 1; break; case 'i': interface = optarg; opts[OPT_INTERFACE].set = 1; break; case 'p': src_ip = libnet_name2addr4(libnet, optarg, LIBNET_DONT_RESOLVE); opts[OPT_SRCIP].set = 1; break; case 'P': dst_ip = libnet_name2addr4(libnet, optarg, LIBNET_DONT_RESOLVE); opts[OPT_DSTIP].set = 1; break; case 's': src_ether = make_ether(optarg); opts[OPT_SRCETHER].set = 1; break; case 'S': hw_addr = make_ether(optarg); opts[OPT_HWADDR].set = 1; break; case 'd': dst_ether = make_ether(optarg); opts[OPT_DSTETHER].set = 1; break; case 'o': if (strcmp(optarg, "req") == 0) { dhcp_op = LIBNET_DHCP_REQUEST; opts[OPT_DHCPOP].set = 1; break; } else if (strcmp(optarg, "rep") == 0) { dhcp_op = LIBNET_DHCP_REPLY; opts[OPT_DHCPOP].set = 1; break; } else { fprintf(stderr, "Invalid dhcp operation %s. Must be one of req, rep\n", optarg); opts[OPT_DHCPOP].set = 0; exit(EXIT_FAILURE); } case 'm': if (strcmp(optarg, "disc") == 0) { dhcp_msg = LIBNET_DHCP_MSGDISCOVER; opts[OPT_DHCPMSG].set = 1; break; } else if (strcmp(optarg, "off") == 0) { dhcp_msg = LIBNET_DHCP_MSGOFFER; opts[OPT_DHCPMSG].set = 1; break; } else if (strcmp(optarg, "req") == 0) { dhcp_msg = LIBNET_DHCP_MSGREQUEST; opts[OPT_DHCPMSG].set = 1; break; } else if (strcmp(optarg, "dec") == 0) { dhcp_msg = LIBNET_DHCP_MSGDECLINE; opts[OPT_DHCPMSG].set = 1; break; } else if (strcmp(optarg, "ack") == 0) { dhcp_msg = LIBNET_DHCP_MSGACK; opts[OPT_DHCPMSG].set = 1; break; } else if (strcmp(optarg, "nack") == 0) { dhcp_msg = LIBNET_DHCP_MSGNACK; opts[OPT_DHCPMSG].set = 1; break; } else if (strcmp(optarg, "rel") == 0) { dhcp_msg = LIBNET_DHCP_MSGRELEASE; opts[OPT_DHCPMSG].set = 1; break; } else if (strcmp(optarg, "inf") == 0) { dhcp_msg = LIBNET_DHCP_MSGINFORM; opts[OPT_DHCPMSG].set = 1; break; } else { fprintf(stderr, "Invalid DHCP message type %s. Must be one of off, req, dec, ack, nack, rel, or inf\n", optarg); exit(EXIT_FAILURE); } default: break; } } if (!opts[OPT_INTERFACE].set) { fprintf(stderr, "Please specify an interface\n"); exit(EXIT_FAILURE); } libnet = libnet_init(LIBNET_LINK, interface, errbuf); if (libnet == NULL) { fprintf(stderr, "libnet_init() failed: %s", errbuf); exit(EXIT_FAILURE); } if (!opts[OPT_SRCETHER].set) { if (opts[OPT_VERBOSE].set) { fprintf(stderr, "No source ethernet address specified. Attempting to use %s's\n", interface); } src_ether = libnet_get_hwaddr(libnet); if (src_ether == NULL) { fprintf(stderr, "No source ethernet address specified, and I couldn't guess it: %s\n", libnet_geterror(libnet)); exit(EXIT_FAILURE); } opts[OPT_SRCETHER].set = 1; } if (!opts[OPT_DSTETHER].set) { if (opts[OPT_VERBOSE].set) { fprintf(stderr, "No destination ethernet address specified. Using broadcast\n"); } memcpy(dst_ether->ether_addr_octet, broadcast, sizeof(broadcast)); opts[OPT_DSTETHER].set = 1; } if (!opts[OPT_HWADDR].set) { hw_addr = libnet_get_hwaddr(libnet); if (hw_addr == NULL) { fprintf(stderr, "No hardware address specified, and I couldn't guess it: %s\n", libnet_geterror(libnet)); exit(EXIT_FAILURE); } } if (!opts[OPT_DSTIP].set) { dst_ip = inet_addr("255.255.255.255"); opts[OPT_DSTIP].set = 1; } if (!opts[OPT_SRCIP].set) { src_ip = inet_addr("0.0.0.0"); opts[OPT_SRCIP].set = 1; } if (!opts[OPT_OPTIONS].set) { i = 0; options_len = 3; options = malloc(3); options[i++] = LIBNET_DHCP_MESSAGETYPE; // type options[i++] = 1; // len options[i++] = dhcp_msg; // message type options[i] = LIBNET_DHCP_END; } dhcp = libnet_build_dhcpv4( dhcp_op, /* dhcp operation */ 1, /* hardware type */ 6, /* hardware address length */ 0, 0xdeadbeef, /* transaction id */ 0, /* seconds since bootstrap */ 0x8000, /* flags */ client_ip, your_ip, server_ip, gateway_ip, hw_addr->ether_addr_octet, NULL, NULL, options, options_len, libnet, 0); udp = libnet_build_udp( 68, 67, LIBNET_UDP_H + LIBNET_DHCPV4_H + options_len, 0, NULL, 0, libnet, 0); ipv4 = libnet_build_ipv4( LIBNET_IPV4_H + LIBNET_UDP_H + LIBNET_DHCPV4_H + options_len, 0x10, 0, 0, 16, IPPROTO_UDP, 0, 0, dst_ip, NULL, 0, libnet, 0); ether = libnet_build_ethernet( dst_ether->ether_addr_octet, src_ether->ether_addr_octet, ETHERTYPE_IP, NULL, 0, libnet, 0); c = libnet_adv_cull_packet(libnet, &packet, &packet_s); if ( (c = libnet_write(libnet)) == -1) { fprintf(stderr, "Couldn't write packet to the wire: %s\n", libnet_geterror(libnet)); } else { if (opts[OPT_VERBOSE].set) { fprintf(stderr, "Wrote %i bytes to %s\n", c, interface); } } libnet_destroy(libnet); return (EXIT_SUCCESS); }