platform: properly handle IPv4 peer-addresses

The peer-address (IFA_ADDRESS) can also be all-zero (0.0.0.0).
That is distinct from an usual address without explicit peer-address,
which implicitly has the same peer and local address.

Previously, we treated an all-zero peer_address as having peer and
local address equal. This is especially grave, because the peer is part
of the primary key for an IPv4 address. So we not only get a property of
the address wrong, but we wrongly consider two different addresses as
one and the same.

To properly handle these addresses, we always must explicitly set the peer.
This commit is contained in:
Thomas Haller
2015-10-21 23:17:11 +02:00
parent aa5b89a2ec
commit 6c8aa669a4
21 changed files with 227 additions and 154 deletions

View File

@@ -3274,8 +3274,7 @@ ipv4ll_get_ip4_config (NMDevice *self, guint32 lla)
g_assert (config); g_assert (config);
memset (&address, 0, sizeof (address)); memset (&address, 0, sizeof (address));
address.address = lla; nm_platform_ip4_address_set_addr (&address, lla, 16);
address.plen = 16;
address.source = NM_IP_CONFIG_SOURCE_IP4LL; address.source = NM_IP_CONFIG_SOURCE_IP4LL;
nm_ip4_config_add_address (config, &address); nm_ip4_config_add_address (config, &address);
@@ -4016,10 +4015,11 @@ reserve_shared_ip (NMDevice *self, NMSettingIPConfig *s_ip4, NMPlatformIP4Addres
if (s_ip4 && nm_setting_ip_config_get_num_addresses (s_ip4)) { if (s_ip4 && nm_setting_ip_config_get_num_addresses (s_ip4)) {
/* Use the first user-supplied address */ /* Use the first user-supplied address */
NMIPAddress *user = nm_setting_ip_config_get_address (s_ip4, 0); NMIPAddress *user = nm_setting_ip_config_get_address (s_ip4, 0);
in_addr_t a;
g_assert (user); g_assert (user);
nm_ip_address_get_address_binary (user, &address->address); nm_ip_address_get_address_binary (user, &a);
address->plen = nm_ip_address_get_prefix (user); nm_platform_ip4_address_set_addr (address, a, nm_ip_address_get_prefix (user));
} else { } else {
/* Find an unused address in the 10.42.x.x range */ /* Find an unused address in the 10.42.x.x range */
guint32 start = (guint32) ntohl (0x0a2a0001); /* 10.42.0.1 */ guint32 start = (guint32) ntohl (0x0a2a0001); /* 10.42.0.1 */
@@ -4032,8 +4032,7 @@ reserve_shared_ip (NMDevice *self, NMSettingIPConfig *s_ip4, NMPlatformIP4Addres
return FALSE; return FALSE;
} }
} }
address->address = start + count; nm_platform_ip4_address_set_addr (address, start + count, 24);
address->plen = 24;
g_hash_table_insert (shared_ips, g_hash_table_insert (shared_ips,
GUINT_TO_POINTER (address->address), GUINT_TO_POINTER (address->address),

View File

@@ -750,6 +750,7 @@ static_stage3_ip4_done (NMModemBroadband *self)
memset (&address, 0, sizeof (address)); memset (&address, 0, sizeof (address));
address.address = address_network; address.address = address_network;
address.peer_address = address_network;
address.plen = mm_bearer_ip_config_get_prefix (self->priv->ipv4_config); address.plen = mm_bearer_ip_config_get_prefix (self->priv->ipv4_config);
address.source = NM_IP_CONFIG_SOURCE_WWAN; address.source = NM_IP_CONFIG_SOURCE_WWAN;
nm_ip4_config_add_address (config, &address); nm_ip4_config_add_address (config, &address);

View File

@@ -675,6 +675,7 @@ nm_dhcp_dhclient_read_lease_ip_configs (const char *iface,
continue; continue;
if (!inet_pton (AF_INET, value, &address.address)) if (!inet_pton (AF_INET, value, &address.address))
continue; continue;
address.peer_address = address.address;
/* Gateway */ /* Gateway */
value = g_hash_table_lookup (hash, "option routers"); value = g_hash_table_lookup (hash, "option routers");

View File

@@ -232,6 +232,7 @@ lease_to_ip4_config (const char *iface,
sd_dhcp_lease_get_address (lease, &tmp_addr); sd_dhcp_lease_get_address (lease, &tmp_addr);
memset (&address, 0, sizeof (address)); memset (&address, 0, sizeof (address));
address.address = tmp_addr.s_addr; address.address = tmp_addr.s_addr;
address.peer_address = tmp_addr.s_addr;
str = nm_utils_inet4_ntop (tmp_addr.s_addr, NULL); str = nm_utils_inet4_ntop (tmp_addr.s_addr, NULL);
LOG_LEASE (LOGD_DHCP4, " address %s", str); LOG_LEASE (LOGD_DHCP4, " address %s", str);
add_option (options, dhcp4_requests, DHCP_OPTION_IP_ADDRESS, str); add_option (options, dhcp4_requests, DHCP_OPTION_IP_ADDRESS, str);

View File

@@ -380,6 +380,7 @@ nm_dhcp_utils_ip4_config_from_options (int ifindex,
{ {
NMIP4Config *ip4_config = NULL; NMIP4Config *ip4_config = NULL;
guint32 tmp_addr; guint32 tmp_addr;
in_addr_t addr;
NMPlatformIP4Address address; NMPlatformIP4Address address;
char *str = NULL; char *str = NULL;
guint32 gwaddr = 0, plen = 0; guint32 gwaddr = 0, plen = 0;
@@ -391,10 +392,9 @@ nm_dhcp_utils_ip4_config_from_options (int ifindex,
address.timestamp = nm_utils_get_monotonic_timestamp_s (); address.timestamp = nm_utils_get_monotonic_timestamp_s ();
str = g_hash_table_lookup (options, "ip_address"); str = g_hash_table_lookup (options, "ip_address");
if (str && (inet_pton (AF_INET, str, &tmp_addr) > 0)) { if (str && (inet_pton (AF_INET, str, &addr) > 0))
address.address = tmp_addr;
nm_log_info (LOGD_DHCP4, " address %s", str); nm_log_info (LOGD_DHCP4, " address %s", str);
} else else
goto error; goto error;
str = g_hash_table_lookup (options, "subnet_mask"); str = g_hash_table_lookup (options, "subnet_mask");
@@ -403,10 +403,10 @@ nm_dhcp_utils_ip4_config_from_options (int ifindex,
nm_log_info (LOGD_DHCP4, " plen %d (%s)", plen, str); nm_log_info (LOGD_DHCP4, " plen %d (%s)", plen, str);
} else { } else {
/* Get default netmask for the IP according to appropriate class. */ /* Get default netmask for the IP according to appropriate class. */
plen = nm_utils_ip4_get_default_prefix (address.address); plen = nm_utils_ip4_get_default_prefix (addr);
nm_log_info (LOGD_DHCP4, " plen %d (default)", plen); nm_log_info (LOGD_DHCP4, " plen %d (default)", plen);
} }
address.plen = plen; nm_platform_ip4_address_set_addr (&address, addr, plen);
/* Routes: if the server returns classless static routes, we MUST ignore /* Routes: if the server returns classless static routes, we MUST ignore
* the 'static_routes' option. * the 'static_routes' option.

View File

@@ -666,6 +666,7 @@ test_read_lease_ip4_config_basic (void)
g_assert (inet_aton ("192.168.1.180", (struct in_addr *) &expected_addr)); g_assert (inet_aton ("192.168.1.180", (struct in_addr *) &expected_addr));
addr = nm_ip4_config_get_address (config, 0); addr = nm_ip4_config_get_address (config, 0);
g_assert_cmpint (addr->address, ==, expected_addr); g_assert_cmpint (addr->address, ==, expected_addr);
g_assert_cmpint (addr->peer_address, ==, expected_addr);
g_assert_cmpint (addr->plen, ==, 24); g_assert_cmpint (addr->plen, ==, 24);
/* Gateway */ /* Gateway */
@@ -688,6 +689,7 @@ test_read_lease_ip4_config_basic (void)
g_assert (inet_aton ("10.77.52.141", (struct in_addr *) &expected_addr)); g_assert (inet_aton ("10.77.52.141", (struct in_addr *) &expected_addr));
addr = nm_ip4_config_get_address (config, 0); addr = nm_ip4_config_get_address (config, 0);
g_assert_cmpint (addr->address, ==, expected_addr); g_assert_cmpint (addr->address, ==, expected_addr);
g_assert_cmpint (addr->peer_address, ==, expected_addr);
g_assert_cmpint (addr->plen, ==, 8); g_assert_cmpint (addr->plen, ==, 8);
/* Gateway */ /* Gateway */

View File

@@ -95,7 +95,7 @@ test_generic_options (void)
address = nm_ip4_config_get_address (ip4_config, 0); address = nm_ip4_config_get_address (ip4_config, 0);
g_assert (inet_pton (AF_INET, expected_addr, &tmp) > 0); g_assert (inet_pton (AF_INET, expected_addr, &tmp) > 0);
g_assert (address->address == tmp); g_assert (address->address == tmp);
g_assert (address->peer_address == 0); g_assert (address->peer_address == tmp);
g_assert_cmpint (address->plen, ==, 24); g_assert_cmpint (address->plen, ==, 24);
/* Gateway */ /* Gateway */

View File

@@ -31,8 +31,7 @@ static NMPlatformIP4Address *
_set_addr (NMPlatformIP4Address *addr, const char *address, int plen) _set_addr (NMPlatformIP4Address *addr, const char *address, int plen)
{ {
memset (addr, 0, sizeof (*addr)); memset (addr, 0, sizeof (*addr));
addr->address = nmtst_inet4_from_string (address); nm_platform_ip4_address_set_addr (addr, nmtst_inet4_from_string (address), plen);
addr->plen = plen;
return addr; return addr;
} }

View File

@@ -180,7 +180,7 @@ addresses_are_duplicate (const NMPlatformIP4Address *a, const NMPlatformIP4Addre
{ {
return a->address == b->address return a->address == b->address
&& a->plen == b->plen && a->plen == b->plen
&& nm_platform_ip4_address_equal_peer_net (a, b); && ((a->peer_address ^ b->peer_address) & nm_utils_ip4_prefix_to_netmask (a->plen)) == 0;
} }
static gboolean static gboolean
@@ -309,7 +309,7 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gboolean routes_fu
route.source = NM_IP_CONFIG_SOURCE_KERNEL; route.source = NM_IP_CONFIG_SOURCE_KERNEL;
/* The destination network depends on the peer-address. */ /* The destination network depends on the peer-address. */
route.network = nm_utils_ip4_address_clear_host_address (nm_platform_ip4_address_get_peer (addr), addr->plen); route.network = nm_utils_ip4_address_clear_host_address (addr->peer_address, addr->plen);
if (_ipv4_is_zeronet (route.network)) { if (_ipv4_is_zeronet (route.network)) {
/* Kernel doesn't add device-routes for destinations that /* Kernel doesn't add device-routes for destinations that
@@ -404,6 +404,7 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, gu
memset (&address, 0, sizeof (address)); memset (&address, 0, sizeof (address));
nm_ip_address_get_address_binary (s_addr, &address.address); nm_ip_address_get_address_binary (s_addr, &address.address);
address.peer_address = address.address;
address.plen = nm_ip_address_get_prefix (s_addr); address.plen = nm_ip_address_get_prefix (s_addr);
address.lifetime = NM_PLATFORM_LIFETIME_PERMANENT; address.lifetime = NM_PLATFORM_LIFETIME_PERMANENT;
address.preferred = NM_PLATFORM_LIFETIME_PERMANENT; address.preferred = NM_PLATFORM_LIFETIME_PERMANENT;
@@ -1005,7 +1006,7 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
dst_addr = nm_ip4_config_get_address (dst, i))) { dst_addr = nm_ip4_config_get_address (dst, i))) {
are_equal = FALSE; are_equal = FALSE;
if ( !addresses_are_duplicate (src_addr, dst_addr) if ( !addresses_are_duplicate (src_addr, dst_addr)
|| (nm_platform_ip4_address_get_peer (src_addr) != nm_platform_ip4_address_get_peer (dst_addr))) { || src_addr->peer_address != dst_addr->peer_address) {
has_relevant_changes = TRUE; has_relevant_changes = TRUE;
break; break;
} }
@@ -1273,7 +1274,7 @@ nm_ip4_config_destination_is_direct (const NMIP4Config *config, guint32 network,
if (item->plen > plen) if (item->plen > plen)
continue; continue;
peer_network = nm_utils_ip4_address_clear_host_address (nm_platform_ip4_address_get_peer (item), item->plen); peer_network = nm_utils_ip4_address_clear_host_address (item->peer_address, item->plen);
if (_ipv4_is_zeronet (peer_network)) if (_ipv4_is_zeronet (peer_network))
continue; continue;
@@ -2013,7 +2014,7 @@ nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only
const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i); const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i);
hash_u32 (sum, address->address); hash_u32 (sum, address->address);
hash_u32 (sum, address->plen); hash_u32 (sum, address->plen);
hash_u32 (sum, nm_platform_ip4_address_get_peer_net (address)); hash_u32 (sum, address->peer_address & nm_utils_ip4_prefix_to_netmask (address->plen));
} }
for (i = 0; i < nm_ip4_config_get_num_routes (config); i++) { for (i = 0; i < nm_ip4_config_get_num_routes (config); i++) {
@@ -2160,8 +2161,7 @@ get_property (GObject *object, guint prop_id,
g_variant_builder_add (&addr_builder, "{sv}", g_variant_builder_add (&addr_builder, "{sv}",
"prefix", "prefix",
g_variant_new_uint32 (address->plen)); g_variant_new_uint32 (address->plen));
if ( address->peer_address if (address->peer_address != address->address) {
&& address->peer_address != address->address) {
g_variant_builder_add (&addr_builder, "{sv}", g_variant_builder_add (&addr_builder, "{sv}",
"peer", "peer",
g_variant_new_string (nm_utils_inet4_ntop (address->peer_address, NULL))); g_variant_new_string (nm_utils_inet4_ntop (address->peer_address, NULL)));

View File

@@ -99,6 +99,14 @@ static gboolean ip6_address_delete (NMPlatform *platform, int ifindex, struct in
/******************************************************************/ /******************************************************************/
static gboolean
_ip4_address_equal_peer_net (in_addr_t peer1, in_addr_t peer2, int plen)
{
return ((peer1 ^ peer2) & nm_utils_ip4_prefix_to_netmask (plen)) == 0;
}
/******************************************************************/
static gboolean static gboolean
sysctl_set (NMPlatform *platform, const char *path, const char *value) sysctl_set (NMPlatform *platform, const char *path, const char *value)
{ {
@@ -871,7 +879,7 @@ ip4_address_add (NMPlatform *platform,
address.source = NM_IP_CONFIG_SOURCE_KERNEL; address.source = NM_IP_CONFIG_SOURCE_KERNEL;
address.ifindex = ifindex; address.ifindex = ifindex;
address.address = addr; address.address = addr;
address.peer_address = peer_addr && peer_addr != addr ? peer_addr : 0; address.peer_address = peer_addr;
address.plen = plen; address.plen = plen;
address.timestamp = nm_utils_get_monotonic_timestamp_s (); address.timestamp = nm_utils_get_monotonic_timestamp_s ();
address.lifetime = lifetime; address.lifetime = lifetime;
@@ -881,17 +889,18 @@ ip4_address_add (NMPlatform *platform,
for (i = 0; i < priv->ip4_addresses->len; i++) { for (i = 0; i < priv->ip4_addresses->len; i++) {
NMPlatformIP4Address *item = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i); NMPlatformIP4Address *item = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
gboolean changed;
if (item->ifindex != address.ifindex) if ( item->ifindex != address.ifindex
continue; || item->address != address.address
if (item->address != address.address) || item->plen != address.plen
continue; || !_ip4_address_equal_peer_net (item->peer_address, address.peer_address, address.plen))
if (item->plen != address.plen)
continue;
if (!nm_platform_ip4_address_equal_peer_net (item, &address))
continue; continue;
changed = !nm_platform_ip4_address_cmp (item, &address);
memcpy (item, &address, sizeof (address)); memcpy (item, &address, sizeof (address));
if (changed)
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex, &address, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL); g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex, &address, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL);
return TRUE; return TRUE;
} }
@@ -928,18 +937,17 @@ ip6_address_add (NMPlatform *platform,
for (i = 0; i < priv->ip6_addresses->len; i++) { for (i = 0; i < priv->ip6_addresses->len; i++) {
NMPlatformIP6Address *item = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i); NMPlatformIP6Address *item = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
gboolean changed;
if (item->ifindex != address.ifindex) if ( item->ifindex != address.ifindex
continue; || !IN6_ARE_ADDR_EQUAL (&item->address, &address.address))
if (!IN6_ARE_ADDR_EQUAL (&item->address, &address.address))
continue;
if (item->plen != address.plen)
continue; continue;
if (nm_platform_ip6_address_cmp (item, &address) != 0) { changed = !nm_platform_ip6_address_cmp (item, &address);
memcpy (item, &address, sizeof (address)); memcpy (item, &address, sizeof (address));
if (changed)
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex, &address, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL); g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex, &address, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL);
}
return TRUE; return TRUE;
} }
@@ -958,8 +966,10 @@ ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen,
for (i = 0; i < priv->ip4_addresses->len; i++) { for (i = 0; i < priv->ip4_addresses->len; i++) {
NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i); NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
if (address->ifindex == ifindex && address->plen == plen && address->address == addr && if ( address->ifindex == ifindex
(!peer_address || address->peer_address == peer_address)) { && address->plen == plen
&& address->address == addr
&& ((peer_address ^ address->peer_address) & nm_utils_ip4_prefix_to_netmask (plen)) == 0) {
NMPlatformIP4Address deleted_address; NMPlatformIP4Address deleted_address;
memcpy (&deleted_address, address, sizeof (deleted_address)); memcpy (&deleted_address, address, sizeof (deleted_address));
@@ -981,7 +991,8 @@ ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int
for (i = 0; i < priv->ip6_addresses->len; i++) { for (i = 0; i < priv->ip6_addresses->len; i++) {
NMPlatformIP6Address *address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i); NMPlatformIP6Address *address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
if (address->ifindex == ifindex && address->plen == plen if ( address->ifindex == ifindex
&& address->plen == plen
&& IN6_ARE_ADDR_EQUAL (&address->address, &addr)) { && IN6_ARE_ADDR_EQUAL (&address->address, &addr)) {
NMPlatformIP6Address deleted_address; NMPlatformIP6Address deleted_address;
@@ -1000,12 +1011,6 @@ ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in
{ {
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
int i; int i;
NMPlatformIP4Address a = {
.ifindex = ifindex,
.address = addr,
.plen = plen,
.peer_address = peer_address,
};
for (i = 0; i < priv->ip4_addresses->len; i++) { for (i = 0; i < priv->ip4_addresses->len; i++) {
NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i); NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
@@ -1013,7 +1018,7 @@ ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in
if ( address->ifindex == ifindex if ( address->ifindex == ifindex
&& address->plen == plen && address->plen == plen
&& address->address == addr && address->address == addr
&& nm_platform_ip4_address_equal_peer_net (address, &a)) && _ip4_address_equal_peer_net (address->peer_address, peer_address, plen))
return address; return address;
} }

View File

@@ -1442,23 +1442,32 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only)
obj->ip_address.ifindex = ifa->ifa_index; obj->ip_address.ifindex = ifa->ifa_index;
obj->ip_address.plen = ifa->ifa_prefixlen; obj->ip_address.plen = ifa->ifa_prefixlen;
if (_check_addr_or_errout (tb, IFA_LOCAL, addr_len)) _check_addr_or_errout (tb, IFA_ADDRESS, addr_len);
memcpy (obj->ip_address.address_ptr, nla_data (tb[IFA_LOCAL]), addr_len); _check_addr_or_errout (tb, IFA_LOCAL, addr_len);
if (is_v4) {
if (_check_addr_or_errout (tb, IFA_ADDRESS, addr_len)) { /* For IPv4, kernel omits IFA_LOCAL/IFA_ADDRESS if (and only if) they
NMIPAddr *a = nla_data (tb[IFA_ADDRESS]); * are effectively 0.0.0.0 (all-zero). */
if (tb[IFA_LOCAL])
/* IPv6 sends the local address as IFA_ADDRESS with memcpy (&obj->ip4_address.address, nla_data (tb[IFA_LOCAL]), addr_len);
* no IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS if (tb[IFA_ADDRESS])
* with IFA_ADDRESS being the peer address if they differ */ memcpy (&obj->ip4_address.peer_address, nla_data (tb[IFA_ADDRESS]), addr_len);
if ( !tb[IFA_LOCAL]
|| !memcmp (a, obj->ip_address.address_ptr, addr_len)) {
memcpy (obj->ip_address.address_ptr, a, addr_len);
} else { } else {
if (is_v4) /* For IPv6, IFA_ADDRESS is always present.
obj->ip4_address.peer_address = a->addr4; *
* If IFA_LOCAL is missing, IFA_ADDRESS is @address and @peer_address
* is :: (all-zero).
*
* If unexpectely IFA_ADDRESS is missing, make the best of it -- but it _should_
* actually be there. */
if (tb[IFA_ADDRESS] || tb[IFA_LOCAL]) {
if (tb[IFA_LOCAL]) {
memcpy (&obj->ip6_address.address, nla_data (tb[IFA_LOCAL]), addr_len);
if (tb[IFA_ADDRESS])
memcpy (&obj->ip6_address.peer_address, nla_data (tb[IFA_ADDRESS]), addr_len);
else else
obj->ip6_address.peer_address = a->addr6; obj->ip6_address.peer_address = obj->ip6_address.address;
} else
memcpy (&obj->ip6_address.address, nla_data (tb[IFA_ADDRESS]), addr_len);
} }
} }
@@ -4256,7 +4265,14 @@ build_rtnl_addr (NMPlatform *platform,
} }
/* Peer/point-to-point address */ /* Peer/point-to-point address */
if (peer_addr) { if ( peer_addr
&& family == AF_INET
&& (*((in_addr_t *) peer_addr)) == (*((in_addr_t *) addr))) {
/* For IPv4, a local address being equal the peer address means that
* no explict peer is set.
*
* We don't have to set it explicitly. */
} else if (peer_addr) {
auto_nl_addr struct nl_addr *nlpeer = _nl_addr_build (family, peer_addr, addrlen); auto_nl_addr struct nl_addr *nlpeer = _nl_addr_build (family, peer_addr, addrlen);
nle = rtnl_addr_set_peer (rtnladdr, nlpeer); nle = rtnl_addr_set_peer (rtnladdr, nlpeer);
@@ -4308,7 +4324,7 @@ _nmp_vt_cmd_plobj_to_nl_ip4_address (NMPlatform *platform, const NMPlatformObjec
AF_INET, AF_INET,
obj->ifindex, obj->ifindex,
&obj->address, &obj->address,
obj->peer_address ? &obj->peer_address : NULL, &obj->peer_address,
obj->plen, obj->plen,
lifetime, lifetime,
preferred, preferred,
@@ -4351,7 +4367,7 @@ ip4_address_add (NMPlatform *platform,
auto_nl_object struct nl_object *nlo = NULL; auto_nl_object struct nl_object *nlo = NULL;
nlo = build_rtnl_addr (platform, AF_INET, ifindex, &addr, nlo = build_rtnl_addr (platform, AF_INET, ifindex, &addr,
peer_addr ? &peer_addr : NULL, &peer_addr,
plen, lifetime, preferred, 0, plen, lifetime, preferred, 0,
label); label);
return do_add_addrroute (platform, return do_add_addrroute (platform,

View File

@@ -1956,10 +1956,12 @@ _to_string_dev (NMPlatform *self, int ifindex, char *buf, size_t size)
/******************************************************************/ /******************************************************************/
in_addr_t void
nm_platform_ip4_address_get_peer (const NMPlatformIP4Address *addr) nm_platform_ip4_address_set_addr (NMPlatformIP4Address *addr, in_addr_t address, int plen)
{ {
return addr->peer_address ?: addr->address; addr->address = address;
addr->peer_address = address;
addr->plen = plen;
} }
const struct in6_addr * const struct in6_addr *
@@ -1971,28 +1973,6 @@ nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr)
return &addr->peer_address; return &addr->peer_address;
} }
in_addr_t
nm_platform_ip4_address_get_peer_net (const NMPlatformIP4Address *addr)
{
return (addr->peer_address ?: addr->address) & nm_utils_ip4_prefix_to_netmask (addr->plen);
}
gboolean
nm_platform_ip4_address_equal_peer_net (const NMPlatformIP4Address *addr1, const NMPlatformIP4Address *addr2)
{
guint32 a1, a2;
if (addr1->plen != addr2->plen)
return FALSE;
/* For kernel, if the peer address is unset, that effectively means that
* the peer address equals the local address. */
a1 = addr1->peer_address ? addr1->peer_address : addr1->address;
a2 = addr2->peer_address ? addr2->peer_address : addr2->address;
return ((a1 ^ a2) & nm_utils_ip4_prefix_to_netmask (addr1->plen)) == 0;
}
GArray * GArray *
nm_platform_ip4_address_get_all (NMPlatform *self, int ifindex) nm_platform_ip4_address_get_all (NMPlatform *self, int ifindex)
{ {
@@ -2091,7 +2071,8 @@ gboolean
nm_platform_ip4_address_delete (NMPlatform *self, int ifindex, in_addr_t address, int plen, in_addr_t peer_address) nm_platform_ip4_address_delete (NMPlatform *self, int ifindex, in_addr_t address, int plen, in_addr_t peer_address)
{ {
char str_dev[TO_STRING_DEV_BUF_SIZE]; char str_dev[TO_STRING_DEV_BUF_SIZE];
char str_peer[NM_UTILS_INET_ADDRSTRLEN]; char str_peer2[NM_UTILS_INET_ADDRSTRLEN];
char str_peer[100];
_CHECK_SELF (self, klass, FALSE); _CHECK_SELF (self, klass, FALSE);
@@ -2099,11 +2080,10 @@ nm_platform_ip4_address_delete (NMPlatform *self, int ifindex, in_addr_t address
g_return_val_if_fail (plen > 0, FALSE); g_return_val_if_fail (plen > 0, FALSE);
g_return_val_if_fail (klass->ip4_address_delete, FALSE); g_return_val_if_fail (klass->ip4_address_delete, FALSE);
_LOGD ("address: deleting IPv4 address %s/%d, %s%s%sifindex %d%s", _LOGD ("address: deleting IPv4 address %s/%d, %sifindex %d%s",
nm_utils_inet4_ntop (address, NULL), plen, nm_utils_inet4_ntop (address, NULL), plen,
peer_address ? "peer " : "", peer_address != address
peer_address ? nm_utils_inet4_ntop (peer_address, str_peer) : "", ? nm_sprintf_buf (str_peer, "peer %s, ", nm_utils_inet4_ntop (peer_address, str_peer2)) : "",
peer_address ? ", " : "",
ifindex, ifindex,
_to_string_dev (self, ifindex, str_dev, sizeof (str_dev))); _to_string_dev (self, ifindex, str_dev, sizeof (str_dev)));
return klass->ip4_address_delete (self, ifindex, address, plen, peer_address); return klass->ip4_address_delete (self, ifindex, address, plen, peer_address);
@@ -2157,7 +2137,7 @@ array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address
if ( candidate->address == address->address if ( candidate->address == address->address
&& candidate->plen == address->plen && candidate->plen == address->plen
&& nm_platform_ip4_address_equal_peer_net (candidate, address)) { && ((candidate->peer_address & address->peer_address) & nm_utils_ip4_prefix_to_netmask (address->plen)) == 0) {
guint32 lifetime, preferred; guint32 lifetime, preferred;
if (nmp_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred, if (nmp_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred,
@@ -2831,7 +2811,7 @@ nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *bu
inet_ntop (AF_INET, &address->address, s_address, sizeof (s_address)); inet_ntop (AF_INET, &address->address, s_address, sizeof (s_address));
if (address->peer_address) { if (address->peer_address != address->address) {
inet_ntop (AF_INET, &address->peer_address, s_peer, sizeof (s_peer)); inet_ntop (AF_INET, &address->peer_address, s_peer, sizeof (s_peer));
str_peer = g_strconcat (" ptp ", s_peer, NULL); str_peer = g_strconcat (" ptp ", s_peer, NULL);
} }
@@ -3237,20 +3217,12 @@ nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan
int int
nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b) nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b)
{ {
in_addr_t p_a, p_b;
_CMP_SELF (a, b); _CMP_SELF (a, b);
_CMP_FIELD (a, b, ifindex); _CMP_FIELD (a, b, ifindex);
_CMP_FIELD (a, b, source); _CMP_FIELD (a, b, source);
_CMP_FIELD (a, b, address); _CMP_FIELD (a, b, address);
_CMP_FIELD (a, b, plen); _CMP_FIELD (a, b, plen);
_CMP_FIELD (a, b, peer_address);
/* a peer-address of zero is the same as setting it to address.
* Here we consider the full address, including the host-part. */
p_a = nm_platform_ip4_address_get_peer (a);
p_b = nm_platform_ip4_address_get_peer (b);
_CMP_DIRECT (p_a, p_b);
_CMP_FIELD (a, b, timestamp); _CMP_FIELD (a, b, timestamp);
_CMP_FIELD (a, b, lifetime); _CMP_FIELD (a, b, lifetime);
_CMP_FIELD (a, b, preferred); _CMP_FIELD (a, b, preferred);

View File

@@ -234,8 +234,21 @@ typedef struct {
**/ **/
struct _NMPlatformIP4Address { struct _NMPlatformIP4Address {
__NMPlatformIPAddress_COMMON; __NMPlatformIPAddress_COMMON;
/* The local address IFA_LOCAL. */
in_addr_t address; in_addr_t address;
/* The IFA_ADDRESS PTP peer address. This field is rather important, because
* it constitutes the identifier for the IPv4 address (e.g. you can add two
* addresses that only differ by their peer's network-part.
*
* Beware that for most cases, NetworkManager doesn't want to set an explicit
* peer-address. Hoever, that corresponds to setting the peer address to @address
* itself. Leaving peer-address unset/zero, means explicitly setting the peer
* address to 0.0.0.0, which you probably don't want.
* */
in_addr_t peer_address; /* PTP peer address */ in_addr_t peer_address; /* PTP peer address */
char label[IFNAMSIZ]; char label[IFNAMSIZ];
}; };
@@ -715,10 +728,8 @@ guint32 nm_platform_mesh_get_channel (NMPlatform *self, int ifindex);
gboolean nm_platform_mesh_set_channel (NMPlatform *self, int ifindex, guint32 channel); gboolean nm_platform_mesh_set_channel (NMPlatform *self, int ifindex, guint32 channel);
gboolean nm_platform_mesh_set_ssid (NMPlatform *self, int ifindex, const guint8 *ssid, gsize len); gboolean nm_platform_mesh_set_ssid (NMPlatform *self, int ifindex, const guint8 *ssid, gsize len);
in_addr_t nm_platform_ip4_address_get_peer (const NMPlatformIP4Address *addr); void nm_platform_ip4_address_set_addr (NMPlatformIP4Address *addr, in_addr_t address, int plen);
const struct in6_addr *nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr); const struct in6_addr *nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr);
in_addr_t nm_platform_ip4_address_get_peer_net (const NMPlatformIP4Address *addr);
gboolean nm_platform_ip4_address_equal_peer_net (const NMPlatformIP4Address *addr1, const NMPlatformIP4Address *addr2);
const NMPlatformIP4Address *nm_platform_ip4_address_get (NMPlatform *self, int ifindex, in_addr_t address, int plen, in_addr_t peer_address); const NMPlatformIP4Address *nm_platform_ip4_address_get (NMPlatform *self, int ifindex, in_addr_t address, int plen, in_addr_t peer_address);
const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address, int plen); const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address, int plen);

View File

@@ -466,8 +466,8 @@ _vt_cmd_plobj_to_string_id_##type (const NMPlatformObject *_obj, char *buf, gsiz
} }
_vt_cmd_plobj_to_string_id (link, NMPlatformLink, "%d", obj->ifindex); _vt_cmd_plobj_to_string_id (link, NMPlatformLink, "%d", obj->ifindex);
_vt_cmd_plobj_to_string_id (ip4_address, NMPlatformIP4Address, "%d: %s/%d%s%s", obj->ifindex, nm_utils_inet4_ntop ( obj->address, buf1), obj->plen, _vt_cmd_plobj_to_string_id (ip4_address, NMPlatformIP4Address, "%d: %s/%d%s%s", obj->ifindex, nm_utils_inet4_ntop ( obj->address, buf1), obj->plen,
obj->peer_address && obj->peer_address != obj->address ? "," : "", obj->peer_address != obj->address ? "," : "",
obj->peer_address && obj->peer_address != obj->address ? nm_utils_inet4_ntop (nm_platform_ip4_address_get_peer_net (obj), buf2) : ""); obj->peer_address != obj->address ? nm_utils_inet4_ntop (obj->peer_address & nm_utils_ip4_prefix_to_netmask (obj->plen), buf2) : "");
_vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s", obj->ifindex, nm_utils_inet6_ntop (&obj->address, buf1)); _vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s", obj->ifindex, nm_utils_inet6_ntop (&obj->address, buf1));
_vt_cmd_plobj_to_string_id (ip4_route, NMPlatformIP4Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet4_ntop ( obj->network, buf1), obj->plen, obj->metric); _vt_cmd_plobj_to_string_id (ip4_route, NMPlatformIP4Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet4_ntop ( obj->network, buf1), obj->plen, obj->metric);
_vt_cmd_plobj_to_string_id (ip6_route, NMPlatformIP6Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet6_ntop (&obj->network, buf1), obj->plen, obj->metric); _vt_cmd_plobj_to_string_id (ip6_route, NMPlatformIP6Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet6_ntop (&obj->network, buf1), obj->plen, obj->metric);
@@ -664,7 +664,7 @@ _vt_cmd_plobj_id_equal (ip4_address, NMPlatformIP4Address,
&& obj1->address == obj2->address && obj1->address == obj2->address
/* for IPv4 addresses, you can add the same local address with differing peer-adddress /* for IPv4 addresses, you can add the same local address with differing peer-adddress
* (IFA_ADDRESS), provided that their net-part differs. */ * (IFA_ADDRESS), provided that their net-part differs. */
&& nm_platform_ip4_address_equal_peer_net (obj1, obj2)); && ((obj1->peer_address ^ obj2->peer_address) & nm_utils_ip4_prefix_to_netmask (obj1->plen)) == 0);
_vt_cmd_plobj_id_equal (ip6_address, NMPlatformIP6Address, _vt_cmd_plobj_id_equal (ip6_address, NMPlatformIP6Address,
obj1->ifindex == obj2->ifindex obj1->ifindex == obj2->ifindex
/* for IPv6 addresses, the prefix length is not part of the primary identifier. */ /* for IPv6 addresses, the prefix length is not part of the primary identifier. */
@@ -719,7 +719,7 @@ _vt_cmd_plobj_id_hash (ip4_address, NMPlatformIP4Address, {
hash = hash * 33 + ((guint) obj->address); hash = hash * 33 + ((guint) obj->address);
/* for IPv4 we must also consider the net-part of the peer-address (IFA_ADDRESS) */ /* for IPv4 we must also consider the net-part of the peer-address (IFA_ADDRESS) */
hash = hash * 33 + ((guint) (nm_platform_ip4_address_get_peer_net (obj))); hash = hash * 33 + ((guint) (obj->peer_address & nm_utils_ip4_prefix_to_netmask (obj->plen)));
}) })
_vt_cmd_plobj_id_hash (ip6_address, NMPlatformIP6Address, { _vt_cmd_plobj_id_hash (ip6_address, NMPlatformIP6Address, {
hash = (guint) 2907861637u; hash = (guint) 2907861637u;

View File

@@ -30,6 +30,7 @@
#include "nm-platform.h" #include "nm-platform.h"
#include "nm-linux-platform.h" #include "nm-linux-platform.h"
#include "nm-fake-platform.h" #include "nm-fake-platform.h"
#include "nm-utils.h"
#define error(...) fprintf (stderr, __VA_ARGS__) #define error(...) fprintf (stderr, __VA_ARGS__)
@@ -490,15 +491,17 @@ do_ip4_address_get_all (char **argv)
int ifindex = parse_ifindex (argv[0]); int ifindex = parse_ifindex (argv[0]);
GArray *addresses; GArray *addresses;
NMPlatformIP4Address *address; NMPlatformIP4Address *address;
char addrstr[INET_ADDRSTRLEN];
int i; int i;
if (ifindex) { if (ifindex) {
addresses = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); addresses = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex);
for (i = 0; i < addresses->len; i++) { for (i = 0; i < addresses->len; i++) {
address = &g_array_index (addresses, NMPlatformIP4Address, i); address = &g_array_index (addresses, NMPlatformIP4Address, i);
inet_ntop (AF_INET, &address->address, addrstr, sizeof (addrstr));
printf ("%s/%d\n", addrstr, address->plen); printf ("%s", nm_utils_inet4_ntop (address->address, NULL));
if (address->address != address->peer_address)
printf (" peer %s", nm_utils_inet4_ntop (address->peer_address, NULL));
printf ("/%d\n", address->plen);
} }
g_array_unref (addresses); g_array_unref (addresses);
} }
@@ -574,7 +577,7 @@ do_ip4_address_add (char **argv)
guint32 lifetime = strtol (*argv++, NULL, 10); guint32 lifetime = strtol (*argv++, NULL, 10);
guint32 preferred = strtol (*argv++, NULL, 10); guint32 preferred = strtol (*argv++, NULL, 10);
gboolean value = nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, address, plen, 0, lifetime, preferred, NULL); gboolean value = nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, address, plen, address, lifetime, preferred, NULL);
return value; return value;
} else } else
return FALSE; return FALSE;
@@ -615,11 +618,11 @@ do_ip6_address_add (char **argv)
} else \ } else \
return FALSE; \ return FALSE; \
} }
#define ADDR_CMD(cmdname, ...) ADDR_CMD_FULL (ip4, cmdname, FALSE, 0, ##__VA_ARGS__) ADDR_CMD_FULL (ip6, cmdname, FALSE) #define ADDR_CMD(cmdname, ...) ADDR_CMD_FULL (ip4, cmdname, FALSE, address, ##__VA_ARGS__) ADDR_CMD_FULL (ip6, cmdname, FALSE)
#define ADDR_CMD_PRINT(cmdname, ...) ADDR_CMD_FULL (ip4, cmdname, TRUE, ##__VA_ARGS__) ADDR_CMD_FULL (ip6, cmdname, TRUE) #define ADDR_CMD_PRINT(cmdname, ...) ADDR_CMD_FULL (ip4, cmdname, TRUE, ##__VA_ARGS__) ADDR_CMD_FULL (ip6, cmdname, TRUE)
ADDR_CMD (delete) ADDR_CMD (delete)
ADDR_CMD_PRINT (get, 0) ADDR_CMD_PRINT (get, address)
static gboolean static gboolean
do_ip4_route_get_all (char **argv) do_ip4_route_get_all (char **argv)

View File

@@ -73,13 +73,13 @@ test_ip4_address_general (void)
inet_pton (AF_INET, IP4_ADDRESS, &addr); inet_pton (AF_INET, IP4_ADDRESS, &addr);
/* Add address */ /* Add address */
g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr));
nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, 0, lifetime, preferred, NULL); nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, NULL);
g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr));
accept_signal (address_added); accept_signal (address_added);
/* Add address again (aka update) */ /* Add address again (aka update) */
nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, 0, lifetime + 100, preferred + 50, NULL); nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime + 100, preferred + 50, NULL);
accept_signals (address_changed, 0, 1); accept_signals (address_changed, 0, 1);
/* Test address listing */ /* Test address listing */
@@ -89,16 +89,17 @@ test_ip4_address_general (void)
address = &g_array_index (addresses, NMPlatformIP4Address, 0); address = &g_array_index (addresses, NMPlatformIP4Address, 0);
g_assert_cmpint (address->ifindex, ==, ifindex); g_assert_cmpint (address->ifindex, ==, ifindex);
g_assert_cmphex (address->address, ==, addr); g_assert_cmphex (address->address, ==, addr);
g_assert_cmphex (address->peer_address, ==, addr);
g_assert_cmpint (address->plen, ==, IP4_PLEN); g_assert_cmpint (address->plen, ==, IP4_PLEN);
g_array_unref (addresses); g_array_unref (addresses);
/* Remove address */ /* Remove address */
nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, 0); nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, addr);
g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr));
accept_signal (address_removed); accept_signal (address_removed);
/* Remove address again */ /* Remove address again */
nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, 0); nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, addr);
free_signal (address_added); free_signal (address_added);
free_signal (address_changed); free_signal (address_changed);
@@ -173,16 +174,16 @@ test_ip4_address_general_2 (void)
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, DEVICE_IFINDEX, NULL)); g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, DEVICE_IFINDEX, NULL));
/* Add/delete notification */ /* Add/delete notification */
nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, 0, lifetime, preferred, NULL); nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, NULL);
accept_signal (address_added); accept_signal (address_added);
g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr));
nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, 0); nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, addr);
accept_signal (address_removed); accept_signal (address_removed);
g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr));
/* Add/delete conflict */ /* Add/delete conflict */
nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, 0, lifetime, preferred, NULL); nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, NULL);
g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr));
accept_signal (address_added); accept_signal (address_added);
free_signal (address_added); free_signal (address_added);
@@ -275,6 +276,59 @@ test_ip4_address_peer (void)
/*****************************************************************************/ /*****************************************************************************/
static void
test_ip4_address_peer_zero (void)
{
const int ifindex = DEVICE_IFINDEX;
in_addr_t addr, addr_peer;
guint32 lifetime = 2000;
guint32 preferred = 1000;
const int plen = 24;
const char *label = NULL;
in_addr_t peers[3], r_peers[3];
int i;
GArray *addrs;
g_assert (ifindex > 0);
inet_pton (AF_INET, "192.168.5.2", &addr);
inet_pton (AF_INET, "192.168.6.2", &addr_peer);
peers[0] = addr;
peers[1] = addr_peer;
peers[2] = 0;
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL));
nmtst_rand_perm (NULL, r_peers, peers, sizeof (peers[0]), G_N_ELEMENTS (peers));
for (i = 0; i < G_N_ELEMENTS (peers); i++) {
g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, plen, r_peers[i]));
nmtstp_ip4_address_add (EX, ifindex, addr, plen, r_peers[i], lifetime, preferred, label);
addrs = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex);
g_assert (addrs);
g_assert_cmpint (addrs->len, ==, i + 1);
g_array_unref (addrs);
}
if (nmtst_is_debug ())
nmtstp_run_command_check ("ip address show dev %s", DEVICE_NAME);
nmtst_rand_perm (NULL, r_peers, peers, sizeof (peers[0]), G_N_ELEMENTS (peers));
for (i = 0; i < G_N_ELEMENTS (peers); i++) {
g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, plen, r_peers[i]));
nmtstp_ip4_address_del (EX, ifindex, addr, plen, r_peers[i]);
addrs = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex);
g_assert (addrs);
g_assert_cmpint (addrs->len, ==, G_N_ELEMENTS (peers) - i - 1);
g_array_unref (addrs);
}
}
/*****************************************************************************/
void void
init_tests (int *argc, char ***argv) init_tests (int *argc, char ***argv)
{ {
@@ -342,4 +396,5 @@ setup_tests (void)
_g_test_add_func ("/address/ipv6/general-2", test_ip6_address_general_2); _g_test_add_func ("/address/ipv6/general-2", test_ip6_address_general_2);
_g_test_add_func ("/address/ipv4/peer", test_ip4_address_peer); _g_test_add_func ("/address/ipv4/peer", test_ip4_address_peer);
_g_test_add_func ("/address/ipv4/peer/zero", test_ip4_address_peer_zero);
} }

