2004-12-21 Colin Walters <walters@redhat.com>

* src/NetworkManager.c (nm_data_new): Initialize named.
	Also, set up a signal handler for SIGINT/SIGTERM, and exit
	the mainloop when these signals are received.
	(nm_data_free): Unref named.
	(sigterm_handler, sigterm_pipe_handler): New functions for
	exiting mainloop.

	* src/NetworkManagerMain.h (NMData): Add signal handling and
	nameserver bits.

	* src/NetworkManager.c (nm_device_unref): Quit device mainloop on
	unref.

	* src/NetworkManagerDHCP.c (set_nameservers): New function;
	set nameservers from DHCP response data.
	(set_domain_search): Set domain search from DHCP response.
	(nm_device_dhcp_configure): Invoke them.

	* src/NetworkManagerSystem.c
	(nm_system_device_update_resolv_conf): Delete.  Deleting
	code is totally sweet.

	* src/Makefile.am (NetworkManager_LDADD): Add libnamed.

	* named/nm-named-manager.h, named/nm-named-manager.c: New files;
	implements an object which controls a nameserver.  Currently
	uses bind 9.

	* configure.in: Check for named.

	* Makefile.am (SUBDIRS): Add named dir.

	* named/named.conf: New template config file.


git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@352 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
Colin Walters
2004-12-21 06:49:21 +00:00
committed by Colin Walters
parent 53c27dec5f
commit 33bd873ec4
14 changed files with 1006 additions and 51 deletions

View File

@@ -1,3 +1,39 @@
2004-12-21 Colin Walters <walters@redhat.com>
* src/NetworkManager.c (nm_data_new): Initialize named.
Also, set up a signal handler for SIGINT/SIGTERM, and exit
the mainloop when these signals are received.
(nm_data_free): Unref named.
(sigterm_handler, sigterm_pipe_handler): New functions for
exiting mainloop.
* src/NetworkManagerMain.h (NMData): Add signal handling and
nameserver bits.
* src/NetworkManager.c (nm_device_unref): Quit device mainloop on
unref.
* src/NetworkManagerDHCP.c (set_nameservers): New function;
set nameservers from DHCP response data.
(set_domain_search): Set domain search from DHCP response.
(nm_device_dhcp_configure): Invoke them.
* src/NetworkManagerSystem.c
(nm_system_device_update_resolv_conf): Delete. Deleting
code is totally sweet.
* src/Makefile.am (NetworkManager_LDADD): Add libnamed.
* named/nm-named-manager.h, named/nm-named-manager.c: New files;
implements an object which controls a nameserver. Currently
uses bind 9.
* configure.in: Check for named.
* Makefile.am (SUBDIRS): Add named dir.
* named/named.conf: New template config file.
2004-12-20 Colin Walters <walters@redhat.com>
* src/NetworkManagerPolicy.c (nm_policy_get_best_device): Fix usage of '=='

View File

@@ -1,4 +1,4 @@
SUBDIRS = dhcpcd src dispatcher-daemon $(notification_icon_dir) info-daemon initscript test po
SUBDIRS = dhcpcd named src dispatcher-daemon $(notification_icon_dir) info-daemon initscript test po
EXTRA_DIST = CONTRIBUTING NetworkManager.pc.in NetworkManager.h

View File

@@ -149,6 +149,15 @@ fi
AC_SUBST(DBUS_SYS_DIR)
AC_DEFINE_UNQUOTED(DBUS_SYSTEMD_DIR, "$DBUS_SYS_DIR", [Where system.d dir for DBUS is])
AC_ARG_WITH(named, AC_HELP_STRING([--with-named=<path>], [path to the named binary]))
if test "x${with_named}" = x; then
AC_PATH_PROG(with_named, [named], no)
if test "x${with_named}" = x; then
AC_MSG_ERROR([must specify path to named binary with --with-named])
fi
fi
AC_DEFINE_UNQUOTED(NM_NAMED_BINARY_PATH, "$with_named", [Define to path of named binary])
AC_ARG_ENABLE(notification-icon, [ --enable-notification-icon builds the wireless applet as a notification icon], enable_notification_icon=$enableval, enable_notification_icon=yes)
AM_CONDITIONAL(BUILD_NOTIFICATION_ICON, test x$enable_notification_icon = xyes)
@@ -229,6 +238,7 @@ dispatcher-daemon/Makefile
info-daemon/Makefile
panel-applet/Makefile
panel-applet/icons/Makefile
named/Makefile
dhcpcd/Makefile
test/Makefile
initscript/Makefile

2
named/.cvsignore Normal file
View File

@@ -0,0 +1,2 @@
Makefile
Makefile.in

13
named/Makefile.am Normal file
View File

