mirror of
https://git.freebsd.org/src.git
synced 2026-01-11 19:57:22 +00:00
ipfw: create "ipfw0" and "ipfwlog0" bpf tapping points without ifnet(9)
As a free bonus the tapping points are now able to match packet direction. Reviewed by: ae Differential Revision: https://reviews.freebsd.org/D53875
This commit is contained in:
parent
94b76ea9d1
commit
ddf4f9eda9
4 changed files with 35 additions and 160 deletions
|
|
@ -157,7 +157,6 @@ firewall_script="/etc/rc.firewall" # Which script to run to set up the firewall
|
|||
firewall_type="UNKNOWN" # Firewall type (see /etc/rc.firewall)
|
||||
firewall_quiet="NO" # Set to YES to suppress rule display
|
||||
firewall_logging="NO" # Set to YES to enable events logging
|
||||
firewall_logif="NO" # Set to YES to create logging-pseudo interface
|
||||
firewall_flags="" # Flags passed to ipfw when type is a file
|
||||
firewall_coscripts="" # List of executables/scripts to run after
|
||||
# firewall starts/stops
|
||||
|
|
|
|||
|
|
@ -85,16 +85,6 @@ ipfw_start()
|
|||
echo 'Firewall logging enabled.'
|
||||
${SYSCTL} net.inet.ip.fw.verbose=1 >/dev/null
|
||||
fi
|
||||
if checkyesno firewall_logif; then
|
||||
if ! ifconfig ipfw0 >/dev/null 2>&1; then
|
||||
ifconfig ipfw0 create
|
||||
echo 'Firewall logging pseudo-interface (ipfw0)' \
|
||||
'created.'
|
||||
else
|
||||
echo 'Firewall logging pseudo-interface (ipfw0)' \
|
||||
'already created.'
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
ipfw_poststart()
|
||||
|
|
|
|||
|
|
@ -701,28 +701,13 @@ Unless per-rule log destination is specified by
|
|||
.Cm logdst Ar logdst_spec
|
||||
option (see below), packets are logged in two ways: if the sysctl variable
|
||||
.Va net.inet.ip.fw.verbose
|
||||
is set to 0 (default), one can use
|
||||
is set to 0 (default), one can use the
|
||||
.Xr bpf 4
|
||||
attached to the
|
||||
.Li ipfw0
|
||||
pseudo interface.
|
||||
This pseudo interface can be created manually after a system
|
||||
boot by using the following command:
|
||||
.Bd -literal -offset indent
|
||||
# ifconfig ipfw0 create
|
||||
.Ed
|
||||
.Pp
|
||||
Or, automatically at boot time by adding the following
|
||||
line to the
|
||||
.Xr rc.conf 5
|
||||
file:
|
||||
.Bd -literal -offset indent
|
||||
firewall_logif="YES"
|
||||
.Ed
|
||||
.Pp
|
||||
tap named
|
||||
.Li ipfw0 .
|
||||
There is zero overhead when no
|
||||
.Xr bpf 4
|
||||
is attached to the pseudo interface.
|
||||
listener is attached to the tap.
|
||||
.Pp
|
||||
If
|
||||
.Va net.inet.ip.fw.verbose
|
||||
|
|
@ -3676,16 +3661,11 @@ reply to the sent ICMP message.
|
|||
Default value is
|
||||
.Ar 60 .
|
||||
.It Cm log
|
||||
Turn on logging of all handled packets via BPF through
|
||||
.Ar ipfwlog0
|
||||
interface.
|
||||
.Ar ipfwlog0
|
||||
is a pseudo interface and can be created after a boot manually with
|
||||
.Cm ifconfig
|
||||
command.
|
||||
Turn on logging of all handled packets via BPF tap named
|
||||
.Ar ipfwlog0 .
|
||||
Note that it has different purpose than
|
||||
.Ar ipfw0
|
||||
interface.
|
||||
tap.
|
||||
Translators sends to BPF an additional information with each packet.
|
||||
With
|
||||
.Cm tcpdump
|
||||
|
|
@ -3744,7 +3724,7 @@ contains mapping how IPv6 addresses should be translated to IPv4 addresses.
|
|||
.It Cm log
|
||||
Turn on logging of all handled packets via BPF through
|
||||
.Ar ipfwlog0
|
||||
interface.
|
||||
tap.
|
||||
.It Cm -log
|
||||
Turn off logging of all handled packets via BPF.
|
||||
.It Cm allow_private
|
||||
|
|
@ -3793,7 +3773,7 @@ This IPv6 prefix should be configured on a remote NAT64 translator.
|
|||
.It Cm log
|
||||
Turn on logging of all handled packets via BPF through
|
||||
.Ar ipfwlog0
|
||||
interface.
|
||||
tap.
|
||||
.It Cm -log
|
||||
Turn off logging of all handled packets via BPF.
|
||||
.It Cm allow_private
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/*-
|
||||
* Copyright (c) 2016 Yandex LLC
|
||||
* Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
|
||||
* Copyright (c) 2025 Gleb Smirnoff <glebius@FreeBSD.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
|
@ -29,14 +30,11 @@
|
|||
#include <sys/mbuf.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/rwlock.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_pflog.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/if_clone.h>
|
||||
#include <net/if_private.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/vnet.h>
|
||||
#include <net/bpf.h>
|
||||
|
||||
|
|
@ -45,158 +43,66 @@
|
|||
#include <netinet/ip_var.h>
|
||||
#include <netpfil/ipfw/ip_fw_private.h>
|
||||
|
||||
VNET_DEFINE_STATIC(struct ifnet *, log_if);
|
||||
VNET_DEFINE_STATIC(struct ifnet *, pflog_if);
|
||||
VNET_DEFINE_STATIC(struct if_clone *, ipfw_cloner);
|
||||
VNET_DEFINE_STATIC(struct if_clone *, ipfwlog_cloner);
|
||||
#define V_ipfw_cloner VNET(ipfw_cloner)
|
||||
#define V_ipfwlog_cloner VNET(ipfwlog_cloner)
|
||||
#define V_log_if VNET(log_if)
|
||||
#define V_pflog_if VNET(pflog_if)
|
||||
|
||||
static const char ipfwname[] = "ipfw";
|
||||
static const char ipfwlogname[] = "ipfwlog";
|
||||
|
||||
static int
|
||||
ipfw_bpf_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
|
||||
static bool
|
||||
bpf_ipfw_chkdir(void *arg __unused, const struct mbuf *m, int dir)
|
||||
{
|
||||
|
||||
return (EINVAL);
|
||||
return ((dir == BPF_D_IN && m_rcvif(m) == NULL) ||
|
||||
(dir == BPF_D_OUT && m_rcvif(m) != NULL));
|
||||
}
|
||||
|
||||
static int
|
||||
ipfw_bpf_output(struct ifnet *ifp, struct mbuf *m,
|
||||
const struct sockaddr *dst, struct route *ro)
|
||||
{
|
||||
static const struct bif_methods bpf_ipfw_methods = {
|
||||
.bif_chkdir = bpf_ipfw_chkdir,
|
||||
};
|
||||
|
||||
if (m != NULL)
|
||||
FREE_PKT(m);
|
||||
return (0);
|
||||
}
|
||||
static const char ipfwname[] = "ipfw0";
|
||||
static const char ipfwlogname[] = "ipfwlog0";
|
||||
|
||||
static void
|
||||
ipfw_clone_destroy(struct ifnet *ifp)
|
||||
{
|
||||
|
||||
if (ifp->if_hdrlen == ETHER_HDR_LEN)
|
||||
V_log_if = NULL;
|
||||
else
|
||||
V_pflog_if = NULL;
|
||||
|
||||
NET_EPOCH_WAIT();
|
||||
bpfdetach(ifp);
|
||||
if_detach(ifp);
|
||||
if_free(ifp);
|
||||
}
|
||||
|
||||
static int
|
||||
ipfw_clone_create(struct if_clone *ifc, int unit, caddr_t params)
|
||||
{
|
||||
struct ifnet *ifp;
|
||||
|
||||
ifp = if_alloc(IFT_PFLOG);
|
||||
if_initname(ifp, ipfwname, unit);
|
||||
ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST;
|
||||
ifp->if_mtu = 65536;
|
||||
ifp->if_ioctl = ipfw_bpf_ioctl;
|
||||
ifp->if_output = ipfw_bpf_output;
|
||||
ifp->if_hdrlen = ETHER_HDR_LEN;
|
||||
if_attach(ifp);
|
||||
bpfattach(ifp, DLT_EN10MB, ETHER_HDR_LEN);
|
||||
if (V_log_if != NULL) {
|
||||
bpfdetach(ifp);
|
||||
if_detach(ifp);
|
||||
if_free(ifp);
|
||||
return (EEXIST);
|
||||
}
|
||||
V_log_if = ifp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ipfwlog_clone_create(struct if_clone *ifc, int unit, caddr_t params)
|
||||
{
|
||||
struct ifnet *ifp;
|
||||
|
||||
ifp = if_alloc(IFT_PFLOG);
|
||||
if_initname(ifp, ipfwlogname, unit);
|
||||
ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST;
|
||||
ifp->if_mtu = 65536;
|
||||
ifp->if_ioctl = ipfw_bpf_ioctl;
|
||||
ifp->if_output = ipfw_bpf_output;
|
||||
ifp->if_hdrlen = PFLOG_HDRLEN;
|
||||
if_attach(ifp);
|
||||
bpfattach(ifp, DLT_PFLOG, PFLOG_HDRLEN);
|
||||
if (V_pflog_if != NULL) {
|
||||
bpfdetach(ifp);
|
||||
if_detach(ifp);
|
||||
if_free(ifp);
|
||||
return (EEXIST);
|
||||
}
|
||||
V_pflog_if = ifp;
|
||||
return (0);
|
||||
}
|
||||
VNET_DEFINE_STATIC(struct bpf_if *, bpf_en10mb);
|
||||
VNET_DEFINE_STATIC(struct bpf_if *, bpf_pflog);
|
||||
#define V_bpf_en10mb VNET(bpf_en10mb)
|
||||
#define V_bpf_pflog VNET(bpf_pflog)
|
||||
|
||||
void
|
||||
ipfw_bpf_tap(u_char *pkt, u_int pktlen)
|
||||
{
|
||||
struct ifnet *ifp = V_log_if;
|
||||
|
||||
NET_EPOCH_ASSERT();
|
||||
if (ifp != NULL)
|
||||
BPF_TAP(ifp, pkt, pktlen);
|
||||
bpf_tap(V_bpf_en10mb, pkt, pktlen);
|
||||
}
|
||||
|
||||
void
|
||||
ipfw_bpf_mtap(struct mbuf *m)
|
||||
{
|
||||
struct ifnet *ifp = V_log_if;
|
||||
|
||||
NET_EPOCH_ASSERT();
|
||||
if (ifp != NULL)
|
||||
BPF_MTAP(ifp, m);
|
||||
bpf_mtap(V_bpf_en10mb, m);
|
||||
}
|
||||
|
||||
void
|
||||
ipfw_bpf_mtap2(void *data, u_int dlen, struct mbuf *m)
|
||||
{
|
||||
struct ifnet *logif;
|
||||
|
||||
NET_EPOCH_ASSERT();
|
||||
switch (dlen) {
|
||||
case (ETHER_HDR_LEN):
|
||||
logif = V_log_if;
|
||||
bpf_mtap2(V_bpf_en10mb, data, dlen, m);
|
||||
break;
|
||||
case (PFLOG_HDRLEN):
|
||||
logif = V_pflog_if;
|
||||
bpf_mtap2(V_bpf_pflog, data, dlen, m);
|
||||
break;
|
||||
default:
|
||||
#ifdef INVARIANTS
|
||||
panic("%s: unsupported len %d", __func__, dlen);
|
||||
#endif
|
||||
logif = NULL;
|
||||
MPASS(0);
|
||||
}
|
||||
|
||||
if (logif != NULL)
|
||||
BPF_MTAP2(logif, data, dlen, m);
|
||||
}
|
||||
|
||||
void
|
||||
ipfw_bpf_init(int first __unused)
|
||||
{
|
||||
|
||||
V_log_if = NULL;
|
||||
V_pflog_if = NULL;
|
||||
V_ipfw_cloner = if_clone_simple(ipfwname, ipfw_clone_create,
|
||||
ipfw_clone_destroy, 0);
|
||||
V_ipfwlog_cloner = if_clone_simple(ipfwlogname, ipfwlog_clone_create,
|
||||
ipfw_clone_destroy, 0);
|
||||
V_bpf_en10mb = bpf_attach(ipfwname, DLT_EN10MB, ETHER_HDR_LEN,
|
||||
&bpf_ipfw_methods, NULL);
|
||||
V_bpf_pflog = bpf_attach(ipfwlogname, DLT_PFLOG, PFLOG_HDRLEN,
|
||||
&bpf_ipfw_methods, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
ipfw_bpf_uninit(int last __unused)
|
||||
{
|
||||
|
||||
if_clone_detach(V_ipfw_cloner);
|
||||
if_clone_detach(V_ipfwlog_cloner);
|
||||
bpf_detach(V_bpf_en10mb);
|
||||
bpf_detach(V_bpf_pflog);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue