Functional Weave
Code in Python

net.ipv4@1.0.0

impl/python/parse_ipv4.py

1,540 bytes · the Python implementation · view raw

from typing import Optional


def parse_ipv4(text: str) -> int:
    """The address as an unsigned 32-bit number.

    Only the strict dotted quad is accepted. The C library's inet_aton also
    reads "010.1.1.1" as octal 8.1.1.1, "0x7f.1" as hex and "127.1" as
    127.0.0.1; a validator that agrees with one reader and a socket library
    that agrees with the other is how an allow-list gets bypassed, so all of
    those are refused.
    """
    value = ipv4_value(text)
    if value is None:
        raise ValueError('"%s" is not a dotted-quad IPv4 address' % (text,))
    return value


# Exported for is_ipv4 and for capabilities that parse IPv4 text without
# wanting an error; not part of the group's contract.


def ipv4_value(text: object) -> Optional[int]:
    """The address as a number, or None when the text is not a strict dotted quad."""
    if not isinstance(text, str):
        return None
    parts = text.split(".")
    if len(parts) != 4:
        return None
    value = 0
    for part in parts:
        if len(part) < 1 or len(part) > 3:
            return None
        # "0" <= ch <= "9" rather than isdigit(), which accepts other scripts' digits.
        for ch in part:
            if not ("0" <= ch <= "9"):
                return None
        # A leading zero is where octal readers and decimal readers part company.
        if len(part) > 1 and part[0] == "0":
            return None
        octet = int(part)
        if octet > 255:
            return None
        value = value * 256 + octet
    return value