dns: merge branch 'bg/dns-dbus-bgo603321'

https://bugzilla.gnome.org/show_bug.cgi?id=603321
This commit is contained in:
Beniamino Galvani 2016-12-12 22:27:39 +01:00
commit 597f327b20
15 changed files with 1352 additions and 132 deletions

View file

@ -223,6 +223,8 @@ introspection_sources = \
introspection/org.freedesktop.NetworkManager.DHCP4Config.h \
introspection/org.freedesktop.NetworkManager.DHCP6Config.c \
introspection/org.freedesktop.NetworkManager.DHCP6Config.h \
introspection/org.freedesktop.NetworkManager.DnsManager.c \
introspection/org.freedesktop.NetworkManager.DnsManager.h \
introspection/org.freedesktop.NetworkManager.IP4Config.c \
introspection/org.freedesktop.NetworkManager.IP4Config.h \
introspection/org.freedesktop.NetworkManager.IP6Config.c \
@ -324,6 +326,7 @@ dbusinterfaces_DATA = \
introspection/org.freedesktop.NetworkManager.Device.xml \
introspection/org.freedesktop.NetworkManager.DHCP4Config.xml \
introspection/org.freedesktop.NetworkManager.DHCP6Config.xml \
introspection/org.freedesktop.NetworkManager.DnsManager.xml \
introspection/org.freedesktop.NetworkManager.IP4Config.xml \
introspection/org.freedesktop.NetworkManager.IP6Config.xml \
introspection/org.freedesktop.NetworkManager.xml \
@ -693,6 +696,7 @@ libnm_lib_h_priv = \
libnm/nm-device-private.h \
libnm/nm-dhcp4-config.h \
libnm/nm-dhcp6-config.h \
libnm/nm-dns-manager.h \
libnm/nm-ip4-config.h \
libnm/nm-ip6-config.h \
libnm/nm-manager.h \
@ -725,6 +729,7 @@ libnm_lib_c_real = \
libnm/nm-dhcp-config.c \
libnm/nm-dhcp4-config.c \
libnm/nm-dhcp6-config.c \
libnm/nm-dns-manager.c \
libnm/nm-ip-config.c \
libnm/nm-ip4-config.c \
libnm/nm-ip6-config.c \

View file

