Esempio n. 1
0
def valid_bin(bin_val, width):
    """
    :param bin_val: A network address in Python's binary representation format
        ('0bxxx').

    :param width: Maximum width (in bits) of a network address (excluding
        delimiters).

    :return: ``True`` if network address is valid, ``False`` otherwise.
    """
    if not _is_str(bin_val):
        return False

    if not bin_val.startswith('0b'):
        return False

    bin_val = bin_val.replace('0b', '')

    if len(bin_val) > width:
        return False

    max_int = 2 ** width - 1

    try:
        if 0 <= int(bin_val, 2) <= max_int:
            return True
    except ValueError:
        pass

    return False
Esempio n. 2
0
    def _set_value(self, value):
        if self._module is None:
            #   EUI version is implicit, detect it from value.
            for module in (_eui48, _eui64):
                try:
                    self._value = module.str_to_int(value)
                    self._module = module
                    break
                except AddrFormatError:
                    try:
                        if 0 <= int(value) <= module.max_int:
                            self._value = int(value)
                            self._module = module
                            break
                    except ValueError:
                        pass

            if self._module is None:
                raise AddrFormatError('failed to detect EUI version: %r' %
                                      value)
        else:
            #   EUI version is explicit.
            if _is_str(value):
                try:
                    self._value = self._module.str_to_int(value)
                except AddrFormatError:
                    raise AddrFormatError('address %r is not an EUIv%d' %
                                          (value, self._module.version))
            else:
                if 0 <= int(value) <= self._module.max_int:
                    self._value = int(value)
                else:
                    raise AddrFormatError('bad address format: %r' % value)
Esempio n. 3
0
def valid_bits(bits, width, word_sep=''):
    """
    :param bits: A network address in a delimited binary string format.

    :param width: Maximum width (in bits) of a network address (excluding
        delimiters).

    :param word_sep: (optional) character or string used to delimit word
        groups (default: '', no separator).

    :return: ``True`` if network address is valid, ``False`` otherwise.
    """
    if not _is_str(bits):
        return False

    if word_sep != '':
        bits = bits.replace(word_sep, '')

    if len(bits) != width:
        return False

    max_int = 2 ** width - 1

    try:
        if 0 <= int(bits, 2) <= max_int:
            return True
    except ValueError:
        pass

    return False
Esempio n. 4
0
def int_to_bits(int_val, word_size, num_words, word_sep=''):
    """
    :param int_val: An unsigned integer.

    :param word_size: Width (in bits) of each unsigned integer word value.

    :param num_words: Number of unsigned integer words expected.

    :param word_sep: (optional) character or string used to delimit word
        groups (default: '', no separator).

    :return: A network address in a delimited binary string format that is
        equivalent in value to unsigned integer.
    """
    bit_words = []

    for word in int_to_words(int_val, word_size, num_words):
        bits = []
        while word:
            bits.append(BYTES_TO_BITS[word & 255])
            word >>= 8
        bits.reverse()
        bit_str = ''.join(bits) or '0' * word_size
        bits = ('0' * word_size + bit_str)[-word_size:]
        bit_words.append(bits)

    if word_sep is not '':
        #   Check custom separator.
        if not _is_str(word_sep):
            raise ValueError('word separator is not a string: %r!' % word_sep)

    return word_sep.join(bit_words)
def valid_bits(bits, width, word_sep=''):
    """
    :param bits: A network address in a delimited binary string format.

    :param width: Maximum width (in bits) of a network address (excluding
        delimiters).

    :param word_sep: (optional) character or string used to delimit word
        groups (default: '', no separator).

    :return: ``True`` if network address is valid, ``False`` otherwise.
    """
    if not _is_str(bits):
        return False

    if word_sep != '':
        bits = bits.replace(word_sep, '')

    if len(bits) != width:
        return False

    max_int = 2**width - 1

    try:
        if 0 <= int(bits, 2) <= max_int:
            return True
    except ValueError:
        pass

    return False
Esempio n. 6
0
def test_compat_py2():
    assert _is_str(unicode(''))

    #   Python 2.x - 8 bit strings are just regular strings
    str_8bit = _bytes_join(['a', 'b', 'c'])
    assert str_8bit == 'abc'.encode()
    assert "'abc'" == '%r' % str_8bit
