On Sat, Jun 24, 2023 at 3:16 PM Ondrej Zajicek <santi...@crfreenet.org> wrote:
>
> On Sat, Jun 24, 2023 at 02:20:03AM +0200, Alexander Zubkov wrote:
> > > Yes, the original idea there was to add bytestring as a data type, make
> > > hex() a regular (filter) function instead of special function-like
> > > syntax, and add equivalent of 'expr' grammar term for other data types.
> > >
> >
> > I see. I think I can look into preparing a patch for that too.
> > But for such variant I would suggest using function names like
> > "from_hex/base64" instead of "hex/base64", or something including
> > bytestring reference: "bs_hex". Because the simple variants could be
> > misleading when used not only in the limited set of scopes.
> > they can be thought of converting to hex/base64 representation too. Or they
> > could collide with "hex" function to convert from string to int, which
> > someone would need to implement in the future.
>
> Yes, that is true.
>
> You can try it if you are brave enough to add new f_val type.

Take a look at the patch, please. Waiting for the critics and
improvement suggestions.

Some remarks:
It was needed to add another function like f_eval_int(), so I decided
to do some more generic approach and replaced all occurences of
f_eval_int() with it.
Bytestrings for password caused conflicts with strings on being
presented as symbol names. Insted of adding something like
"string_or_bytestring", I decided to allow bytestring term to be
derived from strings too.
I also used different approach from "expr", where it evaluates only
complex expressions. I decided that handling constants and symbols via
evalutation would be easier. So I have special case only for literals.
There is separate "term_bs" term, so that it is possible to use
"from_hex()" without outer brackets.
Again, added a new file in lib dir for bytestrings.
And I changed some struct bytestring pointers to const struct bytestring.

>
>
> > > > I think this should be quite good too, the only problem with it
> > > > is inability to mix "hex" symbol with hex("...") bytestrings.
> > >
> > > This is an issue with any keyword, so not a big thing.
> > >
> >
> > Yes. By the way what do you think about the patch that allows using
> > keywords and symbols together? Is it viable?
>
> Answered there.
>
>
> --
> Elen sila lumenn' omentielvo
>
> Ondrej 'Santiago' Zajicek (email: santi...@crfreenet.org)
> OpenPGP encrypted e-mails preferred (KeyID 0x11DEADC3, wwwkeys.pgp.net)
> "To err is human -- to blame it on a computer is even more so."
commit 7cc6700c64e94019df1743de685c84dbca85b406
Author: Alexander Zubkov <gr...@qrator.net>
Date:   Mon Jun 26 02:38:54 2023 +0200

    Conf: make bytestring a type

diff --git a/bird-gdb.py b/bird-gdb.py
index 3cf65a9c..262035dc 100644
--- a/bird-gdb.py
+++ b/bird-gdb.py
@@ -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",
diff --git a/conf/cf-lex.l b/conf/cf-lex.l
index 9025a84d..59b88bd5 100644
--- a/conf/cf-lex.l
+++ b/conf/cf-lex.l
@@ -256,37 +256,26 @@ WHITE [ \t]
 }
 
 ({XIGIT}{2}){16,}|{XIGIT}{2}(:{XIGIT}{2}){15,}|hex:({XIGIT}{2}(:?{XIGIT}{2})*)? {
-  char *s, *sb = yytext;
-  size_t len = 0, i;
+  char *sb = yytext;
+  size_t len = 0;
   struct bytestring *bytes;
-  byte *b;
 
   /* skip 'hex:' prefix */
   if (sb[0] == 'h' && sb[1] == 'e' && sb[2] == 'x' && sb[3] == ':')
     sb += 4;
 
-  s = sb;
-  while (*s) {
-    len++;
-    s += 2;
-    if (*s == ':')
-      s++;
-  }
+  errno = 0;
+  len = bstrhextobin(sb, 0);
+  if (errno || len == (size_t)-1)
+    cf_error("Invalid hex string");
+
   bytes = cfg_allocz(sizeof(*bytes) + len);
 
   bytes->length = len;
-  b = &bytes->data[0];
-  s = sb;
-  errno = 0;
-  for (i = 0; i < len; i++) {
-    *b = bstrtobyte16(s);
-    if (errno == ERANGE)
-      cf_error("Invalid hex string");
-    b++;
-    s += 2;
-    if (*s == ':')
-      s++;
-  }
+  bstrhextobin(sb, bytes->data);
+  if (errno)
+    cf_error("Invalid hex string");
+
   cf_lval.bs = bytes;
   return BYTESTRING;
 }
