pf: allow scrub rules without fragment reassemble
scrub rules have defaulted to handling fragments for a long time, but since we removed "fragment crop" and "fragment drop-ovl" in 64b3b4d611 this has become less obvious and more expensive ("reassemble" being the more expensive option, even if it's the one the vast majority of users should be using). Extend the 'scrub' syntax to allow fragment reassembly to be disabled, while retaining the other scrub behaviour (e.g. TTL changes, random-id, ..) using 'scrub fragment no reassemble'. Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D37459
This commit is contained in:
parent
ce9f36610e
commit
57e047e51c
@ -1528,7 +1528,8 @@ scrub_opt : NODF {
|
||||
}
|
||||
;
|
||||
|
||||
fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ }
|
||||
fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ }
|
||||
| FRAGMENT NO REASSEMBLE { $$ = PFRULE_FRAGMENT_NOREASS; }
|
||||
| FRAGMENT FRAGCROP { $$ = 0; }
|
||||
| FRAGMENT FRAGDROP { $$ = 0; }
|
||||
;
|
||||
|
@ -1131,7 +1131,8 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer
|
||||
if (r->rule_flag & PFRULE_REASSEMBLE_TCP)
|
||||
printf(" reassemble tcp");
|
||||
|
||||
printf(" fragment reassemble");
|
||||
printf(" fragment %sreassemble",
|
||||
r->rule_flag & PFRULE_FRAGMENT_NOREASS ? "no " : "");
|
||||
}
|
||||
i = 0;
|
||||
while (r->label[i][0])
|
||||
|
1
sbin/pfctl/tests/files/pf1011.in
Normal file
1
sbin/pfctl/tests/files/pf1011.in
Normal file
@ -0,0 +1 @@
|
||||
scrub fragment no reassemble
|
1
sbin/pfctl/tests/files/pf1011.ok
Normal file
1
sbin/pfctl/tests/files/pf1011.ok
Normal file
@ -0,0 +1 @@
|
||||
scrub all fragment no reassemble
|
1
sbin/pfctl/tests/files/pf1012.in
Normal file
1
sbin/pfctl/tests/files/pf1012.in
Normal file
@ -0,0 +1 @@
|
||||
scrub
|
1
sbin/pfctl/tests/files/pf1012.ok
Normal file
1
sbin/pfctl/tests/files/pf1012.ok
Normal file
@ -0,0 +1 @@
|
||||
scrub all fragment reassemble
|
@ -121,3 +121,5 @@ PFCTL_TEST(1007, "Basic ethernet rule")
|
||||
PFCTL_TEST(1008, "Ethernet rule with mask length")
|
||||
PFCTL_TEST(1009, "Ethernet rule with mask")
|
||||
PFCTL_TEST(1010, "POM_STICKYADDRESS test")
|
||||
PFCTL_TEST(1011, "Test disabling scrub fragment reassemble")
|
||||
PFCTL_TEST(1012, "Test scrub fragment reassemble is default")
|
||||
|
@ -28,7 +28,7 @@
|
||||
.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd October 28, 2022
|
||||
.Dd November 24, 2022
|
||||
.Dt PF.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -832,6 +832,9 @@ packet, and only the completed packet is passed on to the filter.
|
||||
The advantage is that filter rules have to deal only with complete
|
||||
packets, and can ignore fragments.
|
||||
The drawback of caching fragments is the additional memory cost.
|
||||
This is the default behaviour unless no fragment reassemble is specified.
|
||||
.It Ar no fragment reassemble
|
||||
Do not reassemble fragments.
|
||||
.It Ar reassemble tcp
|
||||
Statefully normalizes TCP connections.
|
||||
.Ar scrub reassemble tcp
|
||||
|
@ -598,6 +598,7 @@ struct pf_rule {
|
||||
|
||||
/* scrub flags */
|
||||
#define PFRULE_NODF 0x0100
|
||||
#define PFRULE_FRAGMENT_NOREASS 0x0200
|
||||
#define PFRULE_RANDOMID 0x0800
|
||||
#define PFRULE_REASSEMBLE_TCP 0x1000
|
||||
#define PFRULE_SET_TOS 0x2000
|
||||
|
@ -1115,31 +1115,34 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kkif *kif, u_short *reason
|
||||
DPFPRINTF(("max packet %d\n", fragoff + ip_len));
|
||||
goto bad;
|
||||
}
|
||||
max = fragoff + ip_len;
|
||||
|
||||
/* Fully buffer all of the fragments
|
||||
* Might return a completely reassembled mbuf, or NULL */
|
||||
PF_FRAG_LOCK();
|
||||
DPFPRINTF(("reass frag %d @ %d-%d\n", h->ip_id, fragoff, max));
|
||||
verdict = pf_reassemble(m0, h, dir, reason);
|
||||
PF_FRAG_UNLOCK();
|
||||
if (! (r->rule_flag & PFRULE_FRAGMENT_NOREASS)) {
|
||||
max = fragoff + ip_len;
|
||||
|
||||
if (verdict != PF_PASS)
|
||||
return (PF_DROP);
|
||||
/* Fully buffer all of the fragments
|
||||
* Might return a completely reassembled mbuf, or NULL */
|
||||
PF_FRAG_LOCK();
|
||||
DPFPRINTF(("reass frag %d @ %d-%d\n", h->ip_id, fragoff, max));
|
||||
verdict = pf_reassemble(m0, h, dir, reason);
|
||||
PF_FRAG_UNLOCK();
|
||||
|
||||
m = *m0;
|
||||
if (m == NULL)
|
||||
return (PF_DROP);
|
||||
if (verdict != PF_PASS)
|
||||
return (PF_DROP);
|
||||
|
||||
h = mtod(m, struct ip *);
|
||||
m = *m0;
|
||||
if (m == NULL)
|
||||
return (PF_DROP);
|
||||
|
||||
h = mtod(m, struct ip *);
|
||||
|
||||
no_fragment:
|
||||
/* At this point, only IP_DF is allowed in ip_off */
|
||||
if (h->ip_off & ~htons(IP_DF)) {
|
||||
u_int16_t ip_off = h->ip_off;
|
||||
/* At this point, only IP_DF is allowed in ip_off */
|
||||
if (h->ip_off & ~htons(IP_DF)) {
|
||||
u_int16_t ip_off = h->ip_off;
|
||||
|
||||
h->ip_off &= htons(IP_DF);
|
||||
h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_off, h->ip_off, 0);
|
||||
h->ip_off &= htons(IP_DF);
|
||||
h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_off, h->ip_off, 0);
|
||||
}
|
||||
}
|
||||
|
||||
pf_scrub_ip(&m, r->rule_flag, r->min_ttl, r->set_tos);
|
||||
|
Loading…
x
Reference in New Issue
Block a user