diff --git a/powerline/segments/common/net.py b/powerline/segments/common/net.py index 0af5762d..eb5b4bcf 100644 --- a/powerline/segments/common/net.py +++ b/powerline/segments/common/net.py @@ -101,16 +101,24 @@ else: return 0 def internal_ip(pl, interface='auto', ipv=4): + family = netifaces.AF_INET6 if ipv == 6 else netifaces.AF_INET if interface == 'auto': try: interface = next(iter(sorted(netifaces.interfaces(), key=_interface_key, reverse=True))) except StopIteration: pl.info('No network interfaces found') return None + elif interface == 'default_gateway': + try: + interface = netifaces.gateways()['default'][family][1] + except KeyError: + pl.info('No default gateway found for IPv{0}', ipv) + return None addrs = netifaces.ifaddresses(interface) try: - return addrs[netifaces.AF_INET6 if ipv == 6 else netifaces.AF_INET][0]['addr'] + return addrs[family][0]['addr'] except (KeyError, IndexError): + pl.info("No IPv{0} address found for interface {1}", ipv, interface) return None @@ -130,6 +138,11 @@ Requires ``netifaces`` module to work properly. #. ``teredo`` followed by number or the end of string. #. Any other interface that is not ``lo*``. #. ``lo`` followed by number or the end of string. + + Use ``default_gateway`` to detect the interface based on the machine's + `default gateway `_ (i.e., + the router to which it is connected). + :param int ipv: 4 or 6 for ipv4 and ipv6 respectively, depending on which IP address you need exactly. diff --git a/tests/test_segments.py b/tests/test_segments.py index b3c77029..58292909 100644 --- a/tests/test_segments.py +++ b/tests/test_segments.py @@ -397,6 +397,29 @@ class TestNet(TestCommon): interfaces[:] = () self.assertEqual(self.module.internal_ip(pl=pl, ipv=6), None) + gateways = { + 'default': { + netifaces.AF_INET: ('192.168.100.1', 'enp2s0'), + netifaces.AF_INET6: ('feff::5446:5eff:fe5a:0001', 'enp2s0') + } + } + + with replace_module_module( + self.module, 'netifaces', + interfaces=(lambda: interfaces), + ifaddresses=(lambda interface: addr[interface]), + gateways=(lambda: gateways), + AF_INET=netifaces.AF_INET, + AF_INET6=netifaces.AF_INET6, + ): + # default gateway has specified address family + self.assertEqual(self.module.internal_ip(pl=pl, interface='default_gateway', ipv=4), '192.168.100.200') + self.assertEqual(self.module.internal_ip(pl=pl, interface='default_gateway', ipv=6), 'feff::5446:5eff:fe5a:7777%enp2s0') + # default gateway doesn't have specified address family + gateways['default'] = {} + self.assertEqual(self.module.internal_ip(pl=pl, interface='default_gateway', ipv=4), None) + self.assertEqual(self.module.internal_ip(pl=pl, interface='default_gateway', ipv=6), None) + def test_network_load(self): def gb(interface): return None