@@ -0,0 +1,13 @@
namedconf_DATA = named.conf
namedconfdir = $(pkgdatadir)
EXTRA_DIST = $(namedconf_DATA)
noinst_LTLIBRARIES = libnamed.la
libnamed_la_SOURCES = nm-named-manager.h nm-named-manager.c
libnamed_la_CPPFLAGS = $(NM_CFLAGS) -DNM_PKGDATADIR=\"$(pkgdatadir)\" -DNM_LOCALSTATEDIR=\"$(localstatedir)\"
libnamed_la_LIBADD = $(NM_LIBS)

15
named/named.conf Normal file
View File

@@ -0,0 +1,15 @@
// Named configuration, generated by NetworkManager
options {
directory "/";
query-source address * port 53;
forward only;
forwarders { @@FORWARDERS@@ };
listen-on { 127.0.0.1; };
pid-file none;
};
// Disable rndc
controls { };
@@DOMAIN_ZONES@@

698
named/nm-named-manager.c Normal file
View File

@@ -0,0 +1,698 @@
/*
* Copyright (C) 2004 Red Hat, Inc.
*
* Written by Colin Walters <walters@redhat.com>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include "config.h"
#include "nm-named-manager.h"
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <ftw.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <errno.h>
#include <resolv.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <glib.h>
#ifndef RESOLV_CONF
#define RESOLV_CONF "/etc/resolv.conf"
#endif
G_DEFINE_TYPE(NMNamedManager, nm_named_manager, G_TYPE_OBJECT)
static void nm_named_manager_finalize (GObject *object);
static void nm_named_manager_dispose (GObject *object);
static GObject *nm_named_manager_constructor (GType type, guint n_construct_properties,
GObjectConstructParam *construct_properties);
static gboolean rewrite_resolv_conf (NMNamedManager *mgr, GError **error);
static int safer_kill (const char *path, pid_t pid, int signum);
struct NMNamedManagerPrivate
{
char *named_realpath_binary;
GPid named_pid;
guint spawn_count;
guint child_watch_id;
guint queued_reload_id;
guint id_serial;
GHashTable *domain_searches; /* guint -> char * */
GHashTable *global_ipv4_nameservers; /* guint -> char * */
GHashTable *domain_ipv4_nameservers; /* char * -> GHashTable(guint -> char *) */
char *named_conf;
gboolean disposed;
};
static void
nm_named_manager_class_init (NMNamedManagerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = nm_named_manager_dispose;
object_class->finalize = nm_named_manager_finalize;
object_class->constructor = nm_named_manager_constructor;
}
static void
nm_named_manager_init (NMNamedManager *mgr)
{
mgr->priv = g_new0 (NMNamedManagerPrivate, 1);
mgr->priv->domain_searches = g_hash_table_new_full (NULL, NULL,
NULL, (GDestroyNotify) g_free);
mgr->priv->global_ipv4_nameservers = g_hash_table_new_full (NULL, NULL,
NULL, (GDestroyNotify) g_free);
mgr->priv->domain_ipv4_nameservers = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free,
(GDestroyNotify) g_hash_table_destroy);
}
static void
nm_named_manager_dispose (GObject *object)
{
NMNamedManager *mgr = NM_NAMED_MANAGER (object);
if (mgr->priv->disposed)
return;
mgr->priv->disposed = TRUE;
if (mgr->priv->named_conf)
unlink (mgr->priv->named_conf);
if (mgr->priv->named_realpath_binary)
safer_kill (mgr->priv->named_realpath_binary, mgr->priv->named_pid, SIGTERM);
if (mgr->priv->child_watch_id)
g_source_remove (mgr->priv->child_watch_id);
}
static void
nm_named_manager_finalize (GObject *object)
{
NMNamedManager *mgr = NM_NAMED_MANAGER (object);
g_return_if_fail (mgr->priv != NULL);
g_hash_table_destroy (mgr->priv->domain_searches);
g_hash_table_destroy (mgr->priv->global_ipv4_nameservers);
g_hash_table_destroy (mgr->priv->domain_ipv4_nameservers);
g_free (mgr->priv->named_conf);
g_free (mgr->priv);
G_OBJECT_CLASS (nm_named_manager_parent_class)->finalize (object);
}
static GObject *
nm_named_manager_constructor (GType type, guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
NMNamedManager *mgr;
NMNamedManagerClass *klass;
GObjectClass *parent_class;
klass = NM_NAMED_MANAGER_CLASS (g_type_class_peek (NM_TYPE_NAMED_MANAGER));
parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
mgr = NM_NAMED_MANAGER (parent_class->constructor (type, n_construct_properties,
construct_properties));
return G_OBJECT (mgr);
}
NMNamedManager *
nm_named_manager_new (void)
{
return NM_NAMED_MANAGER (g_object_new (NM_TYPE_NAMED_MANAGER, NULL));
}
GQuark
nm_named_manager_error_quark (void)
{
static GQuark quark = 0;
if (!quark)
quark = g_quark_from_static_string ("nm_named_manager_error");
return quark;
}
static void
join_forwarders (gpointer key, gpointer value, gpointer data)
{
guint id = GPOINTER_TO_UINT (key);
const char *server = value;
GString *str = data;
g_string_append_c (str, ' ');
g_string_append (str, server);
g_string_append_c (str, ';');
}
static char *
compute_global_forwarders (NMNamedManager *mgr)
{
GString *str = g_string_new ("");
g_hash_table_foreach (mgr->priv->global_ipv4_nameservers,
join_forwarders,
str);
return g_string_free (str, FALSE);
}
static void
compute_zone (gpointer key, gpointer value, gpointer data)
{
const char *domain = key;
GHashTable *servers = value;
GString *str = data;
g_string_append_c (str, '\n');
g_string_append (str, " zone \"");
g_string_append (str, domain);
g_string_append (str, "\"\n");
g_string_append (str, " forwarders {");
g_hash_table_foreach (servers, join_forwarders, str);
g_string_append (str, "}\n}\n");
}
static char *
compute_domain_zones (NMNamedManager *mgr)
{
GString *str = g_string_new ("");
g_hash_table_foreach (mgr->priv->domain_ipv4_nameservers,
compute_zone,
str);
return g_string_free (str, FALSE);
}
gboolean
generate_named_conf (NMNamedManager *mgr, GError **error)
{
char *filename = NULL;
int out_fd;
char *config_contents_str;
char **config_contents;
char **line;
const char *config_name;
config_name = NM_PKGDATADIR "/named.conf";
if (!mgr->priv->named_conf)
{
out_fd = g_file_open_tmp ("NetworkManager-named.conf-XXXXXX",
&mgr->priv->named_conf,
error);
if (out_fd < 0)
return FALSE;
close (out_fd);
}
if (!g_file_get_contents (config_name,
&config_contents_str,
NULL,
error))
{
return FALSE;
}
out_fd = g_file_open_tmp ("NetworkManager-named.conf-XXXXXX",
&filename,
error);
if (out_fd < 0)
{
g_free (config_contents_str);
return FALSE;
}
config_contents = g_strsplit (config_contents_str,
"\n",
0);
g_free (config_contents_str);
for (line = config_contents; *line; line++)
{
const char *variable_pos;
const char *variable_end_pos;
if ((variable_pos = strstr (*line, "@@"))
&& (variable_end_pos = strstr (variable_pos + 2, "@@")))
{
char *variable;
char *replacement = NULL;
variable = g_strndup (variable_pos + 2,
variable_end_pos - (variable_pos + 2));
if (strcmp ("LOCALSTATEDIR", variable) == 0)
replacement = g_strdup (NM_LOCALSTATEDIR);
else if (strcmp ("FORWARDERS", variable) == 0)
replacement = compute_global_forwarders (mgr);
else if (strcmp ("DOMAIN_ZONES", variable) == 0)
replacement = compute_domain_zones (mgr);
else
{
g_warning ("Unknown variable %s in %s",
variable, config_name);
if (write (out_fd, *line, strlen (*line)) < 0)
goto replacement_lose;
}
if (write (out_fd, *line, variable_pos - *line) < 0)
goto replacement_lose;
if (write (out_fd, replacement, strlen (replacement)) < 0)
goto replacement_lose;
if (write (out_fd, variable_end_pos + 2, strlen (variable_end_pos + 2)) < 0)
goto replacement_lose;
if (write (out_fd, "\n", 1) < 0)
goto replacement_lose;
g_free (variable);
g_free (replacement);
continue;
replacement_lose:
g_free (variable);
g_free (replacement);
goto write_lose;
} else {
if (write (out_fd, *line, strlen (*line)) < 0)
goto write_lose;
}
if (write (out_fd, "\n", 1) < 0)
goto write_lose;
}
close (out_fd);
if (rename (filename, mgr->priv->named_conf) < 0) {
g_set_error (error,
NM_NAMED_MANAGER_ERROR,
NM_NAMED_MANAGER_ERROR_SYSTEM,
"Couldn't rename %s to %s: %s",
filename, mgr->priv->named_conf,
g_strerror (errno));
return FALSE;
}
g_strfreev (config_contents);
return TRUE;
write_lose:
close (out_fd);
g_strfreev (config_contents);
unlink (filename);
g_free (filename);
return FALSE;
}
static void
watch_cb (GPid pid, gint status, gpointer data)
{
NMNamedManager *mgr = NM_NAMED_MANAGER (data);
if (WIFEXITED (status))
g_warning ("named exited with error code %d", WEXITSTATUS (status));
else if (WIFSTOPPED (status))
g_warning ("named stopped unexpectedly with signal %d", WSTOPSIG (status));
else if (WIFSIGNALED (status))
g_warning ("named died with signal %d", WTERMSIG (status));
else
g_warning ("named died from an unknown cause");
if (mgr->priv->queued_reload_id > 0)
g_source_remove (mgr->priv->queued_reload_id);
/* FIXME - do something with error; need to handle failure to
* respawn */
nm_named_manager_start (mgr, NULL);
}
gboolean
nm_named_manager_start (NMNamedManager *mgr, GError **error)
{
GPid pid;
const char *named_binary;
GPtrArray *named_argv;
mgr->priv->named_pid = 0;
mgr->priv->spawn_count++;
if (mgr->priv->spawn_count > 5)
{
g_set_error (error,
NM_NAMED_MANAGER_ERROR,
NM_NAMED_MANAGER_ERROR_SYSTEM,
"named crashed more than 5 times, refusing to try again");
return FALSE;
}
if (!generate_named_conf (mgr, error))
return FALSE;
named_argv = g_ptr_array_new ();
named_binary = g_getenv ("NM_NAMED_BINARY_PATH") ?
g_getenv ("NM_NAMED_BINARY_PATH") : NM_NAMED_BINARY_PATH;
g_free (mgr->priv->named_realpath_binary);
mgr->priv->named_realpath_binary = realpath (named_binary, NULL);
if (mgr->priv->named_realpath_binary == NULL)
mgr->priv->named_realpath_binary = g_strdup (named_binary);
g_ptr_array_add (named_argv, (char *) named_binary);
g_ptr_array_add (named_argv, "-f");
g_ptr_array_add (named_argv, "-c");
g_ptr_array_add (named_argv, mgr->priv->named_conf);
g_ptr_array_add (named_argv, NULL);
if (!g_spawn_async (NULL, (char **) named_argv->pdata, NULL,
G_SPAWN_LEAVE_DESCRIPTORS_OPEN |
G_SPAWN_DO_NOT_REAP_CHILD,
NULL, NULL, &pid,
error))
{
g_ptr_array_free (named_argv, TRUE);
return FALSE;
}
g_ptr_array_free (named_argv, TRUE);
mgr->priv->named_pid = pid;
if (mgr->priv->child_watch_id)
g_source_remove (mgr->priv->child_watch_id);
mgr->priv->child_watch_id = g_child_watch_add (pid, watch_cb, mgr);
if (!rewrite_resolv_conf (mgr, error))
{
safer_kill (mgr->priv->named_realpath_binary, mgr->priv->named_pid, SIGTERM);
return FALSE;
}
return TRUE;
}
static gboolean
reload_named (NMNamedManager *mgr, GError **error)
{
/* FIXME - handle error */
if (!generate_named_conf (mgr, error))
return FALSE;
if (safer_kill (mgr->priv->named_realpath_binary, mgr->priv->named_pid, SIGHUP) < 0) {
g_set_error (error,
NM_NAMED_MANAGER_ERROR,
NM_NAMED_MANAGER_ERROR_SYSTEM,
"Couldn't signal nameserver: %s",
g_strerror (errno));
return FALSE;
}
return TRUE;
}
static gboolean
validate_host (const char *server, GError **error)
{
for (; *server; server++)
{
if (!(g_ascii_isalpha (*server)
|| g_ascii_isdigit (*server)
|| *server == '-'
|| *server == '.'))
{
g_set_error (error,
NM_NAMED_MANAGER_ERROR,
NM_NAMED_MANAGER_ERROR_INVALID_HOST,
"Invalid characters in host");
return FALSE;
}
}
return TRUE;
}
static void
compute_search (gpointer key, gpointer value, gpointer data)
{
const char *server = value;
GString *str = data;
g_string_append (str, "search ");
g_string_append (str, server);
g_string_append_c (str, '\n');
}
static char *
compute_domain_searches (NMNamedManager *mgr)
{
GString *str = g_string_new ("");
g_hash_table_foreach (mgr->priv->domain_searches,
compute_search,
str);
return g_string_free (str, FALSE);
}
static gboolean
rewrite_resolv_conf (NMNamedManager *mgr, GError **error)
{
const char *tmp_resolv_conf = RESOLV_CONF ".tmp";
char *searches;
FILE *f;
if ((f = fopen (tmp_resolv_conf, "w")) == NULL)
goto lose;
searches = compute_domain_searches (mgr);
if (fprintf (f, "%s%s%s",
"; generated by NetworkManager, do not edit!\n; Use a local caching nameserver controlled by NetworkManager\n", searches, "\nnameserver 127.0.0.1\n") < 0) {
g_free (searches);
goto lose;
}
g_free (searches);
if (fclose (f) < 0)
goto lose;
if (rename (tmp_resolv_conf, RESOLV_CONF) < 0)
goto lose;
return TRUE;
lose:
g_set_error (error,
NM_NAMED_MANAGER_ERROR,
NM_NAMED_MANAGER_ERROR_SYSTEM,
"Could not update " RESOLV_CONF ": %s\n", g_strerror (errno));
return FALSE;
}
guint
nm_named_manager_add_domain_search (NMNamedManager *mgr,
const char *domain,
GError **error)
{
guint id;
if (!validate_host (domain, error))
return 0;
id = ++mgr->priv->id_serial;
g_hash_table_insert (mgr->priv->domain_searches,
GUINT_TO_POINTER (id),
g_strdup (domain));
if (!rewrite_resolv_conf (mgr, error)) {
g_hash_table_remove (mgr->priv->global_ipv4_nameservers,
GUINT_TO_POINTER (id));
return 0;
}
return id;
}
gboolean
nm_named_manager_remove_domain_search (NMNamedManager *mgr,
guint id,
GError **error)
{
if (!g_hash_table_remove (mgr->priv->domain_searches,
GUINT_TO_POINTER (id)))
{
g_set_error (error,
NM_NAMED_MANAGER_ERROR,
NM_NAMED_MANAGER_ERROR_INVALID_ID,
"Invalid domain search id");
return FALSE;
}
if (!rewrite_resolv_conf (mgr, error))
return FALSE;
return TRUE;
}
guint
nm_named_manager_add_nameserver_ipv4 (NMNamedManager *mgr,
const char *server,
GError **error)
{
guint id;
if (!validate_host (server, error))
return 0;
id = ++mgr->priv->id_serial;
g_hash_table_insert (mgr->priv->global_ipv4_nameservers,
GUINT_TO_POINTER (id),
g_strdup (server));
if (!reload_named (mgr, error)) {
g_hash_table_remove (mgr->priv->global_ipv4_nameservers,
GUINT_TO_POINTER (id));
return 0;
}
return id;
}
guint
nm_named_manager_add_domain_nameserver_ipv4 (NMNamedManager *mgr,
const char *domain,
const char *server,
GError **error)
{
GHashTable *servers;
guint id;
if (!validate_host (server, error))
return 0;
id = ++mgr->priv->id_serial;
servers = g_hash_table_lookup (mgr->priv->domain_ipv4_nameservers,
domain);
if (!servers)
{
servers = g_hash_table_new_full (NULL, NULL,
NULL, (GDestroyNotify) g_free);
g_hash_table_insert (mgr->priv->domain_ipv4_nameservers,
g_strdup (domain),
servers);
}
g_hash_table_insert (servers,
GUINT_TO_POINTER (id),
g_strdup (server));
if (!reload_named (mgr, error)) {
g_hash_table_remove (servers, domain);
return 0;
}
return id;
}
gboolean
nm_named_manager_remove_nameserver_ipv4 (NMNamedManager *mgr,
guint id,
GError **error)
{
if (!g_hash_table_remove (mgr->priv->global_ipv4_nameservers,
GUINT_TO_POINTER (id)))
{
g_set_error (error,
NM_NAMED_MANAGER_ERROR,
NM_NAMED_MANAGER_ERROR_INVALID_ID,
"Invalid nameserver id");
return FALSE;
}
if (!reload_named (mgr, error))
return FALSE;
return TRUE;
}
typedef struct {
guint id;
gboolean removed;
} NMNamedManagerRemoveData;
static void
remove_domain_id (gpointer key, gpointer value, gpointer data)
{
const char *domain = key;
GHashTable *servers = value;
NMNamedManagerRemoveData *removedata = data;
if (removedata->removed)
return;
if (g_hash_table_remove (servers, GUINT_TO_POINTER (removedata->id)))
removedata->removed = TRUE;
}
gboolean
nm_named_manager_remove_domain_nameserver_ipv4 (NMNamedManager *mgr,
guint id,
GError **error)
{
NMNamedManagerRemoveData data;
data.id = id;
data.removed = FALSE;
g_hash_table_foreach (mgr->priv->domain_ipv4_nameservers,
remove_domain_id,
&data);
if (!data.removed)
{
g_set_error (error,
NM_NAMED_MANAGER_ERROR,
NM_NAMED_MANAGER_ERROR_INVALID_ID,
"Invalid nameserver id");
return FALSE;
}
if (!reload_named (mgr, error))
return FALSE;
return TRUE;
}
static int
safer_kill (const char *path, pid_t pid, int signum)
{
#ifdef __linux__
{
char buffer[1024];
int len;
char *procpath;
procpath = g_strdup_printf ("/proc/%d/exe", pid);
len = readlink (procpath, buffer, sizeof (buffer)-1);
g_free (procpath);
buffer[len] = '\0';
if (len > 0) {
if (strcmp (path, buffer) != 0) {
g_warning ("pid %u with exe \"%s'\" did not match expected exe \"%s\"",
(unsigned int) pid, buffer, path);
errno = EPERM;
return -1;
}
}
}
#endif
return kill ((pid_t) pid, signum);
}

