mirror of
https://git.FreeBSD.org/src.git
synced 2024-11-24 07:40:52 +00:00
Add dummymbuf module for testing purposes
Reviewed by: kp Differential Revision: https://reviews.freebsd.org/D45928
This commit is contained in:
parent
bd4f2023bb
commit
8aaffd78c0
@ -135,6 +135,7 @@ MAN= aac.4 \
|
||||
ds1307.4 \
|
||||
ds3231.4 \
|
||||
${_dtrace_provs} \
|
||||
dummymbuf.4 \
|
||||
dummynet.4 \
|
||||
edsc.4 \
|
||||
ehci.4 \
|
||||
|
209
share/man/man4/dummymbuf.4
Normal file
209
share/man/man4/dummymbuf.4
Normal file
@ -0,0 +1,209 @@
|
||||
.\"
|
||||
.\" SPDX-License-Identifier: BSD-2-Clause
|
||||
.\"
|
||||
.\" Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
.\"
|
||||
.\" Note: The date here should be updated whenever a non-trivial
|
||||
.\" change is made to the manual page.
|
||||
.Dd August 2, 2024
|
||||
.Dt DUMMYMBUF 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm dummymbuf
|
||||
.Nd "mbuf alteration pfil hooks"
|
||||
.Sh SYNOPSIS
|
||||
To compile the driver into the kernel,
|
||||
place the following line in the
|
||||
kernel configuration file:
|
||||
.Bd -ragged -offset indent
|
||||
.Cd "device dummymbuf"
|
||||
.Ed
|
||||
.Pp
|
||||
Alternatively, to load the driver as a
|
||||
module at boot time, place the following line in
|
||||
.Xr loader.conf 5 :
|
||||
.Bd -literal -offset indent
|
||||
dummymbuf_load="YES"
|
||||
.Ed
|
||||
.Sh DESCRIPTION
|
||||
This module is intended to test networking code in the face of unusual mbuf
|
||||
layouts.
|
||||
The special
|
||||
.Xr pfil 9
|
||||
hooks are provided for mbuf alteration and can be listed with
|
||||
.Xr pfilctl 8
|
||||
as follows:
|
||||
.Bd -literal -offset indent
|
||||
Hook Type
|
||||
dummymbuf:ethernet Ethernet
|
||||
dummymbuf:inet6 IPv6
|
||||
dummymbuf:inet IPv4
|
||||
.Ed
|
||||
.Pp
|
||||
To activate a hook it must be linked to the respective
|
||||
.Xr pfil 9
|
||||
head.
|
||||
.Xr pfilctl 8
|
||||
can be used for the linking.
|
||||
.Pp
|
||||
Each time a hook is invoked it reads a single shared set of
|
||||
.Sx RULES
|
||||
from
|
||||
.Va net.dummymbuf.rules
|
||||
sysctl.
|
||||
The rules are evaluated sequentially and each matching rule performs the
|
||||
specified operation over the mbuf.
|
||||
.Pp
|
||||
After every successfully applied operation the
|
||||
.Va net.dummymbuf.hits
|
||||
sysctl counter is increased.
|
||||
.Pp
|
||||
A hook returns an altered mbuf for further processing, but it drops a packet
|
||||
if rules parsing or an operation fails.
|
||||
Also, the first mbuf of the original chain may be changed.
|
||||
.Pp
|
||||
The module is
|
||||
.Xr VNET 9
|
||||
based, hence every
|
||||
.Xr jail 2
|
||||
provides its own set of hooks and sysctl variables.
|
||||
.Sh RULES
|
||||
The set of rules is a semicolon separated list.
|
||||
An empty string is treated as a parsing failure.
|
||||
A rule conceptually has two parts, filter and operation, with the following
|
||||
syntax:
|
||||
.Bd -literal -offset indent
|
||||
{inet | inet6 | ethernet} {in | out} <ifname> <opname>[ <opargs>];
|
||||
.Ed
|
||||
.Ss Filter
|
||||
The first word of a rule matches
|
||||
.Xr pfil 9
|
||||
type.
|
||||
The second matches packet's direction, and the third matches the network
|
||||
interface a packet is coming from.
|
||||
.Ss Operation
|
||||
An operation may have arguments separated from its name by space.
|
||||
The available operations are:
|
||||
.Bl -tag -width indent
|
||||
.It pull-head <number-of-bytes>
|
||||
Unconditionally creates a brand new cluster-based mbuf and links it to be the
|
||||
first mbuf of the original mbuf chain, with respective packet header moving.
|
||||
After, the given number of bytes are pulled from the original mbuf chain.
|
||||
.Pp
|
||||
If it is asked to pull 0 bytes then the first mbuf of the resulting chain will
|
||||
be left empty.
|
||||
Asking to pull more than
|
||||
.Dv MCLBYTES
|
||||
is treated as an operation failure.
|
||||
If a mbuf chain has less data than asked then the entire packet is pulled with
|
||||
tail mbuf(s) left empty.
|
||||
.Pp
|
||||
As a result, only the layout of a mbuf chain is altered, its content logically
|
||||
is left intact.
|
||||
.El
|
||||
.Sh SYSCTL VARIABLES
|
||||
The following variables are available:
|
||||
.Bl -tag -width indent
|
||||
.It Va net.dummymbuf.rules
|
||||
A string representing a single set of
|
||||
.Sx RULES
|
||||
shared among all
|
||||
.Nm
|
||||
hooks.
|
||||
.It Va net.dummymbuf.hits
|
||||
Number of times a rule has been applied.
|
||||
It is reset to zero upon writing.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
As it was intended,
|
||||
.Nm
|
||||
can be found useful for firewall testing.
|
||||
A mbuf chain could be altered before it hits a firewall to test that the latter
|
||||
can handle a case respectively.
|
||||
Thus, it is important to have correct sequence of hooks.
|
||||
A test case should prepare and enable a firewall first to get its hooks linked.
|
||||
After, the
|
||||
.Xr pfilctl 8
|
||||
should be used to link
|
||||
.Nm
|
||||
hook(s) to put them in front of a firewall.
|
||||
.Pp
|
||||
The following links
|
||||
.Va dummymbuf:inet6
|
||||
hook for inbound and puts it in front of other hooks:
|
||||
.Bd -literal -offset indent
|
||||
pfilctl link -i dummymbuf:inet6 inet6
|
||||
.Ed
|
||||
.Pp
|
||||
And this does the same for outbound:
|
||||
.Bd -literal -offset indent
|
||||
pfilctl link -o -a dummymbuf:inet6 inet6
|
||||
.Ed
|
||||
.Pp
|
||||
For instance, we want to test a scenario in which the very first mbuf in a
|
||||
chain has zero m_len, to verify that a firewall can correctly read the
|
||||
packet data despite that.
|
||||
The following set of rules does it for inbound and outbound:
|
||||
.Bd -literal -offset indent
|
||||
sysctl net.dummymbuf.rules="inet6 in em0 pull-head 0; inet6 out em0 pull-head 0;"
|
||||
.Ed
|
||||
.Pp
|
||||
It is encouraged to verify
|
||||
.Va net.dummymbuf.hits
|
||||
sysctl counter along with other test assertions to make sure that
|
||||
.Nm
|
||||
really does its work and there is no false positive due to misconfiguration.
|
||||
It is a good idea to reset it before the action:
|
||||
.Bd -literal -offset indent
|
||||
sysctl net.dummymbuf.hits=0
|
||||
.Ed
|
||||
.Pp
|
||||
It is equally important to cleanup the things after the test case:
|
||||
.Bd -literal -offset indent
|
||||
pfilctl unlink -i dummymbuf:inet6 inet6
|
||||
pfilctl unlink -o dummymbuf:inet6 inet6
|
||||
sysctl net.dummymbuf.rules=""
|
||||
.Ed
|
||||
.Pp
|
||||
If a test case operates within a temporary vnet then explicit cleanup can be
|
||||
omitted, the
|
||||
.Nm
|
||||
facilities will vanish along with its vnet instance.
|
||||
.Sh DIAGNOSTICS
|
||||
.Bl -diag
|
||||
.It "dummymbuf: <filter match>: rule parsing failed: <the rule in question>"
|
||||
If everything looks fine then extra spaces removal may help due to the parser
|
||||
is kept very simple.
|
||||
.It "dummymbuf: <filter match>: mbuf operation failed: <the rule in question>"
|
||||
Incorrect operation argument has been found, mbuf allocation has failed, etc.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr jail 2 ,
|
||||
.Xr pfilctl 8 ,
|
||||
.Xr mbuf 9 ,
|
||||
.Xr pfil 9 ,
|
||||
.Xr VNET 9
|
||||
.Sh AUTHORS
|
||||
The module and this manual page were written by
|
||||
.An Igor Ostapenko Aq Mt pm@igoro.pro .
|
@ -4151,6 +4151,7 @@ net/bpf_jitter.c optional bpf_jitter
|
||||
net/bpf_filter.c optional bpf | netgraph_bpf
|
||||
net/bpf_zerocopy.c optional bpf
|
||||
net/bridgestp.c optional bridge | if_bridge
|
||||
net/dummymbuf.c optional dummymbuf
|
||||
net/ieee8023ad_lacp.c optional lagg
|
||||
net/if.c standard
|
||||
net/ifq.c standard
|
||||
|
@ -100,6 +100,7 @@ SUBDIR= \
|
||||
${_dpdk_lpm4} \
|
||||
${_dpdk_lpm6} \
|
||||
${_dpms} \
|
||||
dummymbuf \
|
||||
dummynet \
|
||||
${_dwwdt} \
|
||||
${_e6000sw} \
|
||||
|
9
sys/modules/dummymbuf/Makefile
Normal file
9
sys/modules/dummymbuf/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
.PATH: ${SRCTOP}/sys/net
|
||||
|
||||
KMOD= dummymbuf
|
||||
SRCS= dummymbuf.c
|
||||
SRCS+= opt_inet.h opt_inet6.h
|
||||
|
||||
EXPORT_SYMS= YES
|
||||
|
||||
.include <bsd.kmod.mk>
|
436
sys/net/dummymbuf.c
Normal file
436
sys/net/dummymbuf.c
Normal file
@ -0,0 +1,436 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/vnet.h>
|
||||
#include <net/pfil.h>
|
||||
|
||||
/*
|
||||
* Separate sysctl sub-tree
|
||||
*/
|
||||
|
||||
SYSCTL_NODE(_net, OID_AUTO, dummymbuf, 0, NULL,
|
||||
"Dummy mbuf sysctl");
|
||||
|
||||
/*
|
||||
* Rules
|
||||
*/
|
||||
|
||||
static MALLOC_DEFINE(M_DUMMYMBUF_RULES, "dummymbuf_rules",
|
||||
"dummymbuf rules string buffer");
|
||||
|
||||
#define RULES_MAXLEN 1024
|
||||
VNET_DEFINE_STATIC(char *, dmb_rules) = NULL;
|
||||
#define V_dmb_rules VNET(dmb_rules)
|
||||
|
||||
VNET_DEFINE_STATIC(struct sx, dmb_rules_lock);
|
||||
#define V_dmb_rules_lock VNET(dmb_rules_lock)
|
||||
|
||||
#define DMB_RULES_SLOCK() sx_slock(&V_dmb_rules_lock)
|
||||
#define DMB_RULES_SUNLOCK() sx_sunlock(&V_dmb_rules_lock)
|
||||
#define DMB_RULES_XLOCK() sx_xlock(&V_dmb_rules_lock)
|
||||
#define DMB_RULES_XUNLOCK() sx_xunlock(&V_dmb_rules_lock)
|
||||
|
||||
static int
|
||||
dmb_sysctl_handle_rules(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
int error = 0;
|
||||
char empty = '\0';
|
||||
char **rulesp = (char **)arg1;
|
||||
|
||||
if (req->newptr == NULL) {
|
||||
// read only
|
||||
DMB_RULES_SLOCK();
|
||||
arg1 = *rulesp;
|
||||
if (arg1 == NULL) {
|
||||
arg1 = ∅
|
||||
arg2 = 0;
|
||||
}
|
||||
error = sysctl_handle_string(oidp, arg1, arg2, req);
|
||||
DMB_RULES_SUNLOCK();
|
||||
} else {
|
||||
// read and write
|
||||
DMB_RULES_XLOCK();
|
||||
if (*rulesp == NULL)
|
||||
*rulesp = malloc(arg2, M_DUMMYMBUF_RULES, M_WAITOK);
|
||||
arg1 = *rulesp;
|
||||
error = sysctl_handle_string(oidp, arg1, arg2, req);
|
||||
DMB_RULES_XUNLOCK();
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
SYSCTL_PROC(_net_dummymbuf, OID_AUTO, rules,
|
||||
CTLTYPE_STRING | CTLFLAG_MPSAFE | CTLFLAG_RW | CTLFLAG_VNET,
|
||||
&VNET_NAME(dmb_rules), RULES_MAXLEN, dmb_sysctl_handle_rules, "A",
|
||||
"{inet | inet6 | ethernet} {in | out} <ifname> <opname>[ <opargs>];"
|
||||
" ...;");
|
||||
|
||||
/*
|
||||
* Statistics
|
||||
*/
|
||||
|
||||
VNET_DEFINE_STATIC(counter_u64_t, dmb_hits);
|
||||
#define V_dmb_hits VNET(dmb_hits)
|
||||
SYSCTL_PROC(_net_dummymbuf, OID_AUTO, hits,
|
||||
CTLTYPE_U64 | CTLFLAG_MPSAFE | CTLFLAG_STATS | CTLFLAG_RW | CTLFLAG_VNET,
|
||||
&VNET_NAME(dmb_hits), 0, sysctl_handle_counter_u64,
|
||||
"QU", "Number of times a rule has been applied");
|
||||
|
||||
/*
|
||||
* pfil(9) context
|
||||
*/
|
||||
|
||||
VNET_DEFINE_STATIC(pfil_hook_t, dmb_pfil_inet_hook);
|
||||
#define V_dmb_pfil_inet_hook VNET(dmb_pfil_inet_hook)
|
||||
|
||||
VNET_DEFINE_STATIC(pfil_hook_t, dmb_pfil_inet6_hook);
|
||||
#define V_dmb_pfil_inet6_hook VNET(dmb_pfil_inet6_hook)
|
||||
|
||||
VNET_DEFINE_STATIC(pfil_hook_t, dmb_pfil_ethernet_hook);
|
||||
#define V_dmb_pfil_ethernet_hook VNET(dmb_pfil_ethernet_hook)
|
||||
|
||||
/*
|
||||
* Logging
|
||||
*/
|
||||
|
||||
#define FEEDBACK(pfil_type, pfil_flags, ifp, rule, msg) \
|
||||
printf("dummymbuf: %s %b %s: %s: %.*s\n", \
|
||||
(pfil_type == PFIL_TYPE_IP4 ? "PFIL_TYPE_IP4" : \
|
||||
pfil_type == PFIL_TYPE_IP6 ? "PFIL_TYPE_IP6" : \
|
||||
pfil_type == PFIL_TYPE_ETHERNET ? "PFIL_TYPE_ETHERNET" : \
|
||||
"PFIL_TYPE_UNKNOWN"), \
|
||||
(pfil_flags), "\20\21PFIL_IN\22PFIL_OUT", \
|
||||
(ifp)->if_xname, \
|
||||
(msg), \
|
||||
(rule).syntax_len, (rule).syntax_begin \
|
||||
)
|
||||
|
||||
/*
|
||||
* Internals
|
||||
*/
|
||||
|
||||
struct rule;
|
||||
typedef struct mbuf * (*op_t)(struct mbuf *, struct rule *);
|
||||
struct rule {
|
||||
const char *syntax_begin;
|
||||
int syntax_len;
|
||||
int pfil_type;
|
||||
int pfil_dir;
|
||||
char ifname[IFNAMSIZ];
|
||||
op_t op;
|
||||
const char *opargs;
|
||||
};
|
||||
|
||||
static struct mbuf *
|
||||
dmb_m_pull_head(struct mbuf *m, struct rule *rule)
|
||||
{
|
||||
struct mbuf *n;
|
||||
int count;
|
||||
|
||||
count = (int)strtol(rule->opargs, NULL, 10);
|
||||
if (count < 0 || count > MCLBYTES)
|
||||
goto bad;
|
||||
|
||||
if (!(m->m_flags & M_PKTHDR))
|
||||
goto bad;
|
||||
if (m->m_pkthdr.len <= 0)
|
||||
return (m);
|
||||
if (count > m->m_pkthdr.len)
|
||||
count = m->m_pkthdr.len;
|
||||
|
||||
if ((n = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR)) == NULL)
|
||||
goto bad;
|
||||
|
||||
m_move_pkthdr(n, m);
|
||||
m_copydata(m, 0, count, n->m_ext.ext_buf);
|
||||
n->m_len = count;
|
||||
|
||||
m_adj(m, count);
|
||||
n->m_next = m;
|
||||
|
||||
return (n);
|
||||
|
||||
bad:
|
||||
m_freem(m);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static bool
|
||||
read_rule(const char **cur, struct rule *rule)
|
||||
{
|
||||
// {inet | inet6 | ethernet} {in | out} <ifname> <opname>[ <opargs>];
|
||||
|
||||
rule->syntax_begin = NULL;
|
||||
rule->syntax_len = 0;
|
||||
|
||||
if (*cur == NULL)
|
||||
return (false);
|
||||
|
||||
// syntax_begin
|
||||
while (**cur == ' ')
|
||||
(*cur)++;
|
||||
rule->syntax_begin = *cur;
|
||||
|
||||
// syntax_len
|
||||
char *delim = strchr(*cur, ';');
|
||||
if (delim == NULL)
|
||||
return (false);
|
||||
rule->syntax_len = (int)(delim - *cur + 1);
|
||||
|
||||
// pfil_type
|
||||
if (strstr(*cur, "inet6") == *cur) {
|
||||
rule->pfil_type = PFIL_TYPE_IP6;
|
||||
*cur += strlen("inet6");
|
||||
} else if (strstr(*cur, "inet") == *cur) {
|
||||
rule->pfil_type = PFIL_TYPE_IP4;
|
||||
*cur += strlen("inet");
|
||||
} else if (strstr(*cur, "ethernet")) {
|
||||
rule->pfil_type = PFIL_TYPE_ETHERNET;
|
||||
*cur += strlen("ethernet");
|
||||
} else {
|
||||
return (false);
|
||||
}
|
||||
while (**cur == ' ')
|
||||
(*cur)++;
|
||||
|
||||
// pfil_dir
|
||||
if (strstr(*cur, "in") == *cur) {
|
||||
rule->pfil_dir = PFIL_IN;
|
||||
*cur += strlen("in");
|
||||
} else if (strstr(*cur, "out") == *cur) {
|
||||
rule->pfil_dir = PFIL_OUT;
|
||||
*cur += strlen("out");
|
||||
} else {
|
||||
return (false);
|
||||
}
|
||||
while (**cur == ' ')
|
||||
(*cur)++;
|
||||
|
||||
// ifname
|
||||
char *sp = strchr(*cur, ' ');
|
||||
if (sp == NULL || sp > delim)
|
||||
return (false);
|
||||
size_t len = sp - *cur;
|
||||
if (len >= sizeof(rule->ifname))
|
||||
return (false);
|
||||
strncpy(rule->ifname, *cur, len);
|
||||
rule->ifname[len] = 0;
|
||||
*cur = sp;
|
||||
while (**cur == ' ')
|
||||
(*cur)++;
|
||||
|
||||
// opname
|
||||
if (strstr(*cur, "pull-head") == *cur) {
|
||||
rule->op = dmb_m_pull_head;
|
||||
*cur += strlen("pull-head");
|
||||
} else {
|
||||
return (false);
|
||||
}
|
||||
while (**cur == ' ')
|
||||
(*cur)++;
|
||||
|
||||
// opargs
|
||||
if (*cur > delim)
|
||||
return (false);
|
||||
rule->opargs = *cur;
|
||||
|
||||
*cur = delim + 1;
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
static pfil_return_t
|
||||
dmb_pfil_mbuf_chk(int pfil_type, struct mbuf **mp, struct ifnet *ifp,
|
||||
int flags, void *ruleset, void *unused)
|
||||
{
|
||||
struct mbuf *m = *mp;
|
||||
const char *cursor;
|
||||
bool parsed;
|
||||
struct rule rule;
|
||||
|
||||
DMB_RULES_SLOCK();
|
||||
cursor = V_dmb_rules;
|
||||
while ((parsed = read_rule(&cursor, &rule))) {
|
||||
if (rule.pfil_type == pfil_type &&
|
||||
rule.pfil_dir == (flags & rule.pfil_dir) &&
|
||||
strcmp(rule.ifname, ifp->if_xname) == 0) {
|
||||
m = rule.op(m, &rule);
|
||||
if (m == NULL) {
|
||||
FEEDBACK(pfil_type, flags, ifp, rule,
|
||||
"mbuf operation failed");
|
||||
break;
|
||||
}
|
||||
counter_u64_add(V_dmb_hits, 1);
|
||||
}
|
||||
if (strlen(cursor) == 0)
|
||||
break;
|
||||
}
|
||||
if (!parsed) {
|
||||
FEEDBACK(pfil_type, flags, ifp, rule, "rule parsing failed");
|
||||
m_freem(m);
|
||||
m = NULL;
|
||||
}
|
||||
DMB_RULES_SUNLOCK();
|
||||
|
||||
if (m == NULL) {
|
||||
*mp = NULL;
|
||||
return (PFIL_DROPPED);
|
||||
}
|
||||
if (m != *mp) {
|
||||
*mp = m;
|
||||
return (PFIL_REALLOCED);
|
||||
}
|
||||
|
||||
return (PFIL_PASS);
|
||||
}
|
||||
|
||||
static pfil_return_t
|
||||
dmb_pfil_inet_mbuf_chk(struct mbuf **mp, struct ifnet *ifp, int flags,
|
||||
void *ruleset, struct inpcb *inp)
|
||||
{
|
||||
return (dmb_pfil_mbuf_chk(PFIL_TYPE_IP4, mp, ifp, flags,
|
||||
ruleset, inp));
|
||||
}
|
||||
|
||||
static pfil_return_t
|
||||
dmb_pfil_inet6_mbuf_chk(struct mbuf **mp, struct ifnet *ifp, int flags,
|
||||
void *ruleset, struct inpcb *inp)
|
||||
{
|
||||
return (dmb_pfil_mbuf_chk(PFIL_TYPE_IP6, mp, ifp, flags,
|
||||
ruleset, inp));
|
||||
}
|
||||
|
||||
static pfil_return_t
|
||||
dmb_pfil_ethernet_mbuf_chk(struct mbuf **mp, struct ifnet *ifp, int flags,
|
||||
void *ruleset, struct inpcb *inp)
|
||||
{
|
||||
return (dmb_pfil_mbuf_chk(PFIL_TYPE_ETHERNET, mp, ifp, flags,
|
||||
ruleset, inp));
|
||||
}
|
||||
|
||||
static void
|
||||
dmb_pfil_init(void)
|
||||
{
|
||||
struct pfil_hook_args pha = {
|
||||
.pa_version = PFIL_VERSION,
|
||||
.pa_modname = "dummymbuf",
|
||||
.pa_flags = PFIL_IN | PFIL_OUT,
|
||||
};
|
||||
|
||||
#ifdef INET
|
||||
pha.pa_type = PFIL_TYPE_IP4;
|
||||
pha.pa_mbuf_chk = dmb_pfil_inet_mbuf_chk;
|
||||
pha.pa_rulname = "inet";
|
||||
V_dmb_pfil_inet_hook = pfil_add_hook(&pha);
|
||||
#endif
|
||||
|
||||
#ifdef INET6
|
||||
pha.pa_type = PFIL_TYPE_IP6;
|
||||
pha.pa_mbuf_chk = dmb_pfil_inet6_mbuf_chk;
|
||||
pha.pa_rulname = "inet6";
|
||||
V_dmb_pfil_inet6_hook = pfil_add_hook(&pha);
|
||||
#endif
|
||||
|
||||
pha.pa_type = PFIL_TYPE_ETHERNET;
|
||||
pha.pa_mbuf_chk = dmb_pfil_ethernet_mbuf_chk;
|
||||
pha.pa_rulname = "ethernet";
|
||||
V_dmb_pfil_ethernet_hook = pfil_add_hook(&pha);
|
||||
}
|
||||
|
||||
static void
|
||||
dmb_pfil_uninit(void)
|
||||
{
|
||||
#ifdef INET
|
||||
pfil_remove_hook(V_dmb_pfil_inet_hook);
|
||||
#endif
|
||||
|
||||
#ifdef INET6
|
||||
pfil_remove_hook(V_dmb_pfil_inet6_hook);
|
||||
#endif
|
||||
|
||||
pfil_remove_hook(V_dmb_pfil_ethernet_hook);
|
||||
}
|
||||
|
||||
static void
|
||||
vnet_dmb_init(void *unused __unused)
|
||||
{
|
||||
sx_init(&V_dmb_rules_lock, "dummymbuf rules");
|
||||
V_dmb_hits = counter_u64_alloc(M_WAITOK);
|
||||
dmb_pfil_init();
|
||||
}
|
||||
VNET_SYSINIT(vnet_dmb_init, SI_SUB_PROTO_PFIL, SI_ORDER_ANY,
|
||||
vnet_dmb_init, NULL);
|
||||
|
||||
static void
|
||||
vnet_dmb_uninit(void *unused __unused)
|
||||
{
|
||||
dmb_pfil_uninit();
|
||||
counter_u64_free(V_dmb_hits);
|
||||
sx_destroy(&V_dmb_rules_lock);
|
||||
free(V_dmb_rules, M_DUMMYMBUF_RULES);
|
||||
}
|
||||
VNET_SYSUNINIT(vnet_dmb_uninit, SI_SUB_PROTO_PFIL, SI_ORDER_ANY,
|
||||
vnet_dmb_uninit, NULL);
|
||||
|
||||
static int
|
||||
dmb_modevent(module_t mod __unused, int event, void *arg __unused)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
switch (event) {
|
||||
case MOD_LOAD:
|
||||
case MOD_UNLOAD:
|
||||
break;
|
||||
default:
|
||||
error = EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static moduledata_t dmb_mod = {
|
||||
"dummymbuf",
|
||||
dmb_modevent,
|
||||
NULL
|
||||
};
|
||||
|
||||
DECLARE_MODULE(dummymbuf, dmb_mod, SI_SUB_PROTO_PFIL, SI_ORDER_ANY);
|
||||
MODULE_VERSION(dummymbuf, 1);
|
Loading…
Reference in New Issue
Block a user