/****************************************************************************
   Program:     $Id: net.c,v 1.5 2006/11/19 21:01:17 rbeverly Exp $
   Author:      Rob Beverly <rbeverly@mit.edu>
   Date:        $Date: 2006/11/19 21:01:17 $
   Description: Spoofer utility routines
****************************************************************************/
#include "spoof.h"

#ifdef _WIN32
static int rawsock = 1;
#endif

/* Fill buffer with the spoofed packet */
int craftPacket(char *buf, char *payload, int payloadlen,
             struct sockaddr_in *src, struct sockaddr_in *dst, u_char ttl) {
    struct udpiphdr *ui;
    struct ip *ip;
    int packetlen;

    memset(buf, 0, BUFSIZE);
    ip = (struct ip *)buf;
    ui = (struct udpiphdr *)buf;
    packetlen = payloadlen + sizeof(struct udpiphdr);

    /* Copy payload */
    memcpy((buf + sizeof(struct udpiphdr)), payload, payloadlen);

    /* Create Pseudo-Header First */
    ui->ui_pr = IPPROTO_UDP;
    ui->ui_len = htons(payloadlen + sizeof(struct udphdr));
    ui->ui_src = src->sin_addr;
    ui->ui_dst = dst->sin_addr;
    ui->ui_sport = src->sin_port;
    ui->ui_dport = dst->sin_port;
    ui->ui_ulen = ui->ui_len;
    if ((ui->ui_sum = in_cksum((u_short *) ui, packetlen)) == 0)
        ui->ui_sum = 0xffff;

    ip->ip_v = IPVERSION;
    ip->ip_hl = sizeof(struct ip) >> 2;
    ip->ip_tos = 0;

    /* FreeBSD raw sockets expect host not network order */
#ifdef _FBSD
    ip->ip_len = packetlen;
    ip->ip_off = IP_DF;
#else
    ip->ip_len = htons(packetlen);
    ip->ip_off = htons(IP_DF);
#endif
    ip->ip_id = rand() % 32768;
    ip->ip_sum = 0;
    ip->ip_ttl = ttl;

    if (DEBUG) {
        printf("Complete packet:\n");
        dumpPacket((unsigned char *)ip, packetlen);
    }
    return (packetlen);
}


/* Build Spoofer Report */
void craftReport(spoof_t *report, unsigned short unused, 
                unsigned long addr, char *seqno) {
#ifdef SPOOFER_BIG_ENDIAN
    report->ver = byte16Swap(VERSION);
    report->unused = byte16Swap(unused);
#else
    report->ver = VERSION;
    report->unused = unused;
#endif
    report->addr = addr;
    strncpy((char *) report->seqno, seqno, SEQNOSIZE);
}


unsigned short
in_cksum(unsigned short *addr, int len)
{
	int				nleft = len;
	int				sum = 0;
	unsigned short	*w = addr;
	unsigned short	answer = 0;

	/*
	 * 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.
	 */
	while (nleft > 1)  {
		sum += *w++;
		nleft -= 2;
	}

		/* 4mop up an odd byte, if necessary */
	if (nleft == 1) {
		*(unsigned char *)(&answer) = *(unsigned char *)w ;
		sum += answer;
	}

		/* 4add back carry outs from top 16 bits to low 16 bits */
	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
	sum += (sum >> 16);			/* add carry */
	answer = ~sum;				/* truncate to 16 bits */
	return(answer);
}


/* Debug routine for examining raw packets */
void dumpPacket(unsigned char *pkt, int len) {
	int i;
	for (i=1;i<=len;i++) {
		printf("%02x ", *pkt);
		pkt++;
		if (i%4 == 0) printf("\n");
	}
	printf("\n");
}

/* Generate a random ASCII sequence */
void genSequence(unsigned char *buf, int len) {
	int i;
	int byte;
	rand();
	for (i=0;i<len;i++) {
		byte = (int) ((double)rand() / ((double)RAND_MAX + 1) * 256);
		if (byte >= 48 && byte <= 57) {
			*buf = byte;
			buf++;
		} else if (byte >= 97 && byte <= 122) {
			*buf = byte;
			buf++;
		} else {
			i--;
		}
	}
	*buf = '\0';
}

