/***************************************************************************
 * DBS: Distributed Benchmark System
 * Copyright (c) 1995, 1996, 1997 Yukio Murayama
 * Copyright (c) 1995, 1996, 1997 Nara Institute of Science and Technology
 * All rights reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided only with the following
 * conditions are satisfied:
 *
 * 1. Both the copyright notice and this permission notice appear in
 *    all copies of the software, derivative works or modified versions,
 *    and any portions thereof, and that both notices appear in
 *    supporting documentation.
 * 2. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgement:
 *      This product includes software developed by Nara Institute of 
 *      Science and Technology and its contributors.
 * 3. Neither the name of Nara Institute of Science and Technology nor 
 *    the names of its contributors may be used to endorse or promote 
 *    products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND NARA 
 * INSTITUTE OF SCIENCE AND TECHNOLOGY DISCLAIMS ANY LIABILITY OF 
 * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF 
 * THIS SOFTWARE. ALSO, THERE IS NO WARRANTY IMPLIED OR OTHERWISE, 
 * NOR IS SUPPORT PROVIDED.
 *
 * Feedback of the results generated from any improvements or
 * extensions made to this software would be much appreciated.
 * Any such feedback should be sent to:
 *
 *  Yukio Murayama
 *  E-mail:  <yukio-m@is.aist-nara.ac.jp>
 *  URL:     <http://shika.aist-nara.ac.jp/member/yukio-m/index.html>
 *  Address: Graduate School of Information Science, 
 *           Nara Institute of Science and Technology,
 *           Takayama 8916-5, Ikoma, Nara, Japan
 *
 * Nara Institute of Science and Technology has the rights to 
 * redistribute these changes.
 ***************************************************************************/
/*****************************************************************
 * Distributed Benchmark System
 * TCP Trace
 * $Revision: 1.16 $
 * $Date: 1997/05/05 17:02:18 $
 * $Author: yukio-m $
 *****************************************************************/

#define TCP_TRACE

/*#if !defined(SYSTYPE_SVR4)*/

#include <sys/types.h>

#if defined(__osf__) || defined(__bsdi__)
#include <paths.h>
#endif

#if defined(__osf__) || defined(__bsdi__)
#include <machine/endian.h>
#endif

#include <sys/file.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <nlist.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

#if defined(__svr4__)
#include <sys/fcntl.h>
#endif

#include "dbs.h"
#include "dbsd.h"
#include "record.h"

/*#include <netinet/tcp_debug.h>*/

#define IFASSOSIATION if (rt->d[rt->n].td_tcb == rt->tcp_addr)

/*
#define IFASSOSIATION if (\
			  (\
			   ntohl(rt->d[rt->n].td_ti.ti_src.s_addr) == ntohl(a->dest_address)   &&\
			   ntohl(rt->d[rt->n].td_ti.ti_dst.s_addr) == ntohl(a->source_address) &&\
			   ntohl(rt->d[rt->n].td_ti.ti_sport)      == ntohl(a->dest_port)      &&\
			   ntohl(rt->d[rt->n].td_ti.ti_dport)      == ntohl(a->source_port))   ||\
			  (\
			   ntohl(rt->d[rt->n].td_ti.ti_src.s_addr) == ntohl(a->source_address) &&\
			   ntohl(rt->d[rt->n].td_ti.ti_dst.s_addr) == ntohl(a->dest_address)   &&\
			   ntohl(rt->d[rt->n].td_ti.ti_sport)      == ntohl(a->source_port)    &&\
			   ntohl(rt->d[rt->n].td_ti.ti_dport)      == ntohl(a->dest_port))\
			  )
*/

