Skip to content

Commit 804965e

Browse files
committed
2.17.0 - Added net.get_host + AsyncIO versions of various net module functions
**`privex.helpers.net` module** - Refactored `resolve_ips` to enable re-use of validation and other things between it and the AsyncIO version - Added `resolve_ips_async` - which is simply an AsyncIO version of `resolve_ips` - Added `resolve_ip_async` - again, an AsyncIO version of `resolve_ip` - Added `resolve_ips_multi_async` (AsyncIO `resolve_ips_multi`) - Added `get_rdns_async` (AsyncIO `get_rdns`) - Added new `check_host` function, which checks if a given service (port) on a host is up and working - Added `check_host_async` - same as `check_host` but uses AsyncIO
1 parent 7935511 commit 804965e

10 files changed

+584
-34
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
check\_host
2+
===========
3+
4+
.. currentmodule:: privex.helpers.net
5+
6+
.. autofunction:: check_host
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
check\_host\_async
2+
==================
3+
4+
.. currentmodule:: privex.helpers.net
5+
6+
.. autofunction:: check_host_async
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
get\_rdns\_async
2+
================
3+
4+
.. currentmodule:: privex.helpers.net
5+
6+
.. autofunction:: get_rdns_async
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
resolve\_ip\_async
2+
==================
3+
4+
.. currentmodule:: privex.helpers.net
5+
6+
.. autofunction:: resolve_ip_async
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
resolve\_ips\_async
2+
===================
3+
4+
.. currentmodule:: privex.helpers.net
5+
6+
.. autofunction:: resolve_ips_async
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
resolve\_ips\_multi\_async
2+
==========================
3+
4+
.. currentmodule:: privex.helpers.net
5+
6+
.. autofunction:: resolve_ips_multi_async

docs/source/helpers/privex.helpers.net.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,18 @@ privex.helpers.net
1515
:toctree: net
1616

1717
asn_to_name
18+
check_host
19+
check_host_async
20+
1821
get_rdns
22+
get_rdns_async
1923
get_rdns_multi
2024
resolve_ip
25+
resolve_ip_async
2126
resolve_ips
27+
resolve_ips_async
2228
resolve_ips_multi
29+
resolve_ips_multi_async
2330
ip4_to_rdns
2431
ip6_to_rdns
2532
ip_is_v4

privex/helpers/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ def _setup_logging(level=logging.WARNING):
148148
log = _setup_logging()
149149
name = 'helpers'
150150

151-
VERSION = '2.16.0'
151+
VERSION = '2.17.0'
152152

153153

154154

privex/helpers/net.py

Lines changed: 357 additions & 33 deletions
Large diffs are not rendered by default.

tests/test_net.py

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
"""
22
Test cases related to :py:mod:`privex.helpers.net` or generally network related functions such as :py:func:`.ping`
33
"""
4+
import socket
45
import warnings
6+
7+
from privex.helpers import loop_run
58
from tests import PrivexBaseCase
69
from privex import helpers
710

@@ -124,6 +127,19 @@ def test_get_rdns_multi_invalid(self):
124127
self.assertIsNone(hosts['fe80::5123'])
125128
self.assertEqual(hosts['2a07:e00::333'], 'se.dns.privex.io')
126129

130+
def test_check_host(self):
131+
self.assertTrue(helpers.check_host('hiveseed-se.privex.io', 2001))
132+
self.assertFalse(helpers.check_host('hiveseed-se.privex.io', 9991))
133+
134+
def test_check_host_send(self):
135+
http_req = b"GET / HTTP/1.1\n\n"
136+
self.assertTrue(helpers.check_host('files.privex.io', 80, send=http_req))
137+
self.assertFalse(helpers.check_host('files.privex.io', 9991))
138+
139+
def test_check_host_throw(self):
140+
with self.assertRaises(ConnectionRefusedError):
141+
helpers.check_host('files.privex.io', 9991, throw=True)
142+
127143