@@ -361,7 +350,6 @@ else: {
   quoted_buffer_init();
 }
 
-<QUOTED>\n	cf_error("Unterminated string");
 <QUOTED><<EOF>> cf_error("Unterminated string");
 <QUOTED>["]	{
   BEGIN(INITIAL);
@@ -370,7 +358,7 @@ else: {
   return TEXT;
 }
 
-<QUOTED>.	BUFFER_PUSH(quoted_buffer) = yytext[0];
+<QUOTED>(.|\n)	BUFFER_PUSH(quoted_buffer) = yytext[0];
 
 <INITIAL,COMMENT><<EOF>>	{ if (check_eof()) return END; }
 
diff --git a/conf/confbase.Y b/conf/confbase.Y
index 3e8f5807..ebaa93b8 100644
--- a/conf/confbase.Y
+++ b/conf/confbase.Y
@@ -94,7 +94,7 @@ CF_DECLS
   struct channel_limit cl;
   struct timeformat *tf;
   mpls_label_stack *mls;
-  struct bytestring *bs;
+  const struct bytestring *bs;
 }
 
 %token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT
@@ -117,9 +117,12 @@ CF_DECLS
 %type <mls> label_stack_start label_stack
 
 %type <t> text opttext
+%type <bs> bytestring
 %type <s> symbol
 %type <kw> kw_sym
 
+%type <x> bytestring_inst
+
 %nonassoc PREFIX_DUMMY
 %left AND OR
 %nonassoc '=' '<' '>' '~' GEQ LEQ NEQ NMA PO PC
@@ -155,14 +158,14 @@ conf: definition ;
 definition:
    DEFINE symbol '=' term ';' {
      struct f_val *val = cfg_allocz(sizeof(struct f_val));
-     if (f_eval(f_linearize($4, 1), cfg_mem, val) > F_RETURN) cf_error("Runtime error");
+     f_eval_conf($4, val, T_VOID);
      cf_define_symbol($2, SYM_CONSTANT | val->type, val, val);
    }
  ;
 
 expr:
    NUM
- | '(' term ')' { $$ = f_eval_int(f_linearize($2, 1)); }
+ | '(' term ')' { $$ = f_eval_val($2, T_INT, i); }
  | CF_SYM_KNOWN {
      if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected");
      $$ = SYM_VAL($1).i; }
@@ -395,6 +398,43 @@ opttext:
  | /* empty */ { $$ = NULL; }
  ;
 
+bytestring:
+   BYTESTRING
+ | TEXT {
+     int len = strlen($1);
+     struct bytestring *bs = cfg_allocz(sizeof(*bs) + len);
+     $$ = bs;
+     bs->length = len;
+     memcpy(bs->data, $1, len);
+   }
+ | bytestring_inst {
+     struct f_val val;
+     f_eval_conf($1, &val, T_VOID);
+
+     switch (val.type) {
+       case T_BYTESTRING:
+	 $$ = val.val.bs;
+	 break;
+
+       case T_STRING:
+	 int len = strlen(val.val.s);
+	 struct bytestring *bs = cfg_allocz(sizeof(*bs) + len);
+	 $$ = bs;
+	 bs->length = len;
+	 memcpy(bs->data, val.val.s, len);
+	 break;
+
+       default:
+	 cf_error("Bytestring value is expected");
+     }
+   }
+ ;
+
+bytestring_inst:
+   symbol_value
+ | term_bs
+ | '(' term ')' { $$ = $2; }
+ ;
 
 CF_CODE
 
diff --git a/filter/config.Y b/filter/config.Y
index a1e5e9f1..6718fb78 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -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
@@ -343,6 +344,8 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
 
 CF_GRAMMAR
 
+kw_sym: FROM_HEX ;
+
 conf: filter_def ;
 filter_def:
    FILTER symbol { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); }
@@ -357,7 +360,7 @@ filter_def:
 
 conf: filter_eval ;
 filter_eval:
-   EVAL term { f_eval_int(f_linearize($2, 1)); }
+   EVAL term { f_eval_val($2, T_INT, i); }
  ;
 
 conf: custom_attr ;
@@ -404,6 +407,7 @@ type:
  | EC { $$ = T_EC; }
  | LC { $$ = T_LC; }
  | STRING { $$ = T_STRING; }
+ | BYTESTRING { $$ = T_BYTESTRING; }
  | BGPMASK { $$ = T_PATH_MASK; }
  | BGPPATH { $$ = T_PATH; }
  | CLIST { $$ = T_CLIST; }
