Merge remote branch 'origin/master' into rm-userset

This commit is contained in:
Dan Williams 2010-09-27 10:30:46 -05:00
commit 8b41f70dd5
55 changed files with 5555 additions and 1700 deletions

View file

@ -1317,7 +1317,7 @@
2008-09-30 Dan Williams <dcbw@redhat.com>
* src/NetworkManagerPolicy.c
- (lookup_thread_worker): don't store the idle handler ID becuase the
- (lookup_thread_worker): don't store the idle handler ID because the
idle handler could have already run and freed the LookupThread
structure
@ -8391,7 +8391,7 @@
internally; clients should provide a setting that applies to
the device with 'autoconnect: True'. Problem was that these
internally auto-created connections don't have a proxy or service
name becuase they weren't created by a settings daemon, and therefore
name because they weren't created by a settings daemon, and therefore
clients have no idea what to do with them.
2007-10-03 Dan Williams <dcbw@redhat.com>
@ -9794,7 +9794,7 @@
* libnm-glib/nm-settings.c
libnm-glib/nm-settings.h
- make the dbus path a property of the object, and autogenerate it.
It can't be composed of the 'id' field becuase that's not available
It can't be composed of the 'id' field because that's not available
yet during the GObject creation in nm_connection_settings_init()
2007-08-29 Dan Williams <dcbw@redhat.com>

4
README
View file

@ -66,11 +66,11 @@ those drivers that are shipped with the upstream Linux kernel, because only
those drivers can be easily fixed and debugged. ndiswrapper, vendor binary
drivers, or other out-of-tree drivers may or may not work well with
NetworkManager, precisely because they have not been vetted and improved by the
open-source community, and becuase problems in these drivers usually cannot
open-source community, and because problems in these drivers usually cannot
be fixed.
Sometimes, command-line tools like 'iwconfig' will work, but NetworkManager will
fail. This is again often due to buggy drivers, becuase these drivers simply
fail. This is again often due to buggy drivers, because these drivers simply
aren't expecting the dynamic requests that NetworkManager and wpa_supplicant
make. Driver bugs should be filed in the bug tracker of the distribution being
run, since often distributions customize their kernel and drivers.

View file

@ -60,9 +60,10 @@ static NmcOutputField nmc_fields_con_status[] = {
{"DEFAULT", N_("DEFAULT"), 8, NULL, 0}, /* 3 */
{"SPEC-OBJECT", N_("SPEC-OBJECT"), 10, NULL, 0}, /* 4 */
{"VPN", N_("VPN"), 5, NULL, 0}, /* 5 */
{"DBUS-PATH", N_("DBUS-PATH"), 51, NULL, 0}, /* 6 */
{NULL, NULL, 0, NULL, 0}
};
#define NMC_FIELDS_CON_STATUS_ALL "NAME,UUID,DEVICES,DEFAULT,VPN,SPEC-OBJECT"
#define NMC_FIELDS_CON_STATUS_ALL "NAME,UUID,DEVICES,DEFAULT,VPN,DBUS-PATH,SPEC-OBJECT"
#define NMC_FIELDS_CON_STATUS_COMMON "NAME,UUID,DEVICES,DEFAULT,VPN"
/* Available fields for 'con list' */
@ -74,9 +75,10 @@ static NmcOutputField nmc_fields_con_list[] = {
{"TIMESTAMP-REAL", N_("TIMESTAMP-REAL"), 34, NULL, 0}, /* 4 */
{"AUTOCONNECT", N_("AUTOCONNECT"), 13, NULL, 0}, /* 5 */
{"READONLY", N_("READONLY"), 10, NULL, 0}, /* 6 */
{"DBUS-PATH", N_("DBUS-PATH"), 42, NULL, 0}, /* 7 */
{NULL, NULL, 0, NULL, 0}
};
#define NMC_FIELDS_CON_LIST_ALL "NAME,UUID,TYPE,TIMESTAMP,TIMESTAMP-REAL,AUTOCONNECT,READONLY"
#define NMC_FIELDS_CON_LIST_ALL "NAME,UUID,TYPE,TIMESTAMP,TIMESTAMP-REAL,AUTOCONNECT,READONLY,DBUS-PATH"
#define NMC_FIELDS_CON_LIST_COMMON "NAME,UUID,TYPE,TIMESTAMP-REAL"
@ -370,6 +372,7 @@ show_connection (NMConnection *data, gpointer user_data)
timestamp = nm_setting_connection_get_timestamp (s_con);
timestamp_str = g_strdup_printf ("%" G_GUINT64_FORMAT, timestamp);
strftime (timestamp_real_str, sizeof (timestamp_real_str), "%c", localtime ((time_t *) &timestamp));
nmc->allowed_fields[0].value = nm_setting_connection_get_id (s_con);
nmc->allowed_fields[1].value = nm_setting_connection_get_uuid (s_con);
nmc->allowed_fields[2].value = nm_setting_connection_get_connection_type (s_con);
@ -377,6 +380,7 @@ show_connection (NMConnection *data, gpointer user_data)
nmc->allowed_fields[4].value = timestamp ? timestamp_real_str : _("never");
nmc->allowed_fields[5].value = nm_setting_connection_get_autoconnect (s_con) ? _("yes") : _("no");
nmc->allowed_fields[6].value = nm_setting_connection_get_read_only (s_con) ? _("yes") : _("no");
nmc->allowed_fields[7].value = nm_connection_get_path (connection);
nmc->print_fields.flags &= ~NMC_PF_FLAG_MAIN_HEADER_ADD & ~NMC_PF_FLAG_MAIN_HEADER_ONLY & ~NMC_PF_FLAG_FIELD_NAMES; /* Clear header flags */
print_fields (nmc->print_fields, nmc->allowed_fields);
@ -552,6 +556,7 @@ show_active_connection (gpointer data, gpointer user_data)
nmc->allowed_fields[3].value = nm_active_connection_get_default (active) ? _("yes") : _("no");
nmc->allowed_fields[4].value = nm_active_connection_get_specific_object (active);
nmc->allowed_fields[5].value = NM_IS_VPN_CONNECTION (active) ? _("yes") : _("no");
nmc->allowed_fields[6].value = nm_object_get_path (NM_OBJECT (active));
nmc->print_fields.flags &= ~NMC_PF_FLAG_MAIN_HEADER_ADD & ~NMC_PF_FLAG_MAIN_HEADER_ONLY & ~NMC_PF_FLAG_FIELD_NAMES; /* Clear header flags */
print_fields (nmc->print_fields, nmc->allowed_fields);

View file

@ -58,12 +58,13 @@
/* Available fields for 'dev status' */
static NmcOutputField nmc_fields_dev_status[] = {
{"DEVICE", N_("DEVICE"), 10, NULL, 0}, /* 0 */
{"TYPE", N_("TYPE"), 17, NULL, 0}, /* 1 */
{"STATE", N_("STATE"), 12, NULL, 0}, /* 2 */
{NULL, NULL, 0, NULL, 0}
{"DEVICE", N_("DEVICE"), 10, NULL, 0}, /* 0 */
{"TYPE", N_("TYPE"), 17, NULL, 0}, /* 1 */
{"STATE", N_("STATE"), 13, NULL, 0}, /* 2 */
{"DBUS-PATH", N_("DBUS-PATH"), 43, NULL, 0}, /* 3 */
{NULL, NULL, 0, NULL, 0}
};
#define NMC_FIELDS_DEV_STATUS_ALL "DEVICE,TYPE,STATE"
#define NMC_FIELDS_DEV_STATUS_ALL "DEVICE,TYPE,STATE,DBUS-PATH"
#define NMC_FIELDS_DEV_STATUS_COMMON "DEVICE,TYPE,STATE"
@ -763,6 +764,7 @@ show_device_status (NMDevice *device, NmCli *nmc)
nmc->allowed_fields[0].value = nm_device_get_iface (device);
nmc->allowed_fields[1].value = get_device_type (device);
nmc->allowed_fields[2].value = device_state_to_string (nm_device_get_state (device));
nmc->allowed_fields[3].value = nm_object_get_path (NM_OBJECT (device));
nmc->print_fields.flags &= ~NMC_PF_FLAG_MAIN_HEADER_ADD & ~NMC_PF_FLAG_MAIN_HEADER_ONLY & ~NMC_PF_FLAG_FIELD_NAMES; /* Clear header flags */
print_fields (nmc->print_fields, nmc->allowed_fields);

View file

@ -34,14 +34,16 @@
static NmcOutputField nmc_fields_nm_status[] = {
{"RUNNING", N_("RUNNING"), 15, NULL, 0}, /* 0 */
{"STATE", N_("STATE"), 15, NULL, 0}, /* 1 */
{"WIFI-HARDWARE", N_("WIFI-HARDWARE"), 15, NULL, 0}, /* 2 */
{"WIFI", N_("WIFI"), 10, NULL, 0}, /* 3 */
{"WWAN-HARDWARE", N_("WWAN-HARDWARE"), 15, NULL, 0}, /* 4 */
{"WWAN", N_("WWAN"), 10, NULL, 0}, /* 5 */
{"NET-ENABLED", N_("NET-ENABLED"), 13, NULL, 0}, /* 2 */
{"WIFI-HARDWARE", N_("WIFI-HARDWARE"), 15, NULL, 0}, /* 3 */
{"WIFI", N_("WIFI"), 10, NULL, 0}, /* 4 */
{"WWAN-HARDWARE", N_("WWAN-HARDWARE"), 15, NULL, 0}, /* 5 */
{"WWAN", N_("WWAN"), 10, NULL, 0}, /* 6 */
{NULL, NULL, 0, NULL, 0}
};
#define NMC_FIELDS_NM_STATUS_ALL "RUNNING,STATE,WIFI-HARDWARE,WIFI,WWAN-HARDWARE,WWAN"
#define NMC_FIELDS_NM_STATUS_ALL "RUNNING,STATE,NET-ENABLED,WIFI-HARDWARE,WIFI,WWAN-HARDWARE,WWAN"
#define NMC_FIELDS_NM_STATUS_COMMON "RUNNING,STATE,WIFI-HARDWARE,WIFI,WWAN-HARDWARE,WWAN"
#define NMC_FIELDS_NM_NET_ENABLED "NET-ENABLED"
#define NMC_FIELDS_NM_WIFI "WIFI"
#define NMC_FIELDS_NM_WWAN "WWAN"
@ -60,10 +62,10 @@ usage (void)
{
fprintf (stderr,
_("Usage: nmcli nm { COMMAND | help }\n\n"
" COMMAND := { status | sleep | wakeup | wifi | wwan }\n\n"
" COMMAND := { status | enable | sleep | wifi | wwan }\n\n"
" status\n"
" sleep\n"
" wakeup\n"
" enable [true|false]\n"
" sleep [true|false]\n"
" wifi [on|off]\n"
" wwan [on|off]\n\n"));
}
@ -97,6 +99,7 @@ static NMCResultCode
show_nm_status (NmCli *nmc)
{
gboolean nm_running;
gboolean net_enabled;
NMState state;
const char *wireless_hw_enabled_str, *wireless_enabled_str;
const char *wwan_hw_enabled_str, *wwan_enabled_str;
@ -136,6 +139,7 @@ show_nm_status (NmCli *nmc)
nm_running = nm_client_get_manager_running (nmc->client);
state = nm_client_get_state (nmc->client);
net_enabled = nm_client_networking_get_enabled (nmc->client);
if (nm_running) {
wireless_hw_enabled_str = nm_client_wireless_hardware_get_enabled (nmc->client) ? _("enabled") : _("disabled");
wireless_enabled_str = nm_client_wireless_get_enabled (nmc->client) ? _("enabled") : _("disabled");
@ -147,10 +151,11 @@ show_nm_status (NmCli *nmc)
nmc->allowed_fields[0].value = nm_running ? _("running") : _("not running");
nmc->allowed_fields[1].value = nm_state_to_string (state);
nmc->allowed_fields[2].value = wireless_hw_enabled_str;
nmc->allowed_fields[3].value = wireless_enabled_str;
nmc->allowed_fields[4].value = wwan_hw_enabled_str;
nmc->allowed_fields[5].value = wwan_enabled_str;
nmc->allowed_fields[2].value = net_enabled ? _("enabled") : _("disabled");
nmc->allowed_fields[3].value = wireless_hw_enabled_str;
nmc->allowed_fields[4].value = wireless_enabled_str;
nmc->allowed_fields[5].value = wwan_hw_enabled_str;
nmc->allowed_fields[6].value = wwan_enabled_str;
nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag;
print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
@ -158,12 +163,49 @@ show_nm_status (NmCli *nmc)
return NMC_RESULT_SUCCESS;
}
/* libnm-glib doesn't provide API fro Sleep method - implement D-Bus call ourselves */
static void networking_set_sleep (NmCli *nmc, gboolean in_sleep)
{
DBusGConnection *connection = NULL;
DBusGProxy *proxy = NULL;
GError *err = NULL;
connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err);
if (!connection) {
g_string_printf (nmc->return_text, _("Error: Couldn't connect to system bus: %s"), err->message);
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
g_error_free (err);
goto gone;
}
proxy = dbus_g_proxy_new_for_name (connection,
"org.freedesktop.NetworkManager",
"/org/freedesktop/NetworkManager",
"org.freedesktop.NetworkManager");
if (!proxy) {
g_string_printf (nmc->return_text, _("Error: Couldn't create D-Bus object proxy."));
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
goto gone;
}
if (!dbus_g_proxy_call (proxy, "Sleep", &err, G_TYPE_BOOLEAN, in_sleep, G_TYPE_INVALID, G_TYPE_INVALID)) {
g_string_printf (nmc->return_text, _("Error in sleep: %s"), err->message);
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
g_error_free (err);
}
gone:
if (connection) dbus_g_connection_unref (connection);
if (proxy) g_object_unref (proxy);
}
/* entry point function for global network manager related commands 'nmcli nm' */
NMCResultCode
do_network_manager (NmCli *nmc, int argc, char **argv)
{
GError *error = NULL;
gboolean sleep_flag;
gboolean enable_net;
gboolean enable_wifi;
gboolean enable_wwan;
guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
@ -186,11 +228,54 @@ do_network_manager (NmCli *nmc, int argc, char **argv)
goto opt_error;
nmc->return_value = show_nm_status (nmc);
}
else if (matches (*argv, "sleep") == 0) {
nm_client_sleep (nmc->client, TRUE);
else if (matches (*argv, "enable") == 0) {
if (next_arg (&argc, &argv) != 0) {
/* no argument, show current state of networking */
if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
goto opt_error;
if (nmc->required_fields && strcasecmp (nmc->required_fields, "NET-ENABLED")) {
g_string_printf (nmc->return_text, _("Error: '--fields' value '%s' is not valid here; allowed fields: %s"),
nmc->required_fields, NMC_FIELDS_NM_NET_ENABLED);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto end;
}
nmc->allowed_fields = nmc_fields_nm_status;
nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_NM_NET_ENABLED, nmc->allowed_fields, NULL);
nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
nmc->print_fields.header_name = _("Networking enabled");
print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
nmc->allowed_fields[2].value = nm_client_networking_get_enabled (nmc->client) ? _("enabled") : _("disabled");
nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag;
print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
} else {
if (!strcmp (*argv, "true"))
enable_net = TRUE;
else if (!strcmp (*argv, "false"))
enable_net = FALSE;
else {
g_string_printf (nmc->return_text, _("Error: invalid 'enable' parameter: '%s'; use 'true' or 'false'."), *argv);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto end;
}
nm_client_networking_set_enabled (nmc->client, enable_net);
}
}
else if (matches (*argv, "wakeup") == 0) {
nm_client_sleep (nmc->client, FALSE);
else if (matches (*argv, "sleep") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: Sleeping status is not exported by NetworkManager."));
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
} else {
if (!strcmp (*argv, "true"))
sleep_flag = TRUE;
else if (!strcmp (*argv, "false"))
sleep_flag = FALSE;
else {
g_string_printf (nmc->return_text, _("Error: invalid 'sleep' parameter: '%s'; use 'true' or 'false'."), *argv);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto end;
}
networking_set_sleep (nmc, sleep_flag);
}
}
else if (matches (*argv, "wifi") == 0) {
if (next_arg (&argc, &argv) != 0) {
@ -208,7 +293,7 @@ do_network_manager (NmCli *nmc, int argc, char **argv)
nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
nmc->print_fields.header_name = _("WiFi enabled");
print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
nmc->allowed_fields[3].value = nm_client_wireless_get_enabled (nmc->client) ? _("enabled") : _("disabled");
nmc->allowed_fields[4].value = nm_client_wireless_get_enabled (nmc->client) ? _("enabled") : _("disabled");
nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag;
print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
} else {
@ -240,7 +325,7 @@ do_network_manager (NmCli *nmc, int argc, char **argv)
nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
nmc->print_fields.header_name = _("WWAN enabled");
print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
nmc->allowed_fields[5].value = nm_client_wwan_get_enabled (nmc->client) ? _("enabled") : _("disabled");
nmc->allowed_fields[6].value = nm_client_wwan_get_enabled (nmc->client) ? _("enabled") : _("disabled");
nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag;
print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
} else {

View file

@ -521,7 +521,6 @@ system-settings/plugins/ifcfg-rh/tests/Makefile
system-settings/plugins/ifcfg-rh/tests/network-scripts/Makefile
system-settings/plugins/ifcfg-suse/Makefile
system-settings/plugins/keyfile/Makefile
system-settings/plugins/keyfile/io/Makefile
system-settings/plugins/keyfile/tests/Makefile
system-settings/plugins/keyfile/tests/keyfiles/Makefile
cli/Makefile

View file

@ -17,7 +17,6 @@ EXTRA_DIST = \
nm-manager.xml \
nm-manager-client.xml \
nm-settings.xml \
nm-settings-system.xml \
nm-sysconfig-connection.xml \
nm-vpn-plugin.xml \
nm-vpn-connection.xml \

View file

@ -60,6 +60,7 @@ object. dbus-glib generates the same bound function names for D-Bus the methods
<property name="WwanEnabled" type="b" access="readwrite"/>
<property name="WwanHardwareEnabled" type="b" access="read"/>
<property name="ActiveConnections" type="ao" access="read"/>
<property name="Version" type="s" access="read"/>
<property name="State" type="u" access="read"/>
<signal name="StateChanged">

View file

@ -200,6 +200,12 @@
</tp:docstring>
</property>
<property name="Version" type="s" access="read">
<tp:docstring>
NetworkManager version.
</tp:docstring>
</property>
<property name="State" type="u" access="read" tp:type="NM_STATE">
<tp:docstring>
The overall state of the NetworkManager daemon.

View file

@ -1165,7 +1165,7 @@ nm_device_update_description (NMDevice *device)
* vendor and device ID information off it.
*/
/* Ref the device again becuase we have to unref it each iteration,
/* Ref the device again because we have to unref it each iteration,
* as g_udev_device_get_parent() returns a ref-ed object.
*/
tmpdev = g_object_ref (udev_device);

View file

@ -231,12 +231,30 @@ verify (NMSetting *setting, GSList *all_settings, GError **error)
return FALSE;
}
if (priv->apn && (strlen (priv->apn) < 1 || strchr (priv->apn, '"'))) {
g_set_error (error,
NM_SETTING_GSM_ERROR,
NM_SETTING_GSM_ERROR_INVALID_PROPERTY,
NM_SETTING_GSM_APN);
return FALSE;
if (priv->apn) {
guint32 apn_len = strlen (priv->apn);
guint32 i;
if (apn_len < 1 || apn_len > 64) {
g_set_error (error,
NM_SETTING_GSM_ERROR,
NM_SETTING_GSM_ERROR_INVALID_PROPERTY,
NM_SETTING_GSM_APN);
return FALSE;
}
/* APNs roughly follow the same rules as DNS domain names. Allowed
* characters are a-z, 0-9, . and -. GSM 03.60 Section 14.9.
*/
for (i = 0; i < apn_len; i++) {
if (!isalnum (priv->apn[i]) && (priv->apn[i] != '.') && (priv->apn[i] != '-')) {
g_set_error (error,
NM_SETTING_GSM_ERROR,
NM_SETTING_GSM_ERROR_INVALID_PROPERTY,
NM_SETTING_GSM_APN);
return FALSE;
}
}
}
if (priv->username && !strlen (priv->username)) {
@ -342,11 +360,11 @@ set_property (GObject *object, guint prop_id,
break;
case PROP_APN:
g_free (priv->apn);
priv->apn = g_value_dup_string (value);
priv->apn = g_strstrip (g_value_dup_string (value));
break;
case PROP_NETWORK_ID:
g_free (priv->network_id);
priv->network_id = g_value_dup_string (value);
priv->network_id = g_strstrip (g_value_dup_string (value));
break;
case PROP_NETWORK_TYPE:
priv->network_type = g_value_get_int (value);
@ -503,6 +521,8 @@ nm_setting_gsm_class_init (NMSettingGsmClass *setting_class)
* the user will be billed for their network usage and whether the user has
* access to the Internet or just a provider-specific walled-garden, so it
* is important to use the correct APN for the user's mobile broadband plan.
* The APN may only be composed of the characters a-z, 0-9, ., and - per
* GSM 03.60 Section 14.9.
**/
g_object_class_install_property
(object_class, PROP_APN,
@ -515,7 +535,8 @@ nm_setting_gsm_class_init (NMSettingGsmClass *setting_class)
"user has access to the Internet or just a provider-"
"specific walled-garden, so it is important to use "
"the correct APN for the user's mobile broadband "
"plan.",
"plan. The APN may only be composed of the characters "
"a-z, 0-9, ., and - per GSM 03.60 Section 14.9.",
NULL,
G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));

View file

@ -28,6 +28,7 @@
#include "nm-setting-connection.h"
#include "nm-setting-vpn.h"
#include "nm-setting-gsm.h"
#include "nm-setting-ip6-config.h"
#include "nm-dbus-glib-types.h"
@ -222,6 +223,72 @@ test_setting_ip6_config_old_address_array (void)
g_object_unref (s_ip6);
}
static void
test_setting_gsm_apn_spaces (void)
{
NMSettingGsm *s_gsm;
const char *tmp;
s_gsm = (NMSettingGsm *) nm_setting_gsm_new ();
ASSERT (s_gsm != NULL,
"gsm-apn-spaces",
"error creating GSM setting");
/* Trailing space */
g_object_set (s_gsm, NM_SETTING_GSM_APN, "foobar ", NULL);
tmp = nm_setting_gsm_get_apn (s_gsm);
ASSERT (tmp != NULL,
"gsm-apn-spaces", "empty APN");
ASSERT (strcmp (tmp, "foobar") == 0,
"gsm-apn-spaces", "unexpected APN");
/* Leading space */
g_object_set (s_gsm, NM_SETTING_GSM_APN, " foobar", NULL);
tmp = nm_setting_gsm_get_apn (s_gsm);
ASSERT (tmp != NULL,
"gsm-apn-spaces", "empty APN");
ASSERT (strcmp (tmp, "foobar") == 0,
"gsm-apn-spaces", "unexpected APN");
}
static void
test_setting_gsm_apn_bad_chars (void)
{
NMSettingGsm *s_gsm;
s_gsm = (NMSettingGsm *) nm_setting_gsm_new ();
ASSERT (s_gsm != NULL,
"gsm-apn-bad-chars",
"error creating GSM setting");
g_object_set (s_gsm, NM_SETTING_GSM_NUMBER, "*99#", NULL);
/* Make sure a valid APN works */
g_object_set (s_gsm, NM_SETTING_GSM_APN, "foobar123.-baz", NULL);
ASSERT (nm_setting_verify (NM_SETTING (s_gsm), NULL, NULL) == TRUE,
"gsm-apn-bad-chars", "unexpectedly invalid GSM setting");
/* Random invalid chars */
g_object_set (s_gsm, NM_SETTING_GSM_APN, "@#%$@#%@#%", NULL);
ASSERT (nm_setting_verify (NM_SETTING (s_gsm), NULL, NULL) == FALSE,
"gsm-apn-bad-chars", "unexpectedly valid GSM setting");
/* Spaces */
g_object_set (s_gsm, NM_SETTING_GSM_APN, "foobar baz", NULL);
ASSERT (nm_setting_verify (NM_SETTING (s_gsm), NULL, NULL) == FALSE,
"gsm-apn-bad-chars", "unexpectedly valid GSM setting");
/* 0 characters long */
g_object_set (s_gsm, NM_SETTING_GSM_APN, "", NULL);
ASSERT (nm_setting_verify (NM_SETTING (s_gsm), NULL, NULL) == FALSE,
"gsm-apn-bad-chars", "unexpectedly valid GSM setting");
/* 65-character long */
g_object_set (s_gsm, NM_SETTING_GSM_APN, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl1", NULL);
ASSERT (nm_setting_verify (NM_SETTING (s_gsm), NULL, NULL) == FALSE,
"gsm-apn-bad-chars", "unexpectedly valid GSM setting");
}
int main (int argc, char **argv)
{
GError *error = NULL;
@ -237,6 +304,8 @@ int main (int argc, char **argv)
/* The tests */
test_setting_vpn_items ();
test_setting_ip6_config_old_address_array ();
test_setting_gsm_apn_spaces ();
test_setting_gsm_apn_bad_chars ();
base = g_path_get_basename (argv[0]);
fprintf (stdout, "%s: SUCCESS\n", base);

View file

@ -44,12 +44,13 @@ Description of sections and available keys follows:
This section is the only mandatory section of the configuration file.
.TP
.B plugins=\fIplugin1\fP,\fIplugin2\fP, ...
List plugin names separated by ','. Plugins are used to read/write system-wide
connection. When more plugins are specified, the connections are read from all
listed plugins. When writing connections, the plugins will be asked to save the
connection in the order listed here. If the first plugin cannot write out that
connection type, or can't write out any connections, the next plugin is tried.
If none of the plugins can save the connection, the error is returned to the user.
List system settings plugin names separated by ','. These plugins are used to
read/write system-wide connection. When more plugins are specified, the
connections are read from all listed plugins. When writing connections, the
plugins will be asked to save the connection in the order listed here. If the
first plugin cannot write out that connection type, or can't write out any
connections, the next plugin is tried. If none of the plugins can save the
connection, the error is returned to the user.
.P
.RS
.B "Available plugins:"
@ -88,7 +89,7 @@ This key sets up what DHCP client NetworkManager will use. Presently
be available on your system too. If this key is missing, available DHCP clients
are looked for in this order: dhclient, dhcpcd.
.TP
.B no-auto-default=\fI<hwaddr>\fP,\fI<hwaddr>\fP,...
.B no-auto-default=\fI<hwaddr>\fP,\fI<hwaddr>\fP,... | \fI*\fP
Set devices for which NetworkManager shouldn't create default wired connection
(Auto eth0). NetworkManager creates a default wired connection for any wired
device that is managed and doesn't have a connection configured. List a device
@ -98,12 +99,27 @@ When the default wired connection is deleted or saved to a new persistent connec
by a plugin, the MAC address of the wired device is automatically added to this list
to prevent creating the default connection for that device again.
Devices are specified by their MAC addresses, in lowercase. Multiple
entries are separated by commas.
entries are separated by commas. You can use the glob character \fI*\fP instead
of listing addresses to specify all devices.
.br
Example:
Examples:
.nf
no-auto-default=00:22:68:5c:5d:c4,00:1e:65:ff:aa:ee
no-auto-default=*
.fi
.TP
.B dns=\fIplugin1\fP,\fIplugin2\fP, ...
List DNS plugin names separated by ','. DNS plugins are used to provide local
caching nameserver functionality (which speeds up DNS queries) and to push
DNS data to applications that use it.
.P
.RS
.B "Available plugins:"
.br
.TP
.I dnsmasq
this plugin uses dnsmasq to provide local caching nameserver functionality.
.RE
.SS [keyfile]
This section contains keyfile-specific options and thus only has effect when using \fIkeyfile\fP plugin.
.TP

View file

@ -22,7 +22,7 @@
.\"
.\" Copyright (C) 2010 Red Hat, Inc.
.\"
.TH NMCLI "1" "9 September 2010"
.TH NMCLI "1" "22 September 2010"
.SH NAME
nmcli \- command-line tool for controlling NetworkManager
@ -133,7 +133,7 @@ NetworkManager
.br
Use this object to inquire and change state of NetworkManager.
.TP
.SS \fICOMMAND\fP := { status | sleep | wakeup | wifi | wwan }
.SS \fICOMMAND\fP := { status | enable | sleep | wifi | wwan }
.sp
.RS
.TP
@ -147,28 +147,31 @@ command is provided to \fInm\fP object.
No simple reference.
.fi
.TP
.B sleep
.B enable [true|false]
.br
Put NetworkManager to sleeping mode. Thus all interfaces that NetworkManager
manages are deactivated.
Get networking-enabled status or enable/disable networking by NetworkManager.
All interfaces managed by NetworkManager are deactivated when networking has
been disabled.
.br
.nf
\fBReference to D-Bus:\fP
interface: org.freedesktop.NetworkManager
method: Sleep
arguments: TRUE
method: Enable
arguments: TRUE or FALSE
.fi
.TP
.B wakeup
.B sleep [true|false]
.br
Awake NetworkManager from sleep. When NetworkManager is awaken, devices are
available to be activated.
Get sleep status or put to sleep/awake NetworkManager. All interfaces managed by NetworkManager
are deactivated when it falls asleep. This command is not meant for user to enable/disable
networking, use \fIenable\fP for that. D-Bus \fISleep\fP method is designed
to put NetworkManager to sleep or awake for suspending/resuming computer.
.br
.nf
\fBReference to D-Bus:\fP
interface: org.freedesktop.NetworkManager
method: Sleep
arguments: FALSE
arguments: TRUE or FALSE
.fi
.TP
.B wifi [on|off]

1517
po/de.po

File diff suppressed because it is too large Load diff

314
po/es.po
View file

@ -15,8 +15,8 @@ msgstr ""
"Project-Id-Version: es\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?"
"product=NetworkManager&component=general\n"
"POT-Creation-Date: 2010-08-10 03:25+0000\n"
"PO-Revision-Date: 2010-08-16 21:27+0200\n"
"POT-Creation-Date: 2010-09-17 15:25+0000\n"
"PO-Revision-Date: 2010-09-18 11:01+0200\n"
"Last-Translator: Jorge González <jorgegonz@svn.gnome.org>\n"
"Language-Team: Español <gnome-es-list@gnome.org>\n"
"MIME-Version: 1.0\n"
@ -118,12 +118,12 @@ msgstr ""
#: ../cli/src/connections.c:198 ../cli/src/connections.c:537
#, c-format
msgid "Error: 'con list': %s"
msgstr "Error: 'con list': %s"
msgstr "Error: «con list»: %s"
#: ../cli/src/connections.c:200 ../cli/src/connections.c:539
#, c-format
msgid "Error: 'con list': %s; allowed fields: %s"
msgstr "Error: 'con list': %s; campos permitidos: %s"
msgstr "Error: «con list»: %s; campos permitidos: %s"
#: ../cli/src/connections.c:208
msgid "Connection details"
@ -219,7 +219,7 @@ msgid "Error: no valid parameter specified."
msgstr "Error: no se especificó un parámetro válido."
#: ../cli/src/connections.c:544 ../cli/src/connections.c:1577
#: ../cli/src/devices.c:1293 ../cli/src/network-manager.c:274
#: ../cli/src/devices.c:1293 ../cli/src/network-manager.c:359
#, c-format
msgid "Error: %s."
msgstr "Error: %s."
@ -227,12 +227,12 @@ msgstr "Error: %s."
#: ../cli/src/connections.c:650
#, c-format
msgid "Error: 'con status': %s"
msgstr "Error: 'con status': %s"
msgstr "Error: «con status»: %s"
#: ../cli/src/connections.c:652
#, c-format
msgid "Error: 'con status': %s; allowed fields: %s"
msgstr "Error: 'con status': %s; campos permitidos: %s"
msgstr "Error: «con status»: %s; campos permitidos: %s"
#: ../cli/src/connections.c:659
msgid "Active connections"
@ -241,22 +241,22 @@ msgstr "Conexiones activas"
#: ../cli/src/connections.c:1027
#, c-format
msgid "no active connection on device '%s'"
msgstr "conexión no activa en dispositivo '%s'"
msgstr "conexión no activa en el dispositivo «%s»"
#: ../cli/src/connections.c:1035
#, c-format
msgid "no active connection or device"
msgstr "conexión o dispositivo no activos"
msgstr "conexión o dispositivo no activo"
#: ../cli/src/connections.c:1085
#, c-format
msgid "device '%s' not compatible with connection '%s'"
msgstr "dispositivo '%s' incompatible con conexión '%s'"
msgstr "dispositivo «%s» incompatible con conexión «%s»"
#: ../cli/src/connections.c:1087
#, c-format
msgid "no device found for connection '%s'"
msgstr "no se encontró dispositivo para conexión '%s'"
msgstr "no se encontró dispositivo para conexión «%s»"
#: ../cli/src/connections.c:1098
msgid "activating"
@ -268,8 +268,8 @@ msgstr "activada"
#: ../cli/src/connections.c:1103 ../cli/src/connections.c:1126
#: ../cli/src/connections.c:1159 ../cli/src/devices.c:246
#: ../cli/src/devices.c:558 ../cli/src/network-manager.c:92
#: ../cli/src/network-manager.c:145 ../cli/src/settings.c:473
#: ../cli/src/devices.c:558 ../cli/src/network-manager.c:94
#: ../cli/src/network-manager.c:149 ../cli/src/settings.c:473
msgid "unknown"
msgstr "desconocido"
@ -287,7 +287,7 @@ msgstr "Conectando VPN"
#: ../cli/src/connections.c:1118
msgid "VPN connecting (getting IP configuration)"
msgstr "Conectando VPN (Obteniendo configuración IP)"
msgstr "Conectando VPN (obteniendo configuración IP)"
#: ../cli/src/connections.c:1120
msgid "VPN connected"
@ -295,7 +295,7 @@ msgstr "VPN conectada"
#: ../cli/src/connections.c:1122
msgid "VPN connection failed"
msgstr "Conexión VPN falló"
msgstr "Falló la conexión VPN"
#: ../cli/src/connections.c:1124
msgid "VPN disconnected"
@ -315,19 +315,19 @@ msgstr "el usuario estaba desconectado"
#: ../cli/src/connections.c:1141
msgid "the base network connection was interrupted"
msgstr "la conexión de red de base fue interrumpida"
msgstr "se interrumpió la conexión de red de base"
#: ../cli/src/connections.c:1143
msgid "the VPN service stopped unexpectedly"
msgstr "El servicio VPN se detuvo inesperadamente"
msgstr "el servicio VPN se detuvo inesperadamente"
#: ../cli/src/connections.c:1145
msgid "the VPN service returned invalid configuration"
msgstr "El servicio VPN retornó configuración inválida"
msgstr "el servicio VPN retornó una configuración no válida"
#: ../cli/src/connections.c:1147
msgid "the connection attempt timed out"
msgstr "El intento de conexión se agotó"
msgstr "se agotaron los intentos de conexión"
#: ../cli/src/connections.c:1149
msgid "the VPN service did not start in time"
@ -347,7 +347,7 @@ msgstr "secretos VPN válidos"
#: ../cli/src/connections.c:1157
msgid "the connection was removed"
msgstr "la conexión fue eliminada"
msgstr "se eliminó la conexión"
#: ../cli/src/connections.c:1171
#, c-format
@ -362,7 +362,7 @@ msgstr "Conexión activada\n"
#: ../cli/src/connections.c:1177
#, c-format
msgid "Error: Connection activation failed."
msgstr "Error: Activación de conexión falló."
msgstr "Error: falló la activación de la conexión."
#: ../cli/src/connections.c:1196
#, c-format
@ -372,72 +372,72 @@ msgstr "estado: %s (%d)\n"
#: ../cli/src/connections.c:1206
#, c-format
msgid "Error: Connection activation failed: %s."
msgstr "Error: Activación de conexión falló: %s."
msgstr "Error: falló la activación de la conexión: %s."
#: ../cli/src/connections.c:1223 ../cli/src/devices.c:909
#, c-format
msgid "Error: Timeout %d sec expired."
msgstr "Error: Pausa de %d segundos expiró."
msgstr "Error: expiró la pausa de %d segundos."
#: ../cli/src/connections.c:1266
#, c-format
msgid "Error: Connection activation failed: %s"
msgstr "Error: Activación de conexión falló: %s"
msgstr "Error: falló la activación de la conexión: %s"
#: ../cli/src/connections.c:1280
#, c-format
msgid "Error: Obtaining active connection for '%s' failed."
msgstr "Error: Obtención de conexión activa para '%s' falló."
msgstr "Error: falló la obtención de conexión activa para «%s»."
#: ../cli/src/connections.c:1289
#, c-format
msgid "Active connection state: %s\n"
msgstr "Estado de conexión activa: %s\n"
msgstr "Estado de la conexión activa: %s\n"
#: ../cli/src/connections.c:1290
#, c-format
msgid "Active connection path: %s\n"
msgstr "Ruta de conexión activa: %s\n"
msgstr "Ruta de la conexión activa: %s\n"
#: ../cli/src/connections.c:1344 ../cli/src/connections.c:1465
#, c-format
msgid "Error: Unknown connection: %s."
msgstr "Error: Conexión desconocida: %s."
msgstr "Error: conexión desconocida: %s."
#: ../cli/src/connections.c:1379 ../cli/src/devices.c:980
#, c-format
msgid "Error: timeout value '%s' is not valid."
msgstr "Error: valor de pausa '%s' inválido."
msgstr "Error: valor de pausa «%s» inválido."
#: ../cli/src/connections.c:1392 ../cli/src/connections.c:1482
#, c-format
msgid "Error: id or uuid has to be specified."
msgstr "Error: id o uuid ha sido especificado."
msgstr "Error: se debe especificar un id o uuid."
#: ../cli/src/connections.c:1412
#, c-format
msgid "Error: No suitable device found: %s."
msgstr "Error: Dispositivo inapropiado: %s."
msgstr "Error: no se encontró un dispositivo apropiado: %s."
#: ../cli/src/connections.c:1414
#, c-format
msgid "Error: No suitable device found."
msgstr "Error: Dispositivo no apropiado."
msgstr "Error: no se encontró un dispositivo apropiado."
#: ../cli/src/connections.c:1509
#, c-format
msgid "Warning: Connection not active\n"
msgstr "Advertencia: Conexión inactiva\n"
msgstr "Advertencia: conexión inactiva\n"
#: ../cli/src/connections.c:1566
#, c-format
msgid "Error: 'con' command '%s' is not valid."
msgstr "Error: comando 'con' '%s' es inválido."
msgstr "Error: comando «con» «%s» no es válido."
#: ../cli/src/connections.c:1602
#, c-format
msgid "Error: could not connect to D-Bus."
msgstr "Error: no se pudo conectar a D-Bus."
msgstr "Error: no se pudo conectar con D-Bus."
#: ../cli/src/connections.c:1609
#, c-format
@ -453,7 +453,7 @@ msgstr "Error: No se pudo obtener configuración de usuario."
#, c-format
msgid "Error: Can't obtain connections: settings services are not running."
msgstr ""
"Error: No se pudieron obtener conexiones: servicios de configuración no se "
"Error: no se pudieron obtener conexiones: servicios de configuración no se "
"están ejecutando."
#. 0
@ -506,13 +506,11 @@ msgstr "DNS IP4"
#. 6
#: ../cli/src/devices.c:79
#| msgid "IP4-SETTINGS"
msgid "IP6-SETTINGS"
msgstr "CONFIGURACIONES IP6"
#. 7
#: ../cli/src/devices.c:80
#| msgid "IP4-DNS"
msgid "IP6-DNS"
msgstr "DNS IP6"
@ -667,7 +665,7 @@ msgstr "sin gestión"
msgid "unavailable"
msgstr "no disponible"
#: ../cli/src/devices.c:232 ../cli/src/network-manager.c:89
#: ../cli/src/devices.c:232 ../cli/src/network-manager.c:91
msgid "disconnected"
msgstr "desconectado"
@ -687,7 +685,7 @@ msgstr "conectando (necesita autenticación)"
msgid "connecting (getting IP configuration)"
msgstr "conectando (obteniendo configuración IP)"
#: ../cli/src/devices.c:242 ../cli/src/network-manager.c:87
#: ../cli/src/devices.c:242 ../cli/src/network-manager.c:89
msgid "connected"
msgstr "conectado"
@ -749,16 +747,16 @@ msgstr "Infraestructura"
#: ../cli/src/devices.c:486
#, c-format
msgid "Error: 'dev list': %s"
msgstr "Error: 'dev list': %s"
msgstr "Error: «dev list»: %s"
#: ../cli/src/devices.c:488
#, c-format
msgid "Error: 'dev list': %s; allowed fields: %s"
msgstr "Error: 'dev list': %s; campos permitidos: %s"
msgstr "Error: «dev list»: %s; campos permitidos: %s"
#: ../cli/src/devices.c:497
msgid "Device details"
msgstr "Detalles de dispositivos"
msgstr "Detalles de los dispositivos"
#: ../cli/src/devices.c:527 ../cli/src/devices.c:925
msgid "(unknown)"
@ -786,81 +784,81 @@ msgstr "apagado"
#: ../cli/src/devices.c:808
#, c-format
msgid "Error: 'dev status': %s"
msgstr "Error: 'dev status': %s"
msgstr "Error: «dev status»: %s"
#: ../cli/src/devices.c:810
#, c-format
msgid "Error: 'dev status': %s; allowed fields: %s"
msgstr "Error: 'dev status': %s; campos permitidos: %s"
msgstr "Error: «dev status»: %s; campos permitidos: %s"
#: ../cli/src/devices.c:817
msgid "Status of devices"
msgstr "Estado de dispositivos"
msgstr "Estado de los dispositivos"
#: ../cli/src/devices.c:845
#, c-format
msgid "Error: '%s' argument is missing."
msgstr "Error: '%s' falta argumento."
msgstr "Error: falta el argumento «%s»."
#: ../cli/src/devices.c:874 ../cli/src/devices.c:1013
#: ../cli/src/devices.c:1136
#, c-format
msgid "Error: Device '%s' not found."
msgstr "Error: Dispositivo '%s' no encontrado."
msgstr "Error: no se encontró el dispositivo «%s»."
#: ../cli/src/devices.c:897
#, c-format
msgid "Success: Device '%s' successfully disconnected."
msgstr "Éxito: Dispositivo '%s' desconectado correctamente."
msgstr "Éxito: dispositivo «%s» desconectado correctamente."
#: ../cli/src/devices.c:922
#, c-format
msgid "Error: Device '%s' (%s) disconnecting failed: %s"
msgstr "Error: Desconexión de dispositivo '%s' (%s) falló: %s"
msgstr "Error: falló la desconexión del dispositivo «%s» (%s): %s"
#: ../cli/src/devices.c:930
#, c-format
msgid "Device state: %d (%s)\n"
msgstr "Estado de dispositivo: %d (%s)\n"
msgstr "Estado del dispositivo: %d (%s)\n"
#: ../cli/src/devices.c:994
#, c-format
msgid "Error: iface has to be specified."
msgstr "Error: iface tiene que especificarse."
msgstr "Error: se debe especificar iface."
#: ../cli/src/devices.c:1112
#, c-format
msgid "Error: 'dev wifi': %s"
msgstr "Error: 'dev wifi' '%s'"
msgstr "Error: «dev wifi» «%s»"
#: ../cli/src/devices.c:1114
#, c-format
msgid "Error: 'dev wifi': %s; allowed fields: %s"
msgstr "Error: 'dev wifi': %s; campos permitidos: %s"
msgstr "Error: «dev wifi»: %s; campos permitidos: %s"
#: ../cli/src/devices.c:1121
msgid "WiFi scan list"
msgstr "lista de scan WiFi"
msgstr "lista de análisis WiFi"
#: ../cli/src/devices.c:1156 ../cli/src/devices.c:1210
#, c-format
msgid "Error: Access point with hwaddr '%s' not found."
msgstr "Error: Punto de acceso con hwaddr '%s' no se encontró."
msgstr "Error: no se encontró el punto de acceso con hwaddr «%s»."
#: ../cli/src/devices.c:1173
#, c-format
msgid "Error: Device '%s' is not a WiFi device."
msgstr "Error: Dispositivo '%s' no es un dispositivo WiFi."
msgstr "Error: el dispositivo «%s» no es un dispositivo WiFi."
#: ../cli/src/devices.c:1237
#, c-format
msgid "Error: 'dev wifi' command '%s' is not valid."
msgstr "Error: comando 'dev wifi' '%s' inválido."
msgstr "Error: comando «dev wifi» «%s» inválido."
#: ../cli/src/devices.c:1284
#, c-format
msgid "Error: 'dev' command '%s' is not valid."
msgstr "Error: comando 'dev' '%s' inválido."
msgstr "Error: comando «dev» «%s» no válido."
#: ../cli/src/network-manager.c:35
msgid "RUNNING"
@ -868,119 +866,180 @@ msgstr "EJECUTANDO"
#. 1
#: ../cli/src/network-manager.c:37
msgid "WIFI-HARDWARE"
msgstr "HARDWARE-WIFI"
msgid "NET-ENABLED"
msgstr "RED-ACTIVADA"
#. 2
#: ../cli/src/network-manager.c:38
msgid "WIFI"
msgstr "WIFI"
msgid "WIFI-HARDWARE"
msgstr "HARDWARE-WIFI"
#. 3
#: ../cli/src/network-manager.c:39
msgid "WWAN-HARDWARE"
msgstr "HARDWARE-WWAN"
msgid "WIFI"
msgstr "WIFI"
#. 4
#: ../cli/src/network-manager.c:40
msgid "WWAN-HARDWARE"
msgstr "HARDWARE-WWAN"
#. 5
#: ../cli/src/network-manager.c:41
msgid "WWAN"
msgstr "WWAN"
#: ../cli/src/network-manager.c:62
#: ../cli/src/network-manager.c:64
#, c-format
#| msgid ""
#| "Usage: nmcli nm { COMMAND | help }\n"
#| "\n"
#| " COMMAND := { status | sleep | wakeup | wifi | wwan }\n"
#| "\n"
#| " status\n"
#| " sleep\n"
#| " wakeup\n"
#| " wifi [on|off]\n"
#| " wwan [on|off]\n"
#| "\n"
msgid ""
"Usage: nmcli nm { COMMAND | help }\n"
"\n"
" COMMAND := { status | sleep | wakeup | wifi | wwan }\n"
" COMMAND := { status | enable | sleep | wifi | wwan }\n"
"\n"
" status\n"
" sleep\n"
" wakeup\n"
" enable [true|false]\n"
" sleep [true|false]\n"
" wifi [on|off]\n"
" wwan [on|off]\n"
"\n"
msgstr ""
"Uso: nmcli nm { COMANDO | ayuda }\n"
"\n"
" COMANDO := { status | sleep | wakeup | wifi | wwan }\n"
" COMANDO := { status | enable | sleep | wakeup | wifi | wwan }\n"
"\n"
" estatus\n"
" estado\n"
" activar [cierto|falso]\n"
" dormir\n"
" despertar\n"
" wifi [encendido|apagado]\n"
" wwan [encendido|apagado]\n"
"\n"
#: ../cli/src/network-manager.c:83
#: ../cli/src/network-manager.c:85
msgid "asleep"
msgstr "dormido"
#: ../cli/src/network-manager.c:85
#: ../cli/src/network-manager.c:87
msgid "connecting"
msgstr "conectando"
#: ../cli/src/network-manager.c:125
#: ../cli/src/network-manager.c:128
#, c-format
msgid "Error: 'nm status': %s"
msgstr "Error: 'nm status': %s"
msgstr "Error: «nm status»: %s"
#: ../cli/src/network-manager.c:127
#: ../cli/src/network-manager.c:130
#, c-format
msgid "Error: 'nm status': %s; allowed fields: %s"
msgstr "Error: 'nm status': %s; campos permitidos: %s"
msgstr "Error: «nm status»: %s; campos permitidos: %s"
#: ../cli/src/network-manager.c:134
#: ../cli/src/network-manager.c:137
msgid "NetworkManager status"
msgstr "Estado de NetworkManager"
#. Print header
#: ../cli/src/network-manager.c:140 ../cli/src/network-manager.c:141
#: ../cli/src/network-manager.c:142 ../cli/src/network-manager.c:143
#: ../cli/src/network-manager.c:211 ../cli/src/network-manager.c:243
#: ../cli/src/network-manager.c:144 ../cli/src/network-manager.c:145
#: ../cli/src/network-manager.c:146 ../cli/src/network-manager.c:147
#: ../cli/src/network-manager.c:154 ../cli/src/network-manager.c:247
#: ../cli/src/network-manager.c:296 ../cli/src/network-manager.c:328
msgid "enabled"
msgstr "habilitado"
msgstr "activado"
#: ../cli/src/network-manager.c:140 ../cli/src/network-manager.c:141
#: ../cli/src/network-manager.c:142 ../cli/src/network-manager.c:143
#: ../cli/src/network-manager.c:211 ../cli/src/network-manager.c:243
#: ../cli/src/network-manager.c:144 ../cli/src/network-manager.c:145
#: ../cli/src/network-manager.c:146 ../cli/src/network-manager.c:147
#: ../cli/src/network-manager.c:154 ../cli/src/network-manager.c:247
#: ../cli/src/network-manager.c:296 ../cli/src/network-manager.c:328
msgid "disabled"
msgstr "inhabilitado"
msgstr "desactivado"
#: ../cli/src/network-manager.c:148
#: ../cli/src/network-manager.c:152
msgid "running"
msgstr "ejecutando"
#: ../cli/src/network-manager.c:148
#: ../cli/src/network-manager.c:152
msgid "not running"
msgstr "no ejecutando"
#: ../cli/src/network-manager.c:201 ../cli/src/network-manager.c:233
#: ../cli/src/network-manager.c:175
#, c-format
#| msgid "Error: could not connect to D-Bus."
msgid "Error: Couldn't connect to system bus: %s"
msgstr "Error: no se pudo conectar con el bus del sistema: %s"
#: ../cli/src/network-manager.c:186
#, c-format
#| msgid "Error: could not connect to D-Bus."
msgid "Error: Couldn't create D-Bus object proxy."
msgstr "Error: no se pudo crear un objeto proxy en D-Bus."
#: ../cli/src/network-manager.c:192
#, c-format
#| msgid "Error: 'con list': %s"
msgid "Error in sleep: %s"
msgstr "Error al dormir: %s"
#: ../cli/src/network-manager.c:237 ../cli/src/network-manager.c:286
#: ../cli/src/network-manager.c:318
#, c-format
msgid "Error: '--fields' value '%s' is not valid here; allowed fields: %s"
msgstr "Error: '--fields' valor '%s' no es válido aquí; campos permitidos: %s"
msgstr "Error: «--fields» valor «%s» no es válido aquí; campos permitidos: %s"
#: ../cli/src/network-manager.c:209
#: ../cli/src/network-manager.c:245
#| msgid "WiFi enabled"
msgid "Networking enabled"
msgstr "Red activada"
#: ../cli/src/network-manager.c:256
#, c-format
#| msgid "Error: invalid 'wwan' parameter: '%s'."
msgid "Error: invalid 'enable' parameter: '%s'; use 'true' or 'false'."
msgstr "Error: parámetro «enable» inválido: «%s»; use «true» o «false»."
#: ../cli/src/network-manager.c:265
#, c-format
#| msgid "Error: Could not connect to NetworkManager."
msgid "Error: Sleeping status is not exported by NetworkManager."
msgstr "Error: NetworkManager no exporta el estado para dormir."
#: ../cli/src/network-manager.c:273
#, c-format
#| msgid "Error: invalid 'wifi' parameter: '%s'."
msgid "Error: invalid 'sleep' parameter: '%s'; use 'true' or 'false'."
msgstr "Error: parámetro «wifi» inválido: «%s»."
#: ../cli/src/network-manager.c:294
msgid "WiFi enabled"
msgstr "WiFi habilitado"
msgstr "WiFi activado"
#: ../cli/src/network-manager.c:220
#: ../cli/src/network-manager.c:305
#, c-format
msgid "Error: invalid 'wifi' parameter: '%s'."
msgstr "Error: parámetro 'wifi' inválido: '%s'."
msgstr "Error: parámetro «wifi» inválido: «%s»."
#: ../cli/src/network-manager.c:241
#: ../cli/src/network-manager.c:326
msgid "WWAN enabled"
msgstr "WWAN habilitado"
msgstr "WWAN activado"
#: ../cli/src/network-manager.c:252
#: ../cli/src/network-manager.c:337
#, c-format
msgid "Error: invalid 'wwan' parameter: '%s'."
msgstr "Error: parámetro 'wwan' inválido: '%s'."
msgstr "Error: parámetro «wwan» inválido: «%s»."
#: ../cli/src/network-manager.c:263
#: ../cli/src/network-manager.c:348
#, c-format
msgid "Error: 'nm' command '%s' is not valid."
msgstr "Error: comando 'nm' command '%s' inválido."
msgstr "Error: comando «nm» command «%s» inválido."
#: ../cli/src/nmcli.c:69
#, c-format
@ -1020,42 +1079,42 @@ msgstr ""
#: ../cli/src/nmcli.c:113
#, c-format
msgid "Error: Object '%s' is unknown, try 'nmcli help'."
msgstr "Error: Objeto '%s' desconocido, intente 'nmcli help'."
msgstr "Error: el objeto «%s» desconocido, intente «nmcli help»."
#: ../cli/src/nmcli.c:143
#, c-format
msgid "Error: Option '--terse' is specified the second time."
msgstr "Error: Opción '--terse' se especifica la segunda vez."
msgstr "Error: la opción «--terse» se especifica la segunda vez."
#: ../cli/src/nmcli.c:148
#, c-format
msgid "Error: Option '--terse' is mutually exclusive with '--pretty'."
msgstr "Error: Opción '--terse' es mutuamente exclusiva con '--pretty'."
msgstr "Error: la opción «--terse» es mutuamente exclusiva con «--pretty»."
#: ../cli/src/nmcli.c:156
#, c-format
msgid "Error: Option '--pretty' is specified the second time."
msgstr "Error: Opción '--pretty' se especifica la segunda vez."
msgstr "Error: la opción «--pretty» se especifica la segunda vez."
#: ../cli/src/nmcli.c:161
#, c-format
msgid "Error: Option '--pretty' is mutually exclusive with '--terse'."
msgstr "Error: Opción '--pretty' es mutuamente exclusiva con '--terse'."
msgstr "Error: la opción «--pretty» es mutuamente exclusiva con «--terse»."
#: ../cli/src/nmcli.c:171 ../cli/src/nmcli.c:187
#, c-format
msgid "Error: missing argument for '%s' option."
msgstr "Error: falta argumento para opción '%s'."
msgstr "Error: falta argumento para opción «%s»."
#: ../cli/src/nmcli.c:180 ../cli/src/nmcli.c:196
#, c-format
msgid "Error: '%s' is not valid argument for '%s' option."
msgstr "Error: '%s' no es válido argumento para opción '%s'."
msgstr "Error: «%s» no es válido argumento para opción «%s»."
#: ../cli/src/nmcli.c:203
#, c-format
msgid "Error: fields for '%s' options are missing."
msgstr "Error: faltan campos para opciones '%s'."
msgstr "Error: faltan campos para opciones «%s»."
#: ../cli/src/nmcli.c:209
#, c-format
@ -1065,7 +1124,7 @@ msgstr "herramienta nmcli, versión %s\n"
#: ../cli/src/nmcli.c:215
#, c-format
msgid "Error: Option '%s' is unknown, try 'nmcli -help'."
msgstr "Error: Opción '%s' desconocida, intente 'nmcli -help'."
msgstr "Error: opción «%s» desconocida, intente «nmcli -help»."
#: ../cli/src/nmcli.c:234
#, c-format
@ -1075,7 +1134,7 @@ msgstr "Señal capturada %d, apagando..."
#: ../cli/src/nmcli.c:259
#, c-format
msgid "Error: Could not connect to NetworkManager."
msgstr "Error: No se pudo conectar al NetworkManager."
msgstr "Error: no se pudo conectar con NetworkManager."
#: ../cli/src/nmcli.c:275
msgid "Success"
@ -1160,22 +1219,22 @@ msgstr "no establecido"
#: ../cli/src/utils.c:124
#, c-format
msgid "field '%s' has to be alone"
msgstr "campo '%s' tiene que estar solo"
msgstr "el campo «%s» tiene que estar solo"
#: ../cli/src/utils.c:127
#, c-format
msgid "invalid field '%s'"
msgstr "campo inválido '%s'"
msgstr "campo inválido «%s»"
#: ../cli/src/utils.c:146
#, c-format
msgid "Option '--terse' requires specifying '--fields'"
msgstr "Opción '--terse' requiere especificar '--fields'"
msgstr "Opción «--terse» requiere especificar «--fields»"
#: ../cli/src/utils.c:150
#, c-format
msgid "Option '--terse' requires specific '--fields' option values , not '%s'"
msgstr "Opción '--terse' requiere valores de '--fields' específicos, no '%s'"
msgstr "Opción «--terse» requiere valores de «--fields» específicos, no «%s»"
#: ../libnm-util/crypto.c:120
#, c-format
@ -1635,7 +1694,7 @@ msgstr ""
#: ../src/nm-netlink-monitor.c:265
#, c-format
msgid "unable to enable netlink handle credential passing: %s"
msgstr "no se puede habilitar el manejador netlink para pasar credenciales: %s"
msgstr "no se puede activar el manejador netlink para pasar credenciales: %s"
#: ../src/nm-netlink-monitor.c:291 ../src/nm-netlink-monitor.c:353
#, c-format
@ -1661,22 +1720,22 @@ msgstr "no pudo unirse al grupo netlink: %s"
msgid "error updating link cache: %s"
msgstr "error al actualizar el enlace caché: %s"
#: ../src/main.c:502
#: ../src/main.c:499
#, c-format
msgid "Invalid option. Please use --help to see a list of valid options.\n"
msgstr ""
"Opción no válida. Use --help para ver una lista de las opciones válidas.\n"
#: ../src/main.c:573
#: ../src/main.c:570
#, c-format
msgid "%s. Please use --help to see a list of valid options.\n"
msgstr "%s. Por favor use --help para ver la lista de opciones válidas.\n"
msgstr "%s. Usar --help para ver la lista de opciones válidas.\n"
#: ../src/dhcp-manager/nm-dhcp-dhclient.c:324
#: ../src/dhcp-manager/nm-dhcp-dhclient.c:328
msgid "# Created by NetworkManager\n"
msgstr "# Creado por NetworkManager\n"
#: ../src/dhcp-manager/nm-dhcp-dhclient.c:340
#: ../src/dhcp-manager/nm-dhcp-dhclient.c:344
#, c-format
msgid ""
"# Merged from %s\n"
@ -1691,31 +1750,31 @@ msgstr "cliente DHCP inútil pudo ser hallado."
#: ../src/dhcp-manager/nm-dhcp-manager.c:293
msgid "'dhclient' could be found."
msgstr "'dhclient' pudo ser hallado."
msgstr "se pudo encontrar «dhclient»."
#: ../src/dhcp-manager/nm-dhcp-manager.c:303
msgid "'dhcpcd' could be found."
msgstr "'dhcpcd' pudo ser hallado."
msgstr "se pudo encontrar «dhcpcd»."
#: ../src/dhcp-manager/nm-dhcp-manager.c:311
#, c-format
msgid "unsupported DHCP client '%s'"
msgstr "'%s' Cliente DHCP sin soporte "
msgstr "«%s» cliente DHCP sin soporte "
#: ../src/logging/nm-logging.c:146
#, c-format
msgid "Unknown log level '%s'"
msgstr "Nivel de registro desconocido '%s'"
msgstr "Nivel de registro desconocido «%s»"
#: ../src/logging/nm-logging.c:171
#, c-format
msgid "Unknown log domain '%s'"
msgstr "Dominio de registro desconocido '%s'"
msgstr "Dominio de registro desconocido «%s»"
#: ../src/dns-manager/nm-dns-manager.c:384
msgid "NOTE: the libc resolver may not support more than 3 nameservers."
msgstr ""
"NOTA: el 'resolver' de nombres de libc puede que no soporte más de 3 "
"NOTA: el resolutor de nombres de libc puede que no soporte más de 3 "
"servidores de nombres."
#: ../src/dns-manager/nm-dns-manager.c:386
@ -1725,8 +1784,9 @@ msgstr "Puede que los servidores de nombres listados abajo no se reconozcan."
#: ../src/system-settings/nm-default-wired-connection.c:157
#, c-format
msgid "Auto %s"
msgstr "Auto %ss"
msgstr "Auto %s"
#: ../system-settings/plugins/ifcfg-rh/reader.c:3412
#: ../system-settings/plugins/ifnet/connection_parser.c:49
msgid "System"
msgstr "Sistema"

538
po/pa.po

File diff suppressed because it is too large Load diff

2171
po/sl.po

File diff suppressed because it is too large Load diff

View file

@ -390,7 +390,7 @@ merge_dhclient_config (const char *iface,
}
/* If the client ID is just hex digits and : then don't use quotes,
* becuase dhclient expects either a quoted ASCII string, or a byte
* because dhclient expects either a quoted ASCII string, or a byte
* array formated as hex octets separated by :
*/
if (is_octets)

View file

@ -6,13 +6,20 @@ INCLUDES = \
noinst_LTLIBRARIES = libdns-manager.la
libdns_manager_la_SOURCES = nm-dns-manager.h nm-dns-manager.c
libdns_manager_la_SOURCES = \
nm-dns-manager.h \
nm-dns-manager.c \
nm-dns-plugin.h \
nm-dns-plugin.c \
nm-dns-dnsmasq.h \
nm-dns-dnsmasq.c \
nm-dns-bind.h \
nm-dns-bind.c
libdns_manager_la_CPPFLAGS = \
$(DBUS_CFLAGS) \
$(GLIB_CFLAGS) \
-DNM_PKGDATADIR=\"$(pkgdatadir)\" \
-DNM_LOCALSTATEDIR=\"$(localstatedir)\"
-DLOCALSTATEDIR=\"$(localstatedir)\"
libdns_manager_la_LIBADD = \
$(top_builddir)/src/logging/libnm-logging.la \

View file

@ -0,0 +1,527 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* Copyright (C) 2010 Dan Williams <dcbw@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, 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.
*
*/
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <glib.h>
#include <glib/gi18n.h>
#include "nm-dns-bind.h"
#include "nm-logging.h"
#include "nm-ip4-config.h"
#include "nm-ip6-config.h"
G_DEFINE_TYPE (NMDnsBind, nm_dns_bind, NM_TYPE_DNS_PLUGIN)
#define NM_DNS_BIND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DNS_BIND, NMDnsBindPrivate))
#define PIDFILE LOCALSTATEDIR "/run/nm-dns-named.pid"
#define CONFFILE LOCALSTATEDIR "/run/nm-dns-named.conf"
typedef struct {
GPid pid;
} NMDnsBindPrivate;
/*******************************************/
static inline const char *
find_bind (void)
{
static const char *paths[] = {
"/usr/local/sbin/named",
"/usr/sbin/named",
"/sbin/named",
NULL
};
const char **binary = paths;
while (*binary != NULL) {
if (g_file_test (*binary, G_FILE_TEST_EXISTS))
return *binary;
binary++;
}
return NULL;
}
static gboolean
start_bind (NMDnsBind *self)
{
const char *argv[10];
argv[0] = find_bind ();
argv[1] = "-f"; /* don't daemonize; stay in foreground */
argv[2] = "-c";
argv[3] = CONFFILE;
argv[4] = NULL;
/* And finally spawn bind */
return nm_dns_plugin_child_spawn (NM_DNS_PLUGIN (self), argv, PIDFILE, "bin/named");
}
/*******************************************/
static gboolean
find_address (GPtrArray *array, const char *addr)
{
int n;
for (n = 0; n < array->len; n++) {
if (g_strcmp0 ((const char*) g_ptr_array_index (array, n), addr) == 0)
return TRUE;
}
return FALSE;
}
static void
add_ip4_nameservers (NMIP4Config *ip4, GPtrArray *array)
{
int i;
for (i = 0; i < nm_ip4_config_get_num_nameservers (ip4); i++) {
char buf[INET_ADDRSTRLEN + 1];
struct in_addr addr;
memset (&buf[0], 0, sizeof (buf));
addr.s_addr = nm_ip4_config_get_nameserver (ip4, i);
if (inet_ntop (AF_INET, &addr, buf, sizeof (buf))) {
if (!find_address (array, buf))
g_ptr_array_add (array, g_strdup (buf));
}
}
}
static gboolean
ip6_addr_to_string (const struct in6_addr *addr, char *buf, size_t buflen)
{
/* 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);
return !!inet_ntop (AF_INET6, addr, buf, buflen);
}
static void
add_ip6_nameservers (NMIP6Config *ip6, GPtrArray *array)
{
char buf[INET6_ADDRSTRLEN + 1];
int i;
for (i = 0; i < nm_ip6_config_get_num_nameservers (ip6); i++) {
memset (buf, 0, sizeof (buf));
if (ip6_addr_to_string (nm_ip6_config_get_nameserver (ip6, i), buf, sizeof (buf))) {
if (!find_address (array, buf))
g_ptr_array_add (array, g_strdup (buf));
}
}
}
typedef struct {
guint32 dhash;
char *domain;
GPtrArray *servers;
} ZoneInfo;
static ZoneInfo *
zone_new (const char *domain)
{
ZoneInfo *info;
g_return_val_if_fail (domain != NULL, NULL);
info = g_malloc0 (sizeof (ZoneInfo));
info->domain = g_strdup (domain);
info->dhash = g_str_hash (domain);
info->servers = g_ptr_array_sized_new (4);
return info;
}
static void
zone_add_nameserver (ZoneInfo *info, const char *server)
{
guint32 i;
g_return_if_fail (info != NULL);
g_return_if_fail (server != NULL);
for (i = 0; i < info->servers->len; i++) {
if (g_strcmp0 ((char *) g_ptr_array_index (info->servers, i), server) == 0)
return;
}
g_ptr_array_add (info->servers, g_strdup (server));
}
static void
zone_free (ZoneInfo *info)
{
g_return_if_fail (info != NULL);
g_free (info->domain);
g_ptr_array_foreach (info->servers, (GFunc) g_free, NULL);
g_ptr_array_free (info->servers, TRUE);
memset (info, 0, sizeof (ZoneInfo));
g_free (info);
}
static ZoneInfo *
find_zone (GPtrArray *zones, const char *domain)
{
guint32 dhash, i;
g_return_val_if_fail (domain != NULL, FALSE);
dhash = g_str_hash (domain);
for (i = 0; i < zones->len; i++) {
ZoneInfo *zone = g_ptr_array_index (zones, i);
if (zone->dhash == dhash)
return zone;
}
return NULL;
}
static void
add_zone (GObject *ip, GPtrArray *zones)
{
guint32 i, j, ns, nd, nn;
GPtrArray *to_add;
ZoneInfo *z;
if (NM_IS_IP4_CONFIG (ip)) {
ns = nm_ip4_config_get_num_searches (NM_IP4_CONFIG (ip));
nd = nm_ip4_config_get_num_domains (NM_IP4_CONFIG (ip));
nn = nm_ip4_config_get_num_nameservers (NM_IP4_CONFIG (ip));
} else if (NM_IS_IP6_CONFIG (ip)) {
ns = nm_ip6_config_get_num_searches (NM_IP6_CONFIG (ip));
nd = nm_ip6_config_get_num_domains (NM_IP6_CONFIG (ip));
nn = nm_ip6_config_get_num_nameservers (NM_IP6_CONFIG (ip));
} else
g_assert_not_reached ();
/* If we don't have any domains or searches, or we don't have any
* nameservers, we can't do split DNS for this config.
*/
if ((!nd && !ns) || !nn)
return;
to_add = g_ptr_array_sized_new (MAX (ns, nd));
/* searches are preferred over domains */
for (i = 0; i < ns; i++) {
const char *domain = NULL;
if (NM_IS_IP4_CONFIG (ip))
domain = nm_ip4_config_get_search (NM_IP4_CONFIG (ip), i);
else if (NM_IS_IP6_CONFIG (ip))
domain = nm_ip6_config_get_search (NM_IP6_CONFIG (ip), i);
z = find_zone (zones, domain);
if (!z) {
z = zone_new (domain);
g_ptr_array_add (zones, z);
}
g_ptr_array_add (to_add, z);
}
if (ns == 0) {
/* If no searches, add any domains */
for (i = 0; i < nd; i++) {
const char *domain = NULL;
if (NM_IS_IP4_CONFIG (ip))
domain = nm_ip4_config_get_domain (NM_IP4_CONFIG (ip), i);
else if (NM_IS_IP6_CONFIG (ip))
domain = nm_ip6_config_get_domain (NM_IP6_CONFIG (ip), i);
z = find_zone (zones, domain);
if (!z) {
z = zone_new (domain);
g_ptr_array_add (zones, z);
}
g_ptr_array_add (to_add, z);
}
}
/* Now add the nameservers to every zone for this config */
for (i = 0; i < nn; i++) {
char buf[INET6_ADDRSTRLEN + 1];
struct in_addr addr4;
const struct in6_addr *addr6;
memset (&buf[0], 0, sizeof (buf));
if (NM_IS_IP4_CONFIG (ip)) {
addr4.s_addr = nm_ip4_config_get_nameserver (NM_IP4_CONFIG (ip), i);
if (!inet_ntop (AF_INET, &addr4, buf, sizeof (buf)))
continue;
} else if (NM_IS_IP6_CONFIG (ip)) {
addr6 = nm_ip6_config_get_nameserver (NM_IP6_CONFIG (ip), i);
if (!ip6_addr_to_string (addr6, buf, sizeof (buf)))
continue;
}
/* Add this nameserver to every zone from this IP config */
for (j = 0; j < to_add->len; j++) {
z = g_ptr_array_index (to_add, j);
zone_add_nameserver (z, buf);
}
}
g_ptr_array_free (to_add, TRUE);
}
static gboolean
update (NMDnsPlugin *plugin,
const GSList *vpn_configs,
const GSList *dev_configs,
const GSList *other_configs,
const char *hostname)
{
NMDnsBind *self = NM_DNS_BIND (plugin);
NMDnsBindPrivate *priv = NM_DNS_BIND_GET_PRIVATE (self);
GString *conf;
GPtrArray *globals, *zones;
GSList *iter;
GError *error = NULL;
int ignored, i, j;
gboolean success = FALSE;
/* Build up the new bind config file */
conf = g_string_sized_new (200);
globals = g_ptr_array_sized_new (6);
/* If any of the VPN configs *don't* have domains or searches, then we
* dont' have any split DNS configuration for them, and we add them
* first in the global nameserver lists. Otherwise we add them later as
* split DNS zones.
*/
for (iter = (GSList *) vpn_configs; iter;iter = g_slist_next (iter)) {
if (NM_IS_IP4_CONFIG (iter->data)) {
NMIP4Config *ip4 = NM_IP4_CONFIG (iter->data);
if (!nm_ip4_config_get_num_domains (ip4) && !nm_ip4_config_get_num_searches (ip4))
add_ip4_nameservers (ip4, globals);
} else if (NM_IS_IP6_CONFIG (iter->data)) {
NMIP6Config *ip6 = NM_IP6_CONFIG (iter->data);
if (!nm_ip6_config_get_num_domains (ip6) && !nm_ip6_config_get_num_searches (ip6))
add_ip6_nameservers (ip6, globals);
}
}
/* Get a list of global upstream servers with dupe checking */
for (iter = (GSList *) dev_configs; iter;iter = g_slist_next (iter)) {
if (NM_IS_IP4_CONFIG (iter->data))
add_ip4_nameservers (NM_IP4_CONFIG (iter->data), globals);
else if (NM_IS_IP6_CONFIG (iter->data))
add_ip6_nameservers (NM_IP6_CONFIG (iter->data), globals);
}
/* And any other random configs with dupe checking */
for (iter = (GSList *) other_configs; iter;iter = g_slist_next (iter)) {
if (NM_IS_IP4_CONFIG (iter->data))
add_ip4_nameservers (NM_IP4_CONFIG (iter->data), globals);
else if (NM_IS_IP6_CONFIG (iter->data))
add_ip6_nameservers (NM_IP6_CONFIG (iter->data), globals);
}
g_string_append (conf,
"options {\n"
" directory \"" LOCALSTATEDIR "/named\";\n"
" forward only;\n"
" recursion yes;\n"
" listen-on-v6 { ::1; };\n"
" listen-on { 127.0.0.1; };\n"
" forwarders {\n");
for (i = 0; i < globals->len; i++) {
char *ns = g_ptr_array_index (globals, i);
g_string_append_printf (conf, " %s;\n", ns);
g_free (ns);
}
g_ptr_array_free (globals, TRUE);
g_string_append (conf,
" };\n"
"};\n\n");
/* Build up the list of any split DNS zones, avoiding duplicates */
zones = g_ptr_array_sized_new (4);
for (iter = (GSList *) vpn_configs; iter;iter = g_slist_next (iter)) {
if (NM_IS_IP4_CONFIG (iter->data))
add_zone (G_OBJECT (iter->data), zones);
else if (NM_IS_IP6_CONFIG (iter->data))
add_zone (G_OBJECT (iter->data), zones);
}
/* Add all the zones to the config */
for (i = 0; i < zones->len; i++) {
ZoneInfo *z = g_ptr_array_index (zones, i);
g_string_append_printf (conf,
"zone \"%s\" IN {\n"
" type forward;\n"
" forward only;\n"
" forwarders {\n",
z->domain);
/* Add each nameserver for this zone */
for (j = 0; j < z->servers->len; j++) {
g_string_append_printf (conf,
" %s;\n",
(const char *) g_ptr_array_index (z->servers, j));
}
g_string_append (conf,
" };\n"
"};\n\n");
zone_free (z);
}
g_ptr_array_free (zones, TRUE);
/* Write out the config file */
if (!g_file_set_contents (CONFFILE, conf->str, -1, &error)) {
nm_log_warn (LOGD_DNS, "Failed to write named config file %s: (%d) %s",
CONFFILE,
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
goto out;
}
ignored = chmod (CONFFILE, 0600);
nm_log_dbg (LOGD_DNS, "BIND local caching DNS configuration:");
nm_log_dbg (LOGD_DNS, "%s", conf->str);
if (priv->pid) {
/* Send it SIGHUP to reload the new configuration */
if (kill (priv->pid, SIGHUP) == 0)
success = TRUE;
else {
/* Sigh... some error. Kill it and restart */
nm_dns_plugin_child_kill (NM_DNS_PLUGIN (self));
priv->pid = 0;
}
}
if (!success) {
/* Spawn it */
priv->pid = start_bind (self);
if (priv->pid)
success = TRUE;
}
out:
g_string_free (conf, TRUE);
return success;
}
/****************************************************************/
static void
child_quit (NMDnsPlugin *plugin, gint status)
{
NMDnsBind *self = NM_DNS_BIND (plugin);
gboolean failed = TRUE;
int err;
if (WIFEXITED (status)) {
err = WEXITSTATUS (status);
if (err) {
nm_log_warn (LOGD_DNS, "named exited with error %d", err);
} else
failed = FALSE;
} else if (WIFSTOPPED (status)) {
nm_log_warn (LOGD_DNS, "named stopped unexpectedly with signal %d", WSTOPSIG (status));
} else if (WIFSIGNALED (status)) {
nm_log_warn (LOGD_DNS, "named died with signal %d", WTERMSIG (status));
} else {
nm_log_warn (LOGD_DNS, "named died from an unknown cause");
}
unlink (CONFFILE);
if (failed)
g_signal_emit_by_name (self, NM_DNS_PLUGIN_FAILED);
}
/****************************************************************/
static gboolean
init (NMDnsPlugin *plugin)
{
return TRUE;
}
static gboolean
is_caching (NMDnsPlugin *plugin)
{
return TRUE;
}
static const char *
get_name (NMDnsPlugin *plugin)
{
return "bind";
}
/****************************************************************/
NMDnsBind *
nm_dns_bind_new (void)
{
return (NMDnsBind *) g_object_new (NM_TYPE_DNS_BIND, NULL);
}
static void
nm_dns_bind_init (NMDnsBind *self)
{
}
static void
dispose (GObject *object)
{
unlink (CONFFILE);
G_OBJECT_CLASS (nm_dns_bind_parent_class)->dispose (object);
}
static void
nm_dns_bind_class_init (NMDnsBindClass *dns_class)
{
NMDnsPluginClass *plugin_class = NM_DNS_PLUGIN_CLASS (dns_class);
GObjectClass *object_class = G_OBJECT_CLASS (dns_class);
g_type_class_add_private (dns_class, sizeof (NMDnsBindPrivate));
object_class->dispose = dispose;
plugin_class->init = init;
plugin_class->child_quit = child_quit;
plugin_class->is_caching = is_caching;
plugin_class->update = update;
plugin_class->get_name = get_name;
}

View file

@ -0,0 +1,47 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; 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, 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) 2010 Red Hat, Inc.
*/
#ifndef NM_DNS_BIND_H
#define NM_DNS_BIND_H
#include <glib.h>
#include <glib-object.h>
#include "nm-dns-plugin.h"
#define NM_TYPE_DNS_BIND (nm_dns_bind_get_type ())
#define NM_DNS_BIND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DNS_BIND, NMDnsBind))
#define NM_DNS_BIND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DNS_BIND, NMDnsBindClass))
#define NM_IS_DNS_BIND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DNS_BIND))
#define NM_IS_DNS_BIND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_DNS_BIND))
#define NM_DNS_BIND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DNS_BIND, NMDnsBindClass))
typedef struct {
NMDnsPlugin parent;
} NMDnsBind;
typedef struct {
NMDnsPluginClass parent;
} NMDnsBindClass;
GType nm_dns_bind_get_type (void);
NMDnsBind *nm_dns_bind_new (void);
#endif /* NM_DNS_BIND_H */

View file

@ -0,0 +1,370 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* Copyright (C) 2010 Dan Williams <dcbw@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, 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.
*
*/
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <glib.h>
#include <glib/gi18n.h>
#include "nm-dns-dnsmasq.h"
#include "nm-logging.h"
#include "nm-ip4-config.h"
#include "nm-ip6-config.h"
G_DEFINE_TYPE (NMDnsDnsmasq, nm_dns_dnsmasq, NM_TYPE_DNS_PLUGIN)
#define NM_DNS_DNSMASQ_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DNS_DNSMASQ, NMDnsDnsmasqPrivate))
#define PIDFILE LOCALSTATEDIR "/run/nm-dns-dnsmasq.pid"
#define CONFFILE LOCALSTATEDIR "/run/nm-dns-dnsmasq.conf"
typedef struct {
guint32 foo;
} NMDnsDnsmasqPrivate;
/*******************************************/
static inline const char *
find_dnsmasq (void)
{
static const char *paths[] = {
"/usr/local/sbin/dnsmasq",
"/usr/sbin/dnsmasq",
"/sbin/dnsmasq",
NULL
};
const char **binary = paths;
while (*binary != NULL) {
if (g_file_test (*binary, G_FILE_TEST_EXISTS))
return *binary;
binary++;
}
return NULL;
}
static gboolean
add_ip4_config (GString *str, NMIP4Config *ip4, gboolean split)
{
char buf[INET_ADDRSTRLEN + 1];
struct in_addr addr;
int n, i;
gboolean added = FALSE;
if (split) {
/* FIXME: it appears that dnsmasq can only handle one nameserver
* per domain (at the manpage seems to indicate that) so only use
* the first nameserver here.
*/
addr.s_addr = nm_ip4_config_get_nameserver (ip4, 0);
memset (&buf[0], 0, sizeof (buf));
if (!inet_ntop (AF_INET, &addr, buf, sizeof (buf)))
return FALSE;
/* searches are preferred over domains */
n = nm_ip4_config_get_num_searches (ip4);
for (i = 0; i < n; i++) {
g_string_append_printf (str, "server=/%s/%s\n",
nm_ip4_config_get_search (ip4, i),
buf);
added = TRUE;
}
if (n == 0) {
/* If not searches, use any domains */
n = nm_ip4_config_get_num_domains (ip4);
for (i = 0; i < n; i++) {
g_string_append_printf (str, "server=/%s/%s\n",
nm_ip4_config_get_domain (ip4, i),
buf);
added = TRUE;
}
}
}
/* If no searches or domains, just add the namservers */
if (!added) {
n = nm_ip4_config_get_num_nameservers (ip4);
for (i = 0; i < n; i++) {
memset (&buf[0], 0, sizeof (buf));
addr.s_addr = nm_ip4_config_get_nameserver (ip4, i);
if (inet_ntop (AF_INET, &addr, buf, sizeof (buf)))
g_string_append_printf (str, "server=%s\n", buf);
}
}
return TRUE;
}
static gboolean
ip6_addr_to_string (const struct in6_addr *addr, char *buf, size_t buflen)
{
memset (buf, 0, buflen);
/* 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);
return !!inet_ntop (AF_INET6, addr, buf, buflen);
}
static gboolean
add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split)
{
char buf[INET6_ADDRSTRLEN + 1];
const struct in6_addr *addr;
int n, i;
gboolean added = FALSE;
if (split) {
/* FIXME: it appears that dnsmasq can only handle one nameserver
* per domain (at the manpage seems to indicate that) so only use
* the first nameserver here.
*/
addr = nm_ip6_config_get_nameserver (ip6, 0);
if (!ip6_addr_to_string (addr, &buf[0], sizeof (buf)))
return FALSE;
/* searches are preferred over domains */
n = nm_ip6_config_get_num_searches (ip6);
for (i = 0; i < n; i++) {
g_string_append_printf (str, "server=/%s/%s\n",
nm_ip6_config_get_search (ip6, i),
buf);
added = TRUE;
}
if (n == 0) {
/* If not searches, use any domains */
n = nm_ip6_config_get_num_domains (ip6);
for (i = 0; i < n; i++) {
g_string_append_printf (str, "server=/%s/%s\n",
nm_ip6_config_get_domain (ip6, i),
buf);
added = TRUE;
}
}
}
/* If no searches or domains, just add the namservers */
if (!added) {
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)))
g_string_append_printf (str, "server=%s\n", buf);
}
}
return TRUE;
}
static gboolean
update (NMDnsPlugin *plugin,
const GSList *vpn_configs,
const GSList *dev_configs,
const GSList *other_configs,
const char *hostname)
{
NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin);
GString *conf;
GSList *iter;
const char *argv[10];
GError *error = NULL;
int ignored;
GPid pid = 0;
/* Kill the old dnsmasq; there doesn't appear to be a way to get dnsmasq
* to reread the config file using SIGHUP or similar. This is a small race
* here when restarting dnsmasq when DNS requests could go to the upstream
* servers instead of to dnsmasq.
*/
nm_dns_plugin_child_kill (plugin);
/* Build up the new dnsmasq config file */
conf = g_string_sized_new (150);
/* Use split DNS for VPN configs */
for (iter = (GSList *) vpn_configs; iter; iter = g_slist_next (iter)) {
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);
}
/* Now add interface configs without split DNS */
for (iter = (GSList *) dev_configs; iter;iter = g_slist_next (iter)) {
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);
}
/* And any other random configs */
for (iter = (GSList *) other_configs; iter;iter = g_slist_next (iter)) {
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);
}
/* Write out the config file */
if (!g_file_set_contents (CONFFILE, conf->str, -1, &error)) {
nm_log_warn (LOGD_DNS, "Failed to write dnsmasq config file %s: (%d) %s",
CONFFILE,
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
goto out;
}
ignored = chmod (CONFFILE, 0600);
nm_log_dbg (LOGD_DNS, "dnsmasq local caching DNS configuration:");
nm_log_dbg (LOGD_DNS, "%s", conf->str);
argv[0] = find_dnsmasq ();
argv[1] = "--no-resolv"; /* Use only commandline */
argv[2] = "--keep-in-foreground";
argv[3] = "--strict-order";
argv[4] = "--bind-interfaces";
argv[5] = "--pid-file=" PIDFILE;
argv[6] = "--listen-address=127.0.0.1"; /* Should work for both 4 and 6 */
argv[7] = "--conf-file=" CONFFILE;
argv[8] = NULL;
/* And finally spawn dnsmasq */
pid = nm_dns_plugin_child_spawn (NM_DNS_PLUGIN (self), argv, PIDFILE, "bin/dnsmasq");
out:
g_string_free (conf, TRUE);
return pid ? TRUE : FALSE;
}
/****************************************************************/
static const char *
dm_exit_code_to_msg (int status)
{
if (status == 1)
return "Configuration problem";
else if (status == 2)
return "Network access problem (address in use; permissions; etc)";
else if (status == 3)
return "Filesystem problem (missing file/directory; permissions; etc)";
else if (status == 4)
return "Memory allocation failure";
else if (status == 5)
return "Other problem";
else if (status >= 11)
return "Lease-script 'init' process failure";
return "Unknown error";
}
static void
child_quit (NMDnsPlugin *plugin, gint status)
{
NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin);
gboolean failed = TRUE;
int err;
if (WIFEXITED (status)) {
err = WEXITSTATUS (status);
if (err) {
nm_log_warn (LOGD_DNS, "dnsmasq exited with error: %s (%d)",
dm_exit_code_to_msg (err),
err);
} else
failed = FALSE;
} else if (WIFSTOPPED (status)) {
nm_log_warn (LOGD_DNS, "dnsmasq stopped unexpectedly with signal %d", WSTOPSIG (status));
} else if (WIFSIGNALED (status)) {
nm_log_warn (LOGD_DNS, "dnsmasq died with signal %d", WTERMSIG (status));
} else {
nm_log_warn (LOGD_DNS, "dnsmasq died from an unknown cause");
}
unlink (CONFFILE);
if (failed)
g_signal_emit_by_name (self, NM_DNS_PLUGIN_FAILED);
}
/****************************************************************/
static gboolean
init (NMDnsPlugin *plugin)
{
return TRUE;
}
static gboolean
is_caching (NMDnsPlugin *plugin)
{
return TRUE;
}
static const char *
get_name (NMDnsPlugin *plugin)
{
return "dnsmasq";
}
/****************************************************************/
NMDnsDnsmasq *
nm_dns_dnsmasq_new (void)
{
return (NMDnsDnsmasq *) g_object_new (NM_TYPE_DNS_DNSMASQ, NULL);
}
static void
nm_dns_dnsmasq_init (NMDnsDnsmasq *self)
{
}
static void
dispose (GObject *object)
{
unlink (CONFFILE);
G_OBJECT_CLASS (nm_dns_dnsmasq_parent_class)->dispose (object);
}
static void
nm_dns_dnsmasq_class_init (NMDnsDnsmasqClass *dns_class)
{
NMDnsPluginClass *plugin_class = NM_DNS_PLUGIN_CLASS (dns_class);
GObjectClass *object_class = G_OBJECT_CLASS (dns_class);
g_type_class_add_private (dns_class, sizeof (NMDnsDnsmasqPrivate));
object_class->dispose = dispose;
plugin_class->init = init;
plugin_class->child_quit = child_quit;
plugin_class->is_caching = is_caching;
plugin_class->update = update;
plugin_class->get_name = get_name;
}

View file

@ -0,0 +1,47 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; 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, 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) 2010 Red Hat, Inc.
*/
#ifndef NM_DNS_DNSMASQ_H
#define NM_DNS_DNSMASQ_H
#include <glib.h>
#include <glib-object.h>
#include "nm-dns-plugin.h"
#define NM_TYPE_DNS_DNSMASQ (nm_dns_dnsmasq_get_type ())
#define NM_DNS_DNSMASQ(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DNS_DNSMASQ, NMDnsDnsmasq))
#define NM_DNS_DNSMASQ_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DNS_DNSMASQ, NMDnsDnsmasqClass))
#define NM_IS_DNS_DNSMASQ(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DNS_DNSMASQ))
#define NM_IS_DNS_DNSMASQ_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_DNS_DNSMASQ))
#define NM_DNS_DNSMASQ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DNS_DNSMASQ, NMDnsDnsmasqClass))
typedef struct {
NMDnsPlugin parent;
} NMDnsDnsmasq;
typedef struct {
NMDnsPluginClass parent;
} NMDnsDnsmasqClass;
GType nm_dns_dnsmasq_get_type (void);
NMDnsDnsmasq *nm_dns_dnsmasq_new (void);
#endif /* NM_DNS_DNSMASQ_H */

View file

@ -43,6 +43,10 @@
#include "nm-system.h"
#include "NetworkManagerUtils.h"
#include "nm-dns-plugin.h"
#include "nm-dns-dnsmasq.h"
#include "nm-dns-bind.h"
#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#endif
@ -51,15 +55,12 @@
#define RESOLV_CONF "/etc/resolv.conf"
#endif
#define ADDR_BUF_LEN 50
G_DEFINE_TYPE(NMDnsManager, nm_dns_manager, G_TYPE_OBJECT)
#define NM_DNS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
NM_TYPE_DNS_MANAGER, \
NMDnsManagerPrivate))
struct NMDnsManagerPrivate {
NMIP4Config *ip4_vpn_config;
NMIP4Config *ip4_device_config;
@ -68,6 +69,16 @@ struct NMDnsManagerPrivate {
GSList *configs;
char *hostname;
/* poor man's hash; we assume that the IP4 config object won't change
* after it's given to us, which is (at this time) a fair assumption. So
* we track the order of the currently applied IP configs and if they
* haven't changed we don't need to rewrite resolv.conf.
*/
#define HLEN 6
gpointer hash[HLEN];
GSList *plugins;
/* This is a hack because SUSE's netconfig always wants changes
* associated with a network interface, but sometimes a change isn't
* associated with a network interface (like hostnames).
@ -76,31 +87,6 @@ struct NMDnsManagerPrivate {
};
NMDnsManager *
nm_dns_manager_get (void)
{
static NMDnsManager * singleton = NULL;
if (!singleton)
singleton = NM_DNS_MANAGER (g_object_new (NM_TYPE_DNS_MANAGER, NULL));
else
g_object_ref (singleton);
g_assert (singleton);
return singleton;
}
GQuark
nm_dns_manager_error_quark (void)
{
static GQuark quark = 0;
if (!quark)
quark = g_quark_from_static_string ("nm_dns_manager_error");
return quark;
}
typedef struct {
GPtrArray *nameservers;
const char *domain;
@ -270,7 +256,7 @@ dispatch_netconfig (const char *domain,
const char *iface,
GError **error)
{
char *str;
char *str, *tmp;
GPid pid;
gint fd;
int ret;
@ -294,8 +280,6 @@ dispatch_netconfig (const char *domain,
str = g_strjoinv (" ", searches);
if (domain) {
char *tmp;
tmp = g_strconcat (domain, " ", str, NULL);
g_free (str);
str = tmp;
@ -350,6 +334,7 @@ write_resolv_conf (FILE *f, const char *domain,
char *nameservers_str = NULL;
int i;
gboolean retval = FALSE;
GString *str;
if (fprintf (f, "%s","# Generated by NetworkManager\n") < 0) {
g_set_error (error,
@ -371,12 +356,10 @@ write_resolv_conf (FILE *f, const char *domain,
g_free (tmp_str);
}
if (nameservers) {
GString *str;
int num;
str = g_string_new ("");
str = g_string_new ("");
num = g_strv_length (nameservers);
if (nameservers) {
int num = g_strv_length (nameservers);
for (i = 0; i < num; i++) {
if (i == 3) {
@ -391,14 +374,14 @@ write_resolv_conf (FILE *f, const char *domain,
g_string_append (str, nameservers[i]);
g_string_append_c (str, '\n');
}
nameservers_str = g_string_free (str, FALSE);
}
nameservers_str = g_string_free (str, FALSE);
if (fprintf (f, "%s%s%s",
domain_str ? domain_str : "",
searches_str ? searches_str : "",
nameservers_str ? nameservers_str : "") != -1)
strlen (nameservers_str) ? nameservers_str : "") != -1)
retval = TRUE;
g_free (domain_str);
@ -536,30 +519,67 @@ out:
return *error ? FALSE : TRUE;
}
static void
compute_hash (NMDnsManager *self, gpointer *hash)
{
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
gpointer check[HLEN];
GSList *iter;
int i = 0;
memset (check, 0, sizeof (check));
if (priv->ip4_vpn_config)
check[i++] = priv->ip4_vpn_config;
if (priv->ip4_device_config)
check[i++] = priv->ip4_device_config;
if (priv->ip6_vpn_config)
check[i++] = priv->ip6_vpn_config;
if (priv->ip6_device_config)
check[i++] = priv->ip6_device_config;
/* Add two more "other" configs if any exist */
for (iter = priv->configs; iter && i < HLEN; iter = g_slist_next (iter)) {
if ( (iter->data != priv->ip4_vpn_config)
&& (iter->data != priv->ip4_device_config)
&& (iter->data != priv->ip6_vpn_config)
&& (iter->data != priv->ip6_device_config))
check[i++] = iter->data;
}
memcpy (hash, check, sizeof (check));
}
static gboolean
rewrite_resolv_conf (NMDnsManager *mgr, const char *iface, GError **error)
update_dns (NMDnsManager *self,
const char *iface,
gboolean no_caching,
GError **error)
{
NMDnsManagerPrivate *priv;
NMResolvConfData rc;
GSList *iter;
GSList *iter, *vpn_configs = NULL, *dev_configs = NULL, *other_configs = NULL;
const char *domain = NULL;
const char *nis_domain = NULL;
char **searches = NULL;
char **nameservers = NULL;
char **nis_servers = NULL;
int num, i, len;
gboolean success = FALSE;
gboolean success = FALSE, caching = FALSE;
g_return_val_if_fail (error != NULL, FALSE);
g_return_val_if_fail (*error == NULL, FALSE);
priv = NM_DNS_MANAGER_GET_PRIVATE (mgr);
priv = NM_DNS_MANAGER_GET_PRIVATE (self);
if (iface) {
g_free (priv->last_iface);
priv->last_iface = g_strdup (iface);
}
/* Update hash with config we're applying */
compute_hash (self, priv->hash);
rc.nameservers = g_ptr_array_new ();
rc.domain = NULL;
rc.searches = g_ptr_array_new ();
@ -640,6 +660,71 @@ rewrite_resolv_conf (NMDnsManager *mgr, const char *iface, GError **error)
nis_domain = rc.nis_domain;
/* Build up config lists for plugins; we use the raw configs here, not the
* merged information that we write to resolv.conf so that the plugins can
* still use the domain information in each config to provide split DNS if
* they want to.
*/
if (priv->ip4_vpn_config)
vpn_configs = g_slist_append (vpn_configs, priv->ip4_vpn_config);
if (priv->ip6_vpn_config)
vpn_configs = g_slist_append (vpn_configs, priv->ip6_vpn_config);
if (priv->ip4_device_config)
dev_configs = g_slist_append (dev_configs, priv->ip4_device_config);
if (priv->ip6_device_config)
dev_configs = g_slist_append (dev_configs, priv->ip6_device_config);
for (iter = priv->configs; iter; iter = g_slist_next (iter)) {
if ( (iter->data != priv->ip4_vpn_config)
&& (iter->data != priv->ip4_device_config)
&& (iter->data != priv->ip6_vpn_config)
&& (iter->data != priv->ip6_device_config))
other_configs = g_slist_append (other_configs, iter->data);
}
/* Let any plugins do their thing first */
for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
NMDnsPlugin *plugin = NM_DNS_PLUGIN (iter->data);
const char *plugin_name = nm_dns_plugin_get_name (plugin);
if (nm_dns_plugin_is_caching (plugin)) {
if (no_caching) {
nm_log_dbg (LOGD_DNS, "DNS: plugin %s ignored (caching disabled)",
plugin_name);
continue;
}
caching = TRUE;
}
nm_log_dbg (LOGD_DNS, "DNS: updating plugin %s", plugin_name);
if (!nm_dns_plugin_update (plugin,
vpn_configs,
dev_configs,
other_configs,
priv->hostname)) {
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
* caching DNS configuration to resolv.conf.
*/
caching = FALSE;
}
}
g_slist_free (vpn_configs);
g_slist_free (dev_configs);
g_slist_free (other_configs);
/* If caching was successful, we only send 127.0.0.1 to /etc/resolv.conf
* to ensure that the glibc resolver doesn't try to round-robin nameservers,
* but only uses the local caching nameserver.
*/
if (caching) {
if (nameservers)
g_strfreev (nameservers);
nameservers = g_new0 (char*, 2);
nameservers[0] = g_strdup ("127.0.0.1");
}
#ifdef RESOLVCONF_PATH
success = dispatch_resolvconf (domain, searches, nameservers, iface, error);
#endif
@ -668,6 +753,43 @@ rewrite_resolv_conf (NMDnsManager *mgr, const char *iface, GError **error)
return success;
}
static void
plugin_failed (NMDnsPlugin *plugin, gpointer user_data)
{
NMDnsManager *self = NM_DNS_MANAGER (user_data);
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
GError *error = NULL;
/* Errors with non-caching plugins aren't fatal */
if (!nm_dns_plugin_is_caching (plugin))
return;
/* Disable caching until the next DNS update */
if (!update_dns (self, priv->last_iface, TRUE, &error)) {
nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
}
}
static gboolean
config_changed (NMDnsManager *self)
{
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
gpointer check[HLEN];
/* We only store HLEN configs; so if there are actually more than that,
* we have to assume that the config has changed.
*/
if (g_slist_length (priv->configs) > HLEN)
return TRUE;
/* Otherwise return TRUE if the configuration has changed */
compute_hash (self, check);
return memcmp (check, priv->hash, sizeof (check)) ? TRUE : FALSE;
}
gboolean
nm_dns_manager_add_ip4_config (NMDnsManager *mgr,
const char *iface,
@ -698,9 +820,14 @@ nm_dns_manager_add_ip4_config (NMDnsManager *mgr,
if (!g_slist_find (priv->configs, config))
priv->configs = g_slist_append (priv->configs, g_object_ref (config));
if (!rewrite_resolv_conf (mgr, iface, &error)) {
nm_log_warn (LOGD_DNS, "could not commit DNS changes: '%s'", error ? error->message : "(none)");
g_error_free (error);
if (!config_changed (mgr))
return TRUE;
if (!update_dns (mgr, iface, FALSE, &error)) {
nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
}
return TRUE;
@ -733,10 +860,14 @@ nm_dns_manager_remove_ip4_config (NMDnsManager *mgr,
g_object_unref (config);
if (!rewrite_resolv_conf (mgr, iface, &error)) {
nm_log_warn (LOGD_DNS, "could not commit DNS changes: '%s'", error ? error->message : "(none)");
if (error)
g_error_free (error);
if (config_changed (mgr))
return TRUE;
if (!update_dns (mgr, iface, FALSE, &error)) {
nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
}
return TRUE;
@ -774,9 +905,14 @@ nm_dns_manager_add_ip6_config (NMDnsManager *mgr,
if (!g_slist_find (priv->configs, config))
priv->configs = g_slist_append (priv->configs, g_object_ref (config));
if (!rewrite_resolv_conf (mgr, iface, &error)) {
nm_log_warn (LOGD_DNS, "could not commit DNS changes: '%s'", error ? error->message : "(none)");
g_error_free (error);
if (config_changed (mgr))
return TRUE;
if (!update_dns (mgr, iface, FALSE, &error)) {
nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
}
return TRUE;
@ -809,10 +945,14 @@ nm_dns_manager_remove_ip6_config (NMDnsManager *mgr,
g_object_unref (config);
if (!rewrite_resolv_conf (mgr, iface, &error)) {
nm_log_warn (LOGD_DNS, "could not commit DNS changes: '%s'", error ? error->message : "(none)");
if (error)
g_error_free (error);
if (config_changed (mgr))
return TRUE;
if (!update_dns (mgr, iface, FALSE, &error)) {
nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
}
return TRUE;
@ -846,12 +986,86 @@ nm_dns_manager_set_hostname (NMDnsManager *mgr,
* wants one. But hostname changes are system-wide and *not* tied to a
* specific interface, so netconfig can't really handle this. Fake it.
*/
if (!rewrite_resolv_conf (mgr, priv->last_iface, &error)) {
nm_log_warn (LOGD_DNS, "could not commit DNS changes: '%s'", error ? error->message : "(none)");
if (!update_dns (mgr, priv->last_iface, FALSE, &error)) {
nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
}
}
static void
load_plugins (NMDnsManager *self, const char **plugins)
{
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
NMDnsPlugin *plugin;
const char **iter;
gboolean have_caching = FALSE;
if (plugins && *plugins) {
/* Create each configured plugin */
for (iter = plugins; iter && *iter; iter++) {
if (!strcasecmp (*iter, "dnsmasq"))
plugin = NM_DNS_PLUGIN (nm_dns_dnsmasq_new ());
else if (!strcasecmp (*iter, "bind")) {
plugin = NM_DNS_PLUGIN (nm_dns_bind_new ());
nm_log_warn (LOGD_DNS, "The BIND plugin is experimental!");
} else {
nm_log_warn (LOGD_DNS, "Unknown DNS plugin '%s'", *iter);\
continue;
}
g_assert (plugin);
/* Only one caching DNS plugin is allowed */
if (nm_dns_plugin_is_caching (plugin)) {
if (have_caching) {
nm_log_warn (LOGD_DNS,
"Ignoring plugin %s; only one caching DNS "
"plugin is allowed.",
*iter);
g_object_unref (plugin);
continue;
}
have_caching = TRUE;
}
nm_log_info (LOGD_DNS, "DNS: loaded plugin %s", nm_dns_plugin_get_name (plugin));
priv->plugins = g_slist_append (priv->plugins, plugin);
g_signal_connect (plugin, NM_DNS_PLUGIN_FAILED,
G_CALLBACK (plugin_failed),
self);
}
} else {
/* Create default plugins */
}
}
/******************************************************************/
NMDnsManager *
nm_dns_manager_get (const char **plugins)
{
static NMDnsManager * singleton = NULL;
if (!singleton) {
singleton = NM_DNS_MANAGER (g_object_new (NM_TYPE_DNS_MANAGER, NULL));
g_assert (singleton);
load_plugins (singleton, plugins);
} else
g_object_ref (singleton);
return singleton;
}
GQuark
nm_dns_manager_error_quark (void)
{
static GQuark quark = 0;
if (!quark)
quark = g_quark_from_static_string ("nm_dns_manager_error");
return quark;
}
static void
nm_dns_manager_init (NMDnsManager *mgr)
@ -868,6 +1082,9 @@ nm_dns_manager_finalize (GObject *object)
g_free (priv->hostname);
g_free (priv->last_iface);
g_slist_foreach (priv->plugins, (GFunc) g_object_unref, NULL);
g_slist_free (priv->plugins);
G_OBJECT_CLASS (nm_dns_manager_parent_class)->finalize (object);
}

View file

@ -67,7 +67,7 @@ typedef struct {
GType nm_dns_manager_get_type (void);
NMDnsManager * nm_dns_manager_get (void);
NMDnsManager * nm_dns_manager_get (const char **plugins);
gboolean nm_dns_manager_add_ip4_config (NMDnsManager *mgr,
const char *iface,

View file

@ -0,0 +1,318 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; 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, 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) 2010 Red Hat, Inc.
*
*/
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <glib.h>
#include "nm-dns-plugin.h"
#include "nm-logging.h"
typedef struct {
gboolean disposed;
GPid pid;
guint32 watch_id;
char *progname;
char *pidfile;
} NMDnsPluginPrivate;
#define NM_DNS_PLUGIN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DNS_PLUGIN, NMDnsPluginPrivate))
G_DEFINE_TYPE_EXTENDED (NMDnsPlugin, nm_dns_plugin, G_TYPE_OBJECT, G_TYPE_FLAG_ABSTRACT, {})
enum {
FAILED,
CHILD_QUIT,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
/********************************************/
gboolean
nm_dns_plugin_update (NMDnsPlugin *self,
const GSList *vpn_configs,
const GSList *dev_configs,
const GSList *other_configs,
const char *hostname)
{
g_return_val_if_fail (NM_DNS_PLUGIN_GET_CLASS (self)->update != NULL, FALSE);
return NM_DNS_PLUGIN_GET_CLASS (self)->update (self,
vpn_configs,
dev_configs,
other_configs,
hostname);
}
static gboolean
is_caching (NMDnsPlugin *self)
{
return FALSE;
}
gboolean
nm_dns_plugin_is_caching (NMDnsPlugin *self)
{
return NM_DNS_PLUGIN_GET_CLASS (self)->is_caching (self);
}
const char *
nm_dns_plugin_get_name (NMDnsPlugin *self)
{
g_assert (NM_DNS_PLUGIN_GET_CLASS (self)->get_name);
return NM_DNS_PLUGIN_GET_CLASS (self)->get_name (self);
}
/********************************************/
static void
kill_existing (const char *progname, const char *pidfile, const char *kill_match)
{
char *contents = NULL;
glong pid;
char *proc_path = NULL;
char *cmdline_contents = NULL;
if (!g_file_get_contents (pidfile, &contents, NULL, NULL))
return;
pid = strtol (contents, NULL, 10);
if (pid < 1 || pid > INT_MAX)
goto out;
proc_path = g_strdup_printf ("/proc/%ld/cmdline", pid);
if (!g_file_get_contents (proc_path, &cmdline_contents, NULL, NULL))
goto out;
if (strstr (cmdline_contents, kill_match)) {
if (kill (pid, 0)) {
nm_log_dbg (LOGD_DNS, "Killing stale %s child process %ld", progname, pid);
kill (pid, SIGKILL);
}
unlink (pidfile);
}
out:
g_free (cmdline_contents);
g_free (proc_path);
g_free (contents);
}
static void
watch_cb (GPid pid, gint status, gpointer user_data)
{
NMDnsPlugin *self = NM_DNS_PLUGIN (user_data);
NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self);
priv->pid = 0;
g_free (priv->progname);
priv->progname = NULL;
g_signal_emit (self, signals[CHILD_QUIT], 0, status);
}
static void
child_setup (gpointer user_data G_GNUC_UNUSED)
{
/* We are in the child process at this point */
pid_t pid = getpid ();
setpgid (pid, pid);
}
GPid
nm_dns_plugin_child_spawn (NMDnsPlugin *self,
const char **argv,
const char *pidfile,
const char *kill_match)
{
NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self);
GError *error = NULL;
char *cmdline;
g_return_val_if_fail (argv != NULL, 0);
g_return_val_if_fail (argv[0] != NULL, 0);
g_warn_if_fail (priv->progname == NULL);
g_free (priv->progname);
priv->progname = g_path_get_basename (argv[0]);
if (pidfile) {
g_return_val_if_fail (kill_match != NULL, 0);
kill_existing (priv->progname, pidfile, kill_match);
g_free (priv->pidfile);
priv->pidfile = g_strdup (pidfile);
}
nm_log_info (LOGD_DNS, "DNS: starting %s...", priv->progname);
cmdline = g_strjoinv (" ", (char **) argv);
nm_log_dbg (LOGD_DNS, "DNS: command line: %s", cmdline);
g_free (cmdline);
priv->pid = 0;
if (g_spawn_async (NULL, (char **) argv, NULL,
G_SPAWN_DO_NOT_REAP_CHILD,
child_setup,
NULL, &priv->pid,
&error)) {
nm_log_dbg (LOGD_DNS, "%s started with pid %d", priv->progname, priv->pid);
priv->watch_id = g_child_watch_add (priv->pid, (GChildWatchFunc) watch_cb, self);
} else {
nm_log_warn (LOGD_DNS, "Failed to spawn %s: (%d) %s",
priv->progname, error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
}
return priv->pid;
}
typedef struct {
int pid;
char *progname;
} KillInfo;
static gboolean
ensure_killed (gpointer data)
{
KillInfo *info = data;
if (kill (info->pid, 0) == 0)
kill (info->pid, SIGKILL);
/* ensure the child is reaped */
nm_log_dbg (LOGD_DNS, "waiting for %s pid %d to exit", info->progname, info->pid);
waitpid (info->pid, NULL, 0);
nm_log_dbg (LOGD_DNS, "dnsmasq pid %d cleaned up", info->progname, info->pid);
g_free (info->progname);
g_free (info);
return FALSE;
}
gboolean nm_dns_plugin_child_kill (NMDnsPlugin *self)
{
NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self);
if (priv->watch_id) {
g_source_remove (priv->watch_id);
priv->watch_id = 0;
}
if (priv->pid) {
KillInfo *info;
if (kill (priv->pid, SIGTERM) == 0) {
info = g_malloc0 (sizeof (KillInfo));
info->pid = priv->pid;
info->progname = g_strdup (priv->progname);
g_timeout_add_seconds (2, ensure_killed, info);
} else {
kill (priv->pid, SIGKILL);
/* ensure the child is reaped */
nm_log_dbg (LOGD_DNS, "waiting for %s pid %d to exit", priv->progname, priv->pid);
waitpid (priv->pid, NULL, 0);
nm_log_dbg (LOGD_DNS, "%s pid %d cleaned up", priv->progname, priv->pid);
}
priv->pid = 0;
g_free (priv->progname);
priv->progname = NULL;
}
if (priv->pidfile) {
unlink (priv->pidfile);
g_free (priv->pidfile);
priv->pidfile = NULL;
}
return TRUE;
}
/********************************************/
static void
nm_dns_plugin_init (NMDnsPlugin *self)
{
}
static void
dispose (GObject *object)
{
NMDnsPlugin *self = NM_DNS_PLUGIN (object);
NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self);
if (!priv->disposed) {
priv->disposed = TRUE;
nm_dns_plugin_child_kill (self);
}
G_OBJECT_CLASS (nm_dns_plugin_parent_class)->dispose (object);
}
static void
finalize (GObject *object)
{
NMDnsPlugin *self = NM_DNS_PLUGIN (object);
NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self);
g_free (priv->progname);
g_free (priv->pidfile);
G_OBJECT_CLASS (nm_dns_plugin_parent_class)->finalize (object);
}
static void
nm_dns_plugin_class_init (NMDnsPluginClass *plugin_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (plugin_class);
g_type_class_add_private (plugin_class, sizeof (NMDnsPluginPrivate));
/* virtual methods */
object_class->dispose = dispose;
object_class->finalize = finalize;
plugin_class->is_caching = is_caching;
/* signals */
signals[FAILED] =
g_signal_new (NM_DNS_PLUGIN_FAILED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMDnsPluginClass, failed),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[CHILD_QUIT] =
g_signal_new (NM_DNS_PLUGIN_CHILD_QUIT,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMDnsPluginClass, child_quit),
NULL, NULL,
g_cclosure_marshal_VOID__INT,
G_TYPE_NONE, 1, G_TYPE_INT);
}

View file

@ -0,0 +1,112 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; 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, 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) 2010 Red Hat, Inc.
*/
#ifndef NM_DNS_PLUGIN_H
#define NM_DNS_PLUGIN_H
#include <glib.h>
#include <glib-object.h>
#define NM_TYPE_DNS_PLUGIN (nm_dns_plugin_get_type ())
#define NM_DNS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DNS_PLUGIN, NMDnsPlugin))
#define NM_DNS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DNS_PLUGIN, NMDnsPluginClass))
#define NM_IS_DNS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DNS_PLUGIN))
#define NM_IS_DNS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_DNS_PLUGIN))
#define NM_DNS_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DNS_PLUGIN, NMDnsPluginClass))
#define NM_DNS_PLUGIN_FAILED "failed"
#define NM_DNS_PLUGIN_CHILD_QUIT "child-quit"
typedef struct {
GObject parent;
} NMDnsPlugin;
typedef struct {
GObjectClass parent;
/* Methods */
gboolean (*init) (NMDnsPlugin *self);
/* Called when DNS information is changed. 'vpn_configs' is a list of
* NMIP4Config or NMIP6Config objects from VPN connections, while
* 'dev_configs' is a list of NMPI4Config or NMIP6Config objects from
* active devices. 'other_configs' represent other IP configuration that
* may be in-use. Configs of the same IP version are sorted in priority
* order.
*/
gboolean (*update) (NMDnsPlugin *self,
const GSList *vpn_configs,
const GSList *dev_configs,
const GSList *other_configs,
const char *hostname);
/* Subclasses should override and return TRUE if they start a local
* caching nameserver that listens on localhost and would block any
* other local caching nameserver from operating.
*/
gboolean (*is_caching) (NMDnsPlugin *self);
/* Subclasses should override this and return their plugin name */
const char *(*get_name) (NMDnsPlugin *self);
/* Signals */
/* Emitted by the plugin and consumed by NMDnsManager when
* some error happens with the nameserver subprocess. Causes NM to fall
* back to writing out a non-local-caching resolv.conf until the next
* DNS update.
*/
void (*failed) (NMDnsPlugin *self);
/* Emitted by the plugin base class when the nameserver subprocess
* quits. This signal is consumed by the plugin subclasses and not
* by NMDnsManager. If the subclass decides the exit status (as returned
* by waitpid(2)) is fatal it should then emit the 'failed' signal.
*/
void (*child_quit) (NMDnsPlugin *self, gint status);
} NMDnsPluginClass;
GType nm_dns_plugin_get_type (void);
gboolean nm_dns_plugin_is_caching (NMDnsPlugin *self);
const char *nm_dns_plugin_get_name (NMDnsPlugin *self);
gboolean nm_dns_plugin_update (NMDnsPlugin *self,
const GSList *vpn_configs,
const GSList *dev_configs,
const GSList *other_configs,
const char *hostname);
/* For subclasses/plugins */
/* Spawn a child process and watch for it to quit. 'argv' is the NULL-terminated
* argument vector to spawn the child with, where argv[0] is the full path to
* the child's executable. If 'pidfile' is given the process owning the PID
* contained in 'pidfile' will be killed if its command line matches 'kill_match'
* and the pidfile will be deleted.
*/
GPid nm_dns_plugin_child_spawn (NMDnsPlugin *self,
const char **argv,
const char *pidfile,
const char *kill_match);
gboolean nm_dns_plugin_child_kill (NMDnsPlugin *self);
#endif /* NM_DNS_PLUGIN_H */

View file

@ -300,6 +300,7 @@ static gboolean
parse_config_file (const char *filename,
char **plugins,
char **dhcp_client,
char ***dns_plugins,
char **log_level,
char **log_domains,
GError **error)
@ -322,6 +323,7 @@ parse_config_file (const char *filename,
return FALSE;
*dhcp_client = g_key_file_get_value (config, "main", "dhcp", NULL);
*dns_plugins = g_key_file_get_string_list (config, "main", "dns", NULL, NULL);
*log_level = g_key_file_get_value (config, "logging", "level", NULL);
*log_domains = g_key_file_get_value (config, "logging", "domains", NULL);
@ -442,6 +444,7 @@ main (int argc, char *argv[])
char *pidfile = NULL, *state_file = NULL, *dhcp = NULL;
char *config = NULL, *plugins = NULL, *conf_plugins = NULL;
char *log_level = NULL, *log_domains = NULL;
char **dns = NULL;
gboolean wifi_enabled = TRUE, net_enabled = TRUE, wwan_enabled = TRUE;
gboolean success;
NMPolicy *policy = NULL;
@ -515,7 +518,7 @@ main (int argc, char *argv[])
/* Parse the config file */
if (config) {
if (!parse_config_file (config, &conf_plugins, &dhcp, &cfg_log_level, &cfg_log_domains, &error)) {
if (!parse_config_file (config, &conf_plugins, &dhcp, &dns, &cfg_log_level, &cfg_log_domains, &error)) {
fprintf (stderr, "Config file %s invalid: (%d) %s\n",
config,
error ? error->code : -1,
@ -535,7 +538,7 @@ main (int argc, char *argv[])
/* Try deprecated nm-system-settings.conf first */
if (g_file_test (NM_OLD_SYSTEM_CONF_FILE, G_FILE_TEST_EXISTS)) {
config = g_strdup (NM_OLD_SYSTEM_CONF_FILE);
parsed = parse_config_file (config, &conf_plugins, &dhcp, &cfg_log_level, &cfg_log_domains, &error);
parsed = parse_config_file (config, &conf_plugins, &dhcp, &dns, &cfg_log_level, &cfg_log_domains, &error);
if (!parsed) {
fprintf (stderr, "Default config file %s invalid: (%d) %s\n",
config,
@ -550,7 +553,7 @@ main (int argc, char *argv[])
/* Try the preferred NetworkManager.conf last */
if (!parsed && g_file_test (NM_DEFAULT_SYSTEM_CONF_FILE, G_FILE_TEST_EXISTS)) {
config = g_strdup (NM_DEFAULT_SYSTEM_CONF_FILE);
parsed = parse_config_file (config, &conf_plugins, &dhcp, &cfg_log_level, &cfg_log_domains, &error);
parsed = parse_config_file (config, &conf_plugins, &dhcp, &dns, &cfg_log_level, &cfg_log_domains, &error);
if (!parsed) {
fprintf (stderr, "Default config file %s invalid: (%d) %s\n",
config,
@ -663,7 +666,7 @@ main (int argc, char *argv[])
goto done;
}
dns_mgr = nm_dns_manager_get ();
dns_mgr = nm_dns_manager_get ((const char **) dns);
if (!dns_mgr) {
nm_log_err (LOGD_CORE, "failed to start the DNS manager.");
goto done;
@ -756,6 +759,7 @@ done:
g_free (config);
g_free (plugins);
g_free (dhcp);
g_strfreev (dns);
g_free (log_level);
g_free (log_domains);
g_free (cfg_log_level);

View file

@ -107,8 +107,9 @@ typedef struct Supplicant {
typedef struct {
gboolean disposed;
guint8 hw_addr[ETH_ALEN]; /* Currently set MAC address */
guint8 perm_hw_addr[ETH_ALEN]; /* Currently set MAC address */
guint8 hw_addr[ETH_ALEN]; /* Currently set MAC address */
guint8 perm_hw_addr[ETH_ALEN]; /* Permanent MAC address */
guint8 initial_hw_addr[ETH_ALEN]; /* Initial MAC address (as seen when NM starts) */
gboolean carrier;
NMNetlinkMonitor * monitor;
@ -739,6 +740,33 @@ real_update_permanent_hw_address (NMDevice *dev)
close (fd);
}
static void
real_update_initial_hw_address (NMDevice *dev)
{
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
char *mac_str = NULL;
guint8 *addr = priv->initial_hw_addr;
guint8 zero[ETH_ALEN] = {0,0,0,0,0,0};
/* This sets initial MAC address from current MAC address. It should only
* be called from NMDevice constructor() to really get the initial address.
*/
if (!memcmp (&priv->hw_addr, &zero, ETH_ALEN))
real_update_hw_address (dev);
if (memcmp (&priv->initial_hw_addr, &priv->hw_addr, ETH_ALEN))
memcpy (&priv->initial_hw_addr, &priv->hw_addr, ETH_ALEN);
mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
nm_log_dbg (LOGD_DEVICE | LOGD_ETHER, "(%s): read initial MAC address %s",
nm_device_get_iface (dev), mac_str);
g_free (mac_str);
}
static guint32
real_get_generic_capabilities (NMDevice *dev)
{
@ -1735,8 +1763,8 @@ real_deactivate_quickly (NMDevice *device)
supplicant_interface_release (self);
/* Reset MAC address back to permanent address */
_set_hw_addr (self, priv->perm_hw_addr, "reset");
/* Reset MAC address back to initial address */
_set_hw_addr (self, priv->initial_hw_addr, "reset");
}
static gboolean
@ -2110,6 +2138,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
parent_class->can_interrupt_activation = real_can_interrupt_activation;
parent_class->update_hw_address = real_update_hw_address;
parent_class->update_permanent_hw_address = real_update_permanent_hw_address;
parent_class->update_initial_hw_address = real_update_initial_hw_address;
parent_class->get_best_auto_connection = real_get_best_auto_connection;
parent_class->is_available = real_is_available;
parent_class->connection_secrets_updated = real_connection_secrets_updated;

View file

@ -146,8 +146,9 @@ typedef struct Supplicant {
struct _NMDeviceWifiPrivate {
gboolean disposed;
guint8 hw_addr[ETH_ALEN]; /* Currently set MAC address */
guint8 perm_hw_addr[ETH_ALEN]; /* Permanent MAC address */
guint8 hw_addr[ETH_ALEN]; /* Currently set MAC address */
guint8 perm_hw_addr[ETH_ALEN]; /* Permanent MAC address */
guint8 initial_hw_addr[ETH_ALEN]; /* Initial MAC address (as seen when NM starts) */
/* Legacy rfkill for ipw2x00; will be fixed with 2.6.33 kernel */
char * ipw_rfkill_path;
@ -1250,7 +1251,8 @@ real_deactivate_quickly (NMDevice *dev)
g_object_unref (orig_ap);
}
_set_hw_addr (self, priv->perm_hw_addr, "reset");
/* Reset MAC address back to initial address */
_set_hw_addr (self, priv->initial_hw_addr, "reset");
}
static void
@ -3106,6 +3108,32 @@ real_update_permanent_hw_address (NMDevice *dev)
close (fd);
}
static void
real_update_initial_hw_address (NMDevice *dev)
{
NMDeviceWifi *self = NM_DEVICE_WIFI (dev);
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
char *mac_str = NULL;
guint8 *addr = priv->initial_hw_addr;
guint8 zero[ETH_ALEN] = {0,0,0,0,0,0};
/* This sets initial MAC address from current MAC address. It should only
* be called from NMDevice constructor() to really get the initial address.
*/
if (!memcmp (&priv->hw_addr, &zero, ETH_ALEN))
real_update_hw_address (dev);
if (memcmp (&priv->initial_hw_addr, &priv->hw_addr, ETH_ALEN))
memcpy (&priv->initial_hw_addr, &priv->hw_addr, ETH_ALEN);
mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
nm_log_dbg (LOGD_DEVICE | LOGD_ETHER, "(%s): read initial MAC address %s",
nm_device_get_iface (dev), mac_str);
g_free (mac_str);
}
static NMActStageReturn
real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
@ -3935,6 +3963,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass)
parent_class->take_down = real_take_down;
parent_class->update_hw_address = real_update_hw_address;
parent_class->update_permanent_hw_address = real_update_permanent_hw_address;
parent_class->update_initial_hw_address = real_update_initial_hw_address;
parent_class->get_best_auto_connection = real_get_best_auto_connection;
parent_class->is_available = real_is_available;
parent_class->connection_secrets_updated = real_connection_secrets_updated;

View file

@ -288,6 +288,9 @@ constructor (GType type,
if (NM_DEVICE_GET_CLASS (dev)->update_permanent_hw_address)
NM_DEVICE_GET_CLASS (dev)->update_permanent_hw_address (dev);
if (NM_DEVICE_GET_CLASS (dev)->update_initial_hw_address)
NM_DEVICE_GET_CLASS (dev)->update_initial_hw_address (dev);
priv->dhcp_manager = nm_dhcp_manager_get ();
update_accept_ra_save (dev);
@ -3038,7 +3041,7 @@ nm_device_set_ip4_config (NMDevice *self,
if (diff == NM_IP4_COMPARE_FLAG_NONE)
return TRUE;
dns_mgr = nm_dns_manager_get ();
dns_mgr = nm_dns_manager_get (NULL);
if (old_config) {
/* Remove any previous IP4 Config from the DNS manager */
nm_dns_manager_remove_ip4_config (dns_mgr, ip_iface, old_config);
@ -3141,7 +3144,7 @@ nm_device_set_ip6_config (NMDevice *self,
if (diff == NM_IP6_COMPARE_FLAG_NONE)
return TRUE;
dns_mgr = nm_dns_manager_get ();
dns_mgr = nm_dns_manager_get (NULL);
if (old_config) {
/* Remove any previous IP6 Config from the DNS manager */
nm_dns_manager_remove_ip6_config (dns_mgr, ip_iface, old_config);
@ -3765,7 +3768,7 @@ nm_device_state_changed (NMDevice *device,
case NM_DEVICE_STATE_UNAVAILABLE:
/* If the device can activate now (ie, it's got a carrier, the supplicant
* is active, or whatever) schedule a delayed transition to DISCONNECTED
* to get things rolling. The device can't transition immediately becuase
* to get things rolling. The device can't transition immediately because
* we can't change states again from the state handler for a variety of
* reasons.
*/
@ -3786,7 +3789,7 @@ nm_device_state_changed (NMDevice *device,
case NM_DEVICE_STATE_FAILED:
nm_log_warn (LOGD_DEVICE, "Activation (%s) failed.", nm_device_get_iface (device));
/* Schedule the transition to DISCONNECTED. The device can't transition
* immediately becuase we can't change states again from the state
* immediately because we can't change states again from the state
* handler for a variety of reasons.
*/
priv->failed_to_disconnected_id = g_idle_add (failed_to_disconnected, device);

View file

@ -73,6 +73,7 @@ typedef struct {
void (* update_hw_address) (NMDevice *self);
void (* update_permanent_hw_address) (NMDevice *self);
void (* update_initial_hw_address) (NMDevice *self);
guint32 (* get_type_capabilities) (NMDevice *self);
guint32 (* get_generic_capabilities) (NMDevice *self);

View file

@ -258,6 +258,7 @@ static guint signals[LAST_SIGNAL] = { 0 };
enum {
PROP_0,
PROP_VERSION,
PROP_STATE,
PROP_NETWORKING_ENABLED,
PROP_WIRELESS_ENABLED,
@ -3406,6 +3407,9 @@ get_property (GObject *object, guint prop_id,
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
switch (prop_id) {
case PROP_VERSION:
g_value_set_string (value, VERSION);
break;
case PROP_STATE:
nm_manager_update_state (self);
g_value_set_uint (value, priv->state);
@ -3588,6 +3592,14 @@ nm_manager_class_init (NMManagerClass *manager_class)
object_class->dispose = dispose;
/* properties */
g_object_class_install_property
(object_class, PROP_VERSION,
g_param_spec_string (NM_MANAGER_VERSION,
"Version",
"NetworkManager version",
NULL,
G_PARAM_READABLE));
g_object_class_install_property
(object_class, PROP_STATE,
g_param_spec_uint (NM_MANAGER_STATE,

View file

@ -35,6 +35,7 @@
#define NM_IS_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_MANAGER))
#define NM_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MANAGER, NMManagerClass))
#define NM_MANAGER_VERSION "version"
#define NM_MANAGER_STATE "state"
#define NM_MANAGER_NETWORKING_ENABLED "networking-enabled"
#define NM_MANAGER_WIRELESS_ENABLED "wireless-enabled"

View file

@ -241,7 +241,7 @@ _set_hostname (NMPolicy *policy,
g_free (policy->cur_hostname);
policy->cur_hostname = g_strdup (new_hostname);
dns_mgr = nm_dns_manager_get ();
dns_mgr = nm_dns_manager_get (NULL);
nm_dns_manager_set_hostname (dns_mgr, policy->cur_hostname);
g_object_unref (dns_mgr);
}
@ -553,7 +553,7 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
nm_act_request_set_default (req, FALSE);
}
dns_mgr = nm_dns_manager_get ();
dns_mgr = nm_dns_manager_get (NULL);
nm_dns_manager_add_ip4_config (dns_mgr, ip_iface, ip4_config, dns_type);
g_object_unref (dns_mgr);
@ -679,7 +679,7 @@ update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
nm_act_request_set_default6 (req, FALSE);
}
dns_mgr = nm_dns_manager_get ();
dns_mgr = nm_dns_manager_get (NULL);
nm_dns_manager_add_ip6_config (dns_mgr, ip_iface, ip6_config, dns_type);
g_object_unref (dns_mgr);

View file

@ -711,6 +711,8 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
gboolean success, added;
GString *phase1, *phase2;
const GByteArray *array;
gboolean peap = FALSE;
guint32 i, num_eap;
g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE);
g_return_val_if_fail (setting != NULL, FALSE);
@ -733,6 +735,28 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
ADD_STRING_LIST_VAL (setting, 802_1x, eap_method, eap_methods, "eap", TRUE, FALSE);
/* Check for PEAP + GTC */
num_eap = nm_setting_802_1x_get_num_eap_methods (setting);
for (i = 0; i < num_eap; i++) {
const char *method = nm_setting_802_1x_get_eap_method (setting, i);
if (method && (strcasecmp (method, "peap") == 0)) {
peap = TRUE;
break;
}
}
/* When using PEAP-GTC, we're likely using Cisco kit, so we want to turn
* on PMKSA caching so that roaming between access points actually works
* without a full reauth (which requires a new token code). We may want
* to extend this to all PEAP phase2 methods at some point.
*/
value = nm_setting_802_1x_get_phase2_auth (setting);
if (peap && value && (strcasecmp (value, "gtc") == 0)) {
if (!nm_supplicant_config_add_option (self, "proactive_key_caching", "1", -1, FALSE))
return FALSE;
}
/* Drop the fragment size a bit for better compatibility */
if (!nm_supplicant_config_add_option (self, "fragment_size", "1300", -1, FALSE))
return FALSE;

View file

@ -315,6 +315,7 @@ get_plugin (NMSysconfigSettings *self, guint32 capability)
return NULL;
}
/* Returns an allocated string which the caller owns and must eventually free */
char *
nm_sysconfig_settings_get_hostname (NMSysconfigSettings *self)
{
@ -337,7 +338,7 @@ nm_sysconfig_settings_get_hostname (NMSysconfigSettings *self)
}
}
return hostname;
return NULL;
}
static void
@ -470,7 +471,7 @@ load_plugins (NMSysconfigSettings *self, const char *plugins, GError **error)
for (iter = plist; *iter; iter++) {
GModule *plugin;
char *full_name, *path;
const char *pname = *iter;
const char *pname = g_strstrip (*iter);
GObject *obj;
GObject * (*factory_func) (void);
@ -989,6 +990,11 @@ is_mac_auto_wired_blacklisted (NMSysconfigSettings *self, const GByteArray *mac)
for (iter = list; iter && *iter; iter++) {
struct ether_addr *candidate;
if (strcmp(g_strstrip(*iter), "*") == 0) {
found = TRUE;
break;
}
candidate = ether_aton (*iter);
if (candidate && !memcmp (mac->data, candidate->ether_addr_octet, ETH_ALEN)) {
found = TRUE;
@ -1048,13 +1054,19 @@ default_wired_deleted (NMDefaultWiredConnection *wired,
g_key_file_load_from_file (config, priv->config_file, G_KEY_FILE_KEEP_COMMENTS, NULL);
list = g_key_file_get_string_list (config, "main", CONFIG_KEY_NO_AUTO_DEFAULT, &len, NULL);
/* Traverse entire list to get count of # items */
for (iter = list; iter && *iter; iter++) {
struct ether_addr *candidate;
candidate = ether_aton (*iter);
if (candidate && !memcmp (mac->data, candidate->ether_addr_octet, ETH_ALEN))
if (strcmp(g_strstrip(*iter), "*") == 0) {
found = TRUE;
break;
}
candidate = ether_aton (*iter);
if (candidate && !memcmp (mac->data, candidate->ether_addr_octet, ETH_ALEN)) {
found = TRUE;
break;
}
}
/* Add this device's MAC to the list */

View file

@ -548,7 +548,7 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
priv->gw_route = nm_system_add_ip4_vpn_gateway_route (priv->parent_dev, config);
/* Add the VPN to DNS */
dns_mgr = nm_dns_manager_get ();
dns_mgr = nm_dns_manager_get (NULL);
nm_dns_manager_add_ip4_config (dns_mgr, priv->ip_iface, config, NM_DNS_IP_CONFIG_TYPE_VPN);
g_object_unref (dns_mgr);
@ -901,7 +901,7 @@ vpn_cleanup (NMVPNConnection *connection)
NMDnsManager *dns_mgr;
/* Remove attributes of the VPN's IP4 Config */
dns_mgr = nm_dns_manager_get ();
dns_mgr = nm_dns_manager_get (NULL);
nm_dns_manager_remove_ip4_config (dns_mgr, priv->ip_iface, priv->ip4_config);
g_object_unref (dns_mgr);

View file

@ -1877,7 +1877,7 @@ parse_wpa_psk (shvarFile *ifcfg,
char *psk = NULL, *p, *hashed = NULL;
gboolean quoted = FALSE;
/* Passphrase must be between 10 and 66 characters in length becuase WPA
/* Passphrase must be between 10 and 66 characters in length because WPA
* hex keys are exactly 64 characters (no quoting), and WPA passphrases
* are between 8 and 63 characters (inclusive), plus optional quoting if
* the passphrase contains spaces.

View file

@ -565,6 +565,12 @@ update_system_hostname(NMInotifyHelper *inotify_helper,
priv->hostname = g_strstrip(hostname_file);
/* We shouldn't return a zero-length hostname, but NULL */
if (priv->hostname && !strlen (priv->hostname)) {
g_free (priv->hostname);
priv->hostname = NULL;
}
g_object_notify (G_OBJECT (config), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
}

View file

@ -1,36 +1,49 @@
SUBDIRS=io tests
SUBDIRS=. tests
INCLUDES = \
-I$(top_srcdir)/src/system-settings \
-I$(top_srcdir)/include \
-I$(top_srcdir)/libnm-util \
-I$(top_srcdir)/libnm-glib \
-I$(top_srcdir)/system-settings/plugins/keyfile/io
-I$(top_srcdir)/libnm-glib
pkglib_LTLIBRARIES = libnm-settings-plugin-keyfile.la
noinst_LTLIBRARIES = libkeyfile-io.la
libkeyfile_io_la_SOURCES = \
reader.c \
reader.h \
writer.c \
writer.h \
errors.c \
common.h
libkeyfile_io_la_CPPFLAGS = \
$(GLIB_CFLAGS) \
$(DBUS_CFLAGS) \
-DSYSCONFDIR=\"$(sysconfdir)\" \
-DG_DISABLE_DEPRECATED
libkeyfile_io_la_LIBADD = $(GLIB_LIBS)
libnm_settings_plugin_keyfile_la_SOURCES = \
nm-keyfile-connection.c \
nm-keyfile-connection.h \
plugin.c \
plugin.h
keyfiledir=$(sysconfdir)/NetworkManager/system-connections
libnm_settings_plugin_keyfile_la_CPPFLAGS = \
$(GLIB_CFLAGS) \
$(GMODULE_CFLAGS) \
$(DBUS_CFLAGS) \
-DSYSCONFDIR=\"$(sysconfdir)\" \
-DG_DISABLE_DEPRECATED \
-DKEYFILE_DIR=\""$(keyfiledir)"\" \
-DKEYFILE_PLUGIN_NAME=\""keyfile"\"
-DG_DISABLE_DEPRECATED
libnm_settings_plugin_keyfile_la_LDFLAGS = -module -avoid-version
libnm_settings_plugin_keyfile_la_LIBADD = \
$(top_builddir)/libnm-util/libnm-util.la \
$(top_builddir)/libnm-glib/libnm-glib.la \
$(top_builddir)/system-settings/plugins/keyfile/io/libkeyfile-io.la \
libkeyfile-io.la \
$(GLIB_LIBS) \
$(GMODULE_LIBS) \
$(DBUS_LIBS) \

View file

@ -0,0 +1,37 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager system settings service
*
* 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.
*
* (C) Copyright 2008 - 2010 Red Hat, Inc.
*/
#ifndef __COMMON_H__
#define __COMMON_H__
#include <glib.h>
#define KEYFILE_PLUGIN_NAME "keyfile"
#define KEYFILE_PLUGIN_INFO "(c) 2007 - 2010 Red Hat, Inc. To report bugs please use the NetworkManager mailing list."
#define KEYFILE_DIR SYSCONFDIR "/NetworkManager/system-connections"
#define VPN_SECRETS_GROUP "vpn-secrets"
#define KEYFILE_PLUGIN_ERROR (keyfile_plugin_error_quark ())
GQuark keyfile_plugin_error_quark (void);
#endif /* __COMMON_H__ */

View file

@ -0,0 +1,35 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager system settings service
*
* 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.
*
* (C) Copyright 2008 - 2010 Red Hat, Inc.
*/
#include <glib.h>
#include "common.h"
GQuark
keyfile_plugin_error_quark (void)
{
static GQuark error_quark = 0;
if (G_UNLIKELY (error_quark == 0))
error_quark = g_quark_from_static_string ("keyfile-plugin-error-quark");
return error_quark;
}

View file

@ -1,23 +0,0 @@
INCLUDES = \
-I$(top_srcdir)/system-settings/src \
-I$(top_srcdir)/src/system-settings \
-I$(top_srcdir)/include \
-I$(top_srcdir)/libnm-util \
-I$(top_srcdir)/libnm-glib
noinst_LTLIBRARIES = libkeyfile-io.la
libkeyfile_io_la_SOURCES = \
reader.h \
reader.c \
writer.h \
writer.c
libkeyfile_io_la_CPPFLAGS = \
$(GLIB_CFLAGS) \
$(DBUS_CFLAGS)
libkeyfile_io_la_LIBADD = \
$(top_builddir)/src/system-settings/libsystem-settings.la \
$(GLIB_LIBS)

View file

@ -30,6 +30,7 @@
#include "nm-keyfile-connection.h"
#include "reader.h"
#include "writer.h"
#include "common.h"
G_DEFINE_TYPE (NMKeyfileConnection, nm_keyfile_connection, NM_TYPE_SYSCONFIG_CONNECTION)

View file

@ -38,9 +38,7 @@
#include "nm-system-config-interface.h"
#include "nm-keyfile-connection.h"
#include "writer.h"
#define KEYFILE_PLUGIN_NAME "keyfile"
#define KEYFILE_PLUGIN_INFO "(c) 2007 - 2010 Red Hat, Inc. To report bugs please use the NetworkManager mailing list."
#include "common.h"
#define CONF_FILE SYSCONFDIR "/NetworkManager/NetworkManager.conf"
#define OLD_CONF_FILE SYSCONFDIR "/NetworkManager/nm-system-settings.conf"

View file

@ -40,10 +40,11 @@
#include <arpa/inet.h>
#include <netinet/ether.h>
#include <string.h>
#include <nm-system-config-error.h>
#include <ctype.h>
#include "nm-dbus-glib-types.h"
#include "reader.h"
#include "common.h"
static gboolean
read_array_of_uint (GKeyFile *file,
@ -731,6 +732,68 @@ read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key)
g_strfreev (keys);
}
static void
ssid_parser (NMSetting *setting, const char *key, GKeyFile *keyfile)
{
const char *setting_name = nm_setting_get_name (setting);
GByteArray *array = NULL;
char *p, *tmp_string;
gint *tmp_list;
gsize length;
int i;
/* New format: just a string. We try parsing the new format if there are
* no ';' in the string or it's not just numbers.
*/
p = tmp_string = g_key_file_get_string (keyfile, setting_name, key, NULL);
if (tmp_string) {
gboolean new_format = FALSE;
if (strchr (p, ';') == NULL)
new_format = TRUE;
else {
new_format = TRUE;
while (p && *p) {
if (!isdigit (*p++)) {
new_format = FALSE;
break;
}
}
}
if (new_format) {
array = g_byte_array_sized_new (strlen (tmp_string));
g_byte_array_append (array, (guint8 *) tmp_string, strlen (tmp_string));
goto done;
}
}
g_free (tmp_string);
/* Old format; list of ints */
tmp_list = g_key_file_get_integer_list (keyfile, setting_name, key, &length, NULL);
array = g_byte_array_sized_new (length);
for (i = 0; i < length; i++) {
int val = tmp_list[i];
unsigned char v = (unsigned char) (val & 0xFF);
if (val < 0 || val > 255) {
g_warning ("%s: %s / %s ignoring invalid byte element '%d' (not "
" between 0 and 255 inclusive)", __func__, setting_name,
key, val);
} else
g_byte_array_append (array, (const unsigned char *) &v, sizeof (v));
}
g_free (tmp_list);
done:
if (array->len)
g_object_set (setting, key, array, NULL);
else {
g_warning ("%s: ignoring invalid SSID for %s / %s",
__func__, setting_name, key);
}
g_byte_array_free (array, TRUE);
}
typedef struct {
const char *setting_name;
@ -739,7 +802,7 @@ typedef struct {
void (*parser) (NMSetting *setting, const char *key, GKeyFile *keyfile);
} KeyParser;
/* A table of keys that require further parsing/conversion becuase they are
/* A table of keys that require further parsing/conversion because they are
* stored in a format that can't be automatically read using the key's type.
* i.e. IPv4 addresses, which are stored in NetworkManager as guint32, but are
* stored in keyfiles as strings, eg "10.1.1.2" or IPv6 addresses stored
@ -794,6 +857,10 @@ static KeyParser key_parsers[] = {
NM_SETTING_BLUETOOTH_BDADDR,
TRUE,
mac_address_parser },
{ NM_SETTING_WIRELESS_SETTING_NAME,
NM_SETTING_WIRELESS_SSID,
TRUE,
ssid_parser },
{ NULL, NULL, FALSE }
};
@ -1004,9 +1071,7 @@ connection_from_file (const char *filename, GError **error)
GError *verify_error = NULL;
if (stat (filename, &statbuf) != 0 || !S_ISREG (statbuf.st_mode)) {
g_set_error_literal (error,
NM_SYSCONFIG_SETTINGS_ERROR,
NM_SYSCONFIG_SETTINGS_ERROR_INTERNAL_ERROR,
g_set_error_literal (error, KEYFILE_PLUGIN_ERROR, 0,
"File did not exist or was not a regular file");
return NULL;
}
@ -1015,9 +1080,7 @@ connection_from_file (const char *filename, GError **error)
bad_permissions = statbuf.st_mode & 0077;
if (bad_owner || bad_permissions) {
g_set_error (error,
NM_SYSCONFIG_SETTINGS_ERROR,
NM_SYSCONFIG_SETTINGS_ERROR_INTERNAL_ERROR,
g_set_error (error, KEYFILE_PLUGIN_ERROR, 0,
"File permissions (%o) or owner (%d) were insecure",
statbuf.st_mode, statbuf.st_uid);
return NULL;
@ -1096,9 +1159,7 @@ connection_from_file (const char *filename, GError **error)
/* Verify the connection */
if (!nm_connection_verify (connection, &verify_error)) {
g_set_error (error,
NM_SYSCONFIG_SETTINGS_ERROR,
NM_SYSCONFIG_SETTINGS_ERROR_INTERNAL_ERROR,
g_set_error (error, KEYFILE_PLUGIN_ERROR, 0,
"invalid or missing connection property '%s'",
(verify_error && verify_error->message) ? verify_error->message : "(unknown)");
g_clear_error (&verify_error);

View file

@ -22,8 +22,6 @@
#ifndef _KEYFILE_PLUGIN_READER_H
#define _KEYFILE_PLUGIN_READER_H
#define VPN_SECRETS_GROUP "vpn-secrets"
#include <glib.h>
#include <nm-connection.h>

View file

@ -4,7 +4,7 @@ INCLUDES = \
-I$(top_srcdir)/include \
-I$(top_srcdir)/libnm-util \
-I$(top_srcdir)/libnm-glib \
-I$(top_srcdir)/system-settings/plugins/keyfile/io
-I$(top_srcdir)/system-settings/plugins/keyfile
noinst_PROGRAMS = test-keyfile
@ -18,7 +18,7 @@ test_keyfile_CPPFLAGS = \
-DTEST_SCRATCH_DIR=\"$(abs_builddir)/keyfiles\"
test_keyfile_LDADD = \
$(top_builddir)/system-settings/plugins/keyfile/io/libkeyfile-io.la \
$(top_builddir)/system-settings/plugins/keyfile/libkeyfile-io.la \
$(top_builddir)/libnm-glib/libnm-glib.la \
$(top_builddir)/libnm-util/libnm-util.la \
$(DBUS_LIBS)

View file

@ -5,7 +5,8 @@ EXTRA_DIST = \
Test_Wired_Connection_MAC_Case \
Test_Wired_Connection_IP6 \
ATT_Data_Connect_BT \
ATT_Data_Connect_Plain
ATT_Data_Connect_Plain \
Test_String_SSID
check-local:
@for f in $(EXTRA_DIST); do \

View file

@ -0,0 +1,11 @@
[connection]
id=Test
uuid=2f962388-e5f3-45af-a62c-ac220b8f7baa
type=802-11-wireless
[802-11-wireless]
ssid=blah blah ssid 1234
[ipv4]
method=auto

View file

@ -1296,6 +1296,149 @@ test_write_wireless_connection (void)
g_object_unref (connection);
}
#define TEST_STRING_SSID_FILE TEST_KEYFILES_DIR"/Test_String_SSID"
static void
test_read_string_ssid (void)
{
NMConnection *connection;
NMSettingWireless *s_wireless;
GError *error = NULL;
const GByteArray *array;
const char *expected_ssid = "blah blah ssid 1234";
connection = connection_from_file (TEST_STRING_SSID_FILE, NULL);
ASSERT (connection != NULL,
"connection-read", "failed to read %s", TEST_STRING_SSID_FILE);
ASSERT (nm_connection_verify (connection, &error),
"connection-verify", "failed to verify %s: %s", TEST_STRING_SSID_FILE, error->message);
/* ===== WIRELESS SETTING ===== */
s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
ASSERT (s_wireless != NULL,
"connection-verify-wireless", "failed to verify %s: missing %s setting",
TEST_STRING_SSID_FILE,
NM_SETTING_WIRELESS_SETTING_NAME);
/* SSID */
array = nm_setting_wireless_get_ssid (s_wireless);
ASSERT (array != NULL,
"connection-verify-wireless", "failed to verify %s: missing %s / %s key",
TEST_STRING_SSID_FILE,
NM_SETTING_WIRELESS_SETTING_NAME,
NM_SETTING_WIRELESS_SSID);
ASSERT (memcmp (array->data, expected_ssid, sizeof (expected_ssid)) == 0,
"connection-verify-wireless", "failed to verify %s: unexpected %s / %s key value",
TEST_STRING_SSID_FILE,
NM_SETTING_WIRELESS_SETTING_NAME,
NM_SETTING_WIRELESS_SSID);
g_object_unref (connection);
}
static void
test_write_string_ssid (void)
{
NMConnection *connection;
NMSettingConnection *s_con;
NMSettingWireless *s_wireless;
NMSettingIP4Config *s_ip4;
char *uuid, *testfile = NULL, *tmp;
GByteArray *ssid;
unsigned char tmpssid[] = { 65, 49, 50, 51, 32, 46, 92, 46, 36, 37, 126, 93 };
gboolean success;
NMConnection *reread;
GError *error = NULL;
pid_t owner_grp;
uid_t owner_uid;
GKeyFile *keyfile;
connection = nm_connection_new ();
ASSERT (connection != NULL,
"connection-write", "failed to allocate new connection");
/* Connection setting */
s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
ASSERT (s_con != NULL,
"connection-write", "failed to allocate new %s setting",
NM_SETTING_CONNECTION_SETTING_NAME);
nm_connection_add_setting (connection, NM_SETTING (s_con));
uuid = nm_utils_uuid_generate ();
g_object_set (s_con,
NM_SETTING_CONNECTION_ID, "String SSID Test",
NM_SETTING_CONNECTION_UUID, uuid,
NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME,
NULL);
g_free (uuid);
/* Wireless setting */
s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
ASSERT (s_wireless != NULL,
"connection-write", "failed to allocate new %s setting",
NM_SETTING_WIRELESS_SETTING_NAME);
nm_connection_add_setting (connection, NM_SETTING (s_wireless));
ssid = g_byte_array_sized_new (sizeof (tmpssid));
g_byte_array_append (ssid, &tmpssid[0], sizeof (tmpssid));
g_object_set (s_wireless, NM_SETTING_WIRELESS_SSID, ssid, NULL);
g_byte_array_free (ssid, TRUE);
/* IP4 setting */
s_ip4 = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new ());
ASSERT (s_ip4 != NULL,
"connection-write", "failed to allocate new %s setting",
NM_SETTING_IP4_CONFIG_SETTING_NAME);
nm_connection_add_setting (connection, NM_SETTING (s_ip4));
g_object_set (s_ip4,
NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO,
NULL);
/* Write out the connection */
owner_uid = geteuid ();
owner_grp = getegid ();
success = write_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error);
ASSERT (success == TRUE,
"connection-write", "failed to allocate write keyfile: %s",
error ? error->message : "(none)");
ASSERT (testfile != NULL,
"connection-write", "didn't get keyfile name back after writing connection");
/* Ensure the SSID was written out as a string */
keyfile = g_key_file_new ();
ASSERT (g_key_file_load_from_file (keyfile, testfile, 0, NULL) == TRUE,
"string-ssid-verify", "failed to load keyfile to verify");
tmp = g_key_file_get_string (keyfile, NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_SSID, NULL);
ASSERT (tmp, "string-ssid-verify", "failed to load 'ssid' key from file");
ASSERT (strlen (tmp) == sizeof (tmpssid),
"string-ssid-verify", "reread SSID and expected were different sizes");
ASSERT (memcmp (tmp, tmpssid, sizeof (tmpssid)) == 0,
"string-ssid-verify", "reread SSID and expected were different");
g_free (tmp);
g_key_file_free (keyfile);
/* Read the connection back in and compare it to the one we just wrote out */
reread = connection_from_file (testfile, NULL);
ASSERT (reread != NULL, "connection-write", "failed to re-read test connection");
ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE,
"connection-write", "written and re-read connection weren't the same");
g_clear_error (&error);
unlink (testfile);
g_free (testfile);
g_object_unref (reread);
g_object_unref (connection);
}
#define TEST_BT_DUN_FILE TEST_KEYFILES_DIR"/ATT_Data_Connect_BT"
static void
@ -1867,6 +2010,9 @@ int main (int argc, char **argv)
test_read_valid_wireless_connection ();
test_write_wireless_connection ();
test_read_string_ssid ();
test_write_string_ssid ();
test_read_bt_dun_connection ();
test_write_bt_dun_connection ();

View file

@ -36,11 +36,12 @@
#include <string.h>
#include <arpa/inet.h>
#include <netinet/ether.h>
#include <ctype.h>
#include "nm-dbus-glib-types.h"
#include "nm-system-config-error.h"
#include "writer.h"
#include "reader.h"
#include "common.h"
static gboolean
write_array_of_uint (GKeyFile *file,
@ -454,13 +455,56 @@ write_hash_of_string (GKeyFile *file,
g_hash_table_foreach (hash, write_hash_of_string_helper, &info);
}
static void
ssid_writer (GKeyFile *file,
NMSetting *setting,
const char *key,
const GValue *value)
{
GByteArray *array;
const char *setting_name = nm_setting_get_name (setting);
gboolean new_format = TRUE;
int i, *tmp_array;
char *ssid;
g_return_if_fail (G_VALUE_HOLDS (value, DBUS_TYPE_G_UCHAR_ARRAY));
array = (GByteArray *) g_value_get_boxed (value);
if (!array || !array->len)
return;
/* Check whether each byte is printable. If not, we have to use an
* integer list, otherwise we can just use a string.
*/
for (i = 0; i < array->len; i++) {
char c = array->data[i] & 0xFF;
if (!isprint (c)) {
new_format = FALSE;
break;
}
}
if (new_format) {
ssid = g_malloc0 (array->len + 1);
memcpy (ssid, array->data, array->len);
g_key_file_set_string (file, setting_name, key, ssid);
g_free (ssid);
} else {
tmp_array = g_new (gint, array->len);
for (i = 0; i < array->len; i++)
tmp_array[i] = (int) array->data[i];
g_key_file_set_integer_list (file, setting_name, key, tmp_array, array->len);
g_free (tmp_array);
}
}
typedef struct {
const char *setting_name;
const char *key;
void (*writer) (GKeyFile *keyfile, NMSetting *setting, const char *key, const GValue *value);
} KeyWriter;
/* A table of keys that require further parsing/conversion becuase they are
/* A table of keys that require further parsing/conversion because they are
* stored in a format that can't be automatically read using the key's type.
* i.e. IPv4 addresses, which are stored in NetworkManager as guint32, but are
* stored in keyfiles as strings, eg "10.1.1.2" or IPv6 addresses stored
@ -503,6 +547,9 @@ static KeyWriter key_writers[] = {
{ NM_SETTING_BLUETOOTH_SETTING_NAME,
NM_SETTING_BLUETOOTH_BDADDR,
mac_address_writer },
{ NM_SETTING_WIRELESS_SETTING_NAME,
NM_SETTING_WIRELESS_SSID,
ssid_writer },
{ NULL, NULL, NULL }
};
@ -667,18 +714,14 @@ write_connection (NMConnection *connection,
g_file_set_contents (path, data, len, error);
if (chown (path, owner_uid, owner_grp) < 0) {
g_set_error (error,
NM_SYSCONFIG_SETTINGS_ERROR,
NM_SYSCONFIG_SETTINGS_ERROR_INTERNAL_ERROR,
g_set_error (error, KEYFILE_PLUGIN_ERROR, 0,
"%s.%d: error chowning '%s': %d", __FILE__, __LINE__,
path, errno);
unlink (path);
} else {
err = chmod (path, S_IRUSR | S_IWUSR);
if (err) {
g_set_error (error,
NM_SYSCONFIG_SETTINGS_ERROR,
NM_SYSCONFIG_SETTINGS_ERROR_INTERNAL_ERROR,
g_set_error (error, KEYFILE_PLUGIN_ERROR, 0,
"%s.%d: error setting permissions on '%s': %d", __FILE__,
__LINE__, path, errno);
unlink (path);