ipfw: Add ipfrag filter.
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Wed, 20 Sep 2017 00:21:58 +0000 (08:21 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Wed, 20 Sep 2017 00:48:17 +0000 (08:48 +0800)
Unlike 'frag' filter, which only matches non-first IP fragments,
this filter matches all IP fragments.

sbin/ipfw/ipfw.8
sbin/ipfw/ipfw2.c
sys/net/ipfw/ip_fw2.c
sys/net/ipfw/ip_fw2.h

index 3e09bb5..f734faa 100644 (file)
@@ -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 $
 .\"
 .\" $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
 .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,
 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
 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
 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
 .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
 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 .
 .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 ).
 .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
 .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
 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
 .It Cm tcpseq Ar seq
 TCP packets only.
 Match if the TCP header sequence number field is set to
index 556800d..028c2ec 100644 (file)
@@ -207,6 +207,7 @@ enum tokens {
        TOK_RECV,
        TOK_VIA,
        TOK_FRAG,
        TOK_RECV,
        TOK_VIA,
        TOK_FRAG,
+       TOK_IPFRAG,
        TOK_IPOPTS,
        TOK_IPLEN,
        TOK_IPID,
        TOK_IPOPTS,
        TOK_IPLEN,
        TOK_IPID,
@@ -304,6 +305,7 @@ struct _s_x rule_options[] = {
        { "via",                TOK_VIA },
        { "fragment",           TOK_FRAG },
        { "frag",               TOK_FRAG },
        { "via",                TOK_VIA },
        { "fragment",           TOK_FRAG },
        { "frag",               TOK_FRAG },
+       { "ipfrag",             TOK_IPFRAG },
        { "ipoptions",          TOK_IPOPTS },
        { "ipopts",             TOK_IPOPTS },
        { "iplen",              TOK_IPLEN },
        { "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;
 
                                printf(" frag");
                                break;
 
+                       case O_IPFRAG:
+                               printf(" ipfrag");
+                               break;
+
                        case O_IN:
                                printf(cmd->len & F_NOT ? " out" : " in");
                                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;
 
                        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;
                case TOK_LAYER2:
                        fill_cmd(cmd, O_LAYER2, 0, 0);
                        break;
index 383a8c2..ac6ab41 100644 (file)
@@ -3103,6 +3103,19 @@ check_body:
                                match = (hlen > 0 && offset != 0);
                                break;
 
                                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;
                        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_LAYER2:
                case O_IN:
                case O_FRAG:
+               case O_IPFRAG:
                case O_IPOPT:
                case O_IPLEN:
                case O_IPID:
                case O_IPOPT:
                case O_IPLEN:
                case O_IPID:
index b2b4a25..eed9785 100644 (file)
@@ -117,6 +117,9 @@ enum ipfw_opcodes {         /* arguments (4 byte each)      */
        /* Action. */
        O_DEFRAG,               /* none                         */
 
        /* Action. */
        O_DEFRAG,               /* none                         */
 
+       /* Filter. */
+       O_IPFRAG,               /* none                         */
+
        O_LAST_OPCODE           /* not an opcode!               */
 };
 
        O_LAST_OPCODE           /* not an opcode!               */
 };