Make ipfw0 logging pseudo-interface clonable. It can be created automatically

by $firewall_logif rc.conf(5) variable at boot time or manually by ifconfig(8)
after a boot.

Discussed on:	freebsd-ipfw@
This commit is contained in:
Hiroki Sato 2012-07-09 07:16:19 +00:00
parent ba7de9be0d
commit 8efbd296e0
5 changed files with 143 additions and 30 deletions

View File

@ -123,6 +123,7 @@ 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

View File

@ -57,6 +57,10 @@ ipfw_start()
echo 'Firewall logging enabled.'
sysctl net.inet.ip.fw.verbose=1 >/dev/null
fi
if checkyesno firewall_logif; then
ifconfig ipfw0 create
echo 'Firewall logging pseudo-interface (ipfw0) created.'
fi
}
ipfw_poststart()

View File

@ -1,7 +1,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd July 3, 2012
.Dd July 9, 2012
.Dt IPFW 8
.Os
.Sh NAME
@ -560,7 +560,22 @@ is set to 0 (default), one can use
.Xr bpf 4
attached to the
.Li ipfw0
pseudo interface. There is no overhead if no
pseudo interface.
This pseudo interface can be created after a boot
manually 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
There is no overhead if no
.Xr bpf 4
is attached to the pseudo interface.
.Pp

View File

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd May 6, 2012
.Dd July 9, 2012
.Dt RC.CONF 5
.Os
.Sh NAME
@ -501,6 +501,16 @@ to enable firewall event logging.
This is equivalent to the
.Dv IPFIREWALL_VERBOSE
kernel option.
.It Va firewall_logif
.Pq Vt bool
Set to
.Dq Li YES
to create pseudo interface
.Li ipfw0
for logging.
For more details, see
.Xr ipfw 8
manual page.
.It Va firewall_flags
.Pq Vt str
Flags passed to

View File

@ -44,8 +44,11 @@ __FBSDID("$FreeBSD$");
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
#include <sys/lock.h>
#include <sys/rwlock.h>
#include <net/ethernet.h> /* for ETHERTYPE_IP */
#include <net/if.h>
#include <net/if_clone.h>
#include <net/vnet.h>
#include <net/if_types.h> /* for IFT_ETHER */
#include <net/bpf.h> /* for BPF */
@ -90,6 +93,15 @@ 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)
#define IPFWNAME "ipfw"
/* we use this dummy function for all ifnet callbacks */
static int
@ -116,18 +128,38 @@ ipfw_log_start(struct ifnet* ifp)
static const u_char ipfwbroadcastaddr[6] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
void
ipfw_log_bpf(int onoff)
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;
if (onoff) {
if (log_if)
return;
error = ifc_name2unit(name, &unit);
if (error)
return (error);
error = ifc_alloc_unit(ifc, &unit);
if (error)
return (error);
ifp = if_alloc(IFT_ETHER);
if (ifp == NULL)
return;
if_initname(ifp, "ipfw", 0);
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;
@ -136,17 +168,65 @@ ipfw_log_bpf(int onoff)
ifp->if_output = ipfw_log_output;
ifp->if_addrlen = 6;
ifp->if_hdrlen = 14;
if_attach(ifp);
ifp->if_broadcastaddr = ipfwbroadcastaddr;
ifp->if_baudrate = IF_Mbps(10);
bpfattach(ifp, DLT_EN10MB, 14);
LOGIF_WLOCK();
if (log_if == NULL)
log_if = ifp;
} else {
if (log_if) {
ether_ifdetach(log_if);
if_free(log_if);
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 = IFC_CLONE_INITIALIZER(
IPFWNAME, NULL, IF_MAXUNIT,
NULL, ipfw_log_clone_match, ipfw_log_clone_create, ipfw_log_clone_destroy);
void
ipfw_log_bpf(int onoff)
{
if (onoff) {
LOGIF_LOCK_INIT();
if_clone_attach(&ipfw_log_cloner);
} else {
if_clone_detach(&ipfw_log_cloner);
LOGIF_LOCK_DESTROY();
}
}
#endif /* !WITHOUT_BPF */
@ -166,9 +246,11 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
if (V_fw_verbose == 0) {
#ifndef WITHOUT_BPF
if (log_if == NULL || log_if->if_bpf == NULL)
LOGIF_RLOCK();
if (log_if == NULL || log_if->if_bpf == NULL) {
LOGIF_RUNLOCK();
return;
}
if (args->eh) /* layer2, use orig hdr */
BPF_MTAP2(log_if, args->eh, ETHER_HDR_LEN, m);
@ -177,6 +259,7 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
* more info in the header.
*/
BPF_MTAP2(log_if, "DDDDDDSSSSSS\x08\x00", ETHER_HDR_LEN, m);
LOGIF_RUNLOCK();
#endif /* !WITHOUT_BPF */
return;
}