summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/changelog6
-rw-r--r--src/ipaddrcheck_functions.c24
-rw-r--r--src/ipaddrcheck_functions.h3
-rw-r--r--tests/check_ipaddrcheck.c20
-rwxr-xr-xtests/integration_tests.sh51
5 files changed, 72 insertions, 32 deletions
diff --git a/debian/changelog b/debian/changelog
index e1c5d02..d51c754 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+ipaddrcheck (1.4) unstable; urgency=medium
+
+ * Do not disallow all-zero host part IPv6 addresses for host and interface address checks (Daniil Baturin).
+
+ -- Daniil Baturin <daniil@vyos.io> Fri, 05 Dec 2025 15:04:03 +0000
+
ipaddrcheck (1.3) unstable; urgency=medium
* New option --range-prefix-length to require ranges to be within a subnet (Daniil Baturin).
diff --git a/src/ipaddrcheck_functions.c b/src/ipaddrcheck_functions.c
index fb0e654..75d8eec 100644
--- a/src/ipaddrcheck_functions.c
+++ b/src/ipaddrcheck_functions.c
@@ -2,7 +2,7 @@
* ipaddrcheck_functions.c: IPv4/IPv6 validation functions for ipaddrcheck
*
* Copyright (C) 2013 Daniil Baturin
- * Copyright (C) 2018-2024 VyOS maintainers and contributors
+ * Copyright (C) 2018-2025 VyOS maintainers and contributors
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -325,29 +325,15 @@ int is_ipv6(CIDR *address)
return(result);
}
-/* Is it a correct IPv6 host address? */
+/* Is it a correct IPv6 host address?
+ Everything except the unspecified address is.
+ */
int is_ipv6_host(CIDR *address)
{
int result;
- /* We reuse the same logic that prevents IPv4 network addresses
- from being assigned to interfaces (address == network_address),
- but the reason is slightly differnt.
-
- As per https://www.rfc-editor.org/rfc/rfc4291 section 2.6.1,
- >[Subnet-Router anycast address] is syntactically
- >the same as a unicast address for an interface on the link with the
- >interface identifier set to zero.
-
- So, the first address of the subnet must not be used for link addresses,
- even if the semantic reason is different.
- There's absolutely nothing wrong with assigning the last address, though,
- since there's no broadcast in IPv6.
- */
-
if( (cidr_get_proto(address) == CIDR_IPV6) &&
- ((cidr_equals(address, cidr_addr_network(address)) < 0) ||
- (cidr_get_pflen(address) >= 127)) )
+ (cidr_equals(address, cidr_from_str(IPV6_UNSPECIFIED)) != 0) )
{
result = RESULT_SUCCESS;
}
diff --git a/src/ipaddrcheck_functions.h b/src/ipaddrcheck_functions.h
index b717d74..bd131cf 100644
--- a/src/ipaddrcheck_functions.h
+++ b/src/ipaddrcheck_functions.h
@@ -2,7 +2,7 @@
* ipaddrcheck_functions.h: macros and prototypes for ipaddrcheck
*
* Copyright (C) 2013 Daniil Baturin
- * Copyright (C) 2018-2024 VyOS maintainers and contributors
+ * Copyright (C) 2018-2025 VyOS maintainers and contributors
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -50,6 +50,7 @@
#define IPV6_MULTICAST "ff00::/8"
#define IPV6_LINKLOCAL "fe80::/64"
#define IPV6_LOOPBACK "::1/128"
+#define IPV6_UNSPECIFIED "::/0"
#define NO_LOOPBACK 0
#define LOOPBACK_ALLOWED 1
diff --git a/tests/check_ipaddrcheck.c b/tests/check_ipaddrcheck.c
index ebae1e1..c4be8b1 100644
--- a/tests/check_ipaddrcheck.c
+++ b/tests/check_ipaddrcheck.c
@@ -2,7 +2,7 @@
* check_ipaddrcheck.c: ipaddrcheck unit tests
*
* Copyright (C) 2013 Daniil Baturin
- * Copyright (C) 2018-2024 VyOS maintainers and contributors
+ * Copyright (C) 2018-2025 VyOS maintainers and contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 or later as
@@ -289,11 +289,6 @@ START_TEST (test_is_ipv6_host)
CIDR* good_address_cidr = cidr_from_str(good_address_str_cidr);
ck_assert_int_eq(is_ipv6_host(good_address_cidr), RESULT_SUCCESS);
cidr_free(good_address_cidr);
-
- char* bad_address_str = "2001:db8:f::/48";
- CIDR* bad_address = cidr_from_str(bad_address_str);
- ck_assert_int_eq(is_ipv6_host(bad_address), RESULT_FAILURE);
- cidr_free(bad_address);
}
END_TEST
@@ -367,15 +362,20 @@ START_TEST (test_is_any_host)
ck_assert_int_eq(is_any_host(good_address_v6), RESULT_SUCCESS);
cidr_free(good_address_v6);
+ char* good_address_str_v6_all_zero = "2001:db8::/32";
+ CIDR* good_address_v6_all_zero = cidr_from_str(good_address_str_v6_all_zero);
+ ck_assert_int_eq(is_any_host(good_address_v6_all_zero), RESULT_SUCCESS);
+ cidr_free(good_address_v6_all_zero);
+
char* bad_address_str_v4 = "192.0.2.0/24";
CIDR* bad_address_v4 = cidr_from_str(bad_address_str_v4);
ck_assert_int_eq(is_any_host(bad_address_v4), RESULT_FAILURE);
cidr_free(bad_address_v4);
- char* bad_address_str_v6 = "2001:db8::/32";
- CIDR* bad_address_v6 = cidr_from_str(bad_address_str_v6);
- ck_assert_int_eq(is_any_host(bad_address_v6), RESULT_FAILURE);
- cidr_free(bad_address_v6);
+ char* bad_address_str_v6_unspec = "::/0";
+ CIDR* bad_address_v6_unspec = cidr_from_str(bad_address_str_v6_unspec);
+ ck_assert_int_eq(is_any_host(bad_address_v6_unspec), RESULT_FAILURE);
+ cidr_free(bad_address_v6_unspec);
}
END_TEST
diff --git a/tests/integration_tests.sh b/tests/integration_tests.sh
index 2c2c72b..9c937df 100755
--- a/tests/integration_tests.sh
+++ b/tests/integration_tests.sh
@@ -3,7 +3,7 @@
# integration_tests.sh: ipaddrcheck integration tests
#
# Copyright (C) 2013 Daniil Baturin
-# Copyright (C) 2018-2024 VyOS maintainers and contributors
+# Copyright (C) 2018-2025 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -59,6 +59,28 @@ ipv4_range_negative=(
192.0.2.1-192.0.2.500
)
+ipv4_interface_address_positive=(
+ 192.0.2.1/24
+ 192.168.1.0/23
+)
+
+ipv4_interface_address_negative=(
+ 192.0.2.0/24 # Network address
+ 192.0.2.255/24 # Broadcast
+ 224.0.0.1/24 # Multicast
+ 0.0.0.0/0 # Unspecified
+)
+
+ipv6_interface_address_positive=(
+ 2001:db8::1/64
+ 2001:db8::/64
+)
+
+ipv6_interface_address_negative=(
+ ff02::1:2 # Multicast
+ ::/0 # Unspecified
+)
+
ipv6_range_positive=(
2001:db8::1-2001:db8::99
)
@@ -111,10 +133,11 @@ ipv4_host_negative=(
ipv6_host_positive=(
2001:db8:1::1/64
2001:db8:1::1/127
+ 2001:db8:1::/64 # All-zero IPv6 addresses are valid host addresses
)
ipv6_host_negative=(
- 2001:db8::/32
+ ::/0
)
string="garbage"
@@ -272,7 +295,31 @@ done
# --is-ipv6-net
# --is-ipv6-multicast
# --is-ipv6-link-local
+
# --is-valid-intf-address
+for address in \
+ ${ipv4_interface_address_positive[*]}
+do
+ assert_raises "$IPADDRCHECK --is-valid-intf-address $address" 0
+done
+
+for address in \
+ ${ipv4_interface_address_negative[*]}
+do
+ assert_raises "$IPADDRCHECK --is-valid-intf-address $address" 1
+done
+
+for address in \
+ ${ipv6_interface_address_positive[*]}
+do
+ assert_raises "$IPADDRCHECK --is-valid-intf-address $address" 0
+done
+
+for address in \
+ ${ipv6_interface_address_negative[*]}
+do
+ assert_raises "$IPADDRCHECK --is-valid-intf-address $address" 1
+done
# --is-ipv4-range
for range in \