Package dns :: Module update
[hide private]
[frames] | no frames]

Source Code for Module dns.update

  1  # Copyright (C) 2003-2007, 2009-2011 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 Dynamic Update Support""" 
 17   
 18  import dns.message 
 19  import dns.name 
 20  import dns.opcode 
 21  import dns.rdata 
 22  import dns.rdataclass 
 23  import dns.rdataset 
 24  import dns.tsig 
 25   
26 -class Update(dns.message.Message):
27 - def __init__(self, zone, rdclass=dns.rdataclass.IN, keyring=None, 28 keyname=None, keyalgorithm=dns.tsig.default_algorithm):
29 """Initialize a new DNS Update object. 30 31 @param zone: The zone which is being updated. 32 @type zone: A dns.name.Name or string 33 @param rdclass: The class of the zone; defaults to dns.rdataclass.IN. 34 @type rdclass: An int designating the class, or a string whose value 35 is the name of a class. 36 @param keyring: The TSIG keyring to use; defaults to None. 37 @type keyring: dict 38 @param keyname: The name of the TSIG key to use; defaults to None. 39 The key must be defined in the keyring. If a keyring is specified 40 but a keyname is not, then the key used will be the first key in the 41 keyring. Note that the order of keys in a dictionary is not defined, 42 so applications should supply a keyname when a keyring is used, unless 43 they know the keyring contains only one key. 44 @type keyname: dns.name.Name or string 45 @param keyalgorithm: The TSIG algorithm to use; defaults to 46 dns.tsig.default_algorithm. Constants for TSIG algorithms are defined 47 in dns.tsig, and the currently implemented algorithms are 48 HMAC_MD5, HMAC_SHA1, HMAC_SHA224, HMAC_SHA256, HMAC_SHA384, and 49 HMAC_SHA512. 50 @type keyalgorithm: string 51 """ 52 super(Update, self).__init__() 53 self.flags |= dns.opcode.to_flags(dns.opcode.UPDATE) 54 if isinstance(zone, (str, unicode)): 55 zone = dns.name.from_text(zone) 56 self.origin = zone 57 if isinstance(rdclass, str): 58 rdclass = dns.rdataclass.from_text(rdclass) 59 self.zone_rdclass = rdclass 60 self.find_rrset(self.question, self.origin, rdclass, dns.rdatatype.SOA, 61 create=True, force_unique=True) 62 if not keyring is None: 63 self.use_tsig(keyring, keyname, algorithm=keyalgorithm)
64
65 - def _add_rr(self, name, ttl, rd, deleting=None, section=None):
66 """Add a single RR to the update section.""" 67 68 if section is None: 69 section = self.authority 70 covers = rd.covers() 71 rrset = self.find_rrset(section, name, self.zone_rdclass, rd.rdtype, 72 covers, deleting, True, True) 73 rrset.add(rd, ttl)
74
75 - def _add(self, replace, section, name, *args):
76 """Add records. The first argument is the replace mode. If 77 false, RRs are added to an existing RRset; if true, the RRset 78 is replaced with the specified contents. The second 79 argument is the section to add to. The third argument 80 is always a name. The other arguments can be: 81 82 - rdataset... 83 84 - ttl, rdata... 85 86 - ttl, rdtype, string...""" 87 88 if isinstance(name, (str, unicode)): 89 name = dns.name.from_text(name, None) 90 if isinstance(args[0], dns.rdataset.Rdataset): 91 for rds in args: 92 if replace: 93 self.delete(name, rds.rdtype) 94 for rd in rds: 95 self._add_rr(name, rds.ttl, rd, section=section) 96 else: 97 args = list(args) 98 ttl = int(args.pop(0)) 99 if isinstance(args[0], dns.rdata.Rdata): 100 if replace: 101 self.delete(name, args[0].rdtype) 102 for rd in args: 103 self._add_rr(name, ttl, rd, section=section) 104 else: 105 rdtype = args.pop(0) 106 if isinstance(rdtype, str): 107 rdtype = dns.rdatatype.from_text(rdtype) 108 if replace: 109 self.delete(name, rdtype) 110 for s in args: 111 rd = dns.rdata.from_text(self.zone_rdclass, rdtype, s, 112 self.origin) 113 self._add_rr(name, ttl, rd, section=section)
114
115 - def add(self, name, *args):
116 """Add records. The first argument is always a name. The other 117 arguments can be: 118 119 - rdataset... 120 121 - ttl, rdata... 122 123 - ttl, rdtype, string...""" 124 self._add(False, self.authority, name, *args)
125
126 - def delete(self, name, *args):
127 """Delete records. The first argument is always a name. The other 128 arguments can be: 129 130 - I{nothing} 131 132 - rdataset... 133 134 - rdata... 135 136 - rdtype, [string...]""" 137 138 if isinstance(name, (str, unicode)): 139 name = dns.name.from_text(name, None) 140 if len(args) == 0: 141 rrset = self.find_rrset(self.authority, name, dns.rdataclass.ANY, 142 dns.rdatatype.ANY, dns.rdatatype.NONE, 143 dns.rdatatype.ANY, True, True) 144 elif isinstance(args[0], dns.rdataset.Rdataset): 145 for rds in args: 146 for rd in rds: 147 self._add_rr(name, 0, rd, dns.rdataclass.NONE) 148 else: 149 args = list(args) 150 if isinstance(args[0], dns.rdata.Rdata): 151 for rd in args: 152 self._add_rr(name, 0, rd, dns.rdataclass.NONE) 153 else: 154 rdtype = args.pop(0) 155 if isinstance(rdtype, (str, unicode)): 156 rdtype = dns.rdatatype.from_text(rdtype) 157 if len(args) == 0: 158 rrset = self.find_rrset(self.authority, name, 159 self.zone_rdclass, rdtype, 160 dns.rdatatype.NONE, 161 dns.rdataclass.ANY, 162 True, True) 163 else: 164 for s in args: 165 rd = dns.rdata.from_text(self.zone_rdclass, rdtype, s, 166 self.origin) 167 self._add_rr(name, 0, rd, dns.rdataclass.NONE)
168
169 - def replace(self, name, *args):
170 """Replace records. The first argument is always a name. The other 171 arguments can be: 172 173 - rdataset... 174 175 - ttl, rdata... 176 177 - ttl, rdtype, string... 178 179 Note that if you want to replace the entire node, you should do 180 a delete of the name followed by one or more calls to add.""" 181 182 self._add(True, self.authority, name, *args)
183
184 - def present(self, name, *args):
185 """Require that an owner name (and optionally an rdata type, 186 or specific rdataset) exists as a prerequisite to the 187 execution of the update. The first argument is always a name. 188 The other arguments can be: 189 190 - rdataset... 191 192 - rdata... 193 194 - rdtype, string...""" 195 196 if isinstance(name, (str, unicode)): 197 name = dns.name.from_text(name, None) 198 if len(args) == 0: 199 rrset = self.find_rrset(self.answer, name, 200 dns.rdataclass.ANY, dns.rdatatype.ANY, 201 dns.rdatatype.NONE, None, 202 True, True) 203 elif isinstance(args[0], dns.rdataset.Rdataset) or \ 204 isinstance(args[0], dns.rdata.Rdata) or \ 205 len(args) > 1: 206 if not isinstance(args[0], dns.rdataset.Rdataset): 207 # Add a 0 TTL 208 args = list(args) 209 args.insert(0, 0) 210 self._add(False, self.answer, name, *args) 211 else: 212 rdtype = args[0] 213 if isinstance(rdtype, (str, unicode)): 214 rdtype = dns.rdatatype.from_text(rdtype) 215 rrset = self.find_rrset(self.answer, name, 216 dns.rdataclass.ANY, rdtype, 217 dns.rdatatype.NONE, None, 218 True, True)
219
220 - def absent(self, name, rdtype=None):
221 """Require that an owner name (and optionally an rdata type) does 222 not exist as a prerequisite to the execution of the update.""" 223 224 if isinstance(name, (str, unicode)): 225 name = dns.name.from_text(name, None) 226 if rdtype is None: 227 rrset = self.find_rrset(self.answer, name, 228 dns.rdataclass.NONE, dns.rdatatype.ANY, 229 dns.rdatatype.NONE, None, 230 True, True) 231 else: 232 if isinstance(rdtype, (str, unicode)): 233 rdtype = dns.rdatatype.from_text(rdtype) 234 rrset = self.find_rrset(self.answer, name, 235 dns.rdataclass.NONE, rdtype, 236 dns.rdatatype.NONE, None, 237 True, True)
238
239 - def to_wire(self, origin=None, max_size=65535):
240 """Return a string containing the update in DNS compressed wire 241 format. 242 @rtype: string""" 243 if origin is None: 244 origin = self.origin 245 return super(Update, self).to_wire(origin, max_size)
246