]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
Add support for the AMTRELAY type.
authorBrian Wellington <bwelling@xbill.org>
Wed, 1 Jul 2020 17:32:19 +0000 (10:32 -0700)
committerBrian Wellington <bwelling@xbill.org>
Wed, 1 Jul 2020 17:33:49 +0000 (10:33 -0700)
dns/rdatatype.py
dns/rdtypes/ANY/AMTRELAY.py [new file with mode: 0644]
dns/rdtypes/IN/IPSECKEY.py
dns/rdtypes/__init__.py
dns/rdtypes/util.py [new file with mode: 0644]
tests/example
tests/example1.good
tests/example2.good
tests/example3.good

index 7769657c0187ca8c25609c9a50f5fdcc7756c2cb..c793d5a0d85f11888459dc9371f5ac56fa6dee21 100644 (file)
@@ -92,6 +92,7 @@ class RdataType(dns.enum.IntEnum):
     URI = 256
     CAA = 257
     AVC = 258
+    AMTRELAY = 259
     TA = 32768
     DLV = 32769
 
diff --git a/dns/rdtypes/ANY/AMTRELAY.py b/dns/rdtypes/ANY/AMTRELAY.py
new file mode 100644 (file)
index 0000000..8fb18c1
--- /dev/null
@@ -0,0 +1,87 @@
+# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
+
+# Copyright (C) 2006, 2007, 2009-2011 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.
+
+import struct
+
+import dns.exception
+import dns.rdtypes.util
+
+
+class Relay(dns.rdtypes.util.Gateway):
+    name = 'AMTRELAY relay'
+
+class AMTRELAY(dns.rdata.Rdata):
+
+    """AMTRELAY record"""
+
+    # see: RFC 8777
+
+    __slots__ = ['precedence', 'discovery_optional', 'relay_type', 'relay']
+
+    def __init__(self, rdclass, rdtype, precedence, discovery_optional,
+                 relay_type, relay):
+        super().__init__(rdclass, rdtype)
+        Relay(relay_type, relay).check()
+        object.__setattr__(self, 'precedence', precedence)
+        object.__setattr__(self, 'discovery_optional', discovery_optional)
+        object.__setattr__(self, 'relay_type', relay_type)
+        object.__setattr__(self, 'relay', relay)
+
+    def to_text(self, origin=None, relativize=True, **kw):
+        relay = Relay(self.relay_type, self.relay).to_text(origin, relativize)
+        return '%d %d %d %s' % (self.precedence, self.discovery_optional,
+                                self.relay_type, relay)
+
+    @classmethod
+    def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
+                  relativize_to=None):
+        precedence = tok.get_uint8()
+        discovery_optional = tok.get_uint8()
+        if discovery_optional > 1:
+            raise dns.exception.SyntaxError('expecting 0 or 1')
+        discovery_optional = bool(discovery_optional)
+        relay_type = tok.get_uint8()
+        if relay_type > 0x7f:
+            raise dns.exception.SyntaxError('expecting an integer <= 127')
+        relay = Relay(relay_type).from_text(tok, origin, relativize,
+                                            relativize_to)
+        return cls(rdclass, rdtype, precedence, discovery_optional, relay_type,
+                   relay)
+
+    def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
+        relay_type = self.relay_type | (self.discovery_optional << 7)
+        header = struct.pack("!BB", self.precedence, relay_type)
+        file.write(header)
+        Relay(self.relay_type, self.relay).to_wire(file, compress, origin,
+                                                   canonicalize)
+
+    @classmethod
+    def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None):
+        if rdlen < 2:
+            raise dns.exception.FormError
+        (precedence, relay_type) = struct.unpack('!BB',
+                                                 wire[current: current + 2])
+        current += 2
+        rdlen -= 2
+        discovery_optional = bool(relay_type >> 7)
+        relay_type &= 0x7f
+        (relay, cused) = Relay(relay_type).from_wire(wire, current, rdlen,
+                                                     origin)
+        current += cused
+        rdlen -= cused
+        return cls(rdclass, rdtype, precedence, discovery_optional, relay_type,
+                   relay)
index b5bc0b3d484ff07c20aee5ca7fce7a02832ab1fa..6d0f42593aa9068e1e386ea3a553f2d535530add 100644 (file)
@@ -19,11 +19,12 @@ import struct
 import base64
 
 import dns.exception