/* Ugly and inefficient, but at least it's readable and endian-safe */
int checkRFC1918(struct in_addr *in) {
	in_addr_t a1, a2;
	
	a1 = inet_addr("10.0.0.0");
	a2 = inet_addr("10.255.255.255");
	if ( (ntohl(in->s_addr) >= ntohl(a1)) && (ntohl(in->s_addr) <= ntohl(a2)) )
		return 1;
	a1 = inet_addr("172.16.0.0");
	a2 = inet_addr("172.31.255.255");
	if ( (ntohl(in->s_addr) >= ntohl(a1)) && (ntohl(in->s_addr) <= ntohl(a2)) )
		return 1;
	a1 = inet_addr("192.168.0.0");
	a2 = inet_addr("192.168.255.255");
	if ( (ntohl(in->s_addr) >= ntohl(a1)) && (ntohl(in->s_addr) <= ntohl(a2)) )
		return 1;

	return 0;
}


/* 
  Handy routines that follow taken directly from R. Stevens UNP 
*/

ssize_t						/* Read "n" bytes from a descriptor. */
readn(int fd, void *vptr, size_t n)
{
	size_t	nleft;
	ssize_t	nread;
	char	*ptr;

	ptr = vptr;
	nleft = n;
	while (nleft > 0) {
		if ( (nread = read(fd, ptr, nleft)) < 0) {
			if (errno == EINTR)
				nread = 0;		/* and call read() again */
			else
				return(-1);
		} else if (nread == 0)
			break;				/* EOF */

		nleft -= nread;
		ptr   += nread;
	}
	return(n - nleft);		/* return >= 0 */
}
/* end readn */

ssize_t
Readn(int fd, void *ptr, size_t nbytes)
{
	ssize_t		n;

	if ( (n = readn(fd, ptr, nbytes)) < 0)
		perror("readn error");
	return(n);
}


ssize_t						/* Write "n" bytes to a descriptor. */
writen(int fd, const void *vptr, size_t n)
{
	size_t		nleft;
	ssize_t		nwritten;
	const char	*ptr;

	ptr = vptr;
	nleft = n;
	while (nleft > 0) {
#if _WIN32
		if ( (nwritten = send(fd, ptr, nleft, 0)) <= 0) {
#else
		if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
#endif
			if (errno == EINTR)
				nwritten = 0;		/* and call write() again */
			else
				return(-1);			/* error */
		}

		nleft -= nwritten;
		ptr   += nwritten;
	}
	return(n);
}
/* end writen */

void
Writen(int fd, void *ptr, size_t nbytes)
{
	if (writen(fd, ptr, nbytes) != nbytes)
		perror("writen error");
}


static ssize_t
my_read(int fd, char *ptr)
{
	static int	read_cnt = 0;
	static char	*read_ptr;
	static char	read_buf[MAXLINE];

	if (read_cnt <= 0) {
again:
#if _WIN32
		if ( (read_cnt = recv(fd, read_buf, sizeof(read_buf), 0)) < 0) {
#else
		if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
#endif
			if (errno == EINTR)
				goto again;
			return(-1);
		} else if (read_cnt == 0)
			return(0);
		read_ptr = read_buf;
	}

	read_cnt--;
	*ptr = *read_ptr++;
	return(1);
}

ssize_t
readline(int fd, void *vptr, size_t maxlen)
{
	int		n, rc;
	char	c, *ptr;

	ptr = vptr;
	for (n = 1; n < maxlen; n++) {
		if ( (rc = my_read(fd, &c)) == 1) {
			*ptr++ = c;
			if (c == '\n')
				break;	/* newline is stored, like fgets() */
		} else if (rc == 0) {
			if (n == 1)
				return(0);	/* EOF, no data read */
			else
				break;		/* EOF, some data was read */
		} else
			return(-1);		/* error, errno set by read() */
	}

	*ptr = 0;	/* null terminate like fgets() */
	return(n);
}
/* end readline */

