https://fedorahosted.org/freeipa/ticket/5591

Patch attached.
From 77d1ead350cd17d2c56706c9f9aa5d2d7d5da73d Mon Sep 17 00:00:00 2001
From: Martin Basti <mba...@redhat.com>
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

Reply via email to