@@ -571,7 +575,7 @@ set_atom:
  | VPN_RD { $$.type = T_RD; $$.val.ec = $1; }
  | ENUM   { $$.type = pair_a($1); $$.val.i = pair_b($1); }
  | '(' term ')' {
-     if (f_eval(f_linearize($2, 1), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
+     f_eval_conf($2, &($$), T_VOID);
      if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
    }
  | CF_SYM_KNOWN {
@@ -583,13 +587,13 @@ set_atom:
 
 switch_atom:
    NUM   { $$.type = T_INT; $$.val.i = $1; }
- | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2, 1)); }
+ | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_val($2, T_INT, i); }
  | fipa  { $$ = $1; }
  | ENUM  { $$.type = pair_a($1); $$.val.i = pair_b($1); }
  ;
 
 cnum:
-   term { $$ = f_eval_int(f_linearize($1, 1)); }
+   term { $$ = f_eval_val($1, T_INT, i); }
 
 pair_item:
    '(' cnum ',' cnum ')'		{ $$ = f_new_pair_item($2, $2, $4, $4); }
@@ -714,13 +718,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, }); }
+ | BYTESTRING { $$ = 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 +873,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; }
diff --git a/filter/data.c b/filter/data.c
index 56d746fd..62573f4e 100644
--- a/filter/data.c
+++ b/filter/data.c
@@ -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",
@@ -286,6 +287,8 @@ val_same(const struct f_val *v1, const struct f_val *v2)
     return 0;
 
   switch (v1->type) {
+  case T_BYTESTRING:
+    return v1->val.bs->length == v2->val.bs->length && !memcmp(v1->val.bs->data, v2->val.bs->data, v1->val.bs->length);
   case T_PATH_MASK:
     return pm_same(v1->val.path_mask, v2->val.path_mask);
   case T_PATH_MASK_ITEM:
@@ -585,6 +588,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, 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;
diff --git a/filter/data.h b/filter/data.h
index b3767f7b..f44e08e1 100644
--- a/filter/data.h
+++ b/filter/data.h
@@ -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;
diff --git a/filter/f-inst.c b/filter/f-inst.c
index 33436853..565aa2a9 100644
--- a/filter/f-inst.c
+++ b/filter/f-inst.c
@@ -1555,6 +1555,27 @@
 
   }
 
+  INST(FI_FROM_HEX, 1, 1) {	/* Convert hex text to bytestring */
+    ARG(1, T_STRING);
+
+    size_t len;
+    struct bytestring *bs;
+
+    errno = 0;
+    len = bstrhextobin(v1.val.s, 0);
+    if (errno || len == (size_t)-1)
+      runtime("Invalid hex string");
+
+    bs = falloc(sizeof(*bs) + len);
+    bs->length = len;
+
+    bstrhextobin(v1.val.s, bs->data);
+    if (errno)
+      runtime("Invalid hex string");
+
+    RESULT(T_BYTESTRING, bs, bs);
+  }
+
   INST(FI_FORMAT, 1, 1) {	/* Format */
     ARG_ANY(1);
     RESULT(T_STRING, s, val_format_str(fpool, &v1));
diff --git a/filter/f-inst.h b/filter/f-inst.h
index 72b080f8..185c01ac 100644
--- a/filter/f-inst.h
+++ b/filter/f-inst.h
@@ -13,12 +13,15 @@
 #ifndef _BIRD_F_INST_H_
 #define _BIRD_F_INST_H_
 
+#include <errno.h>
+
 #include "nest/bird.h"
 #include "conf/conf.h"
 #include "filter/filter.h"
 #include "filter/data.h"
 #include "lib/buffer.h"
 #include "lib/flowspec.h"
+#include "lib/string.h"
 
 /* Flags for instructions */
 enum f_instruction_flags {
diff --git a/filter/filter.c b/filter/filter.c
index 20a380dc..2d19f438 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -373,30 +373,18 @@ f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres)
 }
 
 /*
- * f_eval_int - get an integer value of a term
+ * f_eval_conf - evaluate a value of a term and check its type
  * Called internally from the config parser, uses its internal memory pool
  * for allocations. Do not call in other cases.
  */
