diff -ur libpcap-orig/pcap-bpf.c libpcap-divert/pcap-bpf.c --- libpcap-orig/pcap-bpf.c Wed Apr 23 22:17:41 2003 +++ libpcap-divert/pcap-bpf.c Wed Apr 23 22:38:24 2003 @@ -27,6 +27,7 @@ #include "config.h" #endif +#include #include /* optionally get BSD define */ #include #include @@ -35,6 +36,7 @@ #include #include +#include #ifdef _AIX @@ -128,17 +130,40 @@ 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) { + 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(p->sa); + cc = recvfrom(p->fd, (char *)p->buffer, p->bufsize, 0, + &p->sa, &addrlen); + } else + cc = read(p->fd, (char *)p->buffer, p->bufsize); if (cc < 0) { /* Don't choke when we get ptraced */ switch (errno) { @@ -200,42 +225,62 @@ /* * 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. - */ + 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. + */ #ifdef _AIX - /* - * AIX's BPF returns seconds/nanoseconds time stamps, not - * seconds/microseconds time stamps. - * - * XXX - I'm guessing here that it's a "struct timestamp"; - * if not, this code won't compile, but, if not, you - * want to send us a bug report and fall back on using - * DLPI. It's not as if BPF used to work right on - * AIX before this change; this change attempts to fix - * the fact that it didn't.... - */ - bhp->bh_tstamp.tv_usec = bhp->bh_tstamp.tv_usec/1000; + /* + * AIX's BPF returns seconds/nanoseconds time stamps, not + * seconds/microseconds time stamps. + * + * XXX - I'm guessing here that it's a "struct timestamp"; + * if not, this code won't compile, but, if not, you + * want to send us a bug report and fall back on using + * DLPI. It's not as if BPF used to work right on + * AIX before this change; this change attempts to fix + * the fact that it didn't.... + */ + bhp->bh_tstamp.tv_usec = bhp->bh_tstamp.tv_usec/1000; #endif - (*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); + (*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); } +int +pcap_get_last_sockaddr(pcap_t *p, struct sockaddr *in) +{ + if (!p->divert) + return -1; + + memcpy (in, &(p->sa), sizeof(struct sockaddr)); + + return 0; +} + #ifdef _AIX static int bpf_odminit(char *errbuf) @@ -424,6 +469,37 @@ return (fd); } +static int +divert_open(pcap_t *p, char *device, int *port, char *errbuf) +{ + int fd; + char *end; + struct sockaddr_in addr; + + *port = strtoul(device, &end, 0); + if (device == end || end != device + strlen(device)) + return -2; + + if ((fd = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT)) == -1) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "(unable to open diverted socket) %d: %s", + *port, pcap_strerror(errno)); + 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) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "(unable to bind diverted socket) %d: %s", + *port, pcap_strerror(errno)); + return -1; + } + return fd; +} + /* * XXX - on AIX, IBM's tcpdump (and perhaps the incompatible-with-everybody- * else's libpcap in AIX 5.1) appears to forcibly load the BPF driver @@ -438,6 +514,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebuf) { + int port; int fd; struct ifreq ifr; struct bpf_version bv; @@ -458,20 +535,33 @@ return (NULL); } memset(p, 0, sizeof(*p)); - fd = bpf_open(p, ebuf); - if (fd < 0) + + switch ((fd = divert_open(p, device, &port, ebuf))) { + 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) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "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)) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "kernel bpf filter out of date"); goto bad; @@ -494,27 +584,33 @@ * the call 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) - break; /* that size worked; we're done */ - if (errno != ENOBUFS) { - snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", - device, pcap_strerror(errno)); - goto bad; + if (!p->divert) { + if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0) + break; /* that size worked; we're done */ + + if (errno != ENOBUFS) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", + device, pcap_strerror(errno)); + goto bad; + } } } - if (v == 0) { + if (!p->divert && v == 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSBLEN: %s: No buffer size worked", device); 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) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s", pcap_strerror(errno)); goto bad; @@ -580,7 +676,7 @@ * this interface supports. If this fails with EINVAL, it's * not fatal; we just don't get to use the feature later. */ - if (ioctl(fd, BIOCGDLTLIST, (caddr_t)&bdl) == 0) { + if (!p->divert && ioctl(fd, BIOCGDLTLIST, (caddr_t)&bdl) == 0) { bdl.bfl_list = (u_int *) malloc(sizeof(u_int) * bdl.bfl_len); if (bdl.bfl_list == NULL) { (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", @@ -606,7 +702,7 @@ #endif /* set timeout */ - if (to_ms != 0) { + if (!p->divert && to_ms != 0) { /* * XXX - is this seconds/nanoseconds in AIX? * (Treating it as such doesn't fix the timeout @@ -679,7 +775,7 @@ #endif /* BIOCIMMEDIATE */ #endif /* _AIX */ - if (promisc) { + if (!p->divert && promisc) { /* set promiscuous mode, okay if it fails */ if (ioctl(p->fd, BIOCPROMISC, NULL) < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCPROMISC: %s", @@ -687,7 +783,9 @@ } } - if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) { + if (p->divert) + v = 2048; + else if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s", pcap_strerror(errno)); goto bad; @@ -736,7 +834,7 @@ } else if (p->sf.rfile != NULL) { if (install_bpf_program(p, fp) < 0) return (-1); - } else if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) { + } else if (!p->divert && ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s", pcap_strerror(errno)); return (-1); diff -ur libpcap-orig/pcap-int.h libpcap-divert/pcap-int.h --- libpcap-orig/pcap-int.h Wed Apr 23 22:17:41 2003 +++ libpcap-divert/pcap-int.h Wed Apr 23 22:30:39 2003 @@ -91,6 +91,8 @@ int linktype; int tzoff; /* timezone offset */ int offset; /* offset for proper alignment */ + int divert; /* this is a divert socket */ + struct sockaddr sa; /* this is socket address for re-writing in divert */ struct pcap_sf sf; struct pcap_md md; diff -ur libpcap-orig/pcap.h libpcap-divert/pcap.h --- libpcap-orig/pcap.h Wed Apr 23 22:17:42 2003 +++ libpcap-divert/pcap.h Wed Apr 23 22:31:40 2003 @@ -42,6 +42,7 @@ #else /* WIN32 */ #include #include +#include #endif /* WIN32 */ #ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H @@ -203,6 +204,7 @@ /* XXX */ FILE *pcap_file(pcap_t *); int pcap_fileno(pcap_t *); +int pcap_get_last_sockaddr (pcap_t *p, struct sockaddr *in); pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); int pcap_dump_flush(pcap_dumper_t *);