1
2
3
4
5
6
7
8
9
10
11
12
13
14
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):
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):
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
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
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
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