-uint
-f_eval_int(const struct f_line *expr)
+void
+f_eval_conf(const struct f_inst *inst, struct f_val *val, int type)
 {
-  /* Called independently in parse-time to eval expressions */
-  filter_state = (struct filter_state) {
-    .stack = &filter_stack,
-    .pool = cfg_mem,
-  };
-
-  struct f_val val;
-
-  LOG_BUFFER_INIT(filter_state.buf);
-
-  if (interpret(&filter_state, expr, &val) > F_RETURN)
+  if (f_eval(f_linearize(inst, 1), cfg_mem, val) > F_RETURN)
     cf_error("Runtime error while evaluating expression; see log for details");
 
-  if (val.type != T_INT)
-    cf_error("Integer expression expected");
-
-  return val.val.i;
+  if (type != T_VOID && val->type != type)
+    cf_error("Expression of type %s expected", f_type_name(type));
 }
 
 /*
diff --git a/filter/filter.h b/filter/filter.h
index 26c1037b..6e54b4ad 100644
--- a/filter/filter.h
+++ b/filter/filter.h
@@ -43,6 +43,7 @@ static inline const char *filter_return_str(const enum filter_return fret) {
 struct f_val;
 
 /* The filter encapsulating structure to be pointed-to from outside */
+struct f_inst;
 struct f_line;
 struct filter {
   struct symbol *sym;
@@ -53,9 +54,14 @@ struct rte;
 
 enum filter_return f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags);
 enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool);
-uint f_eval_int(const struct f_line *expr);
+void f_eval_conf(const struct f_inst *inst, struct f_val *val, int type);
 enum filter_return f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf);
 
+#define f_eval_val(from_, type_, name_) ({ \
+    struct f_val val; \
+    f_eval_conf(from_, &val, type_); \
+    val.val.name_; })
+
 const char *filter_name(const struct filter *filter);
 int filter_same(const struct filter *new, const struct filter *old);
 int f_same(const struct f_line *f1, const struct f_line *f2);
diff --git a/filter/test.conf b/filter/test.conf
index e9e3af89..819e15a1 100644
--- a/filter/test.conf
+++ b/filter/test.conf
@@ -237,6 +237,27 @@ bt_test_suite(t_string, "Testing string matching");
 
 
 
