Hi, Please look at these patches:
bytestring-hex-prefix.patch - syntax with "hex:" prefix I allowed mixed colons with no-divider there, so hex:12:345678:90 is allowed. As there is a distinguishing prefix here, this should not be a problem. Empty bytestrings are allowed too: "hex:" bytestring-hex-function.patch - function-like hex("...") syntax (on top of the other patch) It wasn't too complex, but you might have wanted to do it some other way. I think this should be quite good too, the only problem with it is inability to mix "hex" symbol with hex("...") bytestrings. I parse string in two steps. First to know the length of a binary output. Current hex realization does the same anyway. I made a separate function for it to reuse it for "classic" bytestrings and for function-like syntax. It ignores all non-alphanumeric symbols and requires that each byte symbols go in pairs without delimiters. I added a HEX keyword and added it to kw_sym, but this solution does not allow to mix "hex" symbol and hex("...") bytestring in the same config. There probably was a mistake in nest/config.Y with missing "|" here: "kw_sym: MIN MAX ;" There is a "TODO" in the heading of strtobin.c, don't know what is your policy regarding that. The code is still based on the current BYTESTRING parser. I also enabled TEXT literals to be multiline. Didn't know it was not allowed already, so I think it should not break things, but allows to be more flexible with binary strings. On Tue, Jun 13, 2023 at 6:37 PM Ondrej Zajicek <santi...@crfreenet.org> wrote: > > On Tue, Jun 13, 2023 at 05:34:18PM +0200, Alexander Zubkov wrote: > > On Tue, Jun 13, 2023, 16:07 Ondrej Zajicek <santi...@crfreenet.org> wrote: > > > > > We agreed on keeping existing format for suffiently long hex bytestrings, > > > using hex: prefix for bytestrings of any length, and adding hex("...") / > > > base64("...") as ordinary expressions. > > > > Hi, > > > > So full house. :) I can try to implement it. Do you need a hand? > > If you implement hex: prefix, we could easily merge that. The > hex("...") / base64("...") is not priority and would require some > nontrivial changes to be done properly. > > -- > 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 a0d088b49510db8f968a99b7e1a5f7f1242e199d Author: Alexander Zubkov <gr...@qrator.net> Date: Tue Jun 13 22:19:28 2023 +0200 Conf: allow to provide a bytestring of any length with 'hex:' prefix diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 9555949d..9025a84d 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -255,12 +255,17 @@ WHITE [ \t] return IP4; } -{XIGIT}{2}((:{XIGIT}{2}){15,}|({XIGIT}{2}){15,}) { - char *s = yytext; +({XIGIT}{2}){16,}|{XIGIT}{2}(:{XIGIT}{2}){15,}|hex:({XIGIT}{2}(:?{XIGIT}{2})*)? { + char *s, *sb = yytext; size_t len = 0, i; 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; @@ -271,7 +276,7 @@ WHITE [ \t] bytes->length = len; b = &bytes->data[0]; - s = yytext; + s = sb; errno = 0; for (i = 0; i < len; i++) { *b = bstrtobyte16(s);
commit eead1fd2f7193bed2bbece8aeebfa04571030f6e Author: Alexander Zubkov <gr...@qrator.net> Date: Wed Jun 14 00:08:23 2023 +0200 Conf: new bytestring syntax hex("..."), allow multiline strings diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 9025a84d..dd607380 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 *str = yytext; + size_t len; 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++; - } + if (str[0] == 'h' && str[1] == 'e' && str[2] == 'x' && str[3] == ':') + str += 4; + + errno = 0; + len = bstrhextobin(str, 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(str, 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..4ee628de 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -10,6 +10,7 @@ CF_HDR #define PARSER 1 +#include <errno.h> #include "nest/bird.h" #include "conf/conf.h" #include "lib/resource.h" @@ -107,6 +108,7 @@ CF_DECLS %token <s> CF_SYM_KNOWN CF_SYM_UNDEFINED %token <t> TEXT %token <bs> BYTESTRING +%type <bs> bytestring %type <iface> ipa_scope %type <i> expr bool pxlen4 @@ -131,9 +133,12 @@ CF_DECLS %start config CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS, FROM) +CF_KEYWORDS(HEX) CF_GRAMMAR +kw_sym: HEX ; + /* Basic config file structure */ config: conf_entries END { return 0; } @@ -395,6 +400,27 @@ opttext: | /* empty */ { $$ = NULL; } ; +bytestring: + BYTESTRING + | HEX '(' TEXT ')' { + size_t len; + struct bytestring *bytes; + + errno = 0; + len = bstrhextobin($3, 0); + if (errno || len == (size_t)-1) + cf_error("Invalid hex string"); + + bytes = cfg_allocz(sizeof(*bytes) + len); + $$ = bytes; + + bytes->length = len; + bstrhextobin($3, bytes->data); + if (errno) + cf_error("Invalid hex string"); + } + ; + CF_CODE diff --git a/lib/Makefile b/lib/Makefile index 812f721c..f83a34eb 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 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 strtobin.c strtoul.c tbf.c timer.c xmalloc.c obj := $(src-o-files) $(all-daemon) diff --git a/lib/string.h b/lib/string.h index 2829943d..51c407c1 100644 --- a/lib/string.h +++ b/lib/string.h @@ -33,6 +33,8 @@ u64 bstrtoul10(const char *str, char **end); u64 bstrtoul16(const char *str, char **end); byte bstrtobyte16(const char *str); +int bstrhextobin(const char *s, byte *d); + int patmatch(const byte *pat, const byte *str); static inline char *xbasename(const char *str) diff --git a/lib/strtobin.c b/lib/strtobin.c new file mode 100644 index 00000000..7a4a04a6 --- /dev/null +++ b/lib/strtobin.c @@ -0,0 +1,52 @@ +/* + * BIRD Library -- Parse binary sequences + * + * (c) 2023 TODO + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include "nest/bird.h" +#include "lib/string.h" + +#include <errno.h> + +static int +is_alnum(char c) +{ + if (c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') + return 1; + else + return 0; +} + +int +bstrhextobin(const char *s, byte *d) +{ + size_t len = 0; + + while (*s) { + if (!is_alnum(s[0])) { + s++; + continue; + } + + if (!is_alnum(s[1])) { + errno = ERANGE; + return -1; + } + + if (d) { + errno = 0; + *d = bstrtobyte16(s); + if (errno) + return -1; + d++; + } + + s += 2; + len++; + } + + return len; +} diff --git a/nest/config.Y b/nest/config.Y index c83c715b..6721dd6f 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -126,6 +126,7 @@ CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS) CF_KEYWORDS(MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE) CF_KEYWORDS(CHECK, LINK) CF_KEYWORDS(SORTED, TRIE, MIN, MAX, SETTLE, TIME, GC, THRESHOLD, PERIOD) +CF_KEYWORDS(HEX) /* For r_args_channel */ CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC) @@ -154,7 +155,7 @@ CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6) CF_GRAMMAR -kw_sym: MIN MAX ; +kw_sym: MIN | MAX ; /* Setting of router ID */ @@ -548,7 +549,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 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..8f5fb2d0 100644 --- a/proto/radv/config.Y +++ b/proto/radv/config.Y @@ -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; }