Skip to content

Commit

Permalink
Add support for RFC 6742 types.
Browse files Browse the repository at this point in the history
This adds the NID, L32, L64, and LP types.
  • Loading branch information
bwelling committed Jul 13, 2021
1 parent 2ad1d9e commit 4174b2e
Show file tree
Hide file tree
Showing 13 changed files with 278 additions and 11 deletions.
20 changes: 10 additions & 10 deletions dns/rdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,34 +39,34 @@
_chunksize = 32


def _wordbreak(data, chunksize=_chunksize):
def _wordbreak(data, chunksize=_chunksize, separator=b' '):
"""Break a binary string into chunks of chunksize characters separated by
a space.
"""

if not chunksize:
return data.decode()
return b' '.join([data[i:i + chunksize]
for i
in range(0, len(data), chunksize)]).decode()
return separator.join([data[i:i + chunksize]
for i
in range(0, len(data), chunksize)]).decode()


# pylint: disable=unused-argument

def _hexify(data, chunksize=_chunksize, **kw):
def _hexify(data, chunksize=_chunksize, separator=b' ', **kw):
"""Convert a binary string into its hex encoding, broken up into chunks
of chunksize characters separated by a space.
of chunksize characters separated by a separator.
"""

return _wordbreak(binascii.hexlify(data), chunksize)
return _wordbreak(binascii.hexlify(data), chunksize, separator)


def _base64ify(data, chunksize=_chunksize, **kw):
def _base64ify(data, chunksize=_chunksize, separator=b' ', **kw):
"""Convert a binary string into its base64 encoding, broken up into chunks
of chunksize characters separated by a space.
of chunksize characters separated by a separator.
"""

return _wordbreak(base64.b64encode(data), chunksize)
return _wordbreak(base64.b64encode(data), chunksize, separator)

# pylint: enable=unused-argument

Expand Down
8 changes: 8 additions & 0 deletions dns/rdatatype.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ class RdataType(dns.enum.IntEnum):
HTTPS = 65
SPF = 99
UNSPEC = 103
NID = 104
L32 = 105
L64 = 106
LP = 107
EUI48 = 108
EUI64 = 109
TKEY = 249
Expand Down Expand Up @@ -286,6 +290,10 @@ def register_type(rdtype, rdtype_text, is_singleton=False):
HTTPS = RdataType.HTTPS
SPF = RdataType.SPF
UNSPEC = RdataType.UNSPEC
NID = RdataType.NID
L32 = RdataType.L32
L64 = RdataType.L64
LP = RdataType.LP
EUI48 = RdataType.EUI48
EUI64 = RdataType.EUI64
TKEY = RdataType.TKEY
Expand Down
40 changes: 40 additions & 0 deletions dns/rdtypes/ANY/L32.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license

import struct

import dns.immutable


@dns.immutable.immutable
class L32(dns.rdata.Rdata):

"""L32 record"""

# see: rfc6742.txt

__slots__ = ['preference', 'locator32']

def __init__(self, rdclass, rdtype, preference, locator32):
super().__init__(rdclass, rdtype)
self.preference = self._as_uint16(preference)
self.locator32 = self._as_ipv4_address(locator32)

def to_text(self, origin=None, relativize=True, **kw):
return f'{self.preference} {self.locator32}'

@classmethod
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
relativize_to=None):
preference = tok.get_uint16()
nodeid = tok.get_identifier()
return cls(rdclass, rdtype, preference, nodeid)

def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
file.write(struct.pack('!H', self.preference))
file.write(dns.ipv4.inet_aton(self.locator32))

@classmethod
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
preference = parser.get_uint16()
locator32 = parser.get_remaining()
return cls(rdclass, rdtype, preference, locator32)
48 changes: 48 additions & 0 deletions dns/rdtypes/ANY/L64.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license

import struct

import dns.immutable
import dns.rdtypes.util


@dns.immutable.immutable
class L64(dns.rdata.Rdata):

"""L64 record"""