View File

@@ -43,7 +43,7 @@ test_cleanup_internal (void)
g_assert (ifindex > 0); g_assert (ifindex > 0);
/* Add routes and addresses */ /* Add routes and addresses */
g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, plen4, 0, lifetime, preferred, NULL)); g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, plen4, addr4, lifetime, preferred, NULL));
g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr6, plen6, in6addr_any, lifetime, preferred, flags)); g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr6, plen6, in6addr_any, lifetime, preferred, flags));
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss)); g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss));
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss)); g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss));

View File

@@ -560,9 +560,6 @@ _ip_address_add (gboolean external_command,
ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex); ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex);
g_assert (ifname); g_assert (ifname);
if (peer_address == address)
peer_address = 0;
if (lifetime != NM_PLATFORM_LIFETIME_PERMANENT) if (lifetime != NM_PLATFORM_LIFETIME_PERMANENT)
s_valid = g_strdup_printf (" valid_lft %d", lifetime); s_valid = g_strdup_printf (" valid_lft %d", lifetime);
if (preferred != NM_PLATFORM_LIFETIME_PERMANENT) if (preferred != NM_PLATFORM_LIFETIME_PERMANENT)
@@ -571,11 +568,20 @@ _ip_address_add (gboolean external_command,
s_label = g_strdup_printf ("%s:%s", ifname, label); s_label = g_strdup_printf ("%s:%s", ifname, label);
if (is_v4) { if (is_v4) {
char s_peer[100];
g_assert (flags == 0); g_assert (flags == 0);
nmtstp_run_command_check ("ip address change %s%s%s/%d dev %s%s%s%s",
if ( peer_address->addr4 != address->addr4
|| nmtst_get_rand_int () % 2) {
/* If the peer is the same as the local address, we can omit it. The result should be identical */
g_snprintf (s_peer, sizeof (s_peer), " peer %s", nm_utils_inet4_ntop (peer_address->addr4, b2));
} else
s_peer[0] = '\0';
nmtstp_run_command_check ("ip address change %s%s/%d dev %s%s%s%s",
nm_utils_inet4_ntop (address->addr4, b1), nm_utils_inet4_ntop (address->addr4, b1),
peer_address->addr4 ? " peer " : "", s_peer,
peer_address->addr4 ? nm_utils_inet4_ntop (peer_address->addr4, b2) : "",
plen, plen,
ifname, ifname,
s_valid ?: "", s_valid ?: "",
@@ -637,7 +643,7 @@ _ip_address_add (gboolean external_command,
g_assert (flags == 0); g_assert (flags == 0);
a = nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, address->addr4, plen, peer_address->addr4); a = nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, address->addr4, plen, peer_address->addr4);
if ( a if ( a
&& nm_platform_ip4_address_get_peer (a) == (peer_address->addr4 ? peer_address->addr4 : address->addr4) && a->peer_address == peer_address->addr4
&& nmtstp_ip_address_check_lifetime ((NMPlatformIPAddress*) a, -1, lifetime, preferred) && nmtstp_ip_address_check_lifetime ((NMPlatformIPAddress*) a, -1, lifetime, preferred)
&& strcmp (a->label, label ?: "") == 0) && strcmp (a->label, label ?: "") == 0)
break; break;
@@ -729,9 +735,6 @@ _ip_address_del (gboolean external_command,
ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex); ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex);
g_assert (ifname); g_assert (ifname);
if (peer_address == address)
peer_address = 0;
/* let's wait until we see the address as we added it. */ /* let's wait until we see the address as we added it. */
if (is_v4) if (is_v4)
had_address = !!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, address->addr4, plen, peer_address->addr4); had_address = !!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, address->addr4, plen, peer_address->addr4);
@@ -741,8 +744,8 @@ _ip_address_del (gboolean external_command,
if (is_v4) { if (is_v4) {
success = nmtstp_run_command ("ip address delete %s%s%s/%d dev %s", success = nmtstp_run_command ("ip address delete %s%s%s/%d dev %s",
nm_utils_inet4_ntop (address->addr4, b1), nm_utils_inet4_ntop (address->addr4, b1),
peer_address->addr4 ? " peer " : "", peer_address->addr4 != address->addr4 ? " peer " : "",
peer_address->addr4 ? nm_utils_inet4_ntop (peer_address->addr4, b2) : "", peer_address->addr4 != address->addr4 ? nm_utils_inet4_ntop (peer_address->addr4, b2) : "",
plen, plen,
ifname); ifname);
} else { } else {

View File

@@ -470,13 +470,14 @@ impl_ppp_manager_set_ip4_config (NMPPPManager *manager,
memset (&address, 0, sizeof (address)); memset (&address, 0, sizeof (address));
address.plen = 32; address.plen = 32;
if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_ADDRESS, "u", &u32))
address.address = u32;
if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_GATEWAY, "u", &u32)) { if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_GATEWAY, "u", &u32)) {
nm_ip4_config_set_gateway (config, u32); nm_ip4_config_set_gateway (config, u32);
address.peer_address = u32; address.peer_address = u32;
} } else
address.peer_address = address.address;
if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_ADDRESS, "u", &u32))
address.address = u32;
if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_PREFIX, "u", &u32)) if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_PREFIX, "u", &u32))
address.plen = u32; address.plen = u32;

