summaryrefslogtreecommitdiffstats
path: root/prog/6/conf.c
diff options
context:
space:
mode:
Diffstat (limited to 'prog/6/conf.c')
-rw-r--r--prog/6/conf.c265
1 files changed, 136 insertions, 129 deletions
diff --git a/prog/6/conf.c b/prog/6/conf.c
index b8ce0be..d22c7c0 100644
--- a/prog/6/conf.c
+++ b/prog/6/conf.c
@@ -1,6 +1,10 @@
+#include <search.h>
#include <stdbool.h>
#include <confuse.h>
#include <arpa/inet.h>
+int compar_pcp (const void * a, const void * b) {
+ return strcmp(*((const char **) a), *((const char **) b));
+}
enum type {
nothing,
network,
@@ -14,14 +18,20 @@ struct trie {
void * data;
};
struct trie * next (struct trie * trie) { // for depth-first walking the trie, pass in the root trie first
- if (trie->dir[0])
+ if (trie->dir[0]) {
+ trie->dir[0]->dir[2] = trie;
return trie->dir[0];
- if (trie->dir[1])
+ }
+ if (trie->dir[1]) {
+ trie->dir[1]->dir[2] = trie;
return trie->dir[1];
+ }
while (trie->dir[2]) {
if (trie->dir[2]->dir[1])
- if (trie->dir[2]->dir[1] != trie)
+ if (trie->dir[2]->dir[1] != trie) {
+ trie->dir[2]->dir[1]->dir[2] = trie->dir[2];
return trie->dir[2]->dir[1];
+ }
trie = trie->dir[2];
}
return NULL;
@@ -32,8 +42,8 @@ struct network {
int mask;
char * email;
char ** ns; // first one is master
- time_t serial; // for soa record
- time_t ttl;
+ int serial; // for soa record
+ int ttl;
struct suffix * suffix; // network does not own a suffix
char * from; // master that sent us this network or NULL if I am the master
};
@@ -53,7 +63,7 @@ struct ns {
struct in6_addr addr;
int mask;
char ** ns;
- time_t ttl;
+ int ttl;
char * from; // master that sent us this ns or NULL if I am the master
};
void free_ns (struct ns * ns) {
@@ -70,7 +80,7 @@ void free_ns (struct ns * ns) {
struct ptr {
struct in6_addr addr;
char * hostname;
- time_t ttl; // time of creation for ptr6c records
+ int ttl; // time of creation for ptr6c records
char * from; // master that sent us this ptr or NULL if I am the master
};
void free_ptr (struct ptr * ptr) {
@@ -95,6 +105,7 @@ void free_trie (struct trie * trie) {
free_ptr((struct ptr *) trie->data);
break;
case nothing:
+ free(trie->data);
break;
}
free_trie(trie->dir[0]);
@@ -114,8 +125,8 @@ struct suffix {
struct trie * accept; // trie structure: http://upload.šijanec.eu./d/suffix.jpg (data is irrelevant)
char ** ns; // first one is master
char * email;
- time_t ttl;
- time_t serial;
+ int ttl;
+ int serial;
char * from; // master that sent us this suffix or NULL if I am the master
};
void free_suffix (struct suffix * suffix) {
@@ -134,21 +145,24 @@ void free_suffix (struct suffix * suffix) {
}
struct config {
struct trie * trie;
- char ** master_servers;
- // char ** master_zones;
- char ** slaves;
+ char ** masters;
int poll_interval;
char * ptr_file;
void * suffixrp; // for tsearch(3)
};
-void add_accept (struct trie * trie, struct in6_addr addr, int mask) {
- int depth = 0;
- while (depth < mask) {
- bool bit = !!(addr.s6_addr[depth/8] & (1 << (7-depth%8)));
+struct netspec {
+ struct in6_addr addr;
+ int mask;
+};
+void add_accept (struct trie * trie, struct netspec netspec) {
+ for (int depth = 0; depth < netspec.mask; depth++) {
+ bool bit = !!(netspec.addr.s6_addr[depth/8] & (1 << (7-depth%8)));
if (!trie->dir[bit])
trie->dir[bit] = calloc(1, sizeof *trie);
trie = trie->dir[bit];
}
+ trie->data = calloc(1, sizeof(struct netspec));
+ memcpy(trie->data, &netspec, sizeof netspec);
}
bool is_acceptable (struct trie * trie, struct in6_addr addr) {
int depth = 0;
@@ -221,55 +235,6 @@ int validate_remote (cfg_t * cfg, cfg_opt_t * opt) {
*cp = '/';
return 0;
}
-int validate_zone (cfg_t * cfg, cfg_opt_t * opt) {
- char * value = cfg_opt_getnstr(opt, cfg_opt_size(opt) - 1);
- char * cp = strchr(value, '/');
- if (cp) {
- char * cp2;
- int mask = strtol(cp+1, &cp2, 10);
- if (*cp2) {
- cfg_error(cfg, "zone %s in %s in section %s has non-numeric characters as part of the netmask", value, opt->name, cfg->name);
- return -1;
- }
- if (mask < 0 || mask > 128) {
- cfg_error(cfg, "specified mask %d of zone %s in %s section %s is not in range 0-128", mask, value, opt->name, cfg->name);
- return -1;
- }
- if (mask % 4) {
- cfg_error(cfg, "specified mask %d of zone %s in %s section %s is not divisible by 4", mask, value, opt->name, cfg->name);
- return -1;
- }
- *cp = '\0';
- struct in6_addr tmp;
- switch (inet_pton(AF_INET6, value, &tmp)) {
- case -1:
- cfg_error(cfg, "error while parsing zone %s in section %s: inet_pton(AF_INET6, \"%s\", &tmp): %s --- your libc must support IPv6", opt->name, cfg->name, value, strerror(errno));
- if (cp)
- *cp = '/';
- return -1;
- case 0:
- cfg_error(cfg, "zone %s in section %s is an invalid ipv6 or v4mapped address (%s). see section AF_INET6 in `man inet_pton` for syntax.", opt->name, cfg->name, value);
- if (cp)
- *cp = '/';
- return -1;
- }
- for (int i = mask; i < 128; i++)
- if (tmp.s6_addr[i/8] & (1 << (7-i%8))) {
- cfg_error(cfg, "zone %s in section %s has host bits set (%s/%d) (debug: %d).", opt->name, cfg->name, value, mask, i);
- if (cp)
- *cp = '/';
- return -1;
- }
- *cp = '/';
- return 0;
- }
- unsigned char tmp[PACKETSZ];
- if (res_mkquery(QUERY, value, C_IN, T_AAAA, NULL, 0, NULL, tmp, PACKETSZ) == -1) {
- cfg_error(cfg, "zone %s in zone specification %s in section %s couldn't be parsed by res_mkquery", value, opt->name, cfg->name);
- return -1;
- }
- return 0;
-}
int validate_fqdn (cfg_t * cfg, cfg_opt_t * opt) {
char * value = cfg_opt_getnstr(opt, cfg_opt_size(opt) - 1);
unsigned char tmp[PACKETSZ];
@@ -303,12 +268,11 @@ int validate_email (cfg_t * cfg, cfg_opt_t * opt) {
int validate_network (cfg_t * cfg, cfg_opt_t * opt) {
cfg_t * sec = cfg_opt_getnsec(opt, cfg_opt_size(opt) - 1);
if (!cfg_size(sec, "networks")) {
- cfg_error(sec, "%s section does not contain any networks", opt->name);
+ cfg_error(cfg, "%s section does not contain any networks", opt->name);
return -1;
}
- char * master = cfg_getstr(sec, "master");
- if (!master) {
- cfg_error(cfg, "%s section does not contain required option master", opt->name);
+ if (!cfg_size(sec, "ns")) {
+ cfg_error(sec, "%s section does not contain any NS records", opt->name);
return -1;
}
return 0;
@@ -330,10 +294,6 @@ int validate_netspec (cfg_t * cfg, cfg_opt_t * opt) {
cfg_error(cfg, "specified mask %d of network specification %s in %s section %s is not in range 0-128", mask, value, opt->name, cfg->name);
return -1;
}
- if (mask % 4) {
- cfg_error(cfg, "specified mask %d of network specification %s in %s section %s is not divisible by 4", mask, value, opt->name, cfg->name);
- return -1;
- }
*cp = '\0';
struct in6_addr tmp;
switch (inet_pton(AF_INET6, value, &tmp)) {
@@ -385,42 +345,50 @@ int validate_ns (cfg_t * cfg, cfg_opt_t * opt) {
}
return 0;
}
+int validate_suffix (cfg_t * cfg, cfg_opt_t * opt) {
+ cfg_t * sec = cfg_opt_getnsec(opt, cfg_opt_size(opt) - 1);
+ if (!cfg_size(sec, "suffixes")) {
+ cfg_error(cfg, "%s section does not contain any suffixes", opt->name);
+ return -1;
+ }
+ if (!cfg_size(sec, "ns")) {
+ cfg_error(sec, "%s section does not contain any NS records", opt->name);
+ return -1;
+ }
+ return 0;
+}
int config (struct config * conf, const char * filename, FILE * output) {
cfg_opt_t network_opts[] = {
- CFG_STR_LIST("networks", NULL, CFGF_NODEFAULT), // REQUIRED at least one
- CFG_STR_LIST("slaves", "{}", CFGF_NONE),
+ CFG_STR_LIST("networks", NULL, CFGF_NODEFAULT),
+ CFG_STR_LIST("ns", NULL, CFGF_NODEFAULT), // REQUIRED at least one.
CFG_STR("admin", "6@sijanec.eu", CFGF_NONE),
- CFG_STR("master", NULL, CFGF_NODEFAULT), // REQUIRED
CFG_STR("suffix", NULL, CFGF_NONE),
CFG_INT("ttl", 420, CFGF_NONE),
CFG_END()
};
cfg_opt_t suffix_opts[] = {
- CFG_STR_LIST("suffixes", NULL, CFGF_NODEFAULT), // REQUIRED at least one
+ CFG_STR_LIST("suffixes", NULL, CFGF_NODEFAULT),
CFG_STR_LIST("accept", "{::/0}", CFGF_NONE),
- CFG_STR_LIST("slaves", "{}", CFGF_NONE),
+ CFG_STR_LIST("ns", NULL, CFGF_NODEFAULT), // REQUIRED at least one.
CFG_STR("admin", "6@sijanec.eu", CFGF_NONE),
- CFG_STR("master", NULL, CFGF_NODEFAULT), // REQUIRED
CFG_INT("ttl", 420, CFGF_NONE),
CFG_END()
};
cfg_opt_t ptr_opts[] = {
- CFG_STR("hostname", NULL, CFGF_NODEFAULT), // REQUIRED
+ CFG_STR("hostname", NULL, CFGF_NODEFAULT),
CFG_INT("ttl", 420, CFGF_NONE),
CFG_END()
};
cfg_opt_t ns_opts[] = {
- CFG_STR_LIST("networks", NULL, CFGF_NODEFAULT), // REQUIRED at least one
- CFG_STR_LIST("ns", NULL, CFGF_NODEFAULT), // REQUIRED
+ CFG_STR_LIST("networks", NULL, CFGF_NODEFAULT),
+ CFG_STR_LIST("ns", NULL, CFGF_NODEFAULT),
CFG_INT("ttl", 420, CFGF_NONE),
CFG_END()
};
cfg_opt_t opts[] = {
- CFG_STR_LIST("master_servers", "{}", CFGF_NONE),
- // CFG_STR_LIST("master_zones", "{}", CFGF_NONE),
+ CFG_STR_LIST("masters", "{}", CFGF_NONE),
CFG_INT("poll_interval", 69, CFGF_NONE),
CFG_STR("ptr_file", "/var/lib/cache/6/backup", CFGF_NONE),
- CFG_STR_LIST("slaves", "{}", CFGF_NONE),
CFG_SEC("network", network_opts, CFGF_MULTI),
CFG_SEC("suffix", suffix_opts, CFGF_MULTI),
CFG_SEC("ptr", ptr_opts, CFGF_TITLE | CFGF_MULTI | CFGF_NO_TITLE_DUPES),
@@ -434,11 +402,9 @@ int config (struct config * conf, const char * filename, FILE * output) {
cfg_set_validate_func(cfg, "suffix|ttl", validate_positive);
cfg_set_validate_func(cfg, "ptr|ttl", validate_positive);
cfg_set_validate_func(cfg, "ns|ttl", validate_positive);
- cfg_set_validate_func(cfg, "master_servers", validate_remote);
- cfg_set_validate_func(cfg, "slaves", validate_remote);
- // cfg_set_validate_func(cfg, "master_zones", validate_zone);
- cfg_set_validate_func(cfg, "network|slaves", validate_fqdn);
- cfg_set_validate_func(cfg, "suffix|slaves", validate_fqdn);
+ cfg_set_validate_func(cfg, "masters", validate_remote);
+ cfg_set_validate_func(cfg, "network|ns", validate_fqdn);
+ cfg_set_validate_func(cfg, "suffix|ns", validate_fqdn);
cfg_set_validate_func(cfg, "ptr|hostname", validate_fqdn);
cfg_set_validate_func(cfg, "ns|ns", validate_fqdn);
cfg_set_validate_func(cfg, "suffix|suffixes", validate_fqdn);
@@ -448,6 +414,7 @@ int config (struct config * conf, const char * filename, FILE * output) {
cfg_set_validate_func(cfg, "suffix|accept", validate_netspec);
cfg_set_validate_func(cfg, "ns|networks", validate_netspec);
cfg_set_validate_func(cfg, "network", validate_network);
+ cfg_set_validate_func(cfg, "suffix", validate_suffix);
cfg_set_validate_func(cfg, "ptr", validate_ptr);
cfg_set_validate_func(cfg, "ns", validate_ns);
switch (cfg_parse(cfg, filename)) {
@@ -459,65 +426,105 @@ int config (struct config * conf, const char * filename, FILE * output) {
fprintf(output, "# configuration file '%s' could not be parsed\n", filename);
return 2;
}
- if (conf->master_servers) {
- char ** pcp = conf->master_servers;
+ if (conf->masters) {
+ char ** pcp = conf->masters;
for (; *pcp; pcp++)
free(*pcp);
- free(conf->master_servers);
+ free(conf->masters);
}
- conf->master_servers = calloc(cfg_size(cfg, "master_servers")+1, sizeof *conf->master_servers);
- for (size_t i = 0; i < cfg_size(cfg, "master_servers"); i++)
- conf->master_servers[i] = strdup(cfg_getnstr(cfg, "master_servers", i));
- /* if (conf->master_zones) {
- char ** pcp = conf->master_zones;
- for (; *pcp; pcp++)
- free(*pcp);
- free(conf->master_zones);
- }
- conf->master_zones = calloc(cfg_size(cfg, "master_zones")+1, sizeof *conf->master_zones);
- for (size_t i = 0; i < cfg_size(cfg, "master_zones"); i++)
- conf->master_zones[i] = strdup(cfg_getnstr(cfg, "master_zones", i)); */
+ conf->masters = calloc(cfg_size(cfg, "masters")+1, sizeof *conf->masters);
+ for (size_t i = 0; i < cfg_size(cfg, "masters"); i++)
+ conf->masters[i] = strdup(cfg_getnstr(cfg, "masters", i));
conf->poll_interval = cfg_getint(cfg, "poll_interval");
free(conf->ptr_file);
conf->ptr_file = strdup(cfg_getstr(cfg, "ptr_file"));
- if (conf->slaves) {
- char ** pcp = conf->slaves;
- for (; *pcp; pcp++)
- free(*pcp);
- free(conf->slaves);
- }
- conf->slaves = calloc(cfg_size(cfg, "slaves")+1, sizeof *conf->slaves);
- for (size_t i = 0; i < cfg_size(cfg, "slaves"); i++)
- conf->slaves[i] = strdup(cfg_getnstr(cfg, "slaves", i));
for (size_t i = 0; i < cfg_size(cfg, "suffix"); i++) {
cfg_t * cfg_suffix = cfg_getnsec(cfg, "suffix", i);
for (size_t j = 0; j < cfg_size(cfg_suffix, "suffixes"); j++) {
-
+ char * suffixstr = strdup(cfg_getnstr(cfg_suffix, "suffixes", j));
+ struct suffix ** found = tfind(&suffixstr, &conf->suffixrp, compar_pcp);
+ if (found) {
+ free_suffix(*found);
+ tdelete(&suffixstr, &conf->suffixrp, compar_pcp);
+ }
+ struct suffix * suffix = calloc(1, sizeof *suffix);
+ suffix->suffix = suffixstr;
+ suffix->accept = calloc(1, sizeof *suffix->accept);
+ if (cfg_getstr(cfg_suffix, "admin"))
+ suffix->email = strdup(cfg_getstr(cfg_suffix, "admin"));
+ suffix->ns = calloc(cfg_size(cfg_suffix, "ns")+1, sizeof *suffix->ns);
+ for (size_t k = 0; k < cfg_size(cfg_suffix, "ns"); k++)
+ suffix->ns[k] = strdup(cfg_getnstr(cfg_suffix, "ns", k));
+ suffix->ttl = cfg_getint(cfg_suffix, "ttl");
+ for (size_t k = 0; k < cfg_size(cfg_suffix, "accept"); k++) {
+ struct netspec netspec;
+ char * cp = strchr(cfg_getnstr(cfg_suffix, "accept", k), '/');
+ cp[0] = '\0';
+ netspec.mask = strtol(cp+1, NULL, 10);
+ inet_pton(AF_INET6, cfg_getnstr(cfg_suffix, "accept", k), netspec.addr.s6_addr);
+ cp[0] = '/';
+ add_accept(suffix->accept, netspec);
+ }
+ suffix->serial = timestamp();
+ tsearch(suffix, &conf->suffixrp, compar_pcp);
}
}
- if (!output)
- return 0;
- fprintf(output, "master_servers = {");
- char ** pcp = conf->master_servers;
- while (*pcp) {
- fprintf(output, "\"%s\"", *pcp);
- if (*++pcp)
+ return 0;
+}
+#ifndef _GNU_SOURCE
+FILE * global_print_suffix_output;
+#endif
+void print_suffix (const void * nodep, VISIT which,
+#ifndef _GNU_SOURCE
+int depth __attribute__((unused))
+#else
+void * closure
+#endif
+) {
+ struct suffix * suffix = *((struct suffix **) nodep);
+ if (!(which == postorder || which == leaf))
+ return;
+#ifndef _GNU_SOURCE
+ FILE * output = global_print_suffix_output;
+#else
+ FILE * output = (FILE *) closure;
+#endif
+ fprintf(output, "suffix\n{\tttl = %d\n\t", suffix->ttl);
+ if (suffix->email)
+ fprintf(output, "admin = \"%s\"\n\t", suffix->email);
+ fprintf(output, "accept = {");
+ unsigned i = 0;
+ for (struct trie * trie = suffix->accept; trie; trie = next(trie)) {
+ if (trie->dir[0] || trie->dir[1])
+ continue;
+ if (i++)
fprintf(output, ", ");
+ char buf[INET_ADDRSTRLEN];
+ inet_ntop(AF_INET6, ((struct netspec *) trie->data)->addr.s6_addr, buf, sizeof buf);
+ fprintf(output, "\"%s/%d\"", buf, ((struct netspec *) trie->data)->mask);
}
- /* fprintf(output, "}\nmaster_zones = {");
- pcp = conf->master_zones;
+ fprintf(output, "}\n\tns = {");
+ char ** pcp = suffix->ns;
while (*pcp) {
fprintf(output, "\"%s\"", *pcp);
if (*++pcp)
fprintf(output, ", ");
- } */
- fprintf(output, "}\npoll_interval = %d\nptr_file = \"%s\"\nslaves = {", conf->poll_interval, conf->ptr_file);
- pcp = conf->slaves;
+ }
+ fprintf(output, "}\n\tsuffixes = {\"%s\"}\n}\n", suffix->suffix);
+}
+void print_config (const struct config * conf, FILE * output) {
+ fprintf(output, "masters = {");
+ char ** pcp = conf->masters;
while (*pcp) {
fprintf(output, "\"%s\"", *pcp);
if (*++pcp)
fprintf(output, ", ");
}
- fprintf(output, "}\n");
- return 0;
+ fprintf(output, "}\npoll_interval = %d\nptr_file = \"%s\"\n", conf->poll_interval, conf->ptr_file);
+#ifndef _GNU_SOURCE
+ global_print_suffix_output = output;
+ twalk(conf->suffixrp, print_suffix);
+#else
+ twalk_r(conf->suffixrp, print_suffix, output);
+#endif
}