123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- # Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
- # Copyright (C) 2003-2017 Nominum, Inc.
- #
- # Permission to use, copy, modify, and distribute this software and its
- # documentation for any purpose with or without fee is hereby granted,
- # provided that the above copyright notice and this permission notice
- # appear in all copies.
- #
- # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
- # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
- # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- """Generic Internet address helper functions."""
- import socket
- import dns.ipv4
- import dns.ipv6
- # We assume that AF_INET and AF_INET6 are always defined. We keep
- # these here for the benefit of any old code (unlikely though that
- # is!).
- AF_INET = socket.AF_INET
- AF_INET6 = socket.AF_INET6
- def inet_pton(family, text):
- """Convert the textual form of a network address into its binary form.
- *family* is an ``int``, the address family.
- *text* is a ``str``, the textual address.
- Raises ``NotImplementedError`` if the address family specified is not
- implemented.
- Returns a ``bytes``.
- """
- if family == AF_INET:
- return dns.ipv4.inet_aton(text)
- elif family == AF_INET6:
- return dns.ipv6.inet_aton(text, True)
- else:
- raise NotImplementedError
- def inet_ntop(family, address):
- """Convert the binary form of a network address into its textual form.
- *family* is an ``int``, the address family.
- *address* is a ``bytes``, the network address in binary form.
- Raises ``NotImplementedError`` if the address family specified is not
- implemented.
- Returns a ``str``.
- """
- if family == AF_INET:
- return dns.ipv4.inet_ntoa(address)
- elif family == AF_INET6:
- return dns.ipv6.inet_ntoa(address)
- else:
- raise NotImplementedError
- def af_for_address(text):
- """Determine the address family of a textual-form network address.
- *text*, a ``str``, the textual address.
- Raises ``ValueError`` if the address family cannot be determined
- from the input.
- Returns an ``int``.
- """
- try:
- dns.ipv4.inet_aton(text)
- return AF_INET
- except Exception:
- try:
- dns.ipv6.inet_aton(text, True)
- return AF_INET6
- except Exception:
- raise ValueError
- def is_multicast(text):
- """Is the textual-form network address a multicast address?
- *text*, a ``str``, the textual address.
- Raises ``ValueError`` if the address family cannot be determined
- from the input.
- Returns a ``bool``.
- """
- try:
- first = dns.ipv4.inet_aton(text)[0]
- return first >= 224 and first <= 239
- except Exception:
- try:
- first = dns.ipv6.inet_aton(text, True)[0]
- return first == 255
- except Exception:
- raise ValueError
- def is_address(text):
- """Is the specified string an IPv4 or IPv6 address?
- *text*, a ``str``, the textual address.
- Returns a ``bool``.
- """
- try:
- dns.ipv4.inet_aton(text)
- return True
- except Exception:
- try:
- dns.ipv6.inet_aton(text, True)
- return True
- except Exception:
- return False
- def low_level_address_tuple(high_tuple, af=None):
- """Given a "high-level" address tuple, i.e.
- an (address, port) return the appropriate "low-level" address tuple
- suitable for use in socket calls.
- If an *af* other than ``None`` is provided, it is assumed the
- address in the high-level tuple is valid and has that af. If af
- is ``None``, then af_for_address will be called.
- """
- address, port = high_tuple
- if af is None:
- af = af_for_address(address)
- if af == AF_INET:
- return (address, port)
- elif af == AF_INET6:
- i = address.find('%')
- if i < 0:
- # no scope, shortcut!
- return (address, port, 0, 0)
- # try to avoid getaddrinfo()
- addrpart = address[:i]
- scope = address[i + 1:]
- if scope.isdigit():
- return (addrpart, port, 0, int(scope))
- try:
- return (addrpart, port, 0, socket.if_nametoindex(scope))
- except AttributeError: # pragma: no cover (we can't really test this)
- ai_flags = socket.AI_NUMERICHOST
- ((*_, tup), *_) = socket.getaddrinfo(address, port, flags=ai_flags)
- return tup
- else:
- raise NotImplementedError(f'unknown address family {af}')
|