Bug #17039
openNAT64 fails when PPPoE interface address is also configured as a CARP VIP on another interface
0%
Description
There are two related issues involved.
pfSense has an existing address-discovery problem when an IPv4 address is simultaneously the actual address of a PPPoE interface and a CARP VIP on another interface. This behavior already existed in 2.8.1 and affected other functionality, but NAT64 continued to work in 2.8.1.
In 2.9.0, NAT64 now fails because its source-address resolution encounters this existing problem.
The underlying PPPoE/VIP address-discovery problem therefore predates 2.9.0, while the NAT64 failure is a 2.9.0 regression.
ENVIRONMENT¶
pfSense CE 2.9.0-RELEASE
amd64
FreeBSD 16.0-CURRENT
Build: RELENG_2_9_0-n256132-d8e3138ecf52
NETWORK TOPOLOGY¶
The ISP provisions the connection as follows.- The Internet connection terminates as a PPPoE session on pppoe0.
- pppoe0 has IPv4 address 11.22.33.65/32.
- The ISP routes 11.22.33.64/28 through the PPPoE session.
- There is no separate WAN interface for this routed /28.
- OPT2 carries the routed /28 internally.
- OPT2 has primary address 192.168.67.1.
- 11.22.33.65 is configured as a CARP VIP on OPT2.
Other hosts on the routed network use addresses such as 11.22.33.66, 11.22.33.67, etc.
Therefore 11.22.33.65 legitimately exists in two contexts:- pppoe0: 11.22.33.65/32, actual PPPoE interface address
- OPT2: 192.168.67.1 primary address, with 11.22.33.65 as a CARP VIP
This is intentional and required by the ISP's routing model.
EXISTING ADDRESS-RESOLUTION PROBLEM¶
The PPPoE address is correctly returned by the lower-level interface-address API.
Command:php -r 'require_once("config.inc"); require_once("interfaces.inc"); var_dump(pfSense_get_ifaddrs("pppoe0"));'
The result includes:["addrs"] =>
array(1) {
[0] =>
array(4) {
["addr"] => string(13) "11.22.33.65"
["subnetbits"] => int(32)
["subnet"] => string(15) "255.255.255.255"
["dstaddr"] => string(13) "78.33.253.139"
}
}
However:
php -r 'require_once("config.inc"); require_once("interfaces.inc"); var_dump(get_interface_addresses("pppoe0"));'
does not return an ipaddr field.
Consequently:php -r 'require_once("config.inc"); require_once("interfaces.inc"); var_dump(get_interface_ip("opt5"));'
returns:
NULL
CAUSE¶
get_interface_addresses() builds a global list of configured IPv4 VIP addresses.
The relevant code is:$v4vips = array();
foreach (array_keys(get_configured_vip_list()) as $viface) {
$vip = get_configured_vip($viface);
if (is_ipaddrv4($vip['subnet'])) {
array_push($v4vips, $vip['subnet']);
}
}
It then filters the addresses returned for the interface:$v4addrs = array_filter($ifaddrs['addrs'], function($addr) use ($v4vips){
return (array_search($addr['addr'], $v4vips) === false);
});
The configured VIP list contains 11.22.3365 because it is a CARP VIP on OPT2.
When processing pppoe0, the same address is therefore removed from the list of actual addresses belonging to pppoe0.
The filtering does not appear to distinguish which interface owns the VIP.
As a result:
pfSense_get_ifaddrs("pppoe0") correctly finds 11.22.33.65.
get_interface_addresses("pppoe0") filters it out.
get_interface_ip("opt5") returns NULL.
VERSION COMPARISON¶
pfSense 2.8.1:
The underlying PPPoE/VIP address-resolution problem already existed.
For this configuration, get_interface_ip("opt5") could fail to resolve the PPPoE address, affecting other pfSense functionality that relied on the common interface-address API.
However, NAT64 still worked in 2.8.1.
- After upgrading to 2.9.0, NAT64 no longer works.
- The NAT64 rule remains present in the GUI but shows zero hits.
- The generated rules contain messages such as:
- Could not determine NAT64 source address - Allow NAT64 traffic
- There is no corresponding NAT64 translation rule in pfctl.
- The affected NAT rule uses opt5ip as its source.
- Changing the rule to use an address/interface that does not encounter this address-resolution problem causes the NAT64 rule to be generated and traffic counters to increase.
IMPACT¶
The immediate regression in 2.9.0 is that NAT64 no longer works when using the PPPoE interface address as the NAT source.
The underlying address-resolution problem can also affect other pfSense functionality using get_interface_ip().
This does not appear to be a NAT64 configuration problem. The lower-level interface-address API correctly discovers the PPPoE address; the address is subsequently discarded by get_interface_addresses() because it also exists as a VIP on another interface.
EXPECTED BEHAVIOR¶
When obtaining the addresses of an interface, a VIP configured on another interface should not cause an identical address that is actually assigned to the queried interface to be discarded.
Specifically:
get_interface_addresses("pppoe0")
should return an ipaddr of:
11.22.33.65
and:
get_interface_ip("opt5")
should return:
11.22.33.65
The presence of 11.22.33.65 as a CARP VIP on OPT2 should not prevent it from being recognized as the actual address of pppoe0.
ACTUAL BEHAVIOR¶
pfSense_get_ifaddrs("pppoe0")
11.22.33.65
get_interface_addresses("pppoe0")
no ipaddr
get_interface_ip("opt5")
NULL
NAT64 in 2.9.0
cannot determine source address
NAT64 translation rule is not generated
SUGGESTED FIX¶
The VIP filtering in get_interface_addresses() should be made interface-aware.
An address should not be discarded merely because the same address exists somewhere in the global VIP list. In particular, an address that is actually assigned to the interface being queried must remain available as that interface's address.
The fix should preserve the existing behavior of excluding VIP addresses where appropriate, while avoiding the removal of an address that is simultaneously a legitimate address of another interface.
No data to display
Also available in: Atom