diff --git a/noipy/__init__.py b/noipy/__init__.py index b53e976..d60a092 100644 --- a/noipy/__init__.py +++ b/noipy/__init__.py @@ -9,7 +9,7 @@ """ __title__ = "noipy" -__version_info__ = ('1', '5', '3') +__version_info__ = ('1', '5', '4') __version__ = ".".join(__version_info__) __author__ = "Pablo O Vieira" __email__ = "noipy@pv8.io" diff --git a/noipy/utils.py b/noipy/utils.py index 355f7ce..2ae9ef9 100644 --- a/noipy/utils.py +++ b/noipy/utils.py @@ -5,12 +5,23 @@ # Copyright (c) 2013 Pablo O Vieira (povieira) # See README.rst and LICENSE for details. +try: + from StringIO import StringIO +except ImportError: + from io import StringIO + import socket +import dns.resolver import requests HTTPBIN_URL = "https://httpbin.org/ip" +IP4ONLY_URL = "http://ip4only.me/api" +IP6ONLY_URL = "http://ip6only.me/api" + +COMMON_DNS = "8.8.8.8" + try: input = raw_input except NameError: @@ -22,19 +33,57 @@ def read_input(message): def get_ip(): - """Return machine's origin IP address. + """Return machine's origin IP address(es). """ + lst = [] + try: + r = requests.get(IP4ONLY_URL) + if r.status_code == 200: + lst.append(r.text.split(',')[1]) + except requests.exceptions.ConnectionError: + pass try: - r = requests.get(HTTPBIN_URL) - return r.json()['origin'] if r.status_code == 200 else None + r = requests.get(IP6ONLY_URL) + if r.status_code == 200: + lst.append(r.text.split(',')[1]) except requests.exceptions.ConnectionError: + pass + if not lst: + try: + r = requests.get(HTTPBIN_URL) + if r.status_code == 200: + lst.append(r.json()['origin']) + except requests.exceptions.ConnectionError: + pass + if not lst: return None + return ','.join(lst) def get_dns_ip(dnsname): - """Return machine's current IP address in DNS. + """Return machine's current IP address(es) in DNS. """ + resolver = dns.resolver.Resolver(StringIO("nameserver %s" % COMMON_DNS)) + + try: + resolve = resolver.resolve + except AttributeError: + resolve = resolver.query + + lst = [] + try: + lst += [a.address for a in resolve(dnsname, 'A')] + except dns.exception.DNSException: + pass try: - return socket.gethostbyname(dnsname) - except socket.error: + lst += [a.address for a in resolve(dnsname, 'AAAA')] + except dns.exception.DNSException: + pass + if not lst: + try: + lst.append(socket.gethostbyname(dnsname)) + except socket.error: + pass + if not lst: return None + return ','.join(lst) diff --git a/requirements-dev.txt b/requirements-dev.txt index 637f1da..7b1841b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -3,3 +3,5 @@ flake8==3.7.9 tox==3.20.0 pytest==4.6.9 +coverage +IPy diff --git a/requirements.txt b/requirements.txt index 566083c..31843ba 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ +dnspython requests==2.22.0 diff --git a/setup.py b/setup.py index 681f62a..e4b2ef8 100644 --- a/setup.py +++ b/setup.py @@ -13,6 +13,7 @@ install_requires = [ "requests>=2.0", + "dnspython", ] if sys.version_info[:2] < (2, 7): diff --git a/test/test_noipy.py b/test/test_noipy.py index 44eeab0..a7387de 100644 --- a/test/test_noipy.py +++ b/test/test_noipy.py @@ -5,9 +5,10 @@ # Copyright (c) 2013 Pablo O Vieira (povieira) # See README.rst and LICENSE for details. +from IPy import IP + import getpass import os -import re import shutil import unittest @@ -32,12 +33,18 @@ def tearDown(self): shutil.rmtree(self.test_dir) def test_get_ip(self): - ip = utils.get_ip() + ips = utils.get_ip() - self.assertTrue(re.match(VALID_IP_REGEX, ip), "get_ip() failed.") + for ip in ips.split(','): + try: + IP(ip) + except Exception as ex: + self.assertIsNone(ex, "get_ip() failed.") # monkey patch for testing (forcing ConnectionError) utils.HTTPBIN_URL = "http://example.nothing" + utils.IP4ONLY_URL = "http://example.nothing" + utils.IP6ONLY_URL = "http://example.nothing" ip = utils.get_ip() self.assertTrue(ip is None, "get_ip() should return None. IP=%s" % ip) @@ -56,7 +63,7 @@ class PluginsTest(unittest.TestCase): def setUp(self): self.parser = main.create_parser() - self.test_ip = "10.1.2.3" + self.test_ip = "10.1.2.3,2004::1:2:3:4" def tearDown(self): pass @@ -168,7 +175,7 @@ class AuthInfoTest(unittest.TestCase): def setUp(self): self.parser = main.create_parser() - self.test_ip = "10.1.2.3" + self.test_ip = "10.1.2.3,2004::1:2:3:4" self.test_dir = os.path.join(os.path.expanduser("~"), "noipy_test") def tearDown(self): diff --git a/tox.ini b/tox.ini index 609ac50..a55168d 100644 --- a/tox.ini +++ b/tox.ini @@ -6,6 +6,7 @@ passenv = CI TRAVIS_BUILD_ID TRAVIS TRAVIS_BRANCH TRAVIS_JOB_NUMBER TRAVIS_PULL_ deps = -rrequirements-dev.txt py{26,27,35,36,37},pypy,pypy3: coverage + py{26,27,35,36,37},pypy,pypy3: IPy commands = python --version