
#include "queso.h"

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

#define ACK_HACK    1000
#define RANDOM_ACK  (ACK_HACK+666)

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

static void ASM
debugTcp(REG(a0) struct global *g,REG(a1) struct dMsg *dmsg,REG(d0) u_long seq)
{
    register char buf[32];

    *buf = 0;
    if (dmsg->tcp.th_flags & URG) strcat(buf,"urg ");
    if (dmsg->tcp.th_flags & SYN) strcat(buf,"syn ");
    if (dmsg->tcp.th_flags & RST) strcat(buf,"rst ");
    if (dmsg->tcp.th_flags & FIN) strcat(buf,"fin ");
    if (dmsg->tcp.th_flags & ACK) strcat(buf,"ack ");
    if (dmsg->tcp.th_flags & PSH) strcat(buf,"psh ");
    if (dmsg->tcp.th_flags & XXX) strcat(buf,"xxx ");
    if (dmsg->tcp.th_flags & YYY) strcat(buf,"yyy ");

    printErr(g,STRING_CHECK_TCPDebug,
            dmsg->ptype,
            dmsg->tcp.th_sport,
            dmsg->tcp.th_dport,
            dmsg->tcp.th_seq ? 1 : 0,
            dmsg->tcp.th_ack ? "+" : " ",
            dmsg->tcp.th_ack ? dmsg->tcp.th_ack-seq : 0,
            dmsg->tcp.th_win,
            dmsg->tcp.th_urp,
            buf);
}

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

static u_short pktFlg[MAXPKT+1] =
{
    SYN,
    SYN | ACK,
    FIN,
    FIN | ACK,
    SYN | FIN,
    PSH,
    SYN | XXX | YYY
};