# see: rfc6742.txt

__slots__ = ['preference', 'locator64']

def __init__(self, rdclass, rdtype, preference, locator64):
super().__init__(rdclass, rdtype)
self.preference = self._as_uint16(preference)
if isinstance(locator64, bytes):
if len(locator64) != 8:
raise ValueError('invalid locator64')
self.locator64 = dns.rdata._hexify(locator64, 4, b':')
else:
dns.rdtypes.util.parse_formatted_hex(locator64, 4, 4, ':')
self.locator64 = locator64

def to_text(self, origin=None, relativize=True, **kw):
return f'{self.preference} {self.locator64}'

@classmethod
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
relativize_to=None):
preference = tok.get_uint16()
locator64 = tok.get_identifier()
return cls(rdclass, rdtype, preference, locator64)

def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
file.write(struct.pack('!H', self.preference))
file.write(dns.rdtypes.util.parse_formatted_hex(self.locator64,
4, 4, ':'))

@classmethod
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
preference = parser.get_uint16()
locator64 = parser.get_remaining()
return cls(rdclass, rdtype, preference, locator64)
41 changes: 41 additions & 0 deletions dns/rdtypes/ANY/LP.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license

import struct

import dns.immutable


@dns.immutable.immutable
class LP(dns.rdata.Rdata):

"""LP record"""

# see: rfc6742.txt

__slots__ = ['preference', 'fqdn']

def __init__(self, rdclass, rdtype, preference, fqdn):
super().__init__(rdclass, rdtype)
self.preference = self._as_uint16(preference)
self.fqdn = self._as_name(fqdn)

def to_text(self, origin=None, relativize=True, **kw):
fqdn = self.fqdn.choose_relativity(origin, relativize)
return '%d %s' % (self.preference, fqdn)

@classmethod
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
relativize_to=None):
preference = tok.get_uint16()
fqdn = tok.get_name(origin, relativize, relativize_to)
return cls(rdclass, rdtype, preference, fqdn)

def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
file.write(struct.pack('!H', self.preference))
self.fqdn.to_wire(file, compress, origin, canonicalize)

@classmethod
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
preference = parser.get_uint16()
fqdn = parser.get_name(origin)
return cls(rdclass, rdtype, preference, fqdn)
47 changes: 47 additions & 0 deletions dns/rdtypes/ANY/NID.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license

import struct

import dns.immutable
import dns.rdtypes.util


@dns.immutable.immutable
class NID(dns.rdata.Rdata):

"""NID record"""

# see: rfc6742.txt

__slots__ = ['preference', 'nodeid']

def __init__(self, rdclass, rdtype, preference, nodeid):
super().__init__(rdclass, rdtype)
self.preference = self._as_uint16(preference)
if isinstance(nodeid, bytes):
if len(nodeid) != 8:
raise ValueError('invalid nodeid')
self.nodeid = dns.rdata._hexify(nodeid, 4, b':')
else:
dns.rdtypes.util.parse_formatted_hex(nodeid, 4, 4, ':')
self.nodeid = nodeid

def to_text(self, origin=None, relativize=True, **kw):
return f'{self.preference} {self.nodeid}'

@classmethod
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
relativize_to=None):
preference = tok.get_uint16()
nodeid = tok.get_identifier()
return cls(rdclass, rdtype, preference, nodeid)

def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
file.write(struct.pack('!H', self.preference))
file.write(dns.rdtypes.util.parse_formatted_hex(self.nodeid, 4, 4, ':'))

@classmethod
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
preference = parser.get_uint16()
nodeid = parser.get_remaining()
return cls(rdclass, rdtype, preference, nodeid)
2 changes: 1 addition & 1 deletion dns/rdtypes/euibase.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def __init__(self, rdclass, rdtype, eui):
% (self.byte_len * 8, self.byte_len))

def to_text(self, origin=None, relativize=True, **kw):
return dns.rdata._hexify(self.eui, chunksize=2, **kw).replace(' ', '-')
return dns.rdata._hexify(self.eui, chunksize=2, separator=b'-', **kw)

