[Dnsmasq-discuss] [PATCH] Add a metric-order option that is a mix between strict-order and Default schedulers
DUPONCHEEL Sébastien
sebastien.duponcheel at corp.ovh.com
Wed Mar 14 14:33:25 GMT 2018
I got some lags, sorry for the duplicated messages.
Le 13/03/2018 à 15:36, DUPONCHEEL Sébastien a écrit :
> The default scheduler in dnsmasq query first all servers and then use the
> fastest responding dns server for a short period and query all servers if a
> timeout occurs.
>
> The all-servers scheduler query fist the last fastest server and query all
> others dns servers every time.
>
> The strict-order scheduler query the first server that appear in resolv.conf
> and if this server timeout dnsmasq try the next one.
>
> strict-order is too slow and not resillient enougth to be use (ex: if only the
> 4th dns server in resolv.conf is reachable each dns request will take 20s).
>
> "Default" and "all-servers" are fast and resilient but does not take care of
> the server preferences defined in the resolv.conf.
>
> This patch introduce a new scheduler that is an hybrid of the Default and the
> strict-order schedulers.
>
> Case study :
>
> MyBox~# cat /etc/resolv.conf
> # Behind VPN server
> nameserver 169.254.254.1
> # FAI or personal closed server
> nameserver 91.121.161.184
> # Open servers
> nameserver 9.9.9.9
> nameserver 8.8.8.8
> nameserver 208.67.222.222
>
> When my VPN is offline i want my router to use only my FAI or personal dns
> server because i don't want to give my personnal datas to Quad9, Google,
> OpenDNS or whatever.
>
> But theses openservers are very good as backups if my personal dns server fail.
> When i am using my VPN to do black magic stuffs like downloading debian dvd
> images, i dont want my FAI to know what im doing by looking my dns requests or
> sniffing my network traffic.
>
> How the metric-order scheduler works ?
>
> Dnsmasq read the resolv.conf and set a metric from 0 to N to each server in the
> list.
>
> The first query will be sent to all dns servers and dnsmasq will listen for
> each answer and set the responding server's with the lowest metric as the
> current server.
>
> The next query will be sent first to the current server and sent to all other
> servers with a lower metric than the current (supposed offline or unreachable).
>
> When a query fail, the current server is cleared out and the query is resent
> to all servers, a new current server is elected based on metric values.
>
> If a server with a lowest metric turn online, it will answer to dns request
> and will be elected as the new current server.
>
> ---
> src/config.h | 14 +++++++++++++-
> src/dbus.c | 6 +++---
> src/dnsmasq.c | 5 +++++
> src/dnsmasq.h | 9 +++++++--
> src/forward.c | 40 +++++++++++++++++++++++++++++++++++++++-
> src/network.c | 11 +++++++----
> src/option.c | 3 +++
> 7 files changed, 77 insertions(+), 11 deletions(-)
>
> diff --git a/src/config.h b/src/config.h
> index b317071..722a7d7 100644
> --- a/src/config.h
> +++ b/src/config.h
> @@ -123,6 +123,9 @@ HAVE_LOOP
> HAVE_INOTIFY
> use the Linux inotify facility to efficiently re-read configuration files.
>
> +HAVE_METRIC_ORDER
> + include an hybrid scheduler that try to use the highest server in the resolv.conf file.
> +
> NO_ID
> Don't report *.bind CHAOS info to clients, forward such requests upstream instead.
> NO_IPV6
> @@ -167,6 +170,7 @@ RESOLVFILE
> #define HAVE_AUTH
> #define HAVE_IPSET
> #define HAVE_LOOP
> +#define HAVE_METRIC_ORDER
>
> /* Build options which require external libraries.
>
> @@ -366,6 +370,10 @@ HAVE_SOCKADDR_SA_LEN
> #undef HAVE_LOOP
> #endif
>
> +#ifdef NO_METRIC_ORDER
> +#undef HAVE_METRIC_ORDER
> +#endif
> +
> #if defined (HAVE_LINUX_NETWORK) && !defined(NO_INOTIFY)
> #define HAVE_INOTIFY
> #endif
> @@ -454,7 +462,11 @@ static char *compile_opts =
> #ifndef HAVE_INOTIFY
> "no-"
> #endif
> -"inotify";
> +"inotify "
> +#ifndef HAVE_METRIC_ORDER
> +"no-"
> +#endif
> +"metric-order";
>
>
> #endif
> diff --git a/src/dbus.c b/src/dbus.c
> index 6a78b20..1621977 100644
> --- a/src/dbus.c
> +++ b/src/dbus.c
> @@ -216,7 +216,7 @@ static void dbus_read_servers(DBusMessage *message)
> domain = NULL;
>
> if (!skip)
> - add_update_server(SERV_FROM_DBUS, &addr, &source_addr, NULL, domain);
> + add_update_server(SERV_FROM_DBUS, &addr, &source_addr, NULL, domain, 0);
>
> } while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
> }
> @@ -393,7 +393,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
> else
> p = NULL;
>
> - add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain);
> + add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain, 0);
> } while ((str_domain = p));
> }
> else
> @@ -408,7 +408,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
> dbus_message_iter_get_basic(&string_iter, &str);
> dbus_message_iter_next (&string_iter);
>
> - add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str);
> + add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str, 0);
> } while (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING);
> }
>
> diff --git a/src/dnsmasq.c b/src/dnsmasq.c
> index ce44809..fe04ae8 100644
> --- a/src/dnsmasq.c
> +++ b/src/dnsmasq.c
> @@ -225,6 +225,11 @@ int main (int argc, char **argv)
> die(_("loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF);
> #endif
>
> +#ifndef HAVE_METRIC_ORDER
> + if (option_bool(OPT_METRIC_ORDER))
> + die(_("metric-order scheduler not available: set HAVE_METRIC_ORDER in src/config.h"), NULL, EC_BADCONF);
> +#endif
> +
> if (daemon->max_port < daemon->min_port)
> die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF);
>
> diff --git a/src/dnsmasq.h b/src/dnsmasq.h
> index 6773b69..39045b8 100644
> --- a/src/dnsmasq.h
> +++ b/src/dnsmasq.h
> @@ -250,7 +250,8 @@ struct event_desc {
> #define OPT_MAC_B64 54
> #define OPT_MAC_HEX 55
> #define OPT_TFTP_APREF_MAC 56
> -#define OPT_LAST 57
> +#define OPT_METRIC_ORDER 57
> +#define OPT_LAST 58
>
> /* extra flags for my_syslog, we use a couple of facilities since they are known
> not to occupy the same bits as priorities, no matter how syslog.h is set up. */
> @@ -525,6 +526,9 @@ struct server {
> #ifdef HAVE_LOOP
> u32 uid;
> #endif
> +#ifdef HAVE_METRIC_ORDER
> + u8 metric;
> +#endif
> struct server *next;
> };
>
> @@ -1282,7 +1286,8 @@ void add_update_server(int flags,
> union mysockaddr *addr,
> union mysockaddr *source_addr,
> const char *interface,
> - const char *domain);
> + const char *domain,
> + u8 metric);
> void check_servers(void);
> int enumerate_interfaces(int reset);
> void create_wildcard_listeners(void);
> diff --git a/src/forward.c b/src/forward.c
> index cdd11d3..36c7d1a 100644
> --- a/src/forward.c
> +++ b/src/forward.c
> @@ -239,6 +239,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
> struct all_addr *addrp = NULL;
> unsigned int flags = 0;
> struct server *start = NULL;
> +#ifdef HAVE_METRIC_ORDER
> + struct server *last_server = NULL;
> +#endif
> #ifdef HAVE_DNSSEC
> void *hash = hash_questions(header, plen, daemon->namebuff);
> int do_dnssec = 0;
> @@ -371,6 +374,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
> {
> if (option_bool(OPT_ORDER))
> start = daemon->servers;
> +#ifdef HAVE_METRIC_ORDER
> + else if (option_bool(OPT_METRIC_ORDER))
> + {
> + forward->forwardall = 1;
> + if(!(start = daemon->last_server))
> + start = daemon->servers;
> + else
> + last_server = daemon->last_server;
> + }
> +#endif
> else if (!(start = daemon->last_server) ||
> daemon->forwardcount++ > FORWARD_TEST ||
> difftime(now, daemon->forwardtime) > FORWARD_TIME)
> @@ -536,6 +549,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
>
> if (start == firstsentto)
> break;
> +#ifdef HAVE_METRIC_ORDER
> + if(option_bool(OPT_METRIC_ORDER) && (start->flags & SERV_FROM_RESOLV) && last_server && (last_server->flags & SERV_FROM_RESOLV) && (start->metric > last_server->metric))
> + start = daemon->servers;
> +#endif
> }
>
> if (forwarded)
> @@ -855,7 +872,19 @@ void reply_query(int fd, int family, time_t now)
> }
> }
> if (!option_bool(OPT_ALL_SERVERS))
> - daemon->last_server = server;
> +#ifdef HAVE_METRIC_ORDER
> + if (!option_bool(OPT_METRIC_ORDER))
> +#endif
> + daemon->last_server = server;
> +#ifdef HAVE_METRIC_ORDER
> + if (option_bool(OPT_METRIC_ORDER) && (server->flags & SERV_FROM_RESOLV))
> + {
> + if (!daemon->last_server)
> + daemon->last_server = server;
> + else if (server->metric < daemon->last_server->metric)
> + daemon->last_server = server;
> + }
> +#endif
> }
>
> /* We tried resending to this server with a smaller maximum size and got an answer.
> @@ -1131,7 +1160,16 @@ void reply_query(int fd, int family, time_t now)
> send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
> &forward->source, &forward->dest, forward->iface);
> }
> +#ifdef HAVE_METRIC_ORDER
> + if (!option_bool(OPT_METRIC_ORDER))
> +#endif
> free_frec(forward); /* cancel */
> +#ifdef HAVE_METRIC_ORDER
> + else if (forward->forwardall > 1)
> + forward->forwardall--;
> + else
> + free_frec(forward);
> +#endif
> }
> }
>
> diff --git a/src/network.c b/src/network.c
> index 0381513..9dd00a2 100644
> --- a/src/network.c
> +++ b/src/network.c
> @@ -1385,7 +1385,8 @@ void add_update_server(int flags,
> union mysockaddr *addr,
> union mysockaddr *source_addr,
> const char *interface,
> - const char *domain)
> + const char *domain,
> + u8 metric)
> {
> struct server *serv, *next = NULL;
> char *domain_str = NULL;
> @@ -1444,6 +1445,9 @@ void add_update_server(int flags,
> serv->domain = domain_str;
> serv->next = next;
> serv->queries = serv->failed_queries = 0;
> +#ifdef HAVE_METRIC_ORDER
> + serv->metric = metric;
> +#endif
> #ifdef HAVE_LOOP
> serv->uid = rand32();
> #endif
> @@ -1616,7 +1620,7 @@ int reload_servers(char *fname)
> FILE *f;
> char *line;
> int gotone = 0;
> -
> + u8 metric = 0;
> /* buff happens to be MAXDNAME long... */
> if (!(f = fopen(fname, "r")))
> {
> @@ -1683,8 +1687,7 @@ int reload_servers(char *fname)
> else
> continue;
> #endif
> -
> - add_update_server(SERV_FROM_RESOLV, &addr, &source_addr, NULL, NULL);
> + add_update_server(SERV_FROM_RESOLV, &addr, &source_addr, NULL, NULL, metric++);
> gotone = 1;
> }
>
> diff --git a/src/option.c b/src/option.c
> index d358d99..84df76e 100644
> --- a/src/option.c
> +++ b/src/option.c
> @@ -160,6 +160,7 @@ struct myoption {
> #define LOPT_DHCPTTL 348
> #define LOPT_TFTP_MTU 349
> #define LOPT_REPLY_DELAY 350
> +#define LOPT_METRIC_ORDER 351
>
> #ifdef HAVE_GETOPT_LONG
> static const struct option opts[] =
> @@ -199,6 +200,7 @@ static const struct myoption opts[] =
> { "filterwin2k", 0, 0, 'f' },
> { "pid-file", 2, 0, 'x' },
> { "strict-order", 0, 0, 'o' },
> + { "metric-order", 0, 0, LOPT_METRIC_ORDER },
> { "server", 1, 0, 'S' },
> { "rev-server", 1, 0, LOPT_REV_SERV },
> { "local", 1, 0, LOPT_LOCAL },
> @@ -380,6 +382,7 @@ static struct {
> { 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE },
> { 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL },
> { 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE },
> + { LOPT_METRIC_ORDER, OPT_METRIC_ORDER, NULL, gettext_noop("Try to use the highest nameserver that is given in %s."), RESOLVFILE },
> { 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL },
> { LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},
> { 'p', ARG_ONE, "<integer>", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
More information about the Dnsmasq-discuss
mailing list