/*

sendto_spoof 0.1.2
by Luigi Auriemma
e-mail: aluigi@autistici.org
web:    aluigi.org

This is a replacement of the sendto() function which enables the spoofing
of the UDP packets in some existent tools or proof-of-concept codes.
By default both source IP and port are something sequential/random.

This is a good way for enabling spoofed packets in some proof-of-concept
codes or other tools where is used sendto() and you don't need to watch
the received packets and want the maximum anonimity.

Implementing it in the programs is very simple, before re-compiling them
you must do the following operations:

- place the following line at the end of the #include list of your program:
    #include "sendto_spoof.h"

- replace the sendto calls with sendto_spoof where you want.
  In the proof-of-concept usually is only one packet that tests a bug so
  must be replaced only the sendto() which sends that packet.

- for Windows only: you NEED to remove or place a comment where is located
  #include <winsock.h> in your program

This code works on both Windows (on versions that support the RAW sockets
like Windows XP) and other systems, and both little and big-endian
architectures.

If something doesn't work or the packet doesn't reach the target host
means there is a firewall, your ISP blocks the spoofed packets, you don't
have the needed permissions (root or administrator), your OS doesn't
support the RAW sockets or simply you have added sendto_spoof() to a
program where this is not possible (for example because it uses a sequence
of packets signed with a unique ID sent by the server and so on).

Is also possible to use this code for sending spoofed packets in a new
program (so not only a sendto() replacement) since all you need to do is
specifying and filling a sockaddr_in structure. You don't need to create
the socket since it is already made by the sendto_spoof() function.

CHECK THE FOLLOWING OPTIONS

*/

/*
OPTIONS
you can enable them here or at compilation time using the -D switch
default is everything random
*/

//#define SRCDSTIP              // source IP is equal to dest IP

//#define SRCPORT     53        // use ever and only the source port SRCPORT

//#define SRCIP       "1.2.3.4" // use ever and only the source IP SRCIP
                                // example at command-line: -DSRCIP=\"1.2.3.4\"



#include <stdlib.h>
#include <string.h>


#ifdef WIN32            // something better than a simple time(NULL)
    #include <windows.h>
    #define SENDTO_SPOOF_RAND   GetTickCount()  // 1000/s resolution
#else
    #include <sys/times.h>
    #define SENDTO_SPOOF_RAND   times(0)        // 100/s resolution
#endif



#ifdef WIN32
    #include <stdint.h>
    #include <winsock2.h>
    #include <ws2tcpip.h>

    #define in_addr_t   uint32_t

    struct iphdr {
        uint32_t    ihl:4;
        uint32_t    version:4;
        uint8_t     tos;
        uint16_t    tot_len;
        uint16_t    id;
        uint16_t    frag_off;
        uint8_t     ttl;
        uint8_t     protocol;
        uint16_t    check;
        uint32_t    saddr;
        uint32_t    daddr;
    };
    struct udphdr {
        uint16_t    source;
        uint16_t    dest;
        uint16_t    len;
        uint16_t    check;
    };
#else
    #include <netinet/ip.h>
    #include <netinet/udp.h>
#endif



in_addr_t sendto_spoof_inet_addr(char *addr) {
    int     i1,
            i2,
            i3,
            i4,
            i5,
            i6;
    u_char  arr[sizeof(in_addr_t)];

    sscanf(addr, "%u.%u.%u.%u.%u.%u", &i1, &i2, &i3, &i4, &i5, &i6);
    arr[0] = i1;
    arr[1] = i2;
    arr[2] = i3;
    arr[3] = i4;
    if(sizeof(in_addr_t) > 4) {
        arr[4] = i5;
        arr[5] = i6;
    }
    return(*(in_addr_t *)arr);  // already htonled
}



