The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=ddf4f9eda9c295082f17e7f26963666b72c97bb9
commit ddf4f9eda9c295082f17e7f26963666b72c97bb9 Author: Gleb Smirnoff <[email protected]> AuthorDate: 2025-12-15 20:51:42 +0000 Commit: Gleb Smirnoff <[email protected]> CommitDate: 2025-12-15 21:17:23 +0000 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 --- libexec/rc/rc.conf | 1 - libexec/rc/rc.d/ipfw | 10 --- sbin/ipfw/ipfw.8 | 38 +++-------- sys/netpfil/ipfw/ip_fw_bpf.c | 146 ++++++++----------------------------------- 4 files changed, 35 insertions(+), 160 deletions(-) diff --git a/libexec/rc/rc.conf b/libexec/rc/rc.conf index ada9094360f6..e8f146807f33 100644 --- a/libexec/rc/rc.conf +++ b/libexec/rc/rc.conf @@ -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 diff --git a/libexec/rc/rc.d/ipfw b/libexec/rc/rc.d/ipfw index 6d6f7577828f..a9b05ee11132 100755 --- a/libexec/rc/rc.d/ipfw +++ b/libexec/rc/rc.d/ipfw @@ -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() diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index 249bd195b4de..789512e5cc1e 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -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 diff --git a/sys/netpfil/ipfw/ip_fw_bpf.c b/sys/netpfil/ipfw/ip_fw_bpf.c index 155e269214ec..68f31ca59b2e 100644 --- a/sys/netpfil/ipfw/ip_fw_bpf.c +++ b/sys/netpfil/ipfw/ip_fw_bpf.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2016 Yandex LLC * Copyright (c) 2016 Andrey V. Elsukov <[email protected]> + * Copyright (c) 2025 Gleb Smirnoff <[email protected]> * * 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) -{ - - return (EINVAL); -} - -static int -ipfw_bpf_output(struct ifnet *ifp, struct mbuf *m, - const struct sockaddr *dst, struct route *ro) +static bool +bpf_ipfw_chkdir(void *arg __unused, const struct mbuf *m, int dir) { - - if (m != NULL) - FREE_PKT(m); - return (0); + return ((dir == BPF_D_IN && m_rcvif(m) == NULL) || + (dir == BPF_D_OUT && m_rcvif(m) != NULL)); } -static void -ipfw_clone_destroy(struct ifnet *ifp) -{ - - if (ifp->if_hdrlen == ETHER_HDR_LEN) - V_log_if = NULL; - else - V_pflog_if = NULL; +static const struct bif_methods bpf_ipfw_methods = { + .bif_chkdir = bpf_ipfw_chkdir, +}; - NET_EPOCH_WAIT(); - bpfdetach(ifp); - if_detach(ifp); - if_free(ifp); -} +static const char ipfwname[] = "ipfw0"; +static const char ipfwlogname[] = "ipfwlog0"; -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); }