93
named/nm-named-manager.h Normal file
View File

@@ -0,0 +1,93 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Copyright (C) 2004 Red Hat, Inc.
*
* Written by Colin Walters <walters@redhat.com>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __NM_NAMED_MANAGER_H__
#define __NM_NAMED_MANAGER_H__
#include "config.h"
#include <glib-object.h>
typedef enum
{
NM_NAMED_MANAGER_ERROR_SYSTEM,
NM_NAMED_MANAGER_ERROR_INVALID_NAMESERVER,
NM_NAMED_MANAGER_ERROR_INVALID_HOST,
NM_NAMED_MANAGER_ERROR_INVALID_ID
} NMNamedManagerError;
#define NM_NAMED_MANAGER_ERROR nm_named_manager_error_quark ()
GQuark nm_named_manager_error_quark (void);
G_BEGIN_DECLS
#define NM_TYPE_NAMED_MANAGER (nm_named_manager_get_type ())
#define NM_NAMED_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NM_TYPE_NAMED_MANAGER, NMNamedManager))
#define NM_NAMED_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NM_TYPE_NAMED_MANAGER, NMNamedManagerClass))
#define NM_IS_NAMED_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NM_TYPE_NAMED_MANAGER))
#define NM_IS_NAMED_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NM_TYPE_NAMED_MANAGER))
#define NM_NAMED_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NM_TYPE_NAMED_MANAGER, NMNamedManagerClass))
typedef struct NMNamedManagerPrivate NMNamedManagerPrivate;
typedef struct
{
GObject parent;
NMNamedManagerPrivate *priv;
} NMNamedManager;
typedef struct
{
GObjectClass parent;
} NMNamedManagerClass;
GType nm_named_manager_get_type (void);
NMNamedManager * nm_named_manager_new (void);
gboolean nm_named_manager_start (NMNamedManager *mgr, GError **error);
guint nm_named_manager_add_domain_search (NMNamedManager *mgr,
const char *domain,
GError **error);
guint nm_named_manager_add_nameserver_ipv4 (NMNamedManager *mgr,
const char *server,
GError **error);
guint nm_named_manager_add_domain_nameserver_ipv4 (NMNamedManager *mgr,
const char *domain,
const char *server,
GError **error);
gboolean nm_named_manager_remove_domain_search (NMNamedManager *mgr,
guint id,
GError **error);
gboolean nm_named_manager_remove_nameserver_ipv4 (NMNamedManager *mgr,
guint id,
GError **error);
gboolean nm_named_manager_remove_domain_nameserver_ipv4 (NMNamedManager *mgr,
guint id,
GError **error);
G_END_DECLS
#endif /* __NM_NAMED_MANAGER_H__ */

