From 9b81bdf6b0404d5813bfb1ca7965fefdc0ea519a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20Luka=20=C5=A0ijanec?= Date: Tue, 8 Aug 2023 01:58:25 +0200 Subject: suffix parsing and config printing works --- prog/6/6d.conf | 53 +++++------- prog/6/conf.c | 265 +++++++++++++++++++++++++++++--------------------------- prog/6/daemon.c | 9 +- 3 files changed, 165 insertions(+), 162 deletions(-) (limited to 'prog') diff --git a/prog/6/6d.conf b/prog/6/6d.conf index 3ecc3ff..c6d8756 100644 --- a/prog/6/6d.conf +++ b/prog/6/6d.conf @@ -8,22 +8,15 @@ # Reloading the server also schedules a synchronization from masters (if any). # Masters and slaves must have accurate clocks (at least minute accuracy is expected) # To specify IPv4 addresses, use the V4MAPPED address format (::ffff:192.0.2.69). -# Zone transfers are made using a 6d-specific TCP+UDP-based protocol, so if you run 6d being a DNS proxy, such as bind9 zone forward, you must specify the host/port combination where 6d listens, not where bind9 listens. When unsigned, this 6d-specific protocol relies on trusted routing to master servers and no MiTM attacks on the line. -# DNSSEC and signed zone transfers are available upon request (mailto:anton@šijanec.eu). +# Config transfers are made using a 6d-specific TCP-based protocol, so if you run 6d being a DNS proxy, such as bind9 zone forward, you must specify the host/port combination where 6d listens, not where bind9 listens. When unencrypted, this 6d-specific protocol relies on trusted routing to master servers and no MiTM attacks on the line. +# DNSSEC and encrypted zone transfers are available upon request (mailto:anton@šijanec.eu). #################### SLAVE CONFIGURATION ###################### (You may delete this part on master-only 6d.) # You can optionally define master servers here, all of their configuration will be periodically retrieved and mirrored to this 6d instance. A host may optionally be followed by /TCPport. -master_servers = {6master.sijanec.eu, 6d2.example, 2001:db8::1/5353} +masters = {6master.sijanec.eu, 6d2.example, 2001:db8::1/5353} -# OBSOLETE NON-FEATURE (NOT WORKING) -# You can optionally define master networks/zones here, they will be also be mirrored from their master server. The master server will be obtained from their SOA record. -# Note that 6d is not a general purpose DNS server! Any FQDNs specified here will be treated as 6d suffix generators. -# Note that if this is used, master must not be behind a DNS proxy, such as bind9 zone forward. Use master_servers instead if that's the case. -# master_zones = {2001:db8:a::/48, 2001:db8:b::/48, 2001:db8:c::/48, 6ptr.sijanec.eu} - -# Master servers will be checked for changes every poll_interval number of seconds. Set to 0 to disable polling. -# 69 is the default. +# Master servers will be checked for changes every poll_interval number of seconds. 69 is the default. poll_interval = 69 # Slaves hold everything they know in memory. @@ -36,37 +29,32 @@ poll_interval = 69 # /var/cache/6/backup is the default file. ptr_file = /var/cache/6/backup -# Instead of polling, slaves can be notified on changes. This is done over a DNS-compatible UDP protocol so slaves can run behind bind9 forward zone-like DNS proxies. -slaves = {6slave.sijanec.eu/666, ::ffff:192.0.2.69, 2001:db8::2/5353} - -# Defines networks to generate PTR records on the fly. The only required option is master. +# Defines networks to generate PTR records on the fly. network { # List of networks this block defines. networks = {2001:db8:d::/48, 2001:db8:e::/48} - # List the following slaves in NS responses. - slaves = {6slave.sijanec.eu, 6slave.example} + # List the following servers in NS responses. The first server will be put into SOA responses. + ns = {6d.example, 6slave.sijanec.eu, 6slave.example} # This will be published in the SOA record. admin = 6@sijanec.eu - # This will be published as the authoritative server in the SOA record (point it to this 6d instance). - master = 6d.example # PTRs will be generated in form 2001-db8-d--5932.suffix for address 2001:db8:d::5932. # By default, this suffix is the [...].ip6.arpa domain, so for network 2001:db8::/32, the suffix will be 8.B.D.0.1.0.0.2.IP6.ARPA, and the above mentioned PTR would be 2001-db8-d--5932.8.b.d.0.1.0.0.2.ip6.adpa, which is totaly OK standard-wise. Do not specify [...].ip6.arpa addresses as suffixes yourself, they will be managed automatically. # The suffix must respond to queries with the correct AAAA records, 6d can serve it for you (see below). ### suffix = "6ptr.sijanec.eu" # TTL for generated records and negative caching. - ttl = 420 + ttl = 513 } # Another networks definition. network { networks = {2001:db8:f:100::/56, 2001:db8:f:200::/56, 2001:db8:900::/48} - master = ptrdns1.example + ns = {ptrdns1.example} suffix = suffixgenerator.net.example } - -# Define suffixes that will generate AAAA records on the fly. The only required option is master. +/* +# Define suffixes that will generate AAAA records on the fly. suffix { # List of suffixes @@ -75,11 +63,10 @@ suffix # By specifying ::/0 here you allow any network on the internet to use your suffix for PTRs. # ::/0 is the default. accept = {::/0} - slaves = {6slave.sijanec.org, 6slave.example} + ns = {6ptr.sijanec.eu, 6slave.sijanec.org, 6slave.example} admin = 6@sijanec.eu - master = 6ptr.sijanec.eu # TTL for generated records and negative caching. - ttl = 420 + ttl = 513 } # Another suffixes definition, this time networks are specified, other IPv6 addresses will be NXDOMAIN. @@ -87,7 +74,15 @@ suffix { suffixes = {private-ipv6.net.example, private-ipv6.org.example} accept = {2001:db8:f:100::/56, 2001:db8:f:200::/56, 2001:db8:900::/48} - master = locked-ns1.net.example + ns = {locked-ns1.net.example} +} +*/ +# Another one with large accept clauses. +suffix +{ + suffixes = {almost-public.example} + accept = {8000::/1, 4000::/2, ::/2} + ns = {weird-ns1.net.example} } ############################# STATIC NS AND PTR RECORDS ############################### @@ -96,7 +91,7 @@ suffix ptr 2001:db8:d::1 { hostname = mail.example - ttl = 420 + ttl = 513 } # Another PTR definition @@ -110,7 +105,7 @@ ns { networks = {2001:db8:d:1337::/64, 2001:db8:d:1338::/64} ns = {ns1.sijanec.org, ns2.sijanec.org} - ttl = 420 + ttl = 513 } # Another NS delegation. 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 #include #include #include +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 } diff --git a/prog/6/daemon.c b/prog/6/daemon.c index a808487..1807933 100644 --- a/prog/6/daemon.c +++ b/prog/6/daemon.c @@ -80,14 +80,15 @@ int main (int argc, char ** argv) { } struct config conf; memset(&conf, 0, sizeof conf); - FILE * conf_output = stderr; - if (argv[1][0] == 'd') - conf_output = stdout; - int ret = config(&conf, argv[2], conf_output); + int ret = config(&conf, argv[2], stderr); if (ret) { fprintf(stderr, "error %d while parsing the configuration file!\n", ret); return 9+ret; } + FILE * conf_output = stderr; + if (argv[1][0] == 'd') + conf_output = stdout; + print_config(&conf, conf_output); if (argv[1][0] == 'd') return 0; int sock = socket(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); -- cgit v1.2.3