
#include "queso.h"

/***************************************************************************/
/*
** create a socket and set IP_HDRINCL on it
*/

LONG ASM
initTCPIP(REG(a0) struct global *g)
{
    int on = 1;

    if ((g->sock = socket(AF_INET,SOCK_RAW,IPPROTO_RAW))<0)
        return ERR_NoSocket;

    if (setsockopt(g->sock,IPPROTO_IP,IP_HDRINCL,(char *)&on,sizeof(on))<0)
        return ERR_BSDSocket;

    return 0;
}

/***************************************************************************/
/*
** ip cksum
*/

static int ASM
inetCksum(REG(a0) u_short *ptr,REG(d0) int nbytes)
{
    register long       sum;
    u_short             oddbyte;
    register u_short    answer;

    sum = 0;

    while (nbytes>1)
    {
        sum += *ptr++;
        nbytes -= 2;
    }

    if (nbytes==1)
    {
        oddbyte = 0;
        *(u_char *)(&oddbyte) = *(u_char *)ptr;
        sum += oddbyte;
    }

    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    answer = ~sum;

    return answer;
}

/***************************************************************************/
/*
** tcp cksum
*/

struct pseudoHeader
{
    u_long          src;
    u_long          dst;
    unsigned char   placeHolder;
    unsigned char   protocol;
    unsigned short  tcpLength;
    struct tcphdr   tcp;
};

static void ASM
tcpCksum(REG(a0) struct global *g,REG(d0) u_long src,REG(d1) u_long dst,REG(a1) struct tcphdr *tcph)
{
    struct pseudoHeader ph;

    ph.src         = src;
    ph.dst         = dst;
    ph.placeHolder = 0;
    ph.protocol    = IPPROTO_TCP;
    ph.tcpLength   = sizeof(struct tcphdr);
    memcpy(&ph.tcp,tcph,sizeof(struct tcphdr));

    tcph->th_sum = inetCksum((u_short *)&ph,sizeof(struct pseudoHeader));
}

/****************************************************************************/
/*
** resolve host
*/

LONG ASM
resolve(REG(a0) struct global *g,REG(a1) char *hostName,REG(a2) struct sockaddr_in *sin)
{
    sin->sin_family = AF_INET;
    sin->sin_port   = 0;
    sin->sin_len    = sizeof(struct sockaddr_in);

    if ((sin->sin_addr.s_addr = inet_addr(hostName))==INADDR_NONE)
    {
        register struct hostent *host;

        if (host = gethostbyname(hostName)) memcpy(&sin->sin_addr,host->h_addr,4);
        else return ERR_NoHost;
    }

    return 0;
}

/***************************************************************************/
/*
** send packets
*/

struct pkt
{
    struct ip       ip;
    struct tcphdr   tcp;
};

LONG ASM
sendtcp(REG(a0) struct global *g,REG(a1) struct spoofrec *spoof,REG(d0) u_short flags)
{
    struct pkt      pkt;
    register int    i;

    /* set ip */
    pkt.ip.ip_hl  = 5;
    pkt.ip.ip_v   = IPVERSION;
    pkt.ip.ip_tos = 0;
    pkt.ip.ip_len = sizeof(struct pkt);
    pkt.ip.ip_id  = 31337 + spoof->sport;
    pkt.ip.ip_off = 0;
    pkt.ip.ip_ttl = IPDEFTTL;
    pkt.ip.ip_p   = IPPROTO_TCP;
    pkt.ip.ip_src = spoof->from.sin_addr;
    pkt.ip.ip_dst = spoof->dest.sin_addr;
    pkt.ip.ip_sum = 0;
    pkt.ip.ip_sum = inetCksum((u_short *)&pkt.ip,sizeof(struct ip));

    /* set tcp */
    pkt.tcp.th_sport = spoof->sport;
    pkt.tcp.th_dport = spoof->dport;
    pkt.tcp.th_seq   = spoof->seq;
    pkt.tcp.th_ack   = 0;
    pkt.tcp.th_x2    = 0;
    pkt.tcp.th_off   = 5;
    pkt.tcp.th_flags = flags;
    pkt.tcp.th_win   = 0x1234;
    pkt.tcp.th_urp   = 0;
    pkt.tcp.th_sum   = 0;
    tcpCksum(g,spoof->from.sin_addr.s_addr,spoof->dest.sin_addr.s_addr,&pkt.tcp);

    /* send times packets */
    for (i = 0; i<g->times; i++)
    {
        register ULONG srec;

        if (sendto(g->sock,(void *)&pkt,sizeof(struct pkt),0,(struct sockaddr *)&spoof->dest,sizeof(spoof->dest))<0)
            return ERR_BSDSocket;

        /* wait delay or ctrl-c (ctrl-d is ignored here) */
        if (srec = waitTimer(g,g->delay))
            return (srec & SIGBREAKF_CTRL_C) ?  ERR_Break : 0;
    }

    return 0;
}

/***************************************************************************/
