/****************************************************************************
   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