Esempio n. 7
0
def _inet_pton_af_inet(ip_string):
    """
    Convert an IP address in string format (123.45.67.89) to the 32-bit packed
    binary format used in low-level network functions. Differs from inet_aton
    by only support decimal octets. Using octal or hexadecimal values will
    raise a ValueError exception.
    """
    #TODO: optimise this ... use inet_aton with mods if available ...
    if _is_str(ip_string):
        invalid_addr = ValueError('illegal IP address string %r' % ip_string)
        #   Support for hexadecimal and octal octets.
        tokens = ip_string.split('.')

        #   Pack octets.
        if len(tokens) == 4:
            words = []
            for token in tokens:
                if token.startswith('0x') or \
                  (token.startswith('0') and len(token) > 1):
                    raise invalid_addr
                try:
                    octet = int(token)
                except ValueError:
                    raise invalid_addr

                if (octet >> 8) != 0:
                    raise invalid_addr
                words.append(_pack('B', octet))
            return _bytes_join(words)
        else:
            raise invalid_addr

    raise ValueError('argument should be a string, not %s' % type(ip_string))
def int_to_bits(int_val, word_size, num_words, word_sep=''):
    """
    :param int_val: An unsigned integer.

    :param word_size: Width (in bits) of each unsigned integer word value.

    :param num_words: Number of unsigned integer words expected.

    :param word_sep: (optional) character or string used to delimit word
        groups (default: '', no separator).

    :return: A network address in a delimited binary string format that is
        equivalent in value to unsigned integer.
    """
    bit_words = []

    for word in int_to_words(int_val, word_size, num_words):
        bits = []
        while word:
            bits.append(BYTES_TO_BITS[word & 255])
            word >>= 8
        bits.reverse()
        bit_str = ''.join(bits) or '0' * word_size
        bits = ('0' * word_size + bit_str)[-word_size:]
        bit_words.append(bits)

    if word_sep is not '':
        #   Check custom separator.
        if not _is_str(word_sep):
            raise ValueError('word separator is not a string: %r!' % word_sep)

    return word_sep.join(bit_words)
Esempio n. 9
0
def inet_ntop(af, packed_ip):
    """Convert an packed IP address of the given family to string format."""
    if af == AF_INET:
        #   IPv4.
        return inet_ntoa(packed_ip)
    elif af == AF_INET6:
        #   IPv6.
        if len(packed_ip) != 16 or not _is_str(packed_ip):
            raise ValueError('invalid length of packed IP address string')

        tokens = ['%x' % i for i in _unpack('>8H', packed_ip)]

        #   Convert packed address to an integer value.
        words = list(_unpack('>8H', packed_ip))
        int_val = 0
        for i, num in enumerate(reversed(words)):
            word = num
            word = word << 16 * i
            int_val = int_val | word

        if 0xffff < int_val <= 0xffffffff or int_val >> 32 == 0xffff:
            #   IPv4 compatible / mapped IPv6.
            packed_ipv4 = _pack('>2H', *[int(i, 16) for i in tokens[-2:]])
            ipv4_str = inet_ntoa(packed_ipv4)
            tokens = tokens[0:-2] + [ipv4_str]

        return ':'.join(_compact_ipv6_tokens(tokens))
    else:
        raise ValueError('unknown address family %d' % af)
def valid_bin(bin_val, width):
    """
    :param bin_val: A network address in Python's binary representation format
        ('0bxxx').

    :param width: Maximum width (in bits) of a network address (excluding
        delimiters).

    :return: ``True`` if network address is valid, ``False`` otherwise.
    """
    if not _is_str(bin_val):
        return False

    if not bin_val.startswith('0b'):
        return False

    bin_val = bin_val.replace('0b', '')

    if len(bin_val) > width:
        return False

    max_int = 2**width - 1

    try:
        if 0 <= int(bin_val, 2) <= max_int:
            return True
    except ValueError:
        pass

    return False
Esempio n. 11
0
    def _set_value(self, value):
        if self._module is None:
            #   EUI version is implicit, detect it from value.
            for module in (_eui48, _eui64):
                try:
                    self._value = module.str_to_int(value)
                    self._module = module
                    break
                except AddrFormatError:
                    try:
                        if 0 <= int(value) <= module.max_int:
                            self._value = int(value)
                            self._module = module
                            break
                    except ValueError:
                        pass

            if self._module is None:
                raise AddrFormatError("failed to detect EUI version: %r" % value)
        else:
            #   EUI version is explicit.
            if _is_str(value):
                try:
                    self._value = self._module.str_to_int(value)
                except AddrFormatError:
                    raise AddrFormatError("address %r is not an EUIv%d" % (value, self._module.version))
            else:
                if 0 <= int(value) <= self._module.max_int:
                    self._value = int(value)
                else:
                    raise AddrFormatError("bad address format: %r" % value)
