]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
iptables: nft: add -f support
authorPablo Neira Ayuso <pablo@netfilter.org>
Mon, 29 Oct 2012 21:52:50 +0000 (22:52 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 30 Dec 2013 22:50:17 +0000 (23:50 +0100)
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
iptables/nft.c

index 1cd432af652fd1693483566bf3011358b481dc8e..0369461ad1eefd89f4610e19fc3b9ec30471ad3d 100644 (file)
@@ -580,6 +580,24 @@ static void add_payload(struct nft_rule *r, int offset, int len)
        nft_rule_add_expr(r, expr);
 }
 
+/* bitwise operation is = sreg & mask ^ xor */
+static void add_bitwise_u16(struct nft_rule *r, int mask, int xor)
+{
+       struct nft_rule_expr *expr;
+
+       expr = nft_rule_expr_alloc("bitwise");
+       if (expr == NULL)
+               return;
+
+       nft_rule_expr_set_u32(expr, NFT_EXPR_BITWISE_SREG, NFT_REG_1);
+       nft_rule_expr_set_u32(expr, NFT_EXPR_BITWISE_DREG, NFT_REG_1);
+       nft_rule_expr_set_u32(expr, NFT_EXPR_BITWISE_LEN, sizeof(uint16_t));
+       nft_rule_expr_set(expr, NFT_EXPR_BITWISE_MASK, &mask, sizeof(uint16_t));
+       nft_rule_expr_set(expr, NFT_EXPR_BITWISE_XOR, &xor, sizeof(uint16_t));
+
+       nft_rule_add_expr(r, expr);
+}
+
 static void add_cmp_ptr(struct nft_rule *r, uint32_t op, void *data, size_t len)
 {
        struct nft_rule_expr *expr;
@@ -595,6 +613,11 @@ static void add_cmp_ptr(struct nft_rule *r, uint32_t op, void *data, size_t len)
        nft_rule_add_expr(r, expr);
 }
 
+static void add_cmp_u16(struct nft_rule *r, uint16_t val, uint32_t op)
+{
+       add_cmp_ptr(r, op, &val, sizeof(val));
+}
+
 static void add_cmp_u32(struct nft_rule *r, uint32_t val, uint32_t op)
 {
        add_cmp_ptr(r, op, &val, sizeof(val));
@@ -699,6 +722,19 @@ nft_rule_add(struct nft_handle *h, const char *chain, const char *table,
 
                add_cmp_u32(r, cs->fw.ip.proto, op);
        }
+       if (cs->fw.ip.flags & IPT_F_FRAG) {
+               add_payload(r, offsetof(struct iphdr, frag_off), 2);
+               /* get the 13 bits that contain the fragment offset */
+               add_bitwise_u16(r, 0x1fff, !0x1fff);
+
+               /* if offset is non-zero, this is a fragment */
+               if (cs->fw.ip.invflags & IPT_INV_FRAG)
+                       op = NFT_CMP_EQ;
+               else
+                       op = NFT_CMP_NEQ;
+
+               add_cmp_u16(r, 0, op);
+       }
 
        for (matchp = cs->matches; matchp; matchp = matchp->next)
                add_match(r, matchp->match->m);
@@ -970,6 +1006,50 @@ get_cmp_data(struct nft_rule_expr_iter *iter, void *data, size_t dlen, bool *inv
                *inv = false;
 }
 
+static void get_frag(struct nft_rule_expr_iter *iter, bool *inv)
+{
+       struct nft_rule_expr *e;
+       const char *name;
+       uint8_t op;
+
+       e = nft_rule_expr_iter_next(iter);
+       if (e == NULL)
+               return;
+
+       /* we assume correct mask and xor */
+       name = nft_rule_expr_get_str(e, NFT_RULE_EXPR_ATTR_NAME);
+       if (strcmp(name, "bitwise") != 0) {
+               DEBUGP("skipping no bitwise after payload\n");
+               return;
+       }
+
+       /* Now check for cmp */
+       e = nft_rule_expr_iter_next(iter);
+       if (e == NULL)
+               return;
+
+       /* we assume correct data */
+       name = nft_rule_expr_get_str(e, NFT_RULE_EXPR_ATTR_NAME);
+       if (strcmp(name, "cmp") != 0) {
+               DEBUGP("skipping no cmp after payload\n");
+               return;
+       }
+
+       op = nft_rule_expr_get_u8(e, NFT_EXPR_CMP_OP);
+       if (op == NFT_CMP_EQ)
+               *inv = true;
+       else
+               *inv = false;
+}
+
+static void print_frag(bool inv)
+{
+       if (inv)
+               printf("! -f ");
+       else
+               printf("-f ");
+}
+
 static void print_proto(uint16_t proto, int invert)
 {
        const struct protoent *pent = getprotobynumber(proto);
@@ -1045,6 +1125,10 @@ nft_print_payload(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter)
                get_cmp_data(iter, &proto, sizeof(proto), &inv);
                print_proto(proto, inv);
                break;
+       case offsetof(struct iphdr, frag_off):
+               get_frag(iter, &inv);
+               print_frag(inv);
+               break;
        default:
                DEBUGP("unknown payload offset %d\n", offset);
                break;
@@ -1803,6 +1887,12 @@ nft_parse_payload(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter,
                if (inv)
                        cs->fw.ip.invflags |= IPT_INV_PROTO;
                break;
+       case offsetof(struct iphdr, frag_off):
+               cs->fw.ip.flags |= IPT_F_FRAG;
+               get_frag(iter, &inv);
+               if (inv)
+                       cs->fw.ip.invflags |= IPT_INV_FRAG;
+               break;
        default:
                DEBUGP("unknown payload offset %d\n", offset);
                break;