1/* $FreeBSD$ */ 2 3/* 4 * (C)opyright 1992-1998 Darren Reed. (from tcplog) 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 * 8 */ 9 10#include <stdio.h> 11#include <netdb.h> 12#include <ctype.h> 13#include <fcntl.h> 14#include <signal.h> 15#include <errno.h> 16#include <sys/types.h> 17#include <sys/time.h> 18#include <sys/timeb.h> 19#include <sys/socket.h> 20#include <sys/file.h> 21#include <sys/ioctl.h> 22#include <sys/stropts.h> 23 24#include <sys/pfmod.h> 25#include <sys/bufmod.h> 26#include <sys/dlpi.h> 27 28#include <net/if.h> 29#include <netinet/in.h> 30#include <netinet/in_systm.h> 31#include <netinet/ip.h> 32#include <netinet/if_ether.h> 33#include <netinet/ip_var.h> 34#include <netinet/udp.h> 35#include <netinet/udp_var.h> 36#include <netinet/tcp.h> 37#include <netinet/tcpip.h> 38 39#include "ip_compat.h" 40 41#ifndef lint 42static char snitid[] = "%W% %G% (C)1995 Darren Reed"; 43#endif 44 45#define BUFSPACE 32768 46 47static int solfd; 48 49/* 50 * Be careful to only include those defined in the flags option for the 51 * interface are included in the header size. 52 */ 53static int timeout; 54 55 56void nullbell() 57{ 58 return 0; 59} 60 61 62int ack_recv(ep) 63char *ep; 64{ 65 struct tcpiphdr tip; 66 tcphdr_t *tcp; 67 ip_t *ip; 68 69 ip = (ip_t *)&tip; 70 tcp = (tcphdr_t *)(ip + 1); 71 bcopy(ep, (char *)ip, sizeof(*ip)); 72 bcopy(ep + (ip->ip_hl << 2), (char *)tcp, sizeof(*tcp)); 73 74 if (ip->ip_off & 0x1fff != 0) 75 return 0; 76 if (0 == detect(ip, tcp)) 77 return 1; 78 return 0; 79} 80 81 82int readloop(fd, port, dst) 83int fd, port; 84struct in_addr dst; 85{ 86 static u_char buf[BUFSPACE]; 87 register u_char *bp, *cp, *bufend; 88 register struct sb_hdr *hp; 89 register int cc; 90 struct strbuf dbuf; 91 ether_header_t eh; 92 time_t now = time(NULL); 93 int flags = 0, i, done = 0; 94 95 fd = solfd; 96 dbuf.len = 0; 97 dbuf.buf = buf; 98 dbuf.maxlen = sizeof(buf); 99 /* 100 * no control data buffer... 101 */ 102 while (1) { 103 (void) signal(SIGALRM, nullbell); 104 alarm(1); 105 i = getmsg(fd, NULL, &dbuf, &flags); 106 alarm(0); 107 (void) signal(SIGALRM, nullbell); 108 109 cc = dbuf.len; 110 if ((time(NULL) - now) > timeout) 111 return done; 112 if (i == -1) 113 if (errno == EINTR) 114 continue; 115 else 116 break; 117 bp = buf; 118 bufend = buf + cc; 119 /* 120 * loop through each snapshot in the chunk 121 */ 122 while (bp < bufend) { 123 /* 124 * get past bufmod header 125 */ 126 hp = (struct sb_hdr *)bp; 127 cp = (u_char *)((char *)bp + sizeof(*hp)); 128 bcopy(cp, (char *)&eh, sizeof(eh)); 129 /* 130 * next snapshot 131 */ 132 bp += hp->sbh_totlen; 133 cc -= hp->sbh_totlen; 134 135 if (eh.ether_type != ETHERTYPE_IP) 136 continue; 137 138 cp += sizeof(eh); 139 done += ack_recv(cp); 140 } 141 alarm(1); 142 } 143 perror("getmsg"); 144 exit(-1); 145} 146 147int initdevice(device, tout) 148char *device; 149int tout; 150{ 151 struct strioctl si; 152 struct timeval to; 153 struct ifreq ifr; 154 struct packetfilt pfil; 155 u_long if_flags; 156 u_short *fwp = pfil.Pf_Filter; 157 char devname[16], *s, buf[256]; 158 int i, offset, fd, snaplen= 58, chunksize = BUFSPACE; 159 160 (void) sprintf(devname, "/dev/%s", device); 161 162 s = devname + 5; 163 while (*s && !ISDIGIT(*s)) 164 s++; 165 if (!*s) 166 { 167 fprintf(stderr, "bad device name %s\n", devname); 168 exit(-1); 169 } 170 i = atoi(s); 171 *s = '\0'; 172 /* 173 * For reading 174 */ 175 if ((fd = open(devname, O_RDWR)) < 0) 176 { 177 fprintf(stderr, "O_RDWR(0) "); 178 perror(devname); 179 exit(-1); 180 } 181 if (dlattachreq(fd, i) == -1 || dlokack(fd, buf) == -1) 182 { 183 fprintf(stderr, "DLPI error\n"); 184 exit(-1); 185 } 186 dlbindreq(fd, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0); 187 dlbindack(fd, buf); 188 /* 189 * read full headers 190 */ 191 if (strioctl(fd, DLIOCRAW, -1, 0, NULL) == -1) 192 { 193 fprintf(stderr, "DLIOCRAW error\n"); 194 exit(-1); 195 } 196 /* 197 * Create some filter rules for our TCP watcher. We only want ethernet 198 * pacets which are IP protocol and only the TCP packets from IP. 199 */ 200 offset = 6; 201 *fwp++ = ENF_PUSHWORD + offset; 202 *fwp++ = ENF_PUSHLIT | ENF_CAND; 203 *fwp++ = htons(ETHERTYPE_IP); 204 *fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4; 205 *fwp++ = ENF_PUSHLIT | ENF_AND; 206 *fwp++ = htons(0x00ff); 207 *fwp++ = ENF_PUSHLIT | ENF_COR; 208 *fwp++ = htons(IPPROTO_TCP); 209 *fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4; 210 *fwp++ = ENF_PUSHLIT | ENF_AND; 211 *fwp++ = htons(0x00ff); 212 *fwp++ = ENF_PUSHLIT | ENF_CAND; 213 *fwp++ = htons(IPPROTO_UDP); 214 pfil.Pf_FilterLen = (fwp - &pfil.Pf_Filter[0]); 215 /* 216 * put filter in place. 217 */ 218 219 if (ioctl(fd, I_PUSH, "pfmod") == -1) 220 { 221 perror("ioctl: I_PUSH pf"); 222 exit(1); 223 } 224 if (strioctl(fd, PFIOCSETF, -1, sizeof(pfil), (char *)&pfil) == -1) 225 { 226 perror("ioctl: PFIOCSETF"); 227 exit(1); 228 } 229 230 /* 231 * arrange to get messages from the NIT STREAM and use NIT_BUF option 232 */ 233 if (ioctl(fd, I_PUSH, "bufmod") == -1) 234 { 235 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