On 10.06.2012 18:20, Alexander V. Chernikov wrote:
On 27.04.2012 03:44, Hiroki Sato wrote:
"Alexander V. Chernikov"<melif...@freebsd.org> wrote
in<4f96e71b.9020...@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
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);
+}
+
_______________________________________________
freebsd-ipfw@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-ipfw
To unsubscribe, send any mail to "freebsd-ipfw-unsubscr...@freebsd.org"