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 16import struct 17 18import dns.exception 19import dns.rdata 20import dns.name 21 22class SOA(dns.rdata.Rdata): 23 """SOA record 24 25 @ivar mname: the SOA MNAME (master name) field 26 @type mname: dns.name.Name object 27 @ivar rname: the SOA RNAME (responsible name) field 28 @type rname: dns.name.Name object 29 @ivar serial: The zone's serial number 30 @type serial: int 31 @ivar refresh: The zone's refresh value (in seconds) 32 @type refresh: int 33 @ivar retry: The zone's retry value (in seconds) 34 @type retry: int 35 @ivar expire: The zone's expiration value (in seconds) 36 @type expire: int 37 @ivar minimum: The zone's negative caching time (in seconds, called 38 "minimum" for historical reasons) 39 @type minimum: int 40 @see: RFC 1035""" 41 42 __slots__ = ['mname', 'rname', 'serial', 'refresh', 'retry', 'expire', 43 'minimum'] 44 45 def __init__(self, rdclass, rdtype, mname, rname, serial, refresh, retry, 46 expire, minimum): 47 super(SOA, self).__init__(rdclass, rdtype) 48 self.mname = mname 49 self.rname = rname 50 self.serial = serial 51 self.refresh = refresh 52 self.retry = retry 53 self.expire = expire 54 self.minimum = minimum 55 56 def to_text(self, origin=None, relativize=True, **kw): 57 mname = self.mname.choose_relativity(origin, relativize) 58 rname = self.rname.choose_relativity(origin, relativize) 59 return '%s %s %d %d %d %d %d' % ( 60 mname, rname, self.serial, self.refresh, self.retry, 61 self.expire, self.minimum ) 62 63 def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): 64 mname = tok.get_name() 65 rname = tok.get_name() 66 mname = mname.choose_relativity(origin, relativize) 67 rname = rname.choose_relativity(origin, relativize) 68 serial = tok.get_uint32() 69 refresh = tok.get_ttl() 70 retry = tok.get_ttl() 71 expire = tok.get_ttl() 72 minimum = tok.get_ttl() 73 tok.get_eol() 74 return cls(rdclass, rdtype, mname, rname, serial, refresh, retry, 75 expire, minimum ) 76 77 from_text = classmethod(from_text) 78 79 def to_wire(self, file, compress = None, origin = None): 80 self.mname.to_wire(file, compress, origin) 81 self.rname.to_wire(file, compress, origin) 82 five_ints = struct.pack('!IIIII', self.serial, self.refresh, 83 self.retry, self.expire, self.minimum) 84 file.write(five_ints) 85 86 def to_digestable(self, origin = None): 87 return self.mname.to_digestable(origin) + \ 88 self.rname.to_digestable(origin) + \ 89 struct.pack('!IIIII', self.serial, self.refresh, 90 self.retry, self.expire, self.minimum) 91 92 def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): 93 (mname, cused) = dns.name.from_wire(wire[: current + rdlen], current) 94 current += cused 95 rdlen -= cused 96 (rname, cused) = dns.name.from_wire(wire[: current + rdlen], current) 97 current += cused 98 rdlen -= cused 99 if rdlen != 20: 100 raise dns.exception.FormError 101 five_ints = struct.unpack('!IIIII', 102 wire[current : current + rdlen]) 103 if not origin is None: 104 mname = mname.relativize(origin) 105 rname = rname.relativize(origin) 106 return cls(rdclass, rdtype, mname, rname, 107 five_ints[0], five_ints[1], five_ints[2], five_ints[3], 108 five_ints[4]) 109 110 from_wire = classmethod(from_wire) 111 112 def choose_relativity(self, origin = None, relativize = True): 113 self.mname = self.mname.choose_relativity(origin, relativize) 114 self.rname = self.rname.choose_relativity(origin, relativize) 115 116 def _cmp(self, other): 117 v = cmp(self.mname, other.mname) 118 if v == 0: 119 v = cmp(self.rname, other.rname) 120 if v == 0: 121 self_ints = struct.pack('!IIIII', self.serial, self.refresh, 122 self.retry, self.expire, self.minimum) 123 other_ints = struct.pack('!IIIII', other.serial, other.refresh, 124 other.retry, other.expire, 125 other.minimum) 126 v = cmp(self_ints, other_ints) 127 return v 128