]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filter: Add bytestring type
authorAlexander Zubkov <green@qrator.net>
Thu, 24 Aug 2023 02:30:42 +0000 (04:30 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Thu, 24 Aug 2023 02:33:33 +0000 (04:33 +0200)
 - Rename BYTESTRING lexem to BYTETEXT, not to collide with 'bytestring' type name
 - Add bytestring type with id T_BYTESTRING (0x2c)
 - Add from_hex() filter function to create bytestring from hex string
 - Add filter test cases for bytestring type

Minor changes by committer.

bird-gdb.py
conf/cf-lex.l
conf/confbase.Y
filter/config.Y
filter/data.c
filter/data.h
filter/f-inst.c
filter/f-inst.h
filter/test.conf
nest/config.Y
proto/radv/config.Y

index 3cf65a9cca0168fc9be709dfab49d2b8dfac7e63..262035dc393a9aed925a9cbac5d13349069f9d0a 100644 (file)
@@ -34,6 +34,7 @@ class BIRDFValPrinter(BIRDPrinter):
             "T_IP": "ip",
             "T_NET": "net",
             "T_STRING": "s",
+            "T_BYTESTRING": "bs",
             "T_PATH_MASK": "path_mask",
             "T_PATH": "ad",
             "T_CLIST": "ad",
index 965e1e3f98f406a4fb59ba8ddb453085d6351630..e789e8641586382f567a91300857a5b67840a6ba 100644 (file)
@@ -272,7 +272,7 @@ WHITE [ \t]
   ASSERT(bs->length == len);
 
   cf_lval.bs = bs;
-  return BYTESTRING;
+  return BYTETEXT;
 }
 
 ({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) {
index 3dd5fed7f0f36533e9770ffe2a7ba850fd08c840..da750d38164148c1911c106ae44ec57c5391c8d1 100644 (file)
@@ -106,7 +106,7 @@ CF_DECLS
 %token <i64> VPN_RD
 %token <s> CF_SYM_KNOWN CF_SYM_UNDEFINED
 %token <t> TEXT
-%token <bs> BYTESTRING
+%token <bs> BYTETEXT
 %type <iface> ipa_scope
 
 %type <i> expr bool pxlen4
index a1e5e9f17fd4bb31213b6ccdf3b063b009800d90..e2d133a9165b7816c813cce44a6231f292dae114 100644 (file)
@@ -301,7 +301,7 @@ CF_DECLS
 CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
        ACCEPT, REJECT, ERROR,
        INT, BOOL, IP, TYPE, PREFIX, RD, PAIR, QUAD, EC, LC,
-       SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
+       SET, STRING, BYTESTRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
        IF, THEN, ELSE, CASE,
        FOR, IN, DO,
        TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
@@ -317,13 +317,14 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
        MIN, MAX,
        EMPTY,
        FILTER, WHERE, EVAL, ATTRIBUTE,
+       FROM_HEX,
        BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT)
 
 %nonassoc THEN
 %nonassoc ELSE
 
 %type <xp> cmds_int cmd_prep
-%type <x> term cmd cmd_var cmds cmds_scoped constant constructor print_list var var_init var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail
+%type <x> term term_bs cmd cmd_var cmds cmds_scoped constant constructor print_list var var_init var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail
 %type <fda> dynamic_attr
 %type <fsa> static_attr
 %type <f> filter where_filter
@@ -404,6 +405,7 @@ type:
  | EC { $$ = T_EC; }
  | LC { $$ = T_LC; }
  | STRING { $$ = T_STRING; }
+ | BYTESTRING { $$ = T_BYTESTRING; }
  | BGPMASK { $$ = T_PATH_MASK; }
  | BGPPATH { $$ = T_PATH; }
  | CLIST { $$ = T_CLIST; }
@@ -714,13 +716,14 @@ bgp_path_tail:
  ;
 
 constant:
-   NUM    { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = $1, }); }
- | TRUE   { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 1, }); }
- | FALSE  { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 0, }); }
- | TEXT   { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_STRING, .val.s = $1, }); }
- | fipa          { $$ = f_new_inst(FI_CONSTANT, $1); }
- | VPN_RD { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_RD, .val.ec = $1, }); }
- | net_   { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_NET, .val.net = $1, }); }
+   NUM      { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = $1, }); }
+ | TRUE     { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 1, }); }
+ | FALSE    { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 0, }); }
+ | TEXT     { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_STRING, .val.s = $1, }); }
+ | BYTETEXT { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BYTESTRING, .val.bs = $1, }); }
+ | fipa     { $$ = f_new_inst(FI_CONSTANT, $1); }
+ | VPN_RD   { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_RD, .val.ec = $1, }); }
+ | net_     { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_NET, .val.net = $1, }); }
  | '[' ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_SET, .val.t = NULL, }); }
  | '[' set_items ']' {
      DBG( "We've got a set here..." );
@@ -868,9 +871,14 @@ term:
 
 /* | term '.' LEN { $$->code = P('P','l'); } */
 
+ | term_bs
  | function_call
  ;
 
+term_bs:
+   FROM_HEX '(' term ')' { $$ = f_new_inst(FI_FROM_HEX, $3); }
+ ;
+
 break_command:
    ACCEPT { $$ = F_ACCEPT; }
  | REJECT { $$ = F_REJECT; }
index 56d746fde6db418160004cd3e2efb68ebb43bfd6..1d740b0d8761898dec10e6f9e08af6ee5b094464 100644 (file)
@@ -46,6 +46,7 @@ static const char * const f_type_str[] = {
   [T_IP]       = "ip",
   [T_NET]      = "prefix",
   [T_STRING]   = "string",
+  [T_BYTESTRING]       = "bytestring",
   [T_PATH_MASK]        = "bgpmask",
   [T_PATH]     = "bgppath",
   [T_CLIST]    = "clist",
@@ -222,6 +223,12 @@ val_compare(const struct f_val *v1, const struct f_val *v2)
   }
 }
 
