On Fri, 2011-08-12 at 13:50 +0200, Michael Stapelberg wrote: > Hi, > > the attached patch makes the dnsmasq DNS plugin work with IPv6 DNS > servers with link-local IP addresses. This is similar to commit > c3893b5325ca61261be1749490352f26b41bd479, where '%interface' is > appended to the entries in /etc/resolv.conf for link-local DNS servers. > > dnsmasq supports link-local IP addresses when using the syntax > '@interface'. I have talked to the dnsmasq author and he will provide > '%interface' in future versions. > > Please tell me if you need any further information or if I should > change something. Otherwise, please merge this patch :).
Thanks! Though we do risk buffer overflows because the buffer being passed into the function is only INET6_ADDRSTRLEN long, so we need to be more careful here when appending the interface name. I've reworked that a bit, can you test the attached patch and make sure it does the same thing yours does? It's compile-tested but not run tested. When I commit you'll still get credit, of course. Thanks for looking into this. Dan
>From b05f137001f310845b43c9230ae144a7ab7b8dd5 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg <[email protected]> Date: Fri, 12 Aug 2011 13:43:07 +0200 Subject: [PATCH] dnsmasq: use '@interface' for link-local DNS servers in the dnsmasq config dnsmasq doesn't support the standard '%' that inet_ntop() returns, so use '@' instead and append the interface name. --- src/dns-manager/nm-dns-bind.c | 3 +- src/dns-manager/nm-dns-dnsmasq.c | 62 +++++++++++++++++++++++++++++-------- src/dns-manager/nm-dns-manager.c | 3 +- src/dns-manager/nm-dns-plugin.c | 6 ++- src/dns-manager/nm-dns-plugin.h | 6 ++- 5 files changed, 60 insertions(+), 20 deletions(-) diff --git a/src/dns-manager/nm-dns-bind.c b/src/dns-manager/nm-dns-bind.c index fc7af77..55fce03 100644 --- a/src/dns-manager/nm-dns-bind.c +++ b/src/dns-manager/nm-dns-bind.c @@ -297,7 +297,8 @@ update (NMDnsPlugin *plugin, const GSList *vpn_configs, const GSList *dev_configs, const GSList *other_configs, - const char *hostname) + const char *hostname, + const char *iface) { NMDnsBind *self = NM_DNS_BIND (plugin); NMDnsBindPrivate *priv = NM_DNS_BIND_GET_PRIVATE (self); diff --git a/src/dns-manager/nm-dns-dnsmasq.c b/src/dns-manager/nm-dns-dnsmasq.c index 9cc0197..2600d1b 100644 --- a/src/dns-manager/nm-dns-dnsmasq.c +++ b/src/dns-manager/nm-dns-dnsmasq.c @@ -133,23 +133,50 @@ add_ip4_config (GString *str, NMIP4Config *ip4, gboolean split) return TRUE; } -static gboolean -ip6_addr_to_string (const struct in6_addr *addr, char *buf, size_t buflen) +#define IP6_ADDR_BUFLEN (INET6_ADDRSTRLEN + 50) + +static char * +ip6_addr_to_string (const struct in6_addr *addr, const char *iface) { - memset (buf, 0, buflen); + char *buf, *p; + + /* allocate enough space for the address + interface name */ + buf = g_malloc0 (IP6_ADDR_BUFLEN + 1); /* inet_ntop is probably supposed to do this for us, but it doesn't */ - if (IN6_IS_ADDR_V4MAPPED (addr)) - return !!inet_ntop (AF_INET, &(addr->s6_addr32[3]), buf, buflen); + if (IN6_IS_ADDR_V4MAPPED (addr)) { + if (!inet_ntop (AF_INET, &(addr->s6_addr32[3]), buf, IP6_ADDR_BUFLEN)) + goto error; + return buf; + } - return !!inet_ntop (AF_INET6, addr, buf, buflen); + if (!inet_ntop (AF_INET6, addr, buf, IP6_ADDR_BUFLEN)) + goto error; + + /* dnsmasq only supports @ at the moment so replace the '%' with '@' */ + p = strchr (buf, '%'); + if (p) { + *p = '@'; + + /* Append interface name for link-local DNS servers; this assumes the + * '@' is the last character. + */ + if (IN6_IS_ADDR_LINKLOCAL (addr)) + strncat (buf, iface, (IP6_ADDR_BUFLEN - strlen (buf) - 1)); + } + + return buf; + +error: + g_free (buf); + return NULL; } static gboolean -add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split) +add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split, const char *iface) { - char buf[INET6_ADDRSTRLEN + 1]; const struct in6_addr *addr; + char *buf; int n, i; gboolean added = FALSE; @@ -159,7 +186,8 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split) * the first nameserver here. */ addr = nm_ip6_config_get_nameserver (ip6, 0); - if (!ip6_addr_to_string (addr, &buf[0], sizeof (buf))) + buf = ip6_addr_to_string (addr, iface); + if (!buf) return FALSE; /* searches are preferred over domains */ @@ -181,6 +209,8 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split) added = TRUE; } } + + g_free (buf); } /* If no searches or domains, just add the namservers */ @@ -188,8 +218,11 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split) n = nm_ip6_config_get_num_nameservers (ip6); for (i = 0; i < n; i++) { addr = nm_ip6_config_get_nameserver (ip6, i); - if (ip6_addr_to_string (addr, &buf[0], sizeof (buf))) + buf = ip6_addr_to_string (addr, iface); + if (buf) { g_string_append_printf (str, "server=%s\n", buf); + g_free (buf); + } } } @@ -201,7 +234,8 @@ update (NMDnsPlugin *plugin, const GSList *vpn_configs, const GSList *dev_configs, const GSList *other_configs, - const char *hostname) + const char *hostname, + const char *iface) { NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin); GString *conf; @@ -226,7 +260,7 @@ update (NMDnsPlugin *plugin, if (NM_IS_IP4_CONFIG (iter->data)) add_ip4_config (conf, NM_IP4_CONFIG (iter->data), TRUE); else if (NM_IS_IP6_CONFIG (iter->data)) - add_ip6_config (conf, NM_IP6_CONFIG (iter->data), TRUE); + add_ip6_config (conf, NM_IP6_CONFIG (iter->data), TRUE, iface); } /* Now add interface configs without split DNS */ @@ -234,7 +268,7 @@ update (NMDnsPlugin *plugin, if (NM_IS_IP4_CONFIG (iter->data)) add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE); else if (NM_IS_IP6_CONFIG (iter->data)) - add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE); + add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE, iface); } /* And any other random configs */ @@ -242,7 +276,7 @@ update (NMDnsPlugin *plugin, if (NM_IS_IP4_CONFIG (iter->data)) add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE); else if (NM_IS_IP6_CONFIG (iter->data)) - add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE); + add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE, iface); } /* Write out the config file */ diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c index 49cd74e..0203f2b 100644 --- a/src/dns-manager/nm-dns-manager.c +++ b/src/dns-manager/nm-dns-manager.c @@ -711,7 +711,8 @@ update_dns (NMDnsManager *self, vpn_configs, dev_configs, other_configs, - priv->hostname)) { + priv->hostname, + iface)) { nm_log_warn (LOGD_DNS, "DNS: plugin %s update failed", plugin_name); /* If the plugin failed to update, we shouldn't write out a local diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c index ae230ad..e997948 100644 --- a/src/dns-manager/nm-dns-plugin.c +++ b/src/dns-manager/nm-dns-plugin.c @@ -55,7 +55,8 @@ nm_dns_plugin_update (NMDnsPlugin *self, const GSList *vpn_configs, const GSList *dev_configs, const GSList *other_configs, - const char *hostname) + const char *hostname, + const char *iface) { g_return_val_if_fail (NM_DNS_PLUGIN_GET_CLASS (self)->update != NULL, FALSE); @@ -63,7 +64,8 @@ nm_dns_plugin_update (NMDnsPlugin *self, vpn_configs, dev_configs, other_configs, - hostname); + hostname, + iface); } static gboolean diff --git a/src/dns-manager/nm-dns-plugin.h b/src/dns-manager/nm-dns-plugin.h index d4298b8..37dd733 100644 --- a/src/dns-manager/nm-dns-plugin.h +++ b/src/dns-manager/nm-dns-plugin.h @@ -53,7 +53,8 @@ typedef struct { const GSList *vpn_configs, const GSList *dev_configs, const GSList *other_configs, - const char *hostname); + const char *hostname, + const char *iface); /* Subclasses should override and return TRUE if they start a local * caching nameserver that listens on localhost and would block any @@ -91,7 +92,8 @@ gboolean nm_dns_plugin_update (NMDnsPlugin *self, const GSList *vpn_configs, const GSList *dev_configs, const GSList *other_configs, - const char *hostname); + const char *hostname, + const char *iface); /* For subclasses/plugins */ -- 1.7.6
_______________________________________________ networkmanager-list mailing list [email protected] http://mail.gnome.org/mailman/listinfo/networkmanager-list
