|
|
@ -272,7 +272,7 @@ class _ValuesMixin(object): |
|
|
values = data['values'] |
|
|
values = data['values'] |
|
|
except KeyError: |
|
|
except KeyError: |
|
|
values = [data['value']] |
|
|
values = [data['value']] |
|
|
self.values = sorted(self._process_values(values)) |
|
|
|
|
|
|
|
|
self.values = sorted(self._value_type.process(values)) |
|
|
|
|
|
|
|
|
def changes(self, other, target): |
|
|
def changes(self, other, target): |
|
|
if self.values != other.values: |
|
|
if self.values != other.values: |
|
|
@ -371,7 +371,7 @@ class _ValueMixin(object): |
|
|
|
|
|
|
|
|
def __init__(self, zone, name, data, source=None): |
|
|
def __init__(self, zone, name, data, source=None): |
|
|
super(_ValueMixin, self).__init__(zone, name, data, source=source) |
|
|
super(_ValueMixin, self).__init__(zone, name, data, source=source) |
|
|
self.value = self._process_value(data['value']) |
|
|
|
|
|
|
|
|
self.value = self._value_type.process(data['value']) |
|
|
|
|
|
|
|
|
def changes(self, other, target): |
|
|
def changes(self, other, target): |
|
|
if self.value != other.value: |
|
|
if self.value != other.value: |
|
|
@ -434,6 +434,10 @@ class Ipv4List(object): |
|
|
reasons.append('invalid IPv4 address "{}"'.format(value)) |
|
|
reasons.append('invalid IPv4 address "{}"'.format(value)) |
|
|
return reasons |
|
|
return reasons |
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
|
|
def process(cls, values): |
|
|
|
|
|
return values |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Ipv6List(object): |
|
|
class Ipv6List(object): |
|
|
|
|
|
|
|
|
@ -456,6 +460,10 @@ class Ipv6List(object): |
|
|
reasons.append('invalid IPv6 address "{}"'.format(value)) |
|
|
reasons.append('invalid IPv6 address "{}"'.format(value)) |
|
|
return reasons |
|
|
return reasons |
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
|
|
def process(cls, values): |
|
|
|
|
|
return values |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _TargetValue(object): |
|
|
class _TargetValue(object): |
|
|
|
|
|
|
|
|
@ -471,6 +479,10 @@ class _TargetValue(object): |
|
|
.format(record_cls._type, data)) |
|
|
.format(record_cls._type, data)) |
|
|
return reasons |
|
|
return reasons |
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
|
|
def process(self, value): |
|
|
|
|
|
return value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CnameValue(_TargetValue): |
|
|
class CnameValue(_TargetValue): |
|
|
pass |
|
|
pass |
|
|
@ -480,17 +492,11 @@ class ARecord(_DynamicMixin, _GeoMixin, Record): |
|
|
_type = 'A' |
|
|
_type = 'A' |
|
|
_value_type = Ipv4List |
|
|
_value_type = Ipv4List |
|
|
|
|
|
|
|
|
def _process_values(self, values): |
|
|
|
|
|
return values |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AaaaRecord(_GeoMixin, Record): |
|
|
class AaaaRecord(_GeoMixin, Record): |
|
|
_type = 'AAAA' |
|
|
_type = 'AAAA' |
|
|
_value_type = Ipv6List |
|
|
_value_type = Ipv6List |
|
|
|
|
|
|
|
|
def _process_values(self, values): |
|
|
|
|
|
return values |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AliasValue(_TargetValue): |
|
|
class AliasValue(_TargetValue): |
|
|
pass |
|
|
pass |
|
|
@ -500,9 +506,6 @@ class AliasRecord(_ValueMixin, Record): |
|
|
_type = 'ALIAS' |
|
|
_type = 'ALIAS' |
|
|
_value_type = AliasValue |
|
|
_value_type = AliasValue |
|
|
|
|
|
|
|
|
def _process_value(self, value): |
|
|
|
|
|
return value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CaaValue(object): |
|
|
class CaaValue(object): |
|
|
# https://tools.ietf.org/html/rfc6844#page-5 |
|
|
# https://tools.ietf.org/html/rfc6844#page-5 |
|
|
@ -526,6 +529,10 @@ class CaaValue(object): |
|
|
reasons.append('missing value') |
|
|
reasons.append('missing value') |
|
|
return reasons |
|
|
return reasons |
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
|
|
def process(cls, values): |
|
|
|
|
|
return [CaaValue(v) for v in values] |
|
|
|
|
|
|
|
|
def __init__(self, value): |
|
|
def __init__(self, value): |
|
|
self.flags = int(value.get('flags', 0)) |
|
|
self.flags = int(value.get('flags', 0)) |
|
|
self.tag = value['tag'] |
|
|
self.tag = value['tag'] |
|
|
@ -554,9 +561,6 @@ class CaaRecord(_ValuesMixin, Record): |
|
|
_type = 'CAA' |
|
|
_type = 'CAA' |
|
|
_value_type = CaaValue |
|
|
_value_type = CaaValue |
|
|
|
|
|
|
|
|
def _process_values(self, values): |
|
|
|
|
|
return [CaaValue(v) for v in values] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CnameRecord(_ValueMixin, Record): |
|
|
class CnameRecord(_ValueMixin, Record): |
|
|
_type = 'CNAME' |
|
|
_type = 'CNAME' |
|
|
@ -570,9 +574,6 @@ class CnameRecord(_ValueMixin, Record): |
|
|
reasons.extend(super(CnameRecord, cls).validate(name, data)) |
|
|
reasons.extend(super(CnameRecord, cls).validate(name, data)) |
|
|
return reasons |
|
|
return reasons |
|
|
|
|
|
|
|
|
def _process_value(self, value): |
|
|
|
|
|
return value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MxValue(object): |
|
|
class MxValue(object): |
|
|
|
|
|
|
|
|
@ -602,6 +603,10 @@ class MxValue(object): |
|
|
reasons.append('missing exchange') |
|
|
reasons.append('missing exchange') |
|
|
return reasons |
|
|
return reasons |
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
|
|
def process(cls, values): |
|
|
|
|
|
return [MxValue(v) for v in values] |
|
|
|
|
|
|
|
|
def __init__(self, value): |
|
|
def __init__(self, value): |
|
|
# RFC1035 says preference, half the providers use priority |
|
|
# RFC1035 says preference, half the providers use priority |
|
|
try: |
|
|
try: |
|
|
@ -636,9 +641,6 @@ class MxRecord(_ValuesMixin, Record): |
|
|
_type = 'MX' |
|
|
_type = 'MX' |
|
|
_value_type = MxValue |
|
|
_value_type = MxValue |
|
|
|
|
|
|
|
|
def _process_values(self, values): |
|
|
|
|
|
return [MxValue(v) for v in values] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NaptrValue(object): |
|
|
class NaptrValue(object): |
|
|
VALID_FLAGS = ('S', 'A', 'U', 'P') |
|
|
VALID_FLAGS = ('S', 'A', 'U', 'P') |
|
|
@ -676,6 +678,10 @@ class NaptrValue(object): |
|
|
|
|
|
|
|
|
return reasons |
|
|
return reasons |
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
|
|
def process(cls, values): |
|
|
|
|
|
return [NaptrValue(v) for v in values] |
|
|
|
|
|
|
|
|
def __init__(self, value): |
|
|
def __init__(self, value): |
|
|
self.order = int(value['order']) |
|
|
self.order = int(value['order']) |
|
|
self.preference = int(value['preference']) |
|
|
self.preference = int(value['preference']) |
|
|
@ -721,9 +727,6 @@ class NaptrRecord(_ValuesMixin, Record): |
|
|
_type = 'NAPTR' |
|
|
_type = 'NAPTR' |
|
|
_value_type = NaptrValue |
|
|
_value_type = NaptrValue |
|
|
|
|
|
|
|
|
def _process_values(self, values): |
|
|
|
|
|
return [NaptrValue(v) for v in values] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _NsValue(object): |
|
|
class _NsValue(object): |
|
|
|
|
|
|
|
|
@ -740,14 +743,15 @@ class _NsValue(object): |
|
|
.format(value)) |
|
|
.format(value)) |
|
|
return reasons |
|
|
return reasons |
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
|
|
def process(cls, values): |
|
|
|
|
|
return values |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NsRecord(_ValuesMixin, Record): |
|
|
class NsRecord(_ValuesMixin, Record): |
|
|
_type = 'NS' |
|
|
_type = 'NS' |
|
|
_value_type = _NsValue |
|
|
_value_type = _NsValue |
|
|
|
|
|
|
|
|
def _process_values(self, values): |
|
|
|
|
|
return values |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PtrValue(_TargetValue): |
|
|
class PtrValue(_TargetValue): |
|
|
pass |
|
|
pass |
|
|
@ -757,9 +761,6 @@ class PtrRecord(_ValueMixin, Record): |
|
|
_type = 'PTR' |
|
|
_type = 'PTR' |
|
|
_value_type = PtrValue |
|
|
_value_type = PtrValue |
|
|
|
|
|
|
|
|
def _process_value(self, value): |
|
|
|
|
|
return value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SshfpValue(object): |
|
|
class SshfpValue(object): |
|
|
VALID_ALGORITHMS = (1, 2, 3, 4) |
|
|
VALID_ALGORITHMS = (1, 2, 3, 4) |
|
|
@ -795,6 +796,10 @@ class SshfpValue(object): |
|
|
reasons.append('missing fingerprint') |
|
|
reasons.append('missing fingerprint') |
|
|
return reasons |
|
|
return reasons |
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
|
|
def process(cls, values): |
|
|
|
|
|
return [SshfpValue(v) for v in values] |
|
|
|
|
|
|
|
|
def __init__(self, value): |
|
|
def __init__(self, value): |
|
|
self.algorithm = int(value['algorithm']) |
|
|
self.algorithm = int(value['algorithm']) |
|
|
self.fingerprint_type = int(value['fingerprint_type']) |
|
|
self.fingerprint_type = int(value['fingerprint_type']) |
|
|
@ -824,22 +829,11 @@ class SshfpRecord(_ValuesMixin, Record): |
|
|
_type = 'SSHFP' |
|
|
_type = 'SSHFP' |
|
|
_value_type = SshfpValue |
|
|
_value_type = SshfpValue |
|
|
|
|
|
|
|
|
def _process_values(self, values): |
|
|
|
|
|
return [SshfpValue(v) for v in values] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _ChunkedValuesMixin(_ValuesMixin): |
|
|
class _ChunkedValuesMixin(_ValuesMixin): |
|
|
CHUNK_SIZE = 255 |
|
|
CHUNK_SIZE = 255 |
|
|
_unescaped_semicolon_re = re.compile(r'\w;') |
|
|
_unescaped_semicolon_re = re.compile(r'\w;') |
|
|
|
|
|
|
|
|
def _process_values(self, values): |
|
|
|
|
|
ret = [] |
|
|
|
|
|
for v in values: |
|
|
|
|
|
if v and v[0] == '"': |
|
|
|
|
|
v = v[1:-1] |
|
|
|
|
|
ret.append(v.replace('" "', '')) |
|
|
|
|
|
return ret |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
@property |
|
|
def chunked_values(self): |
|
|
def chunked_values(self): |
|
|
values = [] |
|
|
values = [] |
|
|
@ -867,6 +861,15 @@ class _ChunkedValue(object): |
|
|
reasons.append('unescaped ; in "{}"'.format(value)) |
|
|
reasons.append('unescaped ; in "{}"'.format(value)) |
|
|
return reasons |
|
|
return reasons |
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
|
|
def process(cls, values): |
|
|
|
|
|
ret = [] |
|
|
|
|
|
for v in values: |
|
|
|
|
|
if v and v[0] == '"': |
|
|
|
|
|
v = v[1:-1] |
|
|
|
|
|
ret.append(v.replace('" "', '')) |
|
|
|
|
|
return ret |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SpfRecord(_ChunkedValuesMixin, Record): |
|
|
class SpfRecord(_ChunkedValuesMixin, Record): |
|
|
_type = 'SPF' |
|
|
_type = 'SPF' |
|
|
@ -909,6 +912,10 @@ class SrvValue(object): |
|
|
reasons.append('missing target') |
|
|
reasons.append('missing target') |
|
|
return reasons |
|
|
return reasons |
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
|
|
def process(cls, values): |
|
|
|
|
|
return [SrvValue(v) for v in values] |
|
|
|
|
|
|
|
|
def __init__(self, value): |
|
|
def __init__(self, value): |
|
|
self.priority = int(value['priority']) |
|
|
self.priority = int(value['priority']) |
|
|
self.weight = int(value['weight']) |
|
|
self.weight = int(value['weight']) |
|
|
@ -951,9 +958,6 @@ class SrvRecord(_ValuesMixin, Record): |
|
|
reasons.extend(super(SrvRecord, cls).validate(name, data)) |
|
|
reasons.extend(super(SrvRecord, cls).validate(name, data)) |
|
|
return reasons |
|
|
return reasons |
|
|
|
|
|
|
|
|
def _process_values(self, values): |
|
|
|
|
|
return [SrvValue(v) for v in values] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _TxtValue(_ChunkedValue): |
|
|
class _TxtValue(_ChunkedValue): |
|
|
pass |
|
|
pass |
|
|
|