https://fedorahosted.org/freeipa/ticket/5591
Patch attached.
From 77d1ead350cd17d2c56706c9f9aa5d2d7d5da73d Mon Sep 17 00:00:00 2001 From: Martin Basti <[email protected]> Date: Wed, 13 Apr 2016 16:14:42 +0200 Subject: [PATCH] Use netifaces module instead of 'ip' command Netifaces allows to get addresses from local interfaces of the host in safer way than parsing output of the ip command. https://fedorahosted.org/freeipa/ticket/5591 --- client/ipa-client-install | 45 +++++++++++++++++++-------------------------- freeipa.spec.in | 2 ++ ipaplatform/base/paths.py | 1 - ipapython/ipautil.py | 33 +++++++++++++++++---------------- 4 files changed, 38 insertions(+), 43 deletions(-) diff --git a/client/ipa-client-install b/client/ipa-client-install index be203586a150e8fc22a42616052b95545918efb8..c38843f85639a9118cd1a471709992690643d79a 100755 --- a/client/ipa-client-install +++ b/client/ipa-client-install @@ -33,6 +33,7 @@ try: from optparse import SUPPRESS_HELP, OptionGroup, OptionValueError import dns import gssapi + import netifaces import nss.nss as nss import SSSDConfig @@ -1526,39 +1527,31 @@ def unconfigure_nisdomain(): def get_iface_from_ip(ip_addr): - result = ipautil.run([paths.IP, '-oneline', 'address', 'show'], - capture_output=True) - for line in result.output.split('\n'): - fields = line.split() - if len(fields) < 6: - continue - if fields[2] not in ['inet', 'inet6']: - continue - (ip, mask) = fields[3].rsplit('/', 1) - if ip == ip_addr: - return fields[1] + for interface in netifaces.interfaces(): + if_addrs = netifaces.ifaddresses(interface) + for family in [netifaces.AF_INET, netifaces.AF_INET6]: + for ip in if_addrs.get(family, []): + if ip['addr'] == ip_addr: + return interface else: raise RuntimeError("IP %s not assigned to any interface." % ip_addr) def get_local_ipaddresses(iface=None): - args = [paths.IP, '-oneline', 'address', 'show'] if iface: - args += ['dev', iface] - result = ipautil.run(args, capture_output=True) - lines = result.output.split('\n') + interfaces = [iface] + else: + interfaces = netifaces.interfaces() + ips = [] - for line in lines: - fields = line.split() - if len(fields) < 6: - continue - if fields[2] not in ['inet', 'inet6']: - continue - (ip, mask) = fields[3].rsplit('/', 1) - try: - ips.append(ipautil.CheckedIPAddress(ip)) - except ValueError: - continue + for interface in interfaces: + if_addrs = netifaces.ifaddresses(interface) + for family in [netifaces.AF_INET, netifaces.AF_INET6]: + for ip in if_addrs.get(family, []): + try: + ips.append(ipautil.CheckedIPAddress(ip['addr'])) + except ValueError: + continue return ips diff --git a/freeipa.spec.in b/freeipa.spec.in index 8582622ccc0f6d85a680b69269b045bd7c6be8c7..72ff5f63b1b3dea2678d34f787c8b2790329f3c6 100644 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -500,6 +500,7 @@ Requires: python-ldap >= 2.4.15 Requires: python-requests Requires: python-custodia Requires: python-dns >= 1.11.1 +Requires: python-netifaces >= 0.10.4 Conflicts: %{alt_name}-python < %{version} @@ -548,6 +549,7 @@ Requires: python3-pyldap >= 2.4.15 Requires: python3-custodia Requires: python3-requests Requires: python3-dns >= 1.11.1 +Requires: python3-netifaces >= 0.10.4 %description -n python3-ipalib IPA is an integrated solution to provide centrally managed Identity (users, diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py index 375a06442ee00301712264318fece30be2b45fd3..18f717aebe4c432d8739006689672c3e6de42268 100644 --- a/ipaplatform/base/paths.py +++ b/ipaplatform/base/paths.py @@ -142,7 +142,6 @@ class BasePathNamespace(object): CACERT_P12 = "/root/cacert.p12" ROOT_IPA_CSR = "/root/ipa.csr" NAMED_PID = "/run/named/named.pid" - IP = "/sbin/ip" NOLOGIN = "/sbin/nologin" SBIN_REBOOT = "/sbin/reboot" SBIN_RESTORECON = "/sbin/restorecon" diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py index d705c51f8d1937ffe57e52cce4b590951653c37b..e595d80ca3b971ad2f0031972e9e58b5adff8e54 100644 --- a/ipapython/ipautil.py +++ b/ipapython/ipautil.py @@ -32,6 +32,7 @@ import socket import re import datetime import netaddr +import netifaces import time import gssapi import pwd @@ -151,24 +152,24 @@ class CheckedIPAddress(netaddr.IPAddress): if match_local: if addr.version == 4: - family = 'inet' + family = netifaces.AF_INET elif addr.version == 6: - family = 'inet6' + family = netifaces.AF_INET6 + else: + raise ValueError( + "Unsupported address family ({})".format(addr.version) + ) - result = run( - [paths.IP, '-family', family, '-oneline', 'address', 'show'], - capture_output=True) - lines = result.output.split('\n') - for line in lines: - fields = line.split() - if len(fields) < 4: - continue - - ifnet = netaddr.IPNetwork(fields[3]) - if ifnet == net or (net is None and ifnet.ip == addr): - net = ifnet - iface = fields[1] - break + for interface in netifaces.interfaces(): + for ifdata in netifaces.ifaddresses(interface).get(family, []): + ifnet = netaddr.IPNetwork('{addr}/{netmask}'.format( + addr=ifdata['addr'], + netmask=ifdata['netmask'] + )) + if ifnet == net or (net is None and ifnet.ip == addr): + net = ifnet + iface = interface + break if iface is None: raise ValueError('No network interface matches the provided IP address and netmask') -- 2.5.5
-- Manage your subscription for the Freeipa-devel mailing list: https://www.redhat.com/mailman/listinfo/freeipa-devel Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code
