From cc9ef3d3edaed64f991ac44775c10b2f2523c349 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Wed, 20 Sep 2017 08:21:58 +0800 Subject: [PATCH] ipfw: Add ipfrag filter. Unlike 'frag' filter, which only matches non-first IP fragments, this filter matches all IP fragments. --- sbin/ipfw/ipfw.8 | 37 ++++++++++++++++++++++++++++++------- sbin/ipfw/ipfw2.c | 10 ++++++++++ sys/net/ipfw/ip_fw2.c | 14 ++++++++++++++ sys/net/ipfw/ip_fw2.h | 3 +++ 4 files changed, 57 insertions(+), 7 deletions(-) diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index 3e09bb58a7..f734faa82f 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -2,7 +2,7 @@ .\" $FreeBSD: src/sbin/ipfw/ipfw.8,v 1.63.2.33 2003/02/04 01:36:02 brueffer Exp $ .\" $DragonFly: src/sbin/ipfw/ipfw.8,v 1.20 2008/11/23 21:55:52 swildner Exp $ .\" -.Dd September 10, 2017 +.Dd September 20, 2017 .Dt IPFW 8 .Os .Sh NAME @@ -442,7 +442,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), +fragment flag, Time To Live .It IP options .It Misc. TCP header fields @@ -861,7 +861,12 @@ fragment) will never match a rule which has one or more port specifications. See the .Cm frag -option for details on matching fragmented packets. +and +.Cm ipfrag +options for details on matching fragmented packets. +Ane see the +.Cm defrag +action for reassembling IP fragments. .El .Ss RULE OPTIONS (MATCH PATTERNS) Additional match patterns can be used within @@ -884,9 +889,14 @@ specified as argument. Matches TCP packets that have the RST or ACK bits set. .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. +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. +See also +.Cm ipfrag +option and +.Cm defrag +action. .It Cm gid Ar group Matches all TCP or UDP packets sent by or received for a .Ar group . @@ -939,6 +949,14 @@ are mutually exclusive (in fact, .Cm out is implemented as .Cm not in Ns No ). +.It Cm ipfrag +Matches IP fragment, +even if it's the first fragment. +See also +.Cm frag +option and +.Cm defrag +action. .It Cm ipid Ar id Matches IP packets whose .Cm ip_id @@ -1130,7 +1148,12 @@ specification can never match a fragmented packet which has a non-zero offset. See the .Cm frag -option for details on matching fragmented packets. +and +.Cm ipfrag +options for details on matching fragmented packets. +And see the +.Cm defrag +action for reassembling IP fragments. .It Cm tcpseq Ar seq TCP packets only. Match if the TCP header sequence number field is set to diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 556800dc74..028c2ecea7 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -207,6 +207,7 @@ enum tokens { TOK_RECV, TOK_VIA, TOK_FRAG, + TOK_IPFRAG, TOK_IPOPTS, TOK_IPLEN, TOK_IPID, @@ -304,6 +305,7 @@ struct _s_x rule_options[] = { { "via", TOK_VIA }, { "fragment", TOK_FRAG }, { "frag", TOK_FRAG }, + { "ipfrag", TOK_IPFRAG }, { "ipoptions", TOK_IPOPTS }, { "ipopts", TOK_IPOPTS }, { "iplen", TOK_IPLEN }, @@ -1067,6 +1069,10 @@ show_ipfw(struct ipfw_ioc_rule *rule, int pcwidth, int bcwidth) printf(" frag"); break; + case O_IPFRAG: + printf(" ipfrag"); + break; + case O_IN: printf(cmd->len & F_NOT ? " out" : " in"); break; @@ -2966,6 +2972,10 @@ read_options: fill_cmd(cmd, O_FRAG, 0, 0); break; + case TOK_IPFRAG: + fill_cmd(cmd, O_IPFRAG, 0, 0); + break; + case TOK_LAYER2: fill_cmd(cmd, O_LAYER2, 0, 0); break; diff --git a/sys/net/ipfw/ip_fw2.c b/sys/net/ipfw/ip_fw2.c index 383a8c224e..ac6ab41cf1 100644 --- a/sys/net/ipfw/ip_fw2.c +++ b/sys/net/ipfw/ip_fw2.c @@ -3103,6 +3103,19 @@ check_body: match = (hlen > 0 && offset != 0); break; + case O_IPFRAG: + if (hlen > 0) { + uint16_t off; + + if (args->eh != NULL) + off = ntohs(ip->ip_off); + else + off = ip->ip_off; + if (off & (IP_MF | IP_OFFMASK)) + match = 1; + } + break; + case O_IN: /* "out" is "not in" */ match = (oif == NULL); break; @@ -4608,6 +4621,7 @@ ipfw_check_ioc_rule(struct ipfw_ioc_rule *rule, int size, uint32_t *rule_flags) case O_LAYER2: case O_IN: case O_FRAG: + case O_IPFRAG: case O_IPOPT: case O_IPLEN: case O_IPID: diff --git a/sys/net/ipfw/ip_fw2.h b/sys/net/ipfw/ip_fw2.h index b2b4a25cf6..eed978528a 100644 --- a/sys/net/ipfw/ip_fw2.h +++ b/sys/net/ipfw/ip_fw2.h @@ -117,6 +117,9 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ /* Action. */ O_DEFRAG, /* none */ + /* Filter. */ + O_IPFRAG, /* none */ + O_LAST_OPCODE /* not an opcode! */ }; -- 2.11.4.GIT