-import dns.ipv4
-import dns.ipv6
-import dns.name
+import dns.rdtypes.util
 
 
+class Gateway(dns.rdtypes.util.Gateway):
+    name = 'IPSECKEY gateway'
+
 class IPSECKEY(dns.rdata.Rdata):
 
     """IPSECKEY record"""
@@ -35,21 +36,7 @@ class IPSECKEY(dns.rdata.Rdata):
     def __init__(self, rdclass, rdtype, precedence, gateway_type, algorithm,
                  gateway, key):
         super().__init__(rdclass, rdtype)
-        if gateway_type == 0:
-            if gateway != '.' and gateway is not None:
-                raise SyntaxError('invalid gateway for gateway type 0')
-            gateway = None
-        elif gateway_type == 1:
-            # check that it's OK
-            dns.ipv4.inet_aton(gateway)
-        elif gateway_type == 2:
-            # check that it's OK
-            dns.ipv6.inet_aton(gateway)
-        elif gateway_type == 3:
-            pass
-        else:
-            raise SyntaxError(
-                'invalid IPSECKEY gateway type: %d' % gateway_type)
+        Gateway(gateway_type, gateway).check()
         object.__setattr__(self, 'precedence', precedence)
         object.__setattr__(self, 'gateway_type', gateway_type)
         object.__setattr__(self, 'algorithm', algorithm)
@@ -57,16 +44,8 @@ class IPSECKEY(dns.rdata.Rdata):
         object.__setattr__(self, 'key', key)
 
     def to_text(self, origin=None, relativize=True, **kw):
-        if self.gateway_type == 0:
-            gateway = '.'
-        elif self.gateway_type == 1:
-            gateway = self.gateway
-        elif self.gateway_type == 2:
-            gateway = self.gateway
-        elif self.gateway_type == 3:
-            gateway = str(self.gateway.choose_relativity(origin, relativize))
-        else:
-            raise ValueError('invalid gateway type')
+        gateway = Gateway(self.gateway_type, self.gateway).to_text(origin,
+                                                                   relativize)
         return '%d %d %d %s %s' % (self.precedence, self.gateway_type,
                                    self.algorithm, gateway,
                                    dns.rdata._base64ify(self.key))
@@ -77,10 +56,8 @@ class IPSECKEY(dns.rdata.Rdata):
         precedence = tok.get_uint8()
         gateway_type = tok.get_uint8()
         algorithm = tok.get_uint8()