Esempio n. 12
0
def _inet_pton_af_inet(ip_string):
    """
    Convert an IP address in string format (123.45.67.89) to the 32-bit packed
    binary format used in low-level network functions. Differs from inet_aton
    by only support decimal octets. Using octal or hexadecimal values will
    raise a ValueError exception.
    """
    #TODO: optimise this ... use inet_aton with mods if available ...
    if _is_str(ip_string):
        invalid_addr = ValueError('illegal IP address string %r' % ip_string)
        #   Support for hexadecimal and octal octets.
        tokens = ip_string.split('.')

        #   Pack octets.
        if len(tokens) == 4:
            words = []
            for token in tokens:
                if token.startswith('0x') or (token.startswith('0')
                                              and len(token) > 1):
                    raise invalid_addr
                try:
                    octet = int(token)
                except ValueError:
                    raise invalid_addr

                if (octet >> 8) != 0:
                    raise invalid_addr
                words.append(_pack('B', octet))
            return _bytes_join(words)
        else:
            raise invalid_addr

    raise ValueError('argument should be a string, not %s' % type(ip_string))
Esempio n. 13
0
def test_compat_py2():
    assert _is_str(unicode(''))

    #   Python 2.x - 8 bit strings are just regular strings
    str_8bit = _bytes_join(['a', 'b', 'c'])
    assert str_8bit == 'abc'.encode()
    assert "'abc'" == '%r' % str_8bit
Esempio n. 14
0
def inet_ntop(af, packed_ip):
    """Convert an packed IP address of the given family to string format."""
    if af == AF_INET:
        #   IPv4.
        return inet_ntoa(packed_ip)
    elif af == AF_INET6:
        #   IPv6.
        if len(packed_ip) != 16 or not _is_str(packed_ip):
            raise ValueError('invalid length of packed IP address string')

        tokens = ['%x' % i for i in _unpack('>8H', packed_ip)]

        #   Convert packed address to an integer value.
        words = list(_unpack('>8H', packed_ip))
        int_val = 0
        for i, num in enumerate(reversed(words)):
            word = num
            word = word << 16 * i
            int_val = int_val | word

        if 0xffff < int_val <= 0xffffffff or int_val >> 32 == 0xffff:
            #   IPv4 compatible / mapped IPv6.
            packed_ipv4 = _pack('>2H', *[int(i, 16) for i in tokens[-2:]])
            ipv4_str = inet_ntoa(packed_ipv4)
            tokens = tokens[0:-2] + [ipv4_str]

        return ':'.join(_compact_ipv6_tokens(tokens))
    else:
        raise ValueError('unknown address family %d' % af)
Esempio n. 15
0
def test_compat_py3():
    assert _is_str(''.encode())

    #   byte string join tests.
    str_8bit = _bytes_join(['a'.encode(), 'b'.encode(), 'c'.encode()])

    assert str_8bit == 'abc'.encode()
    assert "b'abc'" == '%r' % str_8bit
Esempio n. 16
0
def test_compat_py3():
    assert _is_str(''.encode())

    #   byte string join tests.
    str_8bit = _bytes_join(['a'.encode(), 'b'.encode(), 'c'.encode()])

    assert str_8bit == 'abc'.encode()
    assert "b'abc'" == '%r' % str_8bit
Esempio n. 17
0
def inet_ntoa(packed_ip):
    """
    Convert an IP address from 32-bit packed binary format to string format.
    """
    if not _is_str(packed_ip):
        raise TypeError('string type expected, not %s' % str(type(packed_ip)))

    if len(packed_ip) != 4:
        raise ValueError('invalid length of packed IP address string')

    return '%d.%d.%d.%d' % _unpack('4B', packed_ip)
Esempio n. 18
0
def inet_ntoa(packed_ip):
    """
    Convert an IP address from 32-bit packed binary format to string format.
    """
    if not _is_str(packed_ip):
        raise TypeError('string type expected, not %s' % str(type(packed_ip)))

    if len(packed_ip) != 4:
        raise ValueError('invalid length of packed IP address string')

    return '%d.%d.%d.%d' % _unpack('4B', packed_ip)
