TUCoPS :: SunOS/Solaris :: tcpmon.c

Tcpmon is a sniffer-based TCP connection monitor that runs on SunOS (/dev/nit).

/*
 * TCP Monitor (tcpmon) V1.0
 *
 * cc tcpmon.c -o tcpmon -lresolv
 */

#include <stdio.h>
#include <ctype.h>
#include <string.h>

#include <sys/time.h>
#include <sys/file.h>
#include <sys/stropts.h>
#include <sys/signal.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>

#include <net/if.h>
#include <net/nit_if.h>
#include <net/nit_buf.h>
#include <net/if_arp.h>

#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/ip_var.h>
#include <netinet/udp_var.h>
#include <netinet/in_systm.h>
#include <netinet/tcp.h>
#include <netinet/ip_icmp.h>

#include <netdb.h>
#include <arpa/nameser.h>
#include <resolv.h>

#define NIT_DEV         "/dev/nit"
#define CHUNKSIZE       4096
#define STREAM_NULL     (0)
#define STREAM_STOD     (1)
#define STREAM_DTOS     (2)
#define STREAM_MAX      (3)
#define ISeq(s,d)       ((s) == (d))
#define ISneq(s,d)      ((s) != (d))

char *malloc (), *translate_host (), *device, *ProgName;
int debug, translate;

int if_fd = -1;
int Packet[CHUNKSIZE + 32], TCPport[10];


void
Pexit (err, msg)
  int err;
  char *msg;
{
  perror (msg);
  exit (err);
}

void
Zexit (err, msg)
  int err;
  char *msg;
{
  fprintf (stderr, msg);
  exit (err);
}

#define DEBUGstk(Msg,Num,Seq) \
  if(debug) { \
    printf(Msg,Num,Seq); fflush(stdout); \
}

#define IP          ((struct ip *)Packet)
#define IP_OFFSET   (0x1FFF)
#define SZETH       (sizeof(struct ether_header))
#define IPLEN       (ntohs(ip->ip_len))
#define IPHLEN      (ip->ip_hl)
#define ADneq(s,t)  ((s).s_addr != (t).s_addr)

/*
 * important part of the prog, determines if a packet is one we want, and
 * performs sycnhing of sequence numbers
 */
void
filter (cp, pktlen)
  char *cp;
  u_int pktlen;
{
  int match = 0, i;
  char *src, *dst, sp[15], dp[15];
  register int Stream = STREAM_NULL;
  register struct ip *ip;
  struct in_addr Sipaddr;
  struct in_addr Dipaddr;
  struct servent *sv;
  register struct tcphdr *tcph;
  register u_long CurSEQ;
  register u_char *p;
  register u_short EtherType = ntohs (((struct ether_header *) cp)->ether_type);

  if (EtherType < 0x600)
  {
    EtherType = *(u_short *) (cp + SZETH + 6);
    cp += 8;
    pktlen -= 8;

    if (ISneq (EtherType, ETHERTYPE_IP))
      return;
  }
  /* ugh, gotta do an alignment :-( */
  bcopy (cp + SZETH, (char *) Packet, (int) (pktlen - SZETH));

  ip = (struct ip *) Packet;
  if (ISneq (ip->ip_p, IPPROTO_TCP))
    return;

  tcph = (struct tcphdr *) (Packet + IPHLEN);
  CurSEQ = (ntohl (tcph->th_seq));

  if (debug)
  {
    printf ("SRC:%s(%d) ", inet_ntoa (ip->ip_src), tcph->th_sport);
    printf ("DST:%s(%d)\n", inet_ntoa (ip->ip_dst), tcph->th_dport);
  }
  if (ip->ip_src.s_addr <= 0 || ip->ip_dst.s_addr <= 0)
    return;

  for (i = 0; i < 10; i++)
  {
    if (!TCPport[i])
      continue;
    if (ISeq (tcph->th_sport, TCPport[i]) ||
    ISeq (tcph->th_dport, TCPport[i]))
      match = 1;
  }

  if (!match)
    return;

  {
    register int length = ((IPLEN - (IPHLEN * 4)) - (tcph->th_off * 4));

    if (debug)
      printf ("Seq=%08X,pl=%04X,dl=%04X,l=%04X,iph=%04X,ipl=%04X,tf=%04X\n",
          CurSEQ, pktlen,
       (IPLEN - (IPHLEN * 4)), length, ip->ip_hl, ip->ip_len, tcph->th_off);

    p = (u_char *) Packet;
    p += ((ip->ip_hl * 4) + (tcph->th_off * 4));

    if (ip->ip_src.s_addr <= 0 || ip->ip_dst.s_addr <= 0)
      return;

    if (translate)
    {
      src = translate_host (inet_ntoa (ip->ip_src));
      dst = translate_host (inet_ntoa (ip->ip_dst));
    } else
    {
      src = strdup (inet_ntoa (ip->ip_src));
      dst = strdup (inet_ntoa (ip->ip_dst));
    }

    sprintf (sp, "%d", tcph->th_sport);
    sprintf (dp, "%d", tcph->th_dport);

    sv = getservbyport (tcph->th_sport, "tcp");
    if (sv)
      strcpy (sp, sv->s_name);

    sv = getservbyport (tcph->th_dport, "tcp");
    if (sv)
      strcpy (dp, sv->s_name);

    printf ("%s/%s %s/%s ", src, sp, dst, dp);

    while (length-- > 0)
    {
      fputc (*p, stdout);
      if (*p == '\n' || *p == '\r')
      {
    printf ("\n%s/%d %s/%d ", inet_ntoa (ip->ip_src), tcph->th_sport,
        inet_ntoa (ip->ip_dst), tcph->th_dport);
      }
      p++;
      fflush (stdout);
    }
    printf ("\n");
  }
}

