From 7b1eae4f503ba81b9b3a41a52bede6d0eeab9f49 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Thu, 20 Feb 2014 13:43:28 +0000 Subject: Add --servers-file option. --- CHANGELOG | 3 +++ man/dnsmasq.8 | 7 +++++++ src/dbus.c | 2 +- src/dnsmasq.c | 22 ++++++++++++++++++---- src/dnsmasq.h | 3 +++ src/dnssec.c | 2 ++ src/network.c | 34 +++++++++++++++++++--------------- src/option.c | 46 +++++++++++++++++++++++++++++++++++++++------- 8 files changed, 92 insertions(+), 27 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c2e1866..806fc8e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -63,6 +63,9 @@ version 2.69 a workable state. Add --rev-server. Thanks to Dave Taht for suggesting this. + + Add --servers-file. Allows dynamic update of upstream servers + full access to configuration. version 2.68 diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 8d2c95d..ed71ebe 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -1678,6 +1678,13 @@ files. If extension(s) are given, any files which end in those extensions are skipped. Any files whose names end in ~ or start with . or start and end with # are always skipped. This flag may be given on the command line or in a configuration file. +.TP +.B --servers-file= +A special case of +.B --conf-file +which differs in two respects. Firstly, only --server and --rev-server are allowed +in the configuration file included. Secondly, the file is re-read and the configuration +therein is updated when dnsmasq recieves SIGHUP. .SH CONFIG FILE At startup, dnsmasq reads .I /etc/dnsmasq.conf, diff --git a/src/dbus.c b/src/dbus.c index eb0ce6b..ed7ac8a 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -225,7 +225,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings) { const char *str = NULL; union mysockaddr addr, source_addr; - int flags; + int flags = 0; char interface[IF_NAMESIZE]; char *str_addr, *str_domain = NULL; diff --git a/src/dnsmasq.c b/src/dnsmasq.c index 3c8a847..b1a0964 100644 --- a/src/dnsmasq.c +++ b/src/dnsmasq.c @@ -1114,7 +1114,7 @@ static void async_event(int pipe, time_t now) { pid_t p; struct event_desc ev; - int i; + int i, check = 0; char *msg; /* NOTE: the memory used to return msg is leaked: use msgs in events only @@ -1125,11 +1125,25 @@ static void async_event(int pipe, time_t now) { case EVENT_RELOAD: clear_cache_and_reload(now); - if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL)) + + if (daemon->port != 0) { - reload_servers(daemon->resolv_files->name); - check_servers(); + if (daemon->resolv_files && option_bool(OPT_NO_POLL)) + { + reload_servers(daemon->resolv_files->name); + check = 1; + } + + if (daemon->servers_file) + { + read_servers_file(); + check = 1; + } + + if (check) + check_servers(); } + #ifdef HAVE_DHCP rerun_scripts(); #endif diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 59d9e9e..caa8ce7 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -456,6 +456,7 @@ union mysockaddr { #define SERV_COUNTED 512 /* workspace for log code */ #define SERV_USE_RESOLV 1024 /* forward this domain in the normal way */ #define SERV_NO_REBIND 2048 /* inhibit dns-rebind protection */ +#define SERV_FROM_FILE 4096 /* read from --servers-file */ struct serverfd { int fd; @@ -864,6 +865,7 @@ extern struct daemon { unsigned int options, options2; struct resolvc default_resolv, *resolv_files; time_t last_resolv; + char *servers_file; struct mx_srv_record *mxnames; struct naptr *naptr; struct txt_record *txt, *rr; @@ -1130,6 +1132,7 @@ void read_opts (int argc, char **argv, char *compile_opts); char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len); void reread_dhcp(void); +void read_servers_file(void); void set_option_bool(unsigned int opt); void reset_option_bool(unsigned int opt); struct hostsfile *expand_filelist(struct hostsfile *list); diff --git a/src/dnssec.c b/src/dnssec.c index 5511143..8bd7c29 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -287,6 +287,8 @@ static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len, unsigned char *digest, size_t digest_len, int algo) { + (void)digest_len; + switch (algo) { case 1: case 5: case 7: case 8: case 10: diff --git a/src/network.c b/src/network.c index 6eb516b..a4380ae 100644 --- a/src/network.c +++ b/src/network.c @@ -1291,7 +1291,8 @@ void add_update_server(int flags, const char *interface, const char *domain) { - struct server *serv; + struct server *serv, *next = NULL; + char *domain_str = NULL; /* See if there is a suitable candidate, and unmark */ for (serv = daemon->servers; serv; serv = serv->next) @@ -1308,17 +1309,18 @@ void add_update_server(int flags, continue; } - serv->flags &= ~SERV_MARK; - break; } - - if (!serv && (serv = whine_malloc(sizeof (struct server)))) + + if (serv) + { + domain_str = serv->domain; + next = serv->next; + } + else if ((serv = whine_malloc(sizeof (struct server)))) { /* Not found, create a new one. */ - memset(serv, 0, sizeof(struct server)); - - if (domain && !(serv->domain = whine_malloc(strlen(domain)+1))) + if (domain && !(domain_str = whine_malloc(strlen(domain)+1))) { free(serv); serv = NULL; @@ -1335,25 +1337,27 @@ void add_update_server(int flags, s->next = serv; } if (domain) - strcpy(serv->domain, domain); + strcpy(domain_str, domain); } } if (serv) { + memset(serv, 0, sizeof(struct server)); serv->flags = flags; + serv->domain = domain_str; + serv->next = next; serv->queries = serv->failed_queries = 0; if (domain) serv->flags |= SERV_HAS_DOMAIN; if (interface) - strcpy(serv->interface, interface); - else - serv->interface[0] = 0; - - serv->addr = *addr; - serv->source_addr = *source_addr; + strcpy(serv->interface, interface); + if (addr) + serv->addr = *addr; + if (source_addr) + serv->source_addr = *source_addr; } } diff --git a/src/option.c b/src/option.c index b090381..2d860d5 100644 --- a/src/option.c +++ b/src/option.c @@ -142,6 +142,7 @@ struct myoption { #define LOPT_TRUST_ANCHOR 330 #define LOPT_DNSSEC_DEBUG 331 #define LOPT_REV_SERV 332 +#define LOPT_SERVERS_FILE 333 #ifdef HAVE_GETOPT_LONG static const struct option opts[] = @@ -158,6 +159,7 @@ static const struct myoption opts[] = { "user", 2, 0, 'u' }, { "group", 2, 0, 'g' }, { "resolv-file", 2, 0, 'r' }, + { "servers-file", 1, 0, LOPT_SERVERS_FILE }, { "mx-host", 1, 0, 'm' }, { "mx-target", 1, 0, 't' }, { "cache-size", 2, 0, 'c' }, @@ -349,6 +351,7 @@ static struct { { 'Q', ARG_ONE, "", gettext_noop("Force the originating port for upstream DNS queries."), NULL }, { 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL }, { 'r', ARG_DUP, "", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE }, + { LOPT_SERVERS_FILE, ARG_ONE, "", gettext_noop("Specify path to file with server= options"), NULL }, { 'S', ARG_DUP, "//", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL }, { LOPT_REV_SERV, ARG_DUP, "/,", gettext_noop("Specify address of upstream servers for reverse address queries"), NULL }, { LOPT_LOCAL, ARG_DUP, "//", gettext_noop("Never forward queries to specified domains."), NULL }, @@ -1385,7 +1388,7 @@ void reset_option_bool(unsigned int opt) daemon->options2 &= ~(1u << (opt - 32)); } -static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line) +static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only) { int i; char *comma; @@ -1588,6 +1591,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma daemon->resolv_files = list; break; } + + case LOPT_SERVERS_FILE: + daemon->servers_file = opt_string_alloc(arg); + break; case 'm': /* --mx-host */ { @@ -2152,6 +2159,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma memset(newlist, 0, sizeof(struct server)); } + if (servers_only && option == 'S') + newlist->flags |= SERV_FROM_FILE; + if (option == 'A') { newlist->flags |= SERV_LITERAL_ADDRESS; @@ -2223,7 +2233,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma if (string) ret_err(string); - + + if (servers_only) + serv->flags |= SERV_FROM_FILE; + break; } @@ -3801,12 +3814,13 @@ static void read_file(char *file, FILE *f, int hard_opt) while (fgets(buff, MAXDNAME, f)) { - int white, i, option = hard_opt; + int white, i; + volatile int option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt; char *errmess, *p, *arg = NULL, *start; size_t len; /* Memory allocation failure longjmps here if mem_recover == 1 */ - if (option != 0) + if (option != 0 || hard_opt == LOPT_REV_SERV) { if (setjmp(mem_jmp)) continue; @@ -3907,13 +3921,15 @@ static void read_file(char *file, FILE *f, int hard_opt) errmess = _("extraneous parameter"); else if (opts[i].has_arg == 1 && !arg) errmess = _("missing parameter"); + else if (hard_opt == LOPT_REV_SERV && option != 'S' && option != LOPT_REV_SERV) + errmess = _("illegal option"); } oops: if (errmess) strcpy(daemon->namebuff, errmess); - if (errmess || !one_opt(option, arg, buff, _("error"), 0)) + if (errmess || !one_opt(option, arg, buff, _("error"), 0, hard_opt == LOPT_REV_SERV)) { sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file); if (hard_opt != 0) @@ -4095,6 +4111,22 @@ struct hostsfile *expand_filelist(struct hostsfile *list) return list; } +void read_servers_file(void) +{ + FILE *f; + + if (!(f = fopen(daemon->servers_file, "r"))) + { + my_syslog(LOG_ERR, _("cannot read %s: %s"), daemon->servers_file, strerror(errno)); + return; + } + + mark_servers(SERV_FROM_FILE); + cleanup_servers(); + + read_file(daemon->servers_file, f, LOPT_REV_SERV); +} + #ifdef HAVE_DHCP void reread_dhcp(void) @@ -4288,9 +4320,9 @@ void read_opts(int argc, char **argv, char *compile_opts) else { #ifdef HAVE_GETOPT_LONG - if (!one_opt(option, arg, daemon->namebuff, _("try --help"), 1)) + if (!one_opt(option, arg, daemon->namebuff, _("try --help"), 1, 0)) #else - if (!one_opt(option, arg, daemon->namebuff, _("try -w"), 1)) + if (!one_opt(option, arg, daemon->namebuff, _("try -w"), 1, 0)) #endif die(_("bad command line options: %s"), daemon->namebuff, EC_BADCONF); } -- cgit v1.2.1