Use network address as IPv6 lease start

IPv6 address leases were starting at the network address + 1, following
the IPv4 convention where the network address is reserved. However,
IPv6 doesn't have such a restriction, and that behaviour is inconsistent
with IPv6 standards.

Use the IPv6 network address as the server-side tunnel address instead
of network address + 1, as described in REQ-MAIN-NET-006. This fix is
particularly important for point-to-point /127 networks with only 2
addresses. It also prevents a client with ipv6-subnet-prefix < 128 from
being leased the first subnet, which contained the server address.

This changes the server-side address of every IPv6 deployment; the
existing tests are updated accordingly.

Resolves: #714
Signed-off-by: Dimitri Papadopoulos <3350651-DimitriPapadopoulos@users.noreply.gitlab.com>
This commit is contained in:
Dimitri Papadopoulos
2026-09-29 22:12:55 +02:00
committed by Nikos Mavrogiannopoulos
parent 7fc0fb77c0
commit 3206e11665
5 changed files with 16 additions and 9 deletions
+6
View File
@@ -23,6 +23,12 @@
- IPv4 /31 networks (netmask 255.255.255.254) can now be used for leases as
point-to-point links (RFC 3021); previously no address could be leased from
them. The server takes the network address and the client the other one.
- The server-side IPv6 tunnel address is now the network address of
ipv6-network (previously the network address + 1). Firewall rules, DNS
settings or scripts that reference the server's ::1 tunnel address must be
updated. This makes /127 point-to-point networks (RFC 6164) lease the
expected address to the client, and a client can no longer be assigned
the server's address as part of the first subnet (#714)
* Version 1.5.0 (released 2026-06-07)
+4 -3
View File
@@ -366,8 +366,9 @@ test sources after `common.sh`:
same kind into `NAME`. For every allocated `NAME` it MUST set
`NAME_BASE`, the network address without its last all-zero octet
(IPv4, e.g. `10.22.134`) or group (IPv6, ending in `:`), and
`NAME_ADDR`, the first host address (`NAME_BASE` followed by `.1`
or `1`), and it MUST append `NAME` to `VPNNET_VARS` so that
`NAME_ADDR`, the server address: the first host address
(`NAME_BASE` followed by `.1`) for IPv4, and the network address
itself for IPv6 (`REQ-MAIN-NET-006`), and it MUST append `NAME` to `VPNNET_VARS` so that
`update_config` substitutes it (`REQ-GEN-TEST-008`). It MUST also
set `VPNADDR` and `VPNADDR6` to `VPNNET_ADDR` and `VPNNET6_ADDR`.
It MUST NOT modify `ADDRESS` or `CLI_ADDRESS`, so a test using
@@ -414,7 +415,7 @@ draw space is about 70,000 `/24` networks).
`random-vpnnet.sh`, call `alloc_vpnnet4 VPNNET2`, and confirm: `ADDRESS`
is unchanged and `CLI_ADDRESS` unset; `"${VPNNET_BASE}.0/24" = "$VPNNET"`
and `VPNADDR = VPNNET_ADDR = ${VPNNET_BASE}.1`; `VPNNET6` ends in `/112`
and `VPNADDR6 = ${VPNNET6_BASE}1`; `VPNNET2 != VPNNET`; and a template
and `VPNADDR6` equals the network address of `VPNNET6`; `VPNNET2 != VPNNET`; and a template
containing `@VPNNET2@ @VPNNET2_BASE@.9 @VPNNET2_ADDR@` is materialized by
`update_config` with those values. Source `random-net.sh` and confirm
`ADDRESS` and `CLI_ADDRESS` are set to addresses different from
-2
View File
@@ -439,9 +439,7 @@ static int get_ipv6_lease(main_server_st *s, struct proc_st *proc)
if (proc->ipv6 == NULL)
return ERR_MEM;
/* LIP = network address + 1 */
memcpy(&proc->ipv6->lip, &network, sizeof(struct sockaddr_in6));
SA_IN6_U8_P(&proc->ipv6->lip)[15] |= 1;
proc->ipv6->lip_len = sizeof(struct sockaddr_in6);
+1 -1
View File
@@ -1 +1 @@
explicit-ipv6 = @VPNNET6_BASE@1
explicit-ipv6 = @VPNNET6_BASE@0
+5 -3
View File
@@ -33,7 +33,8 @@
# to derive addresses and sub-networks within VPNNET
# VPNNET_ADDR - the first host address of VPNNET (also as VPNADDR)
# VPNNET6 - random IPv6 /112 network
# VPNNET6_BASE, VPNNET6_ADDR (also as VPNADDR6) - likewise for VPNNET6
# VPNNET6_BASE, VPNNET6_ADDR (also as VPNADDR6) - likewise for VPNNET6,
# except that VPNNET6_ADDR is the network address itself
# alloc_vpnnet4 NAME, alloc_vpnnet6 NAME - allocate a further network,
# distinct from the ones already allocated, into NAME,
# NAME_BASE and NAME_ADDR. Every allocated NAME is
@@ -115,13 +116,14 @@ _alloc_vpnnet() {
echo "VPN network $1: ${NETWORK}/${PREFIX} overlaps a local route, redrawing"
done
# the network address minus its last all-zero group or octet;
# for IPv6 it ends in ':', so BASE + host number is an address
# for IPv6 it ends in ':', so BASE + host number is an address.
# The IPv6 server address is the network address (REQ-MAIN-NET-006).
if test "$2" = 24; then
_base="${NETWORK%.0}"
_addr="${_base}.1"
else
_base="${NETWORK%0}"
_addr="${_base}1"
_addr="${NETWORK}"
fi
_VPNNETS_ALLOCATED="${_VPNNETS_ALLOCATED} ${NETWORK}"
VPNNET_VARS="${VPNNET_VARS} $1"