ssize_t
Readline(int fd, void *ptr, size_t maxlen)
{
	ssize_t		n;

	if ( (n = readline(fd, ptr, maxlen)) < 0)
		perror("readline error");
    if (n == 0)
        printf("** server terminated prematurely");
	return(n);
}

/* New socket wrapper */
int newSocket(int type, int proto) {
    int sock = 0;

#ifdef _WIN32
    sock = socket(AF_INET, type, proto);
    if (sock == INVALID_SOCKET) 
        winfatal("** WSASocket() failed: %d\n", WSAGetLastError());
#else
    if ((sock = socket(AF_INET, type, proto)) < 0) 
        pfatal("create socket");
#endif
    return (sock);
}

int connectSock(int sock, struct sockaddr_in *dst, int len) {
#ifdef _WIN32
    int ret;

    ret = connect(sock, (SOCKADDR *) dst, len);
    if (ret == SOCKET_ERROR)
        winfatal("** connect failed: %d\n", WSAGetLastError());
#else
    if ((connect(sock, (struct sockaddr *) dst, len)) < 0) 
        pfatal("connect");
#endif
    return (1);
}

int optSocketTTL(int sock, int val) {
#ifdef _WIN32
    BOOL on = TRUE;
    int ret;
#else
    int on = 1;
#endif
    on = val;

#ifdef _WIN32
    ret = setsockopt(sock, IPPROTO_IP, IP_TTL, (char *)&on, sizeof(on));
    if (ret == SOCKET_ERROR) 
        winfatal("** setsockopt(IP_TTL) failed: %d\n", WSAGetLastError());
#else
    if ((setsockopt(sock, IPPROTO_IP, IP_TTL, (char *)&on, sizeof(on))) < 0) 
        pfatal("setsockopt IP_TTL");
#endif
    return (1);
}

int optSocketHDRINCL(int sock) {
#ifdef _WIN32
    BOOL on = TRUE;
    int ret;
#else
    int on = 1;
#endif

#ifdef _WIN32
    ret = setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on));
    if (ret == SOCKET_ERROR) 
        winfatal("** setsockopt(IP_HDRINCL) failed: %d\n", WSAGetLastError());
#else
    if ((setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on))) < 0) 
        pfatal("setsockopt IP_HDRINCL");
#endif
    return (1);
}

int socketSend(int sock, void *msg, int len, struct sockaddr_in *dst, int tolen) {
#ifdef _WIN32
    int ret;

    ret = sendto(sock, (unsigned char *)msg, len, 0, (SOCKADDR *) dst, tolen);
    if (ret == SOCKET_ERROR) {
        printf("** sendto() failed: %d\n", WSAGetLastError());
        return (SOCKET_ERROR);
    }
#else
    if ((sendto(sock, (unsigned char *)msg, len, 0, (struct sockaddr *) dst, tolen)) < 0) {
        perror("sendto");
        return (SENDTO_ERROR);
    }
#endif
    return (1);
}

int socketSendSpoof(int sock, void *msg, int len, struct sockaddr_in *dst, int tolen) {
#ifdef _WIN32
    int ret;

    if (rawsock) {
        ret = sendto(sock, (unsigned char *)msg, len, 0, (SOCKADDR *) dst, tolen);
        if (ret == SOCKET_ERROR) {
            if (WSAGetLastError() == 10004) {
                printf("%s", WIN_SEND_ERR);
                rawsock = 0;
                return (WINRAWSOCK_ERROR);
            } else {
                printf("** sendto() failed: %d\n", WSAGetLastError());
            }
            return (SOCKET_ERROR);
        }
    } else {
        ret = etherSend(msg, len);
    }
#else
    if ((sendto(sock, (unsigned char *)msg, len, 0, (struct sockaddr *) dst, tolen)) < 0) {
        perror("sendto");
        return (SENDTO_ERROR);
    }
#endif
    return (1);
}


syntax highlighted by Code2HTML, v. 0.9.1