From e56b2f0b28048cea88fa6000a2bf08a75f055526 Mon Sep 17 00:00:00 2001 From: Gleb Smirnoff Date: Tue, 11 Aug 2020 15:46:22 +0000 Subject: [PATCH] MFC r364117 by glebius: ipfw: make the "frag" keyword accept additional options "mf", "df", "rf" and "offset". This allows to match on specific bits of ip_off field. For compatibility reasons lack of keyword means "offset". Reviewed by: ae Approved by: glebius Differential Revision: https://reviews.freebsd.org/D26021 (cherry picked from commit 825398f946221045c565363a0349f68d054d6455) --- sbin/ipfw/ipfw.8 | 33 +++++++++++++++++++++++++-------- sbin/ipfw/ipfw2.c | 20 ++++++++++++++++++-- sys/netpfil/ipfw/ip_fw2.c | 18 +++++++++++++++++- 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index ea35a276784..58bc3662fcc 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -1,7 +1,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 21, 2019 +.Dd August 10, 2020 .Dt IPFW 8 .Os .Sh NAME @@ -600,7 +600,7 @@ See Section By name or address .It Misc. IP header fields Version, type of service, datagram length, identification, -fragment flag (non-zero IP offset), +fragmentation flags, Time To Live .It IP options .It IPv6 Extension headers @@ -1602,12 +1602,29 @@ Matches IPv6 packets containing any of the flow labels given in .Ar labels . .Ar labels is a comma separated list of numeric flow labels. -.It Cm frag -Matches packets that are fragments and not the first -fragment of an IP datagram. -Note that these packets will not have -the next protocol header (e.g.\& TCP, UDP) so options that look into -these headers cannot match. +.It Cm frag Ar spec +Matches IPv4 packets whose +.Cm ip_off +field contains the comma separated list of IPv4 fragmentation +options specified in +.Ar spec . +The recognized options are: +.Cm df +.Pq Dv don't fragment , +.Cm mf +.Pq Dv more fragments , +.Cm rf +.Pq Dv reserved fragment bit +.Cm offset +.Pq Dv non-zero fragment offset . +The absence of a particular options may be denoted +with a +.Ql \&! . +.Pp +Empty list of options defaults to matching on non-zero fragment offset. +Such rule would match all not the first fragment datagrams, +both IPv4 and IPv6. +This is a backward compatibility with older rulesets. .It Cm gid Ar group Matches all TCP or UDP packets sent by or received for a .Ar group . diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index cf66422d2ff..e0b5371adb9 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -168,6 +168,14 @@ static struct _s_x f_iptos[] = { { NULL, 0 } }; +static struct _s_x f_ipoff[] = { + { "rf", IP_RF >> 8 }, + { "df", IP_DF >> 8 }, + { "mf", IP_MF >> 8 }, + { "offset", 0x1 }, + { NULL, 0} +}; + struct _s_x f_ipdscp[] = { { "af11", IPTOS_DSCP_AF11 >> 2 }, /* 001010 */ { "af12", IPTOS_DSCP_AF12 >> 2 }, /* 001100 */ @@ -1531,7 +1539,7 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo, IPPROTO_ETHERTYPE, cmd->opcode); break; case O_FRAG: - bprintf(bp, " frag"); + print_flags(bp, "frag", cmd, f_ipoff); break; case O_FIB: bprintf(bp, " fib %u", cmd->arg1); @@ -4553,7 +4561,15 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate) break; case TOK_FRAG: - fill_cmd(cmd, O_FRAG, 0, 0); + fill_flags_cmd(cmd, O_FRAG, f_ipoff, *av); + /* + * Compatibility: no argument after "frag" + * keyword equals to "frag offset". + */ + if (cmd->arg1 == 0) + cmd->arg1 = 0x1; + else + av++; break; case TOK_LAYER2: diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c index 90f3b3c0819..f639a3bfabb 100644 --- a/sys/netpfil/ipfw/ip_fw2.c +++ b/sys/netpfil/ipfw/ip_fw2.c @@ -1916,7 +1916,23 @@ do { \ break; case O_FRAG: - match = (offset != 0); + if (is_ipv4) { + /* + * Since flags_match() works with + * uint8_t we pack ip_off into 8 bits. + * For this match offset is a boolean. + */ + match = flags_match(cmd, + ((ntohs(ip->ip_off) & ~IP_OFFMASK) + >> 8) | (offset != 0)); + } else { + /* + * Compatiblity: historically bare + * "frag" would match IPv6 fragments. + */ + match = (cmd->arg1 == 0x1 && + (offset != 0)); + } break; case O_IN: /* "out" is "not in" */ -- 2.45.0