View File

@@ -36,6 +36,8 @@ addr_init (NMPlatformIP4Address *a, const char *addr, const char *peer, guint pl
g_assert (inet_pton (AF_INET, addr, (void *) &a->address) == 1); g_assert (inet_pton (AF_INET, addr, (void *) &a->address) == 1);
if (peer) if (peer)
g_assert (inet_pton (AF_INET, peer, (void *) &a->peer_address) == 1); g_assert (inet_pton (AF_INET, peer, (void *) &a->peer_address) == 1);
else
a->peer_address = a->address;
a->plen = plen; a->plen = plen;
} }
@@ -152,7 +154,7 @@ test_subtract (void)
test_addr = nm_ip4_config_get_address (dst, 0); test_addr = nm_ip4_config_get_address (dst, 0);
g_assert (test_addr != NULL); g_assert (test_addr != NULL);
g_assert_cmpuint (test_addr->address, ==, addr_to_num (expected_addr)); g_assert_cmpuint (test_addr->address, ==, addr_to_num (expected_addr));
g_assert_cmpuint (test_addr->peer_address, ==, 0); g_assert_cmpuint (test_addr->peer_address, ==, test_addr->address);
g_assert_cmpuint (test_addr->plen, ==, expected_addr_plen); g_assert_cmpuint (test_addr->plen, ==, expected_addr_plen);
g_assert_cmpuint (nm_ip4_config_get_gateway (dst), ==, 0); g_assert_cmpuint (nm_ip4_config_get_gateway (dst), ==, 0);

View File

@@ -1409,6 +1409,8 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_PTP, "u", &u32)) if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_PTP, "u", &u32))
address.peer_address = u32; address.peer_address = u32;
else
address.peer_address = address.address;
if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, "u", &u32)) if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, "u", &u32))
address.plen = u32; address.plen = u32;