Esempio n. 19
0
def valid_glob(ipglob):
    """
    :param ipglob: An IP address range in a glob-style format.

    :return: ``True`` if IP range glob is valid, ``False`` otherwise.
    """
    #TODO: Add support for abbreviated ipglobs.
    #TODO: e.g. 192.0.*.* == 192.0.*
    #TODO:      *.*.*.*     == *
    #TODO: Add strict flag to enable verbose ipglob checking.
    if not _is_str(ipglob):
        return False

    seen_hyphen = False
    seen_asterisk = False

    octets = ipglob.split('.')

    if len(octets) != 4:
        return False

    for octet in octets:
        if '-' in octet:
            if seen_hyphen:
                return False
            seen_hyphen = True
            if seen_asterisk:
                #   Asterisks cannot precede hyphenated octets.
                return False
            try:
                (octet1, octet2) = [int(i) for i in octet.split('-')]
            except ValueError:
                return False
            if octet1 >= octet2:
                return False
            if not 0 <= octet1 <= 254:
                return False
            if not 1 <= octet2 <= 255:
                return False
        elif octet == '*':
            seen_asterisk = True
        else:
            if seen_hyphen is True:
                return False
            if seen_asterisk is True:
                return False
            try:
                if not 0 <= int(octet) <= 255:
                    return False
            except ValueError:
                return False
    return True
Esempio n. 20
0
def valid_glob(ipglob):
    """
    :param ipglob: An IP address range in a glob-style format.

    :return: ``True`` if IP range glob is valid, ``False`` otherwise.
    """
    #TODO: Add support for abbreviated ipglobs.
    #TODO: e.g. 192.0.*.* == 192.0.*
    #TODO:      *.*.*.*     == *
    #TODO: Add strict flag to enable verbose ipglob checking.
    if not _is_str(ipglob):
        return False

    seen_hyphen = False
    seen_asterisk = False

    octets = ipglob.split('.')

    if len(octets) != 4:
        return False

    for octet in octets:
        if '-' in octet:
            if seen_hyphen:
                return False
            seen_hyphen = True
            if seen_asterisk:
                #   Asterisks cannot precede hyphenated octets.
                return False
            try:
                (octet1, octet2) = [int(i) for i in octet.split('-')]
            except ValueError:
                return False
            if octet1 >= octet2:
                return False
            if not 0 <= octet1 <= 254:
                return False
            if not 1 <= octet2 <= 255:
                return False
        elif octet == '*':
            seen_asterisk = True
        else:
            if seen_hyphen is True:
                return False
            if seen_asterisk is True:
                return False
            try:
                if not 0 <= int(octet) <= 255:
                    return False
            except ValueError:
                return False
    return True
def str_to_int(addr):
    """
    :param addr: An IEEE EUI-48 (MAC) address in string form.

    :return: An unsigned integer that is equivalent to value represented
        by EUI-48/MAC string address formatted according to the dialect
        settings.
    """
    words = []
    if _is_str(addr):
        found_match = False
        for regexp in RE_MAC_FORMATS:
            match_result = regexp.findall(addr)
            if len(match_result) != 0:
                found_match = True
                if isinstance(match_result[0], tuple):
                    words = match_result[0]
                else:
                    words = (match_result[0], )
                break
        if not found_match:
            raise AddrFormatError('%r is not a supported MAC format!' %
                                  (addr, ))
    else:
        raise TypeError('%r is not str() or unicode()!' % (addr, ))

    int_val = None

    if len(words) == 6:
        #   2 bytes x 6 (UNIX, Windows, EUI-48)
        int_val = int(''.join(['%.2x' % int(w, 16) for w in words]), 16)
    elif len(words) == 3:
        #   4 bytes x 3 (Cisco)
        int_val = int(''.join(['%.4x' % int(w, 16) for w in words]), 16)
    elif len(words) == 2:
        #   6 bytes x 2 (PostgreSQL)
        int_val = int(''.join(['%.6x' % int(w, 16) for w in words]), 16)
    elif len(words) == 1:
        #   12 bytes (bare, no delimiters)
        int_val = int('%012x' % int(words[0], 16), 16)
    else:
        raise AddrFormatError('unexpected word count in MAC address %r!' %
                              (addr, ))

    return int_val
