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

Source Code for Module dns.update

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