Special case for IPv4 point-to-point /31 networks

RFC 3021 makes an exception for /31 networks: the network and brodacast
addresses are not reserved, since they are not needed in a point-to-point
context, and a /31 network contains only two addreses.

In that case, start at network address instead of network address + 1.

Signed-off-by: Dimitri Papadopoulos <3350651-DimitriPapadopoulos@users.noreply.gitlab.com>
This commit is contained in:
Dimitri Papadopoulos
2026-05-19 23:17:22 +02:00
parent 583f0c0be5
commit 81d2354def
11 changed files with 26 additions and 16 deletions
+16 -6
View File
@@ -170,16 +170,23 @@ static int is_ipv4_ok(main_server_st *s, struct sockaddr_storage *ip,
{ {
struct sockaddr_storage broadcast; struct sockaddr_storage broadcast;
unsigned int i; unsigned int i;
static const uint8_t mask31[4] = { 0xff, 0xff, 0xff, 0xfe };
memcpy(&broadcast, net, sizeof(broadcast)); memcpy(&broadcast, net, sizeof(broadcast));
for (i = 0; i < sizeof(struct in_addr); i++) { for (i = 0; i < sizeof(struct in_addr); i++) {
SA_IN_U8_P(&broadcast)[i] |= ~(SA_IN_U8_P(mask)[i]); SA_IN_U8_P(&broadcast)[i] |= ~(SA_IN_U8_P(mask)[i]);
} }
if (ip_lease_exists(s, ip, sizeof(struct sockaddr_in)) != 0 || if (ip_lease_exists(s, ip, sizeof(struct sockaddr_in)) != 0) {
ip_cmp(ip, net) == 0 || ip_cmp(ip, &broadcast) == 0) {
return 0; return 0;
} }
/* /31 networks have no reserved network/broadcast addresses (RFC 3021) */
if (memcmp(SA_IN_U8_P(mask), mask31, 4) != 0 &&
(ip_cmp(ip, net) == 0 || ip_cmp(ip, &broadcast) == 0)) {
return 0;
}
return 1; return 1;
} }
@@ -194,6 +201,7 @@ static int get_ipv4_lease(main_server_st *s, struct proc_st *proc)
int ret; int ret;
const char *c_network, *c_netmask; const char *c_network, *c_netmask;
char buf[64]; char buf[64];
static const uint8_t mask31[4] = { 0xff, 0xff, 0xff, 0xfe };
/* Our IP accounting */ /* Our IP accounting */
if (proc->config->ipv4_net && proc->config->ipv4_netmask) { if (proc->config->ipv4_net && proc->config->ipv4_netmask) {
@@ -260,10 +268,11 @@ static int get_ipv4_lease(main_server_st *s, struct proc_st *proc)
goto fail; goto fail;
} }
/* LIP = network address + 1 */ /* LIP = network address + 1, except for /31 networks (RFC 3021) */
memcpy(&proc->ipv4->lip, &network, sizeof(struct sockaddr_in)); memcpy(&proc->ipv4->lip, &network, sizeof(struct sockaddr_in));
proc->ipv4->lip_len = sizeof(struct sockaddr_in); proc->ipv4->lip_len = sizeof(struct sockaddr_in);
SA_IN_U8_P(&proc->ipv4->lip)[3] |= 1; if (memcmp(SA_IN_U8_P(&mask), mask31, 4) != 0)
SA_IN_U8_P(&proc->ipv4->lip)[3] |= 1;
if (ip_cmp(&proc->ipv4->lip, &proc->ipv4->rip) == 0) { if (ip_cmp(&proc->ipv4->lip, &proc->ipv4->rip) == 0) {
mslog(s, NULL, LOG_ERR, mslog(s, NULL, LOG_ERR,
@@ -344,10 +353,11 @@ static int get_ipv4_lease(main_server_st *s, struct proc_st *proc)
memcpy(&proc->ipv4->sig, &rnd, sizeof(struct sockaddr_in)); memcpy(&proc->ipv4->sig, &rnd, sizeof(struct sockaddr_in));
/* LIP = network address + 1 */ /* LIP = network address + 1, except for /31 networks (RFC 3021) */
memcpy(&proc->ipv4->lip, &network, sizeof(struct sockaddr_in)); memcpy(&proc->ipv4->lip, &network, sizeof(struct sockaddr_in));
proc->ipv4->lip_len = sizeof(struct sockaddr_in); proc->ipv4->lip_len = sizeof(struct sockaddr_in);
SA_IN_U8_P(&proc->ipv4->lip)[3] |= 1; if (memcmp(SA_IN_U8_P(&mask), mask31, 4) != 0)
SA_IN_U8_P(&proc->ipv4->lip)[3] |= 1;
if (memcmp(SA_IN_U8_P(&proc->ipv4->lip), if (memcmp(SA_IN_U8_P(&proc->ipv4->lip),
SA_IN_U8_P(&proc->ipv4->rip), SA_IN_U8_P(&proc->ipv4->rip),
+1 -1
View File
@@ -250,7 +250,7 @@ if get_option('root-tests')
root_scripts = [ root_scripts = [
'haproxy-connect', 'test-iroute', 'test-multi-cookie', 'haproxy-connect', 'test-iroute', 'test-multi-cookie',
'test-pass-script', 'idle-timeout', 'idle-timeout-icmpv6', 'test-year-2038', 'test-pass-script', 'idle-timeout', 'test-year-2038',
'test-cookie-timeout', 'test-cookie-timeout-2', 'test-cookie-timeout', 'test-cookie-timeout-2',
'test-explicit-ip', 'test-cookie-invalidation', 'test-explicit-ip', 'test-cookie-invalidation',
'test-user-config', 'test-append-routes', 'test-ban', 'test-user-config', 'test-append-routes', 'test-ban',
+1 -1
View File
@@ -74,7 +74,7 @@ VPNNET=192.168.66.0/24
VPNADDR=192.168.66.1 VPNADDR=192.168.66.1
CLIVPNADDR=192.168.66.192 CLIVPNADDR=192.168.66.192
VPNNET6=fd91:6d14:7241:dc6a::/112 VPNNET6=fd91:6d14:7241:dc6a::/112
VPNADDR6=fd91:6d14:7241:dc6a::1 VPNADDR6=fd91:6d14:7241:dc6a::0
OCCTL_SOCKET=./occtl-radius-$$.socket OCCTL_SOCKET=./occtl-radius-$$.socket
. `dirname $0`/ns.sh . `dirname $0`/ns.sh
+1 -1
View File
@@ -73,7 +73,7 @@ trap finish EXIT
VPNNET=192.168.93.0/24 VPNNET=192.168.93.0/24
VPNADDR=192.168.93.1 VPNADDR=192.168.93.1
VPNNET6=fc7d:b139:f7ba:5f53:c634:e98e:b777:0/112 VPNNET6=fc7d:b139:f7ba:5f53:c634:e98e:b777:0/112
VPNADDR6=fc7d:b139:f7ba:5f53:c634:e98e:b777:1 VPNADDR6=fc7d:b139:f7ba:5f53:c634:e98e:b777:0
OCCTL_SOCKET=./occtl-radius-group-$$.socket OCCTL_SOCKET=./occtl-radius-group-$$.socket
. `dirname $0`/ns.sh . `dirname $0`/ns.sh
+1 -1
View File
@@ -76,7 +76,7 @@ VPNNET=192.168.66.0/24
VPNADDR=192.168.66.1 VPNADDR=192.168.66.1
CLIVPNADDR=192.168.66.194 CLIVPNADDR=192.168.66.194
VPNNET6=fd91:6d14:7241:dc6a::/112 VPNNET6=fd91:6d14:7241:dc6a::/112
VPNADDR6=fd91:6d14:7241:dc6a::1 VPNADDR6=fd91:6d14:7241:dc6a::0
OCCTL_SOCKET=./occtl-radius-ipv6-prefix-$$.socket OCCTL_SOCKET=./occtl-radius-ipv6-prefix-$$.socket
. `dirname $0`/ns.sh . `dirname $0`/ns.sh
+1 -1
View File
@@ -73,7 +73,7 @@ trap finish EXIT
VPNNET=192.168.94.0/24 VPNNET=192.168.94.0/24
VPNADDR=192.168.94.192 VPNADDR=192.168.94.192
VPNNET6=fc7d:b139:f7ba:5f51:c634:e98e:b777:0/112 VPNNET6=fc7d:b139:f7ba:5f51:c634:e98e:b777:0/112
VPNADDR6=fc7d:b139:f7ba:5f51:c634:e98e:b777:1 VPNADDR6=fc7d:b139:f7ba:5f51:c634:e98e:b777:0
OCCTL_SOCKET=./occtl-radius-group-$$.socket OCCTL_SOCKET=./occtl-radius-group-$$.socket
. `dirname $0`/ns.sh . `dirname $0`/ns.sh
+1 -1
View File
@@ -73,7 +73,7 @@ trap finish EXIT
VPNNET=192.168.95.0/24 VPNNET=192.168.95.0/24
VPNADDR=192.168.95.192 VPNADDR=192.168.95.192
VPNNET6=fc7d:b139:f7ba:5f50:c634:e98e:b777:0/112 VPNNET6=fc7d:b139:f7ba:5f50:c634:e98e:b777:0/112
VPNADDR6=fc7d:b139:f7ba:5f50:c634:e98e:b777:1 VPNADDR6=fc7d:b139:f7ba:5f50:c634:e98e:b777:0
OCCTL_SOCKET=./occtl-radius-group-$$.socket OCCTL_SOCKET=./occtl-radius-group-$$.socket
. `dirname $0`/ns.sh . `dirname $0`/ns.sh
+1 -1
View File
@@ -80,7 +80,7 @@ trap finish EXIT
VPNNET=192.168.55.0/24 VPNNET=192.168.55.0/24
VPNADDR=192.168.55.1 VPNADDR=192.168.55.1
VPNNET6=fc7d:b139:f7ba:5f53:c634:e98e:b777:0/112 VPNNET6=fc7d:b139:f7ba:5f53:c634:e98e:b777:0/112
VPNADDR6=fc7d:b139:f7ba:5f53:c634:e98e:b777:1 VPNADDR6=fc7d:b139:f7ba:5f53:c634:e98e:b777:0
OCCTL_SOCKET=./occtl-radius-otp-$$.socket OCCTL_SOCKET=./occtl-radius-otp-$$.socket
. `dirname $0`/ns.sh . `dirname $0`/ns.sh
+1 -1
View File
@@ -51,7 +51,7 @@ while [ $ret = 0 ]
do do
eval $(${IPCALC} -r 112 -np --minaddr) eval $(${IPCALC} -r 112 -np --minaddr)
VPNNET6="${NETWORK}/${PREFIX}" VPNNET6="${NETWORK}/${PREFIX}"
VPNADDR6="${NETWORK}1" VPNADDR6="${NETWORK}0"
ping ${PINGOPS} ${VPNADDR6} >/dev/null 2>&1 ping ${PINGOPS} ${VPNADDR6} >/dev/null 2>&1
ret=$? ret=$?
done done
+1 -1
View File
@@ -62,7 +62,7 @@ CLI_ADDRESS=10.204.4.1
VPNNET=192.168.14.0/24 VPNNET=192.168.14.0/24
VPNADDR=192.168.14.1 VPNADDR=192.168.14.1
VPNNET6=fd91:6d87:7344:dc6a:dc15::/112 VPNNET6=fd91:6d87:7344:dc6a:dc15::/112
VPNADDR6=fd91:6d87:7344:dc6a:dc15::1 VPNADDR6=fd91:6d87:7344:dc6a:dc15::0
OCCTL_SOCKET=./occtl-cpg-$$.socket OCCTL_SOCKET=./occtl-cpg-$$.socket
ROUTE1=192.168.14.0/24 ROUTE1=192.168.14.0/24
USERNAME=test USERNAME=test
+1 -1
View File
@@ -62,7 +62,7 @@ CLI_ADDRESS=10.204.6.1
VPNNET=192.168.24.0/24 VPNNET=192.168.24.0/24
VPNADDR=192.168.24.1 VPNADDR=192.168.24.1
VPNNET6=fd91:6d87:7344:dc6a:dc16::/112 VPNNET6=fd91:6d87:7344:dc6a:dc16::/112
VPNADDR6=fd91:6d87:7344:dc6a:dc16::1 VPNADDR6=fd91:6d87:7344:dc6a:dc16::0
OCCTL_SOCKET=./occtl-cpg-$$.socket OCCTL_SOCKET=./occtl-cpg-$$.socket
ROUTE1=192.168.24.0/24 ROUTE1=192.168.24.0/24
USERNAME=test USERNAME=test