Affects Version/s: FACT 3.1.0, FACT 3.4.0
Fix Version/s: FACT 3.1.7
Release Notes Summary:Before this fix, 'facter ipaddress' could return the address of the wrong network interface when there are routes for 0.0.0.0, with non-zero subnet mask, in addition to the default route. The correct ip address is the address of the interface associated with the interface on the route table entry for the default gateway.Before this fix, 'facter ipaddress' could return the address of the wrong network interface when there are routes for 0.0.0.0, with non-zero subnet mask, in addition to the default route. The correct ip address is the address of the interface associated with the interface on the route table entry for the default gateway.
Facter tries to determine the primary network interface by looking for the "default" route.
However, it will decide that a route is "default" based solely on the destination network address being 0.0.0.0. It's perfectly legitimate to have a route to 0.0.0.0 that is not a default route. What makes a default route is a destination of 0.0.0.0 and a netmask of 0.0.0.0.
My use case:
I have a server that is in a private (RFC1918) network. Its primary network interface (bond0) talks to that private network via one router, but needs to talk to the Internet via a second router on a VLAN interface (bond0.300).
Originally, this was set up with a very simple routing table:
0.0.0.0/0 → Internet on dev bond0.300
10.0.0.0/8 → Private on dev bond0
172.16.0.0/12 → Private on dev bond0
192.168.0.0/16 → Private on dev bond0
However, this causes Facter to decide that the primary network interface is bond0.300 with all the associated settings, which breaks our Hiera configurations and puppet-controlled network setup.
So I changed the routing table so that the default route went to bond0. This means every network besides the private RFC1918 networks now needs a direct route out through bond0.300:
0.0.0.0/0 → Private on dev bond0
0.0.0.0/5 → Internet on dev bond0.300
184.108.40.206/7 → Internet on dev bond0.300
10.0.0.0/8 skipped to be routed to the private network
220.127.116.11/8 → Internet on dev bond0.300
18.104.22.168/6 → Internet on dev bond0.300
22.214.171.124/4 → Internet on dev bond0.300
126.96.36.199/3 → Internet on dev bond0.300
I expected Facter to find the correct default route. It didn't. It turns out this is due to two related facts:
1 Facter looks for any route with a destination of 0.0.0.0 no matter what netmask it uses.
2 Linux (at least, RHEL 6) sorts /proc/net/route from most specific to least specific, so the default route will always be last.
So even with the complicated (34 line) routing table to catch everything except the RFC1918 networks, Facter is still finding the wrong primary interface.
The solution is, in networking_resolver::get_primary_interface, to check both parts == boost::as_literal("00000000") and parts == boost::as_literal("00000000"). (And, by the way, so that you're not trapped if the columns change, you really should look at the first line to identify the Destination and Mask columns).
I will be submitting a pull request for this shortly after I complete this ticket.