128144
class TestNetResolveIP(PrivexBaseCase):
129145
"""
@@ -246,3 +262,170 @@ def test_resolve_ips_multi_v6(self):
246262

247263
self.assertIn('2a07:e00::333', ips['2a07:e00::333'])
248264
self.assertIsNone(ips['8.8.4.4'])
265+
266+
267+
class TestAsyncResolveIP(PrivexBaseCase):
268+
# --- privex.helpers.net.resolve_ips ---
269+
def test_resolve_ips_ipv4_addr(self):
270+
"""Test :func:`.resolve_ips` returns the same IPv4 address passed to it"""
271+
ips = loop_run(helpers.resolve_ips_async('185.130.44.5'))
272+
self.assertEqual(len(ips), 1)
273+
self.assertEqual(ips[0], '185.130.44.5')
274+
275+
def test_resolve_ips_ipv6_addr(self):
276+
"""Test :func:`.resolve_ips` returns the same IPv6 address passed to it"""
277+
ips = loop_run(helpers.resolve_ips_async('2a07:e00::333'))
278+
self.assertEqual(len(ips), 1)
279+
self.assertEqual(ips[0], '2a07:e00::333')
280+
281+
def test_resolve_ips_ipv4_addr_invalid(self):
282+
"""Test :func:`.resolve_ips` raises :class:`.AttributeError` when ``version`` is v4 but an IPv6 address was passed"""
283+
with self.assertRaises(AttributeError):
284+
loop_run(helpers.resolve_ips_async('2a07:e00::333', 'v4'))
285+
286+
def test_resolve_ips_ipv6_addr_invalid(self):
287+
"""Test :func:`.resolve_ips` raises :class:`.AttributeError` when ``version`` is v6 but an IPv4 address was passed"""
288+
with self.assertRaises(AttributeError):
289+
loop_run(helpers.resolve_ips_async('185.130.44.5', 'v6'))
290+
291+
def test_resolve_ips_hiveseed(self):
292+
"""Test :func:`.resolve_ips` returns expected v4 + v6 for ``hiveseed-fin.privex.io``"""
293+
ips = helpers.resolve_ips('hiveseed-fin.privex.io')
294+
self.assertEqual(len(ips), 2)
295+
self.assertIn('2a01:4f9:2a:3d4::2', ips)
296+
self.assertIn('95.216.3.171', ips)
297+
298+
def test_resolve_ips_hiveseed_v4(self):
299+
"""Test :func:`.resolve_ips` returns only v4 for ``hiveseed-fin.privex.io`` when version is set to v4"""
300+
ips = loop_run(helpers.resolve_ips_async('hiveseed-fin.privex.io', 'v4'))
301+
self.assertEqual(len(ips), 1)
302+
self.assertEqual(ips[0], '95.216.3.171')
303+
304+
def test_resolve_ips_hiveseed_v6(self):
305+
"""Test :func:`.resolve_ips` returns only v6 for ``hiveseed-fin.privex.io`` when version is set to v6"""
306+
ips = helpers.resolve_ips('hiveseed-fin.privex.io', 'v6')
307+
self.assertEqual(len(ips), 1)
308+
self.assertEqual(ips[0], '2a01:4f9:2a:3d4::2')
309+
310+
def test_resolve_ips_v4_convert_false(self):
311+
"""Test :func:`.resolve_ips` returns an empty list for ``microsoft.com`` when v6 requested without v4_convert"""
312+
ips = loop_run(helpers.resolve_ips_async('microsoft.com', 'v6', v4_convert=False))
313+
self.assertEqual(len(ips), 0)
314+
315+
def test_resolve_ips_v4_convert(self):
316+
"""Test :func:`.resolve_ips` returns IPv6-wrapped IPv4 addresses for ``microsoft.com`` when v4_convert is enabled + v6 version"""
317+
ips = loop_run(helpers.resolve_ips_async('microsoft.com', 'v6', v4_convert=True))
318+
if ips is None or len(ips) == 0:
319+
return pytest.skip(
320+
f"Skipping test TestNetResolveIP.test_resolve_ips_v4_convert as v6-wrapped IPv4 addresses "
321+
f"aren't supported on this platform."
322+
)
323+
self.assertTrue(ips[0].startswith('::ffff:'))
324+
325+
# --- privex.helpers.net.resolve_ip ---
326+
327+
def test_resolve_ip_v4_convert(self):
328+
"""Test :func:`.resolve_ip` returns an IPv6-wrapped IPv4 address for ``microsoft.com`` when v4_convert is enabled + v6 version"""
329+
ip = loop_run(helpers.resolve_ip_async('microsoft.com', 'v6', v4_convert=True))
330+
if ip is None:
331+
return pytest.skip(
332+
f"Skipping test TestNetResolveIP.test_resolve_ip_v4_convert as v6-wrapped IPv4 addresses "
333+
f"aren't supported on this platform."
334+
)
335+
self.assertTrue(ip.startswith('::ffff:'))
336+
337+
def test_resolve_ip_hiveseed(self):
338+
"""Test :func:`.resolve_ip` returns expected either correct v4 or v6 for ``hiveseed-fin.privex.io``"""
339+
self.assertIn(loop_run(helpers.resolve_ip_async('hiveseed-fin.privex.io')), ['95.216.3.171', '2a01:4f9:2a:3d4::2'])
340+
341+
def test_resolve_ip_hiveseed_v4(self):
342+
"""Test :func:`.resolve_ip` returns only v4 for ``hiveseed-fin.privex.io`` when version is v4"""
343+
self.assertEqual(loop_run(helpers.resolve_ip_async('hiveseed-fin.privex.io', 'v4')), '95.216.3.171')
344+
345+
def test_resolve_ip_hiveseed_v6(self):
346+
"""Test :func:`.resolve_ip` returns only v6 for ``hiveseed-fin.privex.io`` when version is v6"""
347+
self.assertEqual(loop_run(helpers.resolve_ip_async('hiveseed-fin.privex.io', 'v6')), '2a01:4f9:2a:3d4::2')
348+
349+
@staticmethod
350+
async def _resolve_multi_async(*addr, version='any', v4_convert=False):
351+
res = []
352+
async for x in helpers.resolve_ips_multi_async(*addr, version=version, v4_convert=v4_convert):
353+
res.append(x)
354+
return res
355+
356+
def _resolve_multi(self, *addr, version='any', v4_convert=False):
357+
return loop_run(self._resolve_multi_async(*addr, version=version, v4_convert=v4_convert))
358+
359+
# --- privex.helpers.net.resolve_ips_multi ---
360+
def test_resolve_ips_multi_any(self):
361+
"""Test :func:`.resolve_ips_multi` with 2 domains and an IPv4 address"""
362+
ips = dict(self._resolve_multi('hiveseed-fin.privex.io', 'privex.io', '8.8.4.4'))
363+
self.assertIn('2a01:4f9:2a:3d4::2', ips['hiveseed-fin.privex.io'])
364+
self.assertIn('95.216.3.171', ips['hiveseed-fin.privex.io'])
365+
366+
self.assertIn('2a07:e00::abc', ips['privex.io'])
367+
self.assertIn('185.130.44.10', ips['privex.io'])
368+
369+
self.assertIn('8.8.4.4', ips['8.8.4.4'])
370+
371+
def test_resolve_ips_multi_v4(self):
372+
"""Test :func:`.resolve_ips_multi` with 2 domains, an IPv4 address, and an IPv6 address with version ``v4``"""
373+
ips = dict(self._resolve_multi('hiveseed-fin.privex.io', 'privex.io', '8.8.4.4', '2a07:e00::333', version='v4'))
374+
self.assertNotIn('2a01:4f9:2a:3d4::2', ips['hiveseed-fin.privex.io'])
375+
self.assertIn('95.216.3.171', ips['hiveseed-fin.privex.io'])
376+
377+
self.assertNotIn('2a07:e00::abc', ips['privex.io'])
378+
self.assertIn('185.130.44.10', ips['privex.io'])
379+
380+
self.assertIn('8.8.4.4', ips['8.8.4.4'])
381+
self.assertIsNone(ips['2a07:e00::333'])
382+
383+
def test_resolve_ips_multi_v6(self):
384+
"""Test :func:`.resolve_ips_multi` with 2 domains, an IPv4 address, and an IPv6 address with version ``v6``"""
385+
ips = dict(self._resolve_multi('hiveseed-fin.privex.io', 'privex.io', '8.8.4.4', '2a07:e00::333', version='v6'))
386+
self.assertIn('2a01:4f9:2a:3d4::2', ips['hiveseed-fin.privex.io'])
387+
self.assertNotIn('95.216.3.171', ips['hiveseed-fin.privex.io'])
388+
389+
self.assertIn('2a07:e00::abc', ips['privex.io'])
390+
self.assertNotIn('185.130.44.10', ips['privex.io'])
391+
392+
self.assertIn('2a07:e00::333', ips['2a07:e00::333'])
393+
self.assertIsNone(ips['8.8.4.4'])
394+
395+
396+
class TestAsyncNet(PrivexBaseCase):
397+
def test_get_rdns_privex_ns1_ip(self):
398+
"""Test resolving IPv4 and IPv6 addresses into ns1.privex.io"""
399+
self.assertEqual(loop_run(helpers.get_rdns_async('2a07:e00::100')), 'ns1.privex.io')
400+
self.assertEqual(loop_run(helpers.get_rdns_async('185.130.44.3')), 'ns1.privex.io')
401+
402+
def test_get_rdns_privex_ns1_host(self):
403+
"""Test resolving rDNS for the domains ``steemseed-fin.privex.io`` and ``ns1.privex.io``"""
404+
self.assertEqual(loop_run(helpers.get_rdns_async('ns1.privex.io')), 'ns1.privex.io')
405+
self.assertEqual(loop_run(helpers.get_rdns_async('steemseed-fin.privex.io')), 'hiveseed-fin.privex.io')
406+
407+
def test_get_rdns_invalid_domain(self):
408+
"""Test :func:`.get_rdns` raises :class:`.InvalidHost` when given a non-existent domain"""
409+
with self.assertRaises(helpers.InvalidHost):
410+
loop_run(helpers.get_rdns_async('non-existent.domain.example'))
411+
412+
def test_get_rdns_no_rdns_records(self):
413+
"""Test :func:`.get_rdns` raises :class:`.ReverseDNSNotFound` when given a valid IP that has no rDNS records"""
414+
with self.assertRaises(helpers.ReverseDNSNotFound):
415+
loop_run(helpers.get_rdns_async('192.168.5.1'))
416+
417+
def test_check_host_async(self):
418+
self.assertTrue(loop_run(helpers.check_host_async('hiveseed-se.privex.io', 2001)))
419+
self.assertFalse(loop_run(helpers.check_host_async('hiveseed-se.privex.io', 9991)))
420+
421+
def test_check_host_async_send(self):
422+
http_req = b"GET / HTTP/1.1\n\n"
423+
self.assertTrue(loop_run(helpers.check_host_async('files.privex.io', 80, send=http_req)))
424+
# self.assertTrue(loop_run(helpers.check_host_async('files.privex.io', 443)))
425+
self.assertFalse(loop_run(helpers.check_host_async('files.privex.io', 9991)))
426+
427+
def test_check_host_async_throw(self):
428+
with self.assertRaises(ConnectionRefusedError):
429+
loop_run(helpers.check_host_async('files.privex.io', 9991, throw=True))
430+
431+

0 commit comments

Comments
 (0)