/*
 * spoofscan.c  .. - jsbach proof of concept program..... a more robust usage
 * of this concept is forthcoming.. spoofs ur ip as another box on ur
 * ethernet segment, portscans a host "from" that ip, sniffs responses from
 * the host.
 */

/*
 to compile: gcc spoofscan.c -lpcap -o ss
 to use: ./ss host_to_spoof_as host_to_scan high_port
 remember, the host you're spoofing as MUST be on the same ethernet
 segment as you are, or this program will not work!
*/

#include <netdb.h>
#include <linux/sockios.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#define __FAVOR_BSD
#include <netinet/tcp.h>
#include <bpf.h>
#include <pcap.h>
pcap_t         *pcap_global_descriptor;
char           *deviceglobal;
int             offset;		/* offset from datalink protocol hdr to ip
				 * hdr */


int
startpcap(void)
{
	char            errbuf[1028];
	int             datalink;
	struct pcap_pkthdr useless;
	/* is the device null or set to the default still? if so look it up */
	if (!deviceglobal || !strcmp(deviceglobal, "default")) {
		deviceglobal = (char *) malloc(512);
		strcpy(deviceglobal, pcap_lookupdev(errbuf));
		printf("ok got your device, it's %s.\n", deviceglobal);
	}
	/* its still null?! exit this mothafuckaH! :-) */
	if (!deviceglobal) {
		printf("Error getting device - %s\n", errbuf);
		exit(1);
	}
	/* now open a "datalink descriptor" */
	pcap_global_descriptor = pcap_open_live(deviceglobal, 90000, 1, 1000, errbuf);
	if (pcap_global_descriptor == NULL) {
		printf("error opening pcap: %s\n", errbuf);
		exit(1);
	}
	/*
	 * set the offset from the beginning of the datagram that the iphdr
	 * starts.
	 */

	datalink = pcap_datalink(pcap_global_descriptor);
	bzero(&useless, sizeof(struct pcap_pkthdr));
	/*
	 * these offsets were taken from queso by savage@apostols.org who
	 * took them from lamont something-or-other apparently
	 */
	switch (datalink) {
	case DLT_EN10MB:
		offset = 14;
		break;
	case DLT_NULL:
	case DLT_PPP:
		offset = 4;
		break;
	case DLT_SLIP:
		offset = 16;
		break;
	case DLT_RAW:
		offset = 0;
		break;
	case DLT_SLIP_BSDOS:
	case DLT_PPP_BSDOS:
		offset = 24;
		break;
	case DLT_ATM_RFC1483:
		offset = 8;
		break;
	case DLT_IEEE802:
		offset = 22;
		break;
	default:
		fprintf(stderr, "unknown datalink type (%d)", datalink);
		return (0);
	}
	return 1;
}

void
endpcap(void)
{
	pcap_close(pcap_global_descriptor);
}

int
recvtcp(u_long from, char *buf, int sizeofbuffer)
{
	int             datalink;
	struct pcap_pkthdr useless;

	struct p4ck3t {
		struct iphdr    ip;
		struct tcphdr   tcp;
		u_char         *data;
	}
	               *p4ck3t;
	p4ck3t = (struct p4ck3t *) pcap_next(pcap_global_descriptor, &useless);
	(char *) p4ck3t += offset;
	if (ntohs(p4ck3t->ip.tot_len) > sizeofbuffer - 1)
		return 0;
	memcpy(buf, p4ck3t, ntohs(p4ck3t->ip.tot_len));
	/* check to see if its somewhat valid */
	if (p4ck3t->ip.version != 4) {
		return 0;
	}
	if (p4ck3t->ip.protocol == IPPROTO_TCP) {
		if (p4ck3t->ip.saddr == from)
			return 1;
	}
	return 0;
}


unsigned short
in_cksum(unsigned short *ptr, int nbytes)
{

	register long   sum;	/* assumes long == 32 bits */
	u_short         oddbyte;
	register u_short answer;/* assumes u_short == 16 bits */

	/*
         * Our algorithm is simple, using a 32-bit accumulator (sum),
         * we add sequential 16-bit words to it, and at the end, fold back
         * all the carry bits from the top 16 bits into the lower 16 bits.
         */

	sum = 0;
	while (nbytes > 1) {
		sum += *ptr++;
		nbytes -= 2;
	}

	/* mop up an odd byte, if necessary */
	if (nbytes == 1) {
		oddbyte = 0;	/* make sure top half is zero */
		*((u_char *) & oddbyte) = *(u_char *) ptr;	/* one byte only */
		sum += oddbyte;
	}
	/*
         * Add back carry outs from top 16 bits to low 16 bits.
         */

	sum = (sum >> 16) + (sum & 0xffff);	/* add high-16 to low-16 */
	sum += (sum >> 16);	/* add carry */
	answer = ~sum;		/* ones-complement, then truncate to 16 bits */
	return (answer);
}

