aboutsummaryrefslogtreecommitdiffstats
path: root/src/config/lexparse.c
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2024-07-02 18:54:34 +0000
committerLaurent Bercot <ska@appnovation.com>2024-07-02 18:54:34 +0000
commit8b435b76d68dd8f11808f0cff4d8998d2be48f4c (patch)
tree501e5a0047f48fc082b3ed505022a59919c9e716 /src/config/lexparse.c
parent9879f5bf1c7bac2f0ae2e230694c9a86b1b567b0 (diff)
downloadshibari-8b435b76d68dd8f11808f0cff4d8998d2be48f4c.tar.gz
Prepare for 0.0.2.0; add shibari-cache-config
Signed-off-by: Laurent Bercot <ska@appnovation.com>
Diffstat (limited to 'src/config/lexparse.c')
-rw-r--r--src/config/lexparse.c230
1 files changed, 230 insertions, 0 deletions
diff --git a/src/config/lexparse.c b/src/config/lexparse.c
new file mode 100644
index 0000000..9987fbd
--- /dev/null
+++ b/src/config/lexparse.c
@@ -0,0 +1,230 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <skalibs/uint32.h>
+#include <skalibs/bitarray.h>
+#include <skalibs/buffer.h>
+#include <skalibs/strerr.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/skamisc.h>
+
+#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 ;
+ uint32_t value ;
+} ;
+
+enum directivevalue_e
+{
+ T_VERBOSITY,
+ T_LISTEN,
+ T_SERVER,
+ T_FORWARD,
+} ;
+
+static void conftree_checkunique (char const *key, mdt const *md)
+{
+ node const *node = conftree_search(key) ;
+ if (node)
+ {
+ char fmt[UINT32_FMT] ;
+ fmt[uint32_fmt(fmt, node->line)] = 0 ;
+ 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) ;
+ }
+}
+
+static void add_unique (char const *key, char const *value, size_t valuelen, mdt const *md)
+{
+ node node ;
+ conftree_checkunique(key, md) ;
+ confnode_start(&node, key, md->filepos, md->line) ;
+ confnode_add(&node, value, valuelen) ;
+ conftree_add(&node) ;
+}
+
+static int ip40_scan (char const *s, char *ip)
+{
+ size_t len = ip4_scan(s, ip) ;
+ return len ? !s[len] : 0 ;
+}
+
+static int ip60_scan (char const *s, char *ip)
+{
+ size_t len = ip6_scan(s, ip) ;
+ return len ? !s[len] : 0 ;
+}
+
+static inline void parse_verbosity (char const *s, size_t const *word, size_t n, mdt const *md)
+{
+ 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) ;
+ uint32_pack_big(pack, v) ;
+ add_unique("G:logv", pack, 4, md) ;
+}
+
+static inline void parse_listen (char const *s, size_t const *word, size_t n, mdt const *md)
+{
+ if (!n)
+ strerr_dief6x(1, "too few arguments to directive ", "listen", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
+ {
+ 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) ;
+ }
+}
+
+static inline void parse_server (char const *s, size_t const *word, size_t n, mdt const *md, int forward)
+{
+ char const *x = 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) ;
+ word++ ;
+ {
+ 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) ;
+ }
+}
+
+static inline void process_line (char const *s, size_t const *word, size_t n, mdt *md)
+{
+ static struct namevalue_s const directives[] =
+ {
+ { .name = "forward", .value = T_FORWARD },
+ { .name = "listen", .value = T_LISTEN },
+ { .name = "server", .value = T_SERVER },
+ { .name = "verbosity", .value = T_VERBOSITY },
+ } ;
+ struct namevalue_s const *directive ;
+ char const *word0 ;
+ 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) ;
+ switch (directive->value)
+ {
+ case T_VERBOSITY :
+ parse_verbosity(s, word, n, md) ;
+ break ;
+ case T_LISTEN :
+ parse_listen(s, word, n, md) ;
+ break ;
+ case T_SERVER :
+ parse_server(s, word, n, md, 0) ;
+ break ;
+ case T_FORWARD :
+ parse_server(s, word, n, md, 1) ;
+ break ;
+ }
+}
+
+static inline uint8_t cclass (char c)
+{
+ switch (c)
+ {
+ case 0 : return 0 ;
+ case ' ' :
+ case '\t' :
+ case '\f' :
+ case '\r' : return 1 ;
+ case '#' : return 2 ;
+ case '\n' : return 3 ;
+ default : return 4 ;
+ }
+}
+
+static inline char next (buffer *b, mdt const *md)
+{
+ 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) ;
+ return c ;
+}
+
+void conf_lexparse (buffer *b, char const *ifile)
+{
+ static uint8_t const table[4][5] = /* see PARSING-config.txt */
+ {
+ { 0x04, 0x02, 0x01, 0x80, 0x33 },
+ { 0x04, 0x01, 0x01, 0x80, 0x01 },
+ { 0x84, 0x02, 0x01, 0x80, 0x33 },
+ { 0xc4, 0x42, 0x23, 0xc0, 0x23 }
+ } ;
+ stralloc sa = STRALLOC_ZERO ;
+ genalloc words = GENALLOC_ZERO ; /* size_t */
+ mdt md = MDT_ZERO ;
+ uint8_t state = 0 ;
+ if (!stralloc_catb(&g.storage, ifile, strlen(ifile) + 1)) dienomem() ;
+ while (state < 0x04)
+ {
+ char c = next(b, &md) ;
+ uint8_t what = table[state][cclass(c)] ;
+ state = what & 0x07 ;
+ if (what & 0x10) if (!genalloc_catb(size_t, &words, &sa.len, 1)) dienomem() ;
+ if (what & 0x20) if (!stralloc_catb(&sa, &c, 1)) dienomem() ;
+ 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) ;
+ genalloc_setlen(size_t, &words, 0) ;
+ sa.len = 0 ;
+ md.line++ ;
+ md.linefmt[uint32_fmt(md.linefmt, md.line)] = 0 ;
+ }
+ }
+ genalloc_free(size_t, &words) ;
+ stralloc_free(&sa) ;
+}