]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
ct: connlabel matching support
authorFlorian Westphal <fw@strlen.de>
Tue, 22 Oct 2013 13:03:52 +0000 (15:03 +0200)
committerFlorian Westphal <fw@strlen.de>
Tue, 18 Feb 2014 21:31:07 +0000 (22:31 +0100)
Takes advantage of the fact that the current maximum label storage area
is 128 bits, i.e. the dynamically allocated extension area in the
kernel will always fit into a nft register.

Currently this re-uses rt_symbol_table_init() to read connlabel.conf.
This works since the format is pretty much the same.

Signed-off-by: Florian Westphal <fw@strlen.de>
include/datatype.h
include/linux/netfilter/nf_tables.h
src/ct.c
src/parser.y
src/scanner.l

index 9e609cf2e53b673e8ba527163501a8deb498307b..2c66e9d9702f488ac3ba4b641013fa9b96774bae 100644 (file)
@@ -34,6 +34,7 @@
  * @TYPE_CT_DIR:       conntrack direction
  * @TYPE_CT_STATUS:    conntrack status (bitmask subtype)
  * @TYPE_ICMP6_TYPE:   ICMPv6 type codes (integer subtype)
+ * @TYPE_CT_LABEL:     Conntrack Label (bitmask subtype)
  */
 enum datatypes {
        TYPE_INVALID,
@@ -66,6 +67,7 @@ enum datatypes {
        TYPE_CT_DIR,
        TYPE_CT_STATUS,
        TYPE_ICMP6_TYPE,
+       TYPE_CT_LABEL,
        __TYPE_MAX
 };
 #define TYPE_MAX               (__TYPE_MAX - 1)
index 448593c071201f8025ab3d266d9c99901a9390b0..ff9b0a732b88d267eed465d46b011ea684cdf9a8 100644 (file)
@@ -586,6 +586,7 @@ enum nft_meta_attributes {
  * @NFT_CT_PROTOCOL: conntrack layer 4 protocol
  * @NFT_CT_PROTO_SRC: conntrack layer 4 protocol source
  * @NFT_CT_PROTO_DST: conntrack layer 4 protocol destination
+ * @NFT_CT_LABELS: conntrack label bitset (stored in conntrack extension)
  */
 enum nft_ct_keys {
        NFT_CT_STATE,
@@ -601,6 +602,7 @@ enum nft_ct_keys {
        NFT_CT_PROTOCOL,
        NFT_CT_PROTO_SRC,
        NFT_CT_PROTO_DST,
+       NFT_CT_LABEL,
 };
 
 /**
index 79d4666c2d38b55750ef5b73856f85439082b4ea..32f22a5c6705f671f1e95692e3d5d085f46aa97d 100644 (file)
--- a/src/ct.c
+++ b/src/ct.c
 #include <linux/netfilter/nf_conntrack_common.h>
 #include <linux/netfilter/nf_conntrack_tuple_common.h>
 
+#include <erec.h>
 #include <expression.h>
 #include <datatype.h>
+#include <gmputil.h>
 #include <ct.h>
 #include <gmputil.h>
 #include <utils.h>
@@ -91,6 +93,73 @@ static const struct datatype ct_status_type = {
        .sym_tbl        = &ct_status_tbl,
 };
 
+static struct symbol_table *ct_label_tbl;
+
+#define CT_LABEL_BIT_SIZE 128
+
+static void ct_label_type_print(const struct expr *expr)
+{
+       unsigned long bit = mpz_scan1(expr->value, 0);
+       const struct symbolic_constant *s;
+
+       for (s = ct_label_tbl->symbols; s->identifier != NULL; s++) {
+               if (bit != s->value)
+                       continue;
+               printf("%s", s->identifier);
+               return;
+       }
+       /* can happen when connlabel.conf is altered after rules were added */
+       gmp_printf("0x%Zx", expr->value);
+}
+
+static struct error_record *ct_label_type_parse(const struct expr *sym,
+                                               struct expr **res)
+{
+       const struct symbolic_constant *s;
+       const struct datatype *dtype;
+       uint8_t data[CT_LABEL_BIT_SIZE];
+       mpz_t value;
+
+       for (s = ct_label_tbl->symbols; s->identifier != NULL; s++) {
+               if (!strcmp(sym->identifier, s->identifier))
+                       break;
+       }
+
+       dtype = sym->dtype;
+       if (s->identifier == NULL)
+               return error(&sym->location, "Could not parse %s", dtype->desc);
+
+       if (s->value >= CT_LABEL_BIT_SIZE)
+               return error(&sym->location, "%s: out of range (%u max)",
+                            s->identifier, s->value, CT_LABEL_BIT_SIZE);
+
+       mpz_init2(value, dtype->size);
+       mpz_setbit(value, s->value);
+       mpz_export_data(data, value, BYTEORDER_HOST_ENDIAN, sizeof(data));
+
+       *res = constant_expr_alloc(&sym->location, dtype,
+                                  dtype->byteorder, sizeof(data),
+                                  data);
+       mpz_clear(value);
+       return NULL;
+}
+
+static const struct datatype ct_label_type = {
+       .type           = TYPE_CT_LABEL,
+       .name           = "ct_label",
+       .desc           = "conntrack label",
+       .byteorder      = BYTEORDER_HOST_ENDIAN,
+       .size           = CT_LABEL_BIT_SIZE,
+       .basetype       = &bitmask_type,
+       .print          = ct_label_type_print,
+       .parse          = ct_label_type_parse,
+};
+
+static void __init ct_label_table_init(void)
+{
+       ct_label_tbl = rt_symbol_table_init("/etc/xtables/connlabel.conf");
+}
+
 static const struct ct_template ct_templates[] = {
        [NFT_CT_STATE]          = CT_TEMPLATE("state",      &ct_state_type,
                                              BYTEORDER_HOST_ENDIAN,
@@ -125,6 +194,9 @@ static const struct ct_template ct_templates[] = {
        [NFT_CT_PROTO_DST]      = CT_TEMPLATE("proto-dst",  &invalid_type,
                                              BYTEORDER_BIG_ENDIAN,
                                              2 * BITS_PER_BYTE),
+       [NFT_CT_LABEL]          = CT_TEMPLATE("label", &ct_label_type,
+                                             BYTEORDER_HOST_ENDIAN,
+                                             CT_LABEL_BIT_SIZE),
 };
 
 static void ct_expr_print(const struct expr *expr)
index 07613e2107c1bad06967bcfe0f04900041e3f95d..b3acc748ea7e842cb38f645b492cd67ae9ab33f4 100644 (file)
@@ -314,6 +314,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %token L3PROTOCOL              "l3proto"
 %token PROTO_SRC               "proto-src"
 %token PROTO_DST               "proto-dst"
+%token LABEL                   "label"
 
 %token COUNTER                 "counter"
 %token PACKETS                 "packets"
@@ -1551,6 +1552,7 @@ ct_key                    :       STATE           { $$ = NFT_CT_STATE; }
                        |       PROTOCOL        { $$ = NFT_CT_PROTOCOL; }
                        |       PROTO_SRC       { $$ = NFT_CT_PROTO_SRC; }
                        |       PROTO_DST       { $$ = NFT_CT_PROTO_DST; }
+                       |       LABEL           { $$ = NFT_CT_LABEL; }
                        ;
 
 payload_expr           :       payload_raw_expr
index e4cb398382ce78b86cfc3ab1307fa95f19e012cf..45c64763e4e7ec18f1507cf973a2c83063df04b0 100644 (file)
@@ -411,6 +411,7 @@ addrstring  ({macaddr}|{ip4addr}|{ip6addr})
 "l3proto"              { return L3PROTOCOL; }
 "proto-src"            { return PROTO_SRC; }
 "proto-dst"            { return PROTO_DST; }
+"label"                        { return LABEL; }
 
 "xml"                  { return XML; }
 "json"                 { return JSON; }