uint16_t sendto_spoof_cksum(void *data, int len) {
    u_int       sum    = 0;
    int         i      = len >> 1,
                endian = 1; // big endian
    uint16_t    crc,
                *p     = (u_short *)data;

    if(*(char *)&endian) endian = 0;
    while(i--) sum += *p++;
    if(len & 1) sum += *p & (endian ? 0xff00 : 0xff);
    crc = sum = (sum >> 16) + (sum & 0xffff);
    if(sum >>= 16) crc += sum;
    if(!endian) crc = (crc >> 8) | (crc << 8);
    return(~crc);
}



int sendto_spoof(
    int             s,
    const void      *buf,
    int             len,
    int             flags,
    const struct    sockaddr *to,
    int             tolen) {

    struct pseudohdr {
        uint32_t    saddr;
        uint32_t    daddr;
        uint8_t     zero;
        uint8_t     protocol;
        uint16_t    len;
    };

#define IPSZ        sizeof(struct iphdr)
#define UDPSZ       sizeof(struct udphdr)
#define PSEUDOSZ    sizeof(struct pseudohdr)
#define PCKSIZE     (IPSZ + UDPSZ + len)
#define PSSIZE      (PSEUDOSZ + UDPSZ + len)

    struct  iphdr       *ip;
    struct  udphdr      *udp;
    struct  pseudohdr   *pseudo;
    in_addr_t           src;
    int     sd,
            ret,
            on = 1;
    u_char  *buff,
            *data;

    buff = malloc(PCKSIZE);
    if(!buff) return(-1);

    // setuid(0);

    ip     = (struct iphdr *)buff;
    udp    = (struct udphdr *)(buff + IPSZ);
    data   = (u_char *)(buff + IPSZ + UDPSZ);
    pseudo = (struct pseudohdr *)(buff + IPSZ - PSEUDOSZ);

    memcpy(data, buf, len);

#if defined(SRCDSTIP)
    src              = ((struct sockaddr_in *)to)->sin_addr.s_addr;
#elif defined(SRCIP)
    src              = sendto_spoof_inet_addr(SRCIP);
#else
    src              = (SENDTO_SPOOF_RAND * 0x343FDf) + 0x269EC3ff; // f ff
#endif

    pseudo->saddr    = src;
    pseudo->daddr    = ((struct sockaddr_in *)to)->sin_addr.s_addr;
    pseudo->zero     = 0;
    pseudo->protocol = IPPROTO_UDP;
    pseudo->len      = htons(UDPSZ + len);

#if defined(SRCPORT)
    udp->source      = htons(SRCPORT);
#else
    udp->source      = htons((SENDTO_SPOOF_RAND * 0x343FD) + 0x269EC3);
#endif
    udp->dest        = ((struct sockaddr_in *)to)->sin_port;
    udp->check       = 0;
    udp->len         = pseudo->len;
    udp->check       = htons(sendto_spoof_cksum(pseudo, PSSIZE));

    ip->ihl          = 5;
    ip->version      = 4;
    ip->tos          = 0x10;
    ip->tot_len      = htons(PCKSIZE);
    ip->id           = htons(1);
    ip->frag_off     = htons(0);
    ip->ttl          = 128;
    ip->protocol     = IPPROTO_UDP;
    ip->check        = 0;
    ip->saddr        = src;
    ip->daddr        = ((struct sockaddr_in *)to)->sin_addr.s_addr;
    ip->check        = htons(sendto_spoof_cksum(ip, IPSZ));

    sd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    if(sd < 0) {
        free(buff);
        return(sd);
    }
    ret = setsockopt(sd, IPPROTO_IP, IP_HDRINCL, (void *)&on, sizeof(on));
    if(!ret) {
        ret = sendto(sd, buff, PCKSIZE, 0, to, sizeof(struct sockaddr_in));
    }
    close(sd);
    free(buff);
    return(ret);

#undef IPSZ
#undef UDPSZ
#undef PSEUDOSZ
#undef PCKSIZE
#undef PSSIZE
}