-        if gateway_type == 3:
-            gateway = tok.get_name(origin, relativize, relativize_to)
-        else:
-            gateway = tok.get_string()
+        gateway = Gateway(gateway_type).from_text(tok, origin, relativize,
+                                                  relativize_to)
         b64 = tok.concatenate_remaining_identifiers().encode()
         key = base64.b64decode(b64)
         return cls(rdclass, rdtype, precedence, gateway_type, algorithm,
@@ -90,16 +67,8 @@ class IPSECKEY(dns.rdata.Rdata):
         header = struct.pack("!BBB", self.precedence, self.gateway_type,
                              self.algorithm)
         file.write(header)
-        if self.gateway_type == 0:
-            pass
-        elif self.gateway_type == 1:
-            file.write(dns.ipv4.inet_aton(self.gateway))
-        elif self.gateway_type == 2:
-            file.write(dns.ipv6.inet_aton(self.gateway))
-        elif self.gateway_type == 3:
-            self.gateway.to_wire(file, None, origin, False)
-        else:
-            raise ValueError('invalid gateway type')
+        Gateway(self.gateway_type, self.gateway).to_wire(file, compress,
+                                                         origin, canonicalize)
         file.write(self.key)
 
     @classmethod
@@ -110,23 +79,10 @@ class IPSECKEY(dns.rdata.Rdata):
         gateway_type = header[1]
         current += 3
         rdlen -= 3
-        if gateway_type == 0:
-            gateway = None
-        elif gateway_type == 1:
-            gateway = dns.ipv4.inet_ntoa(wire[current: current + 4])
-            current += 4
-            rdlen -= 4
-        elif gateway_type == 2:
-            gateway = dns.ipv6.inet_ntoa(wire[current: current + 16])
-            current += 16
-            rdlen -= 16
-        elif gateway_type == 3:
-            (gateway, cused) = dns.name.from_wire(wire[: current + rdlen],
-                                                  current)
-            current += cused
-            rdlen -= cused
-        else:
-            raise dns.exception.FormError('invalid IPSECKEY gateway type')
+        (gateway, cused) = Gateway(gateway_type).from_wire(wire, current,
+                                                           rdlen, origin)
+        current += cused
+        rdlen -= cused
         key = wire[current: current + rdlen].unwrap()
         if origin is not None and gateway_type == 3:
             gateway = gateway.relativize(origin)
index 1ac137f1fe7f1340e28e8e8adfa06a407956066e..ccc848cf2b166a6496f1fcd5571573d5791e4ad0 100644 (file)
@@ -24,4 +24,5 @@ __all__ = [
     'euibase',
     'mxbase',
     'nsbase',
+    'util'
 ]
diff --git a/dns/rdtypes/util.py b/dns/rdtypes/util.py
new file mode 100644 (file)
index 0000000..5d1f6c9
--- /dev/null
@@ -0,0 +1,91 @@
+# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
+
+# Copyright (C) 2006, 2007, 2009-2011 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.
+
+import dns.exception
+import dns.name
+import dns.ipv4
+import dns.ipv6
+
+class Gateway:
+    """A helper class for the IPSECKEY gateway and AMTRELAY relay fields"""
+    name = ""
+
+    def __init__(self, type, gateway=None):
+        self.type = type
+        self.gateway = gateway
+
+    def _invalid_type(self):
+        return f"invalid {self.name} type: {self.type}"
+
+    def check(self):
+        if self.type == 0:
+            if self.gateway not in (".", None):
+                raise SyntaxError(f"invalid {self.name} for type 0")
+            self.gateway = None
+        elif self.type == 1:
+            # check that it's OK
+            dns.ipv4.inet_aton(self.gateway)
+        elif self.type == 2:
+            # check that it's OK
+            dns.ipv6.inet_aton(self.gateway)
+        elif self.type == 3:
+            if not isinstance(self.gateway, dns.name.Name):
+                raise SyntaxError(f"invalid {self.name}; not a name")
+        else:
+            raise SyntaxError(self._invalid_type())
+
+    def to_text(self, origin=None, relativize=True):
+        if self.type == 0:
+            return "."
+        elif self.type in (1, 2):
+            return self.gateway
+        elif self.type == 3:
+            return str(self.gateway.choose_relativity(origin, relativize))
+        else:
+            raise ValueError(self._invalid_type())
+
+    def from_text(self, tok, origin=None, relativize=True, relativize_to=None):
+        if self.type in (0, 1, 2):
+            return tok.get_string()
+        elif self.type == 3:
+            return tok.get_name(origin, relativize, relativize_to)
+        else:
+            raise dns.exception.SyntaxError(self._invalid_type())
+
+    def to_wire(self, file, compress=None, origin=None, canonicalize=False):
+        if self.type == 0:
+            pass
+        elif self.type == 1:
+            file.write(dns.ipv4.inet_aton(self.gateway))
+        elif self.type == 2:
+            file.write(dns.ipv6.inet_aton(self.gateway))
+        elif self.type == 3:
+            self.gateway.to_wire(file, None, origin, False)
+        else:
+            raise ValueError(self._invalid_type())
+
+    def from_wire(self, wire, current, rdlen, origin=None):
+        if self.type == 0:
+            return (None, 0)
+        elif self.type == 1:
+            return (dns.ipv4.inet_ntoa(wire[current: current + 4]), 4)
+        elif self.type == 2:
+            return (dns.ipv6.inet_ntoa(wire[current: current + 16]), 16)
+        elif self.type == 3:
+            return dns.name.from_wire(wire[: current + rdlen], current)
+        else:
+            raise dns.exception.FormError(self._invalid_type())
index c35ba47009fa8eeaa95a04ff4ee381c0aefeaed6..2cf587876a4e490e4f8682e174593ed7b6618adc 100644 (file)
@@ -225,5 +225,10 @@ LV5eYdPYqfKE+27qjEBARf6PYh/8WQ8CPKS8DILFbwCZbRxUogyrZf/7AiHAGdJi
 8dmpR1WPQYef2hF3kqGX6NngLBPzZ6CQRaHBhD4pHU1S/IRSlx9/3Ytww32PYD9A
 yO732NmCUcq3bmvqcOWy4Cc1NkEwU0Vg0qzwVBNGb84v/ex2MouwtAYScwc=
 )
