Skip to content

Commit

Permalink
feature: IPv6 support
Browse files Browse the repository at this point in the history
Requests, checks, and updates the both, IPv4 and IPv6,
addresses when available.

Uses ip4only.me, ip6only.me, and 8.8.8.8 Google DNS resolver
  • Loading branch information
nnseva committed Oct 14, 2020
1 parent 2483cb6 commit 18d51f0
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 13 deletions.
2 changes: 1 addition & 1 deletion noipy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__ = "[email protected]"
Expand Down
61 changes: 55 additions & 6 deletions noipy/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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)
2 changes: 2 additions & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
flake8==3.7.9
tox==3.20.0
pytest==4.6.9
coverage
IPy
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
dnspython
requests==2.22.0
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

install_requires = [
"requests>=2.0",
"dnspython",
]

if sys.version_info[:2] < (2, 7):
Expand Down
17 changes: 12 additions & 5 deletions test/test_noipy.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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):
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ envlist = py{26,27,35,36,37},pypy,pypy3,pep8
passenv = CI TRAVIS_BUILD_ID TRAVIS TRAVIS_BRANCH TRAVIS_JOB_NUMBER TRAVIS_PULL_REQUEST TRAVIS_JOB_ID TRAVIS_REPO_SLUG TRAVIS_COMMIT
deps =
-rrequirements-dev.txt
py{26,27,35,36,37},pypy,pypy3: coverage
py{26,27,35,36,37},pypy,pypy3: coverage IPy

commands =
python --version
Expand Down

0 comments on commit 18d51f0

Please sign in to comment.