LONG ASM
checkOS(REG(a0) struct global *g,REG(d0) short dport)
{
    register char               line[1024], osname[256], *p;
    struct spoofrec             spoof;
    register struct dMsg        *dmsg;
    register BPTR               f;
    register LONG               res;
    register ULONG              sb, tb, sig;
    register BOOL               stop;
    register int                n;
    register unsigned short     s, flag1, found, lines, pn, ps, pa, pw, pf, pu;

    if (res = initSniffer(g)) return res;
    memset(g->a,0,sizeof(g->a));
    s = (rand() % 26000) + 4000;

    spoof.seq   = rand();
    spoof.ack   = 0;
    spoof.from  = g->from;
    spoof.dest  = g->dest;
    spoof.dport = dport;

    g->count = 0;
    g->srch  = g->dest.sin_addr.s_addr;
    g->dsth  = g->from.sin_addr.s_addr;
    g->srcp  = dport;
    g->start = s;

    if (g->flags & QFLG_Debug)
        printErr(g,STRING_CHECK_Starting,
            Inet_NtoA(g->from.sin_addr.s_addr),
            s,
            Inet_NtoA(g->dest.sin_addr.s_addr),
            dport);

    for (n = 0; n<=MAXPKT; n++, s++)
    {
        spoof.sport = s;
        if (res = sendtcp(g,&spoof,pktFlg[n]))
        {
            closeSniffer(g);
            return res;
        }
    }

    sb   = 1<<g->sigBit;
    tb   = 1<<g->tsigBit;
    sig  = sb|tb|SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D;
    stop = 0;

    doTimer(g,g->timeout,0);

    while (1)
    {
        register ULONG srec;

        srec = Wait(sig);

        if (srec & SIGBREAKF_CTRL_C)
        {
            stop = 1;
            break;
        }

        if (srec & SIGBREAKF_CTRL_D)
        {
            ObtainSemaphore(&g->sem);
            stop = !g->count;
            ReleaseSemaphore(&g->sem);
            break;
        }

        if (AttemptSemaphore(&g->sem))
        {
            register done;

            done = (g->count>MAXPKT);
            ReleaseSemaphore(&g->sem);
            if (done) break;
        }

        if (srec & sb)
            while (dmsg = (struct dMsg *)GetMsg(&g->port))
                debugTcp(g,dmsg,spoof.seq);

        if (srec & tb) break;
    }

    closeSniffer(g);
    stopTimer(g);
    if (stop) return ERR_Break;

    while (dmsg = (struct dMsg *)GetMsg(&g->port))
        debugTcp(g,dmsg,spoof.seq);

    if (g->flags & QFLG_Verbose)
        printErr(g,STRING_CHECK_Sniffed,g->count);

    Seek(g->cfile,0,OFFSET_BEGINNING);

    flag1 = found = lines = pn = ps = pa = pw = pf = pu = 0;

    while (FGets(g->cfile,line,sizeof(osname)-1))
    {
        if (line[0]=='\n')
        {
            if (flag1 && found==lines)
            {
                FPrintf(g->stdOut,"%s:%ld\t%s",
                    Inet_NtoA(g->dest.sin_addr.s_addr),
                    dport,
                    osname);

                if (osname[1]=='-') return STRING_NotAccurate;
                else return 0;
            }
        }

        if (line[0]=='*')
        {
            strcpy(osname,line);
            if (g->flags & QFLG_CfgDebug)
                printErr(g,STRING_CHECK_CfgDebug1,
                    line);

            flag1 = 1;
            found = 0, lines = 0;
            continue;
        }

        /* parse line */
        lines++;
        p = strtok(line," ");
        if (p && isdigit(*p)) pn = atoi(p);
        else
        {
            lines = flag1 = found = 0;
            continue;
        }

        if (p = strtok(NULL," ")) ps = atoi(p);

        if (p = strtok(NULL," "))
        {
            if(*p=='R') pa = RANDOM_ACK;
            else
                if(*p=='+') pa = atoi(p)+ACK_HACK;
                else pa = atoi(p);
        }

        if (p = strtok(NULL," ")) pw = 0xffff & strtol(p,NULL,16);

        if (p = strtok(NULL," \n"))
        {
            if (g->flags & QFLG_CfgDebug)
                printErr(g,STRING_CHECK_CfgDebug2,
                    pn,
                    ps,
                    pa,
                    pw,
                    p);

            pf = 0;
            if (strchr(p,'S')) pf |= SYN;
            if (strchr(p,'R')) pf |= RST;
            if (strchr(p,'A')) pf |= ACK;
            if (strchr(p,'F')) pf |= FIN;
            if (strchr(p,'P')) pf |= PSH;
            if (strchr(p,'X')) pf |= XXX;
            if (strchr(p,'Y')) pf |= YYY;
            if (strchr(p,'U')) pu = 1;
            else pu = 0;
        }

        if (!g->a[pn].set)
        {
            if (pf)
            {
                if (g->flags & QFLG_CfgDebug)
                    printErr(g,STRING_CHECK_DebugNTRecvButConf);

                found = flag1 = 0;
                continue;
            }
            if (g->flags & QFLG_CfgDebug)
                    printErr(g,STRING_CHECK_DebugNTRecvAndNTConf);

            found++;
            continue;
        }

        if ((pa>=ACK_HACK ? (pa==g->a[pn].ack) : pa==(g->a[pn].ack>0)) &&
            ps==g->a[pn].seq &&
            ((pw==g->a[pn].win) || (pw==1 && g->a[pn].win) || (!pw && !g->a[pn].win)) &&
            pf==g->a[pn].flag && pu==g->a[pn].urg)
        {
            if (g->flags & QFLG_CfgDebug)
                printErr(g,STRING_CHECK_Found);

            found++;
            continue;
        }
        else
        {
            if (g->flags & QFLG_CfgDebug)
                printErr(g,STRING_CHECK_DebugFailed,
                        ps,
                        pa,
                        pw,
                        pu,
                        pf,
                        g->a[pn].seq,
                        g->a[pn].ack,
                        g->a[pn].win,
                        g->a[pn].urg,
                        g->a[pn].flag);

            found = flag1 = 0;
            continue;
        }
    }

    if (!(g->flags & QFLG_CfgUpdate)) f = g->stdErr;
    else f = g->cfile;

    Seek(f,0,OFFSET_END);

    if (g->flags & QFLG_CfgUpdate)
        FPrintf(g->stdOut,getString(STRING_CHECK_NewPattern),
            Inet_NtoA(g->dest.sin_addr.s_addr),
            dport,g->cfgFile);
    else
        FPrintf(g->stdOut,getString(STRING_CHECK_Update),
            Inet_NtoA(g->dest.sin_addr.s_addr),
            dport,g->cfgFile);

    if (g->flags & (QFLG_Debug|QFLG_CfgUpdate))
    {
        FPrintf(f,"\n*- Unknown OS @ %s:%ld\n",
            Inet_NtoA(g->dest.sin_addr.s_addr),
            dport);

        for (pn = 0; pn<=MAXPKT; pn++)
        {
            *line = 0;
            if (g->a[pn].urg) strcat (line, "U");
            if (g->a[pn].flag & SYN) strcat(line, "S");
            if (g->a[pn].flag & RST) strcat(line, "R");
            if (g->a[pn].flag & ACK) strcat(line, "A");
            if (g->a[pn].flag & FIN) strcat(line, "F");
            if (g->a[pn].flag & PSH) strcat(line, "P");
            if (g->a[pn].flag & XXX) strcat(line, "X");
            if (g->a[pn].flag & YYY) strcat(line, "Y");
            if (g->a[pn].set)
            {
                FPrintf(f,"%ld %ld %s",
                    pn,
                    g->a[pn].seq,
                    (g->a[pn].ack==RANDOM_ACK ? "R" : ((g->a[pn].ack>=ACK_HACK) ? "+" : "")));

                if(g->a[pn].ack!=RANDOM_ACK)
                    FPrintf(f,"%ld",(g->a[pn].ack>=ACK_HACK) ? g->a[pn].ack-ACK_HACK : g->a[pn].ack);

                FPrintf(f," %ld %s\n",g->a[pn].win ? 1 : 0,line);
            }
            else FPrintf(f,"%ld - - - -\n",pn);
        }
    }

    if (g->flags & QFLG_CfgUpdate)
    {
        FPrintf(f,"\n");
        Flush(f);
    }

    return 0;
}

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