/* * $Id: dhcp_discover.c,v 1.3 2004/01/03 20:31:01 mike Exp $ * * libnet 1.1 * Build a DHCP discover packet * To view: /usr/sbin/tcpdump -vvvvven -s 4096 'port 67 or port 68' * * Copyright (c) 1998 - 2004 Mike D. Schiffman * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * */ #if (HAVE_CONFIG_H) #include "../include/config.h" #endif #include "./libnet_test.h" #ifdef __WIN32__ #include "../include/win32/getopt.h" #endif void usage(char *prog) { fprintf(stderr, "Usage: %s interface\n", prog); exit(1); } int main(int argc, char *argv[]) { char *intf; u_long src_ip, options_len, orig_len; int i; libnet_t *l; libnet_ptag_t t; libnet_ptag_t ip; libnet_ptag_t udp; libnet_ptag_t dhcp; struct libnet_ether_addr *ethaddr; struct libnet_stats ls; char errbuf[LIBNET_ERRBUF_SIZE]; u_char options_req[] = { LIBNET_DHCP_SUBNETMASK , LIBNET_DHCP_BROADCASTADDR , LIBNET_DHCP_TIMEOFFSET , LIBNET_DHCP_ROUTER , LIBNET_DHCP_DOMAINNAME , LIBNET_DHCP_DNS , LIBNET_DHCP_HOSTNAME }; u_char *options; u_char enet_dst[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; u_char *tmp; // have to specify interface if (argc != 2) usage(argv[0]); intf = argv[1]; l = libnet_init( LIBNET_LINK, // injection type intf, // network interface errbuf); // errbuf if (!l) { fprintf(stderr, "libnet_init: %s", errbuf); exit(EXIT_FAILURE); } else { src_ip = libnet_get_ipaddr4(l);; if ((ethaddr = libnet_get_hwaddr(l)) == NULL) { fprintf(stderr, "libnet_get_hwaddr: %s\n", libnet_geterror(l)); exit(EXIT_FAILURE); } printf("ip addr : %s\n", libnet_addr2name4(src_ip, LIBNET_DONT_RESOLVE)); printf("eth addr : "); for (i = 0; i < 6; i++) { printf("%2.2x", ethaddr->ether_addr_octet[i]); if (i != 5) { printf(":"); } } printf("\n"); // build options packet i = 0; options_len = 3; // update total payload size // we are a discover packet options = malloc(3); options[i++] = LIBNET_DHCP_MESSAGETYPE; // type options[i++] = 1; // len options[i++] = LIBNET_DHCP_MSGDISCOVER; // data orig_len = options_len; options_len += sizeof(options_req) + 2; // update total payload size // workaround for realloc on old machines // options = realloc(options, options_len); // resize options buffer tmp = malloc(options_len); memcpy(tmp, options, orig_len); free(options); options = tmp; // we are going to request some parameters options[i++] = LIBNET_DHCP_PARAMREQUEST; // type options[i++] = sizeof(options_req); // len memcpy(options + i, options_req, sizeof(options_req)); // data i += sizeof(options_req); // if we have an ip already, let's request it. if (src_ip) { orig_len = options_len; options_len += 2 + sizeof(src_ip); // workaround for realloc on old machines // options = realloc(options, options_len); tmp = malloc(options_len); memcpy(tmp, options, orig_len); free(options); options = tmp; options[i++] = LIBNET_DHCP_DISCOVERADDR; // type options[i++] = sizeof(src_ip); // len memcpy(options + i, (char *)&src_ip, sizeof(src_ip));// data i += sizeof(src_ip); } // end our options packet // workaround for realloc on old machines // options = realloc(options, options_len); // resize options buffer orig_len = options_len; options_len += 1; tmp = malloc(options_len); memcpy(tmp, options, orig_len); free(options); options = tmp; options[i++] = LIBNET_DHCP_END; // make sure we are at least the minimum length, if not fill // this could go in libnet, but we will leave it in the app for now if (options_len + LIBNET_DHCPV4_H < LIBNET_BOOTP_MIN_LEN) { orig_len = options_len; options_len = LIBNET_BOOTP_MIN_LEN - LIBNET_DHCPV4_H; // workaround for realloc on old machines // options = realloc(options, options_len); tmp = malloc(options_len); memcpy(tmp, options, orig_len); free(options); options = tmp; memset(options + i, 0, options_len - i); } // the goodies are here dhcp = libnet_build_dhcpv4( LIBNET_DHCP_REQUEST, // opcode 1, // hardware type 6, // hardware address length 0, // hop count 0xdeadbeef, // transaction id 0, // seconds since bootstrap 0x8000, // flags 0, // client ip 0, // your ip 0, // server ip 0, // gateway ip ethaddr->ether_addr_octet, // client hardware addr NULL, // server host name NULL, // boot file options, // dhcp options stuck in payload since it is dynamic options_len, // length of options l, // libnet handle 0); // libnet id // wrap it udp = libnet_build_udp( 68, // source port 67, // destination port LIBNET_UDP_H + LIBNET_DHCPV4_H + options_len, // packet size 0, // checksum NULL, // payload 0, // payload size l, // libnet handle 0); // libnet id // hook me up with some ipv4 ip = libnet_build_ipv4( LIBNET_IPV4_H + LIBNET_UDP_H + LIBNET_DHCPV4_H + options_len, // length 0x10, // TOS 0, // IP ID 0, // IP Frag 16, // TTL IPPROTO_UDP, // protocol 0, // checksum src_ip, // src ip inet_addr("255.255.255.255"), // destination ip NULL, // payload 0, // payload size l, // libnet handle 0); // libnet id // we can just autobuild since we arent doing anything tricky t = libnet_autobuild_ethernet( enet_dst, // ethernet destination ETHERTYPE_IP, // protocol type l); // libnet handle // write to the wire if (libnet_write(l) == -1) { fprintf(stderr, " %s: libnet_write: %s\n", argv[0], strerror(errno)); exit(EXIT_FAILURE); } // fill and print stats libnet_stats(l, &ls); fprintf(stderr, "Packets sent: %lld\n" "Packet errors: %lld\n" "Bytes written: %lld\n", ls.packets_sent, ls.packet_errors, ls.bytes_written); libnet_destroy(l); // free mem free(options); exit(0); } exit(0); }