+amtrelay01              AMTRELAY 0 0 0 .
+amtrelay02              AMTRELAY 0 1 0 .
+amtrelay03              AMTRELAY  10 0 1 203.0.113.15
+amtrelay04              AMTRELAY  10 0 2 2001:db8::15
+amtrelay05              AMTRELAY 128 1 3 amtrelays.example.com.
 csync0                 CSYNC 12345 0 A MX RRSIG NSEC TYPE1234
 avc01                  AVC "app-name:WOLFGANG|app-class:OAM|business=yes"
index a52e55c1e41c0e7846f05b81147ef3c1160da984..beb57af242016f269be8544adb2e090fc7e9fae4 100644 (file)
@@ -12,6 +12,11 @@ aaaa01 3600 IN AAAA ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
 aaaa02 3600 IN AAAA ::1
 afsdb01 3600 IN AFSDB 0 hostname
 afsdb02 3600 IN AFSDB 65535 .
+amtrelay01 3600 IN AMTRELAY 0 0 0 .
+amtrelay02 3600 IN AMTRELAY 0 1 0 .
+amtrelay03 3600 IN AMTRELAY 10 0 1 203.0.113.15
+amtrelay04 3600 IN AMTRELAY 10 0 2 2001:db8::15
+amtrelay05 3600 IN AMTRELAY 128 1 3 amtrelays.example.com.
 apl01 3600 IN APL 1:192.168.32.0/21 !1:192.168.38.0/28
 apl02 3600 IN APL 1:224.0.0.0/4 2:FF00:0:0:0:0:0:0:0/8
 avc01 3600 IN AVC "app-name:WOLFGANG|app-class:OAM|business=yes"
index df0fed627096ae0d1348fc0192fb3a49482d0a38..75c787c4fae11091dce0c5014657943c2410791a 100644 (file)
@@ -12,6 +12,11 @@ aaaa01.example. 3600 IN AAAA ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
 aaaa02.example. 3600 IN AAAA ::1
 afsdb01.example. 3600 IN AFSDB 0 hostname.example.
 afsdb02.example. 3600 IN AFSDB 65535 .
+amtrelay01.example. 3600 IN AMTRELAY 0 0 0 .
+amtrelay02.example. 3600 IN AMTRELAY 0 1 0 .
+amtrelay03.example. 3600 IN AMTRELAY 10 0 1 203.0.113.15
+amtrelay04.example. 3600 IN AMTRELAY 10 0 2 2001:db8::15
+amtrelay05.example. 3600 IN AMTRELAY 128 1 3 amtrelays.example.com.
 apl01.example. 3600 IN APL 1:192.168.32.0/21 !1:192.168.38.0/28
 apl02.example. 3600 IN APL 1:224.0.0.0/4 2:FF00:0:0:0:0:0:0:0/8
 avc01.example. 3600 IN AVC "app-name:WOLFGANG|app-class:OAM|business=yes"
index a52e55c1e41c0e7846f05b81147ef3c1160da984..beb57af242016f269be8544adb2e090fc7e9fae4 100644 (file)
@@ -12,6 +12,11 @@ aaaa01 3600 IN AAAA ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
 aaaa02 3600 IN AAAA ::1
 afsdb01 3600 IN AFSDB 0 hostname
 afsdb02 3600 IN AFSDB 65535 .
+amtrelay01 3600 IN AMTRELAY 0 0 0 .
+amtrelay02 3600 IN AMTRELAY 0 1 0 .
+amtrelay03 3600 IN AMTRELAY 10 0 1 203.0.113.15
+amtrelay04 3600 IN AMTRELAY 10 0 2 2001:db8::15
+amtrelay05 3600 IN AMTRELAY 128 1 3 amtrelays.example.com.
 apl01 3600 IN APL 1:192.168.32.0/21 !1:192.168.38.0/28
 apl02 3600 IN APL 1:224.0.0.0/4 2:FF00:0:0:0:0:0:0:0/8
 avc01 3600 IN AVC "app-name:WOLFGANG|app-class:OAM|business=yes"