1 | # Copyright (C) 2006, 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 | """DNS Reverse Map Names.
|
---|
17 |
|
---|
18 | @var ipv4_reverse_domain: The DNS IPv4 reverse-map domain, in-addr.arpa.
|
---|
19 | @type ipv4_reverse_domain: dns.name.Name object
|
---|
20 | @var ipv6_reverse_domain: The DNS IPv6 reverse-map domain, ip6.arpa.
|
---|
21 | @type ipv6_reverse_domain: dns.name.Name object
|
---|
22 | """
|
---|
23 |
|
---|
24 | import dns.name
|
---|
25 | import dns.ipv6
|
---|
26 | import dns.ipv4
|
---|
27 |
|
---|
28 | ipv4_reverse_domain = dns.name.from_text('in-addr.arpa.')
|
---|
29 | ipv6_reverse_domain = dns.name.from_text('ip6.arpa.')
|
---|
30 |
|
---|
31 | def from_address(text):
|
---|
32 | """Convert an IPv4 or IPv6 address in textual form into a Name object whose
|
---|
33 | value is the reverse-map domain name of the address.
|
---|
34 | @param text: an IPv4 or IPv6 address in textual form (e.g. '127.0.0.1',
|
---|
35 | '::1')
|
---|
36 | @type text: str
|
---|
37 | @rtype: dns.name.Name object
|
---|
38 | """
|
---|
39 | try:
|
---|
40 | parts = list(dns.ipv6.inet_aton(text).encode('hex_codec'))
|
---|
41 | origin = ipv6_reverse_domain
|
---|
42 | except:
|
---|
43 | parts = ['%d' % ord(byte) for byte in dns.ipv4.inet_aton(text)]
|
---|
44 | origin = ipv4_reverse_domain
|
---|
45 | parts.reverse()
|
---|
46 | return dns.name.from_text('.'.join(parts), origin=origin)
|
---|
47 |
|
---|
48 | def to_address(name):
|
---|
49 | """Convert a reverse map domain name into textual address form.
|
---|
50 | @param name: an IPv4 or IPv6 address in reverse-map form.
|
---|
51 | @type name: dns.name.Name object
|
---|
52 | @rtype: str
|
---|
53 | """
|
---|
54 | if name.is_subdomain(ipv4_reverse_domain):
|
---|
55 | name = name.relativize(ipv4_reverse_domain)
|
---|
56 | labels = list(name.labels)
|
---|
57 | labels.reverse()
|
---|
58 | text = '.'.join(labels)
|
---|
59 | # run through inet_aton() to check syntax and make pretty.
|
---|
60 | return dns.ipv4.inet_ntoa(dns.ipv4.inet_aton(text))
|
---|
61 | elif name.is_subdomain(ipv6_reverse_domain):
|
---|
62 | name = name.relativize(ipv6_reverse_domain)
|
---|
63 | labels = list(name.labels)
|
---|
64 | labels.reverse()
|
---|
65 | parts = []
|
---|
66 | i = 0
|
---|
67 | l = len(labels)
|
---|
68 | while i < l:
|
---|
69 | parts.append(''.join(labels[i:i+4]))
|
---|
70 | i += 4
|
---|
71 | text = ':'.join(parts)
|
---|
72 | # run through inet_aton() to check syntax and make pretty.
|
---|
73 | return dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(text))
|
---|
74 | else:
|
---|
75 | raise dns.exception.SyntaxError('unknown reverse-map address family')
|
---|