int
send_raw_tcp(u_long srcip, u_long dstip, u_short th_sport,
	     u_short th_dport, u_short th_flags,
	     u_short th_win)
{

	int             sockfd, fromlen;	/* guess */
	int             off = 1;/* off is really on.. heh=) */
	struct pseudo {		/* for tcp checksum calculation */
		u_long          saddr;
		u_long          daddr;
		u_char          zero;
		u_char          protocol;
		u_short         length;
	};
	static struct tcphdr tcpret;
	int             retval;
	struct sockaddr_in sheep;	/* address info */

	u_char          packet[sizeof(struct iphdr) + sizeof(struct pseudo) + sizeof(struct tcphdr)];
	struct iphdr   *ip = (struct iphdr *) packet;
	struct pseudo  *pseudo = (struct pseudo *) (packet + sizeof(struct iphdr));
	struct tcphdr  *tcp = (struct tcphdr *) (packet + sizeof(struct iphdr) + sizeof(struct pseudo));

	bzero(packet, sizeof(packet));
	bzero(&sheep, sizeof(sheep));

	srand(time(NULL));

	pseudo->saddr = srcip;
	pseudo->daddr = dstip;
	pseudo->zero = 0;
	pseudo->protocol = IPPROTO_TCP;
	pseudo->length = htons(sizeof(struct tcphdr));	/* is this right? */
	ip->version = 4;
	ip->ihl = 5;
	ip->id = 666;
	ip->saddr = srcip;
	//de src ip address iz SPOOFED HAHAHBWHAHAH

		ip->daddr = dstip;
	ip->protocol = IPPROTO_TCP;
	//YESSSSSSSS

		ip->ttl = 42;
	ip->frag_off = 0;
	ip->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr);
	tcp->th_sport = htons(th_sport);	/* ba ba ba */
	tcp->th_dport = htons(th_dport);
	tcp->th_seq = htonl(rand());	/* if i had just put in some number
					 * maybe someone would build a
					 * firewall to block thoze
					 * segmentz!#$@ =) */
	tcp->th_ack = htonl(rand());
	tcp->th_off = 5;
	tcp->th_flags = th_flags;
	tcp->th_win = htons(th_win);
	tcp->th_urp = 0;
	tcp->th_sum = in_cksum((u_short *) pseudo, sizeof(struct pseudo) + sizeof(struct tcphdr));

	sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
	retval = setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &off, sizeof(off));
	memcpy(pseudo, tcp, 20);
	sheep.sin_family = AF_INET;
	sheep.sin_addr.s_addr = dstip;
	fromlen = sizeof(sheep);
	sendto(sockfd, packet, sizeof(struct iphdr) + sizeof(struct tcphdr),
	       0, (struct sockaddr *) & sheep, sizeof(sheep));
	close(sockfd);
}

unsigned long int
lookup(char *hostname)
{
	struct hostent *name;
	unsigned long int address;

	if ((address = inet_addr(hostname)) != -1)
		return address;
	if ((name = gethostbyname(hostname)) == NULL)
		return -1;

	memcpy(&address, name->h_addr, name->h_length);
	return address;
}

char
               *
rlookup(u_long ip)
{
	static char     hostname[256];
	struct hostent *host;
	struct sockaddr_in addr;

	addr.sin_addr.s_addr = ip;

	host = gethostbyaddr((char *) &addr.sin_addr, sizeof(addr.sin_addr), AF_INET);

	if (host == NULL)
		snprintf(hostname, 256, "%s\0", inet_ntoa(ip));
	else
		snprintf(hostname, sizeof(hostname), "%s\0", host->h_name);

	return hostname;
}

int
main(int argc, char **argv)
{
	u_long          ourip, theirip;
	u_short         highport, count;
	int             timeout;
	char            readbuf[2048];
	struct p4ck3t {
		struct iphdr    ip;
		struct tcphdr   tcp;
		char            data[2000];
	}              *p4ck3t;

	p4ck3t = (struct p4ck3t *) readbuf;

	if (argc < 3) {
		printf("usage: ./spoofscan <spoof ip> <their ip> <high port #>\n");
		printf("questions, comments, etc: jsb4ch@hotmail.com\n");
		exit(1);
	}
	if ((ourip = lookup(argv[1])) == (int) -1) {
		printf("invalid spoof ip.\n");
		exit(1);
	}
	if ((theirip = lookup(argv[2])) == (int) -1) {
		printf("invalid destination ip %s.\n", inet_ntoa(theirip));
		exit(1);
	}
	highport = atoi(argv[3]);
	printf("src address is %s\n", inet_ntoa(ourip));
	printf("dest address is %s.\n", inet_ntoa(theirip));
	timeout = time(NULL) + 5;
	for (count = 0; count < highport; count++) {
		send_raw_tcp(ourip, theirip, count, count, TH_SYN, 1028);
	}
	startpcap();
	while (time(NULL) < timeout) {
		if (recvtcp(theirip, readbuf, 500)) {
			if (p4ck3t->tcp.th_flags & TH_SYN)
				printf("-** port %d found open **-\n", ntohs(p4ck3t->tcp.th_sport));
		}
	}
}



