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