source: trunk/server/lib/dnspython/dns/update.py

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 10.2 KB
Line 
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
16"""DNS Dynamic Update Support"""
17
18import dns.message
19import dns.name
20import dns.opcode
21import dns.rdata
22import dns.rdataclass
23import dns.rdataset
24import dns.tsig
25
26class 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)
Note: See TracBrowser for help on using the repository browser.