diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 45327cd9..593df9d6 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -168,7 +168,7 @@ WHITE [ \t] char *e; errno = 0; - l = strtoul(yytext, &e, 10); + l = bstrtoul(yytext, &e, 10); if (e && (*e != ':') || (errno == ERANGE) || (l >> 32)) cf_error("ASN out of range"); @@ -186,7 +186,7 @@ WHITE [ \t] } errno = 0; - l = strtoul(e+1, &e, 10); + l = bstrtoul(e+1, &e, 10); if (e && *e || (errno == ERANGE) || (l >> len2)) cf_error("Number out of range"); cf_lval.i64 |= l; @@ -213,13 +213,13 @@ WHITE [ \t] } errno = 0; - l = strtoul(yytext+2, &e, 10); + l = bstrtoul(yytext+2, &e, 10); if (e && (*e != ':') || (errno == ERANGE) || (l >> len1)) cf_error("ASN out of range"); cf_lval.i64 |= ((u64) l) << len2; errno = 0; - l = strtoul(e+1, &e, 10); + l = bstrtoul(e+1, &e, 10); if (e && *e || (errno == ERANGE) || (l >> len2)) cf_error("Number out of range"); cf_lval.i64 |= l; @@ -241,7 +241,7 @@ WHITE [ \t] cf_lval.i64 |= ((u64) ip4_to_u32(ip4)) << 16; errno = 0; - l = strtoul(e, &e, 10); + l = bstrtoul(e, &e, 10); if (e && *e || (errno == ERANGE) || (l >> 16)) cf_error("Number out of range"); cf_lval.i64 |= l; @@ -265,7 +265,7 @@ WHITE [ \t] char *e; unsigned long int l; errno = 0; - l = strtoul(yytext+2, &e, 16); + l = bstrtoul(yytext+2, &e, 16); if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l) cf_error("Number out of range"); cf_lval.i = l; @@ -276,7 +276,7 @@ WHITE [ \t] char *e; unsigned long int l; errno = 0; - l = strtoul(yytext, &e, 10); + l = bstrtoul(yytext, &e, 10); if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l) cf_error("Number out of range"); cf_lval.i = l; diff --git a/lib/Makefile b/lib/Makefile index 01f3114d..18816bb3 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,4 +1,4 @@ -src := bitops.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 tbf.c timer.c xmalloc.c +src := bitops.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/ip.c b/lib/ip.c index 9497248c..0f5a5348 100644 --- a/lib/ip.c +++ b/lib/ip.c @@ -245,7 +245,7 @@ ip4_pton(const char *a, ip4_addr *o) char *d, *c = strchr(a, '.'); if (!c != !i) return 0; - l = strtoul(a, &d, 10); + l = bstrtoul(a, &d, 10); if (((d != c) && *d) || (l > 255)) return 0; ia = (ia << 8) | l; diff --git a/lib/string.h b/lib/string.h index 0d34f9c5..5f7c4666 100644 --- a/lib/string.h +++ b/lib/string.h @@ -24,6 +24,10 @@ int buffer_vprint(buffer *buf, const char *fmt, va_list args); int buffer_print(buffer *buf, const char *fmt, ...); void buffer_puts(buffer *buf, const char *str); +#define bstrtoul(str, end, base) bstrtoul##base(str, end) +u64 bstrtoul10(const char *str, char **end); +u64 bstrtoul16(const char *str, char **end); + int patmatch(const byte *pat, const byte *str); static inline char *xbasename(const char *str) diff --git a/lib/strtoul.c b/lib/strtoul.c new file mode 100644 index 00000000..44a1bb1d --- /dev/null +++ b/lib/strtoul.c @@ -0,0 +1,61 @@ +/* + * BIRD Library -- Parse numbers + * + * (c) 2019 Maria Matejka + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include "nest/bird.h" +#include "lib/string.h" + +#include + +#define ULI_MAX_DIV10 (UINT64_MAX / 10) +#define ULI_MAX_MOD10 (UINT64_MAX % 10) + +u64 +bstrtoul10(const char *str, char **end) +{ + u64 out = 0; + for (*end = (char *) str; (**end >= '0') && (**end <= '9'); (*end)++) { + u64 digit = **end - '0'; + if ((out > ULI_MAX_DIV10) || + (out == ULI_MAX_DIV10) && (digit > ULI_MAX_MOD10)) { + errno = ERANGE; + return UINT64_MAX; + } + + out *= 10; + out += (**end) - '0'; + } + return out; +} + +u64 +bstrtoul16(const char *str, char **end) +{ + u64 out = 0; + for (int i=0; i<=(64/4); i++) { + switch (str[i]) { + case '0' ... '9': + out *= 16; + out += str[i] - '0'; + break; + case 'a' ... 'f': + out *= 16; + out += str[i] + 10 - 'a'; + break; + case 'A' ... 'F': + out *= 16; + out += str[i] + 10 - 'A'; + break; + default: + *end = (char *) &(str[i]); + return out; + } + } + + errno = ERANGE; + return UINT64_MAX; +}