+/*
+ * 	Testing bytestings
+ * 	------------------
+ */
+
+function t_bytestring()
+{
+	bytestring bs1 = hex:;
+	bytestring bs2 = hex:00112233445566778899aabbccddeeff;
+
+	bt_assert(format(bs1) = "hex:");
+	bt_assert(hex:00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff = bs2);
+	bt_assert(00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff = bs2);
+	bt_assert(00112233445566778899aabbccddeeff = bs2);
+	bt_assert(format(hex:0123456789abcdef) = "hex:01:23:45:67:89:ab:cd:ef");
+	bt_assert(from_hex(" ") = bs1);
+	bt_assert(from_hex(" 0011:2233-44556677 88-99 - aa-bb cc:dd : ee:ff ") = bs1);
+}
+
+bt_test_suite(t_bytestring, "Testing bytestrings");
+
 /*
  * 	Testing pairs
  * 	-------------
diff --git a/lib/Makefile b/lib/Makefile
index 812f721c..296152ff 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,4 +1,4 @@
-src := bitmap.c bitops.c blake2s.c blake2b.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
+src := bitmap.c bitops.c blake2s.c blake2b.c bytestring.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
 obj := $(src-o-files)
 $(all-daemon)
 
diff --git a/lib/bytestring.c b/lib/bytestring.c
new file mode 100644
index 00000000..f25c9398
--- /dev/null
+++ b/lib/bytestring.c
@@ -0,0 +1,93 @@
+/*
+ *     BIRD Library -- Work with binary sequences
+ *
+ *     (c) 2023 TODO
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+
+#include "nest/bird.h"
+#include "lib/string.h"
+#include "conf/conf.h"
+
+char
+toxdigit(int b)
+{
+  if (b >= 0 && b <= 9)
+    return ('0' + b);
+  else if (b >= 10 && b < 16)
+    return ('a' + b - 10);
+  else
+    return 0;
+}
+
+int
+bstrhextobin(const char *s, byte *d)
+{
+  size_t len = 0;
+
+  while (*s) {
+    if (!isalnum(s[0])) {
+      s++;
+      continue;
+    }
+
+    if (!isalnum(s[1])) {
+      errno = ERANGE;
+      return -1;
+    }
+
+    if (d) {
+      errno = 0;
+      *d = bstrtobyte16(s);
+      if (errno)
+        return -1;
+      d++;
+    }
+
+    s += 2;
+    len++;
+  }
+
+  return len;
+}
+
+int
+bstrbintohex(const struct bytestring *bs, byte *buf, uint size)
+{
+  if (size < 8)
+    return -1;
+
+  size_t len = bs->length;
+  const byte *b = bs->data;
+
+  byte *end = buf + size - 4;
+
+  memcpy(buf, "hex", 3);
+  buf += 3;
+
+  if (!len) {
+    strcpy(buf, ":");
+    return 0;
+  }
+
+  size_t i;
+  for (i = 0; i < len && buf + 3 <= end; ++i, buf += 3) {
+    byte x = b[i];
+    buf[0] = ':';
+    buf[1] = toxdigit(x >> 4);
+    buf[2] = toxdigit(x & 0xF);
+  }
+
+  if (i < len) {
+    strcpy(buf, "...");
+    return -1;
+  }
+
+  *buf = 0;
+
+  return 0;
+}
diff --git a/lib/string.h b/lib/string.h
index 2829943d..62f03eb6 100644
--- a/lib/string.h
+++ b/lib/string.h
@@ -33,6 +33,10 @@ u64 bstrtoul10(const char *str, char **end);
 u64 bstrtoul16(const char *str, char **end);
 byte bstrtobyte16(const char *str);
 
+struct bytestring;
+int bstrhextobin(const char *s, byte *d);
+int bstrbintohex(const struct bytestring *bs, byte *buf, uint size);
+
 int patmatch(const byte *pat, const byte *str);
 
 static inline char *xbasename(const char *str)
diff --git a/nest/config.Y b/nest/config.Y
index c83c715b..49222442 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -167,7 +167,7 @@ rtrid:
 
 idval:
    NUM { $$ = $1; }
- | '(' term ')' { $$ = f_eval_int(f_linearize($2, 1)); }
+ | '(' term ')' { $$ = f_eval_val($2, T_INT, i); }
  | IP4 { $$ = ip4_to_u32($1); }
  | CF_SYM_KNOWN {
      if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD))
@@ -547,8 +547,7 @@ password_item:
 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 bytestring { init_password_list(); init_password($2->data, $2->length, password_id++); }
 ;
 
 password_item_params:
diff --git a/proto/radv/config.Y b/proto/radv/config.Y
index 5c213d50..3213403a 100644
--- a/proto/radv/config.Y
+++ b/proto/radv/config.Y
@@ -26,7 +26,7 @@ static list radv_dns_list;	/* Used by radv_rdnss and radv_dnssl */
 static u8 radv_mult_val;	/* Used by radv_mult for second return value */
 
 static inline void
-radv_add_to_custom_list(list *l, int type, struct bytestring *payload)
+radv_add_to_custom_list(list *l, int type, const struct bytestring *payload)
 {
   if (type < 0 || type > 255) cf_error("RA cusom type must be in range 0-255");
   struct radv_custom_config *cf = cfg_allocz(sizeof(struct radv_custom_config));
@@ -71,7 +71,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); }
- | OTHER TYPE expr BYTESTRING { radv_add_to_custom_list(&RADV_CFG->custom_list, $3, $4); }
+ | OTHER TYPE expr bytestring { radv_add_to_custom_list(&RADV_CFG->custom_list, $3, $4); }
  | TRIGGER net_ip6 { RADV_CFG->trigger = $2; }
  | PROPAGATE ROUTES bool { RADV_CFG->propagate_routes = $3; }
  ;
@@ -136,7 +136,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); }
- | OTHER TYPE expr BYTESTRING { radv_add_to_custom_list(&RADV_IFACE->custom_list, $3, $4); }
+ | OTHER TYPE expr bytestring { radv_add_to_custom_list(&RADV_IFACE->custom_list, $3, $4); }
  | RDNSS LOCAL bool { RADV_IFACE->rdnss_local = $3; }
  | DNSSL LOCAL bool { RADV_IFACE->dnssl_local = $3; }
  | OTHER LOCAL bool { RADV_IFACE->custom_local = $3; }
diff --git a/proto/radv/radv.h b/proto/radv/radv.h
index 8c716158..2baf0bad 100644
--- a/proto/radv/radv.h
+++ b/proto/radv/radv.h
@@ -129,7 +129,7 @@ struct radv_custom_config
 {
   node n;
   u8 type;			/* Identifier of the type of option */
-  struct bytestring *payload;	/* Payload of the option */
+  const struct bytestring *payload;	/* Payload of the option */
 };
 
 /*

Reply via email to