From 84276816418e99ce7d7a795c1c98aa024f4c3cdf Mon Sep 17 00:00:00 2001 From: Milan Stute Date: Tue, 20 Aug 2019 11:48:15 +0200 Subject: [PATCH] Move from netifaces to ifaddr and add better error handling Display message if `owl` is not running (fixes #7, fixes #12) --- opendrop/client.py | 9 ++++++--- opendrop/server.py | 10 ++++++++-- opendrop/util.py | 39 ++++++++++++++++++++------------------- setup.py | 2 +- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/opendrop/client.py b/opendrop/client.py index 4fb2d3a..c53ea40 100644 --- a/opendrop/client.py +++ b/opendrop/client.py @@ -40,10 +40,13 @@ class AirDropBrowser: def __init__(self, config): self.ip_interface_name = config.interface - self.ip_addr, self.byte_address = AirDropUtil.get_ip_for_interface(self.ip_interface_name, ipv6=True) - + self.ip_addr = AirDropUtil.get_ip_for_interface(self.ip_interface_name, ipv6=True) if self.ip_addr is None: - raise RuntimeError('Interface {} does not have IP(v6) address'.format(self.ip_interface_name)) + if self.ip_interface_name is 'awdl0': + raise RuntimeError('Interface {} does not have an IPv6 address. ' + 'Make sure that `owl` is running.'.format(self.ip_interface_name)) + else: + raise RuntimeError('Interface {} does not have an IPv6 address'.format(self.ip_interface_name)) self.zeroconf = Zeroconf(interfaces=[self.ip_addr], ipv6_interface_name=self.ip_interface_name) diff --git a/opendrop/server.py b/opendrop/server.py index 579780e..a543bc0 100644 --- a/opendrop/server.py +++ b/opendrop/server.py @@ -52,7 +52,13 @@ class AirDropServer: self.ServerClass.allow_reuse_address = False - self.ip_addr, self.byte_address = AirDropUtil.get_ip_for_interface(self.ip_interface_name, ipv6=True) + self.ip_addr = AirDropUtil.get_ip_for_interface(self.ip_interface_name, ipv6=True) + if self.ip_addr is None: + if self.ip_interface_name is 'awdl0': + raise RuntimeError('Interface {} does not have an IPv6 address. ' + 'Make sure that `owl` is running.'.format(self.ip_interface_name)) + else: + raise RuntimeError('Interface {} does not have an IPv6 address'.format(self.ip_interface_name)) self.Handler = AirDropServerHandler self.Handler.config = self.config @@ -69,7 +75,7 @@ class AirDropServer: service_name = self.config.service_id + '._airdrop._tcp.local.' info = ServiceInfo( '_airdrop._tcp.local.', service_name, - self.byte_address, self.config.port, 0, 0, properties, server) + self.ip_addr.packed, self.config.port, 0, 0, properties, server) return info def start_service(self): diff --git a/opendrop/util.py b/opendrop/util.py index 98c5934..d08e031 100644 --- a/opendrop/util.py +++ b/opendrop/util.py @@ -17,8 +17,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -import netifaces - import base64 import datetime import io @@ -26,8 +24,8 @@ import ipaddress import os import platform import plistlib -import socket import hashlib +import ifaddr from PIL import Image, ExifTags from libarchive import ffi from libarchive.entry import new_archive_entry, ArchiveEntry @@ -199,30 +197,33 @@ class AirDropUtil: return file_icon - @staticmethod def get_ip_for_interface(interface_name, ipv6=False): """ Get the ip address in IPv4 or IPv6 for a specific network interface - :param str interace_name: declares the network interface name for which the ip should be accessed - :param bool ipv6: Boolean indicating if the ipv6 address should be rertrieved - :return: (str ipaddress, byte ipaddress_bytes) returns a tuple with the ip address as a string and in bytes + :param str interface_name: declares the network interface name for which the ip should be accessed + :param bool ipv6: Boolean indicating if the ipv6 address should be retrieved + :return: IPv4Address or IPv6Address object or None """ - addresses = netifaces.ifaddresses(interface_name) - if netifaces.AF_INET6 in addresses and ipv6: - # Use the normal ipv6 address - addr = addresses[netifaces.AF_INET6][0]['addr'].split('%')[0] - bytes_addr = ipaddress.IPv6Address(addr).packed - elif netifaces.AF_INET in addresses and not ipv6: - addr = addresses[netifaces.AF_INET][0]['addr'] - bytes_addr = socket.inet_aton(addr) - else: - addr = None - bytes_addr = None + def get_interface_by_name(name): + for interface in ifaddr.get_adapters(): + if interface.name == name: + return interface + return None - return addr, bytes_addr + interface = get_interface_by_name(interface_name) + if interface is None: + return None + + for ip in interface.ips: + if ip.is_IPv6 and ipv6: + return ipaddress.IPv6Address(ip.ip[0]) # first of (ip, flowinfo, scope_id) tuple + if ip.is_IPv4 and not ipv6: + return ipaddress.IPv4Address(ip.ip) + + return None @staticmethod def write_debug(config, data, file_name): diff --git a/setup.py b/setup.py index b36b972..e9ce382 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ setup( package_data={ 'opendrop': ['certs/*.pem'] }, - install_requires=['requests', 'fleep', 'netifaces', 'Pillow', + install_requires=['requests', 'fleep', 'ifaddr', 'Pillow', 'requests_toolbelt', 'ctypescrypto', 'libarchive-c'], entry_points={ 'console_scripts': [