/*
     tcplogger - A TCP traffic logger
     Copyright (C) 1993 Douglas Lee Schales, David K. Hess, David R. Safford

     Please see the file `COPYING' for the complete copyright notice.

tcpsyn.c - 03/20/93

*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <sys/time.h>
#include <netdb.h>
#include <memory.h>

extern char *optarg;
extern int optind, opterr;

#include "defs.h"
#include "version.h"

struct ipaddr {
     unsigned int addr:32;
};

struct tcpsynout {
     struct timeval tp;
     unsigned long ipsrcaddr;
     unsigned long ipdstaddr;
     unsigned long tcpseq;
     unsigned short tcpsrcport;
     unsigned short tcpdstport;
};

static void etherhandler(char *, int, struct timeval);
static void tcpsyn(struct ip *, struct timeval);
static void tcplogbin(struct tcpsynout *);
static void tcplogascii(struct tcpsynout *);
static char *gettcpportname(unsigned short);
extern char *gettimestr(struct timeval);

extern void pushfilter(int);

struct val_str_hndl ether_types[] = {
     0x0800, "DOD Internet Protocol", tcpsyn,
     0, (char *)0, 0
     };

#define LOGBINARY 0
#define LOGASCII 1
static int logtype = LOGBINARY;
static FILE *logfile = stdout;

int resolve = 1;

extern char *getdefaultif(char *);

main(int argc, char **argv)
{
     char *eif = getdefaultif((char *)0);
     int fd;
     int c;
     int promisc = 1;
     
     while((c=getopt(argc, argv, "nvi:apbf:")) != -1){
	  switch(c){
	  case 'v':
	       printf("tcplogger, version %s\n", toolversion);
	       exit(0);
	       break;
	  case 'a':
	       logtype = LOGASCII;
	       break;
	  case 'b':
	       logtype = LOGBINARY;
	       break;
	  case 'n':
	       resolve = 0;
	       break;
	  case 'p':
	       promisc = 0;
	       break;
	  case 'i':
	       eif = optarg;
	       break;
	  case 'f':
	       if(!(logfile = fopen(optarg, "a"))){
		    perror(optarg);
		    exit(1);
	       }
	       break;
	  default:
	       fprintf(stderr, "Unknown option: %c\n", c);
	       exit(1);
	  }
     }

     fd = opennit(eif, promisc, pushfilter);
     procpkts(fd, etherhandler);
}

void
etherhandler(char *pkt, int size, struct timeval tp)
{
     int hlen = 7;
     tcpsyn((struct ip *)(pkt + (hlen*2)), tp);
}


void
tcpsyn(struct ip *ip, struct timeval tp)
{
     struct tcphdr *tcp;
     struct tcpsynout outbuf;

     tcp = (struct tcphdr *)(((char *)ip) + sizeof(struct ip));

     memcpy((char *)&outbuf.tcpseq, (char *)&tcp->th_seq, sizeof(long));
     memcpy((char *)&outbuf.tp, (char *)&tp, sizeof(struct timeval));
     memcpy((char *)&outbuf.ipsrcaddr, (char *)&ip->ip_src, 4);
     memcpy((char *)&outbuf.ipdstaddr, (char *)&ip->ip_dst, 4);
     memcpy((char *)&outbuf.tcpsrcport, (char *)&tcp->th_sport, 2);
     memcpy((char *)&outbuf.tcpdstport, (char *)&tcp->th_dport, 2);

     switch(logtype){
     case LOGBINARY:
	  tcplogbin(&outbuf);
	  break;
     case LOGASCII:
	  tcplogascii(&outbuf);
	  break;
     default:
	  fprintf(stderr, "Log type unknown: %d\n", logtype);
	  break;
     }
}

void
tcplogbin(struct tcpsynout *outbuf)
{
     write(fileno(logfile), (char *)outbuf, sizeof(struct tcpsynout));
}

void
tcplogascii(struct tcpsynout *outbuf)
{
     struct in_addr haddr;

     fputs(gettimestr(outbuf->tp), logfile);
     fprintf(logfile, " %8X ", outbuf->tcpseq);
     memcpy(&haddr.s_addr, &outbuf->ipsrcaddr, 4);

     fprintf(logfile, "%-21s", resolve ? cgethostbyaddr(haddr) : inet_ntoa(haddr));

     fputc(' ', logfile);
     fputs(gettcpportname(outbuf->tcpsrcport), logfile);
     fputs(" -> ", logfile);
     memcpy(&haddr.s_addr, &outbuf->ipdstaddr, 4);
     fprintf(logfile, "%-21s", resolve ? cgethostbyaddr(haddr) : inet_ntoa(haddr));
     fputc(' ', logfile);
     fputs(gettcpportname(outbuf->tcpdstport), logfile);;
     fputc('\n', logfile);
     fflush(logfile);
}

char *
gettcpportname(unsigned short p)
{
     struct servent *se;
     static char result[80];

     if(resolve && (se = getservbyport((unsigned int)ntohs(p), "tcp")))
	  strcpy(result, se->s_name);
     else
	  sprintf(result, "%u", (unsigned int)ntohs(p));
     
     return result;
}
