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>
This commit is contained in:
Martin Basti
2016-04-13 16:14:42 +02:00
parent 62bb478e11
commit 70fd78928c
4 changed files with 39 additions and 45 deletions

View File

@@ -33,6 +33,7 @@ try:
from optparse import SUPPRESS_HELP, OptionGroup, OptionValueError from optparse import SUPPRESS_HELP, OptionGroup, OptionValueError
import dns import dns
import gssapi import gssapi
import netifaces
import nss.nss as nss import nss.nss as nss
import SSSDConfig import SSSDConfig
@@ -1526,39 +1527,31 @@ def unconfigure_nisdomain():
def get_iface_from_ip(ip_addr): def get_iface_from_ip(ip_addr):
result = ipautil.run([paths.IP, '-oneline', 'address', 'show'], for interface in netifaces.interfaces():
capture_output=True) if_addrs = netifaces.ifaddresses(interface)
for line in result.output.split('\n'): for family in [netifaces.AF_INET, netifaces.AF_INET6]:
fields = line.split() for ip in if_addrs.get(family, []):
if len(fields) < 6: if ip['addr'] == ip_addr:
continue return interface
if fields[2] not in ['inet', 'inet6']:
continue
(ip, mask) = fields[3].rsplit('/', 1)
if ip == ip_addr:
return fields[1]
else: else:
raise RuntimeError("IP %s not assigned to any interface." % ip_addr) raise RuntimeError("IP %s not assigned to any interface." % ip_addr)
def get_local_ipaddresses(iface=None): def get_local_ipaddresses(iface=None):
args = [paths.IP, '-oneline', 'address', 'show']
if iface: if iface:
args += ['dev', iface] interfaces = [iface]
result = ipautil.run(args, capture_output=True) else:
lines = result.output.split('\n') interfaces = netifaces.interfaces()
ips = [] ips = []
for line in lines: for interface in interfaces:
fields = line.split() if_addrs = netifaces.ifaddresses(interface)
if len(fields) < 6: for family in [netifaces.AF_INET, netifaces.AF_INET6]:
continue for ip in if_addrs.get(family, []):
if fields[2] not in ['inet', 'inet6']: try:
continue ips.append(ipautil.CheckedIPAddress(ip['addr']))
(ip, mask) = fields[3].rsplit('/', 1) except ValueError:
try: continue
ips.append(ipautil.CheckedIPAddress(ip))
except ValueError:
continue
return ips return ips

View File

@@ -103,6 +103,7 @@ BuildRequires: python-jwcrypto
BuildRequires: custodia BuildRequires: custodia
BuildRequires: libini_config-devel >= 1.2.0 BuildRequires: libini_config-devel >= 1.2.0
BuildRequires: dbus-python BuildRequires: dbus-python
BuildRequires: python-netifaces >= 0.10.4
# Build dependencies for unit tests # Build dependencies for unit tests
BuildRequires: libcmocka-devel BuildRequires: libcmocka-devel
@@ -478,7 +479,6 @@ Provides: python2-ipaplatform = %{version}-%{release}
Requires: %{name}-common = %{version}-%{release} Requires: %{name}-common = %{version}-%{release}
Requires: python-gssapi >= 1.1.2 Requires: python-gssapi >= 1.1.2
Requires: gnupg Requires: gnupg
Requires: iproute
Requires: keyutils Requires: keyutils
Requires: pyOpenSSL Requires: pyOpenSSL
Requires: python-nss >= 0.16 Requires: python-nss >= 0.16
@@ -500,6 +500,7 @@ Requires: python-ldap >= 2.4.15
Requires: python-requests Requires: python-requests
Requires: python-custodia Requires: python-custodia
Requires: python-dns >= 1.11.1 Requires: python-dns >= 1.11.1
Requires: python-netifaces >= 0.10.4
Conflicts: %{alt_name}-python < %{version} Conflicts: %{alt_name}-python < %{version}
@@ -526,7 +527,6 @@ Provides: python3-ipaplatform = %{version}-%{release}
Requires: %{name}-common = %{version}-%{release} Requires: %{name}-common = %{version}-%{release}
Requires: python3-gssapi >= 1.1.2 Requires: python3-gssapi >= 1.1.2
Requires: gnupg Requires: gnupg
Requires: iproute
Requires: keyutils Requires: keyutils
Requires: python3-pyOpenSSL Requires: python3-pyOpenSSL
Requires: python3-nss >= 0.16 Requires: python3-nss >= 0.16
@@ -548,6 +548,7 @@ Requires: python3-pyldap >= 2.4.15
Requires: python3-custodia Requires: python3-custodia
Requires: python3-requests Requires: python3-requests
Requires: python3-dns >= 1.11.1 Requires: python3-dns >= 1.11.1
Requires: python3-netifaces >= 0.10.4
%description -n python3-ipalib %description -n python3-ipalib
IPA is an integrated solution to provide centrally managed Identity (users, IPA is an integrated solution to provide centrally managed Identity (users,

View File

@@ -140,7 +140,6 @@ class BasePathNamespace(object):
CACERT_P12 = "/root/cacert.p12" CACERT_P12 = "/root/cacert.p12"
ROOT_IPA_CSR = "/root/ipa.csr" ROOT_IPA_CSR = "/root/ipa.csr"
NAMED_PID = "/run/named/named.pid" NAMED_PID = "/run/named/named.pid"
IP = "/sbin/ip"
NOLOGIN = "/sbin/nologin" NOLOGIN = "/sbin/nologin"
SBIN_REBOOT = "/sbin/reboot" SBIN_REBOOT = "/sbin/reboot"
SBIN_RESTORECON = "/sbin/restorecon" SBIN_RESTORECON = "/sbin/restorecon"

View File

@@ -32,6 +32,7 @@ import socket
import re import re
import datetime import datetime
import netaddr import netaddr
import netifaces
import time import time
import gssapi import gssapi
import pwd import pwd
@@ -151,24 +152,24 @@ class CheckedIPAddress(netaddr.IPAddress):
if match_local: if match_local:
if addr.version == 4: if addr.version == 4:
family = 'inet' family = netifaces.AF_INET
elif addr.version == 6: elif addr.version == 6:
family = 'inet6' family = netifaces.AF_INET6
else:
raise ValueError(
"Unsupported address family ({})".format(addr.version)
)
result = run( for interface in netifaces.interfaces():
[paths.IP, '-family', family, '-oneline', 'address', 'show'], for ifdata in netifaces.ifaddresses(interface).get(family, []):
capture_output=True) ifnet = netaddr.IPNetwork('{addr}/{netmask}'.format(
lines = result.output.split('\n') addr=ifdata['addr'],
for line in lines: netmask=ifdata['netmask']
fields = line.split() ))
if len(fields) < 4: if ifnet == net or (net is None and ifnet.ip == addr):
continue net = ifnet
iface = interface
ifnet = netaddr.IPNetwork(fields[3]) break
if ifnet == net or (net is None and ifnet.ip == addr):
net = ifnet
iface = fields[1]
break
if iface is None: if iface is None:
raise ValueError('No network interface matches the provided IP address and netmask') raise ValueError('No network interface matches the provided IP address and netmask')