/****************************************************************************
Program: $Id: spoofer.c,v 1.22 2006/11/19 20:28:28 rbeverly Exp $
Author: Rob Beverly <rbeverly@mit.edu>
Date: $Date: 2006/11/19 20:28:28 $
Description: Spoofer - generate spoofed packets
****************************************************************************/
#include "spoof.h"
int main(int argc, char **argv) {
struct sockaddr_in src, dst;
struct in_addr myaddress, tmpaddr;
struct in_addr a[ADDRS + SCANSPACE];
int numAddrs = ADDRS;
char *seqno[ADDRS + SCANSPACE];
char buf[BUFSIZE];
char arg[SMALLBUF], sessionkey[SMALLBUF];
char tracebuf[BIGBUF];
spoof_t report;
char *icmpkey;
unsigned long sessionid = 0;
unsigned long dist = 0;
int spoofsock, ctrlsock, udpsock;
int status = VERSION;
int packetlen;
int ret;
int i, j;
a[0].s_addr = inet_addr("1.2.3.4"); /* valid, not in global BGP table */
a[1].s_addr = inet_addr("172.16.1.100"); /* invalid, RFC1918 addr */
a[2].s_addr = inet_addr("6.1.2.3"); /* valid, in global BGP table */
/* Init */
banner();
checkroot();
srand(time(NULL));
#ifdef _WIN32
win_init();
if (findInterfaces() > 1) {
printf("** Warning: found more than one numbered network interface:\n");
selectInterface();
}
#endif
/* Establish TCP control connection */
src.sin_family = AF_INET;
dst.sin_family = AF_INET;
dst.sin_addr.s_addr = inet_addr(SERVER);
src.sin_port = htons(SRC_PORT);
dst.sin_port = htons(REPORT_PORT);
ctrlsock = newSocket(SOCK_STREAM, IPPROTO_TCP);
connectSock(ctrlsock, &dst, sizeof(dst));
/* Create non-spoofing UDP socket for sanity check */
udpsock = newSocket(SOCK_DGRAM, IPPROTO_UDP);
/* Force TTL for non-spoofed UDP packets to measure hop distance */
optSocketTTL(udpsock, TTL_OUT);
/* Create UDP spoofing socket */
spoofsock = newSocket(SOCK_RAW, IPPROTO_UDP);
optSocketHDRINCL(spoofsock);
/* Say Hello. */
snprintf(buf, sizeof(buf), "HELLO %s %d\n", OS, VERSION);
Writen(ctrlsock, buf, strlen(buf));
Readline(ctrlsock, buf, BUFSIZE);
if (sscanf(buf, "%79s %lu", arg, (unsigned long *)&sessionid) == 2)
printf(">> Server response: %s %lu\n", arg, sessionid);
/* Play nicely. */
if (strstr(arg, "FORBIDDEN") != NULL) {
printf(">> Client forbidden by server. Bye.\n");
goto endtest;
}
/* Get my IP; populate adjacent netblock array */
snprintf(buf, sizeof(buf), "WHOAMI %s %d\n", OS, VERSION);
Writen(ctrlsock, buf, strlen(buf));
Readline(ctrlsock, buf, BUFSIZE);
if (sscanf(buf, "%79s %lu", arg, (unsigned long *)&(tmpaddr.s_addr)) == 2) {
#ifdef SPOOFER_BIG_ENDIAN
myaddress.s_addr = (unsigned long) byte32Swap(tmpaddr.s_addr);
#else
myaddress = tmpaddr;
#endif
if (DEBUG) {
printf("Got myaddr: %s\n", inet_ntoa(myaddress));
printf("RFC1918?: %d\n", checkRFC1918(&myaddress));
}
/* only scan adjacent address prefixes if not RFC1918 */
if (checkRFC1918(&myaddress) != 1) {
for (i = 0; i < SCANSPACE; i++) {
tmpaddr = myaddress;
if (ntohl(myaddress.s_addr) & (1 << i))
tmpaddr.s_addr = htonl(ntohl(myaddress.s_addr) - (1 << i));
else
tmpaddr.s_addr = htonl(ntohl(myaddress.s_addr) + (1 << i));
a[i + ADDRS] = tmpaddr;
}
numAddrs = ADDRS + SCANSPACE;
}
}
/* Send UDP packets to the DNS port of spoofer server */
dst.sin_port = htons(SERV_PORT);
/* Make certain non-spoofed packets can reach the server */
craftReport(&report, sessionid, myaddress.s_addr, NONCE);
printf(">> Source %d non-spoofed packets...\n", DUPLICATES);
for (j = 0; j < DUPLICATES; j++) {
socketSend(udpsock, &report, sizeof(report), &dst, sizeof(dst));
spoofSleep();
}
/* malloc space for array of sequence numbers */
for (i = 0; i < numAddrs; i++) {
seqno[i] = malloc(sizeof(char) * (SEQNOSIZE + 1));
}
#ifdef _WIN32
/* wait to register ethernet until we've already communicated with
the server -- this ensures there is an ARP entry waiting for us */
registerEther();
#endif
/* Send spoofed packets */
for (i = 0; i < numAddrs; i++) {
src.sin_addr = a[i];
genSequence((unsigned char *) seqno[i], SEQNOSIZE);
craftReport(&report, 0, src.sin_addr.s_addr, seqno[i]);
if (DEBUG) {
printf("Spoof attempt sequence number:\n");
dumpPacket(report.seqno, SEQNOSIZE);
}
packetlen = craftPacket(buf, (char *)&report, PAYLOADSIZE, &src, &dst, TTL_OUT);
printf(">> Source %d spoofed packets (IP: %s)...\n",
DUPLICATES, inet_ntoa(a[i]));
for (j = 0; j < DUPLICATES; j++) {
ret = socketSendSpoof(spoofsock, buf, packetlen, &dst, sizeof(dst));
if (ret == WINRAWSOCK_ERROR) {
/* after first winrawsock error, socketSendSpoof uses raw
ethernet frames. try again. */
j--;
} else if (ret == SOCKET_ERROR) {
strncpy(seqno[i], "SENDTOFAIL", strlen("SENDTOFAIL")+1);
/* don't try to send duplicates on error */
j += DUPLICATES;
} else if (ret == SENDTO_ERROR) {
strncpy(seqno[i], "SENDTOFAIL", strlen("SENDTOFAIL")+1);
}
spoofSleep();
}
}
/* Get my IP hop distance from the server */
snprintf(buf, sizeof(buf), "DISTANCE %s %d\n", OS, VERSION);
Writen(ctrlsock, buf, strlen(buf));
Readline(ctrlsock, buf, BUFSIZE);
if (sscanf(buf, "%79s %lu", arg, (unsigned long *)&dist) == 2) {
printf(">> Server response: %s %lu\n", arg, dist);
} else {
printf("** bogus distance response");
dist = 0;
}
/* Sanity check response */
if ( (dist < 0) || (dist > 50) ) {
printf("** bogus distance response");
dist = 0;
}
/* Send TTL-limited reverse traceroute spoofed packets */
src.sin_addr.s_addr = inet_addr(SERVER);
dst.sin_addr.s_addr = inet_addr(VALIDDST);
/* we encode the session ID into the UDP source port */
src.sin_port = htons(sessionid);
for (i = 1; i <= dist; i++) {
/* the TTL of the packet will be encoded as the size of the spoofed
* UDP datagram. TTL = UDPlength - 8 */
icmpkey = calloc(i, sizeof(char));
packetlen = craftPacket(buf, icmpkey, i, &src, &dst, i);
printf(">> Source %d reverse traceroute spoofed packets (TTL: %d)...\n",
DUPLICATES, i);
for (j = 0; j < DUPLICATES; j++) {
socketSendSpoof(spoofsock, buf, packetlen, &dst, sizeof(dst));
spoofSleep();
}
}
/* Send UDP packets to the DNS port of spoofer server */
dst.sin_addr.s_addr = inet_addr(SERVER);
dst.sin_port = htons(SERV_PORT);
/* We send this final round of non-spoofed UDP packets to determine
if the TTL (hop-count) changed during the test */
craftReport(&report, sessionid, myaddress.s_addr, NONCE);
printf(">> Source %d non-spoofed packets...\n", DUPLICATES);
for (j = 0; j < DUPLICATES; j++) {
socketSend(udpsock, &report, sizeof(report), &dst, sizeof(dst));
spoofSleep();
}
/* Confer with server to get results */
printf(">>\n>> Checking spoofing result...\n");
snprintf(buf, sizeof(buf), "SENT %d %d\n", numAddrs, VERSION);
Writen(ctrlsock, buf, strlen(buf));
Readline(ctrlsock, buf, BUFSIZE);
printf(">> Server response: %s", buf);
for (i = 0; i < numAddrs; i++) {
memset(buf, 0, BUFSIZE);
#ifdef SPOOFER_BIG_ENDIAN
snprintf(buf, sizeof(buf), "SPOOF %s %lu\n", seqno[i], byte32Swap(a[i].s_addr));
#else
snprintf(buf, sizeof(buf), "SPOOF %s %lu\n", seqno[i], (unsigned long)a[i].s_addr);
#endif
Writen(ctrlsock, buf, strlen(buf));
Readline(ctrlsock, buf, BUFSIZE);
printf(">> Source IP: %s Server response: %s", inet_ntoa(a[i]), buf);
}
/* run and send trace */
if (findtr(buf) >= 0) {
runtrace(buf, SERVER, tracebuf);
snprintf(buf, sizeof(buf), "TRACE %s %d\n", OS, VERSION);
Writen(ctrlsock, buf, strlen(buf));
Readline(ctrlsock, buf, BUFSIZE);
printf(">> Server response: %s", buf);
Writen(ctrlsock, tracebuf, strlen(tracebuf));
}
endtest:
/* end and cleanup */
snprintf(buf, sizeof(buf), "DONE %s %d\n", OS, status);
Writen(ctrlsock, buf, strlen(buf));
Readline(ctrlsock, buf, BUFSIZE);
if (sscanf(buf, "%79s %79s", arg, sessionkey) == 2)
printf(">> Server response: %s %s\n", arg, sessionkey);
close(udpsock);
close(spoofsock);
close(ctrlsock);
snprintf(buf, SMALLBUF*2, "http://%s/report.php?sessionkey=%s", REPORT_HOST, sessionkey);
printf("\nTest Complete.\n");
printf("Your test results:\n\t%s\n\n", buf);
#ifdef _WIN32
deregisterEther();
/* spawn browser window with the results */
ShellExecute(NULL, "open", buf, NULL, NULL, SW_SHOWNORMAL);
winpause("Press Enter to Exit.");
#endif
exit(0);
}
syntax highlighted by Code2HTML, v. 0.9.1