dnspython  1.16.0
About: dnspython is a DNS toolkit (for Python 2.x) that supports almost all record types.
  Fossies Dox: dnspython-1.16.0.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

update.py
Go to the documentation of this file.
1 # Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
2 
3 # Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
4 #
5 # Permission to use, copy, modify, and distribute this software and its
6 # documentation for any purpose with or without fee is hereby granted,
7 # provided that the above copyright notice and this permission notice
8 # appear in all copies.
9 #
10 # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
11 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
13 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 
18 """DNS Dynamic Update Support"""
19 
20 
21 import dns.message
22 import dns.name
23 import dns.opcode
24 import dns.rdata
25 import dns.rdataclass
26 import dns.rdataset
27 import dns.tsig
28 from ._compat import string_types
29 
30 
32 
33  def __init__(self, zone, rdclass=dns.rdataclass.IN, keyring=None,
34  keyname=None, keyalgorithm=dns.tsig.default_algorithm):
35  """Initialize a new DNS Update object.
36 
37  See the documentation of the Message class for a complete
38  description of the keyring dictionary.
39 
40  *zone*, a ``dns.name.Name`` or ``text``, the zone which is being
41  updated.
42 
43  *rdclass*, an ``int`` or ``text``, the class of the zone.
44 
45  *keyring*, a ``dict``, the TSIG keyring to use. If a
46  *keyring* is specified but a *keyname* is not, then the key
47  used will be the first key in the *keyring*. Note that the
48  order of keys in a dictionary is not defined, so applications
49  should supply a keyname when a keyring is used, unless they
50  know the keyring contains only one key.
51 
52  *keyname*, a ``dns.name.Name`` or ``None``, the name of the TSIG key
53  to use; defaults to ``None``. The key must be defined in the keyring.
54 
55  *keyalgorithm*, a ``dns.name.Name``, the TSIG algorithm to use.
56  """
57  super(Update, self).__init__()
58  self.flags |= dns.opcode.to_flags(dns.opcode.UPDATE)
59  if isinstance(zone, string_types):
60  zone = dns.name.from_text(zone)
61  self.origin = zone
62  if isinstance(rdclass, string_types):
63  rdclass = dns.rdataclass.from_text(rdclass)
64  self.zone_rdclass = rdclass
65  self.find_rrset(self.question, self.origin, rdclass, dns.rdatatype.SOA,
66  create=True, force_unique=True)
67  if keyring is not None:
68  self.use_tsig(keyring, keyname, algorithm=keyalgorithm)
69 
70  def _add_rr(self, name, ttl, rd, deleting=None, section=None):
71  """Add a single RR to the update section."""
72 
73  if section is None:
74  section = self.authority
75  covers = rd.covers()
76  rrset = self.find_rrset(section, name, self.zone_rdclass, rd.rdtype,
77  covers, deleting, True, True)
78  rrset.add(rd, ttl)
79 
80  def _add(self, replace, section, name, *args):
81  """Add records.
82 
83  *replace* is the replacement mode. If ``False``,
84  RRs are added to an existing RRset; if ``True``, the RRset
85  is replaced with the specified contents. The second
86  argument is the section to add to. The third argument
87  is always a name. The other arguments can be:
88 
89  - rdataset...
90 
91  - ttl, rdata...
92 
93  - ttl, rdtype, string...
94  """
95 
96  if isinstance(name, string_types):
97  name = dns.name.from_text(name, None)
98  if isinstance(args[0], dns.rdataset.Rdataset):
99  for rds in args:
100  if replace:
101  self.delete(name, rds.rdtype)
102  for rd in rds:
103  self._add_rr(name, rds.ttl, rd, section=section)
104  else:
105  args = list(args)
106  ttl = int(args.pop(0))
107  if isinstance(args[0], dns.rdata.Rdata):
108  if replace:
109  self.delete(name, args[0].rdtype)
110  for rd in args:
111  self._add_rr(name, ttl, rd, section=section)
112  else:
113  rdtype = args.pop(0)
114  if isinstance(rdtype, string_types):
115  rdtype = dns.rdatatype.from_text(rdtype)
116  if replace:
117  self.delete(name, rdtype)
118  for s in args:
119  rd = dns.rdata.from_text(self.zone_rdclass, rdtype, s,
120  self.origin)
121  self._add_rr(name, ttl, rd, section=section)
122 
123  def add(self, name, *args):
124  """Add records.
125 
126  The first argument is always a name. The other
127  arguments can be:
128 
129  - rdataset...
130 
131  - ttl, rdata...
132 
133  - ttl, rdtype, string...
134  """
135 
136  self._add(False, self.authority, name, *args)
137 
138  def delete(self, name, *args):
139  """Delete records.
140 
141  The first argument is always a name. The other
142  arguments can be:
143 
144  - *empty*
145 
146  - rdataset...
147 
148  - rdata...
149 
150  - rdtype, [string...]
151  """
152 
153  if isinstance(name, string_types):
154  name = dns.name.from_text(name, None)
155  if len(args) == 0:
156  self.find_rrset(self.authority, name, dns.rdataclass.ANY,
157  dns.rdatatype.ANY, dns.rdatatype.NONE,
158  dns.rdatatype.ANY, True, True)
159  elif isinstance(args[0], dns.rdataset.Rdataset):
160  for rds in args:
161  for rd in rds:
162  self._add_rr(name, 0, rd, dns.rdataclass.NONE)
163  else:
164  args = list(args)
165  if isinstance(args[0], dns.rdata.Rdata):
166  for rd in args:
167  self._add_rr(name, 0, rd, dns.rdataclass.NONE)
168  else:
169  rdtype = args.pop(0)
170  if isinstance(rdtype, string_types):
171  rdtype = dns.rdatatype.from_text(rdtype)
172  if len(args) == 0:
173  self.find_rrset(self.authority, name,
174  self.zone_rdclass, rdtype,
175  dns.rdatatype.NONE,
176  dns.rdataclass.ANY,
177  True, True)
178  else:
179  for s in args:
180  rd = dns.rdata.from_text(self.zone_rdclass, rdtype, s,
181  self.origin)
182  self._add_rr(name, 0, rd, dns.rdataclass.NONE)
183 
184  def replace(self, name, *args):
185  """Replace records.
186 
187  The first argument is always a name. The other
188  arguments can be:
189 
190  - rdataset...
191 
192  - ttl, rdata...
193 
194  - ttl, rdtype, string...
195 
196  Note that if you want to replace the entire node, you should do
197  a delete of the name followed by one or more calls to add.
198  """
199 
200  self._add(True, self.authority, name, *args)
201 
202  def present(self, name, *args):
203  """Require that an owner name (and optionally an rdata type,
204  or specific rdataset) exists as a prerequisite to the
205  execution of the update.
206 
207  The first argument is always a name.
208  The other arguments can be:
209 
210  - rdataset...
211 
212  - rdata...
213 
214  - rdtype, string...
215  """
216 
217  if isinstance(name, string_types):
218  name = dns.name.from_text(name, None)
219  if len(args) == 0:
220  self.find_rrset(self.answer, name,
221  dns.rdataclass.ANY, dns.rdatatype.ANY,
222  dns.rdatatype.NONE, None,
223  True, True)
224  elif isinstance(args[0], dns.rdataset.Rdataset) or \
225  isinstance(args[0], dns.rdata.Rdata) or \
226  len(args) > 1:
227  if not isinstance(args[0], dns.rdataset.Rdataset):
228  # Add a 0 TTL
229  args = list(args)
230  args.insert(0, 0)
231  self._add(False, self.answer, name, *args)
232  else:
233  rdtype = args[0]
234  if isinstance(rdtype, string_types):
235  rdtype = dns.rdatatype.from_text(rdtype)
236  self.find_rrset(self.answer, name,
237  dns.rdataclass.ANY, rdtype,
238  dns.rdatatype.NONE, None,
239  True, True)
240 
241  def absent(self, name, rdtype=None):
242  """Require that an owner name (and optionally an rdata type) does
243  not exist as a prerequisite to the execution of the update."""
244 
245  if isinstance(name, string_types):
246  name = dns.name.from_text(name, None)
247  if rdtype is None:
248  self.find_rrset(self.answer, name,
249  dns.rdataclass.NONE, dns.rdatatype.ANY,
250  dns.rdatatype.NONE, None,
251  True, True)
252  else:
253  if isinstance(rdtype, string_types):
254  rdtype = dns.rdatatype.from_text(rdtype)
255  self.find_rrset(self.answer, name,
256  dns.rdataclass.NONE, rdtype,
257  dns.rdatatype.NONE, None,
258  True, True)
259 
260  def to_wire(self, origin=None, max_size=65535):
261  """Return a string containing the update in DNS compressed wire
262  format.
263 
264  *origin*, a ``dns.name.Name`` or ``None``, the origin to be
265  appended to any relative names. If *origin* is ``None``, then
266  the origin of the ``dns.update.Update`` message object is used
267  (i.e. the *zone* parameter passed when the Update object was
268  created).
269 
270  *max_size*, an ``int``, the maximum size of the wire format
271  output; default is 0, which means "the message's request
272  payload, if nonzero, or 65535".
273 
274  Returns a ``binary``.
275  """
276 
277  if origin is None:
278  origin = self.origin
279  return super(Update, self).to_wire(origin, max_size)
dns.rdataset.Rdataset
Definition: rdataset.py:44
dns.message
Definition: message.py:1
dns.tsig
Definition: tsig.py:1
dns.update.Update.absent
def absent(self, name, rdtype=None)
Definition: update.py:241
dns.name.from_text
def from_text(text, origin=root, idna_codec=None)
Definition: name.py:873
dns.update.Update.to_wire
def to_wire(self, origin=None, max_size=65535)
Definition: update.py:260
dns.message.Message.question
question
Definition: message.py:92
dns.opcode.to_flags
def to_flags(value)
Definition: opcode.py:83
dns.rdataset
Definition: rdataset.py:1
dns.rdataclass
Definition: rdataclass.py:1
dns.message.Message.flags
flags
Definition: message.py:91
dns.update.Update.add
def add(self, name, *args)
Definition: update.py:123
dns.message.Message.origin
origin
Definition: message.py:111
dns.update.Update.__init__
def __init__(self, zone, rdclass=dns.rdataclass.IN, keyring=None, keyname=None, keyalgorithm=dns.tsig.default_algorithm)
Definition: update.py:33
dns.message.Message.answer
answer
Definition: message.py:93
dns.rdata.from_text
def from_text(rdclass, rdtype, tok, origin=None, relativize=True)
Definition: rdata.py:344
dns.message.Message.authority
authority
Definition: message.py:94
dns.update.Update.replace
def replace(self, name, *args)
Definition: update.py:184
dns.update.Update
Definition: update.py:31
dns.name
Definition: name.py:1
dns.message.Message.find_rrset
def find_rrset(self, section, name, rdclass, rdtype, covers=dns.rdatatype.NONE, deleting=None, create=False, force_unique=False)
Definition: message.py:287
dns.update.Update._add_rr
def _add_rr(self, name, ttl, rd, deleting=None, section=None)
Definition: update.py:70
dns.message.Message
Definition: message.py:83
dns.rdata
Definition: rdata.py:1
dns.update.Update.present
def present(self, name, *args)
Definition: update.py:202
dns.opcode
Definition: opcode.py:1
dns.rdatatype.from_text
def from_text(text)
Definition: rdatatype.py:193
dns.update.Update._add
def _add(self, replace, section, name, *args)
Definition: update.py:80
dns.update.Update.zone_rdclass
zone_rdclass
Definition: update.py:63
dns.update.Update.delete
def delete(self, name, *args)
Definition: update.py:138
dns.rdataclass.from_text
def from_text(text)
Definition: rdataclass.py:67
dns.message.Message.use_tsig
def use_tsig(self, keyring, keyname=None, fudge=300, original_id=None, tsig_error=0, other_data=b'', algorithm=dns.tsig.default_algorithm)
Definition: message.py:440
dns.rdata.Rdata
Definition: rdata.py:95