/* -*- 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 2007 - 2014 Red Hat, Inc. * Copyright 2007 - 2008 Novell, Inc. */ #include "config.h" #include #include #include #include "nm-setting-ip-config.h" #include "nm-setting-ip4-config.h" #include "nm-setting-ip6-config.h" #include "nm-utils.h" #include "nm-glib-compat.h" #include "nm-setting-private.h" #include "nm-utils-private.h" /** * SECTION:nm-setting-ip-config * @short_description: Abstract base class for IPv4 and IPv6 * addressing, routing, and name service properties * @include: nm-setting-ip-config.h * @see_also: #NMSettingIP4Config, #NMSettingIP6Config * * #NMSettingIPConfig is the abstract base class of * #NMSettingIP4Config and #NMSettingIP6Config, providing properties * related to IP addressing, routing, and Domain Name Service. **/ static char * canonicalize_ip (int family, const char *ip, gboolean null_any) { guint8 addr_bytes[sizeof (struct in6_addr)]; char addr_str[NM_UTILS_INET_ADDRSTRLEN]; int ret; if (!ip) { g_return_val_if_fail (null_any == TRUE, NULL); return NULL; } ret = inet_pton (family, ip, addr_bytes); g_return_val_if_fail (ret == 1, NULL); if (null_any) { int addrlen = (family == AF_INET ? sizeof (struct in_addr) : sizeof (struct in6_addr)); if (!memcmp (addr_bytes, &in6addr_any, addrlen)) return NULL; } return g_strdup (inet_ntop (family, addr_bytes, addr_str, sizeof (addr_str))); } static gboolean valid_ip (int family, const char *ip, GError **error) { if (!nm_utils_ipaddr_valid (family, ip)) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, family == AF_INET ? _("Invalid IPv4 address '%s'") : _("Invalid IPv6 address '%s"), ip); return FALSE; } else return TRUE; } static gboolean valid_prefix (int family, guint prefix, GError **error, gboolean allow_zero_prefix) { if ( (family == AF_INET && prefix > 32) || (family == AF_INET6 && prefix > 128) || (!allow_zero_prefix && prefix == 0)) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, family == AF_INET ? _("Invalid IPv4 address prefix '%u'") : _("Invalid IPv6 address prefix '%u"), prefix); return FALSE; } return TRUE; } static gboolean valid_metric (gint64 metric, GError **error) { if (metric < -1 || metric > G_MAXUINT32) { if (error) { char buf[64]; /* We can't concatenate G_GINT64_FORMAT into a translatable string */ g_snprintf (buf, sizeof (buf), "%" G_GINT64_FORMAT, metric); g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, _("Invalid routing metric '%s'"), buf); } return FALSE; } return TRUE; } G_DEFINE_BOXED_TYPE (NMIPAddress, nm_ip_address, nm_ip_address_dup, nm_ip_address_unref) struct NMIPAddress { guint refcount; char *address; int prefix, family; GHashTable *attributes; }; /** * nm_ip_address_new: * @family: the IP address family (%AF_INET or %AF_INET6) * @addr: the IP address * @prefix: the address prefix length * @error: location to store error, or %NULL * * Creates a new #NMIPAddress object. * * Returns: (transfer full): the new #NMIPAddress object, or %NULL on error **/ NMIPAddress * nm_ip_address_new (int family, const char *addr, guint prefix, GError **error) { NMIPAddress *address; g_return_val_if_fail (family == AF_INET || family == AF_INET6, NULL); g_return_val_if_fail (addr != NULL, NULL); if (!valid_ip (family, addr, error)) return NULL; if (!valid_prefix (family, prefix, error, FALSE)) return NULL; address = g_slice_new0 (NMIPAddress); address->refcount = 1; address->family = family; address->address = canonicalize_ip (family, addr, FALSE); address->prefix = prefix; return address; } /** * nm_ip_address_new_binary: * @family: the IP address family (%AF_INET or %AF_INET6) * @addr: the IP address * @prefix: the address prefix length * @error: location to store error, or %NULL * * Creates a new #NMIPAddress object. @addr must point to a buffer of the * correct size for @family. * * Returns: (transfer full): the new #NMIPAddress object, or %NULL on error **/ NMIPAddress * nm_ip_address_new_binary (int family, gconstpointer addr, guint prefix, GError **error) { NMIPAddress *address; char string[NM_UTILS_INET_ADDRSTRLEN]; g_return_val_if_fail (family == AF_INET || family == AF_INET6, NULL); g_return_val_if_fail (addr != NULL, NULL); if (!valid_prefix (family, prefix, error, FALSE)) return NULL; address = g_slice_new0 (NMIPAddress); address->refcount = 1; address->family = family; address->address = g_strdup (inet_ntop (family, addr, string, sizeof (string))); address->prefix = prefix; return address; } /** * nm_ip_address_ref: * @address: the #NMIPAddress * * Increases the reference count of the object. **/ void nm_ip_address_ref (NMIPAddress *address) { g_return_if_fail (address != NULL); g_return_if_fail (address->refcount > 0); address->refcount++; } /** * nm_ip_address_unref: * @address: the #NMIPAddress * * Decreases the reference count of the object. If the reference count * reaches zero, the object will be destroyed. **/ void nm_ip_address_unref (NMIPAddress *address) { g_return_if_fail (address != NULL); g_return_if_fail (address->refcount > 0); address->refcount--; if (address->refcount == 0) { g_free (address->address); if (address->attributes) g_hash_table_unref (address->attributes); g_slice_free (NMIPAddress, address); } } /** * nm_ip_address_equal: * @address: the #NMIPAddress * @other: the #NMIPAddress to compare @address to. * * Determines if two #NMIPAddress objects contain the same address and prefix * (attributes are not compared). * * Returns: %TRUE if the objects contain the same values, %FALSE if they do not. **/ gboolean nm_ip_address_equal (NMIPAddress *address, NMIPAddress *other) { g_return_val_if_fail (address != NULL, FALSE); g_return_val_if_fail (address->refcount > 0, FALSE); g_return_val_if_fail (other != NULL, FALSE); g_return_val_if_fail (other->refcount > 0, FALSE); if ( address->family != other->family || address->prefix != other->prefix || strcmp (address->address, other->address) != 0) return FALSE; return TRUE; } /** * nm_ip_address_dup: * @address: the #NMIPAddress * * Creates a copy of @address * * Returns: (transfer full): a copy of @address **/ NMIPAddress * nm_ip_address_dup (NMIPAddress *address) { NMIPAddress *copy; g_return_val_if_fail (address != NULL, NULL); g_return_val_if_fail (address->refcount > 0, NULL); copy = nm_ip_address_new (address->family, address->address, address->prefix, NULL); if (address->attributes) { GHashTableIter iter; const char *key; GVariant *value; g_hash_table_iter_init (&iter, address->attributes); while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) nm_ip_address_set_attribute (copy, key, value); } return copy; } /** * nm_ip_address_get_family: * @address: the #NMIPAddress * * Gets the IP address family (eg, AF_INET) property of this address * object. * * Returns: the IP address family **/ int nm_ip_address_get_family (NMIPAddress *address) { g_return_val_if_fail (address != NULL, 0); g_return_val_if_fail (address->refcount > 0, 0); return address->family; } /** * nm_ip_address_get_address: * @address: the #NMIPAddress * * Gets the IP address property of this address object. * * Returns: the IP address **/ const char * nm_ip_address_get_address (NMIPAddress *address) { g_return_val_if_fail (address != NULL, NULL); g_return_val_if_fail (address->refcount > 0, NULL); return address->address; } /** * nm_ip_address_set_address: * @address: the #NMIPAddress * @addr: the IP address, as a string * * Sets the IP address property of this address object. * * @addr must be a valid address of @address's family. If you aren't sure you * have a valid address, use nm_utils_ipaddr_valid() to check it. **/ void nm_ip_address_set_address (NMIPAddress *address, const char *addr) { g_return_if_fail (address != NULL); g_return_if_fail (addr != NULL); g_return_if_fail (nm_utils_ipaddr_valid (address->family, addr)); g_free (address->address); address->address = canonicalize_ip (address->family, addr, FALSE); } /** * nm_ip_address_get_address_binary: (skip) * @address: the #NMIPAddress * @addr: a buffer in which to store the address in binary format. * * Gets the IP address property of this address object. * * @addr must point to a buffer that is the correct size for @address's family. **/ void nm_ip_address_get_address_binary (NMIPAddress *address, gpointer addr) { g_return_if_fail (address != NULL); g_return_if_fail (addr != NULL); inet_pton (address->family, address->address, addr); } /** * nm_ip_address_set_address_binary: (skip) * @address: the #NMIPAddress * @addr: the address, in binary format * * Sets the IP address property of this address object. * * @addr must point to a buffer that is the correct size for @address's family. **/ void nm_ip_address_set_address_binary (NMIPAddress *address, gconstpointer addr) { char string[NM_UTILS_INET_ADDRSTRLEN]; g_return_if_fail (address != NULL); g_return_if_fail (addr != NULL); g_free (address->address); address->address = g_strdup (inet_ntop (address->family, addr, string, sizeof (string))); } /** * nm_ip_address_get_prefix: * @address: the #NMIPAddress * * Gets the IP address prefix (ie "24" or "30" etc) property of this address * object. * * Returns: the IP address prefix **/ guint nm_ip_address_get_prefix (NMIPAddress *address) { g_return_val_if_fail (address != NULL, 0); g_return_val_if_fail (address->refcount > 0, 0); return address->prefix; } /** * nm_ip_address_set_prefix: * @address: the #NMIPAddress * @prefix: the IP address prefix * * Sets the IP address prefix property of this address object. **/ void nm_ip_address_set_prefix (NMIPAddress *address, guint prefix) { g_return_if_fail (address != NULL); g_return_if_fail (valid_prefix (address->family, prefix, NULL, FALSE)); address->prefix = prefix; } /** * nm_ip_address_get_attribute_names: * @address: the #NMIPAddress * * Gets an array of attribute names defined on @address. * * Returns: (transfer full): a %NULL-terminated array of attribute names, **/ char ** nm_ip_address_get_attribute_names (NMIPAddress *address) { GHashTableIter iter; const char *key; GPtrArray *names; g_return_val_if_fail (address != NULL, NULL); names = g_ptr_array_new (); if (address->attributes) { g_hash_table_iter_init (&iter, address->attributes); while (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) g_ptr_array_add (names, g_strdup (key)); } g_ptr_array_add (names, NULL); return (char **) g_ptr_array_free (names, FALSE); } /** * nm_ip_address_get_attribute: * @address: the #NMIPAddress * @name: the name of an address attribute * * Gets the value of the attribute with name @name on @address * * Returns: (transfer none): the value of the attribute with name @name on * @address, or %NULL if @address has no such attribute. **/ GVariant * nm_ip_address_get_attribute (NMIPAddress *address, const char *name) { g_return_val_if_fail (address != NULL, NULL); g_return_val_if_fail (name != NULL && *name != '\0', NULL); if (address->attributes) return g_hash_table_lookup (address->attributes, name); else return NULL; } /** * nm_ip_address_set_attribute: * @address: the #NMIPAddress * @name: the name of an address attribute * @value: (transfer none) (allow-none): the value * * Sets or clears the named attribute on @address to the given value. **/ void nm_ip_address_set_attribute (NMIPAddress *address, const char *name, GVariant *value) { g_return_if_fail (address != NULL); g_return_if_fail (name != NULL && *name != '\0'); g_return_if_fail (strcmp (name, "address") != 0 && strcmp (name, "prefix") != 0); if (!address->attributes) { address->attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref); } if (value) g_hash_table_insert (address->attributes, g_strdup (name), g_variant_ref_sink (value)); else g_hash_table_remove (address->attributes, name); } G_DEFINE_BOXED_TYPE (NMIPRoute, nm_ip_route, nm_ip_route_dup, nm_ip_route_unref) struct NMIPRoute { guint refcount; int family; char *dest; guint prefix; char *next_hop; gint64 metric; GHashTable *attributes; }; /** * nm_ip_route_new: * @family: the IP address family (%AF_INET or %AF_INET6) * @dest: the IP address of the route's destination * @prefix: the address prefix length * @next_hop: (allow-none): the IP address of the next hop (or %NULL) * @metric: the route metric (or -1 for "default") * @error: location to store error, or %NULL * * Creates a new #NMIPRoute object. * * Returns: (transfer full): the new #NMIPRoute object, or %NULL on error **/ NMIPRoute * nm_ip_route_new (int family, const char *dest, guint prefix, const char *next_hop, gint64 metric, GError **error) { NMIPRoute *route; g_return_val_if_fail (family == AF_INET || family == AF_INET6, NULL); if (!valid_ip (family, dest, error)) return NULL; if (!valid_prefix (family, prefix, error, TRUE)) return NULL; if (next_hop && !valid_ip (family, next_hop, error)) return NULL; if (!valid_metric (metric, error)) return NULL; route = g_slice_new0 (NMIPRoute); route->refcount = 1; route->family = family; route->dest = canonicalize_ip (family, dest, FALSE); route->prefix = prefix; route->next_hop = canonicalize_ip (family, next_hop, TRUE); route->metric = metric; return route; } /** * nm_ip_route_new_binary: * @family: the IP address family (%AF_INET or %AF_INET6) * @dest: the IP address of the route's destination * @prefix: the address prefix length * @next_hop: (allow-none): the IP address of the next hop (or %NULL) * @metric: the route metric (or -1 for "default") * @error: location to store error, or %NULL * * Creates a new #NMIPRoute object. @dest and @next_hop (if non-%NULL) must * point to buffers of the correct size for @family. * * Returns: (transfer full): the new #NMIPRoute object, or %NULL on error **/ NMIPRoute * nm_ip_route_new_binary (int family, gconstpointer dest, guint prefix, gconstpointer next_hop, gint64 metric, GError **error) { NMIPRoute *route; char string[NM_UTILS_INET_ADDRSTRLEN]; g_return_val_if_fail (family == AF_INET || family == AF_INET6, NULL); if (!valid_prefix (family, prefix, error, TRUE)) return NULL; if (!valid_metric (metric, error)) return NULL; route = g_slice_new0 (NMIPRoute); route->refcount = 1; route->family = family; route->dest = g_strdup (inet_ntop (family, dest, string, sizeof (string))); route->prefix = prefix; if (next_hop) route->next_hop = g_strdup (inet_ntop (family, next_hop, string, sizeof (string))); route->metric = metric; return route; } /** * nm_ip_route_ref: * @route: the #NMIPRoute * * Increases the reference count of the object. **/ void nm_ip_route_ref (NMIPRoute *route) { g_return_if_fail (route != NULL); g_return_if_fail (route->refcount > 0); route->refcount++; } /** * nm_ip_route_unref: * @route: the #NMIPRoute * * Decreases the reference count of the object. If the reference count * reaches zero, the object will be destroyed. **/ void nm_ip_route_unref (NMIPRoute *route) { g_return_if_fail (route != NULL); g_return_if_fail (route->refcount > 0); route->refcount--; if (route->refcount == 0) { g_free (route->dest); g_free (route->next_hop); if (route->attributes) g_hash_table_unref (route->attributes); g_slice_free (NMIPRoute, route); } } /** * nm_ip_route_equal: * @route: the #NMIPRoute * @other: the #NMIPRoute to compare @route to. * * Determines if two #NMIPRoute objects contain the same destination, prefix, * next hop, and metric. (Attributes are not compared.) * * Returns: %TRUE if the objects contain the same values, %FALSE if they do not. **/ gboolean nm_ip_route_equal (NMIPRoute *route, NMIPRoute *other) { g_return_val_if_fail (route != NULL, FALSE); g_return_val_if_fail (route->refcount > 0, FALSE); g_return_val_if_fail (other != NULL, FALSE); g_return_val_if_fail (other->refcount > 0, FALSE); if ( route->prefix != other->prefix || route->metric != other->metric || strcmp (route->dest, other->dest) != 0 || g_strcmp0 (route->next_hop, other->next_hop) != 0) return FALSE; return TRUE; } /** * nm_ip_route_dup: * @route: the #NMIPRoute * * Creates a copy of @route * * Returns: (transfer full): a copy of @route **/ NMIPRoute * nm_ip_route_dup (NMIPRoute *route) { NMIPRoute *copy; g_return_val_if_fail (route != NULL, NULL); g_return_val_if_fail (route->refcount > 0, NULL); copy = nm_ip_route_new (route->family, route->dest, route->prefix, route->next_hop, route->metric, NULL); if (route->attributes) { GHashTableIter iter; const char *key; GVariant *value; g_hash_table_iter_init (&iter, route->attributes); while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) nm_ip_route_set_attribute (copy, key, value); } return copy; } /** * nm_ip_route_get_family: * @route: the #NMIPRoute * * Gets the IP address family (eg, AF_INET) property of this route * object. * * Returns: the IP address family **/ int nm_ip_route_get_family (NMIPRoute *route) { g_return_val_if_fail (route != NULL, 0); g_return_val_if_fail (route->refcount > 0, 0); return route->family; } /** * nm_ip_route_get_dest: * @route: the #NMIPRoute * * Gets the IP destination address property of this route object. * * Returns: the IP address of the route's destination **/ const char * nm_ip_route_get_dest (NMIPRoute *route) { g_return_val_if_fail (route != NULL, NULL); g_return_val_if_fail (route->refcount > 0, NULL); return route->dest; } /** * nm_ip_route_set_dest: * @route: the #NMIPRoute * @dest: the route's destination, as a string * * Sets the destination property of this route object. * * @dest must be a valid address of @route's family. If you aren't sure you * have a valid address, use nm_utils_ipaddr_valid() to check it. **/ void nm_ip_route_set_dest (NMIPRoute *route, const char *dest) { g_return_if_fail (route != NULL); g_return_if_fail (dest != NULL); g_return_if_fail (nm_utils_ipaddr_valid (route->family, dest)); g_free (route->dest); route->dest = canonicalize_ip (route->family, dest, FALSE); } /** * nm_ip_route_get_dest_binary: (skip) * @route: the #NMIPRoute * @dest: a buffer in which to store the destination in binary format. * * Gets the destination property of this route object. * * @dest must point to a buffer that is the correct size for @route's family. **/ void nm_ip_route_get_dest_binary (NMIPRoute *route, gpointer dest) { g_return_if_fail (route != NULL); g_return_if_fail (dest != NULL); inet_pton (route->family, route->dest, dest); } /** * nm_ip_route_set_dest_binary: (skip) * @route: the #NMIPRoute * @dest: the route's destination, in binary format * * Sets the destination property of this route object. * * @dest must point to a buffer that is the correct size for @route's family. **/ void nm_ip_route_set_dest_binary (NMIPRoute *route, gconstpointer dest) { char string[NM_UTILS_INET_ADDRSTRLEN]; g_return_if_fail (route != NULL); g_return_if_fail (dest != NULL); g_free (route->dest); route->dest = g_strdup (inet_ntop (route->family, dest, string, sizeof (string))); } /** * nm_ip_route_get_prefix: * @route: the #NMIPRoute * * Gets the IP prefix (ie "24" or "30" etc) of this route. * * Returns: the IP prefix **/ guint nm_ip_route_get_prefix (NMIPRoute *route) { g_return_val_if_fail (route != NULL, 0); g_return_val_if_fail (route->refcount > 0, 0); return route->prefix; } /** * nm_ip_route_set_prefix: * @route: the #NMIPRoute * @prefix: the route prefix * * Sets the prefix property of this route object. **/ void nm_ip_route_set_prefix (NMIPRoute *route, guint prefix) { g_return_if_fail (route != NULL); g_return_if_fail (valid_prefix (route->family, prefix, NULL, TRUE)); route->prefix = prefix; } /** * nm_ip_route_get_next_hop: * @route: the #NMIPRoute * * Gets the IP address of the next hop of this route; this will be %NULL if the * route has no next hop. * * Returns: the IP address of the next hop, or %NULL if this is a device route. **/ const char * nm_ip_route_get_next_hop (NMIPRoute *route) { g_return_val_if_fail (route != NULL, NULL); g_return_val_if_fail (route->refcount > 0, NULL); return route->next_hop; } /** * nm_ip_route_set_next_hop: * @route: the #NMIPRoute * @next_hop: (allow-none): the route's next hop, as a string * * Sets the next-hop property of this route object. * * @next_hop (if non-%NULL) must be a valid address of @route's family. If you * aren't sure you have a valid address, use nm_utils_ipaddr_valid() to check * it. **/ void nm_ip_route_set_next_hop (NMIPRoute *route, const char *next_hop) { g_return_if_fail (route != NULL); g_return_if_fail (!next_hop || nm_utils_ipaddr_valid (route->family, next_hop)); g_free (route->next_hop); route->next_hop = canonicalize_ip (route->family, next_hop, TRUE); } /** * nm_ip_route_get_next_hop_binary: (skip) * @route: the #NMIPRoute * @next_hop: a buffer in which to store the next hop in binary format. * * Gets the next hop property of this route object. * * @next_hop must point to a buffer that is the correct size for @route's family. * * Returns: %TRUE if @route has a next hop, %FALSE if not (in which case * @next_hop will be zeroed out) **/ gboolean nm_ip_route_get_next_hop_binary (NMIPRoute *route, gpointer next_hop) { g_return_val_if_fail (route != NULL, FALSE); g_return_val_if_fail (next_hop != NULL, FALSE); if (route->next_hop) { inet_pton (route->family, route->next_hop, next_hop); return TRUE; } else { memset (next_hop, 0, route->family == AF_INET ? sizeof (struct in_addr) : sizeof (struct in6_addr)); return FALSE; } } /** * nm_ip_route_set_next_hop_binary: (skip) * @route: the #NMIPRoute * @next_hop: the route's next hop, in binary format * * Sets the destination property of this route object. * * @next_hop (if non-%NULL) must point to a buffer that is the correct size for * @route's family. **/ void nm_ip_route_set_next_hop_binary (NMIPRoute *route, gconstpointer next_hop) { char string[NM_UTILS_INET_ADDRSTRLEN]; g_return_if_fail (route != NULL); g_free (route->next_hop); if (next_hop) route->next_hop = g_strdup (inet_ntop (route->family, next_hop, string, sizeof (string))); else route->next_hop = NULL; } /** * nm_ip_route_get_metric: * @route: the #NMIPRoute * * Gets the route metric property of this route object; lower values * indicate "better" or more preferred routes; -1 indicates "default" * (meaning NetworkManager will set it appropriately). * * Returns: the route metric **/ gint64 nm_ip_route_get_metric (NMIPRoute *route) { g_return_val_if_fail (route != NULL, 0); g_return_val_if_fail (route->refcount > 0, 0); return route->metric; } /** * nm_ip_route_set_metric: * @route: the #NMIPRoute * @metric: the route metric (or -1 for "default") * * Sets the metric property of this route object. **/ void nm_ip_route_set_metric (NMIPRoute *route, gint64 metric) { g_return_if_fail (route != NULL); g_return_if_fail (valid_metric (metric, NULL)); route->metric = metric; } /** * nm_ip_route_get_attribute_names: * @route: the #NMIPRoute * * Gets an array of attribute names defined on @route. * * Returns: (transfer full): a %NULL-terminated array of attribute names **/ char ** nm_ip_route_get_attribute_names (NMIPRoute *route) { GHashTableIter iter; const char *key; GPtrArray *names; g_return_val_if_fail (route != NULL, NULL); names = g_ptr_array_new (); if (route->attributes) { g_hash_table_iter_init (&iter, route->attributes); while (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) g_ptr_array_add (names, g_strdup (key)); } g_ptr_array_add (names, NULL); return (char **) g_ptr_array_free (names, FALSE); } /** * nm_ip_route_get_attribute: * @route: the #NMIPRoute * @name: the name of an route attribute * * Gets the value of the attribute with name @name on @route * * Returns: (transfer none): the value of the attribute with name @name on * @route, or %NULL if @route has no such attribute. **/ GVariant * nm_ip_route_get_attribute (NMIPRoute *route, const char *name) { g_return_val_if_fail (route != NULL, NULL); g_return_val_if_fail (name != NULL && *name != '\0', NULL); if (route->attributes) return g_hash_table_lookup (route->attributes, name); else return NULL; } /** * nm_ip_route_set_attribute: * @route: the #NMIPRoute * @name: the name of a route attribute * @value: (transfer none) (allow-none): the value * * Sets the named attribute on @route to the given value. **/ void nm_ip_route_set_attribute (NMIPRoute *route, const char *name, GVariant *value) { g_return_if_fail (route != NULL); g_return_if_fail (name != NULL && *name != '\0'); g_return_if_fail ( strcmp (name, "dest") != 0 && strcmp (name, "prefix") != 0 && strcmp (name, "next-hop") != 0 && strcmp (name, "metric") != 0); if (!route->attributes) { route->attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref); } if (value) g_hash_table_insert (route->attributes, g_strdup (name), g_variant_ref_sink (value)); else g_hash_table_remove (route->attributes, name); } G_DEFINE_ABSTRACT_TYPE (NMSettingIPConfig, nm_setting_ip_config, NM_TYPE_SETTING) #define NM_SETTING_IP_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_IP_CONFIG, NMSettingIPConfigPrivate)) typedef struct { char *method; GPtrArray *dns; /* array of IP address strings */ GPtrArray *dns_search; /* array of domain name strings */ GPtrArray *addresses; /* array of NMIPAddress */ GPtrArray *routes; /* array of NMIPRoute */ gint64 route_metric; char *gateway; gboolean ignore_auto_routes; gboolean ignore_auto_dns; char *dhcp_hostname; gboolean dhcp_send_hostname; gboolean never_default; gboolean may_fail; } NMSettingIPConfigPrivate; enum { PROP_0, PROP_METHOD, PROP_DNS, PROP_DNS_SEARCH, PROP_ADDRESSES, PROP_GATEWAY, PROP_ROUTES, PROP_ROUTE_METRIC, PROP_IGNORE_AUTO_ROUTES, PROP_IGNORE_AUTO_DNS, PROP_DHCP_HOSTNAME, PROP_DHCP_SEND_HOSTNAME, PROP_NEVER_DEFAULT, PROP_MAY_FAIL, LAST_PROP }; #define NM_SETTING_IP_CONFIG_GET_FAMILY(setting) (NM_IS_SETTING_IP4_CONFIG (setting) ? AF_INET : AF_INET6) /** * nm_setting_ip_config_get_method: * @setting: the #NMSettingIPConfig * * Returns: the #NMSettingIPConfig:method property of the setting; see * #NMSettingIP4Config and #NMSettingIP6Config for details of the * methods available with each type. **/ const char * nm_setting_ip_config_get_method (NMSettingIPConfig *setting) { g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL); return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->method; } /** * nm_setting_ip_config_get_num_dns: * @setting: the #NMSettingIPConfig * * Returns: the number of configured DNS servers **/ guint nm_setting_ip_config_get_num_dns (NMSettingIPConfig *setting) { g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), 0); return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->dns->len; } /** * nm_setting_ip_config_get_dns: * @setting: the #NMSettingIPConfig * @i: index number of the DNS server to return * * Returns: the IP address of the DNS server at index @i **/ const char * nm_setting_ip_config_get_dns (NMSettingIPConfig *setting, int i) { NMSettingIPConfigPrivate *priv; g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); g_return_val_if_fail (i < priv->dns->len, NULL); return priv->dns->pdata[i]; } /** * nm_setting_ip_config_add_dns: * @setting: the #NMSettingIPConfig * @dns: the IP address of the DNS server to add * * Adds a new DNS server to the setting. * * Returns: %TRUE if the DNS server was added; %FALSE if the server was already * known **/ gboolean nm_setting_ip_config_add_dns (NMSettingIPConfig *setting, const char *dns) { NMSettingIPConfigPrivate *priv; char *dns_canonical; int i; g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); g_return_val_if_fail (dns != NULL, FALSE); g_return_val_if_fail (nm_utils_ipaddr_valid (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), dns), FALSE); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); dns_canonical = canonicalize_ip (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), dns, FALSE); for (i = 0; i < priv->dns->len; i++) { if (!strcmp (dns_canonical, priv->dns->pdata[i])) { g_free (dns_canonical); return FALSE; } } g_ptr_array_add (priv->dns, dns_canonical); g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS); return TRUE; } /** * nm_setting_ip_config_remove_dns: * @setting: the #NMSettingIPConfig * @i: index number of the DNS server to remove * * Removes the DNS server at index @i. **/ void nm_setting_ip_config_remove_dns (NMSettingIPConfig *setting, int i) { NMSettingIPConfigPrivate *priv; g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting)); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); g_return_if_fail (i < priv->dns->len); g_ptr_array_remove_index (priv->dns, i); g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS); } /** * nm_setting_ip_config_remove_dns_by_value: * @setting: the #NMSettingIPConfig * @dns: the DNS server to remove * * Removes the DNS server @dns. * * Returns: %TRUE if the DNS server was found and removed; %FALSE if it was not. **/ gboolean nm_setting_ip_config_remove_dns_by_value (NMSettingIPConfig *setting, const char *dns) { NMSettingIPConfigPrivate *priv; char *dns_canonical; int i; g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); g_return_val_if_fail (dns != NULL, FALSE); g_return_val_if_fail (nm_utils_ipaddr_valid (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), dns), FALSE); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); dns_canonical = canonicalize_ip (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), dns, FALSE); for (i = 0; i < priv->dns->len; i++) { if (!strcmp (dns_canonical, priv->dns->pdata[i])) { g_ptr_array_remove_index (priv->dns, i); g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS); g_free (dns_canonical); return TRUE; } } g_free (dns_canonical); return FALSE; } /** * nm_setting_ip_config_clear_dns: * @setting: the #NMSettingIPConfig * * Removes all configured DNS servers. **/ void nm_setting_ip_config_clear_dns (NMSettingIPConfig *setting) { NMSettingIPConfigPrivate *priv; g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting)); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); g_ptr_array_set_size (priv->dns, 0); g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS); } /** * nm_setting_ip_config_get_num_dns_searches: * @setting: the #NMSettingIPConfig * * Returns: the number of configured DNS search domains **/ guint nm_setting_ip_config_get_num_dns_searches (NMSettingIPConfig *setting) { g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), 0); return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->dns_search->len; } /** * nm_setting_ip_config_get_dns_search: * @setting: the #NMSettingIPConfig * @i: index number of the DNS search domain to return * * Returns: the DNS search domain at index @i **/ const char * nm_setting_ip_config_get_dns_search (NMSettingIPConfig *setting, int i) { NMSettingIPConfigPrivate *priv; g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); g_return_val_if_fail (i < priv->dns_search->len, NULL); return priv->dns_search->pdata[i]; } /** * nm_setting_ip_config_add_dns_search: * @setting: the #NMSettingIPConfig * @dns_search: the search domain to add * * Adds a new DNS search domain to the setting. * * Returns: %TRUE if the DNS search domain was added; %FALSE if the search * domain was already known **/ gboolean nm_setting_ip_config_add_dns_search (NMSettingIPConfig *setting, const char *dns_search) { NMSettingIPConfigPrivate *priv; int i; g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); g_return_val_if_fail (dns_search != NULL, FALSE); g_return_val_if_fail (dns_search[0] != '\0', FALSE); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); for (i = 0; i < priv->dns_search->len; i++) { if (!strcmp (dns_search, priv->dns_search->pdata[i])) return FALSE; } g_ptr_array_add (priv->dns_search, g_strdup (dns_search)); g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_SEARCH); return TRUE; } /** * nm_setting_ip_config_remove_dns_search: * @setting: the #NMSettingIPConfig * @i: index number of the DNS search domain * * Removes the DNS search domain at index @i. **/ void nm_setting_ip_config_remove_dns_search (NMSettingIPConfig *setting, int i) { NMSettingIPConfigPrivate *priv; g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting)); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); g_return_if_fail (i < priv->dns_search->len); g_ptr_array_remove_index (priv->dns_search, i); g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_SEARCH); } /** * nm_setting_ip_config_remove_dns_search_by_value: * @setting: the #NMSettingIPConfig * @dns_search: the search domain to remove * * Removes the DNS search domain @dns_search. * * Returns: %TRUE if the DNS search domain was found and removed; %FALSE if it was not. * * Since 0.9.10 **/ gboolean nm_setting_ip_config_remove_dns_search_by_value (NMSettingIPConfig *setting, const char *dns_search) { NMSettingIPConfigPrivate *priv; int i; g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); g_return_val_if_fail (dns_search != NULL, FALSE); g_return_val_if_fail (dns_search[0] != '\0', FALSE); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); for (i = 0; i < priv->dns_search->len; i++) { if (!strcmp (dns_search, priv->dns_search->pdata[i])) { g_ptr_array_remove_index (priv->dns_search, i); g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_SEARCH); return TRUE; } } return FALSE; } /** * nm_setting_ip_config_clear_dns_searches: * @setting: the #NMSettingIPConfig * * Removes all configured DNS search domains. **/ void nm_setting_ip_config_clear_dns_searches (NMSettingIPConfig *setting) { NMSettingIPConfigPrivate *priv; g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting)); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); g_ptr_array_set_size (priv->dns_search, 0); g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_SEARCH); } /** * nm_setting_ip_config_get_num_addresses: * @setting: the #NMSettingIPConfig * * Returns: the number of configured addresses **/ guint nm_setting_ip_config_get_num_addresses (NMSettingIPConfig *setting) { g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), 0); return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->addresses->len; } /** * nm_setting_ip_config_get_address: * @setting: the #NMSettingIPConfig * @i: index number of the address to return * * Returns: the address at index @i **/ NMIPAddress * nm_setting_ip_config_get_address (NMSettingIPConfig *setting, int i) { NMSettingIPConfigPrivate *priv; g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); g_return_val_if_fail (i < priv->addresses->len, NULL); return priv->addresses->pdata[i]; } /** * nm_setting_ip_config_add_address: * @setting: the #NMSettingIPConfig * @address: the new address to add * * Adds a new IP address and associated information to the setting. The * given address is duplicated internally and is not changed by this function. * * Returns: %TRUE if the address was added; %FALSE if the address was already * known. **/ gboolean nm_setting_ip_config_add_address (NMSettingIPConfig *setting, NMIPAddress *address) { NMSettingIPConfigPrivate *priv; int i; g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); g_return_val_if_fail (address != NULL, FALSE); g_return_val_if_fail (address->family == NM_SETTING_IP_CONFIG_GET_FAMILY (setting), FALSE); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); for (i = 0; i < priv->addresses->len; i++) { if (nm_ip_address_equal (priv->addresses->pdata[i], address)) return FALSE; } g_ptr_array_add (priv->addresses, nm_ip_address_dup (address)); g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ADDRESSES); return TRUE; } /** * nm_setting_ip_config_remove_address: * @setting: the #NMSettingIPConfig * @i: index number of the address to remove * * Removes the address at index @i. **/ void nm_setting_ip_config_remove_address (NMSettingIPConfig *setting, int i) { NMSettingIPConfigPrivate *priv; g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting)); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); g_return_if_fail (i < priv->addresses->len); g_ptr_array_remove_index (priv->addresses, i); g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ADDRESSES); } /** * nm_setting_ip_config_remove_address_by_value: * @setting: the #NMSettingIPConfig * @address: the IP address to remove * * Removes the address @address. * * Returns: %TRUE if the address was found and removed; %FALSE if it was not. **/ gboolean nm_setting_ip_config_remove_address_by_value (NMSettingIPConfig *setting, NMIPAddress *address) { NMSettingIPConfigPrivate *priv; int i; g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); g_return_val_if_fail (address != NULL, FALSE); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); for (i = 0; i < priv->addresses->len; i++) { if (nm_ip_address_equal (priv->addresses->pdata[i], address)) { g_ptr_array_remove_index (priv->addresses, i); g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ADDRESSES); return TRUE; } } return FALSE; } /** * nm_setting_ip_config_clear_addresses: * @setting: the #NMSettingIPConfig * * Removes all configured addresses. **/ void nm_setting_ip_config_clear_addresses (NMSettingIPConfig *setting) { NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting)); g_ptr_array_set_size (priv->addresses, 0); g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ADDRESSES); } /** * nm_setting_ip_config_get_gateway: * @setting: the #NMSettingIPConfig * * Returns: the IP address of the gateway associated with this configuration, or * %NULL. **/ const char * nm_setting_ip_config_get_gateway (NMSettingIPConfig *setting) { g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL); return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->gateway; } /** * nm_setting_ip_config_get_num_routes: * @setting: the #NMSettingIPConfig * * Returns: the number of configured routes **/ guint nm_setting_ip_config_get_num_routes (NMSettingIPConfig *setting) { g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), 0); return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->routes->len; } /** * nm_setting_ip_config_get_route: * @setting: the #NMSettingIPConfig * @i: index number of the route to return * * Returns: the route at index @i **/ NMIPRoute * nm_setting_ip_config_get_route (NMSettingIPConfig *setting, int i) { NMSettingIPConfigPrivate *priv; g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); g_return_val_if_fail (i < priv->routes->len, NULL); return priv->routes->pdata[i]; } /** * nm_setting_ip_config_add_route: * @setting: the #NMSettingIPConfig * @route: the route to add * * Adds a new route and associated information to the setting. The * given route is duplicated internally and is not changed by this function. * * Returns: %TRUE if the route was added; %FALSE if the route was already known. **/ gboolean nm_setting_ip_config_add_route (NMSettingIPConfig *setting, NMIPRoute *route) { NMSettingIPConfigPrivate *priv; int i; g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); g_return_val_if_fail (route != NULL, FALSE); g_return_val_if_fail (route->family == NM_SETTING_IP_CONFIG_GET_FAMILY (setting), FALSE); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); for (i = 0; i < priv->routes->len; i++) { if (nm_ip_route_equal (priv->routes->pdata[i], route)) return FALSE; } g_ptr_array_add (priv->routes, nm_ip_route_dup (route)); g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ROUTES); return TRUE; } /** * nm_setting_ip_config_remove_route: * @setting: the #NMSettingIPConfig * @i: index number of the route * * Removes the route at index @i. **/ void nm_setting_ip_config_remove_route (NMSettingIPConfig *setting, int i) { NMSettingIPConfigPrivate *priv; g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting)); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); g_return_if_fail (i < priv->routes->len); g_ptr_array_remove_index (priv->routes, i); g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ROUTES); } /** * nm_setting_ip_config_remove_route_by_value: * @setting: the #NMSettingIPConfig * @route: the route to remove * * Removes the route @route. * * Returns: %TRUE if the route was found and removed; %FALSE if it was not. **/ gboolean nm_setting_ip_config_remove_route_by_value (NMSettingIPConfig *setting, NMIPRoute *route) { NMSettingIPConfigPrivate *priv; int i; g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); g_return_val_if_fail (route != NULL, FALSE); priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); for (i = 0; i < priv->routes->len; i++) { if (nm_ip_route_equal (priv->routes->pdata[i], route)) { g_ptr_array_remove_index (priv->routes, i); g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ROUTES); return TRUE; } } return FALSE; } /** * nm_setting_ip_config_clear_routes: * @setting: the #NMSettingIPConfig * * Removes all configured routes. **/ void nm_setting_ip_config_clear_routes (NMSettingIPConfig *setting) { NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting)); g_ptr_array_set_size (priv->routes, 0); g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ROUTES); } /** * nm_setting_ip_config_get_route_metric: * @setting: the #NMSettingIPConfig * * Returns the value contained in the #NMSettingIPConfig:route-metric * property. * * Returns: the route metric that is used for routes that don't explicitly * specify a metric. See #NMSettingIPConfig:route-metric for more details. **/ gint64 nm_setting_ip_config_get_route_metric (NMSettingIPConfig *setting) { g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), -1); return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->route_metric; } /** * nm_setting_ip_config_get_ignore_auto_routes: * @setting: the #NMSettingIPConfig * * Returns the value contained in the #NMSettingIPConfig:ignore-auto-routes * property. * * Returns: %TRUE if automatically configured (ie via DHCP) routes should be * ignored. **/ gboolean nm_setting_ip_config_get_ignore_auto_routes (NMSettingIPConfig *setting) { g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->ignore_auto_routes; } /** * nm_setting_ip_config_get_ignore_auto_dns: * @setting: the #NMSettingIPConfig * * Returns the value contained in the #NMSettingIPConfig:ignore-auto-dns * property. * * Returns: %TRUE if automatically configured (ie via DHCP) DNS information * should be ignored. **/ gboolean nm_setting_ip_config_get_ignore_auto_dns (NMSettingIPConfig *setting) { g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->ignore_auto_dns; } /** * nm_setting_ip_config_get_dhcp_hostname: * @setting: the #NMSettingIPConfig * * Returns the value contained in the #NMSettingIPConfig:dhcp-hostname * property. * * Returns: the configured hostname to send to the DHCP server **/ const char * nm_setting_ip_config_get_dhcp_hostname (NMSettingIPConfig *setting) { g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL); return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->dhcp_hostname; } /** * nm_setting_ip_config_get_dhcp_send_hostname: * @setting: the #NMSettingIPConfig * * Returns the value contained in the #NMSettingIPConfig:dhcp-send-hostname * property. * * Returns: %TRUE if NetworkManager should send the machine hostname to the * DHCP server when requesting addresses to allow the server to automatically * update DNS information for this machine. **/ gboolean nm_setting_ip_config_get_dhcp_send_hostname (NMSettingIPConfig *setting) { g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->dhcp_send_hostname; } /** * nm_setting_ip_config_get_never_default: * @setting: the #NMSettingIPConfig * * Returns the value contained in the #NMSettingIPConfig:never-default * property. * * Returns: %TRUE if this connection should never be the default * connection **/ gboolean nm_setting_ip_config_get_never_default (NMSettingIPConfig *setting) { g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->never_default; } /** * nm_setting_ip_config_get_may_fail: * @setting: the #NMSettingIPConfig * * Returns the value contained in the #NMSettingIPConfig:may-fail * property. * * Returns: %TRUE if this connection doesn't require this type of IP * addressing to complete for the connection to succeed. **/ gboolean nm_setting_ip_config_get_may_fail (NMSettingIPConfig *setting) { g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->may_fail; } static gboolean verify_label (const char *label) { const char *p; char *iface; p = strchr (label, ':'); if (!p) return FALSE; iface = g_strndup (label, p - label); if (!nm_utils_iface_valid_name (iface)) { g_free (iface); return FALSE; } g_free (iface); for (p++; *p; p++) { if (!g_ascii_isalnum (*p) && *p != '_') return FALSE; } return TRUE; } static gboolean verify (NMSetting *setting, NMConnection *connection, GError **error) { NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); int i; if (!priv->method) { g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY, _("property is missing")); g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_METHOD); return FALSE; } if (priv->dhcp_hostname && !*priv->dhcp_hostname) { g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("property is empty")); g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_DHCP_HOSTNAME); return FALSE; } /* Validate DNS */ for (i = 0; i < priv->dns->len; i++) { const char *dns = priv->dns->pdata[i]; if (!nm_utils_ipaddr_valid (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), dns)) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("%d. DNS server address is invalid"), i+1); g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_DNS); return FALSE; } } /* Validate addresses */ for (i = 0; i < priv->addresses->len; i++) { NMIPAddress *addr = (NMIPAddress *) priv->addresses->pdata[i]; GVariant *label; if (nm_ip_address_get_family (addr) != NM_SETTING_IP_CONFIG_GET_FAMILY (setting)) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("%d. IP address is invalid"), i+1); g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_ADDRESSES); return FALSE; } label = nm_ip_address_get_attribute (addr, "label"); if (label) { if (!g_variant_is_of_type (label, G_VARIANT_TYPE_STRING)) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("%d. IP address has 'label' property with invalid type"), i+1); g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_ADDRESSES); return FALSE; } if (!verify_label (g_variant_get_string (label, NULL))) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("%d. IP address has invalid label '%s'"), i+1, g_variant_get_string (label, NULL)); g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_ADDRESSES); return FALSE; } } } /* Validate gateway */ if (priv->gateway) { if (!priv->addresses->len) { g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("gateway cannot be set if there are no addresses configured")); g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_GATEWAY); return FALSE; } if (!nm_utils_ipaddr_valid (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), priv->gateway)) { g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("gateway is invalid")); g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_GATEWAY); return FALSE; } } /* Validate routes */ for (i = 0; i < priv->routes->len; i++) { NMIPRoute *route = (NMIPRoute *) priv->routes->pdata[i]; if (nm_ip_route_get_family (route) != NM_SETTING_IP_CONFIG_GET_FAMILY (setting)) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("%d. route is invalid"), i+1); g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_ROUTES); return FALSE; } if (nm_ip_route_get_prefix (route) == 0) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("%d. route cannot be a default route"), i+1); g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_ROUTES); return FALSE; } } return TRUE; } static void nm_setting_ip_config_init (NMSettingIPConfig *setting) { NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); priv->dns = g_ptr_array_new_with_free_func (g_free); priv->dns_search = g_ptr_array_new_with_free_func (g_free); priv->addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref); priv->routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref); } static void finalize (GObject *object) { NMSettingIPConfig *self = NM_SETTING_IP_CONFIG (object); NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (self); g_free (priv->method); g_free (priv->gateway); g_free (priv->dhcp_hostname); g_ptr_array_unref (priv->dns); g_ptr_array_unref (priv->dns_search); g_ptr_array_unref (priv->addresses); g_ptr_array_unref (priv->routes); G_OBJECT_CLASS (nm_setting_ip_config_parent_class)->finalize (object); } static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NMSettingIPConfig *setting = NM_SETTING_IP_CONFIG (object); NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); const char *gateway; switch (prop_id) { case PROP_METHOD: g_free (priv->method); priv->method = g_value_dup_string (value); break; case PROP_DNS: g_ptr_array_unref (priv->dns); priv->dns = _nm_utils_strv_to_ptrarray (g_value_get_boxed (value)); break; case PROP_DNS_SEARCH: g_ptr_array_unref (priv->dns_search); priv->dns_search = _nm_utils_strv_to_ptrarray (g_value_get_boxed (value)); break; case PROP_ADDRESSES: g_ptr_array_unref (priv->addresses); priv->addresses = _nm_utils_copy_array (g_value_get_boxed (value), (NMUtilsCopyFunc) nm_ip_address_dup, (GDestroyNotify) nm_ip_address_unref); break; case PROP_GATEWAY: gateway = g_value_get_string (value); g_return_if_fail (!gateway || nm_utils_ipaddr_valid (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), gateway)); g_free (priv->gateway); priv->gateway = canonicalize_ip (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), gateway, TRUE); break; case PROP_ROUTES: g_ptr_array_unref (priv->routes); priv->routes = _nm_utils_copy_array (g_value_get_boxed (value), (NMUtilsCopyFunc) nm_ip_route_dup, (GDestroyNotify) nm_ip_route_unref); break; case PROP_ROUTE_METRIC: priv->route_metric = g_value_get_int64 (value); break; case PROP_IGNORE_AUTO_ROUTES: priv->ignore_auto_routes = g_value_get_boolean (value); break; case PROP_IGNORE_AUTO_DNS: priv->ignore_auto_dns = g_value_get_boolean (value); break; case PROP_DHCP_HOSTNAME: g_free (priv->dhcp_hostname); priv->dhcp_hostname = g_value_dup_string (value); break; case PROP_DHCP_SEND_HOSTNAME: priv->dhcp_send_hostname = g_value_get_boolean (value); break; case PROP_NEVER_DEFAULT: priv->never_default = g_value_get_boolean (value); break; case PROP_MAY_FAIL: priv->may_fail = g_value_get_boolean (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) { NMSettingIPConfig *setting = NM_SETTING_IP_CONFIG (object); NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); switch (prop_id) { case PROP_METHOD: g_value_set_string (value, nm_setting_ip_config_get_method (setting)); break; case PROP_DNS: g_value_take_boxed (value, _nm_utils_ptrarray_to_strv (priv->dns)); break; case PROP_DNS_SEARCH: g_value_take_boxed (value, _nm_utils_ptrarray_to_strv (priv->dns_search)); break; case PROP_ADDRESSES: g_value_take_boxed (value, _nm_utils_copy_array (priv->addresses, (NMUtilsCopyFunc) nm_ip_address_dup, (GDestroyNotify) nm_ip_address_unref)); break; case PROP_GATEWAY: g_value_set_string (value, nm_setting_ip_config_get_gateway (setting)); break; case PROP_ROUTES: g_value_take_boxed (value, _nm_utils_copy_array (priv->routes, (NMUtilsCopyFunc) nm_ip_route_dup, (GDestroyNotify) nm_ip_route_unref)); break; case PROP_ROUTE_METRIC: g_value_set_int64 (value, priv->route_metric); break; case PROP_IGNORE_AUTO_ROUTES: g_value_set_boolean (value, nm_setting_ip_config_get_ignore_auto_routes (setting)); break; case PROP_IGNORE_AUTO_DNS: g_value_set_boolean (value, nm_setting_ip_config_get_ignore_auto_dns (setting)); break; case PROP_DHCP_HOSTNAME: g_value_set_string (value, nm_setting_ip_config_get_dhcp_hostname (setting)); break; case PROP_DHCP_SEND_HOSTNAME: g_value_set_boolean (value, nm_setting_ip_config_get_dhcp_send_hostname (setting)); break; case PROP_NEVER_DEFAULT: g_value_set_boolean (value, priv->never_default); break; case PROP_MAY_FAIL: g_value_set_boolean (value, priv->may_fail); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void ip_gateway_set (NMSetting *setting, GVariant *connection_dict, const char *property, GVariant *value) { /* Don't set from 'gateway' if we're going to use the gateway in 'addresses' */ if (_nm_setting_use_legacy_property (setting, connection_dict, "addresses", "gateway")) return; g_object_set (setting, property, g_variant_get_string (value, NULL), NULL); } static void nm_setting_ip_config_class_init (NMSettingIPConfigClass *setting_class) { GObjectClass *object_class = G_OBJECT_CLASS (setting_class); NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class); g_type_class_add_private (setting_class, sizeof (NMSettingIPConfigPrivate)); /* virtual methods */ object_class->set_property = set_property; object_class->get_property = get_property; object_class->finalize = finalize; parent_class->verify = verify; /* Properties */ /** * NMSettingIPConfig:method: * * IP configuration method. * * #NMSettingIP4Config and #NMSettingIP6Config both support "auto", * "manual", and "link-local". See the subclass-specific documentation for * other values. * * In general, for the "auto" method, properties such as * #NMSettingIPConfig:dns and #NMSettingIPConfig:routes specify information * that is added on to the information returned from automatic * configuration. The #NMSettingIPConfig:ignore-auto-routes and * #NMSettingIPConfig:ignore-auto-dns properties modify this behavior. * * For methods that imply no upstream network, such as "shared" or * "link-local", these properties must be empty. **/ g_object_class_install_property (object_class, PROP_METHOD, g_param_spec_string (NM_SETTING_IP_CONFIG_METHOD, "", "", NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS)); /** * NMSettingIPConfig:dns: * * Array of IP addresses of DNS servers. **/ g_object_class_install_property (object_class, PROP_DNS, g_param_spec_boxed (NM_SETTING_IP_CONFIG_DNS, "", "", G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * NMSettingIPConfig:dns-search: * * Array of DNS search domains. **/ g_object_class_install_property (object_class, PROP_DNS_SEARCH, g_param_spec_boxed (NM_SETTING_IP_CONFIG_DNS_SEARCH, "", "", G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * NMSettingIPConfig:addresses: * * Array of IP addresses. * * Element-Type: NMIPAddress **/ g_object_class_install_property (object_class, PROP_ADDRESSES, g_param_spec_boxed (NM_SETTING_IP_CONFIG_ADDRESSES, "", "", G_TYPE_PTR_ARRAY, G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | /* "addresses" is a legacy D-Bus property, because the * "addresses" GObject property normally gets set from * the "address-data" D-Bus property... */ NM_SETTING_PARAM_LEGACY | G_PARAM_STATIC_STRINGS)); /** * NMSettingIPConfig:gateway: * * The gateway associated with this configuration. This is only meaningful * if #NMSettingIPConfig:addresses is also set. **/ g_object_class_install_property (object_class, PROP_GATEWAY, g_param_spec_string (NM_SETTING_IP_CONFIG_GATEWAY, "", "", NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS)); _nm_setting_class_override_property (parent_class, NM_SETTING_IP_CONFIG_GATEWAY, G_VARIANT_TYPE_STRING, NULL, ip_gateway_set, NULL); /** * NMSettingIPConfig:routes: * * Array of IP routes. * * Element-Type: NMIPRoute **/ g_object_class_install_property (object_class, PROP_ROUTES, g_param_spec_boxed (NM_SETTING_IP_CONFIG_ROUTES, "", "", G_TYPE_PTR_ARRAY, G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | /* See :addresses above Re: LEGACY */ NM_SETTING_PARAM_LEGACY | G_PARAM_STATIC_STRINGS)); /** * NMSettingIPConfig:route-metric: * * The default metric for routes that don't explicitly specify a metric. * The default value -1 means that the metric is choosen automatically * based on the device type. * The metric applies to dynamic routes, manual (static) routes that * don't have an explicit metric setting, address prefix routes, and * the default route. * Note that for IPv6, the kernel accepts zero (0) but coerces it to * 1024 (user default). Hence, setting this property to zero effectively * mean setting it to 1024. * For IPv4, zero is a regular value for the metric. **/ g_object_class_install_property (object_class, PROP_ROUTE_METRIC, g_param_spec_int64 (NM_SETTING_IP_CONFIG_ROUTE_METRIC, "", "", -1, G_MAXUINT32, -1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); /** * NMSettingIPConfig:ignore-auto-routes: * * When #NMSettingIPConfig:method is set to "auto" and this property to * %TRUE, automatically configured routes are ignored and only routes * specified in the #NMSettingIPConfig:routes property, if any, are used. **/ g_object_class_install_property (object_class, PROP_IGNORE_AUTO_ROUTES, g_param_spec_boolean (NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, "", "", FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); /** * NMSettingIPConfig:ignore-auto-dns: * * When #NMSettingIPConfig:method is set to "auto" and this property to * %TRUE, automatically configured nameservers and search domains are * ignored and only nameservers and search domains specified in the * #NMSettingIPConfig:dns and #NMSettingIPConfig:dns-search properties, if * any, are used. **/ g_object_class_install_property (object_class, PROP_IGNORE_AUTO_DNS, g_param_spec_boolean (NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, "", "", FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); /** * NMSettingIPConfig:dhcp-hostname: * * If the #NMSettingIPConfig:dhcp-send-hostname property is %TRUE, then the * specified name will be sent to the DHCP server when acquiring a lease. **/ g_object_class_install_property (object_class, PROP_DHCP_HOSTNAME, g_param_spec_string (NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, "", "", NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS)); /** * NMSettingIPConfig:dhcp-send-hostname: * * If %TRUE, a hostname is sent to the DHCP server when acquiring a lease. * Some DHCP servers use this hostname to update DNS databases, essentially * providing a static hostname for the computer. If the * #NMSettingIPConfig:dhcp-hostname property is %NULL and this property is * %TRUE, the current persistent hostname of the computer is sent. **/ g_object_class_install_property (object_class, PROP_DHCP_SEND_HOSTNAME, g_param_spec_boolean (NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, "", "", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); /** * NMSettingIPConfig:never-default: * * If %TRUE, this connection will never be the default connection for this * IP type, meaning it will never be assigned the default route by * NetworkManager. **/ g_object_class_install_property (object_class, PROP_NEVER_DEFAULT, g_param_spec_boolean (NM_SETTING_IP_CONFIG_NEVER_DEFAULT, "", "", FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); /** * NMSettingIPConfig:may-fail: * * If %TRUE, allow overall network configuration to proceed even if the * configuration specified by this property times out. Note that at least * one IP configuration must succeed or overall network configuration will * still fail. For example, in IPv6-only networks, setting this property to * %TRUE on the #NMSettingIP4Config allows the overall network configuration * to succeed if IPv4 configuration fails but IPv6 configuration completes * successfully. **/ g_object_class_install_property (object_class, PROP_MAY_FAIL, g_param_spec_boolean (NM_SETTING_IP_CONFIG_MAY_FAIL, "", "", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); }