#define IFASSO	if (\
			    (int)my_tcp_debug.td_act == act &&\
			    (\
			     ((act == TA_INPUT) &&\
			      ((int)my_tcp_debug.td_ti.ti_flags & (int)TH_SYN) != 0 &&\
			      ntohl(my_tcp_debug.td_ti.ti_src.s_addr) == ntohl(a->dest_address)   &&\
			      ntohl(my_tcp_debug.td_ti.ti_dst.s_addr) == ntohl(a->source_address) &&\
			      ntohl(my_tcp_debug.td_ti.ti_sport)      == ntohl(a->dest_port)      &&\
			      ntohl(my_tcp_debug.td_ti.ti_dport)      == ntohl(a->source_port))\
			     ||\
			     ((act == TA_OUTPUT) &&\
			      ((int)my_tcp_debug.td_ti.ti_flags & (int)TH_SYN) != 0 &&\
			      ntohl(my_tcp_debug.td_ti.ti_src.s_addr) == ntohl(a->source_address) &&\
			      ntohl(my_tcp_debug.td_ti.ti_dst.s_addr) == ntohl(a->dest_address)   &&\
			      ntohl(my_tcp_debug.td_ti.ti_sport)      == ntohl(a->source_port)    &&\
			      ntohl(my_tcp_debug.td_ti.ti_dport)      == ntohl(a->dest_port))\
			     )\
			    )

#ifdef DEBUGMODE
#define IF_ASSOSIATION  DEBUGMSG2(5, tcp_trace_debug(&rt->d[rt->n], rt->n, i));\
                        IFASSOSIATION
#define IF_ASSO DEBUGMSG2(5, tcp_trace_debug(&my_tcp_debug, 0, i));\
                        IFASSO
#else
#define IF_ASSOSIATION  IFASSOSIATION
#define IF_ASSO IFASSO
#endif	    

int     get_tcp_debx     __P((int memf));
caddr_t search_syn       __P((int memf, struct assosiation *a, int *debx, int act));
void    tcp_trace_debug  __P((struct tcp_debug *d, int i, int p));
void    tcp_trace_debug2 __P((struct assosiation *a, int act));

#ifdef TCP_NDEBUG  /********** IFDEF TCP_NDEBUG **********/

static struct tcp_debug my_tcp_debug;
static int    my_tcp_debx;

struct nlist nl[] = {
#define	N_TCP_DEBUG	0
	{ "_tcp_debug" },
#define	N_TCP_DEBX	1
	{ "_tcp_debx" },
	{ "" }
};

/*
 * Trace TCP_CB and Store it into buffer
 */