Esempio n. 22
0
def inet_aton(ip_string):
    """
    Convert an IP address in string format (123.45.67.89) to the 32-bit packed
    binary format used in low-level network functions.
    """
    if _is_str(ip_string):
        invalid_addr = ValueError('illegal IP address string %r' % ip_string)
        #   Support for hexadecimal and octal octets.
        tokens = []

        base = 10
        for token in ip_string.split('.'):
            if token.startswith('0x'):
                base = 16
            elif token.startswith('0') and len(token) > 1:
                base = 8
            elif token == '':
                continue
            try:
                tokens.append(int(token, base))
            except ValueError:
                raise invalid_addr

        #   Zero fill missing octets.
        num_tokens = len(tokens)
        if num_tokens < 4:
            fill_tokens = [0] * (4 - num_tokens)
            if num_tokens > 1:
                end_token = tokens.pop()
                tokens = tokens + fill_tokens + [end_token]
            else:
                tokens = tokens + fill_tokens

        #   Pack octets.
        if len(tokens) == 4:
            words = []
            for token in tokens:
                if (token >> 8) != 0:
                    raise invalid_addr
                words.append(_pack('B', token))
            return _bytes_join(words)
        else:
            raise invalid_addr

    raise ValueError('argument should be a string, not %s' % type(ip_string))
Esempio n. 23
0
def _generate_nmap_octet_ranges(nmap_target_spec):
    #   Generate 4 lists containing all octets defined by a given nmap Target
    #   specification.
    if not _is_str(nmap_target_spec):
        raise TypeError('string expected, not %s' % type(nmap_target_spec))

    if not nmap_target_spec:
        raise ValueError('nmap target specification cannot be blank!')

    tokens = nmap_target_spec.split('.')

    if len(tokens) != 4:
        raise AddrFormatError('invalid nmap range: %s' % nmap_target_spec)

    return (_nmap_octet_target_values(tokens[0]),
            _nmap_octet_target_values(tokens[1]),
            _nmap_octet_target_values(tokens[2]),
            _nmap_octet_target_values(tokens[3]))
Esempio n. 24
0
def _generate_nmap_octet_ranges(nmap_target_spec):
    #   Generate 4 lists containing all octets defined by a given nmap Target
    #   specification.
    if not _is_str(nmap_target_spec):
        raise TypeError('string expected, not %s' % type(nmap_target_spec))

    if not nmap_target_spec:
        raise ValueError('nmap target specification cannot be blank!')

    tokens = nmap_target_spec.split('.')

    if len(tokens) != 4:
        raise AddrFormatError('invalid nmap range: %s' % nmap_target_spec)

    return (_nmap_octet_target_values(tokens[0]),
            _nmap_octet_target_values(tokens[1]),
            _nmap_octet_target_values(tokens[2]),
            _nmap_octet_target_values(tokens[3]))
Esempio n. 25
0
def str_to_int(addr):
    """
    :param addr: An IEEE EUI-48 (MAC) address in string form.

    :return: An unsigned integer that is equivalent to value represented
        by EUI-48/MAC string address formatted according to the dialect
        settings.
    """
    words = []
    if _is_str(addr):
        found_match = False
        for regexp in RE_MAC_FORMATS:
            match_result = regexp.findall(addr)
            if len(match_result) != 0:
                found_match = True
                if isinstance(match_result[0], tuple):
                    words = match_result[0]
                else:
                    words = (match_result[0],)
                break
        if not found_match:
            raise AddrFormatError('%r is not a supported MAC format!' % addr)
    else:
        raise TypeError('%r is not str() or unicode()!' % addr)

    int_val = None

    if len(words) == 6:
        #   2 bytes x 6 (UNIX, Windows, EUI-48)
        int_val = int(''.join(['%.2x' % int(w, 16) for w in words]), 16)
    elif len(words) == 3:
        #   4 bytes x 3 (Cisco)
        int_val = int(''.join(['%.4x' % int(w, 16) for w in words]), 16)
    elif len(words) == 2:
        #   6 bytes x 2 (PostgreSQL)
        int_val = int(''.join(['%.6x' % int(w, 16) for w in words]), 16)
    elif len(words) == 1:
        #   12 bytes (bare, no delimiters)
        int_val = int('%012x' % int(words[0], 16), 16)
    else:
        raise AddrFormatError('unexpected word count in MAC address %r!' \
            % addr)

    return int_val