View File

@@ -1,4 +1,4 @@
INCLUDES = -I${top_srcdir}
INCLUDES = -I${top_srcdir} -I../named
AM_CPPFLAGS = \
$(NM_CFLAGS) \
@@ -42,7 +42,7 @@ if !WITH_GCRYPT
NetworkManager_SOURCES += gnome-keyring-md5.c gnome-keyring-md5.h
endif
NetworkManager_LDADD = $(NM_LIBS) $(IWLIB) libnmbackend.la ../dhcpcd/libdhcpc.a
NetworkManager_LDADD = $(NM_LIBS) $(IWLIB) libnmbackend.la ../dhcpcd/libdhcpc.a ../named/libnamed.la
if WITH_GCRYPT
NetworkManager_LDADD += $(LIBGCRYPT_LIBS)
endif

View File

@@ -27,6 +27,7 @@
#include <getopt.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
@@ -41,6 +42,7 @@
#include "NetworkManagerAP.h"
#include "NetworkManagerAPList.h"
#include "NetworkManagerSystem.h"
#include "nm-named-manager.h"
/*
@@ -48,6 +50,8 @@
*/
static NMData *nm_data = NULL;
static gboolean sigterm_pipe_handler (GIOChannel *src, GIOCondition condition, gpointer data);
static void sigterm_handler (int signum);
static void nm_data_free (NMData *data);
@@ -481,13 +485,41 @@ static LibHalFunctions hal_functions =
*/
static NMData *nm_data_new (gboolean enable_test_devices)
{
struct sigaction action;
sigset_t block_mask;
NMData *data;
GSource *iosource;
GError *error = NULL;
data = g_new0 (NMData, 1);
if (!data)
data->main_context = g_main_context_new ();
data->main_loop = g_main_loop_new (data->main_context, FALSE);
if (pipe(data->sigterm_pipe) < 0)
{
syslog( LOG_ERR, "Could not allocate our NetworkManager data... Not enough memory?");
return (NULL);
syslog (LOG_CRIT, "Couldn't create pipe: %s", g_strerror (errno));
exit (EXIT_FAILURE);
}
data->sigterm_iochannel = g_io_channel_unix_new (data->sigterm_pipe[0]);
iosource = g_io_create_watch (data->sigterm_iochannel, G_IO_IN | G_IO_ERR);
g_source_set_callback (iosource, (GSourceFunc) sigterm_pipe_handler, data, NULL);
g_source_attach (iosource, data->main_context);
g_source_unref (iosource);
action.sa_handler = sigterm_handler;
sigemptyset (&block_mask);
action.sa_mask = block_mask;
action.sa_flags = 0;
sigaction (SIGINT, &action, NULL);
sigaction (SIGTERM, &action, NULL);
data->named = nm_named_manager_new ();
if (!nm_named_manager_start (data->named, &error))
{
syslog (LOG_CRIT, "Couldn't initialize nameserver: %s", error->message);
exit (EXIT_FAILURE);
}
/* Initialize the device list mutex to protect additions/deletions to it. */
@@ -516,9 +548,6 @@ static NMData *nm_data_new (gboolean enable_test_devices)
data->enable_test_devices = enable_test_devices;
data->starting_up = TRUE;
data->main_context = g_main_context_new ();
data->main_loop = g_main_loop_new (data->main_context, FALSE);
return (data);
}
@@ -533,6 +562,7 @@ static void nm_data_free (NMData *data)
{
g_return_if_fail (data != NULL);
g_object_unref (data->named);
nm_device_unref (data->active_device);
g_slist_foreach (data->dev_list, (GFunc) nm_device_unref, NULL);
@@ -567,6 +597,19 @@ void nm_data_mark_state_changed (NMData *data)
g_mutex_unlock (data->state_modified_mutex);
}
static void sigterm_handler (int signum)
{
syslog (LOG_NOTICE, "Caught SIGINT/SIGTERM");
write (nm_data->sigterm_pipe[1], "X", 1);
}
static gboolean sigterm_pipe_handler (GIOChannel *src, GIOCondition condition, gpointer user_data)
{
NMData *data = user_data;
syslog (LOG_NOTICE, "Caught terminiation signal");
g_main_loop_quit (data->main_loop);
return FALSE;
}
/*
* nm_print_usage
@@ -737,6 +780,7 @@ int main( int argc, char *argv[] )
exit (1);
}
syslog (LOG_NOTICE, "running mainloop...");
/* Wheeee!!! */
g_main_loop_run (nm_data->main_loop);
@@ -753,5 +797,5 @@ int main( int argc, char *argv[] )
nm_data_free (nm_data);
return (0);
exit (0);
}

