On Thu, Jul 02, 2026 at 01:12:00AM +0200, Stefano Brivio wrote:
On Wed, 1 Jul 2026 15:31:55 +1000 David Gibson
wrote: +++ b/parse.c @@ -18,6 +18,7 @@ #include
#include #include +#include #include "common.h" #include "parse.h" @@ -213,3 +214,31 @@ bool parse_inany_(const char **cursor, union inany_addr *addr,
return false; } + +/** + * parse_ifspec() - Parse a interface name specifier (starting with %) + * @ifname: On success updated with parsed name (must have IFNAMSIZ space) + * + * This will accept a missing specifier (empty string), setting ifname to "" + */ +bool parse_ifspec(const char **cursor, char *ifname) +{ + const char *p = *cursor; + size_t len; + + if (!parse_literal(&p, "%")) { + /* No interface specifier */ + ifname[0] = '\0'; + return true; + } + + /* ifnames can have anything that's not '/', '.' or whitespace */ + len = strcspn(p, "/. \f\n\r\t\v");
I was about to apply the series when I spotted this: '.' is definitely valid in interface names, and even commonly used (think of VLANs), it's just "." and ".." _as an interface name_ that are not supported.
Oh, right, I misuderstood. Should have looked at the kernel code myself to confirm, oops.
If we forbid any interface name with '.' we might very well break somebody's use case. I can fix this up with:
/* ifnames can't contain /, :, or whitespace */ len = strcspn(p, "/: \f\n\r\t\v"); if (!len || len >= IFNAMSIZ) return false;
/* ...and they can't be '..' or '.' either */ if (!strcmp(p, ".") || !strcmp(p, "..")) return false;
if you're fine with it
That won't quite work: the string doesn't end at the end of the interface name. Plus, in my experience you get much better error reporting if you generally try to lexically accept as *much* as possible, then validate, rather than restricting the parser to only accept the minimum it must. I've added a validation of the parsed ifname up in fwd_rule_parse(), instead. I'll post the new spin momentarily. .
+ if (!len || len >= IFNAMSIZ) + return false; + + memcpy(ifname, p, len); + ifname[len] = '\0'; + *cursor = p + len; + return true; +} diff --git a/parse.h b/parse.h index ab1d5adb..257b9c58 100644 --- a/parse.h +++ b/parse.h @@ -32,4 +32,6 @@ bool parse_inany_(const char **cursor, union inany_addr *addr,
#define parse_inany(cursor, addr) parse_inany_((cursor), (addr), NULL)
+bool parse_ifspec(const char **cursor, char *ifname); + #endif /* _PARSE_H */
-- Stefano
-- David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibson