diff options
Diffstat (limited to 'libnm-core/nm-setting-ip4-config.c')
| -rw-r--r-- | libnm-core/nm-setting-ip4-config.c | 695 |
1 files changed, 695 insertions, 0 deletions
diff --git a/libnm-core/nm-setting-ip4-config.c b/libnm-core/nm-setting-ip4-config.c new file mode 100644 index 00000000..68619267 --- /dev/null +++ b/libnm-core/nm-setting-ip4-config.c @@ -0,0 +1,695 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2014 Red Hat, Inc. + */ + +#include "config.h" + +#include <string.h> +#include <glib/gi18n-lib.h> + +#include "nm-setting-ip4-config.h" +#include "nm-setting-private.h" + +/** + * SECTION:nm-setting-ip4-config + * @short_description: Describes IPv4 addressing, routing, and name service properties + * + * The #NMSettingIP4Config object is a #NMSetting subclass that describes + * properties related to IPv4 addressing, routing, and Domain Name Service. + * + * #NMSettingIP4Config has few properties or methods of its own; it inherits + * almost everything from #NMSettingIPConfig. + * + * NetworkManager supports 5 values for the #NMSettingIPConfig:method property + * for IPv4. If "auto" is specified then the appropriate automatic method + * (DHCP, PPP, etc) is used for the interface and most other properties can be + * left unset. If "link-local" is specified, then a link-local address in the + * 169.254/16 range will be assigned to the interface. If "manual" is + * specified, static IP addressing is used and at least one IP address must be + * given in the "addresses" property. If "shared" is specified (indicating that + * this connection will provide network access to other computers) then the + * interface is assigned an address in the 10.42.x.1/24 range and a DHCP and + * forwarding DNS server are started, and the interface is NAT-ed to the current + * default network connection. "disabled" means IPv4 will not be used on this + * connection. + **/ + +G_DEFINE_TYPE_WITH_CODE (NMSettingIP4Config, nm_setting_ip4_config, NM_TYPE_SETTING_IP_CONFIG, + _nm_register_setting (IP4_CONFIG, 4)) +NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_IP4_CONFIG) + +#define NM_SETTING_IP4_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_IP4_CONFIG, NMSettingIP4ConfigPrivate)) + +typedef struct { + char *dhcp_client_id; +} NMSettingIP4ConfigPrivate; + +enum { + PROP_0, + PROP_DHCP_CLIENT_ID, + + LAST_PROP +}; + +/** + * nm_setting_ip4_config_new: + * + * Creates a new #NMSettingIP4Config object with default values. + * + * Returns: (transfer full): the new empty #NMSettingIP4Config object + **/ +NMSetting * +nm_setting_ip4_config_new (void) +{ + return (NMSetting *) g_object_new (NM_TYPE_SETTING_IP4_CONFIG, NULL); +} + +/** + * nm_setting_ip4_config_get_dhcp_client_id: + * @setting: the #NMSettingIP4Config + * + * Returns the value contained in the #NMSettingIP4Config:dhcp-client-id + * property. + * + * Returns: the configured Client ID to send to the DHCP server when requesting + * addresses via DHCP. + **/ +const char * +nm_setting_ip4_config_get_dhcp_client_id (NMSettingIP4Config *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP4_CONFIG (setting), NULL); + + return NM_SETTING_IP4_CONFIG_GET_PRIVATE (setting)->dhcp_client_id; +} + +static gboolean +verify (NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingIP4ConfigPrivate *priv = NM_SETTING_IP4_CONFIG_GET_PRIVATE (setting); + NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG (setting); + NMSettingVerifyResult ret; + const char *method; + + ret = NM_SETTING_CLASS (nm_setting_ip4_config_parent_class)->verify (setting, connection, error); + if (ret != NM_SETTING_VERIFY_SUCCESS) + return ret; + + method = nm_setting_ip_config_get_method (s_ip); + /* Base class already checked that it exists */ + g_assert (method); + + if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { + if (nm_setting_ip_config_get_num_addresses (s_ip) == 0) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("this property cannot be empty for '%s=%s'"), + NM_SETTING_IP_CONFIG_METHOD, method); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_ADDRESSES); + return FALSE; + } + } else if ( !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL) + || !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) + || !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) { + if (nm_setting_ip_config_get_num_dns (s_ip) > 0) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("this property is not allowed for '%s=%s'"), + NM_SETTING_IP_CONFIG_METHOD, method); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_DNS); + return FALSE; + } + + if (nm_setting_ip_config_get_num_dns_searches (s_ip) > 0) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("this property is not allowed for '%s=%s'"), + NM_SETTING_IP_CONFIG_METHOD, method); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_DNS_SEARCH); + return FALSE; + } + + /* Shared allows IP addresses; link-local and disabled do not */ + if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) != 0) { + if (nm_setting_ip_config_get_num_addresses (s_ip) > 0) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("this property is not allowed for '%s=%s'"), + NM_SETTING_IP_CONFIG_METHOD, method); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_ADDRESSES); + return FALSE; + } + } + } else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { + /* nothing to do */ + } else { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("property is invalid")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_METHOD); + return FALSE; + } + + if (priv->dhcp_client_id && !strlen (priv->dhcp_client_id)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("property is empty")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID); + return FALSE; + } + + return TRUE; +} + +static void +nm_setting_ip4_config_init (NMSettingIP4Config *setting) +{ +} + +static void +finalize (GObject *object) +{ + NMSettingIP4ConfigPrivate *priv = NM_SETTING_IP4_CONFIG_GET_PRIVATE (object); + + g_free (priv->dhcp_client_id); + + G_OBJECT_CLASS (nm_setting_ip4_config_parent_class)->finalize (object); +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMSettingIP4ConfigPrivate *priv = NM_SETTING_IP4_CONFIG_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_DHCP_CLIENT_ID: + g_free (priv->dhcp_client_id); + priv->dhcp_client_id = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMSettingIP4Config *s_ip4 = NM_SETTING_IP4_CONFIG (object); + + switch (prop_id) { + case PROP_DHCP_CLIENT_ID: + g_value_set_string (value, nm_setting_ip4_config_get_dhcp_client_id (s_ip4)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GVariant * +ip4_dns_to_dbus (const GValue *prop_value) +{ + return nm_utils_ip4_dns_to_variant (g_value_get_boxed (prop_value)); +} + +static void +ip4_dns_from_dbus (GVariant *dbus_value, + GValue *prop_value) +{ + g_value_take_boxed (prop_value, nm_utils_ip4_dns_from_variant (dbus_value)); +} + +static GVariant * +ip4_addresses_get (NMSetting *setting, + const char *property) +{ + GPtrArray *addrs; + const char *gateway; + GVariant *ret; + + g_object_get (setting, property, &addrs, NULL); + gateway = nm_setting_ip_config_get_gateway (NM_SETTING_IP_CONFIG (setting)); + ret = nm_utils_ip4_addresses_to_variant (addrs, gateway); + g_ptr_array_unref (addrs); + + return ret; +} + +static void +ip4_addresses_set (NMSetting *setting, + GVariant *connection_dict, + const char *property, + GVariant *value) +{ + GPtrArray *addrs; + GVariant *s_ip4; + char **labels, *gateway = NULL; + int i; + + if (!_nm_setting_use_legacy_property (setting, connection_dict, "addresses", "address-data")) + return; + + addrs = nm_utils_ip4_addresses_from_variant (value, &gateway); + + s_ip4 = g_variant_lookup_value (connection_dict, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING); + if (g_variant_lookup (s_ip4, "address-labels", "^as", &labels)) { + for (i = 0; i < addrs->len && labels[i]; i++) + if (*labels[i]) + nm_ip_address_set_attribute (addrs->pdata[i], "label", g_variant_new_string (labels[i])); + g_strfreev (labels); + } + g_variant_unref (s_ip4); + + g_object_set (setting, + NM_SETTING_IP_CONFIG_ADDRESSES, addrs, + NM_SETTING_IP_CONFIG_GATEWAY, gateway, + NULL); + g_ptr_array_unref (addrs); + g_free (gateway); +} + +static GVariant * +ip4_address_labels_get (NMSetting *setting, + NMConnection *connection, + const char *property) +{ + NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG (setting); + gboolean have_labels = FALSE; + GPtrArray *labels; + GVariant *ret; + int num_addrs, i; + + num_addrs = nm_setting_ip_config_get_num_addresses (s_ip); + for (i = 0; i < num_addrs; i++) { + NMIPAddress *addr = nm_setting_ip_config_get_address (s_ip, i); + GVariant *label = nm_ip_address_get_attribute (addr, "label"); + + if (label) { + have_labels = TRUE; + break; + } + } + if (!have_labels) + return NULL; + + labels = g_ptr_array_sized_new (num_addrs); + for (i = 0; i < num_addrs; i++) { + NMIPAddress *addr = nm_setting_ip_config_get_address (s_ip, i); + GVariant *label = nm_ip_address_get_attribute (addr, "label"); + + g_ptr_array_add (labels, (char *) (label ? g_variant_get_string (label, NULL) : "")); + } + + ret = g_variant_new_strv ((const char * const *) labels->pdata, labels->len); + g_ptr_array_unref (labels); + + return ret; +} + +static GVariant * +ip4_address_data_get (NMSetting *setting, + NMConnection *connection, + const char *property) +{ + GPtrArray *addrs; + GVariant *ret; + + g_object_get (setting, NM_SETTING_IP_CONFIG_ADDRESSES, &addrs, NULL); + ret = nm_utils_ip_addresses_to_variant (addrs); + g_ptr_array_unref (addrs); + + return ret; +} + +static void +ip4_address_data_set (NMSetting *setting, + GVariant *connection_dict, + const char *property, + GVariant *value) +{ + GPtrArray *addrs; + + /* Ignore 'address-data' if we're going to process 'addresses' */ + if (_nm_setting_use_legacy_property (setting, connection_dict, "addresses", "address-data")) + return; + + addrs = nm_utils_ip_addresses_from_variant (value, AF_INET); + g_object_set (setting, NM_SETTING_IP_CONFIG_ADDRESSES, addrs, NULL); + g_ptr_array_unref (addrs); +} + +static GVariant * +ip4_routes_get (NMSetting *setting, + const char *property) +{ + GPtrArray *routes; + GVariant *ret; + + g_object_get (setting, property, &routes, NULL); + ret = nm_utils_ip4_routes_to_variant (routes); + g_ptr_array_unref (routes); + + return ret; +} + +static void +ip4_routes_set (NMSetting *setting, + GVariant *connection_dict, + const char *property, + GVariant *value) +{ + GPtrArray *routes; + + if (!_nm_setting_use_legacy_property (setting, connection_dict, "routes", "route-data")) + return; + + routes = nm_utils_ip4_routes_from_variant (value); + g_object_set (setting, property, routes, NULL); + g_ptr_array_unref (routes); +} + +static GVariant * +ip4_route_data_get (NMSetting *setting, + NMConnection *connection, + const char *property) +{ + GPtrArray *routes; + GVariant *ret; + + g_object_get (setting, NM_SETTING_IP_CONFIG_ROUTES, &routes, NULL); + ret = nm_utils_ip_routes_to_variant (routes); + g_ptr_array_unref (routes); + + return ret; +} + +static void +ip4_route_data_set (NMSetting *setting, + GVariant *connection_dict, + const char *property, + GVariant *value) +{ + GPtrArray *routes; + + /* Ignore 'route-data' if we're going to process 'routes' */ + if (_nm_setting_use_legacy_property (setting, connection_dict, "routes", "route-data")) + return; + + routes = nm_utils_ip_routes_from_variant (value, AF_INET); + g_object_set (setting, NM_SETTING_IP_CONFIG_ROUTES, routes, NULL); + g_ptr_array_unref (routes); +} + + +static void +nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *ip4_class) +{ + NMSettingClass *setting_class = NM_SETTING_CLASS (ip4_class); + GObjectClass *object_class = G_OBJECT_CLASS (ip4_class); + + g_type_class_add_private (setting_class, sizeof (NMSettingIP4ConfigPrivate)); + + /* virtual methods */ + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->finalize = finalize; + setting_class->verify = verify; + + /* properties */ + + /* ---ifcfg-rh--- + * property: method + * variable: BOOTPROTO + * format: string + * values: none, dhcp (bootp), static, ibft, autoip, shared + * default: none + * description: Method used for IPv4 protocol configuration. + * ---end--- + */ + + /* ---keyfile--- + * property: dns + * format: list of DNS IP addresses + * description: List of DNS servers. + * example: dns=1.2.3.4;8.8.8.8;8.8.4.4; + * ---end--- + * ---ifcfg-rh--- + * property: dns + * variable: DNS1, DNS2, ... + * format: string + * description: List of DNS servers. Even if NetworkManager supports many DNS + * servers, initscripts and resolver only care about the first three, usually. + * example: DNS1=1.2.3.4 DNS2=10.0.0.254 DNS3=8.8.8.8 + * ---end--- + */ + + /* ---ifcfg-rh--- + * property: dns-search + * variable: DOMAIN + * format: string (space-separated domains) + * description: List of DNS search domains. + * ---end--- + */ + + /* ---keyfile--- + * property: addresses + * variable: address1, address2, ... + * format: address/plen + * description: List of static IP addresses. + * example: address1=192.168.100.100/24 address2=10.1.1.5/24 + * ---end--- + * ---ifcfg-rh--- + * property: addresses + * variable: IPADDR, PREFIX, IPADDR1, PREFIX1, ... + * description: List of static IP addresses. + * example: IPADDR=10.5.5.23 PREFIX=24 IPADDR1=1.1.1.2 PREFIX1=16 + * ---end--- + */ + + /* ---keyfile--- + * property: gateway + * variable: gateway + * format: string + * description: Gateway IP addresses as a string. + * example: gateway=192.168.100.1 + * ---end--- + * ---ifcfg-rh--- + * property: gateway + * variable: GATEWAY + * description: Gateway IP address. + * example: GATEWAY=10.5.5.1 + * ---end--- + */ + + /* ---keyfile--- + * property: routes + * variable: route1, route2, ... + * format: route/plen[,gateway,metric] + * description: List of IP routes. + * example: route1=8.8.8.0/24,10.1.1.1,77 + * route2=7.7.0.0/16 + * ---end--- + * ---ifcfg-rh--- + * property: routes + * variable: ADDRESS1, NETMASK1, GATEWAY1, METRIC1, ... + * description: List of static routes. They are not stored in ifcfg-* file, + * but in route-* file instead. + * ---end--- + */ + + /* ---ifcfg-rh--- + * property: ignore-auto-routes + * variable: PEERROUTES(+) + * default: yes + * description: PEERROUTES has the opposite meaning as 'ignore-auto-routes' property. + * ---end--- + */ + + /* ---ifcfg-rh--- + * property: ignore-auto-dns + * variable: PEERDNS + * default: yes + * description: PEERDNS has the opposite meaning as 'ignore-auto-dns' property. + * ---end--- + */ + + /* ---ifcfg-rh--- + * property: dhcp-send-hostname + * variable: DHCP_SEND_HOSTNAME(+) + * default: yes + * description: Whether DHCP_HOSTNAME should be sent to the DHCP server. + * ---end--- + */ + + /* ---ifcfg-rh--- + * property: dhcp-hostname + * variable: DHCP_HOSTNAME + * description: Hostname to send to the DHCP server. + * ---end--- + */ + + /* ---ifcfg-rh--- + * property: never-default + * variable: DEFROUTE (GATEWAYDEV in /etc/sysconfig/network) + * default: yes + * description: DEFROUTE=no tells NetworkManager that this connection + * should not be assigned the default route. DEFROUTE has the opposite + * meaning as 'never-default' property. + * ---end--- + */ + + /* ---ifcfg-rh--- + * property: may-fail + * variable: IPV4_FAILURE_FATAL(+) + * default: no + * description: IPV4_FAILURE_FATAL has the opposite meaning as 'may-fail' property. + * ---end--- + */ + + /** + * NMSettingIP4Config:dhcp-client-id: + * + * A string sent to the DHCP server to identify the local machine which the + * DHCP server may use to customize the DHCP lease and options. + **/ + /* ---ifcfg-rh--- + * property: dhcp-client-id + * variable: DHCP_CLIENT_ID(+) + * description: A string sent to the DHCP server to identify the local machine. + * example: DHCP_CLIENT_ID=ax-srv-1 + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_DHCP_CLIENT_ID, + g_param_spec_string (NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /* IP4-specific property overrides */ + + /* ---dbus--- + * property: dns + * format: array of uint32 + * description: Array of IP addresses of DNS servers (as network-byte-order + * integers) + * ---end--- + */ + _nm_setting_class_transform_property (setting_class, + NM_SETTING_IP_CONFIG_DNS, + G_VARIANT_TYPE ("au"), + ip4_dns_to_dbus, + ip4_dns_from_dbus); + + /* ---dbus--- + * property: addresses + * format: array of array of uint32 + * description: Deprecated in favor of the 'address-data' and 'gateway' + * properties, but this can be used for backward-compatibility with older + * daemons. Note that if you send this property the daemon will ignore + * 'address-data' and 'gateway'. + * + * Array of IPv4 address structures. Each IPv4 address structure is + * composed of 3 32-bit values; the first being the IPv4 address (network + * byte order), the second the prefix (1 - 32), and last the IPv4 gateway + * (network byte order). The gateway may be left as 0 if no gateway exists + * for that subnet. + * ---end--- + */ + _nm_setting_class_override_property (setting_class, + NM_SETTING_IP_CONFIG_ADDRESSES, + G_VARIANT_TYPE ("aau"), + ip4_addresses_get, + ip4_addresses_set, + NULL); + + _nm_setting_class_add_dbus_only_property (setting_class, + "address-labels", + G_VARIANT_TYPE_STRING_ARRAY, + ip4_address_labels_get, + NULL); + + /* ---dbus--- + * property: address-data + * format: array of vardict + * description: Array of IPv4 addresses. Each address dictionary contains at + * least 'address' and 'prefix' entries, containing the IP address as a + * string, and the prefix length as a uint32. Additional attributes may + * also exist on some addresses. + * ---end--- + */ + _nm_setting_class_add_dbus_only_property (setting_class, + "address-data", + G_VARIANT_TYPE ("aa{sv}"), + ip4_address_data_get, + ip4_address_data_set); + + /* ---dbus--- + * property: routes + * format: array of array of uint32 + * description: Deprecated in favor of the 'route-data' property, but this + * can be used for backward-compatibility with older daemons. Note that if + * you send this property the daemon will ignore 'route-data'. + * + * Array of IPv4 route structures. Each IPv4 route structure is composed + * of 4 32-bit values; the first being the destination IPv4 network or + * address (network byte order), the second the destination network or + * address prefix (1 - 32), the third being the next-hop (network byte + * order) if any, and the fourth being the route metric. If the metric is + * 0, NM will choose an appropriate default metric for the device. (There + * is no way to explicitly specify an actual metric of 0 with this + * property.) + * ---end--- + */ + _nm_setting_class_override_property (setting_class, + NM_SETTING_IP_CONFIG_ROUTES, + G_VARIANT_TYPE ("aau"), + ip4_routes_get, + ip4_routes_set, + NULL); + + /* ---dbus--- + * property: route-data + * format: array of vardict + * description: Array of IPv4 routes. Each route dictionary contains at + * least 'dest' and 'prefix' entries, containing the destination IP + * address as a string, and the prefix length as a uint32. Most routes + * will also have a 'gateway' entry, containing the gateway IP address as + * a string. If the route has a 'metric' entry (containing a uint32), that + * will be used as the metric for the route (otherwise NM will pick a + * default value appropriate to the device). Additional attributes may + * also exist on some routes. + * ---end--- + */ + _nm_setting_class_add_dbus_only_property (setting_class, + "route-data", + G_VARIANT_TYPE ("aa{sv}"), + ip4_route_data_get, + ip4_route_data_set); + +} |