View File

@@ -30,10 +30,80 @@
#include "NetworkManagerDevicePrivate.h"
#include "NetworkManagerDHCP.h"
#include "NetworkManagerSystem.h"
#include "nm-named-manager.h"
#include "../dhcpcd/client.h"
extern gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip);
static void set_nameservers (NMDevice *dev, void *data, int len)
{
int i;
GList *elt;
GError *error = NULL;
/* Reset our nameserver list */
for (elt = dev->app_data->nameserver_ids; elt; elt = elt->next)
{
if (!nm_named_manager_remove_nameserver_ipv4 (dev->app_data->named,
GPOINTER_TO_UINT (elt->data),
&error))
{
syslog (LOG_ERR, G_GNUC_PRETTY_FUNCTION ": Couldn't remove nameserver: %s\n", error->message);
g_clear_error (&error);
}
}
for (i = 0; data && (i < len-3); i += 4)
{
char *nameserver;
guint id;
nameserver = g_strdup_printf ("%u.%u.%u.%u",
((unsigned char *)data)[i],
((unsigned char *)data)[i+1],
((unsigned char *)data)[i+2],
((unsigned char *)data)[i+3]);
syslog (LOG_ERR, G_GNUC_PRETTY_FUNCTION ": Adding nameserver: %s\n", nameserver);
if ((id = nm_named_manager_add_nameserver_ipv4 (dev->app_data->named,
nameserver,
&error)))
dev->app_data->nameserver_ids = g_list_prepend (dev->app_data->nameserver_ids,
GUINT_TO_POINTER (id));
else
{
syslog (LOG_ERR, G_GNUC_PRETTY_FUNCTION ": Couldn't add nameserver: %s\n", error->message);
g_clear_error (&error);
}
g_free (nameserver);
}
}
static void set_domain_search (NMDevice *dev, const char *domain)
{
GError *error = NULL;
guint id;
if (dev->app_data->domain_search_id
&& !nm_named_manager_remove_domain_search (dev->app_data->named,
dev->app_data->domain_search_id,
&error))
{
syslog (LOG_ERR, G_GNUC_PRETTY_FUNCTION ": Couldn't remove domain search: %s\n", error->message);
g_clear_error (&error);
}
syslog (LOG_ERR, G_GNUC_PRETTY_FUNCTION ": Adding domain search: %s\n", domain);
if ((id = nm_named_manager_add_domain_search (dev->app_data->named,
domain,
&error)))
dev->app_data->domain_search_id = id;
else
{
dev->app_data->domain_search_id = 0;
syslog (LOG_ERR, G_GNUC_PRETTY_FUNCTION ": Couldn't add domain search: %s\n", error->message);
g_clear_error (&error);
}
}
/*
* nm_device_dhcp_configure
@@ -72,10 +142,10 @@ static void nm_device_dhcp_configure (NMDevice *dev)
/* Update /etc/resolv.conf */
if (dhcp_interface_dhcp_field_exists (dev->dhcp_iface, dns))
{
nm_system_device_update_resolv_conf (dhcp_interface_get_dhcp_field (dev->dhcp_iface, dns),
dhcp_interface_get_dhcp_field_len (dev->dhcp_iface, dns), dhcp_interface_get_dhcp_field (dev->dhcp_iface, domainName));
}
set_nameservers (dev, dhcp_interface_get_dhcp_field (dev->dhcp_iface, dns), dhcp_interface_get_dhcp_field_len (dev->dhcp_iface, dns));
if (dhcp_interface_dhcp_field_exists (dev->dhcp_iface, domainName))
set_domain_search (dev, dhcp_interface_get_dhcp_field (dev->dhcp_iface, domainName));
}
@@ -106,9 +176,6 @@ gboolean nm_device_do_autoip (NMDevice *dev)
/* Set all traffic to go through the device */
nm_system_flush_loopback_routes ();
nm_system_device_add_default_route_via_device (dev);
/* Kill old resolv.conf */
nm_system_device_update_resolv_conf (NULL, 0, "");
}
return (success);