void record_tcp_trace(rt, a, act)
struct tcp_trace *rt;
struct assosiation *a;
int  act;                           /* XXX act is not used by this virson */
{
    int i, now_p, n1, n2;

    if (rt->n >= rt->size)
	return;

    now_p = get_tcp_debx(rt->memf);

    n1 = rt->p;
    n2 = now_p;

    if (rt->p >= TCP_NDEBUG) {
	fprintf(stderr, "rt->p=%d  now_p=%d TCP_NDEBUG=%d: Internal Error!!! \n", rt->p, now_p, TCP_NDEBUG);
	safe_exit(INTERNALERROR, "TCP_DEBUG.rt->p", "");
    }

    if (n1 < n2) {
	(void)lseek(rt->memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
	(void)lseek(rt->memf, (off_t)(sizeof(struct tcp_debug)*n1), SEEK_CUR);
	
	for (i=n1; i != n2; i = (i+1) % TCP_NDEBUG) {
	    if (read(rt->memf, (char *)&rt->d[rt->n], sizeof(struct tcp_debug)) != sizeof(struct tcp_debug))
		safe_exit(TCPDEBUG, "TCP_DEBUG.read(kernel)", strerror(errno));

	    IF_ASSOSIATION {
		rt->n++;
	    }
	}
    } else if (n1 > n2) {
	(void)lseek(rt->memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
	(void)lseek(rt->memf, (off_t)(sizeof(struct tcp_debug)*n1), SEEK_CUR);

	for (i=n1; i < TCP_NDEBUG; i++) {
	    if (read(rt->memf, (char *)&rt->d[rt->n], sizeof(struct tcp_debug)) != sizeof(struct tcp_debug))
		safe_exit(TCPDEBUG, "TCP_DEBUG.read(kernel)", strerror(errno));

	    IF_ASSOSIATION {
		rt->n++;
	    }
	}

	if (n2 > 0) {
	    (void)lseek(rt->memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
	    
	    for (i=0; i < n2; i++) {
		if (read(rt->memf, (char *)&rt->d[rt->n], sizeof(struct tcp_debug)) != sizeof(struct tcp_debug))
		    safe_exit(TCPDEBUG, "TCP_DEBUG.read(kernel)", strerror(errno));

		IF_ASSOSIATION {
		    rt->n++;
		}
	    }
	}
    }
    rt->p = now_p;
}

void record_tcp_trace2(rt, a, flg)
struct tcp_trace *rt;
struct assosiation *a;
int  flg;                           /* XXX flg is not used by this virson */
{
    int i, now_p, n1, n2;

    if (rt->n >= rt->size)
	return;

    now_p = get_tcp_debx(rt->memf);

    n1 = rt->p;
    n2 = now_p;

    if (rt->p >= TCP_NDEBUG) {
	fprintf(stderr, "rt->p=%d  now_p=%d TCP_NDEBUG=%d: Internal Error!!! \n", rt->p, now_p, TCP_NDEBUG);
	safe_exit(INTERNALERROR, "TCP_DEBUG2.rt->p", "");
    }

    if (n1 < n2) {
	(void)lseek(rt->memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
	(void)lseek(rt->memf, (off_t)(sizeof(struct tcp_debug)*n1), SEEK_CUR);
	
	for (i=n1; i != n2; i = (i+1) % TCP_NDEBUG) {
	    if (read(rt->memf, (char *)&rt->d[rt->n], sizeof(struct tcp_debug)) != sizeof(struct tcp_debug))
		safe_exit(TCPDEBUG, "TCP_DEBUG2.read(kernel)", strerror(errno));

	    IF_ASSOSIATION {
		if(((int)rt->d[rt->n].td_ti.ti_flags & (int)TH_FIN) != 0)
		    return;
		else
		    rt->n++;
	    }
	}
    } else if (n1 > n2) {
	(void)lseek(rt->memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
	(void)lseek(rt->memf, (off_t)(sizeof(struct tcp_debug)*n1), SEEK_CUR);

	for (i=n1; i < TCP_NDEBUG; i++) {
	    if (read(rt->memf, (char *)&rt->d[rt->n], sizeof(struct tcp_debug)) != sizeof(struct tcp_debug))
		safe_exit(TCPDEBUG, "TCP_DEBUG2.read(kernel)", strerror(errno));

	    IF_ASSOSIATION {
		if(((int)rt->d[rt->n].td_ti.ti_flags & (int)TH_FIN) != 0)
		    return;
		else
		    rt->n++;
	    }
	}

	if (n2 > 0) {
	    (void)lseek(rt->memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
	    
	    for (i=0; i < n2; i++) {
		if (read(rt->memf, (char *)&rt->d[rt->n], sizeof(struct tcp_debug)) != sizeof(struct tcp_debug))
		    safe_exit(TCPDEBUG, "TCP_DEBUG2.read(kernel)", strerror(errno));

		IF_ASSOSIATION {
		    if(((int)rt->d[rt->n].td_ti.ti_flags & (int)TH_FIN) != 0)
			return;
		    else
			rt->n++;
		}
	    }
	}
    }
    rt->p = now_p;
}

/*
 * Initialization of TCP TRACE
 */   
void init_so_debug(rt, a,  act, flg)
struct tcp_trace *rt;
struct assosiation *a;
int act, flg;
{
    char *system, *core;
    off_t lseek();
    int debx;

    rt->n=0;

#ifdef _PATH_KMEM
    core   = _PATH_KMEM;
#else
    core   = "/dev/kmem";
#endif

#ifdef _PATH_KERNEL
    system = _PATH_KERNEL;
#else
#ifdef _PATH_UNIX
    system = _PATH_UNIX;
#else    
    system = "/kernel";
#endif
#endif
    
    if (nlist(system, nl) < 0 || !nl[0].n_value) {
	fprintf(stderr, "dbsd: {_tcp_debug}, {_tcp_debx} cannot found in %s\n", system);
	safe_exit(TCPDEBUG, "dbsd: {_tcp_debug}, {_tcp_debx} cannot found in the kernel", "");
    }
    
    if ((rt->memf = open(core, O_RDONLY)) < 0)
	safe_exit(TCPDEBUG, "TCP_DEBUG_INIT.open(kernel)", strerror(errno));

    DEBUGMSG2(4, fprintf(stderr, "rt->memf=%d\n", rt->memf));

    rt->p = debx = get_tcp_debx(rt->memf);

    DEBUGMSG(5, "Search Syncronize\n");
    rt->tcp_addr = search_syn(rt->memf, a, &(rt->p), act);

    if (flg == BEFORE) 
	rt->p = debx;

    DEBUGMSG2(3, fprintf(stderr, "rt->p=%d  rt->tcp_addr=%lu\n", rt->p, (u_long)rt->tcp_addr));
}

/*
 * search TCP_CB syn Packet
 */
caddr_t search_syn(memf, a, debx, act)
int memf;
struct assosiation *a;
int *debx;
int act;
{
    int i, x;

    x = *debx;

    DEBUGMSG2(5, tcp_trace_debug2(a, act));

    if (x < 0 || x > TCP_NDEBUG) {
	fprintf(stderr, "debx=%d TCP_NDEBUG=%d: Internal Error!!! \n", x, TCP_NDEBUG);
	safe_exit(INTERNALERROR, "TCP_DEBUG_SYN.x", "");
    }

    (void)lseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
    (void)lseek(memf, (off_t)(sizeof(struct tcp_debug)*((x-1) % TCP_NDEBUG)), SEEK_CUR);

    for (i=x-1; i >= 0; i--) {
	if (read(memf, (char *)&my_tcp_debug, sizeof(struct tcp_debug)) != sizeof(struct tcp_debug))
	    safe_exit(TCPDEBUG, "TCP_DEBUG_SYN.read(kernel)", strerror(errno));

	IF_ASSO {
	    *debx = i;
	    return my_tcp_debug.td_tcb;
	}
	(void)lseek(memf, (off_t)(sizeof(struct tcp_debug)*(-2)), SEEK_CUR);
    }

   (void)lseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
   (void)lseek(memf, (off_t)(sizeof(struct tcp_debug)*(TCP_NDEBUG-1)), SEEK_CUR);

/*    (void)lseek(memf, (off_t)(sizeof(struct tcp_debug)*(TCP_NDEBUG-2)), SEEK_CUR);*/

    for (i=TCP_NDEBUG-1; i >= x; i--) {
	if (read(memf, (char *)&my_tcp_debug, sizeof(struct tcp_debug)) != sizeof(struct tcp_debug))
	    safe_exit(TCPDEBUG, "TCP_DEBUG_SYN.read(kernel)", strerror(errno));

	IF_ASSO {
	    *debx = i;
	    return my_tcp_debug.td_tcb;
	}
	(void)lseek(memf, (off_t)(sizeof(struct tcp_debug)*(-2)), SEEK_CUR);
    }

    return NULL;
}


/*
 * Read tcp_debx  from Kernel memory
 */   
int get_tcp_debx(memf)
int memf;
{
    off_t lseek();
    
    (void)lseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET);
    
    if (read(memf, (char *)&my_tcp_debx, sizeof(my_tcp_debx)) != sizeof(my_tcp_debx))
	safe_exit(TCPDEBUG, "TCP_DEBUG_DEBX.read(kernel)", strerror(errno));
    
    return my_tcp_debx;         /* -1 */ /* XXX */
}

/*
 * Debug Sub-Routine1
 */
void tcp_trace_debug(d, i, p)
struct tcp_debug *d;
int i, p;
{
    int sp, dp, sa, da, th_flags;;
    
    sa=(int)ntohl(d->td_ti.ti_src.s_addr);
    da=(int)ntohl(d->td_ti.ti_dst.s_addr);
    sp=(int)ntohs(d->td_ti.ti_sport);
    dp=(int)ntohs(d->td_ti.ti_dport);
    th_flags=(int)(d->td_ti.ti_flags);

    fprintf(stderr,"[%3d](%4d)%1d(%3d.%3d.%3d.%3d, %3d.%3d.%3d.%3d)(%5d,%5d)%1u%1u%1u%1u%1u%1u(%lu)\n",
	    p,i, d->td_act,
	    GET_IP_ADDR(sa,4), GET_IP_ADDR(sa,3), GET_IP_ADDR(sa,2), GET_IP_ADDR(sa,1),
	    GET_IP_ADDR(da,4), GET_IP_ADDR(da,3), GET_IP_ADDR(da,2), GET_IP_ADDR(da,1),
	    sp, dp,
	    (int)(0x01 & (th_flags >>5)),   /* URG */
	    (int)(0x01 & (th_flags >>4)),   /* ACK */
	    (int)(0x01 & (th_flags >>3)),   /* PSH */
	    (int)(0x01 & (th_flags >>2)),   /* RST */
	    (int)(0x01 & (th_flags >>1)),   /* SYN */
	    (int)(0x01 & (th_flags >>0)),   /* FIN */
	    (long)d->td_tcb);
}

/*
 * Debug Sub-Routine2
 */
void tcp_trace_debug2(a, act)
struct assosiation *a;
int act;
{
    int sp, dp, sa, da, th_flags;
    
    sa=(int)ntohl(a->source_address);
    da=(int)ntohl(a->dest_address);
    sp=(int)ntohs(a->source_port);
    dp=(int)ntohs(a->dest_port);
    th_flags=(int)(TH_SYN);

    fprintf(stderr,"[%3d](%4d)%1u(%3d.%3d.%3d.%3d, %3d.%3d.%3d.%3d)(%5d,%5d)%1u%1u%1u%1u%1u%1u\n",
	    0,0,
	    act,
	    GET_IP_ADDR(sa,4), GET_IP_ADDR(sa,3), GET_IP_ADDR(sa,2), GET_IP_ADDR(sa,1),
	    GET_IP_ADDR(da,4), GET_IP_ADDR(da,3), GET_IP_ADDR(da,2), GET_IP_ADDR(da,1),
	    sp, dp,
	    (int)(0x01 & (th_flags >>5)),   /* URG */
	    (int)(0x01 & (th_flags >>4)),   /* ACK */
	    (int)(0x01 & (th_flags >>3)),   /* PSH */
	    (int)(0x01 & (th_flags >>2)),   /* RST */
	    (int)(0x01 & (th_flags >>1)),   /* SYN */
	    (int)(0x01 & (th_flags >>0))    /* FIN */
	    );
}

#else /********** ELSE TCP_NDEBUG **********/

/*
 * Dummy Functions for no tcp_debug OS
 */

void record_tcp_trace(rt, a, act)
struct tcp_trace *rt;
struct assosiation *a;
int  act;
{
    /* NULL */
}

void record_tcp_trace2(rt, a, flg)
struct tcp_trace *rt;
struct assosiation *a;
int  flg;
{
    /* NULL */
}

void init_so_debug(rt, a,  act, flg)
struct tcp_trace *rt;
struct assosiation *a;
int act, flg;
{
    /* NULL */
}

caddr_t search_syn(memf, a, debx, act)
int memf;
struct assosiation *a;
int *debx;
int act;
{
    return NULL;
}

int get_tcp_debx(memf)
int memf;
{
    return -1;
}

void tcp_trace_debug(d, i, p)
struct tcp_debug *d;
int i, p;
{
    /* NULL */
}

void tcp_trace_debug2(a, act)
struct assosiation *a;
int act;
{
    /* NULL */
}
#endif /********** ENDIF TCP_NDEBUG **********/



syntax highlighted by Code2HTML, v. 0.9.1