+static inline int
+bs_same(const struct bytestring *bs1, const struct bytestring *bs2)
+{
+  return (bs1->length == bs2->length) && !memcmp(bs1->data, bs2->data, bs1->length);
+}
+
 static inline int
 pmi_same(const struct f_path_mask_item *mi1, const struct f_path_mask_item *mi2)
 {
@@ -286,6 +293,8 @@ val_same(const struct f_val *v1, const struct f_val *v2)
     return 0;
 
   switch (v1->type) {
+  case T_BYTESTRING:
+    return bs_same(v1->val.bs, v2->val.bs);
   case T_PATH_MASK:
     return pm_same(v1->val.path_mask, v2->val.path_mask);
   case T_PATH_MASK_ITEM:
@@ -585,6 +594,7 @@ val_format(const struct f_val *v, buffer *buf)
   case T_BOOL: buffer_puts(buf, v->val.i ? "TRUE" : "FALSE"); return;
   case T_INT:  buffer_print(buf, "%u", v->val.i); return;
   case T_STRING: buffer_print(buf, "%s", v->val.s); return;
+  case T_BYTESTRING: bstrbintohex(v->val.bs->data, v->val.bs->length, buf2, 1000, ':'); buffer_print(buf, "%s", buf2); return;
   case T_IP:   buffer_print(buf, "%I", v->val.ip); return;
   case T_NET:   buffer_print(buf, "%N", v->val.net); return;
   case T_PAIR: buffer_print(buf, "(%u,%u)", v->val.i >> 16, v->val.i & 0xffff); return;
index b3767f7bc7d58df3150297923d0551f8cb6f88c1..f44e08e18d7b6d62b82d0bdd24d23cbc68cdcaad 100644 (file)
@@ -58,6 +58,7 @@ enum f_type {
   T_LCLIST = 0x29,             /* Large community list */
   T_RD = 0x2a,         /* Route distinguisher for VPN addresses */
   T_PATH_MASK_ITEM = 0x2b,     /* Path mask item for path mask constructors */
+  T_BYTESTRING = 0x2c,
 
   T_SET = 0x80,
   T_PREFIX_SET = 0x81,
@@ -73,6 +74,7 @@ struct f_val {
     ip_addr ip;
     const net_addr *net;
     const char *s;
+    const struct bytestring *bs;
     const struct f_tree *t;
     const struct f_trie *ti;
     const struct adata *ad;
index 33436853eaa811557d3fabf690ff5e2c0fc2a3f0..8a2f474e1a46aaa40c61c1e3b43ab36cc6d3c29a 100644 (file)
 
   }
 
+  INST(FI_FROM_HEX, 1, 1) {    /* Convert hex text to bytestring */
+    ARG(1, T_STRING);
+
+    int len = bstrhextobin(v1.val.s, NULL);
+    if (len < 0)
+      runtime("Invalid hex string");
+
+    struct bytestring *bs;
+    bs = falloc(sizeof(struct bytestring) + len);
+    bs->length = bstrhextobin(v1.val.s, bs->data);
+    ASSERT(bs->length == (size_t) len);
+
+    RESULT(T_BYTESTRING, bs, bs);
+  }
+
   INST(FI_FORMAT, 1, 1) {      /* Format */
     ARG_ANY(1);
     RESULT(T_STRING, s, val_format_str(fpool, &v1));
index 72b080f808c2a97aa27e144c14c15d65f243d281..3912df089e324affb8dc2be3d0823a9b7e0a654e 100644 (file)
@@ -19,6 +19,7 @@
 #include "filter/data.h"
 #include "lib/buffer.h"
 #include "lib/flowspec.h"
+#include "lib/string.h"
 
 /* Flags for instructions */
 enum f_instruction_flags {
index e9e3af899375771a88e9f045ec299b435128d331..c014dadd52c872b95c4e1de0181e9ad0897c5647 100644 (file)
@@ -237,6 +237,36 @@ bt_test_suite(t_string, "Testing string matching");
 
 
 
+/*
+ *     Testing bytestings
+ *     ------------------
+ */
+
+function t_bytestring()
+{
+       bytestring bs1 = hex:;
+       bytestring bs2 = hex:0112233445566778899aabbccddeeff0;
+
+       bt_assert(format(bs1) = "");
+       bt_assert(format(bs2) = "01:12:23:34:45:56:67:78:89:9a:ab:bc:cd:de:ef:f0");
+       bt_assert(hex:01:12:23:34:45:56:67:78:89:9a:ab:bc:cd:de:ef:f0 = bs2);
+       bt_assert(01:12:23:34:45:56:67:78:89:9a:ab:bc:cd:de:ef:f0 = bs2);
+       bt_assert(0112233445566778899aabbccddeeff0 = bs2);
+       bt_assert(hex:01234567 = hex:01:23:45:67);
+       bt_assert(hex:0123456789abcdef != bs2);
+       bt_assert(hex:0123456789abcdef != hex:0123);
+       bt_assert(format(hex:0123456789abcdef) = "01:23:45:67:89:ab:cd:ef");
+       bt_assert(from_hex(" ") = bs1);
+       bt_assert(from_hex("01:12:23:34:45:56:67:78:89:9a:ab:bc:cd:de:ef:f0") = bs2);
+       bt_assert(from_hex(format(bs2)) = bs2);
+       bt_assert(from_hex(" 0112:23-34455667 78-89 - 9a-ab bc:cd : de:eff0 ") = bs2);
+}
+
+bt_test_suite(t_bytestring, "Testing bytestrings");
+
+
+
+
 /*
  *     Testing pairs
  *     -------------
index c83c715b9e0ca0c897bb59f356cb4d68224eeb80..9197f98535cd430b06697df74e83cb6029ed67c7 100644 (file)
@@ -548,7 +548,7 @@ pass_key: PASSWORD | KEY;
 
 password_item_begin:
     pass_key text { init_password_list(); init_password($2, strlen($2), password_id++); }
-  | pass_key BYTESTRING { init_password_list(); init_password($2->data, $2->length, password_id++); }
+  | pass_key BYTETEXT { init_password_list(); init_password($2->data, $2->length, password_id++); }
 ;
 
 password_item_params:
index eeafe6f454a8ba439217ffc168738a661eaaee15..9653cd7becd971b53a4fe101158f2e02edf51928 100644 (file)
@@ -73,7 +73,7 @@ radv_proto_item:
  | PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); }
  | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); }
  | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); }
- | CUSTOM OPTION TYPE expr VALUE BYTESTRING { radv_add_to_custom_list(&RADV_CFG->custom_list, $4, $6); }
+ | CUSTOM OPTION TYPE expr VALUE BYTETEXT { radv_add_to_custom_list(&RADV_CFG->custom_list, $4, $6); }
  | TRIGGER net_ip6 { RADV_CFG->trigger = $2; }
  | PROPAGATE ROUTES bool { RADV_CFG->propagate_routes = $3; }
  ;
@@ -138,7 +138,7 @@ radv_iface_item:
  | PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); }
  | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); }
  | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); }
- | CUSTOM OPTION TYPE expr VALUE BYTESTRING { radv_add_to_custom_list(&RADV_IFACE->custom_list, $4, $6); }
+ | CUSTOM OPTION TYPE expr VALUE BYTETEXT { radv_add_to_custom_list(&RADV_IFACE->custom_list, $4, $6); }
  | RDNSS LOCAL bool { RADV_IFACE->rdnss_local = $3; }
  | DNSSL LOCAL bool { RADV_IFACE->dnssl_local = $3; }
  | CUSTOM OPTION LOCAL bool { RADV_IFACE->custom_local = $4; }