/* * Arp toolkit * * Simple frontend for quickly crafting arp packets. * * Jon Hart * Sat Aug 31 13:06:48 EDT 2002 * * Requires: * libnet >= 1.1.x (http://www.packetfactory.net/projects/libnet/) * root * * Compile with something like: * gcc -Wall `libnet-config --defines --cflags` -o arp-tk arp-tk.c `libnet-config --libs` * * Sample uses where 10.0.0.1 is your gateway, eth0 is your default interface * * (arp spoof the gateway to intercept traffic) * arp-tk -i eth0 -o rep -p 10.0.0.1 * * (arp ping some host) * arp-tk -i eth0 -o req -P 10.0.0.2 * * (act as a rarp client ("I have this hardware address. What is my IP?")) * arp-tk -i eth0 -v -o rreq -S 1:2:3:4:5:6 -D 1:2:3:4:5:6 * * (act as a rarpd server for a:b:c:d:e:f/1.2.3.4) * arp-tk -i eth0 -o rrep -D 1:2:3:4:5:6 -P 1.2.3.4 * * * Copyright (c) 2002, Jon Hart * All rights reserved. * * 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 #if (SOLARIS || BSD) #include #else #include #endif #define OPT_HELP 0 #define OPT_VERBOSE 1 #define OPT_INTERFACE 2 #define OPT_SRCIP 3 #define OPT_DSTIP 4 #define OPT_SRCETHER 5 #define OPT_DSTETHER 6 #define OPT_SRCARP 7 #define OPT_DSTARP 8 #define OPT_ARPOP 9 #define OPT_ARPLOAD 10 /* I hate the 'options' thing that people use for getopt. How useless */ 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}, {"source IP", 1, 0}, {"destination IP", 1, 0}, {"source ethernet address", 1, 0}, {"destination ethernet address", 1, 0}, {"source arp address", 1, 0}, {"destination arp address", 1, 0}, {"arp operation", 1, 0}, {"arp payload", 0, 0} }; void usage() { fprintf(stderr, "\tarp-tk\n\tA simple ARP Toolkit\n\tby Jon Hart \n"); fprintf(stderr, "\thttp://spoofed.org/files/arp-tk.c\n"); fprintf(stderr, "\nUsage:\n"); fprintf(stderr, "\n\tRequired:\n"); fprintf(stderr, "\t-i Specify interface\n"); fprintf(stderr, "\t-o One of req, rep, rreq, rrep, ireq, irep\n"); fprintf(stderr, "\n\tOptional:\n\n"); fprintf(stderr, "\tLink Layer:\n"); fprintf(stderr, "\t-e Source ethernet address (default: auto)\n"); fprintf(stderr, "\t-E Destination ethernet adddress (default: FF:FF:FF:FF:FF:FF)\n"); fprintf(stderr, "\tARP Layer:\n"); fprintf(stderr, "\t-p Source IP address (default: auto)\n"); fprintf(stderr, "\t-P Destination IP address (default: 0.0.0.0)\n"); fprintf(stderr, "\t-d Source arp address (default: auto)\n"); fprintf(stderr, "\t-D Destination arp address (default: FF:FF:FF:FF:FF:FF)\n"); fprintf(stderr, "\t-c Put a payload in the arp packet. Serves no purpose. Or does it?\n"); fprintf(stderr, "\t-h Help\n"); fprintf(stderr, "\t-v Be verbose\n"); } int main(int argc, char **argv) { int c; libnet_t *libnet; libnet_ptag_t arp, ether; u_long src_ip, dst_ip; u_short arpop, ethertype; /* The source and destination MAC addresses * for the ethernet level */ struct libnet_ether_addr *src_ether; struct libnet_ether_addr *dst_ether; /* The source and destination MAC addresses * for the arp level */ struct libnet_ether_addr *src_arp; struct libnet_ether_addr *dst_arp; char *interface; struct ether_addr *ether_t; char errbuf[LIBNET_ERRBUF_SIZE]; char *arp_payload; int arp_payload_l; u_char broadcast[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; while ((c = getopt(argc, argv, "i:c:o:e:d:E:D:p:P:vh")) != EOF) { switch (c) { case 'h': usage(); exit(EXIT_SUCCESS); case 'v': opts[OPT_VERBOSE].set = 1; break; case 'i': interface = optarg; opts[OPT_INTERFACE].set = 1; break; case 'c': arp_payload = optarg; arp_payload_l = strlen(arp_payload); opts[OPT_ARPLOAD].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 'e': if ((ether_t = ether_aton(optarg)) == NULL) { printf("Invalid source ethernet address: %s\n", optarg); return(EXIT_FAILURE); } if ((src_ether = malloc(sizeof(struct libnet_ether_addr))) == NULL) { printf("Couldn't malloc() for src_ether\n"); return(EXIT_FAILURE); } memcpy(src_ether->ether_addr_octet, ether_t, sizeof(struct ether_addr)); opts[OPT_SRCETHER].set = 1; break; case 'd': if ((ether_t = ether_aton(optarg)) == NULL) { printf("Invalid source arp address: %s\n", optarg); return(EXIT_FAILURE); } if ((src_arp = malloc(sizeof(struct libnet_ether_addr))) == NULL) { printf("Couldn't malloc() for src_arp\n"); return(EXIT_FAILURE); } memcpy(src_arp->ether_addr_octet, ether_t, sizeof(struct ether_addr)); opts[OPT_SRCARP].set = 1; break; case 'E': if ((ether_t = ether_aton(optarg)) == NULL) { printf("Invalid destination ethernet address: %s\n", optarg); return(EXIT_FAILURE); } if ((dst_ether = malloc(sizeof(struct libnet_ether_addr))) == NULL) { printf("Couldn't malloc() for dst_ether\n"); return(EXIT_FAILURE); } memcpy(dst_ether->ether_addr_octet, ether_t, sizeof(struct ether_addr)); opts[OPT_DSTETHER].set = 1; break; case 'D': if ((ether_t = ether_aton(optarg)) == NULL) { printf("Invalid destination arp address: %s\n", optarg); return(EXIT_FAILURE); } if ((dst_arp = malloc(sizeof(struct libnet_ether_addr))) == NULL) { printf("Couldn't malloc() for dst_arp\n"); return(EXIT_FAILURE); } memcpy(dst_arp->ether_addr_octet, ether_t, sizeof(struct ether_addr)); opts[OPT_DSTARP].set = 1; break; case 'o': if (strncmp(optarg, "req", 3) == 0) { arpop = ARPOP_REQUEST; opts[OPT_ARPOP].set = 1; break; } else if (strncmp(optarg, "rep", 3) == 0) { arpop = ARPOP_REPLY; opts[OPT_ARPOP].set = 1; break; } else if (strncmp(optarg, "rreq", 4) == 0) { arpop = ARPOP_REVREQUEST; opts[OPT_ARPOP].set = 1; break; } else if (strncmp(optarg, "rrep", 4) == 0) { arpop = ARPOP_REVREPLY; opts[OPT_ARPOP].set = 1; break; } else if (strncmp(optarg, "ireq", 4) == 0) { arpop = ARPOP_INVREQUEST; opts[OPT_ARPOP].set = 1; break; } else if (strncmp(optarg, "irep", 4) == 0) { arpop = ARPOP_INVREPLY; opts[OPT_ARPOP].set = 1; break; } else { fprintf(stderr, "Invalid arp operation %s. Must be one of req, rep, rreq, rrep, ireq, or irep\n", optarg); opts[OPT_ARPOP].set = 0; goto fail; } default: usage(); goto fail; } } if (!opts[OPT_INTERFACE].set) { usage(); goto fail; } if ((libnet = libnet_init(LIBNET_LINK, interface, errbuf)) == NULL) { fprintf(stderr, "libnet_init() failed: %s", errbuf); goto fail; } if (!opts[OPT_SRCETHER].set) { 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)); libnet_destroy(libnet); goto fail; } } if (!opts[OPT_DSTETHER].set) { if ((dst_ether = malloc(sizeof(struct libnet_ether_addr))) == NULL) { printf("Couldn't malloc() for dst_ether\n"); libnet_destroy(libnet); goto fail; } memcpy(dst_ether->ether_addr_octet, broadcast, sizeof(broadcast)); opts[OPT_DSTETHER].set = 1; } if (!opts[OPT_SRCARP].set) { if ((src_arp = libnet_get_hwaddr(libnet)) == NULL) { if ((src_arp = malloc(sizeof(struct libnet_ether_addr))) == NULL) { printf("Couldn't malloc() for src_arp\n"); libnet_destroy(libnet); goto fail; } memcpy(src_arp->ether_addr_octet, broadcast, sizeof(broadcast)); } } if (!opts[OPT_DSTARP].set) { if ((dst_arp = malloc(sizeof(struct libnet_ether_addr))) == NULL) { printf("Couldn't malloc() for dst_arp\n"); libnet_destroy(libnet); goto fail; } memcpy(dst_arp->ether_addr_octet, broadcast, sizeof(broadcast)); opts[OPT_DSTARP].set = 1; } if (!opts[OPT_SRCIP].set) { src_ip = libnet_get_ipaddr4(libnet); if (src_ip == -1) { fprintf(stderr, "No source IP specified and I couldn't guess it: %s\n", libnet_geterror(libnet)); libnet_destroy(libnet); goto fail; } opts[OPT_SRCIP].set = 1; } if (!opts[OPT_DSTIP].set) { dst_ip = libnet_name2addr4(libnet, "0.0.0.0", LIBNET_RESOLVE); opts[OPT_DSTIP].set = 1; } if (!opts[OPT_ARPLOAD].set) { arp_payload = NULL; arp_payload_l = 0; opts[OPT_ARPLOAD].set = 1; } if (opts[OPT_ARPOP].set) { /* inverse arp is simply an extension of regular arp. * reverse arp is all sorts of special, so it has its * own ethertype. * just make sure we use the right one... */ switch (arpop) { case ARPOP_REVREQUEST: ethertype = ETHERTYPE_REVARP; break; case ARPOP_REVREPLY: ethertype = ETHERTYPE_REVARP; break; default: ethertype = ETHERTYPE_ARP; break; } } /* build the arp part of the packet */ arp = libnet_build_arp( ARPHRD_ETHER, ETHERTYPE_IP, ETHER_ADDR_LEN, 4, arpop, src_arp->ether_addr_octet, (u_char *)&src_ip, dst_arp->ether_addr_octet, (u_char *)&dst_ip, arp_payload, arp_payload_l, libnet, 0); if (arp == -1) { fprintf(stderr, "Can't build arp: %s\n", libnet_geterror(libnet)); libnet_destroy(libnet); goto fail; } /* sprinkle some ethernet */ ether = libnet_build_ethernet( dst_ether->ether_addr_octet, src_ether->ether_addr_octet, ethertype, NULL, 0, libnet, 0); if (ether == -1) { fprintf(stderr, "Can't build ethernet: %s\n", libnet_geterror(libnet)); libnet_destroy(libnet); goto fail; } 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) { printf("Link Layer: "); printf("%s -> ", opts[OPT_SRCETHER].set ? ether_ntoa((struct ether_addr *) src_ether->ether_addr_octet) : interface); printf("%s\n", opts[OPT_DSTETHER].set ? ether_ntoa((struct ether_addr *) dst_ether->ether_addr_octet) : "(auto)"); printf("ARP Layer: "); switch (arpop) { case ARPOP_REQUEST: printf("arp who-has %s tell %s\n", libnet_addr2name4(dst_ip, LIBNET_DONT_RESOLVE), libnet_addr2name4(src_ip, LIBNET_DONT_RESOLVE)); break; case ARPOP_REPLY: printf("arp reply %s is at %s ", libnet_addr2name4(src_ip, LIBNET_DONT_RESOLVE), ether_ntoa((struct ether_addr *) src_arp->ether_addr_octet)); printf("tell %s (%s)\n\n", libnet_addr2name4(dst_ip, LIBNET_DONT_RESOLVE), ether_ntoa((struct ether_addr *) dst_arp->ether_addr_octet)); break; case ARPOP_INVREQUEST: printf("inverse arp who is %s (%s) ", ether_ntoa((struct ether_addr *) dst_arp->ether_addr_octet), libnet_addr2name4(dst_ip, LIBNET_DONT_RESOLVE)); printf("tell %s (%s)\b\n", ether_ntoa((struct ether_addr *) src_arp->ether_addr_octet), libnet_addr2name4(src_ip, LIBNET_DONT_RESOLVE)); break; case ARPOP_INVREPLY: printf("inverse arp %s is at %s ", ether_ntoa((struct ether_addr *) src_arp->ether_addr_octet), libnet_addr2name4(src_ip, LIBNET_DONT_RESOLVE)); printf("tell %s (%s)\n\n", libnet_addr2name4(dst_ip, LIBNET_DONT_RESOLVE), ether_ntoa((struct ether_addr *) dst_arp->ether_addr_octet)); break; case ARPOP_REVREQUEST: printf("rarp who is %s ", ether_ntoa((struct ether_addr *) dst_arp->ether_addr_octet)); printf("tell %s\n\n", ether_ntoa((struct ether_addr *) src_arp->ether_addr_octet)); break; case ARPOP_REVREPLY: printf("rarp %s is at %s\n\n", ether_ntoa((struct ether_addr *) dst_arp->ether_addr_octet), libnet_addr2name4(dst_ip, LIBNET_DONT_RESOLVE)); break; } } } goto pass; pass: libnet_destroy(libnet); if (opts[OPT_SRCETHER].set) { free(src_ether); } if (opts[OPT_DSTETHER].set) { free(dst_ether); } if (opts[OPT_SRCARP].set) { free(src_arp); } if (opts[OPT_DSTARP].set) { free(dst_arp); } return(EXIT_SUCCESS); fail: if (opts[OPT_SRCETHER].set) { free(src_ether); } if (opts[OPT_DSTETHER].set) { free(dst_ether); } if (opts[OPT_SRCARP].set) { free(src_arp); } if (opts[OPT_DSTARP].set) { free(dst_arp); } return(EXIT_FAILURE); }