/*
 * signal handler
 */
void
flushit ()
{
  printf ("\n\n[Terminating]\n");
  fflush (stdout);
  exit (1);
}

/*
 * opens network interface, performs ioctls and reads from it, passing data
 * to filter function
 */
void
do_it ()
{
  int cc;
  char *buf;
  u_short sp_ts_len;

  if (!(buf = malloc (CHUNKSIZE)))
    Pexit (1, "Eth: malloc");

  /* this /dev/nit initialization code pinched from etherfind */
  {
    struct strioctl si;
    struct ifreq ifr;
    struct timeval timeout;
    u_int chunksize = CHUNKSIZE;
    u_long if_flags = NI_PROMISC;

    if ((if_fd = open (NIT_DEV, O_RDONLY)) < 0)
      Pexit (1, "Eth: nit open");

    if (ioctl (if_fd, I_SRDOPT, (char *) RMSGD) < 0)
      Pexit (1, "Eth: ioctl (I_SRDOPT)");

    si.ic_timout = INFTIM;

    if (ioctl (if_fd, I_PUSH, "nbuf") < 0)
      Pexit (1, "Eth: ioctl (I_PUSH \"nbuf\")");

    timeout.tv_sec = 1;
    timeout.tv_usec = 0;
    si.ic_cmd = NIOCSTIME;
    si.ic_len = sizeof (timeout);
    si.ic_dp = (char *) &timeout;
    if (ioctl (if_fd, I_STR, (char *) &si) < 0)
      Pexit (1, "Eth: ioctl (I_STR: NIOCSTIME)");

    si.ic_cmd = NIOCSCHUNK;
    si.ic_len = sizeof (chunksize);
    si.ic_dp = (char *) &chunksize;
    if (ioctl (if_fd, I_STR, (char *) &si) < 0)
      Pexit (1, "Eth: ioctl (I_STR: NIOCSCHUNK)");

    strncpy (ifr.ifr_name, device, sizeof (ifr.ifr_name));
    ifr.ifr_name[sizeof (ifr.ifr_name) - 1] = '\0';
    si.ic_cmd = NIOCBIND;
    si.ic_len = sizeof (ifr);
    si.ic_dp = (char *) &ifr;
    if (ioctl (if_fd, I_STR, (char *) &si) < 0)
      Pexit (1, "Eth: ioctl (I_STR: NIOCBIND)");

    si.ic_cmd = NIOCSFLAGS;
    si.ic_len = sizeof (if_flags);
    si.ic_dp = (char *) &if_flags;
    if (ioctl (if_fd, I_STR, (char *) &si) < 0)
      Pexit (1, "Eth: ioctl (I_STR: NIOCSFLAGS)");

    if (ioctl (if_fd, I_FLUSH, (char *) FLUSHR) < 0)
      Pexit (1, "Eth: ioctl (I_FLUSH)");
  }

  while ((cc = read (if_fd, buf, CHUNKSIZE)) >= 0)
  {
    register char *bp = buf, *bufstop = (buf + cc);

    while (bp < bufstop)
    {
      register char *cp = bp;
      register struct nit_bufhdr *hdrp;

      hdrp = (struct nit_bufhdr *) cp;
      cp += sizeof (struct nit_bufhdr);
      bp += hdrp->nhb_totlen;
      filter (cp, (u_long) hdrp->nhb_msglen);
    }
  }
  Pexit ((-1), "Eth: read");
}

