Skip to content

Commit

Permalink
Remove socket.inet_pton (#318)
Browse files Browse the repository at this point in the history
Closes #317.

- Remove **socket.inet_pton** which does not reject IPv4 addresses and IPv6 (dual) addresses with leading IPv4 zeroes on macOS.
- Add **test_looks_like_ipv6**
  • Loading branch information
elliotwutingfeng committed Feb 28, 2024
1 parent 4a4e0ec commit 1f77877
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 54 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.language.python-version }}
check-latest: true
- name: Install Python requirements
run: |
pip install --upgrade pip
Expand Down
32 changes: 18 additions & 14 deletions tests/main_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import logging
import os
import sys
import tempfile
from collections.abc import Sequence
from pathlib import Path
Expand All @@ -17,7 +18,7 @@
import tldextract
import tldextract.suffix_list
from tldextract.cache import DiskCache
from tldextract.remote import inet_pton, lenient_netloc, looks_like_ip
from tldextract.remote import lenient_netloc, looks_like_ip, looks_like_ipv6
from tldextract.suffix_list import SuffixListNotFound
from tldextract.tldextract import ExtractResult

Expand Down Expand Up @@ -152,21 +153,24 @@ def test_lenient_netloc() -> None:
)


@pytest.mark.skipif(not inet_pton, reason="inet_pton unavailable")
def test_looks_like_ip_with_inet_pton() -> None:
"""Test preferred function to check if a string looks like an IP address."""
assert looks_like_ip("1.1.1.1", inet_pton) is True
assert looks_like_ip("a.1.1.1", inet_pton) is False
assert looks_like_ip("1.1.1.1\n", inet_pton) is False
assert looks_like_ip("256.256.256.256", inet_pton) is False
def test_looks_like_ip() -> None:
"""Test function to check if a string looks like an IPv4 address."""
assert looks_like_ip("1.1.1.1") is True
assert looks_like_ip("1.1.1.01") is False
assert looks_like_ip("a.1.1.1") is False
assert looks_like_ip("1.1.1.1\n") is False
assert looks_like_ip("256.256.256.256") is False


def test_looks_like_ip_without_inet_pton() -> None:
"""Test fallback function to check if a string looks like an IP address."""
assert looks_like_ip("1.1.1.1", None) is True
assert looks_like_ip("a.1.1.1", None) is False
assert looks_like_ip("1.1.1.1\n", None) is False
assert looks_like_ip("256.256.256.256", None) is False
def test_looks_like_ipv6() -> None:
"""Test function to check if a string looks like an IPv6 address."""
assert looks_like_ipv6("::") is True
assert looks_like_ipv6("aBcD:ef01:2345:6789:aBcD:ef01:aaaa:2288") is True
assert looks_like_ipv6("aBcD:ef01:2345:6789:aBcD:ef01:127.0.0.1") is True
assert looks_like_ipv6("ZBcD:ef01:2345:6789:aBcD:ef01:127.0.0.1") is False
if sys.version_info >= (3, 8, 12): # noqa: UP036
assert looks_like_ipv6("aBcD:ef01:2345:6789:aBcD:ef01:127.0.0.01") is False
assert looks_like_ipv6("aBcD:ef01:2345:6789:aBcD:") is False


def test_similar_to_ip() -> None:
Expand Down
6 changes: 2 additions & 4 deletions tldextract/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ def md5(*args: bytes) -> hashlib._Hash:


def get_pkg_unique_identifier() -> str:
"""
Generate an identifier unique to the python version, tldextract version, and python instance.
"""Generate an identifier unique to the python version, tldextract version, and python instance.
This will prevent interference between virtualenvs and issues that might arise when installing
a new version of tldextract
Expand All @@ -66,8 +65,7 @@ def get_pkg_unique_identifier() -> str:


def get_cache_dir() -> str:
"""
Get a cache dir that we have permission to write to.
"""Get a cache dir that we have permission to write to.
Try to follow the XDG standard, but if that doesn't work fallback to the package directory
http://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
Expand Down
29 changes: 3 additions & 26 deletions tldextract/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,9 @@
from __future__ import annotations

import re
from collections.abc import Callable
from ipaddress import AddressValueError, IPv6Address
from urllib.parse import scheme_chars

inet_pton: Callable[[int, str], bytes] | None
try:
from socket import AF_INET, AF_INET6, inet_pton # Availability: Unix, Windows.
except ImportError:
inet_pton = None

IP_RE = re.compile(
r"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)"
r"{3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
Expand Down Expand Up @@ -59,32 +52,16 @@ def _schemeless_url(url: str) -> str:
return url[double_slashes_start + 2 :]


def looks_like_ip(
maybe_ip: str, pton: Callable[[int, str], bytes] | None = inet_pton
) -> bool:
"""Check whether the given str looks like an IP address."""
def looks_like_ip(maybe_ip: str) -> bool:
"""Check whether the given str looks like an IPv4 address."""
if not maybe_ip[0].isdigit():
return False

if pton is not None:
try:
pton(AF_INET, maybe_ip)
return True
except OSError:
return False
return IP_RE.fullmatch(maybe_ip) is not None


def looks_like_ipv6(
maybe_ip: str, pton: Callable[[int, str], bytes] | None = inet_pton
) -> bool:
def looks_like_ipv6(maybe_ip: str) -> bool:
"""Check whether the given str looks like an IPv6 address."""
if pton is not None:
try:
pton(AF_INET6, maybe_ip)
return True
except OSError:
return False
try:
IPv6Address(maybe_ip)
except AddressValueError:
Expand Down
15 changes: 5 additions & 10 deletions tldextract/tldextract.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,7 @@ class ExtractResult:

@property
def registered_domain(self) -> str:
"""
Joins the domain and suffix fields with a dot, if they're both set.
"""Joins the domain and suffix fields with a dot, if they're both set.
>>> extract('http://forums.bbc.co.uk').registered_domain
'bbc.co.uk'
Expand All @@ -89,8 +88,7 @@ def registered_domain(self) -> str:

@property
def fqdn(self) -> str:
"""
Returns a Fully Qualified Domain Name, if there is a proper domain/suffix.
"""Returns a Fully Qualified Domain Name, if there is a proper domain/suffix.
>>> extract('http://forums.bbc.co.uk/path/to/file').fqdn
'forums.bbc.co.uk'
Expand All @@ -103,8 +101,7 @@ def fqdn(self) -> str:

@property
def ipv4(self) -> str:
"""
Returns the ipv4 if that is what the presented domain/url is.
"""Returns the ipv4 if that is what the presented domain/url is.
>>> extract('http://127.0.0.1/path/to/file').ipv4
'127.0.0.1'
Expand All @@ -123,8 +120,7 @@ def ipv4(self) -> str:

@property
def ipv6(self) -> str:
"""
Returns the ipv6 if that is what the presented domain/url is.
"""Returns the ipv6 if that is what the presented domain/url is.
>>> extract('http://[aBcD:ef01:2345:6789:aBcD:ef01:127.0.0.1]/path/to/file').ipv6
'aBcD:ef01:2345:6789:aBcD:ef01:127.0.0.1'
Expand Down Expand Up @@ -334,8 +330,7 @@ def update(

@property
def tlds(self, session: requests.Session | None = None) -> list[str]:
"""
Returns the list of tld's used by default.
"""Returns the list of tld's used by default.
This will vary based on `include_psl_private_domains` and `extra_suffixes`
"""
Expand Down

0 comments on commit 1f77877

Please sign in to comment.