Date: Sun, 02 Dec 2012 04:48:18 +0400 From: "Alexander V. Chernikov" <melifaro@FreeBSD.org> To: Hiroki Sato <hrs@FreeBSD.org> Cc: freebsd-ipfw@FreeBSD.org, Gleb Smirnoff <glebius@FreeBSD.org>, delphij@freebsd.org, "freebsd-net@freebsd.org" <freebsd-net@FreeBSD.org> Subject: [CFT] Virtual BPF interfaces (was: CFR: ipfw0 pseudo-interface clonable) Message-ID: <50BAA552.1010707@FreeBSD.org> In-Reply-To: <4FD4AD29.3040204@FreeBSD.org> References: <4F96D11B.2060007@FreeBSD.org> <20120425.020518.406495893112283552.hrs@allbsd.org> <4F96E71B.9020405@FreeBSD.org> <20120427.084414.1142593201575277510.hrs@allbsd.org> <4FD4AD29.3040204@FreeBSD.org>
next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format. --------------080701070400070005040601 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit On 10.06.2012 18:20, Alexander V. Chernikov wrote: > On 27.04.2012 03:44, Hiroki Sato wrote: >> "Alexander V. Chernikov"<melifaro@FreeBSD.org> wrote >> in<4F96E71B.9020405@FreeBSD.org>: >> >> me> On 24.04.2012 21:05, Hiroki Sato wrote: > > Proof-of-concept patch attached. Hopefully, libcap code is easily extendable. New version attached: * BPF code is now able to use 'virtual' interfaces without real ifnet * New bpfattach3() / bpfdetach3() routines were added to attach virtual ifaces * New BIOCGIFLIST ioctl is added to permit userland to retrieve available virtual interfaces * freebsd-specific 'platform_finddevs' version is added to libpcap code (new file) There are some rough edges (conditional code in pcap-bpf.c, lack of documentation, maybe some style issues), but generally it seems to work and does not interfere with contrib/ code much (from my point of view). ipfw log device was converted to use new bpf(4) api, see attached patch. Small example: 4:17 [0] zfscurr0# tcpdump -D 1.em0 2.em1 3.lo0 4:17 [0] zfscurr0# kldload ipfw 4:17 [0] zfscurr0# ifconfig -l em0 em1 lo0 4:17 [0] zfscurr0# tcpdump -D 1.em0 2.ipfw0 (ipfw log interface) 3.em1 4.lo0 4:40 [1] zfscurr0# ipfw add 100 count log logamount 0 ip from any to any 00100 count log ip from any to any 4:40 [0] zfscurr0# tcpdump -i ipfw0 -lns0 tcpdump: WARNING: SIOCGIFADDR: ipfw0: Device not configured tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on ipfw0, link-type EN10MB (Ethernet), capture size 65535 bytes 04:41:27.233653 IP 10.0.0.92.22 > 10.0.0.5.59076: Flags [P.], seq 2783103749:2783103941, ack 3836123088, win 1040, options [nop,nop,TS val 1668094903 ecr 564715671], length 192 04:41:27.233678 IP 10.0.0.5.59076 > 10.0.0.92.22: Flags [.], ack 0, win 1039, options [nop,nop,TS val 564715680 ecr 1668094903], length 0 Btw, do we still need warning about lack of IPv4 address? > > Unfortunately, there are problems with this approach, too. > > pcap_findalldevs() uses external to BPF method (possibly NET_RT_IFLIST), > so programs relying on that function for showing some kind of combo-box > (like wireshark) with all possible variant won't allow user to specify > such interface. > > Additionally, tcpdump assumes that passed interface name is real and > warns us that SIOCGIFADDR returns error. > > >> >> -- Hiroki > --------------080701070400070005040601 Content-Type: text/plain; name="bpf_virtual.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="bpf_virtual.diff" Index: lib/libpcap/Makefile =================================================================== --- lib/libpcap/Makefile (revision 243778) +++ lib/libpcap/Makefile (working copy) @@ -6,7 +6,7 @@ SHLIBDIR?= /lib .include <bsd.own.mk> LIB= pcap -SRCS= grammar.y tokdefs.h version.h pcap-bpf.c \ +SRCS= grammar.y tokdefs.h version.h pcap-bpf.c pcap-freebsd.c \ pcap.c pcap-common.c inet.c fad-getad.c gencode.c optimize.c nametoaddr.c \ etherent.c savefile.c bpf_filter.c bpf_image.c bpf_dump.c \ scanner.l sf-pcap.c sf-pcap-ng.c version.c Index: sys/net/bpf.c =================================================================== --- sys/net/bpf.c (revision 243778) +++ sys/net/bpf.c (working copy) @@ -151,6 +151,7 @@ static void bpf_detachd_locked(struct bpf_d *); static void bpf_freed(struct bpf_d *); static int bpf_movein(struct uio *, int, struct ifnet *, struct mbuf **, struct sockaddr *, int *, struct bpf_insn *); +static int bpf_getiflist(struct bpf_d *, struct bpf_iflist *); static int bpf_setif(struct bpf_d *, struct ifreq *); static void bpf_timed_out(void *); static __inline void @@ -654,7 +655,7 @@ bpf_attachd(struct bpf_d *d, struct bpf_if *bp) CTR3(KTR_NET, "%s: bpf_attach called by pid %d, adding to %s list", __func__, d->bd_pid, d->bd_writer ? "writer" : "active"); - if (op_w == 0) + if ((op_w == 0) && (!BPF_IS_VIRTUAL(bp))) EVENTHANDLER_INVOKE(bpf_track, bp->bif_ifp, bp->bif_dlt, 1); } @@ -696,7 +697,8 @@ bpf_upgraded(struct bpf_d *d) CTR2(KTR_NET, "%s: upgrade required by pid %d", __func__, d->bd_pid); - EVENTHANDLER_INVOKE(bpf_track, bp->bif_ifp, bp->bif_dlt, 1); + if (!BPF_IS_VIRTUAL(bp)) + EVENTHANDLER_INVOKE(bpf_track, bp->bif_ifp, bp->bif_dlt, 1); } /* @@ -743,6 +745,10 @@ bpf_detachd_locked(struct bpf_d *d) bpf_bpfd_cnt--; + /* Nothing to do for fake interfaces */ + if (BPF_IS_VIRTUAL(bp)) + return; + /* Call event handler iff d is attached */ if (error == 0) EVENTHANDLER_INVOKE(bpf_track, ifp, bp->bif_dlt, 0); @@ -1037,7 +1043,11 @@ bpfwrite(struct cdev *dev, struct uio *uio, int io return (ENXIO); } - ifp = d->bd_bif->bif_ifp; + /* XXX: Writing to fake interfaces is not supported */ + if ((ifp = d->bd_bif->bif_ifp) == NULL) { + d->bd_wdcount++; + return (ENXIO); + } if ((ifp->if_flags & IFF_UP) == 0) { d->bd_wdcount++; @@ -1266,10 +1276,17 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t add { struct ifnet *ifp; - if (d->bd_bif == NULL) + /* + * Lock d since other thread can do reatach in + * other thread causing d->bd_bif to be set to NULL + */ + BPFD_LOCK(d); + if ((d->bd_bif == NULL) || (BPF_IS_VIRTUAL(d->bd_bif))) { error = EINVAL; - else { + BPFD_UNLOCK(d); + } else { ifp = d->bd_bif->bif_ifp; + BPFD_UNLOCK(d); error = (*ifp->if_ioctl)(ifp, cmd, addr); } break; @@ -1325,6 +1342,13 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t add error = EINVAL; break; } + + if (BPF_IS_VIRTUAL(d->bd_bif)) { + /* Silently ignore fake interfaces */ + error = 0; + break; + } + if (d->bd_promisc == 0) { error = ifpromisc(d->bd_bif->bif_ifp, 1); if (error == 0) @@ -1390,6 +1414,12 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t add BPF_UNLOCK(); break; + case BIOCGIFLIST: + BPF_LOCK(); + error = bpf_getiflist(d, (struct bpf_iflist *)addr); + BPF_UNLOCK(); + break; + /* * Get interface name. */ @@ -1401,7 +1431,8 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t add struct ifnet *const ifp = d->bd_bif->bif_ifp; struct ifreq *const ifr = (struct ifreq *)addr; - strlcpy(ifr->ifr_name, ifp->if_xname, + strlcpy(ifr->ifr_name, BPF_IS_VIRTUAL(d->bd_bif) ? + d->bd_bif->ifname : ifp->if_xname, sizeof(ifr->ifr_name)); } BPF_UNLOCK(); @@ -1701,6 +1732,7 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t add break; } CURVNET_RESTORE(); + return (error); } @@ -1834,6 +1866,55 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp, } /* + * Get a list of available virtual interfaces + */ +static int +bpf_getiflist(struct bpf_d *d, struct bpf_iflist *ifl) +{ + int len, tot_len, error; + struct bpf_if *bp; + struct bpf_ifreply ifr; + char *buffer; + + BPF_LOCK_ASSERT(); + + tot_len = 0; + error = 0; + buffer = ifl->ifl_list; + LIST_FOREACH(bp, &bpf_iflist, bif_next) { + if (!BPF_IS_VIRTUAL(bp)) + continue; + + /* Count total length */ + len = offsetof(struct bpf_ifreply, ifr_descr) + + strlen(bp->ifdescr) + 1; + /* Align on 4-byte boundary */ + len = roundup2(len, 4); + + if (buffer != NULL) { + if (tot_len + len >= ifl->ifl_len) + return (ENOMEM); + + /* Fill in interface record */ + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_len = len; + strlcpy(ifr.ifr_name, bp->ifname, IFNAMSIZ + 1); + + copyout(&ifr, buffer, sizeof(ifr)); + /* Write interface description */ + error = copyout(bp->ifdescr, + buffer + offsetof(struct bpf_ifreply, ifr_descr), + strlen(bp->ifdescr) + 1); + + buffer += len; + } + tot_len += len; + } + ifl->ifl_len = tot_len; + return (error); +} + +/* * Detach a file from its current interface (if attached at all) and attach * to the interface indicated by the name stored in ifr. * Return an errno or 0. @@ -1847,10 +1928,19 @@ bpf_setif(struct bpf_d *d, struct ifreq *ifr) BPF_LOCK_ASSERT(); theywant = ifunit(ifr->ifr_name); - if (theywant == NULL || theywant->if_bpf == NULL) - return (ENXIO); + if (theywant == NULL || theywant->if_bpf == NULL) { + /* Check for fake interface existance */ + LIST_FOREACH(bp, &bpf_iflist, bif_next) { + if (!BPF_IS_VIRTUAL(bp)) + continue; + if (!strcmp(bp->ifname, ifr->ifr_name)) + break; + } - bp = theywant->if_bpf; + if (bp == NULL) + return (ENXIO); + } else + bp = theywant->if_bpf; /* Check if interface is not being detached from BPF */ BPFIF_RLOCK(bp); @@ -2075,7 +2165,8 @@ bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktl if (gottime < bpf_ts_quality(d->bd_tstamp)) gottime = bpf_gettime(&bt, d->bd_tstamp, NULL); #ifdef MAC - if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) + if (BPF_IS_VIRTUAL(bp) || + (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0)) #endif catchpacket(d, pkt, pktlen, slen, bpf_append_bytes, &bt); @@ -2085,6 +2176,7 @@ bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktl BPFIF_RUNLOCK(bp); } +/* Note i CAN be NULL */ #define BPF_CHECK_DIRECTION(d, r, i) \ (((d)->bd_direction == BPF_D_IN && (r) != (i)) || \ ((d)->bd_direction == BPF_D_OUT && (r) == (i))) @@ -2134,7 +2226,8 @@ bpf_mtap(struct bpf_if *bp, struct mbuf *m) if (gottime < bpf_ts_quality(d->bd_tstamp)) gottime = bpf_gettime(&bt, d->bd_tstamp, m); #ifdef MAC - if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) + if ((BPF_IS_VIRTUAL(bp)) || + (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0)) #endif catchpacket(d, (u_char *)m, pktlen, slen, bpf_append_mbuf, &bt); @@ -2190,7 +2283,8 @@ bpf_mtap2(struct bpf_if *bp, void *data, u_int dle if (gottime < bpf_ts_quality(d->bd_tstamp)) gottime = bpf_gettime(&bt, d->bd_tstamp, m); #ifdef MAC - if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) + if ((BPF_IS_VIRTUAL(bp)) || + (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0)) #endif catchpacket(d, (u_char *)&mb, pktlen, slen, bpf_append_mbuf, &bt); @@ -2484,6 +2578,45 @@ bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdr } /* + * Attach fake interface to bpf. ifname is interface name to be attached, + * dlt is the link layer type, and hdrlen is the fixed size of the link header + * (variable length headers are not yet supporrted). + */ +void +bpfattach3(char *ifname, char *ifdescr, u_int dlt, u_int hdrlen, struct bpf_if **driverp) +{ + struct bpf_if *bp; + int len; + + len = strlen(ifdescr) + 1; + + /* Assume bpf_if to be properly aligned */ + bp = malloc(sizeof(*bp) + len, M_BPF, M_NOWAIT | M_ZERO); + if (bp == NULL) + panic("bpfattach"); + + LIST_INIT(&bp->bif_dlist); + LIST_INIT(&bp->bif_wlist); + strlcpy(bp->ifname, ifname, IFNAMSIZ + 1); + bp->ifdescr = (char *)(bp + 1); + strlcpy(bp->ifdescr, ifdescr, len); + bp->bif_dlt = dlt; + rw_init(&bp->bif_lock, "bpf interface lock"); + KASSERT(*driverp == NULL, ("bpfattach3: driverp already initialized")); + *driverp = bp; + + BPF_LOCK(); + LIST_INSERT_HEAD(&bpf_iflist, bp, bif_next); + BPF_UNLOCK(); + + bp->bif_hdrlen = hdrlen; + + if (bootverbose) + printf("%s: bpf attached\n", bp->ifname); +} + + +/* * Detach bpf from an interface. This involves detaching each descriptor * associated with the interface. Notify each descriptor as it's detached * so that any sleepers wake up and get ENXIO. @@ -2546,6 +2679,54 @@ bpfdetach(struct ifnet *ifp) } /* + * Detach bpf from the fake interface. This involves detaching each descriptor + * associated with the interface. Notify each descriptor as it's detached + * so that any sleepers wake up and get ENXIO. + */ +void +bpfdetach3(char *ifname) +{ + struct bpf_if *bp; + struct bpf_d *d; + + BPF_LOCK(); + /* Find all bpf_if struct's which reference ifp and detach them. */ + LIST_FOREACH(bp, &bpf_iflist, bif_next) { + if (!BPF_IS_VIRTUAL(bp)) + continue; + if (!strcmp(bp->ifname, ifname)) + break; + } + + if (bp != NULL) + LIST_REMOVE(bp, bif_next); + + BPF_UNLOCK(); + + if (bp != NULL) { + while ((d = LIST_FIRST(&bp->bif_dlist)) != NULL) { + bpf_detachd_locked(d); + BPFD_LOCK(d); + bpf_wakeup(d); + BPFD_UNLOCK(d); + } + /* Free writer-only descriptors */ + while ((d = LIST_FIRST(&bp->bif_wlist)) != NULL) { + bpf_detachd_locked(d); + BPFD_LOCK(d); + bpf_wakeup(d); + BPFD_UNLOCK(d); + } + + /* + * Since this interface is fake we can free our + * structure immediately. + */ + rw_destroy(&bp->bif_lock); + free(bp, M_BPF); + } +} +/* * Interface departure handler. * Note departure event does not guarantee interface is going down. */ @@ -2594,6 +2775,9 @@ bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist LIST_FOREACH(bp, &bpf_iflist, bif_next) { if (bp->bif_ifp != ifp) continue; + /* Compare fake interfaces by name */ + if ((ifp == NULL) && (strcmp(d->bd_bif->ifname, bp->ifname))) + continue; if (bfl->bfl_list != NULL) { if (n >= bfl->bfl_len) return (ENOMEM); @@ -2623,7 +2807,13 @@ bpf_setdlt(struct bpf_d *d, u_int dlt) ifp = d->bd_bif->bif_ifp; LIST_FOREACH(bp, &bpf_iflist, bif_next) { - if (bp->bif_ifp == ifp && bp->bif_dlt == dlt) + if (bp->bif_ifp != ifp) + continue; + + if ((ifp == NULL) && strcmp(d->bd_bif->ifname, bp->ifname)) + continue; + + if (bp->bif_dlt == dlt) break; } @@ -2718,8 +2908,10 @@ bpfstats_fill_xbpf(struct xbpf_d *d, struct bpf_d d->bd_hlen = bd->bd_hlen; d->bd_bufsize = bd->bd_bufsize; d->bd_pid = bd->bd_pid; - strlcpy(d->bd_ifname, - bd->bd_bif->bif_ifp->if_xname, IFNAMSIZ); + if (!BPF_IS_VIRTUAL(bd->bd_bif)) + strlcpy(d->bd_ifname, bd->bd_bif->bif_ifp->if_xname, IFNAMSIZ); + else + strlcpy(d->bd_ifname, bd->bd_bif->ifname, IFNAMSIZ); d->bd_locked = bd->bd_locked; d->bd_wcount = bd->bd_wcount; d->bd_wdcount = bd->bd_wdcount; Index: sys/net/bpf.h =================================================================== --- sys/net/bpf.h (revision 243778) +++ sys/net/bpf.h (working copy) @@ -147,6 +147,7 @@ struct bpf_zbuf { #define BIOCSETFNR _IOW('B', 130, struct bpf_program) #define BIOCGTSTAMP _IOR('B', 131, u_int) #define BIOCSTSTAMP _IOW('B', 132, u_int) +#define BIOCGIFLIST _IOWR('B', 133, struct bpf_iflist) /* Obsolete */ #define BIOCGSEESENT BIOCGDIRECTION @@ -1224,6 +1225,25 @@ struct bpf_dltlist { u_int *bfl_list; /* array of DLTs */ }; +#define BIFNAMSIZ 16 +#if !defined(_KERNEL) || defined(BPF_INTERNAL) +/* + * Structure to retrieve virtual BPF intefaces. + */ +struct bpf_iflist { + u_int ifl_len; /* total memory size */ + u_int ifl_ver; /* version (set to 0) */ + char *ifl_list; /* array of interfaces */ +}; + +struct bpf_ifreply { + u_int ifr_len; /* Total record length */ + u_int ifr_spare[3]; /* Spare data */ + char ifr_name[BIFNAMSIZ + 1]; /* Interface name */ + char ifr_descr[0]; /* Interface description (variable) */ +}; +#endif + #ifdef _KERNEL #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_BPF); @@ -1262,6 +1282,8 @@ struct bpf_if { struct rwlock bif_lock; /* interface lock */ LIST_HEAD(, bpf_d) bif_wlist; /* writer-only list */ int flags; /* Interface flags */ + char ifname[IFNAMSIZ + 1]; /* Virtual interface name */ + char *ifdescr; /* Virtual interface description */ #endif }; @@ -1272,7 +1294,9 @@ void bpf_mtap(struct bpf_if *, struct mbuf *); void bpf_mtap2(struct bpf_if *, void *, u_int, struct mbuf *); void bpfattach(struct ifnet *, u_int, u_int); void bpfattach2(struct ifnet *, u_int, u_int, struct bpf_if **); +void bpfattach3(char *, char *, u_int, u_int, struct bpf_if **); void bpfdetach(struct ifnet *); +void bpfdetach3(char *); void bpfilterattach(int); u_int bpf_filter(const struct bpf_insn *, u_char *, u_int, u_int); Index: sys/net/bpfdesc.h =================================================================== --- sys/net/bpfdesc.h (revision 243778) +++ sys/net/bpfdesc.h (working copy) @@ -102,6 +102,8 @@ struct bpf_d { u_char bd_compat32; /* 32-bit stream on LP64 system */ }; +#define BPF_IS_VIRTUAL(x) ((x)->bif_ifp == NULL) + /* Values for bd_state */ #define BPF_IDLE 0 /* no select in progress */ #define BPF_WAITING 1 /* waiting for read timeout in select */ Index: sys/netpfil/ipfw/ip_fw_log.c =================================================================== --- sys/netpfil/ipfw/ip_fw_log.c (revision 243778) +++ sys/netpfil/ipfw/ip_fw_log.c (working copy) @@ -93,142 +93,31 @@ ipfw_log_bpf(int onoff) { } #else /* !WITHOUT_BPF */ -static struct ifnet *log_if; /* hook to attach to bpf */ -static struct rwlock log_if_lock; -#define LOGIF_LOCK_INIT(x) rw_init(&log_if_lock, "ipfw log_if lock") -#define LOGIF_LOCK_DESTROY(x) rw_destroy(&log_if_lock) -#define LOGIF_RLOCK(x) rw_rlock(&log_if_lock) -#define LOGIF_RUNLOCK(x) rw_runlock(&log_if_lock) -#define LOGIF_WLOCK(x) rw_wlock(&log_if_lock) -#define LOGIF_WUNLOCK(x) rw_wunlock(&log_if_lock) +static struct bpf_if *log_bpfif = NULL; /* hook to attach to bpf */ +#define BPF_IFNAME "ipfw0" +#define IPFW_MTAP(_if_bpf,_data,_dlen,_m) do { \ + if (bpf_peers_present(_if_bpf)) { \ + M_ASSERTVALID(_m); \ + bpf_mtap2((_if_bpf),(_data),(_dlen),(_m)); \ + } \ +} while (0) -static const char ipfwname[] = "ipfw"; - -/* we use this dummy function for all ifnet callbacks */ -static int -log_dummy(struct ifnet *ifp, u_long cmd, caddr_t addr) -{ - return EINVAL; -} - -static int -ipfw_log_output(struct ifnet *ifp, struct mbuf *m, - struct sockaddr *dst, struct route *ro) -{ - if (m != NULL) - FREE_PKT(m); - return EINVAL; -} - -static void -ipfw_log_start(struct ifnet* ifp) -{ - panic("ipfw_log_start() must not be called"); -} - static const u_char ipfwbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -static int -ipfw_log_clone_match(struct if_clone *ifc, const char *name) -{ - - return (strncmp(name, ipfwname, sizeof(ipfwname) - 1) == 0); -} - -static int -ipfw_log_clone_create(struct if_clone *ifc, char *name, size_t len, - caddr_t params) -{ - int error; - int unit; - struct ifnet *ifp; - - error = ifc_name2unit(name, &unit); - if (error) - return (error); - - error = ifc_alloc_unit(ifc, &unit); - if (error) - return (error); - - ifp = if_alloc(IFT_PFLOG); - if (ifp == NULL) { - ifc_free_unit(ifc, unit); - return (ENOSPC); - } - ifp->if_dname = ipfwname; - ifp->if_dunit = unit; - snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", ipfwname, unit); - strlcpy(name, ifp->if_xname, len); - ifp->if_mtu = 65536; - ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_init = (void *)log_dummy; - ifp->if_ioctl = log_dummy; - ifp->if_start = ipfw_log_start; - ifp->if_output = ipfw_log_output; - ifp->if_addrlen = 6; - ifp->if_hdrlen = 14; - ifp->if_broadcastaddr = ipfwbroadcastaddr; - ifp->if_baudrate = IF_Mbps(10); - - LOGIF_WLOCK(); - if (log_if == NULL) - log_if = ifp; - else { - LOGIF_WUNLOCK(); - if_free(ifp); - ifc_free_unit(ifc, unit); - return (EEXIST); - } - LOGIF_WUNLOCK(); - if_attach(ifp); - bpfattach(ifp, DLT_EN10MB, 14); - - return (0); -} - -static int -ipfw_log_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) -{ - int unit; - - if (ifp == NULL) - return (0); - - LOGIF_WLOCK(); - if (log_if != NULL && ifp == log_if) - log_if = NULL; - else { - LOGIF_WUNLOCK(); - return (EINVAL); - } - LOGIF_WUNLOCK(); - - unit = ifp->if_dunit; - bpfdetach(ifp); - if_detach(ifp); - if_free(ifp); - ifc_free_unit(ifc, unit); - - return (0); -} - -static struct if_clone *ipfw_log_cloner; - void ipfw_log_bpf(int onoff) { - if (onoff) { - LOGIF_LOCK_INIT(); - ipfw_log_cloner = if_clone_advanced(ipfwname, 0, - ipfw_log_clone_match, ipfw_log_clone_create, - ipfw_log_clone_destroy); - } else { - if_clone_detach(ipfw_log_cloner); - LOGIF_LOCK_DESTROY(); - } + if (onoff) { + if (log_bpfif) + return; + bpfattach3(BPF_IFNAME, "ipfw log interface", DLT_EN10MB, 14, &log_bpfif); + } else { + if (log_bpfif != NULL) + bpfdetach3(BPF_IFNAME); + log_bpfif = NULL; + } } #endif /* !WITHOUT_BPF */ @@ -247,20 +136,18 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw if (V_fw_verbose == 0) { #ifndef WITHOUT_BPF - LOGIF_RLOCK(); - if (log_if == NULL || log_if->if_bpf == NULL) { - LOGIF_RUNLOCK(); + if (log_bpfif == NULL) return; - } if (args->eh) /* layer2, use orig hdr */ - BPF_MTAP2(log_if, args->eh, ETHER_HDR_LEN, m); + IPFW_MTAP(log_bpfif, args->eh, ETHER_HDR_LEN, m); else - /* Add fake header. Later we will store + /* + * Add fake header. Later we will store * more info in the header. */ - BPF_MTAP2(log_if, "DDDDDDSSSSSS\x08\x00", ETHER_HDR_LEN, m); - LOGIF_RUNLOCK(); + IPFW_MTAP(log_bpfif, "DDDDDDSSSSSS\x08\x00", + ETHER_HDR_LEN, m); #endif /* !WITHOUT_BPF */ return; } Index: contrib/libpcap/pcap-bpf.c =================================================================== --- contrib/libpcap/pcap-bpf.c (revision 243778) +++ contrib/libpcap/pcap-bpf.c (working copy) @@ -132,6 +132,8 @@ static int bpf_load(char *errbuf); #include "pcap-snf.h" #endif /* HAVE_SNF_API */ +#include "pcap-freebsd.h" + #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif @@ -2311,6 +2313,8 @@ pcap_platform_finddevs(pcap_if_t **alldevsp, char if (snf_platform_finddevs(alldevsp, errbuf) < 0) return (-1); #endif /* HAVE_SNF_API */ + if (freebsd_platform_finddevs(alldevsp, errbuf) < 0) + return (-1); return (0); } --- /dev/null 2012-12-02 04:22:01.000000000 +0400 +++ contrib/libpcap/pcap-freebsd.h 2012-12-02 02:50:44.251624161 +0400 @@ -0,0 +1 @@ +int freebsd_platform_finddevs(pcap_if_t **devlistp, char *errbuf); --- /dev/null 2012-12-02 04:22:01.000000000 +0400 +++ contrib/libpcap/pcap-freebsd.c 2012-12-02 04:22:11.404710869 +0400 @@ -0,0 +1,138 @@ +/* + * pcap-freebsd.c: Packet capture advanced interface to the FreeBSD kernel + * + * License: BSD + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <net/if.h> +#include <net/bpf.h> + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> + +#include "pcap-int.h" + +int +freebsd_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) +{ + int ret; + + struct bpf_iflist ifl; + struct bpf_ifreply *ifr; + char *device = "/dev/bpf"; + int fd, i, len, res; + caddr_t databuf; + + if ((fd = open(device, O_RDWR)) == -1) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "(cannot open device) %s: %s", + device, pcap_strerror(errno)); + + return (-1); + } + + res = 0; + + for (i = 0; i < 10; i++) { + /* Get size */ + memset(&ifl, 0, sizeof(ifl)); + + if (ioctl(fd, BIOCGIFLIST, (caddr_t)&ifl) != 0) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "(cannot get interface list length): %s", + pcap_strerror(errno)); + + close(fd); + return (-1); + } + + /* Allocate requested length */ + len = ifl.ifl_len + 1024; + databuf = calloc(1, len); + + /* Try to read data */ + ifl.ifl_list = databuf; + ifl.ifl_len = len; + + if (ioctl(fd, BIOCGIFLIST, (caddr_t)&ifl) != 0) { + if (errno == ENOMEM) { + /* + * Probably new interface added. + * Let's try another time. + */ + free(databuf); + databuf = NULL; + ifl.ifl_len = 0; + continue; + } + + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "(cannot read interface list): %s", + pcap_strerror(errno)); + + close(fd); + return (-1); + } + + res = 1; + break; + } + + close(fd); + + if (res == 0) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "(error reading interface list): retries exceeded"); + return (-1); + } + + /* Okay, let's parse */ + for (len = 0; len < ifl.ifl_len; ) { + ifr = (struct bpf_ifreply *)&databuf[len]; + + if (pcap_add_if(alldevsp, ifr->ifr_name, 0, + ifr->ifr_descr, errbuf) < 0) + return (-1); + + len += ifr->ifr_len; + } + + return (0); +} + --------------080701070400070005040601--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?50BAA552.1010707>