Esempio n. 26
0
def str_to_int(addr):
    """
    :param addr: An IEEE EUI-64 indentifier in string form.

    :return: An unsigned integer that is equivalent to value represented
        by EUI-64 string identifier.
    """
    words = []

    try:
        words = _get_match_result(addr, RE_EUI64_FORMATS)
        if not words:
            raise TypeError
    except TypeError:
        raise AddrFormatError('invalid IEEE EUI-64 identifier: %r!' % addr)

    if _is_str(words):
        return int(words, 16)
    if len(words) != num_words:
        raise AddrFormatError('bad word count for EUI-64 identifier: %r!' \
            % addr)

    return int(''.join(['%.2x' % int(w, 16) for w in words]), 16)
Esempio n. 27
0
def str_to_int(addr):
    """
    :param addr: An IEEE EUI-64 indentifier in string form.

    :return: An unsigned integer that is equivalent to value represented
        by EUI-64 string identifier.
    """
    words = []

    try:
        words = _get_match_result(addr, RE_EUI64_FORMATS)
        if not words:
            raise TypeError
    except TypeError:
        raise AddrFormatError('invalid IEEE EUI-64 identifier: %r!' % addr)

    if _is_str(words):
        return int(words, 16)
    if len(words) != num_words:
        raise AddrFormatError(
            'bad word count for EUI-64 identifier: %r!' % addr)

    return int(''.join(['%.2x' % int(w, 16) for w in words]), 16)
Esempio n. 28
0
def test_compat_string_and_int_detection():
    assert _is_int(_sys_maxint)
    assert not _is_str(_sys_maxint)
    assert _is_str('')
    assert _is_str(''.encode())
Esempio n. 29
0
def inet_pton(af, ip_string):
    """
    Convert an IP address from string format to a packed string suitable for
    use with low-level network functions.
    """
    if af == AF_INET:
        #   IPv4.
        return _inet_pton_af_inet(ip_string)
    elif af == AF_INET6:
        invalid_addr = ValueError('illegal IP address string %r' % ip_string)
        #   IPv6.
        values = []

        if not _is_str(ip_string):
            raise invalid_addr

        if 'x' in ip_string:
            #   Don't accept hextets with the 0x prefix.
            raise invalid_addr

        if '::' in ip_string:
            if ip_string == '::':
                #   Unspecified address.
                return '\x00'.encode() * 16
            #   IPv6 compact mode.
            try:
                prefix, suffix = ip_string.split('::')
            except ValueError:
                raise invalid_addr

            l_prefix = []
            l_suffix = []

            if prefix != '':
                l_prefix = prefix.split(':')

            if suffix != '':
                l_suffix = suffix.split(':')

            #   IPv6 compact IPv4 compatibility mode.
            if len(l_suffix) and '.' in l_suffix[-1]:
                ipv4_str = _inet_pton_af_inet(l_suffix.pop())
                l_suffix.append('%x' % _unpack('>H', ipv4_str[0:2])[0])
                l_suffix.append('%x' % _unpack('>H', ipv4_str[2:4])[0])

            token_count = len(l_prefix) + len(l_suffix)

            if not 0 <= token_count <= 8 - 1:
                raise invalid_addr

            gap_size = 8 - ( len(l_prefix) + len(l_suffix) )

            values = [_pack('>H', int(i, 16)) for i in l_prefix] \
                   + ['\x00\x00'.encode() for i in range(gap_size)] \
                   + [_pack('>H', int(i, 16)) for i in l_suffix]
            try:
                for token in l_prefix + l_suffix:
                    word = int(token, 16)
                    if not 0 <= word <= 0xffff:
                        raise invalid_addr
            except ValueError:
                raise invalid_addr
        else:
            #   IPv6 verbose mode.
            if ':' in ip_string:
                tokens = ip_string.split(':')

                if '.' in ip_string:
                    ipv6_prefix = tokens[:-1]
                    if ipv6_prefix[:-1] != ['0', '0', '0', '0', '0']:
                        raise invalid_addr

                    if ipv6_prefix[-1].lower() not in ('0', 'ffff'):
                        raise invalid_addr

                    #   IPv6 verbose IPv4 compatibility mode.
                    if len(tokens) != 7:
                        raise invalid_addr

                    ipv4_str = _inet_pton_af_inet(tokens.pop())
                    tokens.append('%x' % _unpack('>H', ipv4_str[0:2])[0])
                    tokens.append('%x' % _unpack('>H', ipv4_str[2:4])[0])

                    values = [_pack('>H', int(i, 16)) for i in tokens]
                else:
                    #   IPv6 verbose mode.
                    if len(tokens) != 8:
                        raise invalid_addr
                try:
                    tokens = [int(token, 16) for token in tokens]
                    for token in tokens:
                        if not 0 <= token <= 0xffff:
                            raise invalid_addr

                except ValueError:
                    raise invalid_addr

                values = [_pack('>H', i) for i in tokens]
            else:
                raise invalid_addr

        return _bytes_join(values)
    else:
        raise ValueError('Unknown address family %d' % af)
Esempio n. 30
0
def inet_pton(af, ip_string):
    """
    Convert an IP address from string format to a packed string suitable for
    use with low-level network functions.
    """
    if af == AF_INET:
        #   IPv4.
        return _inet_pton_af_inet(ip_string)
    elif af == AF_INET6:
        invalid_addr = ValueError('illegal IP address string %r' % ip_string)
        #   IPv6.
        values = []

        if not _is_str(ip_string):
            raise invalid_addr

        if 'x' in ip_string:
            #   Don't accept hextets with the 0x prefix.
            raise invalid_addr

        if '::' in ip_string:
            if ip_string == '::':
                #   Unspecified address.
                return '\x00'.encode() * 16
            #   IPv6 compact mode.
            try:
                prefix, suffix = ip_string.split('::')
            except ValueError:
                raise invalid_addr

            l_prefix = []
            l_suffix = []

            if prefix != '':
                l_prefix = prefix.split(':')

            if suffix != '':
                l_suffix = suffix.split(':')

            #   IPv6 compact IPv4 compatibility mode.
            if len(l_suffix) and '.' in l_suffix[-1]:
                ipv4_str = _inet_pton_af_inet(l_suffix.pop())
                l_suffix.append('%x' % _unpack('>H', ipv4_str[0:2])[0])
                l_suffix.append('%x' % _unpack('>H', ipv4_str[2:4])[0])

            token_count = len(l_prefix) + len(l_suffix)

            if not 0 <= token_count <= 8 - 1:
                raise invalid_addr

            gap_size = 8 - (len(l_prefix) + len(l_suffix))

            values = ([_pack('>H', int(i, 16)) for i in l_prefix] +
                      ['\x00\x00'.encode() for i in range(gap_size)] +
                      [_pack('>H', int(i, 16)) for i in l_suffix])
            try:
                for token in l_prefix + l_suffix:
                    word = int(token, 16)
                    if not 0 <= word <= 0xffff:
                        raise invalid_addr
            except ValueError:
                raise invalid_addr
        else:
            #   IPv6 verbose mode.
            if ':' in ip_string:
                tokens = ip_string.split(':')

                if '.' in ip_string:
                    ipv6_prefix = tokens[:-1]
                    if ipv6_prefix[:-1] != ['0', '0', '0', '0', '0']:
                        raise invalid_addr

                    if ipv6_prefix[-1].lower() not in ('0', 'ffff'):
                        raise invalid_addr

                    #   IPv6 verbose IPv4 compatibility mode.
                    if len(tokens) != 7:
                        raise invalid_addr

                    ipv4_str = _inet_pton_af_inet(tokens.pop())
                    tokens.append('%x' % _unpack('>H', ipv4_str[0:2])[0])
                    tokens.append('%x' % _unpack('>H', ipv4_str[2:4])[0])

                    values = [_pack('>H', int(i, 16)) for i in tokens]
                else:
                    #   IPv6 verbose mode.
                    if len(tokens) != 8:
                        raise invalid_addr
                try:
                    tokens = [int(token, 16) for token in tokens]
                    for token in tokens:
                        if not 0 <= token <= 0xffff:
                            raise invalid_addr

                except ValueError:
                    raise invalid_addr

                values = [_pack('>H', i) for i in tokens]
            else:
                raise invalid_addr

        return _bytes_join(values)
    else:
        raise ValueError('Unknown address family %d' % af)
Esempio n. 31
0
def test_compat_string_and_int_detection():
    assert _is_int(_sys_maxint)
    assert not _is_str(_sys_maxint)
    assert _is_str('')
    assert _is_str(''.encode())