NOTE: This patch assumed tee and not divert. This means that it does not put the packet back into the stream. Since tee sokets are documented, I decided to base my path upon their existance. If you really want to have the packets pass back, it should just be a matter of passing it back using a sendto syscall using the results you got back from the recvfrom syscall. Index: contrib_libpcap/pcap-bpf.c =================================================================== RCS file: /home/ncvs/src/contrib/libpcap/pcap-bpf.c,v retrieving revision 1.1.1.4 diff -u -r1.1.1.4 pcap-bpf.c --- contrib_libpcap/pcap-bpf.c 2000/01/30 00:32:43 1.1.1.4 +++ contrib_libpcap/pcap-bpf.c 2000/06/02 06:07:39 @@ -23,6 +23,7 @@ "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.32 1999/10/19 15:18:30 itojun Exp $ (LBL)"; #endif +#include #include /* optionally get BSD define */ #include #include @@ -31,6 +32,7 @@ #include #include +#include #include #include @@ -64,17 +66,41 @@ return (0); } +/* + * IPDIVERT info from rwatson: +20:23 #bsdco rwatson> int +20:23 #bsdco rwatson> socket_divert_get(struct sockaddr_in *sa, char *buf, int + buflen) +20:23 #bsdco rwatson> { +20:23 #bsdco rwatson> int len, addrlen; +20:23 #bsdco rwatson> addrlen = sizeof(*sa); +20:23 #bsdco rwatson> len = recvfrom(socket_divert, buf, buflen, 0, +20:23 #bsdco rwatson> (struct sockaddr *) sa, &addrlen); +20:23 #bsdco rwatson> if (len == -1) +20:23 #bsdco rwatson> perror("recvfrom"); +20:23 #bsdco rwatson> return (len); +20:23 #bsdco rwatson> } +*/ int pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { + struct sockaddr sa; + int addrlen; int cc; int n = 0; register u_char *bp, *ep; + struct pcap_pkthdr pph; + register int caplen, hdrlen; again: cc = p->cc; if (p->cc == 0) { - cc = read(p->fd, (char *)p->buffer, p->bufsize); + if (p->divert) { + addrlen = sizeof(sa); + cc = recvfrom(p->fd, (char *)p->buffer, p->bufsize, 0, + &sa, &addrlen); + } else + cc = read(p->fd, (char *)p->buffer, p->bufsize); if (cc < 0) { /* Don't choke when we get ptraced */ switch (errno) { @@ -109,24 +135,33 @@ /* * Loop through each packet. */ + + if (p->divert) { + gettimeofday(&pph.ts, NULL); + pph.caplen = cc; + pph.len = cc; + + (*callback)(user, &pph, bp); + n = 1; + } else { #define bhp ((struct bpf_hdr *)bp) - ep = bp + cc; - while (bp < ep) { - register int caplen, hdrlen; - caplen = bhp->bh_caplen; - hdrlen = bhp->bh_hdrlen; - /* - * XXX A bpf_hdr matches a pcap_pkthdr. - */ - (*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen); - bp += BPF_WORDALIGN(caplen + hdrlen); - if (++n >= cnt && cnt > 0) { - p->bp = bp; - p->cc = ep - bp; - return (n); + ep = bp + cc; + while (bp < ep) { + caplen = bhp->bh_caplen; + hdrlen = bhp->bh_hdrlen; + /* + * XXX A bpf_hdr matches a pcap_pkthdr. + */ + (*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen); + bp += BPF_WORDALIGN(caplen + hdrlen); + if (++n >= cnt && cnt > 0) { + p->bp = bp; + p->cc = ep - bp; + return (n); + } } - } #undef bhp + } p->cc = 0; return (n); } @@ -155,9 +190,34 @@ return (fd); } +static int +divert_open(pcap_t *p, char *errbuf, int *port) +{ + int fd; + char *end; + struct sockaddr_in addr; + + *port = strtoul(errbuf, &end, 0); + if (errbuf == end || end != errbuf + strlen(errbuf)) + return -2; + + if ((fd = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT)) == -1) + return fd; + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(*port); + + if (bind(fd, (struct sockaddr *) &addr, sizeof addr) == -1) + return -1; + + return fd; +} + pcap_t * pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) { + int port; int fd; struct ifreq ifr; struct bpf_version bv; @@ -170,19 +230,31 @@ return (NULL); } bzero(p, sizeof(*p)); - fd = bpf_open(p, ebuf); - if (fd < 0) + switch ((fd = divert_open(p, device, &port))) { + case -2: + p->divert = 0; + break; + case -1: goto bad; + default: + p->divert = 1; + } + + if (!p->divert) { + fd = bpf_open(p, ebuf); + if (fd < 0) + goto bad; + } p->fd = fd; p->snapshot = snaplen; - if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) { + if (!p->divert && ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) { sprintf(ebuf, "BIOCVERSION: %s", pcap_strerror(errno)); goto bad; } - if (bv.bv_major != BPF_MAJOR_VERSION || - bv.bv_minor < BPF_MINOR_VERSION) { + if (!p->divert && (bv.bv_major != BPF_MAJOR_VERSION || + bv.bv_minor < BPF_MINOR_VERSION)) { sprintf(ebuf, "kernel bpf filter out of date"); goto bad; } @@ -192,15 +264,18 @@ * fails, it's no big deal, we just continue to use the standard * buffer size. */ - (void) ioctl(fd, BIOCSBLEN, (caddr_t)&v); + if (!p->divert) + (void) ioctl(fd, BIOCSBLEN, (caddr_t)&v); (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); - if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) { + if (!p->divert && ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) { sprintf(ebuf, "%s: %s", device, pcap_strerror(errno)); goto bad; } /* Get the data link layer type. */ - if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) { + if (p->divert) + v = DLT_RAW; + else if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) { sprintf(ebuf, "BIOCGDLT: %s", pcap_strerror(errno)); goto bad; } @@ -235,7 +310,7 @@ p->linktype = v; /* set timeout */ - if (to_ms != 0) { + if (!p->divert && to_ms != 0) { struct timeval to; to.tv_sec = to_ms / 1000; to.tv_usec = (to_ms * 1000) % 1000000; @@ -245,11 +320,13 @@ goto bad; } } - if (promisc) + if (!p->divert && promisc) /* set promiscuous mode, okay if it fails */ (void)ioctl(p->fd, BIOCPROMISC, NULL); - if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) { + if (p->divert) + v = 2048; + else if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) { sprintf(ebuf, "BIOCGBLEN: %s", pcap_strerror(errno)); goto bad; } @@ -279,7 +356,7 @@ p->fcode = *fp; else if (p->sf.rfile != NULL) p->fcode = *fp; - else if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) { + else if (!p->divert && ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) { sprintf(p->errbuf, "BIOCSETF: %s", pcap_strerror(errno)); return (-1); } Index: contrib_libpcap/pcap-int.h =================================================================== RCS file: /home/ncvs/src/contrib/libpcap/pcap-int.h,v retrieving revision 1.3 diff -u -r1.3 pcap-int.h --- contrib_libpcap/pcap-int.h 2000/01/30 00:43:34 1.3 +++ contrib_libpcap/pcap-int.h 2000/06/02 02:58:30 @@ -76,6 +76,7 @@ int linktype; int tzoff; /* timezone offset */ int offset; /* offset for proper alignment */ + int divert; /* this is a divert socket */ struct pcap_sf sf; struct pcap_md md;