int
GetPorts (p, Tp)
  char *p;
  int Tp;
{

  /* get portname, conver from symbolic if needed */
  if ((TCPport[Tp] = atoi (p)) == 0)
  {
    struct servent *sv = getservbyname (p, "tcp");
    if (sv)
      TCPport[Tp] = sv->s_port;
    else
    {
      printf ("Unknown port: %s\n", p);
      exit (-1);
    }
  }
  return (1);
}

void
Usage ()
{
  fprintf (stderr,
       "Usage: %s [-i device] [-d] port ... \n", ProgName);
  fprintf (stderr, "  -d         Debug\n");
  fprintf (stderr, "  -i device  Logical ethernet interface\n");
  fprintf (stderr, "  -t         Translate IP to Hostname\n");
  fprintf (stderr, "  Port       Port name or number\n\n");
  fprintf (stderr, "  Example:   %s -i le0 login finger 21\n",
       ProgName);
  exit (1);
}


void
main (argc, argv)
  int argc;
  char **argv;
{
  int s, ac = 1, i = 0, x = 0;
  char cbuf[BUFSIZ];
  struct ifconf ifc;
  struct servent *sv;

  ProgName = argv[0];

  if (argc == 1)
    Usage ();

  /* parse args */
  device = NULL;
  while (argv[ac][0] == '-')
  {
    register char ch = argv[ac++][1];
    switch (toupper (ch))
    {
    case 'I':
      device = argv[ac++];
      break;
    case 'D':
      debug = 1;
      break;
    case 'T':
      translate = 1;
      break;
    default:
      Usage ();
      break;
    }
  }

  while (argv[ac])
  {
    GetPorts (argv[ac++], i);
    i++;
  }

  /* if not a specified device, determine it */
  if (!device)
  {
    if ((s = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
      Pexit (1, "Eth: socket");

    ifc.ifc_len = sizeof (cbuf);
    ifc.ifc_buf = cbuf;
    if (ioctl (s, SIOCGIFCONF, (char *) &ifc) < 0)
      Pexit (1, "Eth: ioctl");

    close (s);
    device = ifc.ifc_req->ifr_name;
  }
  printf ("=> IP/TCP monitor\n");
  printf ("=> Configured device %s [%s], %ssynching stream ...\n",
      device, NIT_DEV, (debug) ? "(debug) " : "");
  printf ("=> Scanning ports: ");
  for (i = 0; i < 10; i++)
  {
    if (!TCPport[i])
      continue;
    sv = getservbyport (TCPport[i], "tcp");
    if (sv)
      printf ("%s ", sv->s_name);
    else
      printf ("%d ", TCPport[i]);
  }
  printf ("\n");

  fflush (stdout);

  signal (SIGINT, flushit);
  signal (SIGTERM, flushit);

  do_it ();
  /* NOT_REACHED */
}

char *
translate_host (s)
  char s[18];
{
  int size = 0;
  static char hostname[64];
  char *h;
  struct sockaddr_in sin;
  struct hostent *host;

  h = hostname;

  bzero ((char *) &sin, sizeof (sin));
  sin.sin_addr.s_addr = inet_addr (s);
  if (sin.sin_addr.s_addr != -1 && sin.sin_addr.s_addr != 0)
  {
    sin.sin_family = AF_INET;
    host = gethostbyaddr ((char *) &sin.sin_addr, sizeof (sin),
              sin.sin_family);
    if (host)
    {
      strcpy (hostname, host->h_name);
      size = sizeof (hostname) - strlen (hostname);
      if (!index (hostname, '.'))
      {
    if (!(_res.options & RES_INIT))
      res_init ();
    if (_res.defdname[0])
    {
      if (_res.defdname[strlen (_res.defdname) - 1] == '.')
        _res.defdname[strlen (_res.defdname) - 1] = 0;
      strncat (hostname, ".", size);
      strncat (hostname, _res.defdname, size - 2);
    }
      }
      return (h);
    }
  }
  return (s);
}

















TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH