1# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc.
2#
3# Permission to use, copy, modify, and distribute this software and its
4# documentation for any purpose with or without fee is hereby granted,
5# provided that the above copyright notice and this permission notice
6# appear in all copies.
7#
8# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
9# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
11# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
14# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
16"""Generic Internet address helper functions."""
17
18import socket
19
20import dns.ipv4
21import dns.ipv6
22
23
24# We assume that AF_INET is always defined.
25
26AF_INET = socket.AF_INET
27
28# AF_INET6 might not be defined in the socket module, but we need it.
29# We'll try to use the socket module's value, and if it doesn't work,
30# we'll use our own value.
31
32try:
33    AF_INET6 = socket.AF_INET6
34except AttributeError:
35    AF_INET6 = 9999
36
37def inet_pton(family, text):
38    """Convert the textual form of a network address into its binary form.
39
40    @param family: the address family
41    @type family: int
42    @param text: the textual address
43    @type text: string
44    @raises NotImplementedError: the address family specified is not
45    implemented.
46    @rtype: string
47    """
48
49    if family == AF_INET:
50        return dns.ipv4.inet_aton(text)
51    elif family == AF_INET6:
52        return dns.ipv6.inet_aton(text)
53    else:
54        raise NotImplementedError
55
56def inet_ntop(family, address):
57    """Convert the binary form of a network address into its textual form.
58
59    @param family: the address family
60    @type family: int
61    @param address: the binary address
62    @type address: string
63    @raises NotImplementedError: the address family specified is not
64    implemented.
65    @rtype: string
66    """
67    if family == AF_INET:
68        return dns.ipv4.inet_ntoa(address)
69    elif family == AF_INET6:
70        return dns.ipv6.inet_ntoa(address)
71    else:
72        raise NotImplementedError
73
74def af_for_address(text):
75    """Determine the address family of a textual-form network address.
76
77    @param text: the textual address
78    @type text: string
79    @raises ValueError: the address family cannot be determined from the input.
80    @rtype: int
81    """
82    try:
83        junk = dns.ipv4.inet_aton(text)
84        return AF_INET
85    except:
86        try:
87            junk = dns.ipv6.inet_aton(text)
88            return AF_INET6
89        except:
90            raise ValueError
91
92def is_multicast(text):
93    """Is the textual-form network address a multicast address?
94
95    @param text: the textual address
96    @raises ValueError: the address family cannot be determined from the input.
97    @rtype: bool
98    """
99    try:
100        first = ord(dns.ipv4.inet_aton(text)[0])
101        return (first >= 224 and first <= 239)
102    except:
103        try:
104            first = ord(dns.ipv6.inet_aton(text)[0])
105            return (first == 255)
106        except:
107            raise ValueError
108
109