summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Basti <mbasti@redhat.com>2016-04-13 16:14:42 +0200
committerMartin Basti <mbasti@redhat.com>2016-04-14 13:53:27 +0200
commit70fd78928cb874006f218ae4e7aca00e0babf99a (patch)
tree6e9a51b711bb5bff59eb4e96afa366fcc4f0c1ff
parent62bb478e112cd4677e681f4750c5f5e5c9221607 (diff)
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 Reviewed-By: David Kupka <dkupka@redhat.com>
-rwxr-xr-xclient/ipa-client-install45
-rw-r--r--freeipa.spec.in5
-rw-r--r--ipaplatform/base/paths.py1
-rw-r--r--ipapython/ipautil.py35
4 files changed, 40 insertions, 46 deletions
diff --git a/client/ipa-client-install b/client/ipa-client-install
index be203586a..c38843f85 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 b0861d865..1ded30488 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -103,6 +103,7 @@ BuildRequires: python-jwcrypto
BuildRequires: custodia
BuildRequires: libini_config-devel >= 1.2.0
BuildRequires: dbus-python
+BuildRequires: python-netifaces >= 0.10.4
# Build dependencies for unit tests
BuildRequires: libcmocka-devel
@@ -478,7 +479,6 @@ Provides: python2-ipaplatform = %{version}-%{release}
Requires: %{name}-common = %{version}-%{release}
Requires: python-gssapi >= 1.1.2
Requires: gnupg
-Requires: iproute
Requires: keyutils
Requires: pyOpenSSL
Requires: python-nss >= 0.16
@@ -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}
@@ -526,7 +527,6 @@ Provides: python3-ipaplatform = %{version}-%{release}
Requires: %{name}-common = %{version}-%{release}
Requires: python3-gssapi >= 1.1.2
Requires: gnupg
-Requires: iproute
Requires: keyutils
Requires: python3-pyOpenSSL
Requires: python3-nss >= 0.16
@@ -548,6 +548,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 1b79015e4..4aa55d870 100644
--- a/ipaplatform/base/paths.py
+++ b/ipaplatform/base/paths.py
@@ -140,7 +140,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 d705c51f8..e595d80ca 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'
-
- 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
+ family = netifaces.AF_INET6
+ else:
+ raise ValueError(
+ "Unsupported address family ({})".format(addr.version)
+ )
+
+ 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')