|
/* * 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 *) 𝔦 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); }