View File

@@ -318,6 +318,8 @@ void nm_device_unref (NMDevice *dev)
dev->refcount--;
if (dev->refcount <= 0)
{
g_main_loop_quit (dev->loop);
nm_device_ap_list_clear (dev);
dev->options.wireless.ap_list = NULL;

View File

@@ -28,10 +28,19 @@
#include <hal/libhal.h>
#include "NetworkManager.h"
#include "NetworkManagerAP.h"
#include "nm-named-manager.h"
typedef struct NMData
{
GIOChannel *sigterm_iochannel;
int sigterm_pipe[2];
LibHalContext *hal_ctx;
NMNamedManager *named;
GList *nameserver_ids; /* For now these are global instead of per-device */
guint domain_search_id;
DBusConnection *dbus_connection;
GMainContext *main_context;
GMainLoop *main_loop;

View File

@@ -43,7 +43,6 @@
#include "NetworkManagerSystem.h"
#include "NetworkManagerDevice.h"
static int nm_system_open_sock (void)
{
int fd;
@@ -217,36 +216,3 @@ gboolean nm_system_device_set_ip4_default_route (NMDevice *dev, int ip4_def_rout
return (success);
}
/*****************************************************************************/
gboolean nm_system_device_update_resolv_conf (void *data, int len, const char *domain_name)
{
FILE *f;
if ((f = fopen ("/etc/resolv.conf", "w")))
{
int i;
fprintf (f, "; generated by NetworkManager\n");
if (domain_name && strlen (domain_name))
fprintf (f, "search %s\n", (char *)domain_name);
for (i = 0; data && (i < len); i += 4)
{
fprintf (f,"nameserver %u.%u.%u.%u\n",
((unsigned char *)data)[i],
((unsigned char *)data)[i+1],
((unsigned char *)data)[i+2],
((unsigned char *)data)[i+3]);
}
fclose(f);
}
else
syslog (LOG_ERR,"nm_system_device_update_resolv_conf(): could not open /etc/resolv.conf\n");
/* Reload DNS info for all apps */
(void)res_init();
return 0;
}