1145519Sdarrenr/* $FreeBSD$ */ 2145510Sdarrenr 322514Sdarrenr/* 453024Sguido * (C)opyright 1992-1998 Darren Reed. (from tcplog) 522514Sdarrenr * 680486Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 722514Sdarrenr * 822514Sdarrenr */ 922514Sdarrenr 1022514Sdarrenr#include <stdio.h> 1122514Sdarrenr#include <netdb.h> 1222514Sdarrenr#include <ctype.h> 1322514Sdarrenr#include <fcntl.h> 1422514Sdarrenr#include <signal.h> 1522514Sdarrenr#include <errno.h> 1622514Sdarrenr#include <sys/types.h> 1722514Sdarrenr#include <sys/time.h> 1822514Sdarrenr#include <sys/timeb.h> 1922514Sdarrenr#include <sys/socket.h> 2022514Sdarrenr#include <sys/file.h> 2122514Sdarrenr#include <sys/ioctl.h> 2222514Sdarrenr#include <sys/stropts.h> 2322514Sdarrenr 2422514Sdarrenr#include <sys/pfmod.h> 2522514Sdarrenr#include <sys/bufmod.h> 2622514Sdarrenr#include <sys/dlpi.h> 2722514Sdarrenr 2822514Sdarrenr#include <net/if.h> 2922514Sdarrenr#include <netinet/in.h> 3022514Sdarrenr#include <netinet/in_systm.h> 3122514Sdarrenr#include <netinet/ip.h> 3222514Sdarrenr#include <netinet/if_ether.h> 3322514Sdarrenr#include <netinet/ip_var.h> 3422514Sdarrenr#include <netinet/udp.h> 3522514Sdarrenr#include <netinet/udp_var.h> 3622514Sdarrenr#include <netinet/tcp.h> 3722514Sdarrenr#include <netinet/tcpip.h> 3822514Sdarrenr 3922514Sdarrenr#include "ip_compat.h" 4022514Sdarrenr 4122514Sdarrenr#ifndef lint 4222514Sdarrenrstatic char snitid[] = "%W% %G% (C)1995 Darren Reed"; 4322514Sdarrenr#endif 4422514Sdarrenr 4522514Sdarrenr#define BUFSPACE 32768 4622514Sdarrenr 4722514Sdarrenrstatic int solfd; 4822514Sdarrenr 4922514Sdarrenr/* 5022514Sdarrenr * Be careful to only include those defined in the flags option for the 5122514Sdarrenr * interface are included in the header size. 5222514Sdarrenr */ 5322514Sdarrenrstatic int timeout; 5422514Sdarrenr 5522514Sdarrenr 5622514Sdarrenrvoid nullbell() 5722514Sdarrenr{ 5822514Sdarrenr return 0; 5922514Sdarrenr} 6022514Sdarrenr 6122514Sdarrenr 6222514Sdarrenrint ack_recv(ep) 6322514Sdarrenrchar *ep; 6422514Sdarrenr{ 6522514Sdarrenr struct tcpiphdr tip; 6622514Sdarrenr tcphdr_t *tcp; 6722514Sdarrenr ip_t *ip; 6822514Sdarrenr 6922514Sdarrenr ip = (ip_t *)&tip; 7022514Sdarrenr tcp = (tcphdr_t *)(ip + 1); 7122514Sdarrenr bcopy(ep, (char *)ip, sizeof(*ip)); 7222514Sdarrenr bcopy(ep + (ip->ip_hl << 2), (char *)tcp, sizeof(*tcp)); 7322514Sdarrenr 7422514Sdarrenr if (ip->ip_off & 0x1fff != 0) 7522514Sdarrenr return 0; 7622514Sdarrenr if (0 == detect(ip, tcp)) 7722514Sdarrenr return 1; 7822514Sdarrenr return 0; 7922514Sdarrenr} 8022514Sdarrenr 8122514Sdarrenr 8222514Sdarrenrint readloop(fd, port, dst) 8322514Sdarrenrint fd, port; 8422514Sdarrenrstruct in_addr dst; 8522514Sdarrenr{ 8622514Sdarrenr static u_char buf[BUFSPACE]; 8722514Sdarrenr register u_char *bp, *cp, *bufend; 8822514Sdarrenr register struct sb_hdr *hp; 8922514Sdarrenr register int cc; 9022514Sdarrenr struct strbuf dbuf; 9122514Sdarrenr ether_header_t eh; 9222514Sdarrenr time_t now = time(NULL); 9322514Sdarrenr int flags = 0, i, done = 0; 9422514Sdarrenr 9522514Sdarrenr fd = solfd; 9622514Sdarrenr dbuf.len = 0; 9722514Sdarrenr dbuf.buf = buf; 9822514Sdarrenr dbuf.maxlen = sizeof(buf); 9922514Sdarrenr /* 10022514Sdarrenr * no control data buffer... 10122514Sdarrenr */ 10222514Sdarrenr while (1) { 10322514Sdarrenr (void) signal(SIGALRM, nullbell); 10422514Sdarrenr alarm(1); 10522514Sdarrenr i = getmsg(fd, NULL, &dbuf, &flags); 10622514Sdarrenr alarm(0); 10722514Sdarrenr (void) signal(SIGALRM, nullbell); 10822514Sdarrenr 10922514Sdarrenr cc = dbuf.len; 11022514Sdarrenr if ((time(NULL) - now) > timeout) 11122514Sdarrenr return done; 11222514Sdarrenr if (i == -1) 11322514Sdarrenr if (errno == EINTR) 11422514Sdarrenr continue; 11522514Sdarrenr else 11622514Sdarrenr break; 11722514Sdarrenr bp = buf; 11822514Sdarrenr bufend = buf + cc; 11922514Sdarrenr /* 12022514Sdarrenr * loop through each snapshot in the chunk 12122514Sdarrenr */ 12222514Sdarrenr while (bp < bufend) { 12322514Sdarrenr /* 12422514Sdarrenr * get past bufmod header 12522514Sdarrenr */ 12622514Sdarrenr hp = (struct sb_hdr *)bp; 12722514Sdarrenr cp = (u_char *)((char *)bp + sizeof(*hp)); 12822514Sdarrenr bcopy(cp, (char *)&eh, sizeof(eh)); 12922514Sdarrenr /* 13022514Sdarrenr * next snapshot 13122514Sdarrenr */ 13222514Sdarrenr bp += hp->sbh_totlen; 13322514Sdarrenr cc -= hp->sbh_totlen; 13422514Sdarrenr 13522514Sdarrenr if (eh.ether_type != ETHERTYPE_IP) 13622514Sdarrenr continue; 13722514Sdarrenr 13822514Sdarrenr cp += sizeof(eh); 13922514Sdarrenr done += ack_recv(cp); 14022514Sdarrenr } 14122514Sdarrenr alarm(1); 14222514Sdarrenr } 14322514Sdarrenr perror("getmsg"); 14422514Sdarrenr exit(-1); 14522514Sdarrenr} 14622514Sdarrenr 14722514Sdarrenrint initdevice(device, tout) 14822514Sdarrenrchar *device; 14922514Sdarrenrint tout; 15022514Sdarrenr{ 15122514Sdarrenr struct strioctl si; 15222514Sdarrenr struct timeval to; 15322514Sdarrenr struct ifreq ifr; 15422514Sdarrenr struct packetfilt pfil; 15522514Sdarrenr u_long if_flags; 15622514Sdarrenr u_short *fwp = pfil.Pf_Filter; 15722514Sdarrenr char devname[16], *s, buf[256]; 15822514Sdarrenr int i, offset, fd, snaplen= 58, chunksize = BUFSPACE; 15922514Sdarrenr 16022514Sdarrenr (void) sprintf(devname, "/dev/%s", device); 16122514Sdarrenr 16222514Sdarrenr s = devname + 5; 163145510Sdarrenr while (*s && !ISDIGIT(*s)) 16422514Sdarrenr s++; 16522514Sdarrenr if (!*s) 16622514Sdarrenr { 16722514Sdarrenr fprintf(stderr, "bad device name %s\n", devname); 16822514Sdarrenr exit(-1); 16922514Sdarrenr } 17022514Sdarrenr i = atoi(s); 17122514Sdarrenr *s = '\0'; 17222514Sdarrenr /* 17322514Sdarrenr * For reading 17422514Sdarrenr */ 17522514Sdarrenr if ((fd = open(devname, O_RDWR)) < 0) 17622514Sdarrenr { 17722514Sdarrenr fprintf(stderr, "O_RDWR(0) "); 17822514Sdarrenr perror(devname); 17922514Sdarrenr exit(-1); 18022514Sdarrenr } 18122514Sdarrenr if (dlattachreq(fd, i) == -1 || dlokack(fd, buf) == -1) 18222514Sdarrenr { 18322514Sdarrenr fprintf(stderr, "DLPI error\n"); 18422514Sdarrenr exit(-1); 18522514Sdarrenr } 18622514Sdarrenr dlbindreq(fd, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0); 18722514Sdarrenr dlbindack(fd, buf); 18822514Sdarrenr /* 18922514Sdarrenr * read full headers 19022514Sdarrenr */ 19122514Sdarrenr if (strioctl(fd, DLIOCRAW, -1, 0, NULL) == -1) 19222514Sdarrenr { 19322514Sdarrenr fprintf(stderr, "DLIOCRAW error\n"); 19422514Sdarrenr exit(-1); 19522514Sdarrenr } 19622514Sdarrenr /* 19722514Sdarrenr * Create some filter rules for our TCP watcher. We only want ethernet 19822514Sdarrenr * pacets which are IP protocol and only the TCP packets from IP. 19922514Sdarrenr */ 20022514Sdarrenr offset = 6; 20122514Sdarrenr *fwp++ = ENF_PUSHWORD + offset; 20222514Sdarrenr *fwp++ = ENF_PUSHLIT | ENF_CAND; 20322514Sdarrenr *fwp++ = htons(ETHERTYPE_IP); 20422514Sdarrenr *fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4; 20522514Sdarrenr *fwp++ = ENF_PUSHLIT | ENF_AND; 20622514Sdarrenr *fwp++ = htons(0x00ff); 20722514Sdarrenr *fwp++ = ENF_PUSHLIT | ENF_COR; 20822514Sdarrenr *fwp++ = htons(IPPROTO_TCP); 20922514Sdarrenr *fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4; 21022514Sdarrenr *fwp++ = ENF_PUSHLIT | ENF_AND; 21122514Sdarrenr *fwp++ = htons(0x00ff); 21222514Sdarrenr *fwp++ = ENF_PUSHLIT | ENF_CAND; 21322514Sdarrenr *fwp++ = htons(IPPROTO_UDP); 21422514Sdarrenr pfil.Pf_FilterLen = (fwp - &pfil.Pf_Filter[0]); 21522514Sdarrenr /* 21622514Sdarrenr * put filter in place. 21722514Sdarrenr */ 21822514Sdarrenr 21922514Sdarrenr if (ioctl(fd, I_PUSH, "pfmod") == -1) 22022514Sdarrenr { 22122514Sdarrenr perror("ioctl: I_PUSH pf"); 22222514Sdarrenr exit(1); 22322514Sdarrenr } 22422514Sdarrenr if (strioctl(fd, PFIOCSETF, -1, sizeof(pfil), (char *)&pfil) == -1) 22522514Sdarrenr { 22622514Sdarrenr perror("ioctl: PFIOCSETF"); 22722514Sdarrenr exit(1); 22822514Sdarrenr } 22922514Sdarrenr 23022514Sdarrenr /* 23122514Sdarrenr * arrange to get messages from the NIT STREAM and use NIT_BUF option 23222514Sdarrenr */ 23322514Sdarrenr if (ioctl(fd, I_PUSH, "bufmod") == -1) 23422514Sdarrenr { 23522514Sdarrenr perror("ioctl: I_PUSH bufmod"); 23622514Sdarrenr exit(1); 23722514Sdarrenr } 23822514Sdarrenr i = 128; 23922514Sdarrenr strioctl(fd, SBIOCSSNAP, -1, sizeof(i), (char *)&i); 24022514Sdarrenr /* 24122514Sdarrenr * set the timeout 24222514Sdarrenr */ 24322514Sdarrenr to.tv_sec = 1; 24422514Sdarrenr to.tv_usec = 0; 24522514Sdarrenr if (strioctl(fd, SBIOCSTIME, -1, sizeof(to), (char *)&to) == -1) 24622514Sdarrenr { 24722514Sdarrenr perror("strioctl(SBIOCSTIME)"); 24822514Sdarrenr exit(-1); 24922514Sdarrenr } 25022514Sdarrenr /* 25122514Sdarrenr * flush read queue 25222514Sdarrenr */ 25322514Sdarrenr if (ioctl(fd, I_FLUSH, FLUSHR) == -1) 25422514Sdarrenr { 25522514Sdarrenr perror("I_FLUSHR"); 25622514Sdarrenr exit(-1); 25722514Sdarrenr } 25822514Sdarrenr timeout = tout; 25922514Sdarrenr solfd = fd; 26022514Sdarrenr return fd; 26122514Sdarrenr} 262