@ -1193,6 +1193,7 @@ do_overview (NmCli *nmc, int argc, char **argv)
const GPtrArray *p;
NMActiveConnection *ac;
NmcTermColor color;
NMDnsEntry *dns;
char *tmp;
int i;
@ -1248,6 +1249,39 @@ do_overview (NmCli *nmc, int argc, char **argv)
}
g_free (devices);
p = nm_client_get_dns_configuration (nmc->client);
for (i = 0; p && i < p->len; i++) {
const char * const *strv;
dns = p->pdata[i];
strv = nm_dns_entry_get_nameservers (dns);
if (!strv || !strv[0]) {
/* Invalid entry */
continue;
}
if (i == 0)
g_print ("DNS configuration:\n");
tmp = g_strjoinv (" ", (char **) strv);
g_print ("\tservers: %s\n", tmp);
g_free (tmp);
strv = nm_dns_entry_get_domains (dns);
if (strv && strv[0]) {
tmp = g_strjoinv (" ", (char **) strv);
g_print ("\tdomains: %s\n", tmp);
g_free (tmp);
}
if (nm_dns_entry_get_interface (dns))
g_print ("\tinterface: %s\n", nm_dns_entry_get_interface (dns));
if (nm_dns_entry_get_vpn (dns))
g_print ("\ttype: vpn\n");
g_print ("\n");
}
g_print (_("Use \"nmcli device show\" to get complete information about known devices and\n"
"\"nmcli connection show\" to get an overview on active connection profiles.\n"
"\n"

View file

@ -42,6 +42,7 @@ IGNORE_HFILES= \
nm-device-private.h \
nm-dhcp4-config.h \
nm-dhcp6-config.h \
nm-dns-manager.h \
nm-ip4-config.h \
nm-ip6-config.h \
nm-manager.h \

63
examples/python/gi/dns.py Executable file
View file

@ -0,0 +1,63 @@
#!/usr/bin/env python
#
# vim: ft=python ts=4 sts=4 sw=4 et ai
# -*- Mode: Python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright (C) 2016 Red Hat, Inc.
#
import sys
import gi
gi.require_version('NM', '1.0')
from gi.repository import GLib, NM
# This example shows how to monitor the DNS configuration
main_loop = None
def handle_config(config):
print " ---- new configuration ----"
for entry in config:
print " * servers: %s" % ', '.join(map(str, entry.get_nameservers()))
domains = entry.get_domains()
if domains and domains[0]:
print " domains: %s" % ', '.join(map(str, domains))
if entry.get_interface():
print " interface: %s" % entry.get_interface()
print " priority: %d" % entry.get_priority()
if entry.get_vpn():
print " vpn: yes"
print ""
def dns_config_changed(self, property):
handle_config(self.get_dns_configuration())
main_loop = None
if __name__ == "__main__":
c = NM.Client.new(None)
c.connect("notify::dns-configuration", dns_config_changed)
handle_config(c.get_dns_configuration())
main_loop = GLib.MainLoop()
main_loop.run()

View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<node name="/org/freedesktop/NetworkManager/DnsManager">
<!--
org.freedesktop.NetworkManager.DnsManager:
The interface contains DNS-related information.
-->
<interface name="org.freedesktop.NetworkManager.DnsManager">
<!--
Mode:
The current DNS processing mode.
-->
<property name="Mode" type="s" access="read"/>
<!--
RcManager:
The current resolv.conf management mode.
-->
<property name="RcManager" type="s" access="read"/>
<!--
Configuration:
The current DNS configuration represented as an array of
dictionaries. Each dictionary has the "nameservers",
"priority" keys and, optionally, "interface" and "vpn".
"nameservers" is the list of DNS servers, "priority" their
relative priority, "interface" the interface on which these
servers are contacted, "vpn" a boolean telling whether the
configuration was obtained from a VPN connection.
-->
<property name="Configuration" type="aa{sv}" access="read"/>
</interface>
</node>

View file

@ -83,6 +83,9 @@
#define NM_DBUS_INTERFACE_SECRET_AGENT NM_DBUS_INTERFACE ".SecretAgent"
#define NM_DBUS_PATH_SECRET_AGENT "/org/freedesktop/NetworkManager/SecretAgent"
#define NM_DBUS_INTERFACE_DNS_MANAGER "org.freedesktop.NetworkManager.DnsManager"
#define NM_DBUS_PATH_DNS_MANAGER "/org/freedesktop/NetworkManager/DnsManager"
/**
* NMCapability:
* @NM_CAPABILITY_TEAM: Teams can be managed

View file

@ -1087,7 +1087,17 @@ global:
libnm_1_6_0 {
global:
nm_capability_get_type;
nm_client_get_dns_configuration;
nm_client_get_dns_mode;
nm_client_get_dns_rc_manager;
nm_connection_get_setting_proxy;
nm_dns_entry_get_domains;
nm_dns_entry_get_interface;
nm_dns_entry_get_nameservers;
nm_dns_entry_get_priority;
nm_dns_entry_get_type;
nm_dns_entry_get_vpn;
nm_dns_entry_unref;
nm_setting_connection_get_autoconnect_retries;
nm_setting_proxy_get_type;
nm_setting_proxy_new;

View file

@ -26,6 +26,7 @@
#include "nm-utils.h"
#include "nm-client.h"
#include "nm-manager.h"
#include "nm-dns-manager.h"
#include "nm-remote-settings.h"
#include "nm-device-ethernet.h"
#include "nm-device-wifi.h"
@ -40,6 +41,7 @@
#include "introspection/org.freedesktop.NetworkManager.h"
#include "introspection/org.freedesktop.NetworkManager.Device.Wireless.h"
#include "introspection/org.freedesktop.NetworkManager.Device.h"
#include "introspection/org.freedesktop.NetworkManager.DnsManager.h"
#include "introspection/org.freedesktop.NetworkManager.Settings.h"
#include "introspection/org.freedesktop.NetworkManager.Settings.Connection.h"
#include "introspection/org.freedesktop.NetworkManager.VPN.Connection.h"
@ -88,6 +90,7 @@ G_DEFINE_TYPE_WITH_CODE (NMClient, nm_client, G_TYPE_OBJECT,
typedef struct {
NMManager *manager;
NMRemoteSettings *settings;
NMDnsManager *dns_manager;
GDBusObjectManager *object_manager;
GCancellable *new_object_manager_cancellable;
} NMClientPrivate;
@ -115,6 +118,9 @@ enum {
PROP_HOSTNAME,
PROP_CAN_MODIFY,
PROP_METERED,
PROP_DNS_MODE,
PROP_DNS_RC_MANAGER,
PROP_DNS_CONFIGURATION,
LAST_PROP
};
@ -1716,6 +1722,85 @@ nm_client_reload_connections_finish (NMClient *client,
/*****************************************************************************/
/**
* nm_client_get_dns_mode:
* @client: the #NMClient
*
* Gets the current DNS processing mode.
*
* Return value: the DNS processing mode, or %NULL in case the
* value is not available.
*
* Since: 1.6
**/
const char *
nm_client_get_dns_mode (NMClient *client)
{
NMClientPrivate *priv;
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
priv = NM_CLIENT_GET_PRIVATE (client);
if (priv->dns_manager)
return nm_dns_manager_get_mode (priv->dns_manager);
else
return NULL;
}
/**
* nm_client_get_dns_rc_manager:
* @client: the #NMClient
*
* Gets the current DNS resolv.conf manager.
*
* Return value: the resolv.conf manager or %NULL in case the
* value is not available.
*
* Since: 1.6
**/
const char *
nm_client_get_dns_rc_manager (NMClient *client)
{
NMClientPrivate *priv;
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
priv = NM_CLIENT_GET_PRIVATE (client);
if (priv->dns_manager)
return nm_dns_manager_get_rc_manager (priv->dns_manager);
else
return NULL;
}
/**
* nm_client_get_dns_configuration:
* @client: a #NMClient
*
* Gets the current DNS configuration
*
* Returns: (transfer none) (element-type NMDnsEntry): a #GPtrArray
* containing #NMDnsEntry elements or %NULL in case the value is not
* available. The returned array is owned by the #NMClient object
* and should not be modified.
*
* Since: 1.6
**/
const GPtrArray *
nm_client_get_dns_configuration (NMClient *client)
{
NMClientPrivate *priv;
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
priv = NM_CLIENT_GET_PRIVATE (client);
if (priv->dns_manager)
return nm_dns_manager_get_configuration (priv->dns_manager);
else
return NULL;
}
/*****************************************************************************/
/**
* nm_client_new:
* @cancellable: a #GCancellable, or %NULL
@ -1881,6 +1966,22 @@ manager_active_connection_removed (NMManager *manager,
g_signal_emit (client, signals[ACTIVE_CONNECTION_REMOVED], 0, active_connection);
}
static void
dns_notify (GObject *object,
GParamSpec *pspec,
gpointer client)
{
char pname[128];
if (NM_IN_STRSET (pspec->name,
NM_DNS_MANAGER_MODE,
NM_DNS_MANAGER_RC_MANAGER,
NM_DNS_MANAGER_CONFIGURATION)) {
nm_sprintf_buf (pname, "dns-%s", pspec->name);
g_object_notify (client, pname);
}
}
/****************************************************************/
/* Object Initialization */
/****************************************************************/
@ -1909,6 +2010,8 @@ proxy_type (GDBusObjectManagerClient *manager,
return NMDBUS_TYPE_SETTINGS_CONNECTION_PROXY;
else if (strcmp (interface_name, NM_DBUS_INTERFACE_SETTINGS) == 0)
return NMDBUS_TYPE_SETTINGS_PROXY;
else if (strcmp (interface_name, NM_DBUS_INTERFACE_DNS_MANAGER) == 0)
return NMDBUS_TYPE_DNS_MANAGER_PROXY;
else if (strcmp (interface_name, NM_DBUS_INTERFACE_VPN_CONNECTION) == 0)
return NMDBUS_TYPE_VPN_CONNECTION_PROXY;
@ -1988,6 +2091,8 @@ obj_nm_for_gdbus_object (GDBusObject *object, GDBusObjectManager *object_manager
type = NM_TYPE_REMOTE_CONNECTION;
else if (strcmp (ifname, NM_DBUS_INTERFACE_SETTINGS) == 0)
type = NM_TYPE_REMOTE_SETTINGS;
else if (strcmp (ifname, NM_DBUS_INTERFACE_DNS_MANAGER) == 0)
type = NM_TYPE_DNS_MANAGER;
else if (strcmp (ifname, NM_DBUS_INTERFACE_VPN_CONNECTION) == 0)
type = NM_TYPE_VPN_CONNECTION;
else if (strcmp (ifname, NM_DBUS_INTERFACE_WIMAX_NSP) == 0)
@ -2046,6 +2151,7 @@ objects_created (NMClient *client, GDBusObjectManager *object_manager, GError **
NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
gs_unref_object GDBusObject *manager = NULL;
gs_unref_object GDBusObject *settings = NULL;
gs_unref_object GDBusObject *dns_manager = NULL;
NMObject *obj_nm;
GList *objects, *iter;
@ -2119,6 +2225,23 @@ objects_created (NMClient *client, GDBusObjectManager *object_manager, GError **
g_signal_connect (priv->settings, "connection-removed",
G_CALLBACK (settings_connection_removed), client);
dns_manager = g_dbus_object_manager_get_object (object_manager, NM_DBUS_PATH_DNS_MANAGER);
if (dns_manager) {
obj_nm = g_object_get_qdata (G_OBJECT (dns_manager), _nm_object_obj_nm_quark ());
if (!obj_nm) {
g_set_error_literal (error,
NM_CLIENT_ERROR,
NM_CLIENT_ERROR_MANAGER_NOT_RUNNING,
"DNS manager object lacks the proper interface");
return FALSE;
}
priv->dns_manager = NM_DNS_MANAGER (g_object_ref (obj_nm));
g_signal_connect (priv->dns_manager, "notify",
G_CALLBACK (dns_notify), client);
}
/* The handlers don't really use the client instance. However
* it makes it convenient to unhook them by data. */
g_signal_connect (object_manager, "object-added",
@ -2257,6 +2380,10 @@ unhook_om (NMClient *self)
g_object_notify (G_OBJECT (self), NM_CLIENT_HOSTNAME);
g_object_notify (G_OBJECT (self), NM_CLIENT_CAN_MODIFY);
}
if (priv->dns_manager) {
g_signal_handlers_disconnect_by_data (priv->dns_manager, self);
g_clear_object (&priv->dns_manager);
}
objects = g_dbus_object_manager_get_objects (priv->object_manager);
for (iter = objects; iter; iter = iter->next)
@ -2415,6 +2542,11 @@ dispose (GObject *object)
g_clear_object (&priv->settings);
}
if (priv->dns_manager) {
g_signal_handlers_disconnect_by_data (priv->dns_manager, object);
g_clear_object (&priv->dns_manager);
}
if (priv->object_manager) {
GList *objects, *iter;
@ -2547,6 +2679,25 @@ get_property (GObject *object, guint prop_id,
else
g_value_set_boolean (value, FALSE);
break;
/* DNS properties */
case PROP_DNS_MODE:
case PROP_DNS_RC_MANAGER:
g_return_if_fail (pspec->name && strlen (pspec->name) > NM_STRLEN ("dns-"));
if (priv->dns_manager)
g_object_get_property (G_OBJECT (priv->dns_manager),
&pspec->name[NM_STRLEN ("dns-")], value);
else
g_value_set_string (value, NULL);
break;
case PROP_DNS_CONFIGURATION:
if (priv->dns_manager) {
g_object_get_property (G_OBJECT (priv->dns_manager),
NM_DNS_MANAGER_CONFIGURATION,
value);
} else
g_value_take_boxed (value, NULL);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -2838,6 +2989,54 @@ nm_client_class_init (NMClientClass *client_class)
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
* NMClient:dns-mode:
*
* The current DNS processing mode.
*
* Since: 1.6
**/
g_object_class_install_property
(object_class, PROP_DNS_MODE,
g_param_spec_string (NM_CLIENT_DNS_MODE, "", "",
"",
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
* NMClient:dns-rc-manager:
*
* The current resolv.conf management mode.
*
* Since: 1.6
**/
g_object_class_install_property
(object_class, PROP_DNS_RC_MANAGER,
g_param_spec_string (NM_CLIENT_DNS_RC_MANAGER, "", "",
"",
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
* NMClient:dns-configuration:
*
* The current DNS configuration represented as an array of
* dictionaries. Each dictionary has the "nameservers",
* "priority" keys and, optionally, "interface" and "vpn".
* "nameservers" is the list of DNS servers, "priority" their
* relative priority, "interface" the interface on which these
* servers are contacted, "vpn" a boolean telling whether the
* configuration was obtained from a VPN connection.
*
* Since: 1.6
**/
g_object_class_install_property
(object_class, PROP_DNS_CONFIGURATION,
g_param_spec_boxed (NM_CLIENT_DNS_CONFIGURATION, "", "",
G_TYPE_PTR_ARRAY,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/* signals */
/**

View file

@ -58,6 +58,9 @@ G_BEGIN_DECLS
#define NM_CLIENT_HOSTNAME "hostname"
#define NM_CLIENT_CAN_MODIFY "can-modify"
#define NM_CLIENT_METERED "metered"
#define NM_CLIENT_DNS_MODE "dns-mode"
#define NM_CLIENT_DNS_RC_MANAGER "dns-rc-manager"
#define NM_CLIENT_DNS_CONFIGURATION "dns-configuration"
#define NM_CLIENT_DEVICE_ADDED "device-added"
#define NM_CLIENT_DEVICE_REMOVED "device-removed"
@ -169,6 +172,25 @@ typedef enum {
#define NM_CLIENT_ERROR nm_client_error_quark ()
GQuark nm_client_error_quark (void);
/* DNS stuff */
typedef struct NMDnsEntry NMDnsEntry;
NM_AVAILABLE_IN_1_6
GType nm_dns_entry_get_type (void);
NM_AVAILABLE_IN_1_6
void nm_dns_entry_unref (NMDnsEntry *entry);
NM_AVAILABLE_IN_1_6
const char * nm_dns_entry_get_interface (NMDnsEntry *entry);
NM_AVAILABLE_IN_1_6
const char * const *nm_dns_entry_get_nameservers (NMDnsEntry *entry);
NM_AVAILABLE_IN_1_6
const char * const *nm_dns_entry_get_domains (NMDnsEntry *entry);
NM_AVAILABLE_IN_1_6
int nm_dns_entry_get_priority (NMDnsEntry *entry);
NM_AVAILABLE_IN_1_6
gboolean nm_dns_entry_get_vpn (NMDnsEntry *entry);
/**
* NMClient:
*/
@ -359,6 +381,13 @@ gboolean nm_client_reload_connections_finish (NMClient *client,
GAsyncResult *result,
GError **error);
NM_AVAILABLE_IN_1_6
const char *nm_client_get_dns_mode (NMClient *client);
NM_AVAILABLE_IN_1_6
const char *nm_client_get_dns_rc_manager (NMClient *client);
NM_AVAILABLE_IN_1_6
const GPtrArray *nm_client_get_dns_configuration (NMClient *client);
G_END_DECLS
#endif /* __NM_CLIENT_H__ */

448
libnm/nm-dns-manager.c Normal file
View file

@ -0,0 +1,448 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright 2016 Red Hat, Inc.
*/
#include "nm-default.h"
#include "nm-dns-manager.h"
#include <string.h>
#include "nm-dbus-interface.h"
#include "nm-connection.h"
#include "nm-client.h"
#include "nm-object-private.h"
#include "nm-dbus-helpers.h"
#include "nm-core-internal.h"
#include "introspection/org.freedesktop.NetworkManager.DnsManager.h"
G_DEFINE_TYPE (NMDnsManager, nm_dns_manager, NM_TYPE_OBJECT)
#define NM_DNS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DNS_MANAGER, NMDnsManagerPrivate))
typedef struct {
NMDBusDnsManager *proxy;
char *mode;
char *rc_manager;
GPtrArray *configuration;
} NMDnsManagerPrivate;
enum {
PROP_0,
PROP_MODE,
PROP_RC_MANAGER,
PROP_CONFIGURATION,
LAST_PROP
};
/*****************************************************************************
* NMDnsEntry
*****************************************************************************/
G_DEFINE_BOXED_TYPE (NMDnsEntry, nm_dns_entry, nm_dns_entry_dup, nm_dns_entry_unref)
struct NMDnsEntry {
guint refcount;
char *interface;
char **nameservers;
char **domains;
int priority;
gboolean vpn;
};
/**
* nm_dns_entry_new:
*
* Creates a new #NMDnsEntry object.
*
* Returns: (transfer full): the new #NMDnsEntry object, or %NULL on error
**/
NMDnsEntry *
nm_dns_entry_new (const char *interface,
const char * const *nameservers,
const char * const *domains,
int priority,
gboolean vpn)
{
NMDnsEntry *entry;
guint i, len;
entry = g_slice_new0 (NMDnsEntry);
entry->refcount = 1;
entry->interface = g_strdup (interface);
if (nameservers) {
len = g_strv_length ((char **) nameservers);
entry->nameservers = g_new (char *, len + 1);
for (i = 0; i < len + 1; i++)
entry->nameservers[i] = g_strdup (nameservers[i]);
}
if (domains) {
len = g_strv_length ((char **) domains);
entry->domains = g_new (char *, len + 1);
for (i = 0; i < len + 1; i++)
entry->domains[i] = g_strdup (domains[i]);
}
entry->priority = priority;
entry->vpn = vpn;
return entry;
}
/**
* nm_dns_entry_dup:
* @entry: the #NMDnsEntry
*
* Creates a copy of @entry
*
* Returns: (transfer full): a copy of @entry
**/
NMDnsEntry *
nm_dns_entry_dup (NMDnsEntry *entry)
{
NMDnsEntry *copy;
g_return_val_if_fail (entry != NULL, NULL);
g_return_val_if_fail (entry->refcount > 0, NULL);
copy = nm_dns_entry_new (entry->interface,
(const char * const *) entry->nameservers,
(const char * const *) entry->domains,
entry->priority,
entry->vpn);
return copy;
}
/**
* nm_dns_entry_unref:
* @entry: the #NMDnsEntry
*
* Decreases the reference count of the object. If the reference count
* reaches zero, the object will be destroyed.
*
* Since: 1.6
**/
void
nm_dns_entry_unref (NMDnsEntry *entry)
{
g_return_if_fail (entry != NULL);
g_return_if_fail (entry->refcount > 0);
entry->refcount--;
if (entry->refcount == 0) {
g_free (entry->interface);
g_strfreev (entry->nameservers);
g_strfreev (entry->domains);
g_slice_free (NMDnsEntry, entry);
}
}
/**
* nm_dns_entry_get_interface:
* @entry: the #NMDnsEntry
*
* Gets the interface on which name servers are contacted.
*
* Returns: (transfer none): the interface name
*
* Since: 1.6
**/
const char *
nm_dns_entry_get_interface (NMDnsEntry *entry)
{
g_return_val_if_fail (entry, 0);
g_return_val_if_fail (entry->refcount > 0, 0);
return entry->interface;
}
/**
* nm_dns_entry_get_nameservers:
* @entry: the #NMDnsEntry
*
* Gets the list of name servers for this entry.
*
* Returns: (transfer none): the list of name servers
*
* Since: 1.6
**/
const char * const *
nm_dns_entry_get_nameservers (NMDnsEntry *entry)
{
g_return_val_if_fail (entry, 0);
g_return_val_if_fail (entry->refcount > 0, 0);
return (const char * const *) entry->nameservers;
}
/**
* nm_dns_entry_get_domains:
* @entry: the #NMDnsEntry
*
* Gets the list of DNS domains.
*
* Returns: (transfer none): the list of DNS domains
*
* Since: 1.6
**/
const char * const *
nm_dns_entry_get_domains (NMDnsEntry *entry)
{
g_return_val_if_fail (entry, 0);
g_return_val_if_fail (entry->refcount > 0, 0);
return (const char * const *)entry->domains;
}
/**
* nm_dns_entry_get_vpn:
* @entry: the #NMDnsEntry
*
* Gets whether the entry refers to VPN name servers.
*
* Returns: %TRUE if the entry refers to VPN name servers
*
* Since: 1.6
**/
gboolean
nm_dns_entry_get_vpn (NMDnsEntry *entry)
{
g_return_val_if_fail (entry, 0);
g_return_val_if_fail (entry->refcount > 0, 0);
return entry->vpn;
}
/**
* nm_dns_entry_get_priority:
* @entry: the #NMDnsEntry
*
* Gets the priority of the entry
*
* Returns: the priority of the entry
*
* Since: 1.6
**/
int
nm_dns_entry_get_priority (NMDnsEntry *entry)
{
g_return_val_if_fail (entry, 0);
g_return_val_if_fail (entry->refcount > 0, 0);
return entry->priority;
}
/*****************************************************************************/
static gboolean
demarshal_dns_configuration (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
{
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (object);
GVariant *entry_var;
GVariantIter iter, *iterp;
NMDnsEntry *entry;
GPtrArray *array;
g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")), FALSE);
g_variant_iter_init (&iter, value);
g_ptr_array_unref (priv->configuration);
priv->configuration = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_dns_entry_unref);
while (g_variant_iter_next (&iter, "@a{sv}", &entry_var)) {
char **nameservers = NULL, **domains = NULL;
gboolean vpn = FALSE;
char *interface = NULL, *str;
gint priority;
if ( !g_variant_lookup (entry_var, "nameservers", "as", &iterp)
|| !g_variant_lookup (entry_var, "priority", "i", &priority)) {
g_warning ("Ignoring invalid DNS configuration");
g_variant_unref (entry_var);
continue;
}
array = g_ptr_array_new ();
while (g_variant_iter_next (iterp, "&s", &str))
g_ptr_array_add (array, str);
g_ptr_array_add (array, NULL);
nameservers = (char **) g_ptr_array_free (array, FALSE);
g_variant_iter_free (iterp);
if (g_variant_lookup (entry_var, "domains", "as", &iterp)) {
array = g_ptr_array_new ();
while (g_variant_iter_next (iterp, "&s", &str))
g_ptr_array_add (array, str);
g_ptr_array_add (array, NULL);
domains = (char **) g_ptr_array_free (array, FALSE);
g_variant_iter_free (iterp);
}
g_variant_lookup (entry_var, "interface", "&s", &interface);
g_variant_lookup (entry_var, "priority", "i", &priority);
g_variant_lookup (entry_var, "vpn", "b", &vpn);
entry = nm_dns_entry_new (interface,
(const char * const *) nameservers,
(const char * const *) domains,
priority,
vpn);
if (!entry) {
g_warning ("Ignoring invalid DNS entry");
g_variant_unref (entry_var);
continue;
}
g_ptr_array_add (priv->configuration, entry);
}
_nm_object_queue_notify (object, NM_DNS_MANAGER_CONFIGURATION);
return TRUE;
}
/*****************************************************************************/
const char *
nm_dns_manager_get_mode (NMDnsManager *manager)
{
return NM_DNS_MANAGER_GET_PRIVATE (manager)->mode;
}
const char *
nm_dns_manager_get_rc_manager (NMDnsManager *manager)
{
return NM_DNS_MANAGER_GET_PRIVATE (manager)->rc_manager;
}
const GPtrArray *
nm_dns_manager_get_configuration (NMDnsManager *manager)
{
return NM_DNS_MANAGER_GET_PRIVATE (manager)->configuration;
}
/*****************************************************************************/
static void
nm_dns_manager_init (NMDnsManager *self)
{
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
priv->configuration = g_ptr_array_new ();
}
static void
init_dbus (NMObject *object)
{
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (object);
const NMPropertiesInfo property_info[] = {
{ NM_DNS_MANAGER_MODE, &priv->mode },
{ NM_DNS_MANAGER_RC_MANAGER, &priv->rc_manager },
{ NM_DNS_MANAGER_CONFIGURATION, &priv->configuration, demarshal_dns_configuration },
{ NULL },
};
NM_OBJECT_CLASS (nm_dns_manager_parent_class)->init_dbus (object);
priv->proxy = NMDBUS_DNS_MANAGER (_nm_object_get_proxy (object, NM_DBUS_INTERFACE_DNS_MANAGER));
_nm_object_register_properties (object,
NM_DBUS_INTERFACE_DNS_MANAGER,
property_info);
}
static void
dispose (GObject *object)
{
NMDnsManager *self = NM_DNS_MANAGER (object);
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
g_clear_pointer (&priv->mode, g_free);
g_clear_pointer (&priv->rc_manager, g_free);
g_clear_pointer (&priv->configuration, g_ptr_array_unref);
G_OBJECT_CLASS (nm_dns_manager_parent_class)->dispose (object);
}
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (object);
switch (prop_id) {
case PROP_MODE:
g_value_set_string (value, priv->mode);
break;
case PROP_RC_MANAGER:
g_value_set_string (value, priv->rc_manager);
break;
case PROP_CONFIGURATION:
g_value_take_boxed (value, _nm_utils_copy_array (priv->configuration,
(NMUtilsCopyFunc) nm_dns_entry_dup,
(GDestroyNotify) nm_dns_entry_unref));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
nm_dns_manager_class_init (NMDnsManagerClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
NMObjectClass *nm_object_class = NM_OBJECT_CLASS (class);
g_type_class_add_private (class, sizeof (NMDnsManagerPrivate));
/* Virtual methods */
object_class->get_property = get_property;
object_class->dispose = dispose;
nm_object_class->init_dbus = init_dbus;
/* Properties */
g_object_class_install_property
(object_class, PROP_MODE,
g_param_spec_string (NM_DNS_MANAGER_MODE, "", "",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_RC_MANAGER,
g_param_spec_string (NM_DNS_MANAGER_RC_MANAGER, "", "",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_CONFIGURATION,
g_param_spec_boxed (NM_DNS_MANAGER_CONFIGURATION, "", "",
G_TYPE_PTR_ARRAY,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
}

72
libnm/nm-dns-manager.h Normal file
View file

@ -0,0 +1,72 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright 2016 Red Hat, Inc.
*/
#ifndef __NM_DNS_MANAGER_H__
#define __NM_DNS_MANAGER_H__
#include <nm-object.h>
#include "nm-client.h"
G_BEGIN_DECLS
#define NM_TYPE_DNS_MANAGER (nm_dns_manager_get_type ())
#define NM_DNS_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DNS_MANAGER, NMDnsManager))
#define NM_DNS_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DNS_MANAGER, NMDnsManagerClass))
#define NM_IS_DNS_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DNS_MANAGER))
#define NM_IS_DNS_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DNS_MANAGER))
#define NM_DNS_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DNS_MANAGER, NMDnsManagerClass))
#define NM_DNS_MANAGER_MODE "mode"
#define NM_DNS_MANAGER_RC_MANAGER "rc-manager"
#define NM_DNS_MANAGER_CONFIGURATION "configuration"
typedef struct _NMDnsManager NMDnsManager;
typedef struct _NMDnsManagerClass NMDnsManagerClass;
/**
* NMDnsManager:
*/
struct _NMDnsManager {
NMObject parent;
};
struct _NMDnsManagerClass {
NMObjectClass parent;
/*< private >*/
gpointer padding[8];
};
G_END_DECLS
GType nm_dns_manager_get_type (void);
const char *nm_dns_manager_get_mode (NMDnsManager *manager);
const char *nm_dns_manager_get_rc_manager (NMDnsManager *manager);
const GPtrArray *nm_dns_manager_get_configuration (NMDnsManager *manager);
NMDnsEntry * nm_dns_entry_new (const char *interface,
const char * const *nameservers,
const char * const *domains,
int priority,
gboolean vpn);
NMDnsEntry * nm_dns_entry_dup (NMDnsEntry *entry);
#endif /* __NM_DNS_MANAGER_H__ */

View file

@ -42,12 +42,16 @@
#include "nm-ip6-config.h"
#include "NetworkManagerUtils.h"
#include "nm-config.h"
#include "devices/nm-device.h"
#include "nm-manager.h"
#include "nm-dns-plugin.h"
#include "nm-dns-dnsmasq.h"
#include "nm-dns-systemd-resolved.h"
#include "nm-dns-unbound.h"
#include "introspection/org.freedesktop.NetworkManager.DnsManager.h"
#if WITH_LIBSOUP
#include <libsoup/soup.h>
@ -82,6 +86,12 @@ enum {
LAST_SIGNAL
};
NM_GOBJECT_PROPERTIES_DEFINE (NMDnsManager,
PROP_MODE,
PROP_RC_MANAGER,
PROP_CONFIGURATION,
);
static guint signals[LAST_SIGNAL] = { 0 };
typedef enum {
@ -116,6 +126,7 @@ typedef enum {
typedef struct {
GPtrArray *configs;
GVariant *config_variant;
NMDnsIPConfigData *best_conf4, *best_conf6;
gboolean need_sort;
@ -126,6 +137,7 @@ typedef struct {
guint8 prev_hash[HASH_LEN]; /* Hash when begin_updates() was called */
NMDnsManagerResolvConfManager rc_manager;
char *mode;
NMDnsPlugin *plugin;
NMConfig *config;
@ -140,15 +152,15 @@ typedef struct {
} NMDnsManagerPrivate;
struct _NMDnsManager {
GObject parent;
NMExportedObject parent;
NMDnsManagerPrivate _priv;
};
struct _NMDnsManagerClass {
GObjectClass parent;
NMExportedObjectClass parent;
};
G_DEFINE_TYPE (NMDnsManager, nm_dns_manager, G_TYPE_OBJECT)
G_DEFINE_TYPE (NMDnsManager, nm_dns_manager, NM_TYPE_EXPORTED_OBJECT)
NM_DEFINE_SINGLETON_INSTANCE (NMDnsManager);
@ -389,8 +401,7 @@ merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src, const char *iface)
}
static void
merge_one_ip_config_data (NMDnsManager *self,
NMResolvConfData *rc,
merge_one_ip_config_data (NMResolvConfData *rc,
NMDnsIPConfigData *data)
{
if (NM_IS_IP4_CONFIG (data->config))
@ -968,30 +979,141 @@ get_nameserver_list (void *config, GString **str)
return (*str)->str;
}
static char **
_ptrarray_to_strv (GPtrArray *parray)
{
if (parray->len > 0)
g_ptr_array_add (parray, NULL);
return (char **) g_ptr_array_free (parray, parray->len == 0);
}
static void
_collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no other side-effects */
NMGlobalDnsConfig *global_config,
const GPtrArray *configs,
const char *hostname,
char ***out_searches,
char ***out_options,
char ***out_nameservers,
char ***out_nis_servers,
const char **out_nis_domain,
NMDnsIPConfigData ***out_plugin_confs)
{
NMDnsIPConfigData **plugin_confs = NULL;
guint i, num, len;
NMResolvConfData rc = {
.nameservers = g_ptr_array_new (),
.searches = g_ptr_array_new (),
.options = g_ptr_array_new (),
.nis_domain = NULL,
.nis_servers = g_ptr_array_new (),
};
if (global_config)
merge_global_dns_config (&rc, global_config);
else {
nm_auto_free_gstring GString *tmp_gstring = NULL;
int prio, prev_prio = 0;
NMDnsIPConfigData *current;
gboolean skip = FALSE, v4;
plugin_confs = g_new (NMDnsIPConfigData *, configs->len + 1);
for (i = 0; i < configs->len; i++) {
current = configs->pdata[i];
v4 = NM_IS_IP4_CONFIG (current->config);
prio = v4 ?
nm_ip4_config_get_dns_priority ((NMIP4Config *) current->config) :
nm_ip6_config_get_dns_priority ((NMIP6Config *) current->config);
if (prev_prio < 0 && prio != prev_prio) {
skip = TRUE;
plugin_confs[i] = NULL;
}
prev_prio = prio;
if ( ( v4 && nm_ip4_config_get_num_nameservers ((NMIP4Config *) current->config))
|| (!v4 && nm_ip6_config_get_num_nameservers ((NMIP6Config *) current->config))) {
_LOGT ("config: %8d %-7s v%c %-16s %s: %s",
prio,
_config_type_to_string (current->type),
v4 ? '4' : '6',
current->iface,
skip ? "<SKIP>" : "",
get_nameserver_list (current->config, &tmp_gstring));
}
if (!skip) {
merge_one_ip_config_data (&rc, current);
plugin_confs[i] = current;
}
}
plugin_confs[i] = NULL;
}
/* If the hostname is a FQDN ("dcbw.example.com"), then add the domain part of it
* ("example.com") to the searches list, to ensure that we can still resolve its
* non-FQ form ("dcbw") too. (Also, if there are no other search domains specified,
* this makes a good default.) However, if the hostname is the top level of a domain
* (eg, "example.com"), then use the hostname itself as the search (since the user is
* unlikely to want "com" as a search domain).
*/
if (hostname) {
const char *hostdomain = strchr (hostname, '.');
if ( hostdomain
&& !nm_utils_ipaddr_valid (AF_UNSPEC, hostname)) {
hostdomain++;
if (DOMAIN_IS_VALID (hostdomain))
add_string_item (rc.searches, hostdomain);
else if (DOMAIN_IS_VALID (hostname))
add_string_item (rc.searches, hostname);
}
}
/* Per 'man resolv.conf', the search list is limited to 6 domains
* totalling 256 characters.
*/
num = MIN (rc.searches->len, 6u);
for (i = 0, len = 0; i < num; i++) {
len += strlen (rc.searches->pdata[i]) + 1; /* +1 for spaces */
if (len > 256)
break;
}
g_ptr_array_set_size (rc.searches, i);
*out_plugin_confs = plugin_confs;
*out_searches = _ptrarray_to_strv (rc.searches);
*out_options = _ptrarray_to_strv (rc.options);
*out_nameservers = _ptrarray_to_strv (rc.nameservers);
*out_nis_servers = _ptrarray_to_strv (rc.nis_servers);
*out_nis_domain = rc.nis_domain;
}
static gboolean
update_dns (NMDnsManager *self,
gboolean no_caching,
GError **error)
{
NMDnsManagerPrivate *priv;
NMResolvConfData rc;
const char *nis_domain = NULL;
char **searches = NULL;
char **options = NULL;
char **nameservers = NULL;
char **nis_servers = NULL;
int num, i, len;
gs_strfreev char **searches = NULL;
gs_strfreev char **options = NULL;
gs_strfreev char **nameservers = NULL;
gs_strfreev char **nis_servers = NULL;
gboolean caching = FALSE, update = TRUE;
gboolean resolv_conf_updated = FALSE;
SpawnResult result = SR_ERROR;
NMConfigData *data;
NMGlobalDnsConfig *global_config;
gs_free NMDnsIPConfigData **plugin_confs = NULL;
nm_auto_free_gstring GString *tmp_gstring = NULL;
g_return_val_if_fail (!error || !*error, FALSE);
priv = NM_DNS_MANAGER_GET_PRIVATE (self);
nm_clear_g_source (&priv->plugin_ratelimit.timer);
if (NM_IN_SET (priv->rc_manager, NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED,
@ -1014,107 +1136,9 @@ update_dns (NMDnsManager *self,
/* Update hash with config we're applying */
compute_hash (self, global_config, priv->hash);
rc.nameservers = g_ptr_array_new ();
rc.searches = g_ptr_array_new ();
rc.options = g_ptr_array_new ();
rc.nis_domain = NULL;
rc.nis_servers = g_ptr_array_new ();
if (global_config)
merge_global_dns_config (&rc, global_config);
else {
int prio, prev_prio = 0;
NMDnsIPConfigData *current;
gboolean skip = FALSE, v4;
plugin_confs = g_new (NMDnsIPConfigData *, priv->configs->len + 1);
for (i = 0; i < priv->configs->len; i++) {
current = priv->configs->pdata[i];
v4 = NM_IS_IP4_CONFIG (current->config);
prio = v4 ?
nm_ip4_config_get_dns_priority ((NMIP4Config *) current->config) :
nm_ip6_config_get_dns_priority ((NMIP6Config *) current->config);
if (prev_prio < 0 && prio != prev_prio) {
skip = TRUE;
plugin_confs[i] = NULL;
}
prev_prio = prio;
_LOGT ("config: %8d %-7s v%c %-16s %s: %s",
prio,
_config_type_to_string (current->type),
v4 ? '4' : '6',
current->iface,
skip ? "<SKIP>" : "",
get_nameserver_list (current->config, &tmp_gstring));
if (!skip) {
merge_one_ip_config_data (self, &rc, current);
plugin_confs[i] = current;
}
}
plugin_confs[i] = NULL;
}
/* If the hostname is a FQDN ("dcbw.example.com"), then add the domain part of it
* ("example.com") to the searches list, to ensure that we can still resolve its
* non-FQ form ("dcbw") too. (Also, if there are no other search domains specified,
* this makes a good default.) However, if the hostname is the top level of a domain
* (eg, "example.com"), then use the hostname itself as the search (since the user is
* unlikely to want "com" as a search domain).
*/
if (priv->hostname) {
const char *hostdomain = strchr (priv->hostname, '.');
if ( hostdomain
&& !nm_utils_ipaddr_valid (AF_UNSPEC, priv->hostname)) {
hostdomain++;
if (DOMAIN_IS_VALID (hostdomain))
add_string_item (rc.searches, hostdomain);
else if (DOMAIN_IS_VALID (priv->hostname))
add_string_item (rc.searches, priv->hostname);
}
}
/* Per 'man resolv.conf', the search list is limited to 6 domains
* totalling 256 characters.
*/
num = MIN (rc.searches->len, 6);
for (i = 0, len = 0; i < num; i++) {
len += strlen (rc.searches->pdata[i]) + 1; /* +1 for spaces */
if (len > 256)
break;
}
g_ptr_array_set_size (rc.searches, i);
if (rc.searches->len) {
g_ptr_array_add (rc.searches, NULL);
searches = (char **) g_ptr_array_free (rc.searches, FALSE);
} else
g_ptr_array_free (rc.searches, TRUE);
if (rc.options->len) {
g_ptr_array_add (rc.options, NULL);
options = (char **) g_ptr_array_free (rc.options, FALSE);
} else
g_ptr_array_free (rc.options, TRUE);
if (rc.nameservers->len) {
g_ptr_array_add (rc.nameservers, NULL);
nameservers = (char **) g_ptr_array_free (rc.nameservers, FALSE);
} else
g_ptr_array_free (rc.nameservers, TRUE);
if (rc.nis_servers->len) {
g_ptr_array_add (rc.nis_servers, NULL);
nis_servers = (char **) g_ptr_array_free (rc.nis_servers, FALSE);
} else
g_ptr_array_free (rc.nis_servers, TRUE);
nis_domain = rc.nis_domain;
_collect_resolv_conf_data (self, global_config, priv->configs, priv->hostname,
&searches, &options, &nameservers, &nis_servers, &nis_domain,
&plugin_confs);
/* Let any plugins do their thing first */
if (priv->plugin) {
@ -1152,8 +1176,7 @@ update_dns (NMDnsManager *self,
* but only uses the local caching nameserver.
*/
if (caching) {
if (nameservers)
g_strfreev (nameservers);
g_strfreev (nameservers);
nameservers = g_new0 (char*, 2);
nameservers[0] = g_strdup ("127.0.0.1");
}
@ -1193,14 +1216,8 @@ update_dns (NMDnsManager *self,
if (update && result == SR_SUCCESS)
g_signal_emit (self, signals[CONFIG_CHANGED], 0);
if (searches)
g_strfreev (searches);
if (options)
g_strfreev (options);
if (nameservers)
g_strfreev (nameservers);
if (nis_servers)
g_strfreev (nis_servers);
g_clear_pointer (&priv->config_variant, g_variant_unref);
_notify (self, PROP_CONFIGURATION);
return !update || result == SR_SUCCESS;
}
@ -1626,7 +1643,7 @@ init_resolv_conf_mode (NMDnsManager *self, gboolean force_reload_plugin)
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
NMDnsManagerResolvConfManager rc_manager;
const char *mode;
gboolean plugin_changed = FALSE;
gboolean param_changed = FALSE, plugin_changed = FALSE;
mode = nm_config_data_get_dns_mode (nm_config_get_data (priv->config));
@ -1701,13 +1718,29 @@ again:
g_signal_connect (priv->plugin, NM_DNS_PLUGIN_CHILD_QUIT, G_CALLBACK (plugin_child_quit), self);
}
if ( plugin_changed
|| priv->rc_manager != rc_manager) {
g_object_freeze_notify (G_OBJECT (self));
if (!nm_streq0 (priv->mode, mode)) {
g_free (priv->mode);
priv->mode = g_strdup (mode);
param_changed = TRUE;
_notify (self, PROP_MODE);
}
if (priv->rc_manager != rc_manager) {
priv->rc_manager = rc_manager;
param_changed = TRUE;
_notify (self, PROP_RC_MANAGER);
}
if (param_changed || plugin_changed) {
_LOGI ("init: dns=%s, rc-manager=%s%s%s%s",
mode, _rc_manager_to_string (rc_manager),
NM_PRINT_FMT_QUOTED (priv->plugin, ", plugin=", nm_dns_plugin_get_name (priv->plugin), "", ""));
NM_PRINT_FMT_QUOTED (priv->plugin, ", plugin=",
nm_dns_plugin_get_name (priv->plugin), "", ""));
}
g_object_thaw_notify (G_OBJECT (self));
}
static void
@ -1746,6 +1779,221 @@ config_changed_cb (NMConfig *config,
}
}
static GVariant *
_get_global_config_variant (NMGlobalDnsConfig *global)
{
NMGlobalDnsDomain *domain;
GVariantBuilder builder;
guint i, num;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
num = nm_global_dns_config_get_num_domains (global);
for (i = 0; i < num; i++) {
GVariantBuilder conf_builder;
GVariantBuilder item_builder;
const char *domain_name;
const char * const *servers;
g_variant_builder_init (&conf_builder, G_VARIANT_TYPE ("a{sv}"));
domain = nm_global_dns_config_get_domain (global, i);
domain_name = nm_global_dns_domain_get_name (domain);
if (domain_name && !nm_streq0 (domain_name, "*")) {
g_variant_builder_init (&item_builder, G_VARIANT_TYPE ("as"));
g_variant_builder_add (&item_builder,
"s",
domain_name);
g_variant_builder_add (&conf_builder,
"{sv}",
"domains",
g_variant_builder_end (&item_builder));
}
g_variant_builder_init (&item_builder, G_VARIANT_TYPE ("as"));
for (servers = nm_global_dns_domain_get_servers (domain); *servers; servers++) {
g_variant_builder_add (&item_builder,
"s",
*servers);
}
g_variant_builder_add (&conf_builder,
"{sv}",
"nameservers",
g_variant_builder_end (&item_builder));
g_variant_builder_add (&conf_builder,
"{sv}",
"priority",
g_variant_new_int32 (NM_DNS_PRIORITY_DEFAULT_NORMAL));
g_variant_builder_add (&builder, "a{sv}", &conf_builder);
}
return g_variant_ref_sink (g_variant_builder_end (&builder));
}
static GVariant *
_get_config_variant (NMDnsManager *self)
{
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
NMGlobalDnsConfig *global_config;
GVariantBuilder builder;
NMConfigData *data;
guint i, j;
if (priv->config_variant)
return priv->config_variant;
data = nm_config_get_data (priv->config);
global_config = nm_config_data_get_global_dns_config (data);
if (global_config) {
priv->config_variant = _get_global_config_variant (global_config);
_LOGT ("current configuration: %s", g_variant_print (priv->config_variant, TRUE));
return priv->config_variant;
}
g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
for (i = 0; i < priv->configs->len; i++) {
NMDnsIPConfigData *current = priv->configs->pdata[i];
GVariantBuilder entry_builder;
GVariantBuilder strv_builder;
gboolean v4 = NM_IS_IP4_CONFIG (current->config);
gint priority;
g_variant_builder_init (&entry_builder, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as"));
if (v4) {
NMIP4Config *config = NM_IP4_CONFIG (current->config);
guint num = nm_ip4_config_get_num_nameservers (config);
guint32 ns;
if (!num)
continue;
/* Add nameservers */
for (j = 0; j < num; j++) {
ns = nm_ip4_config_get_nameserver (config, j);
g_variant_builder_add (&strv_builder,
"s",
nm_utils_inet4_ntop (ns, NULL));
}
g_variant_builder_add (&entry_builder,
"{sv}",
"nameservers",
g_variant_builder_end (&strv_builder));
/* Add domains */
g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as"));
num = nm_ip4_config_get_num_domains (config);
for (j = 0; j < num; j++) {
g_variant_builder_add (&strv_builder,
"s",
nm_ip4_config_get_domain (config, j));
}
if (num) {
g_variant_builder_add (&entry_builder,
"{sv}",
"domains",
g_variant_builder_end (&strv_builder));
}
priority = nm_ip4_config_get_dns_priority (config);
} else {
NMIP6Config *config = NM_IP6_CONFIG (current->config);
guint num = nm_ip6_config_get_num_nameservers (config);
const struct in6_addr *ns;
if (!num)
continue;
/* Add nameservers */
for (j = 0; j < num; j++) {
ns = nm_ip6_config_get_nameserver (config, j);
g_variant_builder_add (&strv_builder,
"s",
nm_utils_inet6_ntop (ns, NULL));
}
g_variant_builder_add (&entry_builder,
"{sv}",
"nameservers",
g_variant_builder_end (&strv_builder));
/* Add domains */
g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as"));
num = nm_ip6_config_get_num_domains (config);
for (j = 0; j < num; j++) {
g_variant_builder_add (&strv_builder,
"s",
nm_ip6_config_get_domain (config, j));
}
if (num) {
g_variant_builder_add (&entry_builder,
"{sv}",
"domains",
g_variant_builder_end (&strv_builder));
}
priority = nm_ip6_config_get_dns_priority (config);
}
/* Add device */
if (current->iface) {
g_variant_builder_add (&entry_builder,
"{sv}",
"interface",
g_variant_new_string (current->iface));
}
/* Add priority */
g_variant_builder_add (&entry_builder,
"{sv}",
"priority",
g_variant_new_int32 (priority));
/* Add VPN */
g_variant_builder_add (&entry_builder,
"{sv}",
"vpn",
g_variant_new_boolean (current->type == NM_DNS_IP_CONFIG_TYPE_VPN));
g_variant_builder_add (&builder, "a{sv}", &entry_builder);
}
priv->config_variant = g_variant_ref_sink (g_variant_builder_end (&builder));
_LOGT ("current configuration: %s", g_variant_print (priv->config_variant, TRUE));
return priv->config_variant;
}
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
NMDnsManager *self = NM_DNS_MANAGER (object);
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
switch (prop_id) {
case PROP_MODE:
g_value_set_string (value, priv->mode);
break;
case PROP_RC_MANAGER:
g_value_set_string (value, _rc_manager_to_string (priv->rc_manager));
break;
case PROP_CONFIGURATION:
g_value_set_variant (value, _get_config_variant (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
nm_dns_manager_init (NMDnsManager *self)
{
@ -1816,6 +2064,7 @@ finalize (GObject *object)
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
g_free (priv->hostname);
g_free (priv->mode);
G_OBJECT_CLASS (nm_dns_manager_parent_class)->finalize (object);
}
@ -1824,12 +2073,36 @@ static void
nm_dns_manager_class_init (NMDnsManagerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (klass);
/* virtual methods */
object_class->dispose = dispose;
object_class->finalize = finalize;
object_class->get_property = get_property;
exported_object_class->export_path = NM_DBUS_PATH "/DnsManager";
exported_object_class->export_on_construction = TRUE;
obj_properties[PROP_MODE] =
g_param_spec_string (NM_DNS_MANAGER_MODE, "", "",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_RC_MANAGER] =
g_param_spec_string (NM_DNS_MANAGER_RC_MANAGER, "", "",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_CONFIGURATION] =
g_param_spec_variant (NM_DNS_MANAGER_CONFIGURATION, "", "",
G_VARIANT_TYPE ("aa{sv}"),
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
/* signals */
signals[CONFIG_CHANGED] =
g_signal_new (NM_DNS_MANAGER_CONFIG_CHANGED,
G_OBJECT_CLASS_TYPE (object_class),
@ -1837,5 +2110,9 @@ nm_dns_manager_class_init (NMDnsManagerClass *klass)
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass),
NMDBUS_TYPE_DNS_MANAGER_SKELETON,
NULL);
}

View file

@ -51,6 +51,12 @@ typedef struct {
#define NM_IS_DNS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NM_TYPE_DNS_MANAGER))
#define NM_DNS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NM_TYPE_DNS_MANAGER, NMDnsManagerClass))
/* properties */
#define NM_DNS_MANAGER_MODE "mode"
#define NM_DNS_MANAGER_RC_MANAGER "rc-manager"
#define NM_DNS_MANAGER_CONFIGURATION "configuration"
/* internal signals */
#define NM_DNS_MANAGER_CONFIG_CHANGED "config-changed"
typedef struct _NMDnsManager NMDnsManager;

View file

@ -947,8 +947,7 @@ vtype_found:
g_hash_table_insert (ifdata->pending_notifies,
(gpointer) dbus_property_name,
value_variant);
} else
nm_assert_not_reached ();
}
if (!priv->notify_idle_id)
priv->notify_idle_id = g_idle_add (idle_emit_properties_changed, self);

View file

@ -1264,7 +1264,41 @@ class ObjectManager(dbus.service.Object):
pass
###################################################################
IFACE_DNS_MANAGER = 'org.freedesktop.NetworkManager.DnsManager'
class DnsManager(ExportedObj):
def __init__(self, bus, object_path):
self.props = {}
self.props['Mode'] = "dnsmasq"
self.props['RcManager'] = "symlink"
self.props['Configuration'] = dbus.Array([
dbus.Dictionary(
{ 'nameservers' : dbus.Array(['1.2.3.4', '5.6.7.8'], 's'),
'priority' : dbus.Int32(100) },
'sv') ],
'a{sv}')
self.add_dbus_interface(IFACE_DNS_MANAGER, self.__get_props, None)
ExportedObj.__init__(self, bus, object_path)
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='s', out_signature='a{sv}')
def GetAll(self, iface):
if iface != IFACE_DNS_MANAGER:
raise UnknownInterfaceException()
return self.props
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='ss', out_signature='v')
def Get(self, iface, name):
if iface != IFACE_DNS_MANAGER:
raise UnknownInterfaceException()
if not name in self.props.keys():
raise UnknownPropertyException()
return self.props[name]
def __get_props(self):
return self.props
###################################################################
def stdin_cb(io, condition):
mainloop.quit()
@ -1276,13 +1310,14 @@ def main():
random.seed()
global manager, settings, agent_manager, object_manager, bus
global manager, settings, agent_manager, dns_manager, object_manager, bus
bus = dbus.SessionBus()
object_manager = ObjectManager(bus, "/org/freedesktop")
manager = NetworkManager(bus, "/org/freedesktop/NetworkManager")
settings = Settings(bus, "/org/freedesktop/NetworkManager/Settings")
agent_manager = AgentManager(bus, "/org/freedesktop/NetworkManager/AgentManager")
dns_manager = DnsManager(bus, "/org/freedesktop/NetworkManager/DnsManager")
if not bus.request_name("org.freedesktop.NetworkManager"):
sys.exit(1)