@classmethod
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
Expand Down
13 changes: 13 additions & 0 deletions dns/rdtypes/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,16 @@ def weighted_processing_order(iterable):
del rdatas[n] # pylint: disable=undefined-loop-variable
ordered.append(rdatas[0])
return ordered

def parse_formatted_hex(formatted, num_chunks, chunk_size, separator):
if len(formatted) != num_chunks * (chunk_size + 1) - 1:
raise ValueError('invalid formatted hex string')
value = b''
for n in range(num_chunks):
chunk = formatted[0:chunk_size]
value += int(chunk, 16).to_bytes(chunk_size // 2, 'big')
formatted = formatted[chunk_size:]
if len(formatted) > 0 and formatted[0] != separator:
raise ValueError('invalid formatted hex string')
formatted = formatted[1:]
return value
14 changes: 14 additions & 0 deletions tests/example
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,20 @@ hip02 HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH
hip03 HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs1.example.com. rvs2.example.com.
cds01 CDS 12345 3 1 123456789abcdef67890123456789abcdef67890
cdnskey01 CDNSKEY 256 3 8 ( AwEAAbmiLgh411Pz3v3XCSBrvYf52A/Gv55ItN1NbOLH Cqt3Ec3p+VB/kQ87VjjMrycanZFnZT4l9uCFuYh21Ccy xVpcxExbM0UuhX5rJoDyeFSXoQlkHrB01osPl5Vri5Ym KtcmqGxZ9An0VSunohkyiX1SrNRZSdQnk9/pIHDe/c8D )
nid01 NID 10 0014:4fff:ff20:ee64
nid02 NID 20 0015:5fff:ff21:ee65
nid03 NID 10 0016:6fff:ff22:ee66
l3201 L32 10 10.1.2.0
l3202 L32 20 10.1.4.0
l3203 L32 10 10.1.8.0
l6401 L64 10 2001:0DB8:1140:1000
l6402 L64 20 2001:0DB8:2140:2000
l6403 L64 10 2001:0DB8:4140:4000
lp01 LP 10 l64-subnet1.example.com.
lp02 LP 10 l64-subnet2.example.com.
lp03 LP 20 l32-subnet1.example.com.
eui48 EUI48 00-00-5e-00-53-2a
eui64 EUI64 00-00-5e-ef-10-00-00-2a
uri01 URI 10 1 "ftp://ftp1.example.com/public"
uri02 URI 10 1 "http://www.example.com/path"
caa01 CAA 0 issue "ca.example.net"
Expand Down
14 changes: 14 additions & 0 deletions tests/example1.good
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ e 300 IN A 73.80.65.49
e 300 IN A 73.80.65.50
e 300 IN A 73.80.65.52
e 300 IN A 73.80.65.51
eui48 3600 IN EUI48 00-00-5e-00-53-2a
eui64 3600 IN EUI64 00-00-5e-ef-10-00-00-2a
f 300 IN A 73.80.65.52
gpos01 3600 IN GPOS -22.6882 116.8652 250.0
hinfo01 3600 IN HINFO "Generic PC clone" "NetBSD-1.4"
Expand All @@ -74,6 +76,12 @@ isdn03 3600 IN ISDN "isdn-address"
isdn04 3600 IN ISDN "isdn-address" "subaddress"
kx01 3600 IN KX 10 kdc
kx02 3600 IN KX 10 .
l3201 3600 IN L32 10 10.1.2.0
l3202 3600 IN L32 20 10.1.4.0
l3203 3600 IN L32 10 10.1.8.0
l6401 3600 IN L64 10 2001:0DB8:1140:1000
l6402 3600 IN L64 20 2001:0DB8:2140:2000
l6403 3600 IN L64 10 2001:0DB8:4140:4000
loc01 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m
loc02 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m
loc03 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m
Expand All @@ -82,10 +90,16 @@ loc05 3600 IN LOC 60 9 1.510 N 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m
loc06 3600 IN LOC 60 9 1.000 N 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m
loc07 3600 IN LOC 0 9 1.000 N 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m
loc08 3600 IN LOC 0 9 1.000 S 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m
lp01 3600 IN LP 10 l64-subnet1.example.com.
lp02 3600 IN LP 10 l64-subnet2.example.com.
lp03 3600 IN LP 20 l32-subnet1.example.com.
mx01 3600 IN MX 10 mail
mx02 3600 IN MX 10 .
naptr01 3600 IN NAPTR 0 0 "" "" "" .
naptr02 3600 IN NAPTR 65535 65535 "blurgh" "blorf" "blegh" foo.
nid01 3600 IN NID 10 0014:4fff:ff20:ee64
nid02 3600 IN NID 20 0015:5fff:ff21:ee65
nid03 3600 IN NID 10 0016:6fff:ff22:ee66
ns1 300 IN A 10.53.0.1
ns2 300 IN A 10.53.0.2
nsap-ptr01 3600 IN NSAP-PTR foo.
Expand Down
14 changes: 14 additions & 0 deletions tests/example2.good
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ e.example. 300 IN A 73.80.65.49
e.example. 300 IN A 73.80.65.50
e.example. 300 IN A 73.80.65.52
e.example. 300 IN A 73.80.65.51
eui48.example. 3600 IN EUI48 00-00-5e-00-53-2a
eui64.example. 3600 IN EUI64 00-00-5e-ef-10-00-00-2a
f.example. 300 IN A 73.80.65.52
gpos01.example. 3600 IN GPOS -22.6882 116.8652 250.0
hinfo01.example. 3600 IN HINFO "Generic PC clone" "NetBSD-1.4"
Expand All @@ -74,6 +76,12 @@ isdn03.example. 3600 IN ISDN "isdn-address"
isdn04.example. 3600 IN ISDN "isdn-address" "subaddress"
kx01.example. 3600 IN KX 10 kdc.example.
kx02.example. 3600 IN KX 10 .
l3201.example. 3600 IN L32 10 10.1.2.0
l3202.example. 3600 IN L32 20 10.1.4.0
l3203.example. 3600 IN L32 10 10.1.8.0
l6401.example. 3600 IN L64 10 2001:0DB8:1140:1000
l6402.example. 3600 IN L64 20 2001:0DB8:2140:2000
l6403.example. 3600 IN L64 10 2001:0DB8:4140:4000
loc01.example. 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m
loc02.example. 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m
loc03.example. 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m
Expand All @@ -82,10 +90,16 @@ loc05.example. 3600 IN LOC 60 9 1.510 N 24 39 0.000 E 10.00m 90000000.00m 2000.0
loc06.example. 3600 IN LOC 60 9 1.000 N 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m
loc07.example. 3600 IN LOC 0 9 1.000 N 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m
loc08.example. 3600 IN LOC 0 9 1.000 S 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m
lp01.example. 3600 IN LP 10 l64-subnet1.example.com.
lp02.example. 3600 IN LP 10 l64-subnet2.example.com.
lp03.example. 3600 IN LP 20 l32-subnet1.example.com.
mx01.example. 3600 IN MX 10 mail.example.
mx02.example. 3600 IN MX 10 .
naptr01.example. 3600 IN NAPTR 0 0 "" "" "" .
naptr02.example. 3600 IN NAPTR 65535 65535 "blurgh" "blorf" "blegh" foo.
nid01.example. 3600 IN NID 10 0014:4fff:ff20:ee64
nid02.example. 3600 IN NID 20 0015:5fff:ff21:ee65
nid03.example. 3600 IN NID 10 0016:6fff:ff22:ee66
ns1.example. 300 IN A 10.53.0.1
ns2.example. 300 IN A 10.53.0.2
nsap-ptr01.example. 3600 IN NSAP-PTR foo.
Expand Down
Loading

0 comments on commit 4174b2e

Please sign in to comment.