summaryrefslogtreecommitdiff
path: root/src/config/lexparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/config/lexparse.c')
-rw-r--r--src/config/lexparse.c227
1 files changed, 115 insertions, 112 deletions
diff --git a/src/config/lexparse.c b/src/config/lexparse.c
index 9fa3416..250fa62 100644
--- a/src/config/lexparse.c
+++ b/src/config/lexparse.c
@@ -5,6 +5,7 @@
#include <stdlib.h>
#include <errno.h>
+#include <skalibs/gccattributes.h>
#include <skalibs/uint16.h>
#include <skalibs/uint32.h>
#include <skalibs/fmtscan.h>
@@ -17,20 +18,8 @@
#include <s6-dns/s6dns-domain.h>
-#include <shibari/config.h>
#include "shibari-cache-config-internal.h"
-#define dietoobig() strerr_diefu1sys(100, "read configuration")
-
-typedef struct mdt_s mdt, *mdt_ref ;
-struct mdt_s
-{
- size_t filepos ;
- uint32_t line ;
- char linefmt[UINT32_FMT] ;
-} ;
-#define MDT_ZERO { .filepos = 0, .line = 0, .linefmt = "0" }
-
struct namevalue_s
{
char const *name ;
@@ -47,28 +36,50 @@ enum directivevalue_e
T_FORWARD,
} ;
-static void conftree_checkunique (char const *key, mdt const *md)
+static void dieparse (char const *, uint32_t, char const *, char const *, char const *, uint32_t, uint32_t) gccattr_noreturn ;
+static void dieparse (char const *ifile, uint32_t line, char const *directive, char const *what, char const *key, uint32_t keylen, uint32_t prevline)
{
- node const *node = conftree_search(key) ;
- if (node)
+ unsigned int m = 3 ;
+ stralloc sa = STRALLOC_ZERO ;
+ char const *ar[11] = { "in file ", ifile, " line " } ;
+ char fmtl[UINT32_FMT] ;
+ char fmtp[UINT32_FMT] ;
+ fmtl[uint32_fmt(fmtl, line)] = 0 ;
+ ar[m++] = fmtl ;
+ if (directive)
+ {
+ ar[m++] = " directive " ;
+ ar[m++] = directive ;
+ }
+ ar[m++] = ": " ;
+ ar[m++] = what ;
+ if (key)
{
- char fmt[UINT32_FMT] ;
- fmt[uint32_fmt(fmt, node->line)] = 0 ;
- if (key[0] == 'A')
- strerr_diefn(1, 11, "duplicate ", "key in file ", g.storage.s + md->filepos, " line ", md->linefmt, ", previously defined", " in file ", g.storage.s + node->filepos, " line ", fmt) ;
- else
- strerr_diefn(1, 12, "duplicate ", "key ", key, " in file ", g.storage.s + md->filepos, " line ", md->linefmt, ", previously defined", " in file ", g.storage.s + node->filepos, " line ", fmt) ;
+ if (!string_quote(&sa, key, keylen) || !stralloc_0(&sa)) dienomem() ;
+ ar[m++] = sa.s ;
}
+ if (prevline)
+ {
+ fmtp[uint32_fmt(fmtp, prevline)] = 0 ;
+ ar[m++] = " - see line " ;
+ ar[m++] = fmtp ;
+ }
+ strerr_diev(1, ar, m) ;
+}
+
+static void add_unique (char const *ifile, uint32_t line, char const *directive, char const *key, uint32_t keylen, char const *data, size_t datalen)
+{
+ uint32_t prev = repo_add(&conf, key, keylen, data, datalen, line, 0, 0) ;
+ if (prev) dieparse(ifile, line, directive, "duplicate key ", key, keylen, prev) ;
}
+#define adds_unique(ifile, line, directive, key, data, datalen) add_unique(ifile, line, directive, key, strlen(key), data, datalen)
-static void add_unique (char const *key, char const *value, size_t valuelen, mdt const *md)
+static void add_accu (char const *ifile, uint32_t line, char const *directive, char const *key, uint32_t keylen, char const *data, size_t datalen, memcmp_func_ref f)
{
- node node ;
- conftree_checkunique(key, md) ;
- confnode_start(&node, key, md->filepos, md->line) ;
- confnode_add(&node, value, valuelen) ;
- conftree_add(&node) ;
+ uint32_t prev = repo_add(&conf, key, keylen, data, datalen, line, 1, f) ;
+ if (prev) dieparse(ifile, line, directive, "value already listed for key ", key, keylen, prev) ;
}
+#define adds_accu(ifile, line, directive, key, data, datalen, f) add_accu(ifile, line, directive, key, strlen(key), data, datalen, f)
static int ip40_scan (char const *s, char *ip)
{
@@ -82,109 +93,104 @@ static int ip60_scan (char const *s, char *ip)
return len ? !s[len] : 0 ;
}
-static inline void parse_verbosity (char const *s, size_t const *word, size_t n, mdt const *md)
+static int ipcmp (void const *a, void const *b, size_t n)
+{
+ char const *aa = a ;
+ char const * bb = b ;
+ return memcmp(aa+1, bb+1, n-1) ;
+}
+
+
+static inline void parse_verbosity (char const *s, size_t const *word, size_t n, char const *ifile, uint32_t line)
{
uint32_t v ;
char pack[4] ;
- if (n != 1)
- strerr_dief8x(1, "too ", n ? "many" : "few", " arguments to directive ", "verbosity", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
- if (!uint320_scan(s + word[0], &v))
- strerr_dief7x(1, " argument to directive ", "verbosity", " must be an integer ", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
+ if (n != 1) dieparse(ifile, line, "verbosity", n ? "too many arguments" : "too few arguments", 0, 0, 0) ;
+ if (!uint320_scan(s + word[0], &v)) dieparse(ifile, line, "verbosity", "argument must be an integer", 0, 0, 0) ;
uint32_pack_big(pack, v) ;
- add_unique("G:logv", pack, 4, md) ;
+ adds_unique(ifile, line, "verbosity", "G:logv", pack, 4) ;
}
-static inline void parse_maxtcp (char const *s, size_t const *word, size_t n, mdt const *md)
+static inline void parse_maxtcp (char const *s, size_t const *word, size_t n, char const *ifile, uint32_t line)
{
uint32_t max ;
char pack[4] ;
- if (n != 1)
- strerr_dief8x(1, "too ", n ? "many" : "few", " arguments to directive ", "maxtcp", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
- if (!uint320_scan(s + word[0], &max))
- strerr_dief7x(1, " argument to directive ", "maxtcp", " must be an integer ", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
- if (max > 4000)
- strerr_dief7x(1, " argument to directive ", "maxtcp", " must be 4000 or less ", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
+ if (n != 1) dieparse(ifile, line, "maxtcp", n ? "too many arguments" : "too few arguments", 0, 0, 0) ;
+ if (!uint320_scan(s + word[0], &max)) dieparse(ifile, line, "maxtcp", "argument must be an integer", 0, 0, 0) ;
+ if (max > 4000) dieparse(ifile, line, "maxtcp", "argument must be 4000 or less", 0, 0, 0) ;
uint32_pack_big(pack, max) ;
- add_unique("G:maxtcp", pack, 4, md) ;
+ adds_unique(ifile, line, "maxtcp", "G:maxtcp", pack, 4) ;
}
-static inline void parse_listen (char const *s, size_t const *word, size_t n, mdt const *md)
+static inline void parse_listen (char const *s, size_t const *word, size_t n, char const *ifile, uint32_t line)
{
- if (!n)
- strerr_dief6x(1, "too few arguments to directive ", "listen", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
+ if (!n) dieparse(ifile, line, "listen", "too few arguments", 0, 0, 0) ;
+ for (size_t i = 0 ; i < n ; i++)
{
- size_t n4 = 0, n6 = 0 ;
- char ip6[n << 4] ;
- char ip4[n << 2] ;
- for (size_t i = 0 ; i < n ; i++)
- {
- if (ip60_scan(s + word[i], ip6 + (n6 << 4))) n6++ ;
- else if (ip40_scan(s + word[i], ip4 + (n4 << 2))) n4++ ;
- else strerr_dief6x(1, "arguments to directive ", "listen", " must be IPs in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
- }
- add_unique("G:listen4", ip4, n4 << 2, md) ;
- add_unique("G:listen6", ip6, n6 << 4, md) ;
+ char ip[16] ;
+ char key[10] = "G:listen?" ;
+ if (ip60_scan(s + word[i], ip)) key[8] = '6' ;
+ else if (ip40_scan(s + word[i], ip)) key[8] = '4' ;
+ else dieparse(ifile, line, "listen", "arguments must be IP addresses", 0, 0, 0) ;
+ adds_accu(ifile, line, "listen", key, ip, key[8] == '6' ? 16 : 4, &memcmp) ;
}
+ adds_accu(ifile, line, "listen", "G:listen4", "", 0, 0) ;
+ adds_accu(ifile, line, "listen", "G:listen6", "", 0, 0) ;
}
-static inline void parse_accept (char const *s, size_t const *word, size_t n, mdt const *md)
+static inline void parse_accept (char const *s, size_t const *word, size_t n, char const *ifile, uint32_t line)
{
- char key[21] = "A?:" ;
- if (!n)
- strerr_dief6x(1, "too few arguments to directive ", "accept", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
+ char key[20] = "A?:" ;
+ if (!n) dieparse(ifile, line, "accept", "too few arguments", 0, 0, 0) ;
for (size_t i = 0 ; i < n ; i++)
{
uint16_t mask ;
- uint8_t ipz = 16 ;
- size_t n = ip6_scan(s + word[i], key + 4) ;
- if (!n)
+ size_t len = ip6_scan(s + word[i], key + 4) ;
+ if (!len)
{
- ipz = 4 ;
- n = ip4_scan(s + word[i], key + 4) ;
- if (!n) goto err ;
+ len = ip4_scan(s + word[i], key + 4) ;
+ if (!len) dieparse(ifile, line, "accept", "arguments must be ip/netmask", 0, 0, 0) ;
+ key[1] = '4' ;
}
- if (s[word[i] + n] != '/' && s[word[i] + n] != '_') goto err ;
- if (!uint160_scan(s + word[i] + n + 1, &mask) || mask > (ipz << 3)) goto err ;
- key[1] = ipz == 16 ? '6' : '4' ;
+ else key[1] = '6' ;
+ if ((s[word[i] + len] != '/' && s[word[i] + len] != '_')
+ || !uint160_scan(s + word[i] + len + 1, &mask)
+ || mask > (key[1] == 6 ? 128 : 32))
+ dieparse(ifile, line, "accept", "arguments must be ip/netmask", 0, 0, 0) ;
key[3] = (uint8_t)mask ;
- if (ipz == 16) ip6_netmask(key + 4, mask) ; else ip4_netmask(key + 4, mask) ;
- add_unique(key, "", 0, md) ;
+ if (key[1] == '6') ip6_netmask(key + 4, mask) ; else ip4_netmask(key + 4, mask) ;
+ add_unique(ifile, line, "accept", key, key[1] == '6' ? 20 : 8, "", 0) ;
}
- err:
- strerr_dief6x(1, "arguments to directive ", "accept", " must be IP/mask in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
}
-static inline void parse_server (char const *s, size_t const *word, size_t n, mdt const *md, int forward)
+static inline void parse_server (char const *s, size_t const *word, size_t n, char const *ifile, uint32_t line, int forward)
{
- char const *x = forward ? "forward" : "server" ;
+ char const *what = forward ? "forward" : "server" ;
s6dns_domain_t domain ;
- if (n-- < 2)
- strerr_dief8x(1, "too ", "few", " arguments to directive ", x, " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
- if (!s6dns_domain_fromstring(&domain, s + word[0], strlen(s + word[0]))
- || !s6dns_domain_noqualify(&domain))
- strerr_dief7x(1, "first argument to directive ", x, " must be a zone ", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
+ char key[258] = "R?:" ;
+ char data[17] ;
+ if (n-- < 2) dieparse(ifile, line, what, "too few arguments", 0, 0, 0) ;
+ if (!s6dns_domain_fromstring_noqualify_encode(&domain, s + word[0], strlen(s + word[0])))
+ dieparse(ifile, line, what, "first argument must be a zone", 0, 0, 0) ;
word++ ;
+ memcpy(key + 3, domain.s, domain.len - 1) ;
+ for (size_t i = 0 ; i < n ; i++)
{
- size_t n4 = 0, n6 = 0 ;
- char ip6[n * 17] ;
- char ip4[n * 5] ;
- char key[3 + domain.len] ;
- for (size_t i = 0 ; i < n ; i++)
- {
- if (ip60_scan(s + word[i], ip6 + (n6 * 17) + 1)) ip6[n6++ * 17] = !!forward ;
- else if (ip40_scan(s + word[i], ip4 + (n4 * 5) + 1)) ip4[n4++ * 5] = !!forward ;
- else strerr_dief6x(1, "subsequent arguments to directive ", x, " must be IPs in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
- }
- memcpy(key, "R4:", 3) ;
- memcpy(key + 3, domain.s + 1, domain.len - 1) ;
- key[2 + domain.len] = 0 ;
- add_unique(key, ip4, n4 * 5, md) ;
- key[1] = '6' ;
- add_unique(key, ip6, n6 * 17, md) ;
+ if (ip60_scan(s + word[i], data + 1)) key[1] = '6' ;
+ else if (ip40_scan(s + word[i], data + 1)) key[1] = '4' ;
+ else dieparse(ifile, line, what, "second and subsequent arguments must be IP addresses", 0, 0, 0) ;
+ data[0] = !!forward ;
+ add_accu(ifile, line, what, key, 3 + domain.len, data, key[1] == '6' ? 17 : 5, &ipcmp) ;
+ }
+ if (domain.len == 1)
+ {
+ adds_accu(ifile, line, what, "R4:", "", 0, 0) ;
+ adds_accu(ifile, line, what, "R6:", "", 0, 0) ;
}
}
-static inline void process_line (char const *s, size_t const *word, size_t n, mdt *md)
+
+static inline void process_line (char const *s, size_t const *word, size_t n, char const *ifile, uint32_t line)
{
static struct namevalue_s const directives[] =
{
@@ -200,27 +206,26 @@ static inline void process_line (char const *s, size_t const *word, size_t n, md
if (!n--) return ;
word0 = s + *word++ ;
directive = BSEARCH(struct namevalue_s, word0, directives) ;
- if (!directive)
- strerr_dief6x(1, "unrecognized word ", word0, " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
+ if (!directive) dieparse(ifile, line, 0, "unrecognized word: ", word0, strlen(word0), 0) ;
switch (directive->value)
{
case T_VERBOSITY :
- parse_verbosity(s, word, n, md) ;
+ parse_verbosity(s, word, n, ifile, line) ;
break ;
case T_MAXTCP :
- parse_maxtcp(s, word, n, md) ;
+ parse_maxtcp(s, word, n, ifile, line) ;
break ;
case T_LISTEN :
- parse_listen(s, word, n, md) ;
+ parse_listen(s, word, n, ifile, line) ;
break ;
case T_ACCEPT :
- parse_accept(s, word, n, md) ;
+ parse_accept(s, word, n, ifile, line) ;
break ;
case T_SERVER :
- parse_server(s, word, n, md, 0) ;
+ parse_server(s, word, n, ifile, line, 0) ;
break ;
case T_FORWARD :
- parse_server(s, word, n, md, 1) ;
+ parse_server(s, word, n, ifile, line, 1) ;
break ;
}
}
@@ -240,13 +245,13 @@ static inline uint8_t cclass (char c)
}
}
-static inline char next (buffer *b, mdt const *md)
+static inline char next (buffer *b, char const *ifile, uint32_t line)
{
char c ;
ssize_t r = buffer_get(b, &c, 1) ;
if (r == -1) strerr_diefu1sys(111, "read from preprocessor") ;
if (!r) return 0 ;
- if (!c) strerr_dief5x(1, "null character", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
+ if (!c) dieparse(ifile, line, 0, "null character", 0, 0, 0) ;
return c ;
}
@@ -261,12 +266,11 @@ void conf_lexparse (buffer *b, char const *ifile)
} ;
stralloc sa = STRALLOC_ZERO ;
genalloc words = GENALLOC_ZERO ; /* size_t */
- mdt md = MDT_ZERO ;
+ uint32_t line = 1 ;
uint8_t state = 0 ;
- if (!stralloc_catb(&g.storage, ifile, strlen(ifile) + 1)) dienomem() ;
while (state < 0x04)
{
- char c = next(b, &md) ;
+ char c = next(b, ifile, line) ;
uint8_t what = table[state][cclass(c)] ;
state = what & 0x07 ;
if (what & 0x10) if (!genalloc_catb(size_t, &words, &sa.len, 1)) dienomem() ;
@@ -274,11 +278,10 @@ void conf_lexparse (buffer *b, char const *ifile)
if (what & 0x40) if (!stralloc_0(&sa)) dienomem() ;
if (what & 0x80)
{
- process_line(sa.s, genalloc_s(size_t, &words), genalloc_len(size_t, &words), &md) ;
+ process_line(sa.s, genalloc_s(size_t, &words), genalloc_len(size_t, &words), ifile, line) ;
genalloc_setlen(size_t, &words, 0) ;
sa.len = 0 ;
- md.line++ ;
- md.linefmt[uint32_fmt(md.linefmt, md.line)] = 0 ;
+ line++ ;
}
}
genalloc_free(size_t, &words) ;