155714Skris/* $FreeBSD$ */ 255714Skris 355714Skris/* 455714Skris * (C)opyright 1992-1998 Darren Reed. (from tcplog) 555714Skris * 655714Skris * See the IPFILTER.LICENCE file for details on licencing. 755714Skris * 8280304Sjkim */ 955714Skris 1055714Skris#include <stdio.h> 1155714Skris#include <netdb.h> 1255714Skris#include <ctype.h> 1355714Skris#include <fcntl.h> 1455714Skris#include <signal.h> 15280304Sjkim#include <errno.h> 1655714Skris#include <sys/types.h> 1755714Skris#include <sys/time.h> 1855714Skris#include <sys/timeb.h> 1955714Skris#include <sys/socket.h> 2055714Skris#include <sys/file.h> 2155714Skris#include <sys/ioctl.h> 22280304Sjkim#include <sys/stropts.h> 2355714Skris 2455714Skris#include <sys/pfmod.h> 2555714Skris#include <sys/bufmod.h> 2655714Skris#include <sys/dlpi.h> 2755714Skris 2855714Skris#include <net/if.h> 2955714Skris#include <netinet/in.h> 3055714Skris#include <netinet/in_systm.h> 3155714Skris#include <netinet/ip.h> 3255714Skris#include <netinet/if_ether.h> 3355714Skris#include <netinet/ip_var.h> 3455714Skris#include <netinet/udp.h> 3555714Skris#include <netinet/udp_var.h> 3655714Skris#include <netinet/tcp.h> 37280304Sjkim#include <netinet/tcpip.h> 3855714Skris 3955714Skris#include "ip_compat.h" 40280304Sjkim 4155714Skris#ifndef lint 4255714Skrisstatic char snitid[] = "%W% %G% (C)1995 Darren Reed"; 4355714Skris#endif 4455714Skris 4555714Skris#define BUFSPACE 32768 4655714Skris 4755714Skrisstatic int solfd; 4855714Skris 4955714Skris/* 5055714Skris * Be careful to only include those defined in the flags option for the 5155714Skris * interface are included in the header size. 52280304Sjkim */ 5355714Skrisstatic int timeout; 5455714Skris 5555714Skris 5655714Skrisvoid nullbell() 5755714Skris{ 5855714Skris return 0; 5955714Skris} 6055714Skris 6155714Skris 6255714Skrisint ack_recv(ep) 6355714Skris char *ep; 6455714Skris{ 65280304Sjkim struct tcpiphdr tip; 66280304Sjkim tcphdr_t *tcp; 67280304Sjkim ip_t *ip; 68280304Sjkim 6955714Skris ip = (ip_t *)&tip; 70280304Sjkim tcp = (tcphdr_t *)(ip + 1); 7155714Skris bcopy(ep, (char *)ip, sizeof(*ip)); 7255714Skris bcopy(ep + (ip->ip_hl << 2), (char *)tcp, sizeof(*tcp)); 73109998Smarkm 7455714Skris if (ip->ip_off & 0x1fff != 0) 75109998Smarkm return 0; 7655714Skris if (0 == detect(ip, tcp)) 7755714Skris return 1; 7855714Skris return 0; 7955714Skris} 8055714Skris 8155714Skris 8255714Skrisint readloop(fd, port, dst) 8355714Skris int fd, port; 8455714Skris struct in_addr dst; 8555714Skris{ 86109998Smarkm static u_char buf[BUFSPACE]; 87280304Sjkim register u_char *bp, *cp, *bufend; 88280304Sjkim register struct sb_hdr *hp; 89238405Sjkim register int cc; 90280304Sjkim struct strbuf dbuf; 91238405Sjkim ether_header_t eh; 92280304Sjkim time_t now = time(NULL); 93280304Sjkim int flags = 0, i, done = 0; 94280304Sjkim 95280304Sjkim fd = solfd; 96280304Sjkim dbuf.len = 0; 97280304Sjkim dbuf.buf = buf; 98280304Sjkim dbuf.maxlen = sizeof(buf); 99280304Sjkim /* 100280304Sjkim * no control data buffer... 101280304Sjkim */ 102280304Sjkim while (1) { 103280304Sjkim (void) signal(SIGALRM, nullbell); 104280304Sjkim alarm(1); 105280304Sjkim i = getmsg(fd, NULL, &dbuf, &flags); 10655714Skris alarm(0); 107280304Sjkim (void) signal(SIGALRM, nullbell); 108280304Sjkim 109280304Sjkim cc = dbuf.len; 110280304Sjkim if ((time(NULL) - now) > timeout) 111280304Sjkim return done; 112280304Sjkim if (i == -1) 113280304Sjkim if (errno == EINTR) 114280304Sjkim continue; 115280304Sjkim else 116280304Sjkim break; 117280304Sjkim bp = buf; 118280304Sjkim bufend = buf + cc; 119280304Sjkim /* 120280304Sjkim * loop through each snapshot in the chunk 121280304Sjkim */ 122280304Sjkim while (bp < bufend) { 123280304Sjkim /* 124280304Sjkim * get past bufmod header 125280304Sjkim */ 126280304Sjkim hp = (struct sb_hdr *)bp; 127280304Sjkim cp = (u_char *)((char *)bp + sizeof(*hp)); 128280304Sjkim bcopy(cp, (char *)&eh, sizeof(eh)); 129280304Sjkim /* 130280304Sjkim * next snapshot 131280304Sjkim */ 132280304Sjkim bp += hp->sbh_totlen; 133280304Sjkim cc -= hp->sbh_totlen; 134280304Sjkim 135280304Sjkim if (eh.ether_type != ETHERTYPE_IP) 136280304Sjkim continue; 137280304Sjkim 138280304Sjkim cp += sizeof(eh); 139280304Sjkim done += ack_recv(cp); 140280304Sjkim } 141280304Sjkim alarm(1); 142280304Sjkim } 14355714Skris perror("getmsg"); 144280304Sjkim exit(-1); 145280304Sjkim} 146280304Sjkim 14755714Skrisint initdevice(device, tout) 148280304Sjkim char *device; 149280304Sjkim int tout; 150280304Sjkim{ 151280304Sjkim struct strioctl si; 152280304Sjkim struct timeval to; 153280304Sjkim struct ifreq ifr; 154280304Sjkim struct packetfilt pfil; 155280304Sjkim u_long if_flags; 156280304Sjkim u_short *fwp = pfil.Pf_Filter; 157280304Sjkim char devname[16], *s, buf[256]; 158280304Sjkim int i, offset, fd, snaplen= 58, chunksize = BUFSPACE; 159280304Sjkim 160280304Sjkim (void) sprintf(devname, "/dev/%s", device); 161280304Sjkim 162280304Sjkim s = devname + 5; 16355714Skris while (*s && !ISDIGIT(*s)) 164280304Sjkim s++; 165280304Sjkim if (!*s) 166280304Sjkim { 167280304Sjkim fprintf(stderr, "bad device name %s\n", devname); 168280304Sjkim exit(-1); 169280304Sjkim } 170280304Sjkim i = atoi(s); 171280304Sjkim *s = '\0'; 172280304Sjkim /* 173280304Sjkim * For reading 174280304Sjkim */ 17555714Skris if ((fd = open(devname, O_RDWR)) < 0) 176280304Sjkim { 177280304Sjkim fprintf(stderr, "O_RDWR(0) "); 178280304Sjkim perror(devname); 179280304Sjkim exit(-1); 180280304Sjkim } 181280304Sjkim if (dlattachreq(fd, i) == -1 || dlokack(fd, buf) == -1) 182280304Sjkim { 183280304Sjkim fprintf(stderr, "DLPI error\n"); 184280304Sjkim exit(-1); 185280304Sjkim } 186280304Sjkim dlbindreq(fd, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0); 187280304Sjkim dlbindack(fd, buf); 188280304Sjkim /* 189280304Sjkim * read full headers 190280304Sjkim */ 19155714Skris if (strioctl(fd, DLIOCRAW, -1, 0, NULL) == -1) 192280304Sjkim { 193280304Sjkim fprintf(stderr, "DLIOCRAW error\n"); 194280304Sjkim exit(-1); 195280304Sjkim } 196280304Sjkim /* 197280304Sjkim * Create some filter rules for our TCP watcher. We only want ethernet 198280304Sjkim * pacets which are IP protocol and only the TCP packets from IP. 199280304Sjkim */ 200280304Sjkim offset = 6; 20155714Skris *fwp++ = ENF_PUSHWORD + offset; 202280304Sjkim *fwp++ = ENF_PUSHLIT | ENF_CAND; 203280304Sjkim *fwp++ = htons(ETHERTYPE_IP); 204280304Sjkim *fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4; 205280304Sjkim *fwp++ = ENF_PUSHLIT | ENF_AND; 206280304Sjkim *fwp++ = htons(0x00ff); 207280304Sjkim *fwp++ = ENF_PUSHLIT | ENF_COR; 208280304Sjkim *fwp++ = htons(IPPROTO_TCP); 209280304Sjkim *fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4; 210280304Sjkim *fwp++ = ENF_PUSHLIT | ENF_AND; 211280304Sjkim *fwp++ = htons(0x00ff); 212280304Sjkim *fwp++ = ENF_PUSHLIT | ENF_CAND; 213280304Sjkim *fwp++ = htons(IPPROTO_UDP); 214280304Sjkim pfil.Pf_FilterLen = (fwp - &pfil.Pf_Filter[0]); 21555714Skris /* 216280304Sjkim * put filter in place. 217280304Sjkim */ 218280304Sjkim 219280304Sjkim if (ioctl(fd, I_PUSH, "pfmod") == -1) 22055714Skris { 221280304Sjkim perror("ioctl: I_PUSH pf"); 222280304Sjkim exit(1); 223280304Sjkim } 224280304Sjkim if (strioctl(fd, PFIOCSETF, -1, sizeof(pfil), (char *)&pfil) == -1) 225280304Sjkim { 226280304Sjkim perror("ioctl: PFIOCSETF"); 227280304Sjkim exit(1); 228280304Sjkim } 229280304Sjkim 230280304Sjkim /* 231280304Sjkim * arrange to get messages from the NIT STREAM and use NIT_BUF option 232280304Sjkim */ 233280304Sjkim if (ioctl(fd, I_PUSH, "bufmod") == -1) 234280304Sjkim { 235280304Sjkim perror("ioctl: I_PUSH bufmod"); 236 exit(1); 237 } 238 i = 128; 239 strioctl(fd, SBIOCSSNAP, -1, sizeof(i), (char *)&i); 240 /* 241 * set the timeout 242 */ 243 to.tv_sec = 1; 244 to.tv_usec = 0; 245 if (strioctl(fd, SBIOCSTIME, -1, sizeof(to), (char *)&to) == -1) 246 { 247 perror("strioctl(SBIOCSTIME)"); 248 exit(-1); 249 } 250 /* 251 * flush read queue 252 */ 253 if (ioctl(fd, I_FLUSH, FLUSHR) == -1) 254 { 255 perror("I_FLUSHR"); 256 exit(-1); 257 } 258 timeout = tout; 259 solfd = fd; 260 return fd; 261} 262