Import upstream version 1.16.0+git20191031.0d018c3, md5 cb8672cb0f2d59a5715b3e10cf7c789d
Debian Janitor
4 years ago
0 | 0 | language: python |
1 | 1 | python: |
2 | - "2.7" | |
3 | - "3.4" | |
4 | 2 | - "3.5" |
5 | 3 | - "3.6" |
4 | - "3.7" | |
5 | - "3.8" | |
6 | 6 | #- "nightly" |
7 | 7 | matrix: |
8 | 8 | include: |
17 | 17 | install: |
18 | 18 | - pip install typing pylint pycryptodome ecdsa idna |
19 | 19 | script: |
20 | - make typecheck | |
21 | - make lint | |
22 | 20 | - make test |
17 | 17 | # $Id: Makefile,v 1.16 2004/03/19 00:17:27 halley Exp $ |
18 | 18 | |
19 | 19 | PYTHON=python |
20 | PYTHON3=python3 | |
20 | PIP=pip | |
21 | # set this to "--user" if you prefer | |
22 | PIPMODE= | |
21 | 23 | |
22 | 24 | all: |
23 | 25 | ${PYTHON} ./setup.py build |
51 | 53 | rm -rf html.tar.gz html.zip html |
52 | 54 | |
53 | 55 | kits: |
54 | ${PYTHON3} ./setup.py sdist --formats=gztar,zip bdist_wheel | |
56 | ${PYTHON} ./setup.py sdist --formats=gztar,zip bdist_wheel | |
55 | 57 | |
56 | 58 | tags: |
57 | 59 | find . -name '*.py' -print | etags - |
59 | 61 | check: test |
60 | 62 | |
61 | 63 | test: |
62 | cd tests; make PYTHON=${PYTHON} test | |
64 | cd tests; make test | |
63 | 65 | |
64 | test2: | |
65 | cd tests; make PYTHON=python test | |
66 | ||
67 | test3: | |
68 | cd tests; make PYTHON=${PYTHON3} test | |
66 | test3: test | |
69 | 67 | |
70 | 68 | lint: |
71 | 69 | pylint dns tests examples/*.py |
72 | 70 | |
73 | lint3: | |
74 | pylint3 dns tests examples/*.py | |
71 | lint3: lint | |
75 | 72 | |
76 | 73 | typecheck: |
77 | if [ $(shell python -c "import sys; print(sys.version_info[0])") -ne 2 ]; then pip install mypy; mypy examples tests; else echo Skipping typecheck on Python 2; fi | |
74 | ${PIP} show mypy >/dev/null 2>&1 || ${PIP} install ${PIPMODE} mypy | |
75 | mypy examples tests |
0 | 0 | # dnspython |
1 | 1 | |
2 | 2 | [![Build Status](https://travis-ci.org/rthalley/dnspython.svg?branch=master)](https://travis-ci.org/rthalley/dnspython) |
3 | [![PyPI version](https://badge.fury.io/py/dnspython.svg)](https://badge.fury.io/py/dnspython) | |
4 | [![PyPI Statistics](https://img.shields.io/pypi/dm/dnspython.svg)](https://pypistats.org/packages/dnspython) | |
5 | ||
3 | 6 | |
4 | 7 | ## INTRODUCTION |
5 | 8 | |
30 | 33 | |
31 | 34 | ## ABOUT THIS RELEASE |
32 | 35 | |
33 | This is dnspython 1.16.0 | |
36 | This is the development verison of dnspython 2.0.0 | |
34 | 37 | |
35 | 38 | ### Notices |
36 | 39 | |
37 | Python 2.x support ends with the release of 1.16.0, unless there are | |
38 | critical bugs in 1.16.0. Future versions of dnspython will only | |
39 | support Python 3. | |
40 | ||
41 | Version numbering of future dnspython releases will also start at 2.0, as | |
42 | incompatible changes will be permitted. We're not planning huge changes at | |
43 | this time, but we'd like to do a better job at IDNA, and there are other | |
44 | API improvements to be made. | |
40 | Python 2.x support ended with the release of 1.16.0. dnspython 2.0.0 and | |
41 | later only support Python 3.4 and later. | |
45 | 42 | |
46 | 43 | The ChangeLog has been discontinued. Please see the git history for detailed |
47 | 44 | change information. |
48 | ||
49 | ### New since 1.15.0: | |
50 | ||
51 | * Much of the internals of dns.query.udp() and dns.query.tcp() have | |
52 | been factored out into dns.query.send_udp(), | |
53 | dns.query.receive_udp(), dns.query.send_tcp(), and | |
54 | dns.query.receive_tcp(). Applications which want more control over | |
55 | the socket may find the new routines helpful; for example it would | |
56 | be easy to send multiple queries over a single TCP connection. | |
57 | ||
58 | * The OPENPGPKEY RR, and the CHAOS class A RR are now supported. | |
59 | ||
60 | * EDNS0 client-subnet is supported. | |
61 | ||
62 | * dns.resover.query() now has a lifetime timeout optional parameter. | |
63 | ||
64 | * pycryptodome and pycryptodomex are now supported and recommended for use | |
65 | instead of pycrypto. | |
66 | ||
67 | * dns.message.from_wire() now has an ignore_trailing option. | |
68 | ||
69 | * type signatures have been provided. | |
70 | ||
71 | * module dns.hash is now deprecated, use standard Python libraries instead. | |
72 | ||
73 | * setup.py supports Cythonization to improve performance. | |
74 | ||
75 | ### Bugs fixed since 1.15.0: | |
76 | ||
77 | * DNSSEC signature validation didn't check names correctly. [Issue #295] | |
78 | ||
79 | * The NXDOMAIN exception should not use its docstring. [Issue #253] | |
80 | ||
81 | * Fixed regression where trailing zeros in APL RRs were not | |
82 | suppressed, and then fixed the problem where trailing zeros | |
83 | were not added back properly on python 3 when needed. | |
84 | ||
85 | * Masterfile TTL defaulting is now harmonized with BIND practice. | |
86 | ||
87 | * dns.query.xfr() now raises on a non-zero rcode. | |
88 | ||
89 | * Rdata module importing is now locked to avoid races. | |
90 | ||
91 | * Several Python 3 incompatibilities have been fixed. | |
92 | ||
93 | * NSEC3 bitmap parsing now works with mulitple NSEC3 windows. | |
94 | ||
95 | * dns.renderer.Render supports TSIG on DNS envelope sequences. | |
96 | ||
97 | * DNSSEC validation now checks names properly [Issue #295] | |
98 | ||
99 | ### New since 1.14.0: | |
100 | ||
101 | * IDNA 2008 support is now available if the "idna" module has been | |
102 | installed and IDNA 2008 is requested. The default IDNA behavior is | |
103 | still IDNA 2003. The new IDNA codec mechanism is currently only | |
104 | useful for direct calls to dns.name.from_text() or | |
105 | dns.name.from_unicode(), but in future releases it will be deployed | |
106 | throughout dnspython, e.g. so that you can read a masterfile with an | |
107 | IDNA 2008 codec in force. | |
108 | ||
109 | * By default, dns.name.to_unicode() is not strict about which | |
110 | version of IDNA the input complies with. Strictness can be | |
111 | requested by using one of the strict IDNA codecs. | |
112 | ||
113 | * The AVC RR is now supported. | |
114 | ||
115 | ### Bugs fixed since 1.14.0: | |
116 | ||
117 | * Some problems with newlines in various output modes have been | |
118 | addressed. | |
119 | ||
120 | * dns.name.to_text() now returns text and not bytes on Python 3.x | |
121 | ||
122 | * Miscellaneous fixes for the Python 2/3 codeline merge. | |
123 | ||
124 | * Many "lint" fixes after the addition of pylint support. | |
125 | ||
126 | * The random number generator reseeds after a fork(). | |
127 | ||
128 | ||
129 | ## REQUIREMENTS | |
130 | ||
131 | Python 2.7 or 3.4+. | |
132 | ||
133 | ||
134 | ## HOME PAGE | |
135 | ||
136 | For the latest in releases, documentation, and information, visit the dnspython | |
137 | home page at http://www.dnspython.org/ | |
138 | ||
139 | ||
140 | ## BUG REPORTS | |
141 | ||
142 | Bug reports may be opened at | |
143 | https://github.com/rthalley/dnspython/issues or sent to | |
144 | bugs@dnspython.org | |
145 | ||
146 | ||
147 | ## MAILING LISTS | |
148 | ||
149 | A number of mailing lists are available. Visit the dnspython home page to | |
150 | subscribe or unsubscribe. | |
151 | ||
152 | ||
153 | ## PRIOR RELEASE INFORMATION | |
154 | ||
155 | ### New since 1.13.0: | |
156 | ||
157 | * CSYNC RRs are now supported. | |
158 | ||
159 | * `dns/message.py` (`make_query`): Setting any value which implies EDNS will | |
160 | turn on EDNS if `use_edns` has not been specified. | |
161 | ||
162 | ### Bugs fixed since 1.13.0: | |
163 | ||
164 | * TSIG signature algorithm setting was broken by the Python 2 and Python 3 code | |
165 | line merge. | |
166 | ||
167 | * A bug in the LOC RR destroyed N/S and E/W distinctions within a degree of the | |
168 | equator or prime merdian respectively. | |
169 | ||
170 | * Misc. fixes to deal with fallout from the Python 2 & 3 merge. | |
171 | Fixes #156, #157, #158, #159, #160. | |
172 | ||
173 | * Running with python optimization on caused issues when stripped docstrings | |
174 | were referenced. Fixes #154 | |
175 | ||
176 | * `dns.zone.from_text()` erroneously required the zone to be provided. | |
177 | Fixes #153 | |
178 | ||
179 | ### New since 1.12.0: | |
180 | ||
181 | * Dnspython now uses a single source for Python 2 and Python 3, eliminating the | |
182 | painful merging between the Python 2 and Python 3 branches. Thank you so much | |
183 | to Arthur Gautier for taking on this challenge and making it work! It was a | |
184 | big job! | |
185 | ||
186 | * Support for Python older than 2.6 dropped. | |
187 | ||
188 | * Support for Python older than 3.3 dropped. | |
189 | ||
190 | * Zone origin can be specified as a string. | |
191 | ||
192 | * A rich string representation for all DNSExceptions. | |
193 | ||
194 | * setuptools has replaced distutils | |
195 | ||
196 | * Added support for CAA, CDS, CDNSKEY, EUI48, EUI64, and URI RR types. | |
197 | ||
198 | * Names now support the pickle protocol. | |
199 | ||
200 | * Ports can be specified per-nameserver in the stub resolver. | |
201 | ||
202 | ### Bugs fixed since 1.12.0: | |
203 | ||
204 | * A number of Unicode name bugs have been fixed. | |
205 | ||
206 | * `resolv.conf` processing now rejects lines with too few tokens. | |
207 | ||
208 | * NameDicts now keep the max-depth value correct, and update properly. | |
209 | ||
210 | ### New since 1.11.1: | |
211 | ||
212 | * Added `dns.zone.to_text()`. | |
213 | ||
214 | * Added support for "options rotate" in `/etc/resolv.conf`. | |
215 | ||
216 | * `dns.rdtypes.ANY.DNSKEY` now has helpers functions to convert between the | |
217 | numeric form of the flags and a set of human-friendly strings | |
218 | ||
219 | * The reverse name of an IPv6 mapped IPv4 address is now in the IPv4 reverse | |
220 | namespace. | |
221 | ||
222 | * The test system can now run the tests without requiring dnspython to be | |
223 | installed. | |
224 | ||
225 | * Preliminary Elliptic Curve DNSSEC Validation (requires ecdsa module) | |
226 | ||
227 | ### Bugs fixed since 1.11.1: | |
228 | ||
229 | * dnspython raised an exception when reading a masterfile starting with leading | |
230 | whitespace | |
231 | ||
232 | * dnspython was affected by a python slicing API bug present on 64-bit windows. | |
233 | ||
234 | * Unicode escaping was applied at the wrong time. | |
235 | ||
236 | * RRSIG `to_text()` did not respect the relativize setting. | |
237 | ||
238 | * APL RRs with zero rdlength were rejected. | |
239 | ||
240 | * The tokenizer could put back an unescaped token. | |
241 | ||
242 | * Making a response to a message signed with TSIG was broken. | |
243 | ||
244 | * The IXFR state machine didn't handle long IXFR diffs. | |
245 | ||
246 | ### New since 1.11.0: | |
247 | ||
248 | * Nothing | |
249 | ||
250 | ### Bugs fixed since 1.11.0: | |
251 | ||
252 | * `dns.resolver.Resolver` erroneously referred to `retry_servfail` | |
253 | instead of `self.retry_servfail`. | |
254 | ||
255 | * `dns.tsigkeyring.to_text()` would fail trying to convert the keyname to text. | |
256 | ||
257 | * Multi-message TSIGs were broken for algorithms other than HMAC-MD5 because we | |
258 | weren't passing the right digest module to the HMAC code. | |
259 | ||
260 | * `dns.dnssec._find_candidate_keys()` tried to extract the key from the wrong | |
261 | variable name. | |
262 | ||
263 | * $GENERATE tests were not backward compatible with python 2.4. | |
264 | ||
265 | ### New since 1.10.0: | |
266 | ||
267 | * $GENERATE support | |
268 | ||
269 | * TLSA RR support | |
270 | ||
271 | * Added set_flags() method to dns.resolver.Resolver | |
272 | ||
273 | ### Bugs fixed since 1.10.0: | |
274 | ||
275 | * Names with offsets >= 2^14 are no longer added to the compression table. | |
276 | ||
277 | * The "::" syntax is not used to shorten a single 16-bit section of the text | |
278 | form an IPv6 address. | |
279 | ||
280 | * Caches are now locked. | |
281 | ||
282 | * YXDOMAIN is raised if seen by the resolver. | |
283 | ||
284 | * Empty rdatasets are not printed. | |
285 | ||
286 | * DNSKEY key tags are no longer assumed to be unique. | |
287 | ||
288 | ### New since 1.9.4: | |
289 | ||
290 | * Added dns.resolver.LRUCache. In this cache implementation, the cache size is | |
291 | limited to a user-specified number of nodes, and when adding a new node to a | |
292 | full cache the least-recently used node is removed. If you're crawling the web | |
293 | or otherwise doing lots of resolutions and you are using a cache, switching | |
294 | to the LRUCache is recommended. | |
295 | ||
296 | * `dns.resolver.query()` will try TCP if a UDP response is truncated. | |
297 | ||
298 | * The python socket module's DNS methods can be now be overridden with | |
299 | implementations that use dnspython's resolver. | |
300 | ||
301 | * Old DNSSEC types KEY, NXT, and SIG have been removed. | |
302 | ||
303 | * Whitespace is allowed in SSHFP fingerprints. | |
304 | ||
305 | * Origin checking in `dns.zone.from_xfr()` can be disabled. | |
306 | ||
307 | * Trailing junk checking can be disabled. | |
308 | ||
309 | * A source port can be specified when creating a resolver query. | |
310 | ||
311 | * All EDNS values may now be specified to `dns.message.make_query()`. | |
312 | ||
313 | ### Bugs fixed since 1.9.4: | |
314 | ||
315 | * IPv4 and IPv6 address processing is now stricter. | |
316 | ||
317 | * Bounds checking of slices in rdata wire processing is now more strict, and | |
318 | bounds errors (e.g. we got less data than was expected) now raise | |
319 | `dns.exception.FormError` rather than `IndexError`. | |
320 | ||
321 | * Specifying a source port without specifying source used to have no effect, but | |
322 | now uses the wildcard address and the specified port. | |
323 | ||
324 | ### New since 1.9.3: | |
325 | ||
326 | * Nothing. | |
327 | ||
328 | ### Bugs fixed since 1.9.3: | |
329 | ||
330 | * The rdata `_wire_cmp()` routine now handles relative names. | |
331 | ||
332 | * The SIG RR implementation was missing `import struct`. | |
333 | ||
334 | ### New since 1.9.2: | |
335 | ||
336 | * A boolean parameter, `raise_on_no_answer`, has been added to the `query()` | |
337 | methods. In no-error, no-data situations, this parameter determines whether | |
338 | `NoAnswer` should be raised or not. If True, `NoAnswer` is raised. If False, | |
339 | then an `Answer()` object with a None rrset will be returned. | |
340 | ||
341 | * Resolver `Answer()` objects now have a canonical_name field. | |
342 | ||
343 | * Rdata now has a `__hash__` method. | |
344 | ||
345 | ### Bugs fixed since 1.9.2: | |
346 | ||
347 | * Dnspython was erroneously doing case-insensitive comparisons of the names in | |
348 | NSEC and RRSIG RRs. | |
349 | ||
350 | * We now use `is` and not `==` when testing what section an RR is in. | |
351 | ||
352 | * The resolver now disallows metaqueries. | |
353 | ||
354 | ### New since 1.9.1: | |
355 | ||
356 | * Nothing. | |
357 | ||
358 | ### Bugs fixed since 1.9.1: | |
359 | ||
360 | * The `dns.dnssec` module didn't work at all due to missing imports that escaped | |
361 | detection in testing because the test suite also did the imports. The third | |
362 | time is the charm! | |
363 | ||
364 | ### New since 1.9.0: | |
365 | ||
366 | * Nothing. | |
367 | ||
368 | ### Bugs fixed since 1.9.0: | |
369 | ||
370 | * The `dns.dnssec` module didn't work with DSA due to namespace contamination | |
371 | from a "from"-style import. | |
372 | ||
373 | ### New since 1.8.0: | |
374 | ||
375 | * dnspython now uses `poll()` instead of `select()` when available. | |
376 | ||
377 | * Basic DNSSEC validation can be done using `dns.dnsec.validate()` and | |
378 | `dns.dnssec.validate_rrsig()` if you have PyCrypto 2.3 or later installed. | |
379 | Complete secure resolution is not yet available. | |
380 | ||
381 | * Added `key_id()` to the DNSSEC module, which computes the DNSSEC key id of a | |
382 | DNSKEY rdata. | |
383 | ||
384 | * Added `make_ds()` to the DNSSEC module, which returns the DS RR for a given | |
385 | DNSKEY rdata. | |
386 | ||
387 | * dnspython now raises an exception if HMAC-SHA284 or HMAC-SHA512 are used with | |
388 | a Python older than 2.5.2. (Older Pythons do not compute the correct value.) | |
389 | ||
390 | * Symbolic constants are now available for TSIG algorithm names. | |
391 | ||
392 | ### Bugs fixed since 1.8.0 | |
393 | ||
394 | * `dns.resolver.zone_for_name()` didn't handle a query response with a CNAME or | |
395 | DNAME correctly in some cases. | |
396 | ||
397 | * When specifying rdata types and classes as text, Unicode strings may now be | |
398 | used. | |
399 | ||
400 | * Hashlib compatibility issues have been fixed. | |
401 | ||
402 | * `dns.message` now imports `dns.edns`. | |
403 | ||
404 | * The TSIG algorithm value was passed incorrectly to `use_tsig()` in some cases. | |
405 | ||
406 | ### New since 1.7.1: | |
407 | ||
408 | * Support for hmac-sha1, hmac-sha224, hmac-sha256, hmac-sha384 and hmac-sha512 | |
409 | has been contributed by Kevin Chen. | |
410 | ||
411 | * The tokenizer's tokens are now Token objects instead of (type, value) tuples. | |
412 | ||
413 | ### Bugs fixed since 1.7.1: | |
414 | ||
415 | * Escapes in masterfiles now work correctly. Previously they were only working | |
416 | correctly when the text involved was part of a domain name. | |
417 | ||
418 | * When constructing a DDNS update, if the `present()` method was used with a | |
419 | single rdata, a zero TTL was not added. | |
420 | ||
421 | * The entropy pool needed locking to be thread safe. | |
422 | ||
423 | * The entropy pool's reading of `/dev/random` could cause dnspython to block. | |
424 | ||
425 | * The entropy pool did buffered reads, potentially consuming more randomness | |
426 | than we needed. | |
427 | ||
428 | * The entropy pool did not seed with high quality randomness on Windows. | |
429 | ||
430 | * SRV records were compared incorrectly. | |
431 | ||
432 | * In the e164 query function, the resolver parameter was not used. | |
433 | ||
434 | ### New since 1.7.0: | |
435 | ||
436 | * Nothing | |
437 | ||
438 | ### Bugs fixed since 1.7.0: | |
439 | ||
440 | * The 1.7.0 kitting process inadvertently omitted the code for the DLV RR. | |
441 | ||
442 | * Negative DDNS prerequisites are now handled correctly. | |
443 | ||
444 | ### New since 1.6.0: | |
445 | ||
446 | * Rdatas now have a `to_digestable()` method, which returns the DNSSEC canonical | |
447 | form of the rdata, suitable for use in signature computations. | |
448 | ||
449 | * The NSEC3, NSEC3PARAM, DLV, and HIP RR types are now supported. | |
450 | ||
451 | * An entropy module has been added and is used to randomize query ids. | |
452 | ||
453 | * EDNS0 options are now supported. | |
454 | ||
455 | * UDP IXFR is now supported. | |
456 | ||
457 | * The wire format parser now has a `one_rr_per_rrset` mode, which suppresses the | |
458 | usual coalescing of all RRs of a given type into a single RRset. | |
459 | ||
460 | * Various helpful DNSSEC-related constants are now defined. | |
461 | ||
462 | * The resolver's `query()` method now has an optional `source` parameter, | |
463 | allowing the source IP address to be specified. | |
464 | ||
465 | ### Bugs fixed since 1.6.0: | |
466 | ||
467 | * On Windows, the resolver set the domain incorrectly. | |
468 | ||
469 | * DS RR parsing only allowed one Base64 chunk. | |
470 | ||
471 | * TSIG validation didn't always use absolute names. | |
472 | ||
473 | * `NSEC.to_text()` only printed the last window. | |
474 | ||
475 | * We did not canonicalize IPv6 addresses before comparing them; we | |
476 | would thus treat equivalent but different textual forms, e.g. | |
477 | "1:00::1" and "1::1" as being non-equivalent. | |
478 | ||
479 | * If the peer set a TSIG error, we didn't raise an exception. | |
480 | ||
481 | * Some EDNS bugs in the message code have been fixed (see the ChangeLog | |
482 | for details). | |
483 | ||
484 | ### New since 1.5.0: | |
485 | ||
486 | * Added dns.inet.is_multicast(). | |
487 | ||
488 | ### Bugs fixed since 1.5.0: | |
489 | ||
490 | * If `select()` raises an exception due to EINTR, we should just `select()` | |
491 | again. | |
492 | ||
493 | * If the queried address is a multicast address, then don't check that the | |
494 | address of the response is the same as the address queried. | |
495 | ||
496 | * NAPTR comparisons didn't compare the preference field due to a typo. | |
497 | ||
498 | * Testing of whether a Windows NIC is enabled now works on Vista thanks to code | |
499 | contributed by Paul Marks. | |
500 | ||
501 | ### New since 1.4.0: | |
502 | ||
503 | * Answer objects now support more of the python sequence protocol, forwarding | |
504 | the requests to the answer rrset. E.g. `for a in answer` is equivalent to | |
505 | `for a in answer.rrset`, `answer[i]` is equivalent to `answer.rrset[i]`, and | |
506 | `answer[i:j]` is equivalent to `answer.rrset[i:j]`. | |
507 | ||
508 | * Making requests using EDNS, including indicating DNSSEC awareness, | |
509 | is now easier. For example, you can now say: | |
510 | `q = dns.message.make_query('www.dnspython.org', 'MX', want_dnssec=True)` | |
511 | ||
512 | * `dns.query.xfr()` can now be used for IXFR. | |
513 | ||
514 | * Support has been added for the DHCID, IPSECKEY, and SPF RR types. | |
515 | ||
516 | * UDP messages from unexpected sources can now be ignored by setting | |
517 | `ignore_unexpected` to True when calling `dns.query.udp`. | |
518 | ||
519 | ### Bugs fixed since 1.4.0: | |
520 | ||
521 | * If `/etc/resolv.conf` didn't exist, we raised an exception instead of simply | |
522 | using the default resolver configuration. | |
523 | ||
524 | * In `dns.resolver.Resolver._config_win32_fromkey()`, we were passing the wrong | |
525 | variable to `self._config_win32_search()`. | |
526 | ||
527 | ### New since 1.3.5: | |
528 | ||
529 | * You can now convert E.164 numbers to/from their ENUM name forms: | |
530 | ```python | |
531 | >>> import dns.e164 | |
532 | >>> n = dns.e164.from_e164("+1 555 1212") | |
533 | >>> n | |
534 | <DNS name 2.1.2.1.5.5.5.1.e164.arpa.> | |
535 | >>> dns.e164.to_e164(n) | |
536 | '+15551212' | |
537 | ``` | |
538 | ||
539 | * You can now convert IPv4 and IPv6 address to/from their corresponding DNS | |
540 | reverse map names: | |
541 | ```python | |
542 | >>> import dns.reversename | |
543 | >>> n = dns.reversename.from_address("127.0.0.1") | |
544 | >>> n | |
545 | <DNS name 1.0.0.127.in-addr.arpa.> | |
546 | >>> dns.reversename.to_address(n) | |
547 | '127.0.0.1' | |
548 | ``` | |
549 | ||
550 | * You can now convert between Unicode strings and their IDN ACE form: | |
551 | ```python | |
552 | >>> n = dns.name.from_text(u'les-\u00e9l\u00e8ves.example.') | |
553 | >>> n | |
554 | <DNS name xn--les-lves-50ai.example.> | |
555 | >>> n.to_unicode() | |
556 | u'les-\xe9l\xe8ves.example.' | |
557 | ``` | |
558 | ||
559 | * The origin parameter to `dns.zone.from_text()` and `dns.zone.to_text()` is now | |
560 | optional. If not specified, the origin will be taken from the first $ORIGIN | |
561 | statement in the master file. | |
562 | ||
563 | * Sanity checking of a zone can be disabled; this is useful when working with | |
564 | files which are zone fragments. | |
565 | ||
566 | ### Bugs fixed since 1.3.5: | |
567 | ||
568 | * The correct delimiter was not used when retrieving the list of nameservers | |
569 | from the registry in certain versions of windows. | |
570 | ||
571 | * The floating-point version of latitude and longitude in LOC RRs | |
572 | (`float_latitude` and `float_longitude`) had incorrect signs for south | |
573 | latitudes and west longitudes. | |
574 | ||
575 | * BIND 8 TTL syntax is now accepted in all TTL-like places (i.e. SOA fields | |
576 | refresh, retry, expire, and minimum; SIG/RRSIG field original_ttl). | |
577 | ||
578 | * TTLs are now bounds checked when their text form is parsed, and their values | |
579 | must be in the closed interval `[0, 2^31 - 1]`. | |
580 | ||
581 | ### New since 1.3.4: | |
582 | ||
583 | * In the resolver, if time goes backward a little bit, ignore it. | |
584 | ||
585 | * `zone_for_name()` has been added to the resolver module. It returns the zone | |
586 | which is authoritative for the specified name, which is handy for dynamic | |
587 | update. E.g. | |
588 | ||
589 | import dns.resolver | |
590 | print dns.resolver.zone_for_name('www.dnspython.org') | |
591 | ||
592 | will output `"dnspython.org."` and | |
593 | `print dns.resolver.zone_for_name('a.b.c.d.e.f.example.')` | |
594 | will output `"."`. | |
595 | ||
596 | * The default resolver can be fetched with the `get_default_resolver()` method. | |
597 | ||
598 | * You can now get the parent (immediate superdomain) of a name by using the | |
599 | `parent()` method. | |
600 | ||
601 | * `Zone.iterate_rdatasets()` and `Zone.iterate_rdatas()` now have a default | |
602 | rdtype of `dns.rdatatype.ANY` like the documentation says. | |
603 | ||
604 | * A Dynamic DNS example, ddns.py, has been added. | |
605 | ||
606 | ### New since 1.3.3: | |
607 | ||
608 | * The source address and port may now be specified when calling | |
609 | `dns.query.{udp,tcp,xfr}`. | |
610 | ||
611 | * The resolver now does exponential backoff each time it runs through all of the | |
612 | nameservers. | |
613 | ||
614 | * Rcodes which indicate a nameserver is likely to be a "permanent failure" for a | |
615 | query cause the nameserver to be removed from the mix for that query. | |
616 | ||
617 | ### New since 1.3.2: | |
618 | ||
619 | * `dns.message.Message.find_rrset()` now uses an index, vastly improving the | |
620 | `from_wire()` performance of large messages such as zone transfers. | |
621 | ||
622 | * Added `dns.message.make_response()`, which creates a skeletal response for the | |
623 | specified query. | |
624 | ||
625 | * Added `opcode()` and `set_opcode()` convenience methods to the | |
626 | `dns.message.Message` class. Added the `request_payload` attribute to the | |
627 | Message class. | |
628 | ||
629 | * The `file` parameter of `dns.name.Name.to_wire()` is now optional; if omitted, | |
630 | the wire form will be returned as the value of the function. | |
631 | ||
632 | * `dns.zone.from_xfr()` in relativization mode incorrectly set `zone.origin` to | |
633 | the empty name. | |
634 | ||
635 | * The masterfile parser incorrectly rejected TXT records where a value was not | |
636 | quoted. | |
637 | ||
638 | ### New since 1.3.1: | |
639 | ||
640 | * The NSEC format doesn't allow specifying types by number, so we shouldn't | |
641 | either. (Using the unknown type format is still OK though.) | |
642 | ||
643 | * The resolver wasn't catching `dns.exception.Timeout`, so a timeout erroneously | |
644 | caused the whole resolution to fail instead of just going on to the next | |
645 | server. | |
646 | ||
647 | * The renderer module didn't import random, causing an exception to be raised if | |
648 | a query id wasn't provided when a Renderer was created. | |
649 | ||
650 | * The conversion of LOC milliseconds values from text to binary was incorrect if | |
651 | the length of the milliseconds string was not 3. | |
652 | ||
653 | ### New since 1.3.0: | |
654 | ||
655 | * Added support for the SSHFP type. | |
656 | ||
657 | ### New since 1.2.0: | |
658 | ||
659 | * Added support for new DNSSEC types RRSIG, NSEC, and DNSKEY. | |
660 | ||
661 | * This release fixes all known bugs. | |
662 | ||
663 | * See the ChangeLog file for more detailed information on changes since the | |
664 | prior release. |
0 | # Incompatible differences between dnspython 1.x and 2.x | |
1 | ||
2 | ## Rounding | |
3 | ||
4 | dnspython 2.0 rounds in the standard python 3 fashion; dnspython 1.x rounded | |
5 | in the python 2 style on both python 2 and 3. | |
6 | ||
7 | # Removed hash module | |
8 | ||
9 | dns.hash module was removed. Use Python built in hashlib instead. |
23 | 23 | 'entropy', |
24 | 24 | 'exception', |
25 | 25 | 'flags', |
26 | 'hash', | |
27 | 26 | 'inet', |
28 | 27 | 'ipv4', |
29 | 28 | 'ipv6', |
53 | 52 | 'wiredata', |
54 | 53 | 'zone', |
55 | 54 | ] |
55 | ||
56 | from dns.version import version as __version__ |
0 | import sys | |
1 | import decimal | |
2 | from decimal import Context | |
3 | ||
4 | PY3 = sys.version_info[0] == 3 | |
5 | PY2 = sys.version_info[0] == 2 | |
6 | ||
7 | ||
8 | if PY3: | |
9 | long = int | |
10 | xrange = range | |
11 | else: | |
12 | long = long # pylint: disable=long-builtin | |
13 | xrange = xrange # pylint: disable=xrange-builtin | |
14 | ||
15 | # unicode / binary types | |
16 | if PY3: | |
17 | text_type = str | |
18 | binary_type = bytes | |
19 | string_types = (str,) | |
20 | unichr = chr | |
21 | def maybe_decode(x): | |
22 | return x.decode() | |
23 | def maybe_encode(x): | |
24 | return x.encode() | |
25 | def maybe_chr(x): | |
26 | return x | |
27 | def maybe_ord(x): | |
28 | return x | |
29 | else: | |
30 | text_type = unicode # pylint: disable=unicode-builtin, undefined-variable | |
31 | binary_type = str | |
32 | string_types = ( | |
33 | basestring, # pylint: disable=basestring-builtin, undefined-variable | |
34 | ) | |
35 | unichr = unichr # pylint: disable=unichr-builtin | |
36 | def maybe_decode(x): | |
37 | return x | |
38 | def maybe_encode(x): | |
39 | return x | |
40 | def maybe_chr(x): | |
41 | return chr(x) | |
42 | def maybe_ord(x): | |
43 | return ord(x) | |
44 | ||
45 | ||
46 | def round_py2_compat(what): | |
47 | """ | |
48 | Python 2 and Python 3 use different rounding strategies in round(). This | |
49 | function ensures that results are python2/3 compatible and backward | |
50 | compatible with previous py2 releases | |
51 | :param what: float | |
52 | :return: rounded long | |
53 | """ | |
54 | d = Context( | |
55 | prec=len(str(long(what))), # round to integer with max precision | |
56 | rounding=decimal.ROUND_HALF_UP | |
57 | ).create_decimal(str(what)) # str(): python 2.6 compat | |
58 | return long(d) |
16 | 16 | |
17 | 17 | """Common DNSSEC-related functions and constants.""" |
18 | 18 | |
19 | import hashlib # used in make_ds() to avoid pycrypto dependency | |
19 | 20 | from io import BytesIO |
20 | 21 | import struct |
21 | 22 | import time |
27 | 28 | import dns.rdata |
28 | 29 | import dns.rdatatype |
29 | 30 | import dns.rdataclass |
30 | from ._compat import string_types | |
31 | 31 | |
32 | 32 | |
33 | 33 | class UnsupportedAlgorithm(dns.exception.DNSException): |
131 | 131 | """ |
132 | 132 | |
133 | 133 | rdata = _to_rdata(key, origin) |
134 | rdata = bytearray(rdata) | |
135 | 134 | if key.algorithm == RSAMD5: |
136 | 135 | return (rdata[-3] << 8) + rdata[-2] |
137 | 136 | else: |
161 | 160 | |
162 | 161 | Returns a ``dns.rdtypes.ANY.DS``. |
163 | 162 | """ |
164 | ||
165 | 163 | if algorithm.upper() == 'SHA1': |
166 | 164 | dsalg = 1 |
167 | hash = SHA1.new() | |
165 | dshash = hashlib.sha1() | |
168 | 166 | elif algorithm.upper() == 'SHA256': |
169 | 167 | dsalg = 2 |
170 | hash = SHA256.new() | |
168 | dshash = hashlib.sha256() | |
171 | 169 | else: |
172 | 170 | raise UnsupportedAlgorithm('unsupported algorithm "%s"' % algorithm) |
173 | 171 | |
174 | if isinstance(name, string_types): | |
172 | if isinstance(name, str): | |
175 | 173 | name = dns.name.from_text(name, origin) |
176 | hash.update(name.canonicalize().to_wire()) | |
177 | hash.update(_to_rdata(key, origin)) | |
178 | digest = hash.digest() | |
174 | dshash.update(name.canonicalize().to_wire()) | |
175 | dshash.update(_to_rdata(key, origin)) | |
176 | digest = dshash.digest() | |
179 | 177 | |
180 | 178 | dsrdata = struct.pack("!HBB", key_id(key), key.algorithm, dsalg) + digest |
181 | 179 | return dns.rdata.from_wire(dns.rdataclass.IN, dns.rdatatype.DS, dsrdata, 0, |
291 | 289 | in seconds since the UNIX epoch. The default is the current time. |
292 | 290 | """ |
293 | 291 | |
294 | if isinstance(origin, string_types): | |
292 | if isinstance(origin, str): | |
295 | 293 | origin = dns.name.from_text(origin, dns.name.root) |
296 | 294 | |
297 | 295 | candidate_keys = _find_candidate_keys(keys, rrsig) |
442 | 440 | in seconds since the UNIX epoch. The default is the current time. |
443 | 441 | """ |
444 | 442 | |
445 | if isinstance(origin, string_types): | |
443 | if isinstance(origin, str): | |
446 | 444 | origin = dns.name.from_text(origin, dns.name.root) |
447 | 445 | |
448 | 446 | if isinstance(rrset, tuple): |
19 | 19 | import dns.exception |
20 | 20 | import dns.name |
21 | 21 | import dns.resolver |
22 | from ._compat import string_types, maybe_decode | |
23 | 22 | |
24 | 23 | #: The public E.164 domain. |
25 | 24 | public_enum_domain = dns.name.from_text('e164.arpa.') |
74 | 73 | text = b''.join(dlabels) |
75 | 74 | if want_plus_prefix: |
76 | 75 | text = b'+' + text |
77 | return maybe_decode(text) | |
76 | return text.decode() | |
78 | 77 | |
79 | 78 | |
80 | 79 | def query(number, domains, resolver=None): |
94 | 93 | resolver = dns.resolver.get_default_resolver() |
95 | 94 | e_nx = dns.resolver.NXDOMAIN() |
96 | 95 | for domain in domains: |
97 | if isinstance(domain, string_types): | |
96 | if isinstance(domain, str): | |
98 | 97 | domain = dns.name.from_text(domain) |
99 | 98 | qname = dns.e164.from_e164(number, domain) |
100 | 99 | try: |
153 | 153 | return 1 |
154 | 154 | return -1 |
155 | 155 | |
156 | def __str__(self): | |
157 | return self.to_text() | |
156 | 158 | |
157 | 159 | class ECSOption(Option): |
158 | 160 | """EDNS Client Subnet (ECS, RFC7871)""" |
194 | 196 | self.addrdata = addrdata[:nbytes] |
195 | 197 | nbits = srclen % 8 |
196 | 198 | if nbits != 0: |
197 | last = struct.pack('B', ord(self.addrdata[-1:]) & (0xff << nbits)) | |
199 | last = struct.pack('B', | |
200 | ord(self.addrdata[-1:]) & (0xff << (8 - nbits))) | |
198 | 201 | self.addrdata = self.addrdata[:-1] + last |
199 | 202 | |
200 | 203 | def to_text(self): |
201 | 204 | return "ECS {}/{} scope/{}".format(self.address, self.srclen, |
202 | 205 | self.scopelen) |
206 | @staticmethod | |
207 | def from_text(text): | |
208 | """Convert a string into a `dns.edns.ECSOption` | |
209 | ||
210 | :param text: string | |
211 | :return: `dns.edns.ECSOption` | |
212 | ||
213 | Examples: | |
214 | ||
215 | >>> import dns.edns | |
216 | >>> | |
217 | >>> # basic example | |
218 | >>> dns.edns.ECSOption.from_text('1.2.3.4/24') | |
219 | >>> | |
220 | >>> # also understands scope | |
221 | >>> dns.edns.ECSOption.from_text('1.2.3.4/24/32') | |
222 | >>> | |
223 | >>> # IPv6 | |
224 | >>> dns.edns.ECSOption.from_text('2001:4b98::1/64/64') | |
225 | >>> | |
226 | >>> # it understands results from `dns.edns.ECSOption.to_text()` | |
227 | >>> dns.edns.ECSOption.from_text('ECS 1.2.3.4/24/32') | |
228 | """ | |
229 | optional_prefix = 'ECS' | |
230 | tokens = text.split() | |
231 | ecs_text = None | |
232 | if len(tokens) == 1: | |
233 | ecs_text = tokens[0] | |
234 | elif len(tokens) == 2: | |
235 | if tokens[0] != optional_prefix: | |
236 | raise ValueError('could not parse ECS from "{}"'.format(text)) | |
237 | ecs_text = tokens[1] | |
238 | else: | |
239 | raise ValueError('could not parse ECS from "{}"'.format(text)) | |
240 | n_slashes = ecs_text.count('/') | |
241 | if n_slashes == 1: | |
242 | address, srclen = ecs_text.split('/') | |
243 | scope = 0 | |
244 | elif n_slashes == 2: | |
245 | address, srclen, scope = ecs_text.split('/') | |
246 | else: | |
247 | raise ValueError('could not parse ECS from "{}"'.format(text)) | |
248 | try: | |
249 | scope = int(scope) | |
250 | except ValueError: | |
251 | raise ValueError('invalid scope "{}": scope must be an integer'.format(scope)) | |
252 | try: | |
253 | srclen = int(srclen) | |
254 | except ValueError: | |
255 | raise ValueError('invalid srclen "{}": srclen must be an integer'.format(srclen)) | |
256 | return ECSOption(address, srclen, scope) | |
203 | 257 | |
204 | 258 | def to_wire(self, file): |
205 | 259 | file.write(struct.pack('!H', self.family)) |
232 | 286 | return 1 |
233 | 287 | return -1 |
234 | 288 | |
289 | def __str__(self): | |
290 | return self.to_text() | |
291 | ||
235 | 292 | _type_to_class = { |
236 | 293 | ECS: ECSOption |
237 | 294 | } |
17 | 17 | import os |
18 | 18 | import random |
19 | 19 | import time |
20 | from ._compat import long, binary_type | |
21 | 20 | try: |
22 | 21 | import threading as _threading |
23 | 22 | except ImportError: |
96 | 95 | try: |
97 | 96 | self._maybe_seed() |
98 | 97 | if self.digest is None or self.next_byte == self.hash_len: |
99 | self.hash.update(binary_type(self.pool)) | |
98 | self.hash.update(bytes(self.pool)) | |
100 | 99 | self.digest = bytearray(self.hash.digest()) |
101 | 100 | self.stir(self.digest, True) |
102 | 101 | self.next_byte = 0 |
114 | 113 | |
115 | 114 | def random_between(self, first, last): |
116 | 115 | size = last - first + 1 |
117 | if size > long(4294967296): | |
116 | if size > 4294967296: | |
118 | 117 | raise ValueError('too big') |
119 | 118 | if size > 65536: |
120 | 119 | rand = self.random_32 |
121 | max = long(4294967295) | |
120 | max = 4294967295 | |
122 | 121 | elif size > 256: |
123 | 122 | rand = self.random_16 |
124 | 123 | max = 65535 |
0 | # Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license | |
1 | ||
2 | # Copyright (C) 2011 Nominum, Inc. | |
3 | # | |
4 | # Permission to use, copy, modify, and distribute this software and its | |
5 | # documentation for any purpose with or without fee is hereby granted, | |
6 | # provided that the above copyright notice and this permission notice | |
7 | # appear in all copies. | |
8 | # | |
9 | # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES | |
10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR | |
12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | |
15 | # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | ||
17 | """Hashing backwards compatibility wrapper""" | |
18 | ||
19 | import hashlib | |
20 | import warnings | |
21 | ||
22 | warnings.warn( | |
23 | "dns.hash module will be removed in future versions. Please use hashlib instead.", | |
24 | DeprecationWarning) | |
25 | ||
26 | hashes = {} | |
27 | hashes['MD5'] = hashlib.md5 | |
28 | hashes['SHA1'] = hashlib.sha1 | |
29 | hashes['SHA224'] = hashlib.sha224 | |
30 | hashes['SHA256'] = hashlib.sha256 | |
31 | hashes['SHA384'] = hashlib.sha384 | |
32 | hashes['SHA512'] = hashlib.sha512 | |
33 | ||
34 | ||
35 | def get(algorithm): | |
36 | return hashes[algorithm.upper()] |
20 | 20 | |
21 | 21 | import dns.ipv4 |
22 | 22 | import dns.ipv6 |
23 | ||
24 | from ._compat import maybe_ord | |
25 | 23 | |
26 | 24 | # We assume that AF_INET is always defined. |
27 | 25 | |
113 | 111 | """ |
114 | 112 | |
115 | 113 | try: |
116 | first = maybe_ord(dns.ipv4.inet_aton(text)[0]) | |
114 | first = dns.ipv4.inet_aton(text)[0] | |
117 | 115 | return first >= 224 and first <= 239 |
118 | 116 | except Exception: |
119 | 117 | try: |
120 | first = maybe_ord(dns.ipv6.inet_aton(text)[0]) | |
118 | first = dns.ipv6.inet_aton(text)[0] | |
121 | 119 | return first == 255 |
122 | 120 | except Exception: |
123 | 121 | raise ValueError |
19 | 19 | import struct |
20 | 20 | |
21 | 21 | import dns.exception |
22 | from ._compat import binary_type | |
23 | 22 | |
24 | 23 | def inet_ntoa(address): |
25 | 24 | """Convert an IPv4 address in binary form to text form. |
26 | 25 | |
27 | *address*, a ``binary``, the IPv4 address in binary form. | |
26 | *address*, a ``bytes``, the IPv4 address in binary form. | |
28 | 27 | |
29 | Returns a ``text``. | |
28 | Returns a ``str``. | |
30 | 29 | """ |
31 | 30 | |
32 | 31 | if len(address) != 4: |
33 | 32 | raise dns.exception.SyntaxError |
34 | if not isinstance(address, bytearray): | |
35 | address = bytearray(address) | |
36 | 33 | return ('%u.%u.%u.%u' % (address[0], address[1], |
37 | 34 | address[2], address[3])) |
38 | 35 | |
39 | 36 | def inet_aton(text): |
40 | 37 | """Convert an IPv4 address in text form to binary form. |
41 | 38 | |
42 | *text*, a ``text``, the IPv4 address in textual form. | |
39 | *text*, a ``str``, the IPv4 address in textual form. | |
43 | 40 | |
44 | Returns a ``binary``. | |
41 | Returns a ``bytes``. | |
45 | 42 | """ |
46 | 43 | |
47 | if not isinstance(text, binary_type): | |
44 | if not isinstance(text, bytes): | |
48 | 45 | text = text.encode() |
49 | 46 | parts = text.split(b'.') |
50 | 47 | if len(parts) != 4: |
56 | 53 | # No leading zeros |
57 | 54 | raise dns.exception.SyntaxError |
58 | 55 | try: |
59 | bytes = [int(part) for part in parts] | |
60 | return struct.pack('BBBB', *bytes) | |
56 | b = [int(part) for part in parts] | |
57 | return struct.pack('BBBB', *b) | |
61 | 58 | except: |
62 | 59 | raise dns.exception.SyntaxError |
21 | 21 | |
22 | 22 | import dns.exception |
23 | 23 | import dns.ipv4 |
24 | from ._compat import xrange, binary_type, maybe_decode | |
25 | 24 | |
26 | 25 | _leading_zero = re.compile(r'0+([0-9a-f]+)') |
27 | 26 | |
28 | 27 | def inet_ntoa(address): |
29 | 28 | """Convert an IPv6 address in binary form to text form. |
30 | 29 | |
31 | *address*, a ``binary``, the IPv6 address in binary form. | |
30 | *address*, a ``bytes``, the IPv6 address in binary form. | |
32 | 31 | |
33 | 32 | Raises ``ValueError`` if the address isn't 16 bytes long. |
34 | Returns a ``text``. | |
33 | Returns a ``str``. | |
35 | 34 | """ |
36 | 35 | |
37 | 36 | if len(address) != 16: |
41 | 40 | i = 0 |
42 | 41 | l = len(hex) |
43 | 42 | while i < l: |
44 | chunk = maybe_decode(hex[i : i + 4]) | |
43 | chunk = hex[i : i + 4].decode() | |
45 | 44 | # strip leading zeros. we do this with an re instead of |
46 | 45 | # with lstrip() because lstrip() didn't support chars until |
47 | 46 | # python 2.2.2 |
57 | 56 | best_len = 0 |
58 | 57 | start = -1 |
59 | 58 | last_was_zero = False |
60 | for i in xrange(8): | |
59 | for i in range(8): | |
61 | 60 | if chunks[i] != '0': |
62 | 61 | if last_was_zero: |
63 | 62 | end = i |
101 | 100 | |
102 | 101 | *text*, a ``text``, the IPv6 address in textual form. |
103 | 102 | |
104 | Returns a ``binary``. | |
103 | Returns a ``bytes``. | |
105 | 104 | """ |
106 | 105 | |
107 | 106 | # |
108 | 107 | # Our aim here is not something fast; we just want something that works. |
109 | 108 | # |
110 | if not isinstance(text, binary_type): | |
109 | if not isinstance(text, bytes): | |
111 | 110 | text = text.encode() |
112 | 111 | |
113 | 112 | if text == b'::': |
117 | 116 | # |
118 | 117 | m = _v4_ending.match(text) |
119 | 118 | if not m is None: |
120 | b = bytearray(dns.ipv4.inet_aton(m.group(2))) | |
119 | b = dns.ipv4.inet_aton(m.group(2)) | |
121 | 120 | text = (u"{}:{:02x}{:02x}:{:02x}{:02x}".format(m.group(1).decode(), |
122 | 121 | b[0], b[1], b[2], |
123 | 122 | b[3])).encode() |
146 | 145 | if seen_empty: |
147 | 146 | raise dns.exception.SyntaxError |
148 | 147 | seen_empty = True |
149 | for i in xrange(0, 8 - l + 1): | |
148 | for i in range(0, 8 - l + 1): | |
150 | 149 | canonical.append(b'0000') |
151 | 150 | else: |
152 | 151 | lc = len(c) |
172 | 171 | def is_mapped(address): |
173 | 172 | """Is the specified address a mapped IPv4 address? |
174 | 173 | |
175 | *address*, a ``binary`` is an IPv6 address in binary form. | |
174 | *address*, a ``bytes`` is an IPv6 address in binary form. | |
176 | 175 | |
177 | 176 | Returns a ``bool``. |
178 | 177 | """ |
37 | 37 | import dns.tsig |
38 | 38 | import dns.wiredata |
39 | 39 | |
40 | from ._compat import long, xrange, string_types | |
41 | ||
42 | 40 | |
43 | 41 | class ShortHeader(dns.exception.FormError): |
44 | 42 | """The DNS packet passed to from_wire() is too short.""" |
65 | 63 | |
66 | 64 | class UnknownTSIGKey(dns.exception.DNSException): |
67 | 65 | """A TSIG with an unknown key was received.""" |
66 | ||
67 | ||
68 | class Truncated(dns.exception.DNSException): | |
69 | """The truncated flag is set.""" | |
68 | 70 | |
69 | 71 | |
70 | 72 | #: The question section number |
130 | 132 | """ |
131 | 133 | |
132 | 134 | s = StringIO() |
133 | s.write(u'id %d\n' % self.id) | |
134 | s.write(u'opcode %s\n' % | |
135 | s.write('id %d\n' % self.id) | |
136 | s.write('opcode %s\n' % | |
135 | 137 | dns.opcode.to_text(dns.opcode.from_flags(self.flags))) |
136 | 138 | rc = dns.rcode.from_flags(self.flags, self.ednsflags) |
137 | s.write(u'rcode %s\n' % dns.rcode.to_text(rc)) | |
138 | s.write(u'flags %s\n' % dns.flags.to_text(self.flags)) | |
139 | s.write('rcode %s\n' % dns.rcode.to_text(rc)) | |
140 | s.write('flags %s\n' % dns.flags.to_text(self.flags)) | |
139 | 141 | if self.edns >= 0: |
140 | s.write(u'edns %s\n' % self.edns) | |
142 | s.write('edns %s\n' % self.edns) | |
141 | 143 | if self.ednsflags != 0: |
142 | s.write(u'eflags %s\n' % | |
144 | s.write('eflags %s\n' % | |
143 | 145 | dns.flags.edns_to_text(self.ednsflags)) |
144 | s.write(u'payload %d\n' % self.payload) | |
146 | s.write('payload %d\n' % self.payload) | |
145 | 147 | for opt in self.options: |
146 | s.write(u'option %s\n' % opt.to_text()) | |
148 | s.write('option %s\n' % opt.to_text()) | |
147 | 149 | is_update = dns.opcode.is_update(self.flags) |
148 | 150 | if is_update: |
149 | s.write(u';ZONE\n') | |
150 | else: | |
151 | s.write(u';QUESTION\n') | |
151 | s.write(';ZONE\n') | |
152 | else: | |
153 | s.write(';QUESTION\n') | |
152 | 154 | for rrset in self.question: |
153 | 155 | s.write(rrset.to_text(origin, relativize, **kw)) |
154 | s.write(u'\n') | |
156 | s.write('\n') | |
155 | 157 | if is_update: |
156 | s.write(u';PREREQ\n') | |
157 | else: | |
158 | s.write(u';ANSWER\n') | |
158 | s.write(';PREREQ\n') | |
159 | else: | |
160 | s.write(';ANSWER\n') | |
159 | 161 | for rrset in self.answer: |
160 | 162 | s.write(rrset.to_text(origin, relativize, **kw)) |
161 | s.write(u'\n') | |
163 | s.write('\n') | |
162 | 164 | if is_update: |
163 | s.write(u';UPDATE\n') | |
164 | else: | |
165 | s.write(u';AUTHORITY\n') | |
165 | s.write(';UPDATE\n') | |
166 | else: | |
167 | s.write(';AUTHORITY\n') | |
166 | 168 | for rrset in self.authority: |
167 | 169 | s.write(rrset.to_text(origin, relativize, **kw)) |
168 | s.write(u'\n') | |
169 | s.write(u';ADDITIONAL\n') | |
170 | s.write('\n') | |
171 | s.write(';ADDITIONAL\n') | |
170 | 172 | for rrset in self.additional: |
171 | 173 | s.write(rrset.to_text(origin, relativize, **kw)) |
172 | s.write(u'\n') | |
174 | s.write('\n') | |
173 | 175 | # |
174 | 176 | # We strip off the final \n so the caller can print the result without |
175 | 177 | # doing weird things to get around eccentricities in Python print |
471 | 473 | if keyname is None: |
472 | 474 | self.keyname = list(self.keyring.keys())[0] |
473 | 475 | else: |
474 | if isinstance(keyname, string_types): | |
476 | if isinstance(keyname, str): | |
475 | 477 | keyname = dns.name.from_text(keyname) |
476 | 478 | self.keyname = keyname |
477 | 479 | self.keyalgorithm = algorithm |
519 | 521 | options = [] |
520 | 522 | else: |
521 | 523 | # make sure the EDNS version in ednsflags agrees with edns |
522 | ednsflags &= long(0xFF00FFFF) | |
524 | ednsflags &= 0xFF00FFFF | |
523 | 525 | ednsflags |= (edns << 16) |
524 | 526 | if options is None: |
525 | 527 | options = [] |
560 | 562 | (value, evalue) = dns.rcode.to_flags(rcode) |
561 | 563 | self.flags &= 0xFFF0 |
562 | 564 | self.flags |= value |
563 | self.ednsflags &= long(0x00FFFFFF) | |
565 | self.ednsflags &= 0x00FFFFFF | |
564 | 566 | self.ednsflags |= evalue |
565 | 567 | if self.ednsflags != 0 and self.edns < 0: |
566 | 568 | self.edns = 0 |
616 | 618 | if self.updating and qcount > 1: |
617 | 619 | raise dns.exception.FormError |
618 | 620 | |
619 | for i in xrange(0, qcount): | |
621 | for i in range(0, qcount): | |
620 | 622 | (qname, used) = dns.name.from_wire(self.wire, self.current) |
621 | 623 | if self.message.origin is not None: |
622 | 624 | qname = qname.relativize(self.message.origin) |
644 | 646 | else: |
645 | 647 | force_unique = False |
646 | 648 | seen_opt = False |
647 | for i in xrange(0, count): | |
649 | for i in range(0, count): | |
648 | 650 | rr_start = self.current |
649 | 651 | (name, used) = dns.name.from_wire(self.wire, self.current) |
650 | 652 | absolute_name = name |
740 | 742 | (self.message.id, self.message.flags, qcount, ancount, |
741 | 743 | aucount, adcount) = struct.unpack('!HHHHHH', self.wire[:12]) |
742 | 744 | self.current = 12 |
745 | self.message.original_id = self.message.id | |
743 | 746 | if dns.opcode.is_update(self.message.flags): |
744 | 747 | self.updating = True |
748 | if self.message.flags & dns.flags.TC: | |
749 | raise Truncated | |
745 | 750 | self._get_question(qcount) |
746 | 751 | if self.question_only: |
747 | 752 | return |
804 | 809 | |
805 | 810 | Raises ``dns.message.BadTSIG`` if a TSIG record was not the last |
806 | 811 | record of the additional data section. |
812 | ||
813 | Raises ``dns.message.Truncated`` if the TC flag is set. | |
807 | 814 | |
808 | 815 | Returns a ``dns.message.Message``. |
809 | 816 | """ |
1040 | 1047 | Returns a ``dns.message.Message object`` |
1041 | 1048 | """ |
1042 | 1049 | |
1043 | str_type = string_types | |
1050 | str_type = str | |
1044 | 1051 | opts = 'rU' |
1045 | 1052 | |
1046 | 1053 | if isinstance(f, str_type): |
1098 | 1105 | Returns a ``dns.message.Message`` |
1099 | 1106 | """ |
1100 | 1107 | |
1101 | if isinstance(qname, string_types): | |
1108 | if isinstance(qname, str): | |
1102 | 1109 | qname = dns.name.from_text(qname) |
1103 | if isinstance(rdtype, string_types): | |
1110 | if isinstance(rdtype, str): | |
1104 | 1111 | rdtype = dns.rdatatype.from_text(rdtype) |
1105 | if isinstance(rdclass, string_types): | |
1112 | if isinstance(rdclass, str): | |
1106 | 1113 | rdclass = dns.rdataclass.from_text(rdclass) |
1107 | 1114 | m = Message() |
1108 | 1115 | m.flags |= dns.flags.RD |
31 | 31 | import dns.exception |
32 | 32 | import dns.wiredata |
33 | 33 | |
34 | from ._compat import long, binary_type, text_type, unichr, maybe_decode | |
35 | ||
36 | 34 | try: |
37 | 35 | maxint = sys.maxint # pylint: disable=sys-max-int |
38 | 36 | except AttributeError: |
109 | 107 | def __init__(self): |
110 | 108 | pass |
111 | 109 | |
110 | def is_idna(self, label): | |
111 | return label.lower().startswith(b'xn--') | |
112 | ||
112 | 113 | def encode(self, label): |
113 | 114 | raise NotImplementedError |
114 | 115 | |
115 | 116 | def decode(self, label): |
116 | # We do not apply any IDNA policy on decode; we just | |
117 | downcased = label.lower() | |
118 | if downcased.startswith(b'xn--'): | |
117 | # We do not apply any IDNA policy on decode. | |
118 | if self.is_idna(label): | |
119 | 119 | try: |
120 | label = downcased[4:].decode('punycode') | |
120 | label = label[4:].decode('punycode') | |
121 | 121 | except Exception as e: |
122 | 122 | raise IDNAException(idna_exception=e) |
123 | else: | |
124 | label = maybe_decode(label) | |
125 | return _escapify(label, True) | |
123 | return _escapify(label) | |
126 | 124 | |
127 | 125 | |
128 | 126 | class IDNA2003Codec(IDNACodec): |
154 | 152 | if not self.strict_decode: |
155 | 153 | return super(IDNA2003Codec, self).decode(label) |
156 | 154 | if label == b'': |
157 | return u'' | |
155 | return '' | |
158 | 156 | try: |
159 | return _escapify(encodings.idna.ToUnicode(label), True) | |
157 | return _escapify(encodings.idna.ToUnicode(label)) | |
160 | 158 | except Exception as e: |
161 | 159 | raise IDNAException(idna_exception=e) |
162 | 160 | |
194 | 192 | self.allow_pure_ascii = allow_pure_ascii |
195 | 193 | self.strict_decode = strict_decode |
196 | 194 | |
197 | def is_all_ascii(self, label): | |
198 | for c in label: | |
199 | if ord(c) > 0x7f: | |
200 | return False | |
201 | return True | |
202 | ||
203 | 195 | def encode(self, label): |
204 | 196 | if label == '': |
205 | 197 | return b'' |
206 | if self.allow_pure_ascii and self.is_all_ascii(label): | |
198 | if self.allow_pure_ascii and is_all_ascii(label): | |
207 | 199 | return label.encode('ascii') |
208 | 200 | if not have_idna_2008: |
209 | 201 | raise NoIDNA2008 |
218 | 210 | if not self.strict_decode: |
219 | 211 | return super(IDNA2008Codec, self).decode(label) |
220 | 212 | if label == b'': |
221 | return u'' | |
213 | return '' | |
222 | 214 | if not have_idna_2008: |
223 | 215 | raise NoIDNA2008 |
224 | 216 | try: |
225 | 217 | if self.uts_46: |
226 | 218 | label = idna.uts46_remap(label, False, False) |
227 | return _escapify(idna.ulabel(label), True) | |
219 | return _escapify(idna.ulabel(label)) | |
228 | 220 | except idna.IDNAError as e: |
229 | 221 | raise IDNAException(idna_exception=e) |
230 | 222 | |
231 | _escaped = bytearray(b'"().;\\@$') | |
223 | _escaped = b'"().;\\@$' | |
224 | _escaped_text = '"().;\\@$' | |
232 | 225 | |
233 | 226 | IDNA_2003_Practical = IDNA2003Codec(False) |
234 | 227 | IDNA_2003_Strict = IDNA2003Codec(True) |
239 | 232 | IDNA_2008_Transitional = IDNA2008Codec(True, True, False, False) |
240 | 233 | IDNA_2008 = IDNA_2008_Practical |
241 | 234 | |
242 | def _escapify(label, unicode_mode=False): | |
235 | def _escapify(label): | |
243 | 236 | """Escape the characters in label which need it. |
244 | @param unicode_mode: escapify only special and whitespace (<= 0x20) | |
245 | characters | |
246 | 237 | @returns: the escaped string |
247 | 238 | @rtype: string""" |
248 | if not unicode_mode: | |
239 | if isinstance(label, bytes): | |
240 | # Ordinary DNS label mode. Escape special characters and values | |
241 | # < 0x20 or > 0x7f. | |
249 | 242 | text = '' |
250 | if isinstance(label, text_type): | |
243 | if isinstance(label, str): | |
251 | 244 | label = label.encode() |
252 | for c in bytearray(label): | |
245 | for c in label: | |
253 | 246 | if c in _escaped: |
254 | 247 | text += '\\' + chr(c) |
255 | 248 | elif c > 0x20 and c < 0x7F: |
256 | 249 | text += chr(c) |
257 | 250 | else: |
258 | 251 | text += '\\%03d' % c |
259 | return text.encode() | |
260 | ||
261 | text = u'' | |
262 | if isinstance(label, binary_type): | |
263 | label = label.decode() | |
252 | return text | |
253 | ||
254 | # Unicode label mode. Escape only special characters and values < 0x20 | |
255 | text = '' | |
264 | 256 | for c in label: |
265 | if c > u'\x20' and c < u'\x7f': | |
257 | if c in _escaped_text: | |
258 | text += '\\' + c | |
259 | elif c <= '\x20': | |
260 | text += '\\%03d' % ord(c) | |
261 | else: | |
266 | 262 | text += c |
267 | else: | |
268 | if c >= u'\x7f': | |
269 | text += c | |
270 | else: | |
271 | text += u'\\%03d' % ord(c) | |
272 | 263 | return text |
273 | 264 | |
274 | 265 | def _validate_labels(labels): |
307 | 298 | |
308 | 299 | """ |
309 | 300 | |
310 | if isinstance(label, binary_type): | |
301 | if isinstance(label, bytes): | |
311 | 302 | return label |
312 | if isinstance(label, text_type): | |
303 | if isinstance(label, str): | |
313 | 304 | return label.encode() |
314 | 305 | raise ValueError |
315 | 306 | |
373 | 364 | Returns an ``int``. |
374 | 365 | """ |
375 | 366 | |
376 | h = long(0) | |
367 | h = 0 | |
377 | 368 | for label in self.labels: |
378 | for c in bytearray(label.lower()): | |
369 | for c in label.lower(): | |
379 | 370 | h += (h << 3) + c |
380 | return int(h % maxint) | |
371 | return h % maxint | |
381 | 372 | |
382 | 373 | def fullcompare(self, other): |
383 | 374 | """Compare two names, returning a 3-tuple |
543 | 534 | """ |
544 | 535 | |
545 | 536 | if len(self.labels) == 0: |
546 | return maybe_decode(b'@') | |
537 | return '@' | |
547 | 538 | if len(self.labels) == 1 and self.labels[0] == b'': |
548 | return maybe_decode(b'.') | |
539 | return '.' | |
549 | 540 | if omit_final_dot and self.is_absolute(): |
550 | 541 | l = self.labels[:-1] |
551 | 542 | else: |
552 | 543 | l = self.labels |
553 | s = b'.'.join(map(_escapify, l)) | |
554 | return maybe_decode(s) | |
544 | s = '.'.join(map(_escapify, l)) | |
545 | return s | |
555 | 546 | |
556 | 547 | def to_unicode(self, omit_final_dot=False, idna_codec=None): |
557 | 548 | """Convert name to Unicode text format. |
572 | 563 | """ |
573 | 564 | |
574 | 565 | if len(self.labels) == 0: |
575 | return u'@' | |
566 | return '@' | |
576 | 567 | if len(self.labels) == 1 and self.labels[0] == b'': |
577 | return u'.' | |
568 | return '.' | |
578 | 569 | if omit_final_dot and self.is_absolute(): |
579 | 570 | l = self.labels[:-1] |
580 | 571 | else: |
581 | 572 | l = self.labels |
582 | 573 | if idna_codec is None: |
583 | 574 | idna_codec = IDNA_2003_Practical |
584 | return u'.'.join([idna_codec.decode(x) for x in l]) | |
575 | return '.'.join([idna_codec.decode(x) for x in l]) | |
585 | 576 | |
586 | 577 | def to_digestable(self, origin=None): |
587 | 578 | """Convert name to a format suitable for digesting in hashes. |
812 | 803 | Returns a ``dns.name.Name``. |
813 | 804 | """ |
814 | 805 | |
815 | if not isinstance(text, text_type): | |
806 | if not isinstance(text, str): | |
816 | 807 | raise ValueError("input to from_unicode() must be a unicode string") |
817 | 808 | if not (origin is None or isinstance(origin, Name)): |
818 | 809 | raise ValueError("origin must be a Name or None") |
819 | 810 | labels = [] |
820 | label = u'' | |
811 | label = '' | |
821 | 812 | escaping = False |
822 | 813 | edigits = 0 |
823 | 814 | total = 0 |
824 | 815 | if idna_codec is None: |
825 | 816 | idna_codec = IDNA_2003 |
826 | if text == u'@': | |
827 | text = u'' | |
817 | if text == '@': | |
818 | text = '' | |
828 | 819 | if text: |
829 | if text == u'.': | |
820 | if text in ['.', '\u3002', '\uff0e', '\uff61']: | |
830 | 821 | return Name([b'']) # no Unicode "u" on this constant! |
831 | 822 | for c in text: |
832 | 823 | if escaping: |
845 | 836 | edigits += 1 |
846 | 837 | if edigits == 3: |
847 | 838 | escaping = False |
848 | label += unichr(total) | |
849 | elif c in [u'.', u'\u3002', u'\uff0e', u'\uff61']: | |
839 | label += chr(total) | |
840 | elif c in ['.', '\u3002', '\uff0e', '\uff61']: | |
850 | 841 | if len(label) == 0: |
851 | 842 | raise EmptyLabel |
852 | 843 | labels.append(idna_codec.encode(label)) |
853 | label = u'' | |
854 | elif c == u'\\': | |
844 | label = '' | |
845 | elif c == '\\': | |
855 | 846 | escaping = True |
856 | 847 | edigits = 0 |
857 | 848 | total = 0 |
868 | 859 | labels.extend(list(origin.labels)) |
869 | 860 | return Name(labels) |
870 | 861 | |
862 | def is_all_ascii(text): | |
863 | for c in text: | |
864 | if ord(c) > 0x7f: | |
865 | return False | |
866 | return True | |
871 | 867 | |
872 | 868 | def from_text(text, origin=root, idna_codec=None): |
873 | 869 | """Convert text into a Name object. |
884 | 880 | Returns a ``dns.name.Name``. |
885 | 881 | """ |
886 | 882 | |
887 | if isinstance(text, text_type): | |
888 | return from_unicode(text, origin, idna_codec) | |
889 | if not isinstance(text, binary_type): | |
883 | if isinstance(text, str): | |
884 | if not is_all_ascii(text): | |
885 | # Some codepoint in the input text is > 127, so IDNA applies. | |
886 | return from_unicode(text, origin, idna_codec) | |
887 | # The input is all ASCII, so treat this like an ordinary non-IDNA | |
888 | # domain name. Note that "all ASCII" is about the input text, | |
889 | # not the codepoints in the domain name. E.g. if text has value | |
890 | # | |
891 | # r'\150\151\152\153\154\155\156\157\158\159' | |
892 | # | |
893 | # then it's still "all ASCII" even though the domain name has | |
894 | # codepoints > 127. | |
895 | text = text.encode('ascii') | |
896 | if not isinstance(text, bytes): | |
890 | 897 | raise ValueError("input to from_text() must be a string") |
891 | 898 | if not (origin is None or isinstance(origin, Name)): |
892 | 899 | raise ValueError("origin must be a Name or None") |
900 | 907 | if text: |
901 | 908 | if text == b'.': |
902 | 909 | return Name([b'']) |
903 | for c in bytearray(text): | |
910 | for c in text: | |
904 | 911 | byte_ = struct.pack('!B', c) |
905 | 912 | if escaping: |
906 | 913 | if edigits == 0: |
960 | 967 | which were consumed reading it. |
961 | 968 | """ |
962 | 969 | |
963 | if not isinstance(message, binary_type): | |
970 | if not isinstance(message, bytes): | |
964 | 971 | raise ValueError("input to from_wire() must be a byte string") |
965 | 972 | message = dns.wiredata.maybe_wrap(message) |
966 | 973 | labels = [] |
26 | 26 | |
27 | 27 | """DNS name dictionary""" |
28 | 28 | |
29 | import collections | |
29 | try: | |
30 | from collections.abc import MutableMapping | |
31 | except ImportError: | |
32 | from collections import MutableMapping | |
30 | 33 | import dns.name |
31 | from ._compat import xrange | |
32 | 34 | |
33 | 35 | |
34 | class NameDict(collections.MutableMapping): | |
36 | class NameDict(MutableMapping): | |
35 | 37 | """A dictionary whose keys are dns.name.Name objects. |
36 | 38 | |
37 | 39 | In addition to being like a regular Python dictionary, this |
99 | 101 | depth = len(name) |
100 | 102 | if depth > self.max_depth: |
101 | 103 | depth = self.max_depth |
102 | for i in xrange(-depth, 0): | |
104 | for i in range(-depth, 0): | |
103 | 105 | n = dns.name.Name(name[i:]) |
104 | 106 | if n in self: |
105 | 107 | return (n, self[n]) |
48 | 48 | for rds in self.rdatasets: |
49 | 49 | if len(rds) > 0: |
50 | 50 | s.write(rds.to_text(name, **kw)) |
51 | s.write(u'\n') | |
51 | s.write('\n') | |
52 | 52 | return s.getvalue()[:-1] |
53 | 53 | |
54 | 54 | def __repr__(self): |
19 | 19 | from __future__ import generators |
20 | 20 | |
21 | 21 | import errno |
22 | import os | |
22 | 23 | import select |
23 | 24 | import socket |
24 | 25 | import struct |
32 | 33 | import dns.rcode |
33 | 34 | import dns.rdataclass |
34 | 35 | import dns.rdatatype |
35 | from ._compat import long, string_types, PY3 | |
36 | ||
37 | if PY3: | |
38 | select_error = OSError | |
39 | else: | |
40 | select_error = select.error | |
36 | ||
37 | try: | |
38 | import ssl | |
39 | except ImportError: | |
40 | class ssl(object): | |
41 | class WantReadException(Exception): | |
42 | pass | |
43 | class WantWriteException(Exception): | |
44 | pass | |
45 | class SSLSocket(object): | |
46 | pass | |
47 | def create_default_context(self, *args, **kwargs): | |
48 | raise Exception('no ssl support') | |
41 | 49 | |
42 | 50 | # Function used to create a socket. Can be overridden if needed in special |
43 | 51 | # situations. |
86 | 94 | pollable.register(fd, event_mask) |
87 | 95 | |
88 | 96 | if timeout: |
89 | event_list = pollable.poll(long(timeout * 1000)) | |
97 | event_list = pollable.poll(timeout * 1000) | |
90 | 98 | else: |
91 | 99 | event_list = pollable.poll() |
92 | 100 | |
127 | 135 | if timeout <= 0.0: |
128 | 136 | raise dns.exception.Timeout |
129 | 137 | try: |
138 | if isinstance(fd, ssl.SSLSocket) and readable and fd.pending() > 0: | |
139 | return True | |
130 | 140 | if not _polling_backend(fd, readable, writable, error, timeout): |
131 | 141 | raise dns.exception.Timeout |
132 | except select_error as e: | |
142 | except OSError as e: | |
133 | 143 | if e.args[0] != errno.EINTR: |
134 | 144 | raise e |
135 | 145 | done = True |
343 | 353 | s = b'' |
344 | 354 | while count > 0: |
345 | 355 | _wait_for_readable(sock, expiration) |
346 | n = sock.recv(count) | |
356 | try: | |
357 | n = sock.recv(count) | |
358 | except ssl.SSLWantReadError: | |
359 | continue | |
360 | except ssl.SSLWantWriteError: | |
361 | _wait_for_writable(sock, expiration) | |
362 | continue | |
347 | 363 | if n == b'': |
348 | 364 | raise EOFError |
349 | 365 | count = count - len(n) |
360 | 376 | l = len(data) |
361 | 377 | while current < l: |
362 | 378 | _wait_for_writable(sock, expiration) |
363 | current += sock.send(data[current:]) | |
379 | try: | |
380 | current += sock.send(data[current:]) | |
381 | except ssl.SSLWantReadError: | |
382 | _wait_for_readable(sock, expiration) | |
383 | continue | |
384 | except ssl.SSLWantWriteError: | |
385 | continue | |
364 | 386 | |
365 | 387 | |
366 | 388 | def send_tcp(sock, what, expiration=None): |
424 | 446 | ignore_trailing=ignore_trailing) |
425 | 447 | return (r, received_time) |
426 | 448 | |
427 | def _connect(s, address): | |
449 | def _connect(s, address, expiration): | |
428 | 450 | try: |
429 | 451 | s.connect(address) |
430 | 452 | except socket.error: |
436 | 458 | v_err = v[0] |
437 | 459 | if v_err not in [errno.EINPROGRESS, errno.EWOULDBLOCK, errno.EALREADY]: |
438 | 460 | raise v |
461 | _wait_for_writable(s, expiration) | |
462 | err = s.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) | |
463 | if err != 0: | |
464 | raise OSError(err, os.strerror(err)) from None | |
439 | 465 | |
440 | 466 | |
441 | 467 | def tcp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, |
484 | 510 | begin_time = time.time() |
485 | 511 | if source is not None: |
486 | 512 | s.bind(source) |
487 | _connect(s, destination) | |
513 | _connect(s, destination, expiration) | |
488 | 514 | send_tcp(s, wire, expiration) |
489 | 515 | (r, received_time) = receive_tcp(s, expiration, one_rr_per_rrset, |
490 | 516 | q.keyring, q.mac, ignore_trailing) |
500 | 526 | return r |
501 | 527 | |
502 | 528 | |
529 | def tls(q, where, timeout=None, port=853, af=None, source=None, source_port=0, | |
530 | one_rr_per_rrset=False, ignore_trailing=False, | |
531 | ssl_context=None, server_hostname=None): | |
532 | """Return the response obtained after sending a query via TLS. | |
533 | ||
534 | *q*, a ``dns.message.Message``, the query to send | |
535 | ||
536 | *where*, a ``text`` containing an IPv4 or IPv6 address, where | |
537 | to send the message. | |
538 | ||
539 | *timeout*, a ``float`` or ``None``, the number of seconds to wait before the | |
540 | query times out. If ``None``, the default, wait forever. | |
541 | ||
542 | *port*, an ``int``, the port send the message to. The default is 853. | |
543 | ||
544 | *af*, an ``int``, the address family to use. The default is ``None``, | |
545 | which causes the address family to use to be inferred from the form of | |
546 | *where*. If the inference attempt fails, AF_INET is used. This | |
547 | parameter is historical; you need never set it. | |
548 | ||
549 | *source*, a ``text`` containing an IPv4 or IPv6 address, specifying | |
550 | the source address. The default is the wildcard address. | |
551 | ||
552 | *source_port*, an ``int``, the port from which to send the message. | |
553 | The default is 0. | |
554 | ||
555 | *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own | |
556 | RRset. | |
557 | ||
558 | *ignore_trailing*, a ``bool``. If ``True``, ignore trailing | |
559 | junk at end of the received message. | |
560 | ||
561 | *ssl_context*, an ``ssl.SSLContext``, the context to use when establishing | |
562 | a TLS connection. If ``None``, the default, creates one with the default | |
563 | configuration. | |
564 | ||
565 | *server_hostname*, a ``text`` containing the server's hostname. The | |
566 | default is ``None``, which means that no hostname is known, and if an | |
567 | SSL context is created, hostname checking will be disabled. | |
568 | ||
569 | Returns a ``dns.message.Message``. | |
570 | """ | |
571 | ||
572 | wire = q.to_wire() | |
573 | (af, destination, source) = _destination_and_source(af, where, port, | |
574 | source, source_port) | |
575 | s = socket_factory(af, socket.SOCK_STREAM, 0) | |
576 | begin_time = None | |
577 | received_time = None | |
578 | try: | |
579 | expiration = _compute_expiration(timeout) | |
580 | s.setblocking(0) | |
581 | begin_time = time.time() | |
582 | if source is not None: | |
583 | s.bind(source) | |
584 | _connect(s, destination, expiration) | |
585 | if ssl_context is None: | |
586 | ssl_context = ssl.create_default_context() | |
587 | if server_hostname is None: | |
588 | ssl_context.check_hostname = False | |
589 | s = ssl_context.wrap_socket(s, do_handshake_on_connect=False, | |
590 | server_hostname=server_hostname) | |
591 | while True: | |
592 | try: | |
593 | s.do_handshake() | |
594 | break | |
595 | except ssl.SSLWantReadError: | |
596 | _wait_for_readable(s, expiration) | |
597 | except ssl.SSLWantWriteError: | |
598 | _wait_for_writable(s, expiration) | |
599 | send_tcp(s, wire, expiration) | |
600 | (r, received_time) = receive_tcp(s, expiration, one_rr_per_rrset, | |
601 | q.keyring, q.mac, ignore_trailing) | |
602 | finally: | |
603 | if begin_time is None or received_time is None: | |
604 | response_time = 0 | |
605 | else: | |
606 | response_time = received_time - begin_time | |
607 | s.close() | |
608 | r.time = response_time | |
609 | if not q.is_response(r): | |
610 | raise BadResponse | |
611 | return r | |
612 | ||
613 | ||
503 | 614 | def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN, |
504 | 615 | timeout=None, port=53, keyring=None, keyname=None, relativize=True, |
505 | 616 | af=None, lifetime=None, source=None, source_port=0, serial=0, |
561 | 672 | Returns a generator of ``dns.message.Message`` objects. |
562 | 673 | """ |
563 | 674 | |
564 | if isinstance(zone, string_types): | |
675 | if isinstance(zone, str): | |
565 | 676 | zone = dns.name.from_text(zone) |
566 | if isinstance(rdtype, string_types): | |
677 | if isinstance(rdtype, str): | |
567 | 678 | rdtype = dns.rdatatype.from_text(rdtype) |
568 | 679 | q = dns.message.make_query(zone, rdtype, rdclass) |
569 | 680 | if rdtype == dns.rdatatype.IXFR: |
585 | 696 | if source is not None: |
586 | 697 | s.bind(source) |
587 | 698 | expiration = _compute_expiration(lifetime) |
588 | _connect(s, destination) | |
699 | _connect(s, destination, expiration) | |
589 | 700 | l = len(wire) |
590 | 701 | if use_udp: |
591 | 702 | _wait_for_writable(s, expiration) |
607 | 718 | first = True |
608 | 719 | while not done: |
609 | 720 | mexpiration = _compute_expiration(timeout) |
610 | if mexpiration is None or mexpiration > expiration: | |
721 | if mexpiration is None or \ | |
722 | (expiration is not None and mexpiration > expiration): | |
611 | 723 | mexpiration = expiration |
612 | 724 | if use_udp: |
613 | 725 | _wait_for_readable(s, expiration) |
0 | 0 | from typing import Optional, Union, Dict, Generator, Any |
1 | from . import message, tsig, rdatatype, rdataclass, name, message | |
2 | def tcp(q : message.Message, where : str, timeout : float = None, port=53, af : Optional[int] = None, source : Optional[str] = None, source_port : int = 0, | |
3 | one_rr_per_rrset=False) -> message.Message: | |
1 | from . import tsig, rdatatype, rdataclass, name, message | |
2 | ||
3 | try: | |
4 | import ssl | |
5 | except ImportError: | |
6 | class ssl(object): | |
7 | SSLContext = {} | |
8 | ||
9 | def tcp(q : message.Message, where : str, timeout : float = None, port=53, af : Optional[int] = None, source : Optional[str] = None, source_port : Optional[int] = 0, | |
10 | one_rr_per_rrset : Optional[bool] = False, ignore_trailing : Optional[bool] = False) -> message.Message: | |
4 | 11 | pass |
5 | 12 | |
6 | 13 | def xfr(where : None, zone : Union[name.Name,str], rdtype=rdatatype.AXFR, rdclass=rdataclass.IN, |
7 | 14 | timeout : Optional[float] =None, port=53, keyring : Optional[Dict[name.Name, bytes]] =None, keyname : Union[str,name.Name]=None, relativize=True, |
8 | 15 | af : Optional[int] =None, lifetime : Optional[float]=None, source : Optional[str] =None, source_port=0, serial=0, |
9 | use_udp=False, keyalgorithm=tsig.default_algorithm) -> Generator[Any,Any,message.Message]: | |
16 | use_udp : Optional[bool] = False, keyalgorithm=tsig.default_algorithm) -> Generator[Any,Any,message.Message]: | |
10 | 17 | pass |
11 | 18 | |
12 | def udp(q : message.Message, where : str, timeout : Optional[float] = None, port=53, af : Optional[int] = None, source : Optional[str] = None, source_port=0, | |
13 | ignore_unexpected=False, one_rr_per_rrset=False) -> message.Message: | |
14 | ... | |
19 | def udp(q : message.Message, where : str, timeout : Optional[float] = None, port=53, af : Optional[int] = None, source : Optional[str] = None, source_port : Optional[int] = 0, | |
20 | ignore_unexpected : Optional[bool] = False, one_rr_per_rrset : Optional[bool] = False, ignore_trailing : Optional[bool] = False) -> message.Message: | |
21 | pass | |
22 | ||
23 | def tls(q : message.Message, where : str, timeout : Optional[float] = None, port=53, af : Optional[int] = None, source : Optional[str] = None, source_port : Optional[int] = 0, | |
24 | one_rr_per_rrset : Optional[bool] = False, ignore_trailing : Optional[bool] = False, ssl_context: Optional[ssl.SSLContext] = None, server_hostname: Optional[str] = None) -> message.Message: | |
25 | pass |
17 | 17 | """DNS Result Codes.""" |
18 | 18 | |
19 | 19 | import dns.exception |
20 | from ._compat import long | |
21 | 20 | |
22 | 21 | #: No error |
23 | 22 | NOERROR = 0 |
121 | 120 | if value < 0 or value > 4095: |
122 | 121 | raise ValueError('rcode must be >= 0 and <= 4095') |
123 | 122 | v = value & 0xf |
124 | ev = long(value & 0xff0) << 20 | |
123 | ev = (value & 0xff0) << 20 | |
125 | 124 | return (v, ev) |
126 | 125 | |
127 | 126 |
26 | 26 | import dns.rdatatype |
27 | 27 | import dns.tokenizer |
28 | 28 | import dns.wiredata |
29 | from ._compat import xrange, string_types, text_type | |
30 | 29 | |
31 | 30 | try: |
32 | 31 | import threading as _threading |
59 | 58 | for i |
60 | 59 | in range(0, len(line), chunksize)]).decode() |
61 | 60 | |
62 | __escaped = bytearray(b'"\\') | |
61 | __escaped = b'"\\' | |
63 | 62 | |
64 | 63 | def _escapify(qstring): |
65 | 64 | """Escape the characters in a quoted string which need it.""" |
66 | 65 | |
67 | if isinstance(qstring, text_type): | |
66 | if isinstance(qstring, str): | |
68 | 67 | qstring = qstring.encode() |
69 | 68 | if not isinstance(qstring, bytearray): |
70 | 69 | qstring = bytearray(qstring) |
85 | 84 | return the bitmap that contains all the bytes less than that index. |
86 | 85 | """ |
87 | 86 | |
88 | for i in xrange(len(what) - 1, -1, -1): | |
87 | for i in range(len(what) - 1, -1, -1): | |
89 | 88 | if what[i] != 0: |
90 | 89 | return what[0: i + 1] |
91 | 90 | return what[0:1] |
369 | 368 | Returns an instance of the chosen Rdata subclass. |
370 | 369 | """ |
371 | 370 | |
372 | if isinstance(tok, string_types): | |
371 | if isinstance(tok, str): | |
373 | 372 | tok = dns.tokenizer.Tokenizer(tok) |
374 | 373 | cls = get_rdata_class(rdclass, rdtype) |
375 | 374 | if cls != GenericRdata: |
25 | 25 | import dns.rdataclass |
26 | 26 | import dns.rdata |
27 | 27 | import dns.set |
28 | from ._compat import string_types | |
29 | 28 | |
30 | 29 | # define SimpleSet here for backwards compatibility |
31 | 30 | SimpleSet = dns.set.Set |
205 | 204 | # some dynamic updates, so we don't need to print out the TTL |
206 | 205 | # (which is meaningless anyway). |
207 | 206 | # |
208 | s.write(u'{}{}{} {}\n'.format(ntext, pad, | |
209 | dns.rdataclass.to_text(rdclass), | |
210 | dns.rdatatype.to_text(self.rdtype))) | |
207 | s.write('{}{}{} {}\n'.format(ntext, pad, | |
208 | dns.rdataclass.to_text(rdclass), | |
209 | dns.rdatatype.to_text(self.rdtype))) | |
211 | 210 | else: |
212 | 211 | for rd in self: |
213 | s.write(u'%s%s%d %s %s %s\n' % | |
212 | s.write('%s%s%d %s %s %s\n' % | |
214 | 213 | (ntext, pad, self.ttl, dns.rdataclass.to_text(rdclass), |
215 | 214 | dns.rdatatype.to_text(self.rdtype), |
216 | 215 | rd.to_text(origin=origin, relativize=relativize, |
296 | 295 | Returns a ``dns.rdataset.Rdataset`` object. |
297 | 296 | """ |
298 | 297 | |
299 | if isinstance(rdclass, string_types): | |
298 | if isinstance(rdclass, str): | |
300 | 299 | rdclass = dns.rdataclass.from_text(rdclass) |
301 | if isinstance(rdtype, string_types): | |
300 | if isinstance(rdtype, str): | |
302 | 301 | rdtype = dns.rdatatype.from_text(rdtype) |
303 | 302 | r = Rdataset(rdclass, rdtype) |
304 | 303 | r.update_ttl(ttl) |
70 | 70 | NSEC3PARAM = 51 |
71 | 71 | TLSA = 52 |
72 | 72 | HIP = 55 |
73 | NINFO = 56 | |
73 | 74 | CDS = 59 |
74 | 75 | CDNSKEY = 60 |
75 | 76 | OPENPGPKEY = 61 |
142 | 143 | 'NSEC3PARAM': NSEC3PARAM, |
143 | 144 | 'TLSA': TLSA, |
144 | 145 | 'HIP': HIP, |
146 | 'NINFO': NINFO, | |
145 | 147 | 'CDS': CDS, |
146 | 148 | 'CDNSKEY': CDNSKEY, |
147 | 149 | 'OPENPGPKEY': OPENPGPKEY, |
169 | 171 | # would cause the mapping not to be true inverse. |
170 | 172 | |
171 | 173 | _by_value = {y: x for x, y in _by_text.items()} |
174 | # Render type 0 as "TYPE0" not "NONE", as NONE is a dnspython-ism and not | |
175 | # an official mnemonic. | |
176 | _by_value[0] = 'TYPE0' | |
172 | 177 | |
173 | 178 | _metatypes = { |
174 | 179 | OPT: True |
20 | 20 | import dns.rdata |
21 | 21 | import dns.rdatatype |
22 | 22 | import dns.name |
23 | from dns._compat import xrange | |
24 | 23 | |
25 | 24 | class CSYNC(dns.rdata.Rdata): |
26 | 25 | |
45 | 44 | text = '' |
46 | 45 | for (window, bitmap) in self.windows: |
47 | 46 | bits = [] |
48 | for i in xrange(0, len(bitmap)): | |
49 | byte = bitmap[i] | |
50 | for j in xrange(0, 8): | |
47 | for (i, byte) in enumerate(bitmap): | |
48 | for j in range(0, 8): | |
51 | 49 | if byte & (0x80 >> j): |
52 | 50 | bits.append(dns.rdatatype.to_text(window * 256 + |
53 | 51 | i * 8 + j)) |
19 | 19 | import dns.exception |
20 | 20 | import dns.rdata |
21 | 21 | import dns.tokenizer |
22 | from dns._compat import long, text_type | |
23 | 22 | |
24 | 23 | |
25 | 24 | def _validate_float_string(what): |
37 | 36 | |
38 | 37 | |
39 | 38 | def _sanitize(value): |
40 | if isinstance(value, text_type): | |
39 | if isinstance(value, str): | |
41 | 40 | return value.encode() |
42 | 41 | return value |
43 | 42 | |
59 | 58 | def __init__(self, rdclass, rdtype, latitude, longitude, altitude): |
60 | 59 | super(GPOS, self).__init__(rdclass, rdtype) |
61 | 60 | if isinstance(latitude, float) or \ |
62 | isinstance(latitude, int) or \ | |
63 | isinstance(latitude, long): | |
61 | isinstance(latitude, int): | |
64 | 62 | latitude = str(latitude) |
65 | 63 | if isinstance(longitude, float) or \ |
66 | isinstance(longitude, int) or \ | |
67 | isinstance(longitude, long): | |
64 | isinstance(longitude, int): | |
68 | 65 | longitude = str(longitude) |
69 | 66 | if isinstance(altitude, float) or \ |
70 | isinstance(altitude, int) or \ | |
71 | isinstance(altitude, long): | |
67 | isinstance(altitude, int): | |
72 | 68 | altitude = str(altitude) |
73 | 69 | latitude = _sanitize(latitude) |
74 | 70 | longitude = _sanitize(longitude) |
19 | 19 | import dns.exception |
20 | 20 | import dns.rdata |
21 | 21 | import dns.tokenizer |
22 | from dns._compat import text_type | |
23 | 22 | |
24 | 23 | |
25 | 24 | class HINFO(dns.rdata.Rdata): |
36 | 35 | |
37 | 36 | def __init__(self, rdclass, rdtype, cpu, os): |
38 | 37 | super(HINFO, self).__init__(rdclass, rdtype) |
39 | if isinstance(cpu, text_type): | |
38 | if isinstance(cpu, str): | |
40 | 39 | self.cpu = cpu.encode() |
41 | 40 | else: |
42 | 41 | self.cpu = cpu |
43 | if isinstance(os, text_type): | |
42 | if isinstance(os, str): | |
44 | 43 | self.os = os.encode() |
45 | 44 | else: |
46 | 45 | self.os = os |
49 | 49 | def to_text(self, origin=None, relativize=True, **kw): |
50 | 50 | hit = binascii.hexlify(self.hit).decode() |
51 | 51 | key = base64.b64encode(self.key).replace(b'\n', b'').decode() |
52 | text = u'' | |
52 | text = '' | |
53 | 53 | servers = [] |
54 | 54 | for server in self.servers: |
55 | 55 | servers.append(server.choose_relativity(origin, relativize)) |
56 | 56 | if len(servers) > 0: |
57 | text += (u' ' + u' '.join((x.to_unicode() for x in servers))) | |
58 | return u'%u %s %s%s' % (self.algorithm, hit, key, text) | |
57 | text += (' ' + ' '.join((x.to_unicode() for x in servers))) | |
58 | return '%u %s %s%s' % (self.algorithm, hit, key, text) | |
59 | 59 | |
60 | 60 | @classmethod |
61 | 61 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): |
19 | 19 | import dns.exception |
20 | 20 | import dns.rdata |
21 | 21 | import dns.tokenizer |
22 | from dns._compat import text_type | |
23 | 22 | |
24 | 23 | |
25 | 24 | class ISDN(dns.rdata.Rdata): |
36 | 35 | |
37 | 36 | def __init__(self, rdclass, rdtype, address, subaddress): |
38 | 37 | super(ISDN, self).__init__(rdclass, rdtype) |
39 | if isinstance(address, text_type): | |
38 | if isinstance(address, str): | |
40 | 39 | self.address = address.encode() |
41 | 40 | else: |
42 | 41 | self.address = address |
43 | if isinstance(address, text_type): | |
42 | if isinstance(address, str): | |
44 | 43 | self.subaddress = subaddress.encode() |
45 | 44 | else: |
46 | 45 | self.subaddress = subaddress |
20 | 20 | |
21 | 21 | import dns.exception |
22 | 22 | import dns.rdata |
23 | from dns._compat import long, xrange, round_py2_compat | |
24 | ||
25 | ||
26 | _pows = tuple(long(10**i) for i in range(0, 11)) | |
23 | ||
24 | ||
25 | _pows = tuple(10**i for i in range(0, 11)) | |
27 | 26 | |
28 | 27 | # default values are in centimeters |
29 | 28 | _default_size = 100.0 |
35 | 34 | if what == 0: |
36 | 35 | return 0 |
37 | 36 | exp = None |
38 | for i in xrange(len(_pows)): | |
39 | if what // _pows[i] == long(0): | |
37 | for (i, pow) in enumerate(_pows): | |
38 | if what // pow == 0: | |
40 | 39 | exp = i - 1 |
41 | 40 | break |
42 | 41 | if exp is None or exp < 0: |
50 | 49 | what *= -1 |
51 | 50 | else: |
52 | 51 | sign = 1 |
53 | what = round_py2_compat(what * 3600000) | |
52 | what = round(what * 3600000) # pylint: disable=round-builtin | |
54 | 53 | degrees = int(what // 3600000) |
55 | 54 | what -= degrees * 3600000 |
56 | 55 | minutes = int(what // 60000) |
70 | 69 | |
71 | 70 | |
72 | 71 | def _encode_size(what, desc): |
73 | what = long(what) | |
72 | what = int(what) | |
74 | 73 | exponent = _exponent_of(what, desc) & 0xF |
75 | 74 | base = what // pow(10, exponent) & 0xF |
76 | 75 | return base * 16 + exponent |
83 | 82 | base = (what & 0xF0) >> 4 |
84 | 83 | if base > 9: |
85 | 84 | raise dns.exception.SyntaxError("bad %s base" % desc) |
86 | return long(base) * pow(10, exponent) | |
85 | return base * pow(10, exponent) | |
87 | 86 | |
88 | 87 | |
89 | 88 | class LOC(dns.rdata.Rdata): |
121 | 120 | and vertical precision are specified in centimeters.""" |
122 | 121 | |
123 | 122 | super(LOC, self).__init__(rdclass, rdtype) |
124 | if isinstance(latitude, int) or isinstance(latitude, long): | |
123 | if isinstance(latitude, int): | |
125 | 124 | latitude = float(latitude) |
126 | 125 | if isinstance(latitude, float): |
127 | 126 | latitude = _float_to_tuple(latitude) |
128 | 127 | self.latitude = latitude |
129 | if isinstance(longitude, int) or isinstance(longitude, long): | |
128 | if isinstance(longitude, int): | |
130 | 129 | longitude = float(longitude) |
131 | 130 | if isinstance(longitude, float): |
132 | 131 | longitude = _float_to_tuple(longitude) |
270 | 269 | self.latitude[1] * 60000 + |
271 | 270 | self.latitude[2] * 1000 + |
272 | 271 | self.latitude[3]) * self.latitude[4] |
273 | latitude = long(0x80000000) + milliseconds | |
272 | latitude = 0x80000000 + milliseconds | |
274 | 273 | milliseconds = (self.longitude[0] * 3600000 + |
275 | 274 | self.longitude[1] * 60000 + |
276 | 275 | self.longitude[2] * 1000 + |
277 | 276 | self.longitude[3]) * self.longitude[4] |
278 | longitude = long(0x80000000) + milliseconds | |
279 | altitude = long(self.altitude) + long(10000000) | |
277 | longitude = 0x80000000 + milliseconds | |
278 | altitude = int(self.altitude) + 10000000 | |
280 | 279 | size = _encode_size(self.size, "size") |
281 | 280 | hprec = _encode_size(self.horizontal_precision, "horizontal precision") |
282 | 281 | vprec = _encode_size(self.vertical_precision, "vertical precision") |
288 | 287 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): |
289 | 288 | (version, size, hprec, vprec, latitude, longitude, altitude) = \ |
290 | 289 | struct.unpack("!BBBBIII", wire[current: current + rdlen]) |
291 | if latitude > long(0x80000000): | |
292 | latitude = float(latitude - long(0x80000000)) / 3600000 | |
290 | if latitude > 0x80000000: | |
291 | latitude = float(latitude - 0x80000000) / 3600000 | |
293 | 292 | else: |
294 | latitude = -1 * float(long(0x80000000) - latitude) / 3600000 | |
293 | latitude = -1 * float(0x80000000 - latitude) / 3600000 | |
295 | 294 | if latitude < -90.0 or latitude > 90.0: |
296 | 295 | raise dns.exception.FormError("bad latitude") |
297 | if longitude > long(0x80000000): | |
298 | longitude = float(longitude - long(0x80000000)) / 3600000 | |
296 | if longitude > 0x80000000: | |
297 | longitude = float(longitude - 0x80000000) / 3600000 | |
299 | 298 | else: |
300 | longitude = -1 * float(long(0x80000000) - longitude) / 3600000 | |
299 | longitude = -1 * float(0x80000000 - longitude) / 3600000 | |
301 | 300 | if longitude < -180.0 or longitude > 180.0: |
302 | 301 | raise dns.exception.FormError("bad longitude") |
303 | 302 | altitude = float(altitude) - 10000000.0 |
0 | # Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license | |
1 | ||
2 | # Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. | |
3 | # | |
4 | # Permission to use, copy, modify, and distribute this software and its | |
5 | # documentation for any purpose with or without fee is hereby granted, | |
6 | # provided that the above copyright notice and this permission notice | |
7 | # appear in all copies. | |
8 | # | |
9 | # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES | |
10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR | |
12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | |
15 | # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | ||
17 | import dns.rdtypes.txtbase | |
18 | ||
19 | ||
20 | class NINFO(dns.rdtypes.txtbase.TXTBase): | |
21 | ||
22 | """NINFO record | |
23 | @see: draft-reid-dnsext-zs-01""" |
20 | 20 | import dns.rdata |
21 | 21 | import dns.rdatatype |
22 | 22 | import dns.name |
23 | from dns._compat import xrange | |
24 | 23 | |
25 | 24 | |
26 | 25 | class NSEC(dns.rdata.Rdata): |
44 | 43 | text = '' |
45 | 44 | for (window, bitmap) in self.windows: |
46 | 45 | bits = [] |
47 | for i in xrange(0, len(bitmap)): | |
48 | byte = bitmap[i] | |
49 | for j in xrange(0, 8): | |
46 | for (i, byte) in enumerate(bitmap): | |
47 | for j in range(0, 8): | |
50 | 48 | if byte & (0x80 >> j): |
51 | 49 | bits.append(dns.rdatatype.to_text(window * 256 + |
52 | 50 | i * 8 + j)) |
16 | 16 | |
17 | 17 | import base64 |
18 | 18 | import binascii |
19 | import string | |
20 | 19 | import struct |
21 | 20 | |
22 | 21 | import dns.exception |
23 | 22 | import dns.rdata |
24 | 23 | import dns.rdatatype |
25 | from dns._compat import xrange, text_type, PY3 | |
26 | 24 | |
27 | # pylint: disable=deprecated-string-function | |
28 | if PY3: | |
29 | b32_hex_to_normal = bytes.maketrans(b'0123456789ABCDEFGHIJKLMNOPQRSTUV', | |
30 | b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567') | |
31 | b32_normal_to_hex = bytes.maketrans(b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', | |
32 | b'0123456789ABCDEFGHIJKLMNOPQRSTUV') | |
33 | else: | |
34 | b32_hex_to_normal = string.maketrans('0123456789ABCDEFGHIJKLMNOPQRSTUV', | |
35 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567') | |
36 | b32_normal_to_hex = string.maketrans('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', | |
37 | '0123456789ABCDEFGHIJKLMNOPQRSTUV') | |
38 | # pylint: enable=deprecated-string-function | |
39 | 25 | |
26 | b32_hex_to_normal = bytes.maketrans(b'0123456789ABCDEFGHIJKLMNOPQRSTUV', | |
27 | b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567') | |
28 | b32_normal_to_hex = bytes.maketrans(b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', | |
29 | b'0123456789ABCDEFGHIJKLMNOPQRSTUV') | |
40 | 30 | |
41 | 31 | # hash algorithm constants |
42 | 32 | SHA1 = 1 |
70 | 60 | self.algorithm = algorithm |
71 | 61 | self.flags = flags |
72 | 62 | self.iterations = iterations |
73 | if isinstance(salt, text_type): | |
63 | if isinstance(salt, str): | |
74 | 64 | self.salt = salt.encode() |
75 | 65 | else: |
76 | 66 | self.salt = salt |
84 | 74 | salt = '-' |
85 | 75 | else: |
86 | 76 | salt = binascii.hexlify(self.salt).decode() |
87 | text = u'' | |
77 | text = '' | |
88 | 78 | for (window, bitmap) in self.windows: |
89 | 79 | bits = [] |
90 | for i in xrange(0, len(bitmap)): | |
91 | byte = bitmap[i] | |
92 | for j in xrange(0, 8): | |
80 | for (i, byte) in enumerate(bitmap): | |
81 | for j in range(0, 8): | |
93 | 82 | if byte & (0x80 >> j): |
94 | 83 | bits.append(dns.rdatatype.to_text(window * 256 + |
95 | 84 | i * 8 + j)) |
96 | text += (u' ' + u' '.join(bits)) | |
97 | return u'%u %u %u %s %s%s' % (self.algorithm, self.flags, | |
98 | self.iterations, salt, next, text) | |
85 | text += (' ' + ' '.join(bits)) | |
86 | return '%u %u %u %s %s%s' % (self.algorithm, self.flags, | |
87 | self.iterations, salt, next, text) | |
99 | 88 | |
100 | 89 | @classmethod |
101 | 90 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): |
103 | 92 | flags = tok.get_uint8() |
104 | 93 | iterations = tok.get_uint16() |
105 | 94 | salt = tok.get_string() |
106 | if salt == u'-': | |
95 | if salt == '-': | |
107 | 96 | salt = b'' |
108 | 97 | else: |
109 | 98 | salt = binascii.unhexlify(salt.encode('ascii')) |
19 | 19 | |
20 | 20 | import dns.exception |
21 | 21 | import dns.rdata |
22 | from dns._compat import text_type | |
23 | 22 | |
24 | 23 | |
25 | 24 | class NSEC3PARAM(dns.rdata.Rdata): |
42 | 41 | self.algorithm = algorithm |
43 | 42 | self.flags = flags |
44 | 43 | self.iterations = iterations |
45 | if isinstance(salt, text_type): | |
44 | if isinstance(salt, str): | |
46 | 45 | self.salt = salt.encode() |
47 | 46 | else: |
48 | 47 | self.salt = salt |
31 | 31 | |
32 | 32 | |
33 | 33 | def sigtime_to_posixtime(what): |
34 | if len(what) <= 10 and what.isdigit(): | |
35 | return int(what) | |
34 | 36 | if len(what) != 14: |
35 | 37 | raise BadSigTime |
36 | 38 | year = int(what[0:4]) |
20 | 20 | import dns.exception |
21 | 21 | import dns.rdata |
22 | 22 | import dns.name |
23 | from dns._compat import text_type | |
24 | 23 | |
25 | 24 | |
26 | 25 | class URI(dns.rdata.Rdata): |
43 | 42 | self.weight = weight |
44 | 43 | if len(target) < 1: |
45 | 44 | raise dns.exception.SyntaxError("URI target cannot be empty") |
46 | if isinstance(target, text_type): | |
45 | if isinstance(target, str): | |
47 | 46 | self.target = target.encode() |
48 | 47 | else: |
49 | 48 | self.target = target |
19 | 19 | import dns.exception |
20 | 20 | import dns.rdata |
21 | 21 | import dns.tokenizer |
22 | from dns._compat import text_type | |
23 | 22 | |
24 | 23 | |
25 | 24 | class X25(dns.rdata.Rdata): |
34 | 33 | |
35 | 34 | def __init__(self, rdclass, rdtype, address): |
36 | 35 | super(X25, self).__init__(rdclass, rdtype) |
37 | if isinstance(address, text_type): | |
36 | if isinstance(address, str): | |
38 | 37 | self.address = address.encode() |
39 | 38 | else: |
40 | 39 | self.address = address |
22 | 22 | import dns.inet |
23 | 23 | import dns.rdata |
24 | 24 | import dns.tokenizer |
25 | from dns._compat import xrange, maybe_chr | |
26 | ||
27 | 25 | |
28 | 26 | class APLItem(object): |
29 | 27 | |
64 | 62 | # Truncate least significant zero bytes. |
65 | 63 | # |
66 | 64 | last = 0 |
67 | for i in xrange(len(address) - 1, -1, -1): | |
68 | if address[i] != maybe_chr(0): | |
65 | for i in range(len(address) - 1, -1, -1): | |
66 | if address[i] != 0: | |
69 | 67 | last = i + 1 |
70 | 68 | break |
71 | 69 | address = address[0: last] |
19 | 19 | import dns.exception |
20 | 20 | import dns.name |
21 | 21 | import dns.rdata |
22 | from dns._compat import xrange, text_type | |
23 | 22 | |
24 | 23 | |
25 | 24 | def _write_string(file, s): |
30 | 29 | |
31 | 30 | |
32 | 31 | def _sanitize(value): |
33 | if isinstance(value, text_type): | |
32 | if isinstance(value, str): | |
34 | 33 | return value.encode() |
35 | 34 | return value |
36 | 35 | |
102 | 101 | current += 4 |
103 | 102 | rdlen -= 4 |
104 | 103 | strings = [] |
105 | for i in xrange(3): | |
104 | for i in range(3): | |
106 | 105 | l = wire[current] |
107 | 106 | current += 1 |
108 | 107 | rdlen -= 1 |
19 | 19 | |
20 | 20 | import dns.ipv4 |
21 | 21 | import dns.rdata |
22 | from dns._compat import xrange | |
23 | 22 | |
24 | 23 | _proto_tcp = socket.getprotobyname('tcp') |
25 | 24 | _proto_udp = socket.getprotobyname('udp') |
50 | 49 | |
51 | 50 | def to_text(self, origin=None, relativize=True, **kw): |
52 | 51 | bits = [] |
53 | for i in xrange(0, len(self.bitmap)): | |
52 | for i in range(0, len(self.bitmap)): | |
54 | 53 | byte = self.bitmap[i] |
55 | for j in xrange(0, 8): | |
54 | for j in range(0, 8): | |
56 | 55 | if byte & (0x80 >> j): |
57 | 56 | bits.append(str(i * 8 + j)) |
58 | 57 | text = ' '.join(bits) |
84 | 83 | i = serv // 8 |
85 | 84 | l = len(bitmap) |
86 | 85 | if l < i + 1: |
87 | for j in xrange(l, i + 1): | |
86 | for j in range(l, i + 1): | |
88 | 87 | bitmap.append(0) |
89 | 88 | bitmap[i] = bitmap[i] | (0x80 >> (serv % 8)) |
90 | 89 | bitmap = dns.rdata._truncate_bitmap(bitmap) |
16 | 16 | import binascii |
17 | 17 | |
18 | 18 | import dns.rdata |
19 | from dns._compat import xrange | |
20 | 19 | |
21 | 20 | |
22 | 21 | class EUIBase(dns.rdata.Rdata): |
49 | 48 | if len(text) != cls.text_len: |
50 | 49 | raise dns.exception.SyntaxError( |
51 | 50 | 'Input text must have %s characters' % cls.text_len) |
52 | expected_dash_idxs = xrange(2, cls.byte_len * 3 - 1, 3) | |
53 | for i in expected_dash_idxs: | |
51 | for i in range(2, cls.byte_len * 3 - 1, 3): | |
54 | 52 | if text[i] != '-': |
55 | 53 | raise dns.exception.SyntaxError('Dash expected at position %s' |
56 | 54 | % i) |
21 | 21 | import dns.exception |
22 | 22 | import dns.rdata |
23 | 23 | import dns.tokenizer |
24 | from dns._compat import binary_type, string_types | |
25 | 24 | |
26 | 25 | |
27 | 26 | class TXTBase(dns.rdata.Rdata): |
36 | 35 | |
37 | 36 | def __init__(self, rdclass, rdtype, strings): |
38 | 37 | super(TXTBase, self).__init__(rdclass, rdtype) |
39 | if isinstance(strings, binary_type) or \ | |
40 | isinstance(strings, string_types): | |
38 | if isinstance(strings, bytes) or \ | |
39 | isinstance(strings, str): | |
41 | 40 | strings = [strings] |
42 | 41 | self.strings = [] |
43 | 42 | for string in strings: |
44 | if isinstance(string, string_types): | |
43 | if isinstance(string, str): | |
45 | 44 | string = string.encode() |
46 | 45 | self.strings.append(string) |
47 | 46 | |
65 | 64 | if len(token.value) > 255: |
66 | 65 | raise dns.exception.SyntaxError("string too long") |
67 | 66 | value = token.value |
68 | if isinstance(value, binary_type): | |
67 | if isinstance(value, bytes): | |
69 | 68 | strings.append(value) |
70 | 69 | else: |
71 | 70 | strings.append(value.encode()) |
23 | 23 | |
24 | 24 | import dns.exception |
25 | 25 | import dns.tsig |
26 | from ._compat import long | |
27 | 26 | |
28 | 27 | |
29 | 28 | QUESTION = 0 |
171 | 170 | """Add an EDNS OPT record to the message.""" |
172 | 171 | |
173 | 172 | # make sure the EDNS version in ednsflags agrees with edns |
174 | ednsflags &= long(0xFF00FFFF) | |
173 | ednsflags &= 0xFF00FFFF | |
175 | 174 | ednsflags |= (edns << 16) |
176 | 175 | self._set_section(ADDITIONAL) |
177 | 176 | before = self.output.tell() |
20 | 20 | import sys |
21 | 21 | import time |
22 | 22 | import random |
23 | ||
24 | 23 | try: |
25 | 24 | import threading as _threading |
26 | 25 | except ImportError: |
38 | 37 | import dns.rdatatype |
39 | 38 | import dns.reversename |
40 | 39 | import dns.tsig |
41 | from ._compat import xrange, string_types | |
42 | 40 | |
43 | 41 | if sys.platform == 'win32': |
44 | 42 | try: |
181 | 179 | class NoMetaqueries(dns.exception.DNSException): |
182 | 180 | """DNS metaqueries are not allowed.""" |
183 | 181 | |
182 | class NoResolverConfiguration(dns.exception.DNSException): | |
183 | """Resolver configuration could not be read or specified no nameservers.""" | |
184 | 184 | |
185 | 185 | class Answer(object): |
186 | 186 | """DNS stub resolver answer. |
199 | 199 | """ |
200 | 200 | |
201 | 201 | def __init__(self, qname, rdtype, rdclass, response, |
202 | raise_on_no_answer=True): | |
202 | raise_on_no_answer=True, nameserver=None, | |
203 | port=None): | |
203 | 204 | self.qname = qname |
204 | 205 | self.rdtype = rdtype |
205 | 206 | self.rdclass = rdclass |
206 | 207 | self.response = response |
208 | self.nameserver = nameserver | |
209 | self.port = port | |
207 | 210 | min_ttl = -1 |
208 | 211 | rrset = None |
209 | for count in xrange(0, 15): | |
212 | for count in range(0, 15): | |
210 | 213 | try: |
211 | 214 | rrset = response.find_rrset(response.answer, qname, |
212 | 215 | rdclass, rdtype) |
572 | 575 | a ``text``, it is used as the name of the file to open; otherwise it |
573 | 576 | is treated as the file itself.""" |
574 | 577 | |
575 | if isinstance(f, string_types): | |
578 | if isinstance(f, str): | |
576 | 579 | try: |
577 | 580 | f = open(f, 'r') |
578 | 581 | except IOError: |
579 | 582 | # /etc/resolv.conf doesn't exist, can't be read, etc. |
580 | # We'll just use the default resolver configuration. | |
581 | self.nameservers = ['127.0.0.1'] | |
582 | return | |
583 | raise NoResolverConfiguration | |
583 | 584 | want_close = True |
584 | 585 | else: |
585 | 586 | want_close = False |
607 | 608 | if want_close: |
608 | 609 | f.close() |
609 | 610 | if len(self.nameservers) == 0: |
610 | self.nameservers.append('127.0.0.1') | |
611 | raise NoResolverConfiguration | |
611 | 612 | |
612 | 613 | def _determine_split_char(self, entry): |
613 | 614 | # |
823 | 824 | |
824 | 825 | *source_port*, an ``int``, the port from which to send the message. |
825 | 826 | |
826 | *lifetime*, a ``float``, how long query should run before timing out. | |
827 | *lifetime*, a ``float``, how many seconds a query should run before timing out. | |
827 | 828 | |
828 | 829 | Raises ``dns.exception.Timeout`` if no answers could be found |
829 | 830 | in the specified lifetime. |
843 | 844 | Returns a ``dns.resolver.Answer`` instance. |
844 | 845 | """ |
845 | 846 | |
846 | if isinstance(qname, string_types): | |
847 | if isinstance(qname, str): | |
847 | 848 | qname = dns.name.from_text(qname, None) |
848 | if isinstance(rdtype, string_types): | |
849 | if isinstance(rdtype, str): | |
849 | 850 | rdtype = dns.rdatatype.from_text(rdtype) |
850 | 851 | if dns.rdatatype.is_metatype(rdtype): |
851 | 852 | raise NoMetaqueries |
852 | if isinstance(rdclass, string_types): | |
853 | if isinstance(rdclass, str): | |
853 | 854 | rdclass = dns.rdataclass.from_text(rdclass) |
854 | 855 | if dns.rdataclass.is_metaclass(rdclass): |
855 | 856 | raise NoMetaqueries |
892 | 893 | if self.rotate: |
893 | 894 | random.shuffle(nameservers) |
894 | 895 | backoff = 0.10 |
896 | # keep track of nameserver and port | |
897 | # to include them in Answer | |
898 | nameserver_answered = None | |
899 | port_answered = None | |
895 | 900 | while response is None: |
896 | 901 | if len(nameservers) == 0: |
897 | 902 | raise NoNameservers(request=request, errors=errors) |
906 | 911 | source=source, |
907 | 912 | source_port=source_port) |
908 | 913 | else: |
909 | response = dns.query.udp(request, nameserver, | |
910 | timeout, port, | |
911 | source=source, | |
912 | source_port=source_port) | |
913 | if response.flags & dns.flags.TC: | |
914 | try: | |
915 | response = dns.query.udp(request, nameserver, | |
916 | timeout, port, | |
917 | source=source, | |
918 | source_port=\ | |
919 | source_port) | |
920 | except dns.message.Truncated: | |
914 | 921 | # Response truncated; retry with TCP. |
915 | 922 | tcp_attempt = True |
916 | 923 | timeout = self._compute_timeout(start, lifetime) |
959 | 966 | response)) |
960 | 967 | response = None |
961 | 968 | continue |
969 | nameserver_answered = nameserver | |
970 | port_answered = port | |
962 | 971 | rcode = response.rcode() |
963 | 972 | if rcode == dns.rcode.YXDOMAIN: |
964 | 973 | ex = YXDOMAIN() |
1000 | 1009 | if all_nxdomain: |
1001 | 1010 | raise NXDOMAIN(qnames=qnames_to_try, responses=nxdomain_responses) |
1002 | 1011 | answer = Answer(_qname, rdtype, rdclass, response, |
1003 | raise_on_no_answer) | |
1012 | raise_on_no_answer, nameserver_answered, port_answered) | |
1004 | 1013 | if self.cache: |
1005 | 1014 | self.cache.put((_qname, rdtype, rdclass), answer) |
1006 | 1015 | return answer |
1120 | 1129 | Returns a ``dns.name.Name``. |
1121 | 1130 | """ |
1122 | 1131 | |
1123 | if isinstance(name, string_types): | |
1132 | if isinstance(name, str): | |
1124 | 1133 | name = dns.name.from_text(name, dns.name.root) |
1125 | 1134 | if resolver is None: |
1126 | 1135 | resolver = get_default_resolver() |
1161 | 1170 | def _getaddrinfo(host=None, service=None, family=socket.AF_UNSPEC, socktype=0, |
1162 | 1171 | proto=0, flags=0): |
1163 | 1172 | if flags & (socket.AI_ADDRCONFIG | socket.AI_V4MAPPED) != 0: |
1164 | raise NotImplementedError | |
1173 | # Not implemented. We raise a gaierror as opposed to a | |
1174 | # NotImplementedError as it helps callers handle errors more | |
1175 | # appropriately. [Issue #316] | |
1176 | raise socket.gaierror(socket.EAI_SYSTEM) | |
1165 | 1177 | if host is None and service is None: |
1166 | 1178 | raise socket.gaierror(socket.EAI_NONAME) |
1167 | 1179 | v6addrs = [] |
2 | 2 | |
3 | 3 | import socket |
4 | 4 | _gethostbyname = socket.gethostbyname |
5 | class NXDOMAIN(exception.DNSException): | |
6 | ... | |
5 | ||
6 | class NXDOMAIN(exception.DNSException): ... | |
7 | class YXDOMAIN(exception.DNSException): ... | |
8 | class NoAnswer(exception.DNSException): ... | |
9 | class NoNameservers(exception.DNSException): ... | |
10 | class NotAbsolute(exception.DNSException): ... | |
11 | class NoRootSOA(exception.DNSException): ... | |
12 | class NoMetaqueries(exception.DNSException): ... | |
13 | class NoResolverConfiguration(exception.DNSException): ... | |
14 | Timeout = exception.Timeout | |
15 | ||
7 | 16 | def query(qname : str, rdtype : Union[int,str] = 0, rdclass : Union[int,str] = 0, |
8 | 17 | tcp=False, source=None, raise_on_no_answer=True, |
9 | 18 | source_port=0): |
22 | 22 | import dns.ipv6 |
23 | 23 | import dns.ipv4 |
24 | 24 | |
25 | from dns._compat import PY3 | |
26 | ||
27 | 25 | ipv4_reverse_domain = dns.name.from_text('in-addr.arpa.') |
28 | 26 | ipv6_reverse_domain = dns.name.from_text('ip6.arpa.') |
29 | 27 | |
43 | 41 | try: |
44 | 42 | v6 = dns.ipv6.inet_aton(text) |
45 | 43 | if dns.ipv6.is_mapped(v6): |
46 | if PY3: | |
47 | parts = ['%d' % byte for byte in v6[12:]] | |
48 | else: | |
49 | parts = ['%d' % ord(byte) for byte in v6[12:]] | |
44 | parts = ['%d' % byte for byte in v6[12:]] | |
50 | 45 | origin = ipv4_reverse_domain |
51 | 46 | else: |
52 | 47 | parts = [x for x in str(binascii.hexlify(v6).decode())] |
53 | 48 | origin = ipv6_reverse_domain |
54 | 49 | except Exception: |
55 | 50 | parts = ['%d' % |
56 | byte for byte in bytearray(dns.ipv4.inet_aton(text))] | |
51 | byte for byte in dns.ipv4.inet_aton(text)] | |
57 | 52 | origin = ipv4_reverse_domain |
58 | 53 | parts.reverse() |
59 | 54 | return dns.name.from_text('.'.join(parts), origin=origin) |
21 | 21 | import dns.rdataset |
22 | 22 | import dns.rdataclass |
23 | 23 | import dns.renderer |
24 | from ._compat import string_types | |
25 | 24 | |
26 | 25 | |
27 | 26 | class RRset(dns.rdataset.Rdataset): |
133 | 132 | Returns a ``dns.rrset.RRset`` object. |
134 | 133 | """ |
135 | 134 | |
136 | if isinstance(name, string_types): | |
135 | if isinstance(name, str): | |
137 | 136 | name = dns.name.from_text(name, None, idna_codec=idna_codec) |
138 | if isinstance(rdclass, string_types): | |
137 | if isinstance(rdclass, str): | |
139 | 138 | rdclass = dns.rdataclass.from_text(rdclass) |
140 | if isinstance(rdtype, string_types): | |
139 | if isinstance(rdtype, str): | |
141 | 140 | rdtype = dns.rdatatype.from_text(rdtype) |
142 | 141 | r = RRset(name, rdclass, rdtype) |
143 | 142 | r.update_ttl(ttl) |
164 | 163 | Returns a ``dns.rrset.RRset`` object. |
165 | 164 | """ |
166 | 165 | |
167 | if isinstance(name, string_types): | |
166 | if isinstance(name, str): | |
168 | 167 | name = dns.name.from_text(name, None, idna_codec=idna_codec) |
169 | 168 | |
170 | 169 | if len(rdatas) == 0: |
22 | 22 | import dns.exception |
23 | 23 | import dns.name |
24 | 24 | import dns.ttl |
25 | from ._compat import long, text_type, binary_type | |
26 | 25 | |
27 | 26 | _DELIMITERS = { |
28 | 27 | ' ': True, |
188 | 187 | will return. |
189 | 188 | """ |
190 | 189 | |
191 | if isinstance(f, text_type): | |
190 | if isinstance(f, str): | |
192 | 191 | f = StringIO(f) |
193 | 192 | if filename is None: |
194 | 193 | filename = '<string>' |
195 | elif isinstance(f, binary_type): | |
194 | elif isinstance(f, bytes): | |
196 | 195 | f = StringIO(f.decode()) |
197 | 196 | if filename is None: |
198 | 197 | filename = '<string>' |
496 | 495 | raise dns.exception.SyntaxError('expecting an identifier') |
497 | 496 | if not token.value.isdigit(): |
498 | 497 | raise dns.exception.SyntaxError('expecting an integer') |
499 | value = long(token.value) | |
500 | if value < 0 or value > long(4294967296): | |
498 | value = int(token.value) | |
499 | if value < 0 or value > 4294967296: | |
501 | 500 | raise dns.exception.SyntaxError( |
502 | 501 | '%d is not an unsigned 32-bit integer' % value) |
503 | 502 | return value |
23 | 23 | import dns.exception |
24 | 24 | import dns.rdataclass |
25 | 25 | import dns.name |
26 | from ._compat import long, string_types, text_type | |
27 | 26 | |
28 | 27 | class BadTime(dns.exception.DNSException): |
29 | 28 | |
96 | 95 | @raises NotImplementedError: I{algorithm} is not supported |
97 | 96 | """ |
98 | 97 | |
99 | if isinstance(other_data, text_type): | |
98 | if isinstance(other_data, str): | |
100 | 99 | other_data = other_data.encode() |
101 | 100 | (algorithm_name, digestmod) = get_algorithm(algorithm) |
102 | 101 | if first: |
112 | 111 | ctx.update(keyname.to_digestable()) |
113 | 112 | ctx.update(struct.pack('!H', dns.rdataclass.ANY)) |
114 | 113 | ctx.update(struct.pack('!I', 0)) |
115 | long_time = time + long(0) | |
116 | upper_time = (long_time >> 32) & long(0xffff) | |
117 | lower_time = long_time & long(0xffffffff) | |
114 | upper_time = (time >> 32) & 0xffff | |
115 | lower_time = time & 0xffffffff | |
118 | 116 | time_mac = struct.pack('!HIH', upper_time, lower_time, fudge) |
119 | 117 | pre_mac = algorithm_name + time_mac |
120 | 118 | ol = len(other_data) |
166 | 164 | current = current + used |
167 | 165 | (upper_time, lower_time, fudge, mac_size) = \ |
168 | 166 | struct.unpack("!HIHH", wire[current:current + 10]) |
169 | time = ((upper_time + long(0)) << 32) + (lower_time + long(0)) | |
167 | time = (upper_time << 32) + lower_time | |
170 | 168 | current += 10 |
171 | 169 | mac = wire[current:current + mac_size] |
172 | 170 | current += mac_size |
208 | 206 | @raises NotImplementedError: I{algorithm} is not supported |
209 | 207 | """ |
210 | 208 | |
211 | if isinstance(algorithm, string_types): | |
209 | if isinstance(algorithm, str): | |
212 | 210 | algorithm = dns.name.from_text(algorithm) |
213 | 211 | |
214 | 212 | try: |
16 | 16 | |
17 | 17 | """A place to store TSIG keys.""" |
18 | 18 | |
19 | from dns._compat import maybe_decode, maybe_encode | |
20 | ||
21 | 19 | import base64 |
22 | 20 | |
23 | 21 | import dns.name |
31 | 29 | keyring = {} |
32 | 30 | for keytext in textring: |
33 | 31 | keyname = dns.name.from_text(keytext) |
34 | secret = base64.decodestring(maybe_encode(textring[keytext])) | |
32 | secret = base64.decodebytes(textring[keytext].encode()) | |
35 | 33 | keyring[keyname] = secret |
36 | 34 | return keyring |
37 | 35 | |
43 | 41 | |
44 | 42 | textring = {} |
45 | 43 | for keyname in keyring: |
46 | keytext = maybe_decode(keyname.to_text()) | |
47 | secret = maybe_decode(base64.encodestring(keyring[keyname])) | |
44 | keytext = keyname.to_text() | |
45 | # rstrip to get rid of the \n encoding adds | |
46 | secret = base64.encodebytes(keyring[keyname]).decode().rstrip() | |
48 | 47 | textring[keytext] = secret |
49 | 48 | return textring |
17 | 17 | """DNS TTL conversion.""" |
18 | 18 | |
19 | 19 | import dns.exception |
20 | from ._compat import long | |
21 | 20 | |
22 | 21 | |
23 | 22 | class BadTTL(dns.exception.SyntaxError): |
37 | 36 | """ |
38 | 37 | |
39 | 38 | if text.isdigit(): |
40 | total = long(text) | |
39 | total = int(text) | |
41 | 40 | else: |
42 | 41 | if not text[0].isdigit(): |
43 | 42 | raise BadTTL |
44 | total = long(0) | |
45 | current = long(0) | |
43 | total = 0 | |
44 | current = 0 | |
46 | 45 | for c in text: |
47 | 46 | if c.isdigit(): |
48 | 47 | current *= 10 |
49 | current += long(c) | |
48 | current += int(c) | |
50 | 49 | else: |
51 | 50 | c = c.lower() |
52 | 51 | if c == 'w': |
53 | total += current * long(604800) | |
52 | total += current * 604800 | |
54 | 53 | elif c == 'd': |
55 | total += current * long(86400) | |
54 | total += current * 86400 | |
56 | 55 | elif c == 'h': |
57 | total += current * long(3600) | |
56 | total += current * 3600 | |
58 | 57 | elif c == 'm': |
59 | total += current * long(60) | |
58 | total += current * 60 | |
60 | 59 | elif c == 's': |
61 | 60 | total += current |
62 | 61 | else: |
64 | 63 | current = 0 |
65 | 64 | if not current == 0: |
66 | 65 | raise BadTTL("trailing integer") |
67 | if total < long(0) or total > long(2147483647): | |
66 | if total < 0 or total > 2147483647: | |
68 | 67 | raise BadTTL("TTL should be between 0 and 2^31 - 1 (inclusive)") |
69 | 68 | return total |
24 | 24 | import dns.rdataclass |
25 | 25 | import dns.rdataset |
26 | 26 | import dns.tsig |
27 | from ._compat import string_types | |
28 | 27 | |
29 | 28 | |
30 | 29 | class Update(dns.message.Message): |
55 | 54 | """ |
56 | 55 | super(Update, self).__init__() |
57 | 56 | self.flags |= dns.opcode.to_flags(dns.opcode.UPDATE) |
58 | if isinstance(zone, string_types): | |
57 | if isinstance(zone, str): | |
59 | 58 | zone = dns.name.from_text(zone) |
60 | 59 | self.origin = zone |
61 | if isinstance(rdclass, string_types): | |
60 | if isinstance(rdclass, str): | |
62 | 61 | rdclass = dns.rdataclass.from_text(rdclass) |
63 | 62 | self.zone_rdclass = rdclass |
64 | 63 | self.find_rrset(self.question, self.origin, rdclass, dns.rdatatype.SOA, |
92 | 91 | - ttl, rdtype, string... |
93 | 92 | """ |
94 | 93 | |
95 | if isinstance(name, string_types): | |
94 | if isinstance(name, str): | |
96 | 95 | name = dns.name.from_text(name, None) |
97 | 96 | if isinstance(args[0], dns.rdataset.Rdataset): |
98 | 97 | for rds in args: |
110 | 109 | self._add_rr(name, ttl, rd, section=section) |
111 | 110 | else: |
112 | 111 | rdtype = args.pop(0) |
113 | if isinstance(rdtype, string_types): | |
112 | if isinstance(rdtype, str): | |
114 | 113 | rdtype = dns.rdatatype.from_text(rdtype) |
115 | 114 | if replace: |
116 | 115 | self.delete(name, rdtype) |
149 | 148 | - rdtype, [string...] |
150 | 149 | """ |
151 | 150 | |
152 | if isinstance(name, string_types): | |
151 | if isinstance(name, str): | |
153 | 152 | name = dns.name.from_text(name, None) |
154 | 153 | if len(args) == 0: |
155 | 154 | self.find_rrset(self.authority, name, dns.rdataclass.ANY, |
166 | 165 | self._add_rr(name, 0, rd, dns.rdataclass.NONE) |
167 | 166 | else: |
168 | 167 | rdtype = args.pop(0) |
169 | if isinstance(rdtype, string_types): | |
168 | if isinstance(rdtype, str): | |
170 | 169 | rdtype = dns.rdatatype.from_text(rdtype) |
171 | 170 | if len(args) == 0: |
172 | 171 | self.find_rrset(self.authority, name, |
213 | 212 | - rdtype, string... |
214 | 213 | """ |
215 | 214 | |
216 | if isinstance(name, string_types): | |
215 | if isinstance(name, str): | |
217 | 216 | name = dns.name.from_text(name, None) |
218 | 217 | if len(args) == 0: |
219 | 218 | self.find_rrset(self.answer, name, |
230 | 229 | self._add(False, self.answer, name, *args) |
231 | 230 | else: |
232 | 231 | rdtype = args[0] |
233 | if isinstance(rdtype, string_types): | |
232 | if isinstance(rdtype, str): | |
234 | 233 | rdtype = dns.rdatatype.from_text(rdtype) |
235 | 234 | self.find_rrset(self.answer, name, |
236 | 235 | dns.rdataclass.ANY, rdtype, |
241 | 240 | """Require that an owner name (and optionally an rdata type) does |
242 | 241 | not exist as a prerequisite to the execution of the update.""" |
243 | 242 | |
244 | if isinstance(name, string_types): | |
243 | if isinstance(name, str): | |
245 | 244 | name = dns.name.from_text(name, None) |
246 | 245 | if rdtype is None: |
247 | 246 | self.find_rrset(self.answer, name, |
249 | 248 | dns.rdatatype.NONE, None, |
250 | 249 | True, True) |
251 | 250 | else: |
252 | if isinstance(rdtype, string_types): | |
251 | if isinstance(rdtype, str): | |
253 | 252 | rdtype = dns.rdatatype.from_text(rdtype) |
254 | 253 | self.find_rrset(self.answer, name, |
255 | 254 | dns.rdataclass.NONE, rdtype, |
17 | 17 | """dnspython release version information.""" |
18 | 18 | |
19 | 19 | #: MAJOR |
20 | MAJOR = 1 | |
20 | MAJOR = 2 | |
21 | 21 | #: MINOR |
22 | MINOR = 16 | |
22 | MINOR = 0 | |
23 | 23 | #: MICRO |
24 | 24 | MICRO = 0 |
25 | 25 | #: RELEASELEVEL |
17 | 17 | """DNS Wire Data Helper""" |
18 | 18 | |
19 | 19 | import dns.exception |
20 | from ._compat import binary_type, string_types, PY2 | |
21 | 20 | |
22 | 21 | # Figure out what constant python passes for an unspecified slice bound. |
23 | 22 | # It's supposed to be sys.maxint, yet on 64-bit windows sys.maxint is 2^31 - 1 |
26 | 25 | # out what constant Python will use. |
27 | 26 | |
28 | 27 | |
29 | class _SliceUnspecifiedBound(binary_type): | |
28 | class _SliceUnspecifiedBound(bytes): | |
30 | 29 | |
31 | 30 | def __getitem__(self, key): |
32 | 31 | return key.stop |
33 | 32 | |
34 | if PY2: | |
35 | def __getslice__(self, i, j): # pylint: disable=getslice-method | |
36 | return self.__getitem__(slice(i, j)) | |
37 | ||
38 | 33 | _unspecified_bound = _SliceUnspecifiedBound()[1:] |
39 | 34 | |
40 | 35 | |
41 | class WireData(binary_type): | |
36 | class WireData(bytes): | |
42 | 37 | # WireData is a binary type with stricter slicing |
43 | 38 | |
44 | 39 | def __getitem__(self, key): |
50 | 45 | start = key.start |
51 | 46 | stop = key.stop |
52 | 47 | |
53 | if PY2: | |
54 | if stop == _unspecified_bound: | |
55 | # handle the case where the right bound is unspecified | |
56 | stop = len(self) | |
57 | ||
58 | if start < 0 or stop < 0: | |
48 | for index in (start, stop): | |
49 | if index is None: | |
50 | continue | |
51 | elif abs(index) > len(self): | |
59 | 52 | raise dns.exception.FormError |
60 | # If it's not an empty slice, access left and right bounds | |
61 | # to make sure they're valid | |
62 | if start != stop: | |
63 | super(WireData, self).__getitem__(start) | |
64 | super(WireData, self).__getitem__(stop - 1) | |
65 | else: | |
66 | for index in (start, stop): | |
67 | if index is None: | |
68 | continue | |
69 | elif abs(index) > len(self): | |
70 | raise dns.exception.FormError | |
71 | 53 | |
72 | 54 | return WireData(super(WireData, self).__getitem__( |
73 | 55 | slice(start, stop))) |
74 | return bytearray(self.unwrap())[key] | |
56 | return self.unwrap()[key] | |
75 | 57 | except IndexError: |
76 | 58 | raise dns.exception.FormError |
77 | ||
78 | if PY2: | |
79 | def __getslice__(self, i, j): # pylint: disable=getslice-method | |
80 | return self.__getitem__(slice(i, j)) | |
81 | 59 | |
82 | 60 | def __iter__(self): |
83 | 61 | i = 0 |
89 | 67 | raise StopIteration |
90 | 68 | |
91 | 69 | def unwrap(self): |
92 | return binary_type(self) | |
70 | return bytes(self) | |
93 | 71 | |
94 | 72 | |
95 | 73 | def maybe_wrap(wire): |
96 | 74 | if isinstance(wire, WireData): |
97 | 75 | return wire |
98 | elif isinstance(wire, binary_type): | |
76 | elif isinstance(wire, bytes): | |
99 | 77 | return WireData(wire) |
100 | elif isinstance(wire, string_types): | |
78 | elif isinstance(wire, str): | |
101 | 79 | return WireData(wire.encode()) |
102 | 80 | raise ValueError("unhandled type %s" % type(wire)) |
34 | 34 | import dns.tokenizer |
35 | 35 | import dns.ttl |
36 | 36 | import dns.grange |
37 | from ._compat import string_types, text_type, PY3 | |
38 | 37 | |
39 | 38 | |
40 | 39 | class BadZone(dns.exception.DNSException): |
94 | 93 | @type rdclass: int""" |
95 | 94 | |
96 | 95 | if origin is not None: |
97 | if isinstance(origin, string_types): | |
96 | if isinstance(origin, str): | |
98 | 97 | origin = dns.name.from_text(origin) |
99 | 98 | elif not isinstance(origin, dns.name.Name): |
100 | 99 | raise ValueError("origin parameter must be convertible to a " |
128 | 127 | return not self.__eq__(other) |
129 | 128 | |
130 | 129 | def _validate_name(self, name): |
131 | if isinstance(name, string_types): | |
130 | if isinstance(name, str): | |
132 | 131 | name = dns.name.from_text(name, None) |
133 | 132 | elif not isinstance(name, dns.name.Name): |
134 | 133 | raise KeyError("name parameter must be convertible to a DNS name") |
156 | 155 | return self.nodes.__iter__() |
157 | 156 | |
158 | 157 | def iterkeys(self): |
159 | if PY3: | |
160 | return self.nodes.keys() # pylint: disable=dict-keys-not-iterating | |
161 | else: | |
162 | return self.nodes.iterkeys() # pylint: disable=dict-iter-method | |
158 | return self.nodes.keys() # pylint: disable=dict-keys-not-iterating | |
163 | 159 | |
164 | 160 | def keys(self): |
165 | 161 | return self.nodes.keys() # pylint: disable=dict-keys-not-iterating |
166 | 162 | |
167 | 163 | def itervalues(self): |
168 | if PY3: | |
169 | return self.nodes.values() # pylint: disable=dict-values-not-iterating | |
170 | else: | |
171 | return self.nodes.itervalues() # pylint: disable=dict-iter-method | |
164 | return self.nodes.values() # pylint: disable=dict-values-not-iterating | |
172 | 165 | |
173 | 166 | def values(self): |
174 | 167 | return self.nodes.values() # pylint: disable=dict-values-not-iterating |
264 | 257 | """ |
265 | 258 | |
266 | 259 | name = self._validate_name(name) |
267 | if isinstance(rdtype, string_types): | |
260 | if isinstance(rdtype, str): | |
268 | 261 | rdtype = dns.rdatatype.from_text(rdtype) |
269 | if isinstance(covers, string_types): | |
262 | if isinstance(covers, str): | |
270 | 263 | covers = dns.rdatatype.from_text(covers) |
271 | 264 | node = self.find_node(name, create) |
272 | 265 | return node.find_rdataset(self.rdclass, rdtype, covers, create) |
327 | 320 | """ |
328 | 321 | |
329 | 322 | name = self._validate_name(name) |
330 | if isinstance(rdtype, string_types): | |
323 | if isinstance(rdtype, str): | |
331 | 324 | rdtype = dns.rdatatype.from_text(rdtype) |
332 | if isinstance(covers, string_types): | |
325 | if isinstance(covers, str): | |
333 | 326 | covers = dns.rdatatype.from_text(covers) |
334 | 327 | node = self.get_node(name) |
335 | 328 | if node is not None: |
390 | 383 | """ |
391 | 384 | |
392 | 385 | name = self._validate_name(name) |
393 | if isinstance(rdtype, string_types): | |
386 | if isinstance(rdtype, str): | |
394 | 387 | rdtype = dns.rdatatype.from_text(rdtype) |
395 | if isinstance(covers, string_types): | |
388 | if isinstance(covers, str): | |
396 | 389 | covers = dns.rdatatype.from_text(covers) |
397 | 390 | rdataset = self.nodes[name].find_rdataset(self.rdclass, rdtype, covers) |
398 | 391 | rrset = dns.rrset.RRset(name, self.rdclass, rdtype, covers) |
446 | 439 | @type covers: int or string |
447 | 440 | """ |
448 | 441 | |
449 | if isinstance(rdtype, string_types): | |
442 | if isinstance(rdtype, str): | |
450 | 443 | rdtype = dns.rdatatype.from_text(rdtype) |
451 | if isinstance(covers, string_types): | |
444 | if isinstance(covers, str): | |
452 | 445 | covers = dns.rdatatype.from_text(covers) |
453 | 446 | for (name, node) in self.iteritems(): # pylint: disable=dict-iter-method |
454 | 447 | for rds in node: |
469 | 462 | @type covers: int or string |
470 | 463 | """ |
471 | 464 | |
472 | if isinstance(rdtype, string_types): | |
465 | if isinstance(rdtype, str): | |
473 | 466 | rdtype = dns.rdatatype.from_text(rdtype) |
474 | if isinstance(covers, string_types): | |
467 | if isinstance(covers, str): | |
475 | 468 | covers = dns.rdatatype.from_text(covers) |
476 | 469 | for (name, node) in self.iteritems(): # pylint: disable=dict-iter-method |
477 | 470 | for rds in node: |
498 | 491 | @type nl: string or None |
499 | 492 | """ |
500 | 493 | |
501 | if isinstance(f, string_types): | |
494 | if isinstance(f, str): | |
502 | 495 | f = open(f, 'wb') |
503 | 496 | want_close = True |
504 | 497 | else: |
512 | 505 | |
513 | 506 | if nl is None: |
514 | 507 | nl_b = os.linesep.encode(file_enc) # binary mode, '\n' is not enough |
515 | nl = u'\n' | |
516 | elif isinstance(nl, string_types): | |
508 | nl = '\n' | |
509 | elif isinstance(nl, str): | |
517 | 510 | nl_b = nl.encode(file_enc) |
518 | 511 | else: |
519 | 512 | nl_b = nl |
528 | 521 | for n in names: |
529 | 522 | l = self[n].to_text(n, origin=self.origin, |
530 | 523 | relativize=relativize) |
531 | if isinstance(l, text_type): | |
524 | if isinstance(l, str): | |
532 | 525 | l_b = l.encode(file_enc) |
533 | 526 | else: |
534 | 527 | l_b = l |
618 | 611 | |
619 | 612 | def __init__(self, tok, origin, rdclass, relativize, zone_factory=Zone, |
620 | 613 | allow_include=False, check_origin=True): |
621 | if isinstance(origin, string_types): | |
614 | if isinstance(origin, str): | |
622 | 615 | origin = dns.name.from_text(origin) |
623 | 616 | self.tok = tok |
624 | 617 | self.current_origin = origin |
664 | 657 | token = self.tok.get() |
665 | 658 | if not token.is_identifier(): |
666 | 659 | raise dns.exception.SyntaxError |
660 | ||
667 | 661 | # TTL |
662 | ttl = None | |
668 | 663 | try: |
669 | 664 | ttl = dns.ttl.from_text(token.value) |
670 | 665 | self.last_ttl = ttl |
673 | 668 | if not token.is_identifier(): |
674 | 669 | raise dns.exception.SyntaxError |
675 | 670 | except dns.ttl.BadTTL: |
676 | if not (self.last_ttl_known or self.default_ttl_known): | |
677 | raise dns.exception.SyntaxError("Missing default TTL value") | |
678 | 671 | if self.default_ttl_known: |
679 | 672 | ttl = self.default_ttl |
680 | else: | |
673 | elif self.last_ttl_known: | |
681 | 674 | ttl = self.last_ttl |
675 | ||
682 | 676 | # Class |
683 | 677 | try: |
684 | 678 | rdclass = dns.rdataclass.from_text(token.value) |
725 | 719 | self.default_ttl = rd.minimum |
726 | 720 | self.default_ttl_known = True |
727 | 721 | |
722 | # TTL check | |
723 | if ttl is None: | |
724 | if not (self.last_ttl_known or self.default_ttl_known): | |
725 | raise dns.exception.SyntaxError("Missing default TTL value") | |
726 | else: | |
727 | if self.default_ttl_known: | |
728 | ttl = self.default_ttl | |
729 | else: | |
730 | ttl = self.last_ttl | |
731 | ||
728 | 732 | rd.choose_relativity(self.zone.origin, self.relativize) |
729 | 733 | covers = rd.covers() |
730 | 734 | rds = n.find_rdataset(rdclass, rdtype, covers, True) |
733 | 737 | def _parse_modify(self, side): |
734 | 738 | # Here we catch everything in '{' '}' in a group so we can replace it |
735 | 739 | # with ''. |
736 | is_generate1 = re.compile("^.*\$({(\+|-?)(\d+),(\d+),(.)}).*$") | |
737 | is_generate2 = re.compile("^.*\$({(\+|-?)(\d+)}).*$") | |
738 | is_generate3 = re.compile("^.*\$({(\+|-?)(\d+),(\d+)}).*$") | |
740 | is_generate1 = re.compile(r"^.*\$({(\+|-?)(\d+),(\d+),(.)}).*$") | |
741 | is_generate2 = re.compile(r"^.*\$({(\+|-?)(\d+)}).*$") | |
742 | is_generate3 = re.compile(r"^.*\$({(\+|-?)(\d+),(\d+)}).*$") | |
739 | 743 | # Sometimes there are modifiers in the hostname. These come after |
740 | 744 | # the dollar sign. They are in the form: ${offset[,width[,base]]}. |
741 | 745 | # Make names |
753 | 757 | base = 'd' |
754 | 758 | g3 = is_generate3.match(side) |
755 | 759 | if g3: |
756 | mod, sign, offset, width = g1.groups() | |
760 | mod, sign, offset, width = g3.groups() | |
757 | 761 | if sign == '': |
758 | 762 | sign = '+' |
759 | width = g1.groups()[2] | |
760 | 763 | base = 'd' |
761 | 764 | |
762 | 765 | if not (g1 or g2 or g3): |
810 | 813 | raise dns.exception.SyntaxError("Missing default TTL value") |
811 | 814 | if self.default_ttl_known: |
812 | 815 | ttl = self.default_ttl |
813 | else: | |
816 | elif self.last_ttl_known: | |
814 | 817 | ttl = self.last_ttl |
815 | 818 | # Class |
816 | 819 | try: |
845 | 848 | for i in range(start, stop + 1, step): |
846 | 849 | # +1 because bind is inclusive and python is exclusive |
847 | 850 | |
848 | if lsign == u'+': | |
851 | if lsign == '+': | |
849 | 852 | lindex = i + int(loffset) |
850 | elif lsign == u'-': | |
853 | elif lsign == '-': | |
851 | 854 | lindex = i - int(loffset) |
852 | 855 | |
853 | if rsign == u'-': | |
856 | if rsign == '-': | |
854 | 857 | rindex = i - int(roffset) |
855 | elif rsign == u'+': | |
858 | elif rsign == '+': | |
856 | 859 | rindex = i + int(roffset) |
857 | 860 | |
858 | 861 | lzfindex = str(lindex).zfill(int(lwidth)) |
859 | 862 | rzfindex = str(rindex).zfill(int(rwidth)) |
860 | 863 | |
861 | name = lhs.replace(u'$%s' % (lmod), lzfindex) | |
862 | rdata = rhs.replace(u'$%s' % (rmod), rzfindex) | |
864 | name = lhs.replace('$%s' % (lmod), lzfindex) | |
865 | rdata = rhs.replace('$%s' % (rmod), rzfindex) | |
863 | 866 | |
864 | 867 | self.last_name = dns.name.from_text(name, self.current_origin) |
865 | 868 | name = self.last_name |
924 | 927 | elif token.is_comment(): |
925 | 928 | self.tok.get_eol() |
926 | 929 | continue |
927 | elif token.value[0] == u'$': | |
930 | elif token.value[0] == '$': | |
928 | 931 | c = token.value.upper() |
929 | if c == u'$TTL': | |
932 | if c == '$TTL': | |
930 | 933 | token = self.tok.get() |
931 | 934 | if not token.is_identifier(): |
932 | 935 | raise dns.exception.SyntaxError("bad $TTL") |
933 | 936 | self.default_ttl = dns.ttl.from_text(token.value) |
934 | 937 | self.default_ttl_known = True |
935 | 938 | self.tok.get_eol() |
936 | elif c == u'$ORIGIN': | |
939 | elif c == '$ORIGIN': | |
937 | 940 | self.current_origin = self.tok.get_name() |
938 | 941 | self.tok.get_eol() |
939 | 942 | if self.zone.origin is None: |
940 | 943 | self.zone.origin = self.current_origin |
941 | elif c == u'$INCLUDE' and self.allow_include: | |
944 | elif c == '$INCLUDE' and self.allow_include: | |
942 | 945 | token = self.tok.get() |
943 | 946 | filename = token.value |
944 | 947 | token = self.tok.get() |
964 | 967 | self.tok = dns.tokenizer.Tokenizer(self.current_file, |
965 | 968 | filename) |
966 | 969 | self.current_origin = new_origin |
967 | elif c == u'$GENERATE': | |
970 | elif c == '$GENERATE': | |
968 | 971 | self._generate_line() |
969 | 972 | else: |
970 | 973 | raise dns.exception.SyntaxError( |
1059 | 1062 | @rtype: dns.zone.Zone object |
1060 | 1063 | """ |
1061 | 1064 | |
1062 | str_type = string_types | |
1063 | if PY3: | |
1064 | opts = 'r' | |
1065 | else: | |
1066 | opts = 'rU' | |
1067 | ||
1068 | if isinstance(f, str_type): | |
1065 | if isinstance(f, str): | |
1069 | 1066 | if filename is None: |
1070 | 1067 | filename = f |
1071 | f = open(f, opts) | |
1068 | f = open(f, 'r') | |
1072 | 1069 | want_close = True |
1073 | 1070 | else: |
1074 | 1071 | if filename is None: |
22 | 22 | while True: |
23 | 23 | (wire, address) = s.recvfrom(512) |
24 | 24 | notify = dns.message.from_wire(wire) |
25 | soa = notify.find_rrset(notify.answer, notify.question[0].name, | |
26 | dns.rdataclass.IN, dns.rdatatype.SOA) | |
27 | 25 | |
28 | # Do something with the SOA RR here | |
29 | print('The serial number for', soa.name, 'is', soa[0].serial) | |
26 | try: | |
27 | soa = notify.find_rrset(notify.answer, notify.question[0].name, | |
28 | dns.rdataclass.IN, dns.rdatatype.SOA) | |
29 | ||
30 | # Do something with the SOA RR here | |
31 | print('The serial number for', soa.name, 'is', soa[0].serial) | |
32 | except KeyError: | |
33 | # No SOA RR in the answer section. | |
34 | pass | |
30 | 35 | |
31 | 36 | response = dns.message.make_response(notify) # type: dns.message.Message |
32 | 37 | response.flags |= dns.flags.AA |
0 | #!/usr/bin/env python | |
1 | # | |
0 | 2 | # Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license |
1 | ||
2 | #!/usr/bin/env python | |
3 | 3 | # |
4 | 4 | # Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. |
5 | 5 | # |
19 | 19 | import sys |
20 | 20 | from setuptools import setup |
21 | 21 | |
22 | version = '1.16.0' | |
22 | version = '2.0.0' | |
23 | 23 | |
24 | 24 | try: |
25 | 25 | sys.argv.remove("--cython-compile") |
61 | 61 | "Programming Language :: Python", |
62 | 62 | "Topic :: Internet :: Name Service (DNS)", |
63 | 63 | "Topic :: Software Development :: Libraries :: Python Modules", |
64 | "Programming Language :: Python :: 2", | |
65 | "Programming Language :: Python :: 2.7", | |
66 | 64 | "Programming Language :: Python :: 3", |
67 | 65 | "Programming Language :: Python :: 3.4", |
68 | 66 | "Programming Language :: Python :: 3.5", |
69 | 67 | "Programming Language :: Python :: 3.6", |
70 | 68 | "Programming Language :: Python :: 3.7", |
71 | 69 | ], |
72 | 'python_requires': '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', | |
70 | 'python_requires': '>=3.4', | |
73 | 71 | 'test_suite': 'tests', |
74 | 72 | 'provides': ['dns'], |
73 | 'tests_require': ['typing ; python_version<"3.5"'], | |
75 | 74 | 'extras_require': { |
76 | 75 | 'IDNA': ['idna>=2.1'], |
77 | 76 | 'DNSSEC': ['pycryptodome', 'ecdsa>=0.13'], |
167 | 167 | unknown2 TYPE999 \# 8 0a0000010a000001 |
168 | 168 | unknown3 A \# 4 7f000002 |
169 | 169 | rrsig01 RRSIG NSEC 1 3 3600 20200101000000 20030101000000 2143 foo MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl d80jEeC8aTrO+KKmCaY= |
170 | rrsig02 RRSIG NSEC 1 3 3600 1577836800 1041379200 2143 foo MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgi WCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nl d80jEeC8aTrO+KKmCaY= | |
170 | 171 | nsec01 NSEC a.secure A MX RRSIG NSEC TYPE1234 |
171 | 172 | nsec02 NSEC . ( NSAP-PTR NSEC ) |
172 | 173 | nsec03 NSEC . ( NSEC TYPE65535 ) |
95 | 95 | rp01 3600 IN RP mbox-dname txt-dname |
96 | 96 | rp02 3600 IN RP . . |
97 | 97 | rrsig01 3600 IN RRSIG NSEC 1 3 3600 20200101000000 20030101000000 2143 foo MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= |
98 | rrsig02 3600 IN RRSIG NSEC 1 3 3600 20200101000000 20030101000000 2143 foo MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= | |
98 | 99 | rt01 3600 IN RT 0 intermediate-host |
99 | 100 | rt02 3600 IN RT 65535 . |
100 | 101 | s 300 IN NS ns.s |
95 | 95 | rp01.example. 3600 IN RP mbox-dname.example. txt-dname.example. |
96 | 96 | rp02.example. 3600 IN RP . . |
97 | 97 | rrsig01.example. 3600 IN RRSIG NSEC 1 3 3600 20200101000000 20030101000000 2143 foo.example. MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= |
98 | rrsig02.example. 3600 IN RRSIG NSEC 1 3 3600 20200101000000 20030101000000 2143 foo.example. MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= | |
98 | 99 | rt01.example. 3600 IN RT 0 intermediate-host.example. |
99 | 100 | rt02.example. 3600 IN RT 65535 . |
100 | 101 | s.example. 300 IN NS ns.s.example. |
95 | 95 | rp01 3600 IN RP mbox-dname txt-dname |
96 | 96 | rp02 3600 IN RP . . |
97 | 97 | rrsig01 3600 IN RRSIG NSEC 1 3 3600 20200101000000 20030101000000 2143 foo MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= |
98 | rrsig02 3600 IN RRSIG NSEC 1 3 3600 20200101000000 20030101000000 2143 foo MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= | |
98 | 99 | rt01 3600 IN RT 0 intermediate-host |
99 | 100 | rt02 3600 IN RT 65535 . |
100 | 101 | s 300 IN NS ns.s |
30 | 30 | def test_float_LOC(self): |
31 | 31 | rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.LOC, |
32 | 32 | u"30 30 0.000 N 100 30 0.000 W 10.00m 20m 2000m 20m") |
33 | self.failUnless(rdata.float_latitude == 30.5) | |
34 | self.failUnless(rdata.float_longitude == -100.5) | |
33 | self.assertTrue(rdata.float_latitude == 30.5) | |
34 | self.assertTrue(rdata.float_longitude == -100.5) | |
35 | 35 | |
36 | 36 | def test_SOA_BIND8_TTL(self): |
37 | 37 | rdata1 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, |
38 | 38 | u"a b 100 1s 1m 1h 1d") |
39 | 39 | rdata2 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, |
40 | 40 | u"a b 100 1 60 3600 86400") |
41 | self.failUnless(rdata1 == rdata2) | |
41 | self.assertTrue(rdata1 == rdata2) | |
42 | 42 | |
43 | 43 | def test_TTL_bounds_check(self): |
44 | 44 | def bad(): |
45 | 45 | dns.ttl.from_text("2147483648") |
46 | self.failUnlessRaises(dns.ttl.BadTTL, bad) | |
46 | self.assertRaises(dns.ttl.BadTTL, bad) | |
47 | 47 | |
48 | 48 | def test_empty_NSEC3_window(self): |
49 | 49 | rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NSEC3, |
50 | 50 | u"1 0 100 ABCD SCBCQHKU35969L2A68P3AD59LHF30715") |
51 | self.failUnless(rdata.windows == []) | |
51 | self.assertTrue(rdata.windows == []) | |
52 | 52 | |
53 | 53 | def test_zero_size_APL(self): |
54 | 54 | rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.APL, |
55 | 55 | "") |
56 | 56 | rdata2 = dns.rdata.from_wire(dns.rdataclass.IN, dns.rdatatype.APL, |
57 | 57 | "", 0, 0) |
58 | self.failUnless(rdata == rdata2) | |
58 | self.assertTrue(rdata == rdata2) | |
59 | 59 | |
60 | 60 | def test_CAA_from_wire(self): |
61 | 61 | rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CAA, |
62 | u'0 issue "ca.example.net"') | |
62 | '0 issue "ca.example.net"') | |
63 | 63 | f = BytesIO() |
64 | 64 | rdata.to_wire(f) |
65 | 65 | wire = f.getvalue() |
67 | 67 | wire += b"trailing garbage" |
68 | 68 | rdata2 = dns.rdata.from_wire(dns.rdataclass.IN, dns.rdatatype.CAA, |
69 | 69 | wire, 0, rdlen) |
70 | self.failUnless(rdata == rdata2) | |
70 | self.assertTrue(rdata == rdata2) | |
71 | 71 | |
72 | 72 | def test_trailing_zero_APL(self): |
73 | 73 | in4 = "!1:127.0.0.0/1" |
74 | 74 | rd4 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.APL, in4) |
75 | 75 | out4 = rd4.to_digestable(dns.name.from_text("test")) |
76 | 76 | text4 = binascii.hexlify(out4).decode('ascii') |
77 | self.failUnless(text4 == '000101817f') | |
77 | self.assertTrue(text4 == '000101817f') | |
78 | 78 | in6 = "!2:::1000/1" |
79 | 79 | rd6 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.APL, in6) |
80 | 80 | out6 = rd6.to_digestable(dns.name.from_text("test")) |
81 | 81 | text6 = binascii.hexlify(out6).decode('ascii') |
82 | self.failUnless(text6 == '0002018f000000000000000000000000000010') | |
82 | self.assertTrue(text6 == '0002018f000000000000000000000000000010') | |
83 | 83 | |
84 | 84 | def test_TXT_conversions(self): |
85 | 85 | t1 = dns.rdtypes.ANY.TXT.TXT(dns.rdataclass.IN, dns.rdatatype.TXT, |
90 | 90 | 'foo') |
91 | 91 | t4 = dns.rdtypes.ANY.TXT.TXT(dns.rdataclass.IN, dns.rdatatype.TXT, |
92 | 92 | ['foo']) |
93 | self.failUnless(t1 == t2) | |
94 | self.failUnless(t1 == t2) | |
95 | self.failUnless(t1 == t4) | |
93 | self.assertTrue(t1 == t2) | |
94 | self.assertTrue(t1 == t2) | |
95 | self.assertTrue(t1 == t4) | |
96 | 96 | |
97 | 97 | if __name__ == '__main__': |
98 | 98 | unittest.main() |
149 | 149 | "SOA 14 1 86400 20130929021229 20130921230729 63571 example. CrnCu34EeeRz0fEhL9PLlwjpBKGYW8QjBjFQTwd+ViVLRAS8tNkcDwQE NhSV89NEjj7ze1a/JcCfcJ+/mZgnvH4NHLNg3Tf6KuLZsgs2I4kKQXEk 37oIHravPEOlGYNI") |
150 | 150 | |
151 | 151 | |
152 | ||
153 | 152 | @unittest.skipUnless(dns.dnssec._have_pycrypto, |
154 | 153 | "Pycryptodome cannot be imported") |
155 | 154 | class DNSSECValidatorTestCase(unittest.TestCase): |
156 | 155 | |
157 | def testAbsoluteRSAGood(self): # type: () -> None | |
156 | def testAbsoluteRSAGood(self): # type: () -> None | |
158 | 157 | dns.dnssec.validate(abs_soa, abs_soa_rrsig, abs_keys, None, when) |
159 | 158 | |
160 | def testDuplicateKeytag(self): # type: () -> None | |
159 | def testDuplicateKeytag(self): # type: () -> None | |
161 | 160 | dns.dnssec.validate(abs_soa, abs_soa_rrsig, abs_keys_duplicate_keytag, None, when) |
162 | 161 | |
163 | def testAbsoluteRSABad(self): # type: () -> None | |
164 | def bad(): # type: () -> None | |
162 | def testAbsoluteRSABad(self): # type: () -> None | |
163 | def bad(): # type: () -> None | |
165 | 164 | dns.dnssec.validate(abs_other_soa, abs_soa_rrsig, abs_keys, None, |
166 | 165 | when) |
167 | self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) | |
168 | ||
169 | def testRelativeRSAGood(self): # type: () -> None | |
166 | self.assertRaises(dns.dnssec.ValidationFailure, bad) | |
167 | ||
168 | def testRelativeRSAGood(self): # type: () -> None | |
170 | 169 | dns.dnssec.validate(rel_soa, rel_soa_rrsig, rel_keys, |
171 | 170 | abs_dnspython_org, when) |
172 | 171 | |
173 | def testRelativeRSABad(self): # type: () -> None | |
174 | def bad(): # type: () -> None | |
172 | def testRelativeRSABad(self): # type: () -> None | |
173 | def bad(): # type: () -> None | |
175 | 174 | dns.dnssec.validate(rel_other_soa, rel_soa_rrsig, rel_keys, |
176 | 175 | abs_dnspython_org, when) |
177 | self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) | |
178 | ||
179 | def testMakeSHA256DS(self): # type: () -> None | |
180 | ds = dns.dnssec.make_ds(abs_dnspython_org, sep_key, 'SHA256') | |
181 | self.failUnless(ds == good_ds) | |
182 | ||
183 | def testAbsoluteDSAGood(self): # type: () -> None | |
176 | self.assertRaises(dns.dnssec.ValidationFailure, bad) | |
177 | ||
178 | def testAbsoluteDSAGood(self): # type: () -> None | |
184 | 179 | dns.dnssec.validate(abs_dsa_soa, abs_dsa_soa_rrsig, abs_dsa_keys, None, |
185 | 180 | when2) |
186 | 181 | |
187 | def testAbsoluteDSABad(self): # type: () -> None | |
188 | def bad(): # type: () -> None | |
182 | def testAbsoluteDSABad(self): # type: () -> None | |
183 | def bad(): # type: () -> None | |
189 | 184 | dns.dnssec.validate(abs_other_dsa_soa, abs_dsa_soa_rrsig, |
190 | 185 | abs_dsa_keys, None, when2) |
191 | self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) | |
192 | ||
193 | def testMakeExampleSHA1DS(self): # type: () -> None | |
194 | ds = dns.dnssec.make_ds(abs_example, example_sep_key, 'SHA1') | |
195 | self.failUnless(ds == example_ds_sha1) | |
196 | ||
197 | def testMakeExampleSHA256DS(self): # type: () -> None | |
198 | ds = dns.dnssec.make_ds(abs_example, example_sep_key, 'SHA256') | |
199 | self.failUnless(ds == example_ds_sha256) | |
200 | ||
201 | @unittest.skipUnless(dns.dnssec._have_ecdsa, | |
202 | "python ECDSA cannot be imported") | |
203 | def testAbsoluteECDSA256Good(self): # type: () -> None | |
186 | self.assertRaises(dns.dnssec.ValidationFailure, bad) | |
187 | ||
188 | @unittest.skipUnless(dns.dnssec._have_ecdsa, | |
189 | "python ECDSA cannot be imported") | |
190 | def testAbsoluteECDSA256Good(self): # type: () -> None | |
204 | 191 | dns.dnssec.validate(abs_ecdsa256_soa, abs_ecdsa256_soa_rrsig, |
205 | 192 | abs_ecdsa256_keys, None, when3) |
206 | 193 | |
207 | 194 | @unittest.skipUnless(dns.dnssec._have_ecdsa, |
208 | 195 | "python ECDSA cannot be imported") |
209 | def testAbsoluteECDSA256Bad(self): # type: () -> None | |
210 | def bad(): # type: () -> None | |
196 | def testAbsoluteECDSA256Bad(self): # type: () -> None | |
197 | def bad(): # type: () -> None | |
211 | 198 | dns.dnssec.validate(abs_other_ecdsa256_soa, abs_ecdsa256_soa_rrsig, |
212 | 199 | abs_ecdsa256_keys, None, when3) |
213 | self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) | |
214 | ||
215 | @unittest.skipUnless(dns.dnssec._have_ecdsa, | |
216 | "python ECDSA cannot be imported") | |
217 | def testAbsoluteECDSA384Good(self): # type: () -> None | |
200 | self.assertRaises(dns.dnssec.ValidationFailure, bad) | |
201 | ||
202 | @unittest.skipUnless(dns.dnssec._have_ecdsa, | |
203 | "python ECDSA cannot be imported") | |
204 | def testAbsoluteECDSA384Good(self): # type: () -> None | |
218 | 205 | dns.dnssec.validate(abs_ecdsa384_soa, abs_ecdsa384_soa_rrsig, |
219 | 206 | abs_ecdsa384_keys, None, when4) |
220 | 207 | |
221 | 208 | @unittest.skipUnless(dns.dnssec._have_ecdsa, |
222 | 209 | "python ECDSA cannot be imported") |
223 | def testAbsoluteECDSA384Bad(self): # type: () -> None | |
224 | def bad(): # type: () -> None | |
210 | def testAbsoluteECDSA384Bad(self): # type: () -> None | |
211 | def bad(): # type: () -> None | |
225 | 212 | dns.dnssec.validate(abs_other_ecdsa384_soa, abs_ecdsa384_soa_rrsig, |
226 | 213 | abs_ecdsa384_keys, None, when4) |
227 | self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) | |
214 | self.assertRaises(dns.dnssec.ValidationFailure, bad) | |
215 | ||
216 | ||
217 | class DNSSECMakeDSTestCase(unittest.TestCase): | |
218 | ||
219 | def testMakeExampleSHA1DS(self): # type: () -> None | |
220 | ds = dns.dnssec.make_ds(abs_example, example_sep_key, 'SHA1') | |
221 | self.assertTrue(ds == example_ds_sha1) | |
222 | ||
223 | def testMakeExampleSHA256DS(self): # type: () -> None | |
224 | ds = dns.dnssec.make_ds(abs_example, example_sep_key, 'SHA256') | |
225 | self.assertTrue(ds == example_ds_sha256) | |
226 | ||
227 | def testMakeSHA256DS(self): # type: () -> None | |
228 | ds = dns.dnssec.make_ds(abs_dnspython_org, sep_key, 'SHA256') | |
229 | self.assertTrue(ds == good_ds) | |
228 | 230 | |
229 | 231 | |
230 | 232 | if __name__ == '__main__': |
53 | 53 | data = io.getvalue() |
54 | 54 | self.assertEqual(data, b'\x00\x01\x18\x00\x01\x02\x03') |
55 | 55 | |
56 | def testECSOption25(self): | |
57 | opt = dns.edns.ECSOption('1.2.3.255', 25) | |
58 | io = BytesIO() | |
59 | opt.to_wire(io) | |
60 | data = io.getvalue() | |
61 | self.assertEqual(data, b'\x00\x01\x19\x00\x01\x02\x03\x80') | |
62 | ||
56 | 63 | def testECSOption_v6(self): |
57 | 64 | opt = dns.edns.ECSOption('2001:4b98::1') |
58 | 65 | io = BytesIO() |
59 | 66 | opt.to_wire(io) |
60 | 67 | data = io.getvalue() |
61 | 68 | self.assertEqual(data, b'\x00\x02\x38\x00\x20\x01\x4b\x98\x00\x00\x00') |
69 | ||
70 | def testECSOption_from_text_valid(self): | |
71 | ecs1 = dns.edns.ECSOption.from_text('1.2.3.4/24/0') | |
72 | self.assertEqual(ecs1, dns.edns.ECSOption('1.2.3.4', 24, 0)) | |
73 | ||
74 | ecs2 = dns.edns.ECSOption.from_text('1.2.3.4/24') | |
75 | self.assertEqual(ecs2, dns.edns.ECSOption('1.2.3.4', 24, 0)) | |
76 | ||
77 | ecs3 = dns.edns.ECSOption.from_text('ECS 1.2.3.4/24') | |
78 | self.assertEqual(ecs3, dns.edns.ECSOption('1.2.3.4', 24, 0)) | |
79 | ||
80 | ecs4 = dns.edns.ECSOption.from_text('ECS 1.2.3.4/24/32') | |
81 | self.assertEqual(ecs4, dns.edns.ECSOption('1.2.3.4', 24, 32)) | |
82 | ||
83 | ecs5 = dns.edns.ECSOption.from_text('2001:4b98::1/64/56') | |
84 | self.assertEqual(ecs5, dns.edns.ECSOption('2001:4b98::1', 64, 56)) | |
85 | ||
86 | ecs6 = dns.edns.ECSOption.from_text('2001:4b98::1/64') | |
87 | self.assertEqual(ecs6, dns.edns.ECSOption('2001:4b98::1', 64, 0)) | |
88 | ||
89 | ecs7 = dns.edns.ECSOption.from_text('ECS 2001:4b98::1/0') | |
90 | self.assertEqual(ecs7, dns.edns.ECSOption('2001:4b98::1', 0, 0)) | |
91 | ||
92 | ecs8 = dns.edns.ECSOption.from_text('ECS 2001:4b98::1/64/128') | |
93 | self.assertEqual(ecs8, dns.edns.ECSOption('2001:4b98::1', 64, 128)) | |
94 | ||
95 | def testECSOption_from_text_invalid(self): | |
96 | with self.assertRaises(ValueError): | |
97 | dns.edns.ECSOption.from_text('some random text 1.2.3.4/24/0 24') | |
98 | ||
99 | with self.assertRaises(ValueError): | |
100 | dns.edns.ECSOption.from_text('1.2.3.4/twentyfour') | |
101 | ||
102 | with self.assertRaises(ValueError): | |
103 | dns.edns.ECSOption.from_text('1.2.3.4/24/O') # <-- that's not a zero | |
104 | ||
105 | with self.assertRaises(ValueError): | |
106 | dns.edns.ECSOption.from_text('') | |
107 | ||
108 | with self.assertRaises(ValueError): | |
109 | dns.edns.ECSOption.from_text('1.2.3.4/2001:4b98::1/24') |
23 | 23 | class FlagsTestCase(unittest.TestCase): |
24 | 24 | |
25 | 25 | def test_rcode1(self): |
26 | self.failUnless(dns.rcode.from_text('FORMERR') == dns.rcode.FORMERR) | |
26 | self.assertTrue(dns.rcode.from_text('FORMERR') == dns.rcode.FORMERR) | |
27 | 27 | |
28 | 28 | def test_rcode2(self): |
29 | self.failUnless(dns.rcode.to_text(dns.rcode.FORMERR) == "FORMERR") | |
29 | self.assertTrue(dns.rcode.to_text(dns.rcode.FORMERR) == "FORMERR") | |
30 | 30 | |
31 | 31 | def test_rcode3(self): |
32 | self.failUnless(dns.rcode.to_flags(dns.rcode.FORMERR) == (1, 0)) | |
32 | self.assertTrue(dns.rcode.to_flags(dns.rcode.FORMERR) == (1, 0)) | |
33 | 33 | |
34 | 34 | def test_rcode4(self): |
35 | self.failUnless(dns.rcode.to_flags(dns.rcode.BADVERS) == \ | |
35 | self.assertTrue(dns.rcode.to_flags(dns.rcode.BADVERS) == \ | |
36 | 36 | (0, 0x01000000)) |
37 | 37 | |
38 | 38 | def test_rcode6(self): |
39 | self.failUnless(dns.rcode.from_flags(0, 0x01000000) == \ | |
39 | self.assertTrue(dns.rcode.from_flags(0, 0x01000000) == \ | |
40 | 40 | dns.rcode.BADVERS) |
41 | 41 | |
42 | 42 | def test_rcode7(self): |
43 | self.failUnless(dns.rcode.from_flags(5, 0) == dns.rcode.REFUSED) | |
43 | self.assertTrue(dns.rcode.from_flags(5, 0) == dns.rcode.REFUSED) | |
44 | 44 | |
45 | 45 | def test_rcode8(self): |
46 | 46 | def bad(): |
47 | 47 | dns.rcode.to_flags(4096) |
48 | self.failUnlessRaises(ValueError, bad) | |
48 | self.assertRaises(ValueError, bad) | |
49 | 49 | |
50 | 50 | def test_flags1(self): |
51 | self.failUnless(dns.flags.from_text("RA RD AA QR") == \ | |
51 | self.assertTrue(dns.flags.from_text("RA RD AA QR") == \ | |
52 | 52 | dns.flags.QR|dns.flags.AA|dns.flags.RD|dns.flags.RA) |
53 | 53 | |
54 | 54 | def test_flags2(self): |
55 | 55 | flags = dns.flags.QR|dns.flags.AA|dns.flags.RD|dns.flags.RA |
56 | self.failUnless(dns.flags.to_text(flags) == "QR AA RD RA") | |
56 | self.assertTrue(dns.flags.to_text(flags) == "QR AA RD RA") | |
57 | 57 | |
58 | 58 | |
59 | 59 | if __name__ == '__main__': |
25 | 25 | import dns.rdatatype |
26 | 26 | import dns.rrset |
27 | 27 | import dns.zone |
28 | from dns._compat import long | |
29 | ||
30 | 28 | import pprint |
31 | 29 | |
32 | 30 | |
132 | 130 | $GENERATE 27-28 $.2 PTR zlb${-26}.oob |
133 | 131 | """ |
134 | 132 | |
133 | example_text11 = """$TTL 1h | |
134 | @ 3600 IN SOA foo bar 1 2 3 4 5 | |
135 | @ 3600 IN NS ns1 | |
136 | @ 3600 IN NS ns2 | |
137 | bar.foo 300 IN MX 0 blaz.foo | |
138 | ns1 3600 IN A 10.0.0.1 | |
139 | ns2 3600 IN A 10.0.0.2 | |
140 | $GENERATE 27-28 prefix-${0,3} A 10.0.0.$ | |
141 | """ | |
142 | ||
143 | ||
135 | 144 | def _rdata_sort(a): |
136 | 145 | return (a[0], a[2].rdclass, a[2].to_text()) |
137 | 146 | |
141 | 150 | def testFromText(self): # type: () -> None |
142 | 151 | def bad(): # type: () -> None |
143 | 152 | dns.zone.from_text(example_text, 'example.', relativize=True) |
144 | self.failUnlessRaises(dns.zone.NoSOA, bad) | |
153 | self.assertRaises(dns.zone.NoSOA, bad) | |
145 | 154 | |
146 | 155 | def testFromText1(self): # type: () -> None |
147 | 156 | def bad(): # type: () -> None |
148 | 157 | dns.zone.from_text(example_text1, 'example.', relativize=True) |
149 | self.failUnlessRaises(dns.zone.NoSOA, bad) | |
158 | self.assertRaises(dns.zone.NoSOA, bad) | |
150 | 159 | |
151 | 160 | def testIterateAllRdatas2(self): # type: () -> None |
152 | 161 | z = dns.zone.from_text(example_text2, 'example.', relativize=True) |
190 | 199 | '10.0.0.5'))] |
191 | 200 | |
192 | 201 | exl.sort(key=_rdata_sort) |
193 | self.failUnless(l == exl) | |
202 | self.assertTrue(l == exl) | |
194 | 203 | |
195 | 204 | def testIterateAllRdatas3(self): # type: () -> None |
196 | 205 | z = dns.zone.from_text(example_text3, 'example.', relativize=True) |
230 | 239 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, |
231 | 240 | '10.0.0.8'))] |
232 | 241 | exl.sort(key=_rdata_sort) |
233 | self.failUnless(l == exl) | |
242 | self.assertTrue(l == exl) | |
234 | 243 | def testGenerate1(self): # type: () -> None |
235 | 244 | z = dns.zone.from_text(example_text4, 'example.', relativize=True) |
236 | 245 | l = list(z.iterate_rdatas()) |
237 | 246 | l.sort(key=_rdata_sort) |
238 | 247 | exl = [(dns.name.from_text('@', None), |
239 | long(3600), | |
240 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
241 | 'ns1')), | |
242 | (dns.name.from_text('@', None), | |
243 | long(3600), | |
244 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
245 | 'ns2')), | |
246 | (dns.name.from_text('@', None), | |
247 | long(3600), | |
248 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, | |
249 | 'foo bar 1 2 3 4 5')), | |
250 | (dns.name.from_text('bar.foo', None), | |
251 | long(300), | |
252 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, | |
253 | '0 blaz.foo')), | |
254 | (dns.name.from_text('ns1', None), | |
255 | long(3600), | |
256 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
257 | '10.0.0.1')), | |
258 | (dns.name.from_text('ns2', None), | |
259 | long(3600), | |
248 | 3600, | |
249 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
250 | 'ns1')), | |
251 | (dns.name.from_text('@', None), | |
252 | 3600, | |
253 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
254 | 'ns2')), | |
255 | (dns.name.from_text('@', None), | |
256 | 3600, | |
257 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, | |
258 | 'foo bar 1 2 3 4 5')), | |
259 | (dns.name.from_text('bar.foo', None), | |
260 | 300, | |
261 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, | |
262 | '0 blaz.foo')), | |
263 | (dns.name.from_text('ns1', None), | |
264 | 3600, | |
265 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
266 | '10.0.0.1')), | |
267 | (dns.name.from_text('ns2', None), | |
268 | 3600, | |
260 | 269 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, |
261 | 270 | '10.0.0.2')), |
262 | 271 | |
263 | 272 | (dns.name.from_text('wp-db01.services.mozilla.com', None), |
264 | long(0), | |
273 | 0, | |
265 | 274 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, |
266 | 275 | 'SERVER.FOOBAR.')), |
267 | 276 | |
268 | 277 | (dns.name.from_text('wp-db02.services.mozilla.com', None), |
269 | long(0), | |
278 | 0, | |
270 | 279 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, |
271 | 280 | 'SERVER.FOOBAR.')), |
272 | 281 | |
273 | 282 | (dns.name.from_text('wp-db03.services.mozilla.com', None), |
274 | long(0), | |
283 | 0, | |
275 | 284 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, |
276 | 285 | 'SERVER.FOOBAR.'))] |
277 | 286 | exl.sort(key=_rdata_sort) |
282 | 291 | l = list(z.iterate_rdatas()) |
283 | 292 | l.sort(key=_rdata_sort) |
284 | 293 | exl = [(dns.name.from_text('@', None), |
285 | long(3600), | |
286 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
287 | 'ns1')), | |
288 | (dns.name.from_text('@', None), | |
289 | long(3600), | |
290 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
291 | 'ns2')), | |
292 | (dns.name.from_text('@', None), | |
293 | long(3600), | |
294 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, | |
295 | 'foo bar 1 2 3 4 5')), | |
296 | (dns.name.from_text('bar.foo', None), | |
297 | long(300), | |
298 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, | |
299 | '0 blaz.foo')), | |
300 | (dns.name.from_text('ns1', None), | |
301 | long(3600), | |
302 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
303 | '10.0.0.1')), | |
304 | (dns.name.from_text('ns2', None), | |
305 | long(3600), | |
306 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
307 | '10.0.0.2')), | |
308 | ||
309 | (dns.name.from_text('wp-db21.services.mozilla.com', None), long(0), | |
294 | 3600, | |
295 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
296 | 'ns1')), | |
297 | (dns.name.from_text('@', None), | |
298 | 3600, | |
299 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
300 | 'ns2')), | |
301 | (dns.name.from_text('@', None), | |
302 | 3600, | |
303 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, | |
304 | 'foo bar 1 2 3 4 5')), | |
305 | (dns.name.from_text('bar.foo', None), | |
306 | 300, | |
307 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, | |
308 | '0 blaz.foo')), | |
309 | (dns.name.from_text('ns1', None), | |
310 | 3600, | |
311 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
312 | '10.0.0.1')), | |
313 | (dns.name.from_text('ns2', None), | |
314 | 3600, | |
315 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
316 | '10.0.0.2')), | |
317 | ||
318 | (dns.name.from_text('wp-db21.services.mozilla.com', None), 0, | |
310 | 319 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, |
311 | 320 | 'SERVER.FOOBAR.')), |
312 | 321 | |
313 | (dns.name.from_text('wp-db22.services.mozilla.com', None), long(0), | |
322 | (dns.name.from_text('wp-db22.services.mozilla.com', None), 0, | |
314 | 323 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, |
315 | 324 | 'SERVER.FOOBAR.')), |
316 | 325 | |
317 | (dns.name.from_text('wp-db23.services.mozilla.com', None), long(0), | |
326 | (dns.name.from_text('wp-db23.services.mozilla.com', None), 0, | |
318 | 327 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, |
319 | 328 | 'SERVER.FOOBAR.'))] |
320 | 329 | exl.sort(key=_rdata_sort) |
321 | self.failUnless(l == exl) | |
330 | self.assertTrue(l == exl) | |
322 | 331 | |
323 | 332 | def testGenerate3(self): # type: () -> None |
324 | 333 | z = dns.zone.from_text(example_text6, 'example.', relativize=True) |
326 | 335 | l.sort(key=_rdata_sort) |
327 | 336 | |
328 | 337 | exl = [(dns.name.from_text('@', None), |
329 | long(3600), | |
330 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
331 | 'ns1')), | |
332 | (dns.name.from_text('@', None), | |
333 | long(3600), | |
334 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
335 | 'ns2')), | |
336 | (dns.name.from_text('@', None), | |
337 | long(3600), | |
338 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, | |
339 | 'foo bar 1 2 3 4 5')), | |
340 | (dns.name.from_text('bar.foo', None), | |
341 | long(300), | |
342 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, | |
343 | '0 blaz.foo')), | |
344 | (dns.name.from_text('ns1', None), | |
345 | long(3600), | |
346 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
347 | '10.0.0.1')), | |
348 | (dns.name.from_text('ns2', None), | |
349 | long(3600), | |
350 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
351 | '10.0.0.2')), | |
352 | (dns.name.from_text('wp-db21.services.mozilla.com', None), long(0), | |
338 | 3600, | |
339 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
340 | 'ns1')), | |
341 | (dns.name.from_text('@', None), | |
342 | 3600, | |
343 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
344 | 'ns2')), | |
345 | (dns.name.from_text('@', None), | |
346 | 3600, | |
347 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, | |
348 | 'foo bar 1 2 3 4 5')), | |
349 | (dns.name.from_text('bar.foo', None), | |
350 | 300, | |
351 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, | |
352 | '0 blaz.foo')), | |
353 | (dns.name.from_text('ns1', None), | |
354 | 3600, | |
355 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
356 | '10.0.0.1')), | |
357 | (dns.name.from_text('ns2', None), | |
358 | 3600, | |
359 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
360 | '10.0.0.2')), | |
361 | (dns.name.from_text('wp-db21.services.mozilla.com', None), 0, | |
353 | 362 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, |
354 | 363 | 'SERVER.FOOBAR.')), |
355 | 364 | |
356 | (dns.name.from_text('wp-db22.services.mozilla.com', None), long(0), | |
365 | (dns.name.from_text('wp-db22.services.mozilla.com', None), 0, | |
357 | 366 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, |
358 | 367 | 'SERVER.FOOBAR.')), |
359 | 368 | |
360 | (dns.name.from_text('wp-db23.services.mozilla.com', None), long(0), | |
369 | (dns.name.from_text('wp-db23.services.mozilla.com', None), 0, | |
361 | 370 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, |
362 | 371 | 'SERVER.FOOBAR.'))] |
363 | 372 | exl.sort(key=_rdata_sort) |
364 | self.failUnless(l == exl) | |
373 | self.assertTrue(l == exl) | |
365 | 374 | |
366 | 375 | def testGenerate4(self): # type: () -> None |
367 | 376 | z = dns.zone.from_text(example_text7, 'example.', relativize=True) |
368 | 377 | l = list(z.iterate_rdatas()) |
369 | 378 | l.sort(key=_rdata_sort) |
370 | 379 | exl = [(dns.name.from_text('@', None), |
371 | long(3600), | |
372 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
373 | 'ns1')), | |
374 | (dns.name.from_text('@', None), | |
375 | long(3600), | |
376 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
377 | 'ns2')), | |
378 | (dns.name.from_text('@', None), | |
379 | long(3600), | |
380 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, | |
381 | 'foo bar 1 2 3 4 5')), | |
382 | (dns.name.from_text('bar.foo', None), | |
383 | long(300), | |
384 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, | |
385 | '0 blaz.foo')), | |
386 | (dns.name.from_text('ns1', None), | |
387 | long(3600), | |
388 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
389 | '10.0.0.1')), | |
390 | (dns.name.from_text('ns2', None), | |
391 | long(3600), | |
392 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
393 | '10.0.0.2')), | |
394 | ||
395 | (dns.name.from_text('sync1.db', None), long(3600), | |
380 | 3600, | |
381 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
382 | 'ns1')), | |
383 | (dns.name.from_text('@', None), | |
384 | 3600, | |
385 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
386 | 'ns2')), | |
387 | (dns.name.from_text('@', None), | |
388 | 3600, | |
389 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, | |
390 | 'foo bar 1 2 3 4 5')), | |
391 | (dns.name.from_text('bar.foo', None), | |
392 | 300, | |
393 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, | |
394 | '0 blaz.foo')), | |
395 | (dns.name.from_text('ns1', None), | |
396 | 3600, | |
397 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
398 | '10.0.0.1')), | |
399 | (dns.name.from_text('ns2', None), | |
400 | 3600, | |
401 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
402 | '10.0.0.2')), | |
403 | ||
404 | (dns.name.from_text('sync1.db', None), 3600, | |
396 | 405 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, |
397 | 406 | '10.10.16.0')), |
398 | 407 | |
399 | (dns.name.from_text('sync2.db', None), long(3600), | |
408 | (dns.name.from_text('sync2.db', None), 3600, | |
400 | 409 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, |
401 | 410 | '10.10.16.0')), |
402 | 411 | |
403 | (dns.name.from_text('sync3.db', None), long(3600), | |
412 | (dns.name.from_text('sync3.db', None), 3600, | |
404 | 413 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, |
405 | 414 | '10.10.16.0'))] |
406 | 415 | exl.sort(key=_rdata_sort) |
407 | self.failUnless(l == exl) | |
416 | self.assertTrue(l == exl) | |
408 | 417 | |
409 | 418 | def testGenerate6(self): # type: () -> None |
410 | 419 | z = dns.zone.from_text(example_text9, 'example.', relativize=True) |
411 | 420 | l = list(z.iterate_rdatas()) |
412 | 421 | l.sort(key=_rdata_sort) |
413 | 422 | exl = [(dns.name.from_text('@', None), |
414 | long(3600), | |
415 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
416 | 'ns1')), | |
417 | (dns.name.from_text('@', None), | |
418 | long(3600), | |
419 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
420 | 'ns2')), | |
421 | (dns.name.from_text('@', None), | |
422 | long(3600), | |
423 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, | |
424 | 'foo bar 1 2 3 4 5')), | |
425 | (dns.name.from_text('bar.foo', None), | |
426 | long(300), | |
427 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, | |
428 | '0 blaz.foo')), | |
429 | (dns.name.from_text('ns1', None), | |
430 | long(3600), | |
431 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
432 | '10.0.0.1')), | |
433 | (dns.name.from_text('ns2', None), | |
434 | long(3600), | |
435 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
436 | '10.0.0.2')), | |
437 | ||
438 | (dns.name.from_text('wp-db01', None), long(3600), | |
423 | 3600, | |
424 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
425 | 'ns1')), | |
426 | (dns.name.from_text('@', None), | |
427 | 3600, | |
428 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
429 | 'ns2')), | |
430 | (dns.name.from_text('@', None), | |
431 | 3600, | |
432 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, | |
433 | 'foo bar 1 2 3 4 5')), | |
434 | (dns.name.from_text('bar.foo', None), | |
435 | 300, | |
436 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, | |
437 | '0 blaz.foo')), | |
438 | (dns.name.from_text('ns1', None), | |
439 | 3600, | |
440 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
441 | '10.0.0.1')), | |
442 | (dns.name.from_text('ns2', None), | |
443 | 3600, | |
444 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
445 | '10.0.0.2')), | |
446 | ||
447 | (dns.name.from_text('wp-db01', None), 3600, | |
439 | 448 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, |
440 | 449 | '10.10.16.0')), |
441 | (dns.name.from_text('wp-db02', None), long(3600), | |
450 | (dns.name.from_text('wp-db02', None), 3600, | |
442 | 451 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, |
443 | 452 | '10.10.16.0')), |
444 | 453 | |
445 | (dns.name.from_text('sync1.db', None), long(3600), | |
454 | (dns.name.from_text('sync1.db', None), 3600, | |
446 | 455 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, |
447 | 456 | '10.10.16.0')), |
448 | 457 | |
449 | (dns.name.from_text('sync2.db', None), long(3600), | |
458 | (dns.name.from_text('sync2.db', None), 3600, | |
450 | 459 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, |
451 | 460 | '10.10.16.0')), |
452 | 461 | |
453 | (dns.name.from_text('sync3.db', None), long(3600), | |
462 | (dns.name.from_text('sync3.db', None), 3600, | |
454 | 463 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, |
455 | 464 | '10.10.16.0'))] |
456 | 465 | exl.sort(key=_rdata_sort) |
457 | self.failUnless(l == exl) | |
466 | self.assertTrue(l == exl) | |
458 | 467 | |
459 | 468 | def testGenerate7(self): # type: () -> None |
460 | 469 | z = dns.zone.from_text(example_text10, 'example.', relativize=True) |
461 | 470 | l = list(z.iterate_rdatas()) |
462 | 471 | l.sort(key=_rdata_sort) |
463 | 472 | exl = [(dns.name.from_text('@', None), |
464 | long(3600), | |
465 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
466 | 'ns1')), | |
467 | (dns.name.from_text('@', None), | |
468 | long(3600), | |
469 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
470 | 'ns2')), | |
471 | (dns.name.from_text('@', None), | |
472 | long(3600), | |
473 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, | |
474 | 'foo bar 1 2 3 4 5')), | |
475 | (dns.name.from_text('bar.foo', None), | |
476 | long(300), | |
477 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, | |
478 | '0 blaz.foo')), | |
479 | (dns.name.from_text('ns1', None), | |
480 | long(3600), | |
481 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
482 | '10.0.0.1')), | |
483 | (dns.name.from_text('ns2', None), | |
484 | long(3600), | |
485 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
486 | '10.0.0.2')), | |
487 | ||
488 | (dns.name.from_text('27.2', None), long(3600), | |
473 | 3600, | |
474 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
475 | 'ns1')), | |
476 | (dns.name.from_text('@', None), | |
477 | 3600, | |
478 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
479 | 'ns2')), | |
480 | (dns.name.from_text('@', None), | |
481 | 3600, | |
482 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, | |
483 | 'foo bar 1 2 3 4 5')), | |
484 | (dns.name.from_text('bar.foo', None), | |
485 | 300, | |
486 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, | |
487 | '0 blaz.foo')), | |
488 | (dns.name.from_text('ns1', None), | |
489 | 3600, | |
490 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
491 | '10.0.0.1')), | |
492 | (dns.name.from_text('ns2', None), | |
493 | 3600, | |
494 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
495 | '10.0.0.2')), | |
496 | ||
497 | (dns.name.from_text('27.2', None), 3600, | |
489 | 498 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.PTR, |
490 | 499 | 'zlb1.oob')), |
491 | 500 | |
492 | (dns.name.from_text('28.2', None), long(3600), | |
501 | (dns.name.from_text('28.2', None), 3600, | |
493 | 502 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.PTR, |
494 | 503 | 'zlb2.oob'))] |
495 | 504 | |
496 | 505 | exl.sort(key=_rdata_sort) |
497 | self.failUnless(l == exl) | |
506 | self.assertTrue(l == exl) | |
507 | ||
508 | def testGenerate8(self): # type: () -> None | |
509 | z = dns.zone.from_text(example_text11, 'example.', relativize=True) | |
510 | l = list(z.iterate_rdatas()) | |
511 | l.sort(key=_rdata_sort) | |
512 | exl = [(dns.name.from_text('@', None), | |
513 | 3600, | |
514 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
515 | 'ns1')), | |
516 | (dns.name.from_text('@', None), | |
517 | 3600, | |
518 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, | |
519 | 'ns2')), | |
520 | (dns.name.from_text('@', None), | |
521 | 3600, | |
522 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, | |
523 | 'foo bar 1 2 3 4 5')), | |
524 | (dns.name.from_text('bar.foo', None), | |
525 | 300, | |
526 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, | |
527 | '0 blaz.foo')), | |
528 | ||
529 | (dns.name.from_text('prefix-027', None), 3600, | |
530 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
531 | '10.0.0.27')), | |
532 | ||
533 | (dns.name.from_text('prefix-028', None), 3600, | |
534 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
535 | '10.0.0.28')), | |
536 | ||
537 | (dns.name.from_text('ns1', None), | |
538 | 3600, | |
539 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
540 | '10.0.0.1')), | |
541 | (dns.name.from_text('ns2', None), | |
542 | 3600, | |
543 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, | |
544 | '10.0.0.2'))] | |
545 | ||
546 | exl.sort(key=_rdata_sort) | |
547 | self.assertTrue(l == exl) | |
498 | 548 | |
499 | 549 | |
500 | 550 | if __name__ == '__main__': |
23 | 23 | import dns.name |
24 | 24 | import dns.rdataclass |
25 | 25 | import dns.rdatatype |
26 | from dns._compat import xrange | |
27 | 26 | |
28 | 27 | query_text = """id 1234 |
29 | 28 | opcode QUERY |
96 | 95 | def test_comparison_eq1(self): |
97 | 96 | q1 = dns.message.from_text(query_text) |
98 | 97 | q2 = dns.message.from_text(query_text) |
99 | self.failUnless(q1 == q2) | |
98 | self.assertTrue(q1 == q2) | |
100 | 99 | |
101 | 100 | def test_comparison_ne1(self): |
102 | 101 | q1 = dns.message.from_text(query_text) |
103 | 102 | q2 = dns.message.from_text(query_text) |
104 | 103 | q2.id = 10 |
105 | self.failUnless(q1 != q2) | |
104 | self.assertTrue(q1 != q2) | |
106 | 105 | |
107 | 106 | def test_comparison_ne2(self): |
108 | 107 | q1 = dns.message.from_text(query_text) |
109 | 108 | q2 = dns.message.from_text(query_text) |
110 | 109 | q2.question = [] |
111 | self.failUnless(q1 != q2) | |
110 | self.assertTrue(q1 != q2) | |
112 | 111 | |
113 | 112 | def test_comparison_ne3(self): |
114 | 113 | q1 = dns.message.from_text(query_text) |
115 | self.failUnless(q1 != 1) | |
114 | self.assertTrue(q1 != 1) | |
116 | 115 | |
117 | 116 | def test_EDNS_to_wire1(self): |
118 | 117 | q = dns.message.from_text(query_text) |
119 | 118 | w = q.to_wire() |
120 | self.failUnless(w == goodwire) | |
119 | self.assertTrue(w == goodwire) | |
121 | 120 | |
122 | 121 | def test_EDNS_from_wire1(self): |
123 | 122 | m = dns.message.from_wire(goodwire) |
126 | 125 | def test_EDNS_to_wire2(self): |
127 | 126 | q = dns.message.from_text(query_text_2) |
128 | 127 | w = q.to_wire() |
129 | self.failUnless(w == goodwire3) | |
128 | self.assertTrue(w == goodwire3) | |
130 | 129 | |
131 | 130 | def test_EDNS_from_wire2(self): |
132 | 131 | m = dns.message.from_wire(goodwire3) |
133 | self.failUnless(str(m) == query_text_2) | |
132 | self.assertTrue(str(m) == query_text_2) | |
134 | 133 | |
135 | 134 | def test_TooBig(self): |
136 | 135 | def bad(): |
137 | 136 | q = dns.message.from_text(query_text) |
138 | for i in xrange(0, 25): | |
137 | for i in range(0, 25): | |
139 | 138 | rrset = dns.rrset.from_text('foo%d.' % i, 3600, |
140 | 139 | dns.rdataclass.IN, |
141 | 140 | dns.rdatatype.A, |
142 | 141 | '10.0.0.%d' % i) |
143 | 142 | q.additional.append(rrset) |
144 | 143 | q.to_wire(max_size=512) |
145 | self.failUnlessRaises(dns.exception.TooBig, bad) | |
144 | self.assertRaises(dns.exception.TooBig, bad) | |
146 | 145 | |
147 | 146 | def test_answer1(self): |
148 | 147 | a = dns.message.from_text(answer_text) |
149 | 148 | wire = a.to_wire(want_shuffle=False) |
150 | self.failUnless(wire == goodwire2) | |
149 | self.assertTrue(wire == goodwire2) | |
151 | 150 | |
152 | 151 | def test_TrailingJunk(self): |
153 | 152 | def bad(): |
154 | 153 | badwire = goodwire + b'\x00' |
155 | 154 | dns.message.from_wire(badwire) |
156 | self.failUnlessRaises(dns.message.TrailingJunk, bad) | |
155 | self.assertRaises(dns.message.TrailingJunk, bad) | |
157 | 156 | |
158 | 157 | def test_ShortHeader(self): |
159 | 158 | def bad(): |
160 | 159 | badwire = b'\x00' * 11 |
161 | 160 | dns.message.from_wire(badwire) |
162 | self.failUnlessRaises(dns.message.ShortHeader, bad) | |
161 | self.assertRaises(dns.message.ShortHeader, bad) | |
163 | 162 | |
164 | 163 | def test_RespondingToResponse(self): |
165 | 164 | def bad(): |
166 | 165 | q = dns.message.make_query('foo', 'A') |
167 | 166 | r1 = dns.message.make_response(q) |
168 | 167 | dns.message.make_response(r1) |
169 | self.failUnlessRaises(dns.exception.FormError, bad) | |
168 | self.assertRaises(dns.exception.FormError, bad) | |
170 | 169 | |
171 | 170 | def test_ExtendedRcodeSetting(self): |
172 | 171 | m = dns.message.make_query('foo', 'A') |
173 | 172 | m.set_rcode(4095) |
174 | self.failUnless(m.rcode() == 4095) | |
173 | self.assertTrue(m.rcode() == 4095) | |
175 | 174 | m.set_rcode(2) |
176 | self.failUnless(m.rcode() == 2) | |
175 | self.assertTrue(m.rcode() == 2) | |
177 | 176 | |
178 | 177 | def test_EDNSVersionCoherence(self): |
179 | 178 | m = dns.message.make_query('foo', 'A') |
180 | 179 | m.use_edns(1) |
181 | self.failUnless((m.ednsflags >> 16) & 0xFF == 1) | |
180 | self.assertTrue((m.ednsflags >> 16) & 0xFF == 1) | |
182 | 181 | |
183 | 182 | def test_SettingNoEDNSOptionsImpliesNoEDNS(self): |
184 | 183 | m = dns.message.make_query('foo', 'A') |
185 | self.failUnless(m.edns == -1) | |
184 | self.assertTrue(m.edns == -1) | |
186 | 185 | |
187 | 186 | def test_SettingEDNSFlagsImpliesEDNS(self): |
188 | 187 | m = dns.message.make_query('foo', 'A', ednsflags=dns.flags.DO) |
189 | self.failUnless(m.edns == 0) | |
188 | self.assertTrue(m.edns == 0) | |
190 | 189 | |
191 | 190 | def test_SettingEDNSPayloadImpliesEDNS(self): |
192 | 191 | m = dns.message.make_query('foo', 'A', payload=4096) |
193 | self.failUnless(m.edns == 0) | |
192 | self.assertTrue(m.edns == 0) | |
194 | 193 | |
195 | 194 | def test_SettingEDNSRequestPayloadImpliesEDNS(self): |
196 | 195 | m = dns.message.make_query('foo', 'A', request_payload=4096) |
197 | self.failUnless(m.edns == 0) | |
196 | self.assertTrue(m.edns == 0) | |
198 | 197 | |
199 | 198 | def test_SettingOptionsImpliesEDNS(self): |
200 | 199 | m = dns.message.make_query('foo', 'A', options=[]) |
201 | self.failUnless(m.edns == 0) | |
200 | self.assertTrue(m.edns == 0) | |
202 | 201 | |
203 | 202 | def test_FindRRset(self): |
204 | 203 | a = dns.message.from_text(answer_text) |
206 | 205 | rrs1 = a.find_rrset(a.answer, n, dns.rdataclass.IN, dns.rdatatype.SOA) |
207 | 206 | rrs2 = a.find_rrset(dns.message.ANSWER, n, dns.rdataclass.IN, |
208 | 207 | dns.rdatatype.SOA) |
209 | self.failUnless(rrs1 == rrs2) | |
208 | self.assertTrue(rrs1 == rrs2) | |
209 | ||
210 | def test_CleanTruncated(self): | |
211 | def bad(): | |
212 | a = dns.message.from_text(answer_text) | |
213 | a.flags |= dns.flags.TC | |
214 | wire = a.to_wire(want_shuffle=False) | |
215 | dns.message.from_wire(wire) | |
216 | self.assertRaises(dns.message.Truncated, bad) | |
217 | ||
218 | def test_MessyTruncated(self): | |
219 | def bad(): | |
220 | a = dns.message.from_text(answer_text) | |
221 | a.flags |= dns.flags.TC | |
222 | wire = a.to_wire(want_shuffle=False) | |
223 | dns.message.from_wire(wire[:-3]) | |
224 | self.assertRaises(dns.message.Truncated, bad) | |
210 | 225 | |
211 | 226 | if __name__ == '__main__': |
212 | 227 | unittest.main() |
47 | 47 | |
48 | 48 | def testFromTextRel4(self): |
49 | 49 | n = dns.name.from_text('@', origin=None) |
50 | self.failUnless(n == dns.name.empty) | |
50 | self.assertTrue(n == dns.name.empty) | |
51 | 51 | |
52 | 52 | def testFromTextRel5(self): |
53 | 53 | n = dns.name.from_text('@', origin=self.origin) |
54 | self.failUnless(n == self.origin) | |
54 | self.assertTrue(n == self.origin) | |
55 | 55 | |
56 | 56 | def testFromTextAbs1(self): |
57 | 57 | n = dns.name.from_text('foo.bar.') |
100 | 100 | def testImmutable1(self): |
101 | 101 | def bad(): |
102 | 102 | self.origin.labels = () |
103 | self.failUnlessRaises(TypeError, bad) | |
103 | self.assertRaises(TypeError, bad) | |
104 | 104 | |
105 | 105 | def testImmutable2(self): |
106 | 106 | def bad(): |
107 | 107 | self.origin.labels[0] = 'foo' |
108 | self.failUnlessRaises(TypeError, bad) | |
108 | self.assertRaises(TypeError, bad) | |
109 | 109 | |
110 | 110 | def testAbs1(self): |
111 | self.failUnless(dns.name.root.is_absolute()) | |
111 | self.assertTrue(dns.name.root.is_absolute()) | |
112 | 112 | |
113 | 113 | def testAbs2(self): |
114 | self.failUnless(not dns.name.empty.is_absolute()) | |
114 | self.assertTrue(not dns.name.empty.is_absolute()) | |
115 | 115 | |
116 | 116 | def testAbs3(self): |
117 | self.failUnless(self.origin.is_absolute()) | |
117 | self.assertTrue(self.origin.is_absolute()) | |
118 | 118 | |
119 | 119 | def testAbs4(self): |
120 | 120 | n = dns.name.from_text('foo', origin=None) |
121 | self.failUnless(not n.is_absolute()) | |
121 | self.assertTrue(not n.is_absolute()) | |
122 | 122 | |
123 | 123 | def testWild1(self): |
124 | 124 | n = dns.name.from_text('*.foo', origin=None) |
125 | self.failUnless(n.is_wild()) | |
125 | self.assertTrue(n.is_wild()) | |
126 | 126 | |
127 | 127 | def testWild2(self): |
128 | 128 | n = dns.name.from_text('*a.foo', origin=None) |
129 | self.failUnless(not n.is_wild()) | |
129 | self.assertTrue(not n.is_wild()) | |
130 | 130 | |
131 | 131 | def testWild3(self): |
132 | 132 | n = dns.name.from_text('a.*.foo', origin=None) |
133 | self.failUnless(not n.is_wild()) | |
133 | self.assertTrue(not n.is_wild()) | |
134 | 134 | |
135 | 135 | def testWild4(self): |
136 | self.failUnless(not dns.name.root.is_wild()) | |
136 | self.assertTrue(not dns.name.root.is_wild()) | |
137 | 137 | |
138 | 138 | def testWild5(self): |
139 | self.failUnless(not dns.name.empty.is_wild()) | |
139 | self.assertTrue(not dns.name.empty.is_wild()) | |
140 | 140 | |
141 | 141 | def testHash1(self): |
142 | 142 | n1 = dns.name.from_text('fOo.COM') |
146 | 146 | def testCompare1(self): |
147 | 147 | n1 = dns.name.from_text('a') |
148 | 148 | n2 = dns.name.from_text('b') |
149 | self.failUnless(n1 < n2) | |
150 | self.failUnless(n2 > n1) | |
149 | self.assertTrue(n1 < n2) | |
150 | self.assertTrue(n2 > n1) | |
151 | 151 | |
152 | 152 | def testCompare2(self): |
153 | 153 | n1 = dns.name.from_text('') |
154 | 154 | n2 = dns.name.from_text('b') |
155 | self.failUnless(n1 < n2) | |
156 | self.failUnless(n2 > n1) | |
155 | self.assertTrue(n1 < n2) | |
156 | self.assertTrue(n2 > n1) | |
157 | 157 | |
158 | 158 | def testCompare3(self): |
159 | self.failUnless(dns.name.empty < dns.name.root) | |
160 | self.failUnless(dns.name.root > dns.name.empty) | |
159 | self.assertTrue(dns.name.empty < dns.name.root) | |
160 | self.assertTrue(dns.name.root > dns.name.empty) | |
161 | 161 | |
162 | 162 | def testCompare4(self): |
163 | self.failUnless(dns.name.root != 1) | |
163 | self.assertTrue(dns.name.root != 1) | |
164 | 164 | |
165 | 165 | def testSubdomain1(self): |
166 | self.failUnless(not dns.name.empty.is_subdomain(dns.name.root)) | |
166 | self.assertTrue(not dns.name.empty.is_subdomain(dns.name.root)) | |
167 | 167 | |
168 | 168 | def testSubdomain2(self): |
169 | self.failUnless(not dns.name.root.is_subdomain(dns.name.empty)) | |
169 | self.assertTrue(not dns.name.root.is_subdomain(dns.name.empty)) | |
170 | 170 | |
171 | 171 | def testSubdomain3(self): |
172 | 172 | n = dns.name.from_text('foo', origin=self.origin) |
173 | self.failUnless(n.is_subdomain(self.origin)) | |
173 | self.assertTrue(n.is_subdomain(self.origin)) | |
174 | 174 | |
175 | 175 | def testSubdomain4(self): |
176 | 176 | n = dns.name.from_text('foo', origin=self.origin) |
177 | self.failUnless(n.is_subdomain(dns.name.root)) | |
177 | self.assertTrue(n.is_subdomain(dns.name.root)) | |
178 | 178 | |
179 | 179 | def testSubdomain5(self): |
180 | 180 | n = dns.name.from_text('foo', origin=self.origin) |
181 | self.failUnless(n.is_subdomain(n)) | |
181 | self.assertTrue(n.is_subdomain(n)) | |
182 | 182 | |
183 | 183 | def testSuperdomain1(self): |
184 | self.failUnless(not dns.name.empty.is_superdomain(dns.name.root)) | |
184 | self.assertTrue(not dns.name.empty.is_superdomain(dns.name.root)) | |
185 | 185 | |
186 | 186 | def testSuperdomain2(self): |
187 | self.failUnless(not dns.name.root.is_superdomain(dns.name.empty)) | |
187 | self.assertTrue(not dns.name.root.is_superdomain(dns.name.empty)) | |
188 | 188 | |
189 | 189 | def testSuperdomain3(self): |
190 | 190 | n = dns.name.from_text('foo', origin=self.origin) |
191 | self.failUnless(self.origin.is_superdomain(n)) | |
191 | self.assertTrue(self.origin.is_superdomain(n)) | |
192 | 192 | |
193 | 193 | def testSuperdomain4(self): |
194 | 194 | n = dns.name.from_text('foo', origin=self.origin) |
195 | self.failUnless(dns.name.root.is_superdomain(n)) | |
195 | self.assertTrue(dns.name.root.is_superdomain(n)) | |
196 | 196 | |
197 | 197 | def testSuperdomain5(self): |
198 | 198 | n = dns.name.from_text('foo', origin=self.origin) |
199 | self.failUnless(n.is_superdomain(n)) | |
199 | self.assertTrue(n.is_superdomain(n)) | |
200 | 200 | |
201 | 201 | def testCanonicalize1(self): |
202 | 202 | n = dns.name.from_text('FOO.bar', origin=self.origin) |
234 | 234 | def testToText7(self): |
235 | 235 | n = dns.name.from_text(r'FOO\.bar', origin=None) |
236 | 236 | t = n.to_text() |
237 | self.assertEqual(t, 'FOO\.bar') | |
237 | self.assertEqual(t, r'FOO\.bar') | |
238 | 238 | |
239 | 239 | def testToText8(self): |
240 | 240 | n = dns.name.from_text(r'\070OO\.bar', origin=None) |
241 | 241 | t = n.to_text() |
242 | self.assertEqual(t, 'FOO\.bar') | |
242 | self.assertEqual(t, r'FOO\.bar') | |
243 | 243 | |
244 | 244 | def testToText9(self): |
245 | 245 | n = dns.name.from_text('FOO bar', origin=None) |
254 | 254 | t = dns.name.root.to_unicode() |
255 | 255 | self.assertEqual(t, '.') |
256 | 256 | |
257 | def testToText12(self): | |
258 | n = dns.name.from_text(r'a\.b.c') | |
259 | t = n.to_unicode() | |
260 | self.assertEqual(t, r'a\.b.c.') | |
261 | ||
262 | def testToText13(self): | |
263 | n = dns.name.from_text(r'\150\151\152\153\154\155\156\157\158\159.') | |
264 | t = n.to_text() | |
265 | self.assertEqual(t, r'\150\151\152\153\154\155\156\157\158\159.') | |
266 | ||
267 | def testToText14(self): | |
268 | # Something that didn't start as unicode should go to escapes and not | |
269 | # raise due to interpreting arbitrary binary DNS labels as UTF-8. | |
270 | n = dns.name.from_text(r'\150\151\152\153\154\155\156\157\158\159.') | |
271 | t = n.to_unicode() | |
272 | self.assertEqual(t, r'\150\151\152\153\154\155\156\157\158\159.') | |
273 | ||
257 | 274 | def testSlice1(self): |
258 | 275 | n = dns.name.from_text(r'a.b.c.', origin=None) |
259 | 276 | s = n[:] |
272 | 289 | def testEmptyLabel1(self): |
273 | 290 | def bad(): |
274 | 291 | dns.name.Name(['a', '', 'b']) |
275 | self.failUnlessRaises(dns.name.EmptyLabel, bad) | |
292 | self.assertRaises(dns.name.EmptyLabel, bad) | |
276 | 293 | |
277 | 294 | def testEmptyLabel2(self): |
278 | 295 | def bad(): |
279 | 296 | dns.name.Name(['', 'b']) |
280 | self.failUnlessRaises(dns.name.EmptyLabel, bad) | |
297 | self.assertRaises(dns.name.EmptyLabel, bad) | |
281 | 298 | |
282 | 299 | def testEmptyLabel3(self): |
283 | 300 | n = dns.name.Name(['b', '']) |
284 | self.failUnless(n) | |
301 | self.assertTrue(n) | |
285 | 302 | |
286 | 303 | def testLongLabel(self): |
287 | 304 | n = dns.name.Name(['a' * 63]) |
288 | self.failUnless(n) | |
305 | self.assertTrue(n) | |
289 | 306 | |
290 | 307 | def testLabelTooLong(self): |
291 | 308 | def bad(): |
292 | 309 | dns.name.Name(['a' * 64, 'b']) |
293 | self.failUnlessRaises(dns.name.LabelTooLong, bad) | |
310 | self.assertRaises(dns.name.LabelTooLong, bad) | |
294 | 311 | |
295 | 312 | def testLongName(self): |
296 | 313 | n = dns.name.Name(['a' * 63, 'a' * 63, 'a' * 63, 'a' * 62]) |
297 | self.failUnless(n) | |
314 | self.assertTrue(n) | |
298 | 315 | |
299 | 316 | def testNameTooLong(self): |
300 | 317 | def bad(): |
301 | 318 | dns.name.Name(['a' * 63, 'a' * 63, 'a' * 63, 'a' * 63]) |
302 | self.failUnlessRaises(dns.name.NameTooLong, bad) | |
319 | self.assertRaises(dns.name.NameTooLong, bad) | |
303 | 320 | |
304 | 321 | def testConcat1(self): |
305 | 322 | n1 = dns.name.Name(['a', 'b']) |
306 | 323 | n2 = dns.name.Name(['c', 'd']) |
307 | 324 | e = dns.name.Name(['a', 'b', 'c', 'd']) |
308 | 325 | r = n1 + n2 |
309 | self.failUnless(r == e) | |
326 | self.assertTrue(r == e) | |
310 | 327 | |
311 | 328 | def testConcat2(self): |
312 | 329 | n1 = dns.name.Name(['a', 'b']) |
313 | 330 | n2 = dns.name.Name([]) |
314 | 331 | e = dns.name.Name(['a', 'b']) |
315 | 332 | r = n1 + n2 |
316 | self.failUnless(r == e) | |
333 | self.assertTrue(r == e) | |
317 | 334 | |
318 | 335 | def testConcat3(self): |
319 | 336 | n1 = dns.name.Name([]) |
320 | 337 | n2 = dns.name.Name(['a', 'b']) |
321 | 338 | e = dns.name.Name(['a', 'b']) |
322 | 339 | r = n1 + n2 |
323 | self.failUnless(r == e) | |
340 | self.assertTrue(r == e) | |
324 | 341 | |
325 | 342 | def testConcat4(self): |
326 | 343 | n1 = dns.name.Name(['a', 'b', '']) |
327 | 344 | n2 = dns.name.Name([]) |
328 | 345 | e = dns.name.Name(['a', 'b', '']) |
329 | 346 | r = n1 + n2 |
330 | self.failUnless(r == e) | |
347 | self.assertTrue(r == e) | |
331 | 348 | |
332 | 349 | def testConcat5(self): |
333 | 350 | n1 = dns.name.Name(['a', 'b']) |
334 | 351 | n2 = dns.name.Name(['c', '']) |
335 | 352 | e = dns.name.Name(['a', 'b', 'c', '']) |
336 | 353 | r = n1 + n2 |
337 | self.failUnless(r == e) | |
354 | self.assertTrue(r == e) | |
338 | 355 | |
339 | 356 | def testConcat6(self): |
340 | 357 | def bad(): |
341 | 358 | n1 = dns.name.Name(['a', 'b', '']) |
342 | 359 | n2 = dns.name.Name(['c']) |
343 | 360 | return n1 + n2 |
344 | self.failUnlessRaises(dns.name.AbsoluteConcatenation, bad) | |
361 | self.assertRaises(dns.name.AbsoluteConcatenation, bad) | |
345 | 362 | |
346 | 363 | def testBadEscape(self): |
347 | 364 | def bad(): |
348 | 365 | n = dns.name.from_text(r'a.b\0q1.c.') |
349 | 366 | print(n) |
350 | self.failUnlessRaises(dns.name.BadEscape, bad) | |
367 | self.assertRaises(dns.name.BadEscape, bad) | |
351 | 368 | |
352 | 369 | def testDigestable1(self): |
353 | 370 | n = dns.name.from_text('FOO.bar') |
359 | 376 | n2 = dns.name.from_text('foo.BAR.') |
360 | 377 | d1 = n1.to_digestable() |
361 | 378 | d2 = n2.to_digestable() |
362 | self.failUnless(d1 == d2) | |
379 | self.assertTrue(d1 == d2) | |
363 | 380 | |
364 | 381 | def testDigestable3(self): |
365 | 382 | d = dns.name.root.to_digestable() |
374 | 391 | def bad(): |
375 | 392 | n = dns.name.from_text('FOO.bar', None) |
376 | 393 | n.to_digestable() |
377 | self.failUnlessRaises(dns.name.NeedAbsoluteNameOrOrigin, bad) | |
394 | self.assertRaises(dns.name.NeedAbsoluteNameOrOrigin, bad) | |
378 | 395 | |
379 | 396 | def testToWire1(self): |
380 | 397 | n = dns.name.from_text('FOO.bar') |
430 | 447 | f = BytesIO() |
431 | 448 | compress = {} # type: Dict[dns.name.Name,int] |
432 | 449 | n.to_wire(f, compress) |
433 | self.failUnlessRaises(dns.name.NeedAbsoluteNameOrOrigin, bad) | |
450 | self.assertRaises(dns.name.NeedAbsoluteNameOrOrigin, bad) | |
434 | 451 | |
435 | 452 | def testSplit1(self): |
436 | 453 | n = dns.name.from_text('foo.bar.') |
437 | 454 | (prefix, suffix) = n.split(2) |
438 | 455 | ep = dns.name.from_text('foo', None) |
439 | 456 | es = dns.name.from_text('bar.', None) |
440 | self.failUnless(prefix == ep and suffix == es) | |
457 | self.assertTrue(prefix == ep and suffix == es) | |
441 | 458 | |
442 | 459 | def testSplit2(self): |
443 | 460 | n = dns.name.from_text('foo.bar.') |
444 | 461 | (prefix, suffix) = n.split(1) |
445 | 462 | ep = dns.name.from_text('foo.bar', None) |
446 | 463 | es = dns.name.from_text('.', None) |
447 | self.failUnless(prefix == ep and suffix == es) | |
464 | self.assertTrue(prefix == ep and suffix == es) | |
448 | 465 | |
449 | 466 | def testSplit3(self): |
450 | 467 | n = dns.name.from_text('foo.bar.') |
451 | 468 | (prefix, suffix) = n.split(0) |
452 | 469 | ep = dns.name.from_text('foo.bar.', None) |
453 | 470 | es = dns.name.from_text('', None) |
454 | self.failUnless(prefix == ep and suffix == es) | |
471 | self.assertTrue(prefix == ep and suffix == es) | |
455 | 472 | |
456 | 473 | def testSplit4(self): |
457 | 474 | n = dns.name.from_text('foo.bar.') |
458 | 475 | (prefix, suffix) = n.split(3) |
459 | 476 | ep = dns.name.from_text('', None) |
460 | 477 | es = dns.name.from_text('foo.bar.', None) |
461 | self.failUnless(prefix == ep and suffix == es) | |
478 | self.assertTrue(prefix == ep and suffix == es) | |
462 | 479 | |
463 | 480 | def testBadSplit1(self): |
464 | 481 | def bad(): |
465 | 482 | n = dns.name.from_text('foo.bar.') |
466 | 483 | n.split(-1) |
467 | self.failUnlessRaises(ValueError, bad) | |
484 | self.assertRaises(ValueError, bad) | |
468 | 485 | |
469 | 486 | def testBadSplit2(self): |
470 | 487 | def bad(): |
471 | 488 | n = dns.name.from_text('foo.bar.') |
472 | 489 | n.split(4) |
473 | self.failUnlessRaises(ValueError, bad) | |
490 | self.assertRaises(ValueError, bad) | |
474 | 491 | |
475 | 492 | def testRelativize1(self): |
476 | 493 | n = dns.name.from_text('a.foo.bar.', None) |
477 | 494 | o = dns.name.from_text('bar.', None) |
478 | 495 | e = dns.name.from_text('a.foo', None) |
479 | self.failUnless(n.relativize(o) == e) | |
496 | self.assertTrue(n.relativize(o) == e) | |
480 | 497 | |
481 | 498 | def testRelativize2(self): |
482 | 499 | n = dns.name.from_text('a.foo.bar.', None) |
483 | 500 | o = n |
484 | 501 | e = dns.name.empty |
485 | self.failUnless(n.relativize(o) == e) | |
502 | self.assertTrue(n.relativize(o) == e) | |
486 | 503 | |
487 | 504 | def testRelativize3(self): |
488 | 505 | n = dns.name.from_text('a.foo.bar.', None) |
489 | 506 | o = dns.name.from_text('blaz.', None) |
490 | 507 | e = n |
491 | self.failUnless(n.relativize(o) == e) | |
508 | self.assertTrue(n.relativize(o) == e) | |
492 | 509 | |
493 | 510 | def testRelativize4(self): |
494 | 511 | n = dns.name.from_text('a.foo', None) |
495 | 512 | o = dns.name.root |
496 | 513 | e = n |
497 | self.failUnless(n.relativize(o) == e) | |
514 | self.assertTrue(n.relativize(o) == e) | |
498 | 515 | |
499 | 516 | def testDerelativize1(self): |
500 | 517 | n = dns.name.from_text('a.foo', None) |
501 | 518 | o = dns.name.from_text('bar.', None) |
502 | 519 | e = dns.name.from_text('a.foo.bar.', None) |
503 | self.failUnless(n.derelativize(o) == e) | |
520 | self.assertTrue(n.derelativize(o) == e) | |
504 | 521 | |
505 | 522 | def testDerelativize2(self): |
506 | 523 | n = dns.name.empty |
507 | 524 | o = dns.name.from_text('a.foo.bar.', None) |
508 | 525 | e = o |
509 | self.failUnless(n.derelativize(o) == e) | |
526 | self.assertTrue(n.derelativize(o) == e) | |
510 | 527 | |
511 | 528 | def testDerelativize3(self): |
512 | 529 | n = dns.name.from_text('a.foo.bar.', None) |
513 | 530 | o = dns.name.from_text('blaz.', None) |
514 | 531 | e = n |
515 | self.failUnless(n.derelativize(o) == e) | |
532 | self.assertTrue(n.derelativize(o) == e) | |
516 | 533 | |
517 | 534 | def testChooseRelativity1(self): |
518 | 535 | n = dns.name.from_text('a.foo.bar.', None) |
519 | 536 | o = dns.name.from_text('bar.', None) |
520 | 537 | e = dns.name.from_text('a.foo', None) |
521 | self.failUnless(n.choose_relativity(o, True) == e) | |
538 | self.assertTrue(n.choose_relativity(o, True) == e) | |
522 | 539 | |
523 | 540 | def testChooseRelativity2(self): |
524 | 541 | n = dns.name.from_text('a.foo.bar.', None) |
525 | 542 | o = dns.name.from_text('bar.', None) |
526 | 543 | e = n |
527 | self.failUnless(n.choose_relativity(o, False) == e) | |
544 | self.assertTrue(n.choose_relativity(o, False) == e) | |
528 | 545 | |
529 | 546 | def testChooseRelativity3(self): |
530 | 547 | n = dns.name.from_text('a.foo', None) |
531 | 548 | o = dns.name.from_text('bar.', None) |
532 | 549 | e = dns.name.from_text('a.foo.bar.', None) |
533 | self.failUnless(n.choose_relativity(o, False) == e) | |
550 | self.assertTrue(n.choose_relativity(o, False) == e) | |
534 | 551 | |
535 | 552 | def testChooseRelativity4(self): |
536 | 553 | n = dns.name.from_text('a.foo', None) |
537 | 554 | o = None |
538 | 555 | e = n |
539 | self.failUnless(n.choose_relativity(o, True) == e) | |
556 | self.assertTrue(n.choose_relativity(o, True) == e) | |
540 | 557 | |
541 | 558 | def testChooseRelativity5(self): |
542 | 559 | n = dns.name.from_text('a.foo', None) |
543 | 560 | o = None |
544 | 561 | e = n |
545 | self.failUnless(n.choose_relativity(o, False) == e) | |
562 | self.assertTrue(n.choose_relativity(o, False) == e) | |
546 | 563 | |
547 | 564 | def testChooseRelativity6(self): |
548 | 565 | n = dns.name.from_text('a.foo.', None) |
549 | 566 | o = None |
550 | 567 | e = n |
551 | self.failUnless(n.choose_relativity(o, True) == e) | |
568 | self.assertTrue(n.choose_relativity(o, True) == e) | |
552 | 569 | |
553 | 570 | def testChooseRelativity7(self): |
554 | 571 | n = dns.name.from_text('a.foo.', None) |
555 | 572 | o = None |
556 | 573 | e = n |
557 | self.failUnless(n.choose_relativity(o, False) == e) | |
574 | self.assertTrue(n.choose_relativity(o, False) == e) | |
558 | 575 | |
559 | 576 | def testFromWire1(self): |
560 | 577 | w = b'\x03foo\x00\xc0\x00' |
564 | 581 | en2 = en1 |
565 | 582 | ecused1 = 5 |
566 | 583 | ecused2 = 2 |
567 | self.failUnless(n1 == en1 and cused1 == ecused1 and \ | |
584 | self.assertTrue(n1 == en1 and cused1 == ecused1 and \ | |
568 | 585 | n2 == en2 and cused2 == ecused2) |
569 | 586 | |
570 | 587 | def testFromWire2(self): |
581 | 598 | ecused1 = 5 |
582 | 599 | ecused2 = 4 |
583 | 600 | ecused3 = 4 |
584 | self.failUnless(n1 == en1 and cused1 == ecused1 and \ | |
601 | self.assertTrue(n1 == en1 and cused1 == ecused1 and \ | |
585 | 602 | n2 == en2 and cused2 == ecused2 and \ |
586 | 603 | n3 == en3 and cused3 == ecused3) |
587 | 604 | |
589 | 606 | def bad(): |
590 | 607 | w = b'\x03foo\xc0\x04' |
591 | 608 | dns.name.from_wire(w, 0) |
592 | self.failUnlessRaises(dns.name.BadPointer, bad) | |
609 | self.assertRaises(dns.name.BadPointer, bad) | |
593 | 610 | |
594 | 611 | def testBadFromWire2(self): |
595 | 612 | def bad(): |
596 | 613 | w = b'\x03foo\xc0\x05' |
597 | 614 | dns.name.from_wire(w, 0) |
598 | self.failUnlessRaises(dns.name.BadPointer, bad) | |
615 | self.assertRaises(dns.name.BadPointer, bad) | |
599 | 616 | |
600 | 617 | def testBadFromWire3(self): |
601 | 618 | def bad(): |
602 | 619 | w = b'\xbffoo' |
603 | 620 | dns.name.from_wire(w, 0) |
604 | self.failUnlessRaises(dns.name.BadLabelType, bad) | |
621 | self.assertRaises(dns.name.BadLabelType, bad) | |
605 | 622 | |
606 | 623 | def testBadFromWire4(self): |
607 | 624 | def bad(): |
608 | 625 | w = b'\x41foo' |
609 | 626 | dns.name.from_wire(w, 0) |
610 | self.failUnlessRaises(dns.name.BadLabelType, bad) | |
627 | self.assertRaises(dns.name.BadLabelType, bad) | |
611 | 628 | |
612 | 629 | def testParent1(self): |
613 | 630 | n = dns.name.from_text('foo.bar.') |
614 | self.failUnless(n.parent() == dns.name.from_text('bar.')) | |
615 | self.failUnless(n.parent().parent() == dns.name.root) | |
631 | self.assertTrue(n.parent() == dns.name.from_text('bar.')) | |
632 | self.assertTrue(n.parent().parent() == dns.name.root) | |
616 | 633 | |
617 | 634 | def testParent2(self): |
618 | 635 | n = dns.name.from_text('foo.bar', None) |
619 | self.failUnless(n.parent() == dns.name.from_text('bar', None)) | |
620 | self.failUnless(n.parent().parent() == dns.name.empty) | |
636 | self.assertTrue(n.parent() == dns.name.from_text('bar', None)) | |
637 | self.assertTrue(n.parent().parent() == dns.name.empty) | |
621 | 638 | |
622 | 639 | def testParent3(self): |
623 | 640 | def bad(): |
624 | 641 | n = dns.name.root |
625 | 642 | n.parent() |
626 | self.failUnlessRaises(dns.name.NoParent, bad) | |
643 | self.assertRaises(dns.name.NoParent, bad) | |
627 | 644 | |
628 | 645 | def testParent4(self): |
629 | 646 | def bad(): |
630 | 647 | n = dns.name.empty |
631 | 648 | n.parent() |
632 | self.failUnlessRaises(dns.name.NoParent, bad) | |
649 | self.assertRaises(dns.name.NoParent, bad) | |
633 | 650 | |
634 | 651 | def testFromUnicode1(self): |
635 | n = dns.name.from_text(u'foo.bar') | |
652 | n = dns.name.from_text('foo.bar') | |
636 | 653 | self.assertEqual(n.labels, (b'foo', b'bar', b'')) |
637 | 654 | |
638 | 655 | def testFromUnicode2(self): |
639 | n = dns.name.from_text(u'foo\u1234bar.bar') | |
656 | n = dns.name.from_text('foo\u1234bar.bar') | |
640 | 657 | self.assertEqual(n.labels, (b'xn--foobar-r5z', b'bar', b'')) |
641 | 658 | |
642 | 659 | def testFromUnicodeAlternateDot1(self): |
643 | n = dns.name.from_text(u'foo\u3002bar') | |
660 | n = dns.name.from_text('foo\u3002bar') | |
644 | 661 | self.assertEqual(n.labels, (b'foo', b'bar', b'')) |
645 | 662 | |
646 | 663 | def testFromUnicodeAlternateDot2(self): |
647 | n = dns.name.from_text(u'foo\uff0ebar') | |
664 | n = dns.name.from_text('foo\uff0ebar') | |
648 | 665 | self.assertEqual(n.labels, (b'foo', b'bar', b'')) |
649 | 666 | |
650 | 667 | def testFromUnicodeAlternateDot3(self): |
651 | n = dns.name.from_text(u'foo\uff61bar') | |
668 | n = dns.name.from_text('foo\uff61bar') | |
652 | 669 | self.assertEqual(n.labels, (b'foo', b'bar', b'')) |
653 | 670 | |
671 | def testFromUnicodeRoot(self): | |
672 | n = dns.name.from_text('.') | |
673 | self.assertEqual(n.labels, (b'',)) | |
674 | ||
675 | def testFromUnicodeAlternateRoot1(self): | |
676 | n = dns.name.from_text('\u3002') | |
677 | self.assertEqual(n.labels, (b'',)) | |
678 | ||
679 | def testFromUnicodeAlternateRoot2(self): | |
680 | n = dns.name.from_text('\uff0e') | |
681 | self.assertEqual(n.labels, (b'',)) | |
682 | ||
683 | def testFromUnicodeAlternateRoot3(self): | |
684 | n = dns.name.from_text('\uff61') | |
685 | self.assertEqual(n.labels, (b'', )) | |
686 | ||
654 | 687 | def testFromUnicodeIDNA2003Explicit(self): |
655 | t = u'Königsgäßchen' | |
688 | t = 'Königsgäßchen' | |
656 | 689 | e = dns.name.from_unicode(t, idna_codec=dns.name.IDNA_2003) |
657 | 690 | self.assertEqual(str(e), 'xn--knigsgsschen-lcb0w.') |
658 | 691 | |
659 | 692 | def testFromUnicodeIDNA2003Default(self): |
660 | t = u'Königsgäßchen' | |
693 | t = 'Königsgäßchen' | |
661 | 694 | e = dns.name.from_unicode(t) |
662 | 695 | self.assertEqual(str(e), 'xn--knigsgsschen-lcb0w.') |
663 | 696 | |
664 | 697 | def testFromUnicodeIDNA2008(self): |
665 | 698 | if dns.name.have_idna_2008: |
666 | t = u'Königsgäßchen' | |
699 | t = 'Königsgäßchen' | |
667 | 700 | def bad(): |
668 | 701 | codec = dns.name.IDNA_2008_Strict |
669 | 702 | return dns.name.from_unicode(t, idna_codec=codec) |
670 | self.failUnlessRaises(dns.name.IDNAException, bad) | |
703 | self.assertRaises(dns.name.IDNAException, bad) | |
671 | 704 | e1 = dns.name.from_unicode(t, idna_codec=dns.name.IDNA_2008) |
672 | 705 | self.assertEqual(str(e1), 'xn--knigsgchen-b4a3dun.') |
673 | 706 | c2 = dns.name.IDNA_2008_Transitional |
676 | 709 | |
677 | 710 | def testFromUnicodeIDNA2008Mixed(self): |
678 | 711 | # the IDN rules for names are very restrictive, disallowing |
679 | # practical names like u'_sip._tcp.Königsgäßchen'. Dnspython | |
712 | # practical names like '_sip._tcp.Königsgäßchen'. Dnspython | |
680 | 713 | # has a "practical" mode which permits labels which are purely |
681 | 714 | # ASCII to go straight through, and thus not invalid useful |
682 | 715 | # things in the real world. |
683 | 716 | if dns.name.have_idna_2008: |
684 | t = u'_sip._tcp.Königsgäßchen' | |
717 | t = '_sip._tcp.Königsgäßchen' | |
685 | 718 | def bad1(): |
686 | 719 | codec = dns.name.IDNA_2008_Strict |
687 | 720 | return dns.name.from_unicode(t, idna_codec=codec) |
691 | 724 | def bad3(): |
692 | 725 | codec = dns.name.IDNA_2008_Transitional |
693 | 726 | return dns.name.from_unicode(t, idna_codec=codec) |
694 | self.failUnlessRaises(dns.name.IDNAException, bad1) | |
695 | self.failUnlessRaises(dns.name.IDNAException, bad2) | |
696 | self.failUnlessRaises(dns.name.IDNAException, bad3) | |
727 | self.assertRaises(dns.name.IDNAException, bad1) | |
728 | self.assertRaises(dns.name.IDNAException, bad2) | |
729 | self.assertRaises(dns.name.IDNAException, bad3) | |
697 | 730 | e = dns.name.from_unicode(t, |
698 | 731 | idna_codec=dns.name.IDNA_2008_Practical) |
699 | 732 | self.assertEqual(str(e), '_sip._tcp.xn--knigsgchen-b4a3dun.') |
700 | 733 | |
701 | 734 | def testToUnicode1(self): |
702 | n = dns.name.from_text(u'foo.bar') | |
735 | n = dns.name.from_text('foo.bar') | |
703 | 736 | s = n.to_unicode() |
704 | self.assertEqual(s, u'foo.bar.') | |
737 | self.assertEqual(s, 'foo.bar.') | |
705 | 738 | |
706 | 739 | def testToUnicode2(self): |
707 | n = dns.name.from_text(u'foo\u1234bar.bar') | |
740 | n = dns.name.from_text('foo\u1234bar.bar') | |
708 | 741 | s = n.to_unicode() |
709 | self.assertEqual(s, u'foo\u1234bar.bar.') | |
742 | self.assertEqual(s, 'foo\u1234bar.bar.') | |
710 | 743 | |
711 | 744 | def testToUnicode3(self): |
712 | 745 | n = dns.name.from_text('foo.bar') |
713 | 746 | s = n.to_unicode() |
714 | self.assertEqual(s, u'foo.bar.') | |
747 | self.assertEqual(s, 'foo.bar.') | |
715 | 748 | |
716 | 749 | def testToUnicode4(self): |
717 | 750 | if dns.name.have_idna_2008: |
718 | n = dns.name.from_text(u'ドメイン.テスト', | |
751 | n = dns.name.from_text('ドメイン.テスト', | |
719 | 752 | idna_codec=dns.name.IDNA_2008) |
720 | 753 | s = n.to_unicode() |
721 | 754 | self.assertEqual(str(n), 'xn--eckwd4c7c.xn--zckzah.') |
722 | self.assertEqual(s, u'ドメイン.テスト.') | |
755 | self.assertEqual(s, 'ドメイン.テスト.') | |
723 | 756 | |
724 | 757 | def testDefaultDecodeIsJustPunycode(self): |
725 | 758 | # groß.com. in IDNA2008 form, pre-encoded. |
726 | 759 | n = dns.name.from_text('xn--gro-7ka.com') |
727 | 760 | # output using default codec which just decodes the punycode and |
728 | 761 | # doesn't test for IDNA2003 or IDNA2008. |
729 | self.assertEqual(n.to_unicode(), u'groß.com.') | |
762 | self.assertEqual(n.to_unicode(), 'groß.com.') | |
730 | 763 | |
731 | 764 | def testStrictINDA2003Decode(self): |
732 | 765 | # groß.com. in IDNA2008 form, pre-encoded. |
734 | 767 | def bad(): |
735 | 768 | # This throws in IDNA2003 because it doesn't "round trip". |
736 | 769 | n.to_unicode(idna_codec=dns.name.IDNA_2003_Strict) |
737 | self.failUnlessRaises(dns.name.IDNAException, bad) | |
770 | self.assertRaises(dns.name.IDNAException, bad) | |
738 | 771 | |
739 | 772 | def testReverseIPv4(self): |
740 | 773 | e = dns.name.from_text('1.0.0.127.in-addr.arpa.') |
749 | 782 | def testReverseIPv6MappedIpv4(self): |
750 | 783 | e = dns.name.from_text('1.0.0.127.in-addr.arpa.') |
751 | 784 | n = dns.reversename.from_address('::ffff:127.0.0.1') |
752 | self.failUnless(e == n) | |
785 | self.assertTrue(e == n) | |
753 | 786 | |
754 | 787 | def testBadReverseIPv4(self): |
755 | 788 | def bad(): |
756 | 789 | dns.reversename.from_address('127.0.foo.1') |
757 | self.failUnlessRaises(dns.exception.SyntaxError, bad) | |
790 | self.assertRaises(dns.exception.SyntaxError, bad) | |
758 | 791 | |
759 | 792 | def testBadReverseIPv6(self): |
760 | 793 | def bad(): |
761 | 794 | dns.reversename.from_address('::1::1') |
762 | self.failUnlessRaises(dns.exception.SyntaxError, bad) | |
795 | self.assertRaises(dns.exception.SyntaxError, bad) | |
763 | 796 | |
764 | 797 | def testForwardIPv4(self): |
765 | 798 | n = dns.name.from_text('1.0.0.127.in-addr.arpa.') |
777 | 810 | text = '+1 650 555 1212' |
778 | 811 | e = dns.name.from_text('2.1.2.1.5.5.5.0.5.6.1.e164.arpa.') |
779 | 812 | n = dns.e164.from_e164(text) |
780 | self.failUnless(n == e) | |
813 | self.assertTrue(n == e) | |
781 | 814 | |
782 | 815 | def testEnumToE164(self): |
783 | 816 | n = dns.name.from_text('2.1.2.1.5.5.5.0.5.6.1.e164.arpa.') |
34 | 34 | self.rndict[n2] = 2 |
35 | 35 | |
36 | 36 | def testDepth(self): |
37 | self.failUnless(self.ndict.max_depth == 3) | |
37 | self.assertTrue(self.ndict.max_depth == 3) | |
38 | 38 | |
39 | 39 | def testLookup1(self): |
40 | 40 | k = dns.name.from_text('foo.bar.') |
41 | self.failUnless(self.ndict[k] == 1) | |
41 | self.assertTrue(self.ndict[k] == 1) | |
42 | 42 | |
43 | 43 | def testLookup2(self): |
44 | 44 | k = dns.name.from_text('foo.bar.') |
45 | self.failUnless(self.ndict.get_deepest_match(k)[1] == 1) | |
45 | self.assertTrue(self.ndict.get_deepest_match(k)[1] == 1) | |
46 | 46 | |
47 | 47 | def testLookup3(self): |
48 | 48 | k = dns.name.from_text('a.b.c.foo.bar.') |
49 | self.failUnless(self.ndict.get_deepest_match(k)[1] == 1) | |
49 | self.assertTrue(self.ndict.get_deepest_match(k)[1] == 1) | |
50 | 50 | |
51 | 51 | def testLookup4(self): |
52 | 52 | k = dns.name.from_text('a.b.c.bar.') |
53 | self.failUnless(self.ndict.get_deepest_match(k)[1] == 2) | |
53 | self.assertTrue(self.ndict.get_deepest_match(k)[1] == 2) | |
54 | 54 | |
55 | 55 | def testLookup5(self): |
56 | 56 | def bad(): |
57 | 57 | n = dns.name.from_text('a.b.c.') |
58 | 58 | self.ndict.get_deepest_match(n) |
59 | self.failUnlessRaises(KeyError, bad) | |
59 | self.assertRaises(KeyError, bad) | |
60 | 60 | |
61 | 61 | def testLookup6(self): |
62 | 62 | def bad(): |
63 | 63 | self.ndict.get_deepest_match(dns.name.empty) |
64 | self.failUnlessRaises(KeyError, bad) | |
64 | self.assertRaises(KeyError, bad) | |
65 | 65 | |
66 | 66 | def testLookup7(self): |
67 | 67 | self.ndict[dns.name.empty] = 100 |
68 | 68 | n = dns.name.from_text('a.b.c.') |
69 | 69 | v = self.ndict.get_deepest_match(n)[1] |
70 | self.failUnless(v == 100) | |
70 | self.assertTrue(v == 100) | |
71 | 71 | |
72 | 72 | def testLookup8(self): |
73 | 73 | def bad(): |
74 | 74 | self.ndict['foo'] = 100 |
75 | self.failUnlessRaises(ValueError, bad) | |
75 | self.assertRaises(ValueError, bad) | |
76 | 76 | |
77 | 77 | def testRelDepth(self): |
78 | self.failUnless(self.rndict.max_depth == 2) | |
78 | self.assertTrue(self.rndict.max_depth == 2) | |
79 | 79 | |
80 | 80 | def testRelLookup1(self): |
81 | 81 | k = dns.name.from_text('foo.bar', None) |
82 | self.failUnless(self.rndict[k] == 1) | |
82 | self.assertTrue(self.rndict[k] == 1) | |
83 | 83 | |
84 | 84 | def testRelLookup2(self): |
85 | 85 | k = dns.name.from_text('foo.bar', None) |
86 | self.failUnless(self.rndict.get_deepest_match(k)[1] == 1) | |
86 | self.assertTrue(self.rndict.get_deepest_match(k)[1] == 1) | |
87 | 87 | |
88 | 88 | def testRelLookup3(self): |
89 | 89 | k = dns.name.from_text('a.b.c.foo.bar', None) |
90 | self.failUnless(self.rndict.get_deepest_match(k)[1] == 1) | |
90 | self.assertTrue(self.rndict.get_deepest_match(k)[1] == 1) | |
91 | 91 | |
92 | 92 | def testRelLookup4(self): |
93 | 93 | k = dns.name.from_text('a.b.c.bar', None) |
94 | self.failUnless(self.rndict.get_deepest_match(k)[1] == 2) | |
94 | self.assertTrue(self.rndict.get_deepest_match(k)[1] == 2) | |
95 | 95 | |
96 | 96 | def testRelLookup7(self): |
97 | 97 | self.rndict[dns.name.empty] = 100 |
98 | 98 | n = dns.name.from_text('a.b.c', None) |
99 | 99 | v = self.rndict.get_deepest_match(n)[1] |
100 | self.failUnless(v == 100) | |
100 | self.assertTrue(v == 100) | |
101 | 101 | |
102 | 102 | if __name__ == '__main__': |
103 | 103 | unittest.main() |
28 | 28 | u"1 0 100 ABCD SCBCQHKU35969L2A68P3AD59LHF30715 A CAA TYPE65534") |
29 | 29 | bitmap = bytearray(b'\0' * 32) |
30 | 30 | bitmap[31] = bitmap[31] | 2 |
31 | self.assertEqual(rdata.windows, [(0, bytearray(b'@')), | |
32 | (1, bytearray(b'@')), # CAA = 257 | |
31 | self.assertEqual(rdata.windows, [(0, b'@'), | |
32 | (1, b'@'), # CAA = 257 | |
33 | 33 | (255, bitmap) |
34 | 34 | ]) |
35 | 35 |
38 | 38 | |
39 | 39 | def test_aton1(self): |
40 | 40 | a = aton6('::') |
41 | self.failUnless(a == b'\x00' * 16) | |
41 | self.assertTrue(a == b'\x00' * 16) | |
42 | 42 | |
43 | 43 | def test_aton2(self): |
44 | 44 | a = aton6('::1') |
45 | self.failUnless(a == b'\x00' * 15 + b'\x01') | |
45 | self.assertTrue(a == b'\x00' * 15 + b'\x01') | |
46 | 46 | |
47 | 47 | def test_aton3(self): |
48 | 48 | a = aton6('::10.0.0.1') |
49 | self.failUnless(a == b'\x00' * 12 + b'\x0a\x00\x00\x01') | |
49 | self.assertTrue(a == b'\x00' * 12 + b'\x0a\x00\x00\x01') | |
50 | 50 | |
51 | 51 | def test_aton4(self): |
52 | 52 | a = aton6('abcd::dcba') |
53 | self.failUnless(a == b'\xab\xcd' + b'\x00' * 12 + b'\xdc\xba') | |
53 | self.assertTrue(a == b'\xab\xcd' + b'\x00' * 12 + b'\xdc\xba') | |
54 | 54 | |
55 | 55 | def test_aton5(self): |
56 | 56 | a = aton6('1:2:3:4:5:6:7:8') |
60 | 60 | def test_bad_aton1(self): |
61 | 61 | def bad(): |
62 | 62 | aton6('abcd:dcba') |
63 | self.failUnlessRaises(dns.exception.SyntaxError, bad) | |
63 | self.assertRaises(dns.exception.SyntaxError, bad) | |
64 | 64 | |
65 | 65 | def test_bad_aton2(self): |
66 | 66 | def bad(): |
67 | 67 | aton6('abcd::dcba::1') |
68 | self.failUnlessRaises(dns.exception.SyntaxError, bad) | |
68 | self.assertRaises(dns.exception.SyntaxError, bad) | |
69 | 69 | |
70 | 70 | def test_bad_aton3(self): |
71 | 71 | def bad(): |
72 | 72 | aton6('1:2:3:4:5:6:7:8:9') |
73 | self.failUnlessRaises(dns.exception.SyntaxError, bad) | |
73 | self.assertRaises(dns.exception.SyntaxError, bad) | |
74 | 74 | |
75 | 75 | def test_aton6(self): |
76 | 76 | a = aton6('::') |
161 | 161 | def test_bad_ntoa1(self): |
162 | 162 | def bad(): |
163 | 163 | ntoa6('') |
164 | self.failUnlessRaises(ValueError, bad) | |
164 | self.assertRaises(ValueError, bad) | |
165 | 165 | |
166 | 166 | def test_bad_ntoa2(self): |
167 | 167 | def bad(): |
168 | 168 | ntoa6('\x00' * 17) |
169 | self.failUnlessRaises(ValueError, bad) | |
169 | self.assertRaises(ValueError, bad) | |
170 | 170 | |
171 | 171 | def test_good_v4_aton(self): |
172 | 172 | pairs = [('1.2.3.4', b'\x01\x02\x03\x04'), |
185 | 185 | return bad |
186 | 186 | for addr in v4_bad_addrs: |
187 | 187 | print(addr) |
188 | self.failUnlessRaises(dns.exception.SyntaxError, make_bad(addr)) | |
188 | self.assertRaises(dns.exception.SyntaxError, make_bad(addr)) | |
189 | 189 | |
190 | 190 | def test_bad_v6_aton(self): |
191 | 191 | addrs = ['+::0', '0::0::', '::0::', '1:2:3:4:5:6:7:8:9', |
197 | 197 | x = aton6(a) |
198 | 198 | return bad |
199 | 199 | for addr in addrs: |
200 | self.failUnlessRaises(dns.exception.SyntaxError, make_bad(addr)) | |
200 | self.assertRaises(dns.exception.SyntaxError, make_bad(addr)) | |
201 | 201 | |
202 | 202 | def test_rfc5952_section_4_2_2(self): |
203 | 203 | addr = '2001:db8:0:1:1:1:1:1' |
209 | 209 | t1 = '2001:db8:0:1:1:1:1:1' |
210 | 210 | t2 = '::ffff:127.0.0.1' |
211 | 211 | t3 = '1::ffff:127.0.0.1' |
212 | self.failIf(dns.ipv6.is_mapped(aton6(t1))) | |
213 | self.failUnless(dns.ipv6.is_mapped(aton6(t2))) | |
214 | self.failIf(dns.ipv6.is_mapped(aton6(t3))) | |
212 | self.assertFalse(dns.ipv6.is_mapped(aton6(t1))) | |
213 | self.assertTrue(dns.ipv6.is_mapped(aton6(t2))) | |
214 | self.assertFalse(dns.ipv6.is_mapped(aton6(t3))) | |
215 | 215 | |
216 | 216 | def test_is_multicast(self): |
217 | 217 | t1 = '223.0.0.1' |
220 | 220 | t4 = '239.0.0.1' |
221 | 221 | t5 = 'fe00::1' |
222 | 222 | t6 = 'ff00::1' |
223 | self.failIf(dns.inet.is_multicast(t1)) | |
224 | self.failIf(dns.inet.is_multicast(t2)) | |
225 | self.failUnless(dns.inet.is_multicast(t3)) | |
226 | self.failUnless(dns.inet.is_multicast(t4)) | |
227 | self.failIf(dns.inet.is_multicast(t5)) | |
228 | self.failUnless(dns.inet.is_multicast(t6)) | |
223 | self.assertFalse(dns.inet.is_multicast(t1)) | |
224 | self.assertFalse(dns.inet.is_multicast(t2)) | |
225 | self.assertTrue(dns.inet.is_multicast(t3)) | |
226 | self.assertTrue(dns.inet.is_multicast(t4)) | |
227 | self.assertFalse(dns.inet.is_multicast(t5)) | |
228 | self.assertTrue(dns.inet.is_multicast(t6)) | |
229 | 229 | |
230 | 230 | if __name__ == '__main__': |
231 | 231 | unittest.main() |
26 | 26 | |
27 | 27 | def test_str(self): |
28 | 28 | rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.4") |
29 | self.failUnless(rdata.address == "1.2.3.4") | |
29 | self.assertTrue(rdata.address == "1.2.3.4") | |
30 | 30 | |
31 | 31 | def test_unicode(self): |
32 | 32 | rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, u"1.2.3.4") |
33 | self.failUnless(rdata.address == "1.2.3.4") | |
33 | self.assertTrue(rdata.address == "1.2.3.4") | |
34 | 34 | |
35 | 35 | def test_module_registration(self): |
36 | 36 | TTXT = 64001 |
37 | 37 | dns.rdata.register_type(tests.ttxt_module, TTXT, 'TTXT') |
38 | 38 | rdata = dns.rdata.from_text(dns.rdataclass.IN, TTXT, 'hello world') |
39 | self.failUnless(rdata.strings == [b'hello', b'world']) | |
40 | self.failUnless(dns.rdatatype.to_text(TTXT) == 'TTXT') | |
41 | self.failUnless(dns.rdatatype.from_text('TTXT') == TTXT) | |
39 | self.assertTrue(rdata.strings == [b'hello', b'world']) | |
40 | self.assertTrue(dns.rdatatype.to_text(TTXT) == 'TTXT') | |
41 | self.assertTrue(dns.rdatatype.from_text('TTXT') == TTXT) | |
42 | 42 | |
43 | 43 | def test_module_reregistration(self): |
44 | 44 | def bad(): |
45 | 45 | TTXTTWO = dns.rdatatype.TXT |
46 | 46 | dns.rdata.register_type(tests.ttxt_module, TTXTTWO, 'TTXTTWO') |
47 | self.failUnlessRaises(dns.rdata.RdatatypeExists, bad) | |
47 | self.assertRaises(dns.rdata.RdatatypeExists, bad) | |
48 | 48 | |
49 | 49 | if __name__ == '__main__': |
50 | 50 | unittest.main() |
24 | 24 | # Classes |
25 | 25 | |
26 | 26 | def test_class_meta1(self): |
27 | self.failUnless(dns.rdataclass.is_metaclass(dns.rdataclass.ANY)) | |
27 | self.assertTrue(dns.rdataclass.is_metaclass(dns.rdataclass.ANY)) | |
28 | 28 | |
29 | 29 | def test_class_meta2(self): |
30 | self.failUnless(not dns.rdataclass.is_metaclass(dns.rdataclass.IN)) | |
30 | self.assertTrue(not dns.rdataclass.is_metaclass(dns.rdataclass.IN)) | |
31 | 31 | |
32 | 32 | def test_class_bytext1(self): |
33 | self.failUnless(dns.rdataclass.from_text('IN') == dns.rdataclass.IN) | |
33 | self.assertTrue(dns.rdataclass.from_text('IN') == dns.rdataclass.IN) | |
34 | 34 | |
35 | 35 | def test_class_bytext2(self): |
36 | self.failUnless(dns.rdataclass.from_text('CLASS1') == | |
36 | self.assertTrue(dns.rdataclass.from_text('CLASS1') == | |
37 | 37 | dns.rdataclass.IN) |
38 | 38 | |
39 | 39 | def test_class_bytext_bounds1(self): |
40 | self.failUnless(dns.rdataclass.from_text('CLASS0') == 0) | |
41 | self.failUnless(dns.rdataclass.from_text('CLASS65535') == 65535) | |
40 | self.assertTrue(dns.rdataclass.from_text('CLASS0') == 0) | |
41 | self.assertTrue(dns.rdataclass.from_text('CLASS65535') == 65535) | |
42 | 42 | |
43 | 43 | def test_class_bytext_bounds2(self): |
44 | 44 | def bad(): |
45 | 45 | dns.rdataclass.from_text('CLASS65536') |
46 | self.failUnlessRaises(ValueError, bad) | |
46 | self.assertRaises(ValueError, bad) | |
47 | 47 | |
48 | 48 | def test_class_bytext_unknown(self): |
49 | 49 | def bad(): |
50 | 50 | dns.rdataclass.from_text('XXX') |
51 | self.failUnlessRaises(dns.rdataclass.UnknownRdataclass, bad) | |
51 | self.assertRaises(dns.rdataclass.UnknownRdataclass, bad) | |
52 | 52 | |
53 | 53 | def test_class_totext1(self): |
54 | self.failUnless(dns.rdataclass.to_text(dns.rdataclass.IN) == 'IN') | |
54 | self.assertTrue(dns.rdataclass.to_text(dns.rdataclass.IN) == 'IN') | |
55 | 55 | |
56 | 56 | def test_class_totext2(self): |
57 | self.failUnless(dns.rdataclass.to_text(999) == 'CLASS999') | |
57 | self.assertTrue(dns.rdataclass.to_text(999) == 'CLASS999') | |
58 | 58 | |
59 | 59 | def test_class_totext_bounds1(self): |
60 | 60 | def bad(): |
61 | 61 | dns.rdataclass.to_text(-1) |
62 | self.failUnlessRaises(ValueError, bad) | |
62 | self.assertRaises(ValueError, bad) | |
63 | 63 | |
64 | 64 | def test_class_totext_bounds2(self): |
65 | 65 | def bad(): |
66 | 66 | dns.rdataclass.to_text(65536) |
67 | self.failUnlessRaises(ValueError, bad) | |
67 | self.assertRaises(ValueError, bad) | |
68 | 68 | |
69 | 69 | # Types |
70 | 70 | |
71 | 71 | def test_type_meta1(self): |
72 | self.failUnless(dns.rdatatype.is_metatype(dns.rdatatype.ANY)) | |
72 | self.assertTrue(dns.rdatatype.is_metatype(dns.rdatatype.ANY)) | |
73 | 73 | |
74 | 74 | def test_type_meta2(self): |
75 | self.failUnless(dns.rdatatype.is_metatype(dns.rdatatype.OPT)) | |
75 | self.assertTrue(dns.rdatatype.is_metatype(dns.rdatatype.OPT)) | |
76 | 76 | |
77 | 77 | def test_type_meta3(self): |
78 | self.failUnless(not dns.rdatatype.is_metatype(dns.rdatatype.A)) | |
78 | self.assertTrue(not dns.rdatatype.is_metatype(dns.rdatatype.A)) | |
79 | 79 | |
80 | 80 | def test_type_singleton1(self): |
81 | self.failUnless(dns.rdatatype.is_singleton(dns.rdatatype.SOA)) | |
81 | self.assertTrue(dns.rdatatype.is_singleton(dns.rdatatype.SOA)) | |
82 | 82 | |
83 | 83 | def test_type_singleton2(self): |
84 | self.failUnless(not dns.rdatatype.is_singleton(dns.rdatatype.A)) | |
84 | self.assertTrue(not dns.rdatatype.is_singleton(dns.rdatatype.A)) | |
85 | 85 | |
86 | 86 | def test_type_bytext1(self): |
87 | self.failUnless(dns.rdatatype.from_text('A') == dns.rdatatype.A) | |
87 | self.assertTrue(dns.rdatatype.from_text('A') == dns.rdatatype.A) | |
88 | 88 | |
89 | 89 | def test_type_bytext2(self): |
90 | self.failUnless(dns.rdatatype.from_text('TYPE1') == | |
90 | self.assertTrue(dns.rdatatype.from_text('TYPE1') == | |
91 | 91 | dns.rdatatype.A) |
92 | 92 | |
93 | 93 | def test_type_bytext_bounds1(self): |
94 | self.failUnless(dns.rdatatype.from_text('TYPE0') == 0) | |
95 | self.failUnless(dns.rdatatype.from_text('TYPE65535') == 65535) | |
94 | self.assertTrue(dns.rdatatype.from_text('TYPE0') == 0) | |
95 | self.assertTrue(dns.rdatatype.from_text('TYPE65535') == 65535) | |
96 | 96 | |
97 | 97 | def test_type_bytext_bounds2(self): |
98 | 98 | def bad(): |
99 | 99 | dns.rdatatype.from_text('TYPE65536') |
100 | self.failUnlessRaises(ValueError, bad) | |
100 | self.assertRaises(ValueError, bad) | |
101 | 101 | |
102 | 102 | def test_type_bytext_unknown(self): |
103 | 103 | def bad(): |
104 | 104 | dns.rdatatype.from_text('XXX') |
105 | self.failUnlessRaises(dns.rdatatype.UnknownRdatatype, bad) | |
105 | self.assertRaises(dns.rdatatype.UnknownRdatatype, bad) | |
106 | 106 | |
107 | 107 | def test_type_totext1(self): |
108 | self.failUnless(dns.rdatatype.to_text(dns.rdatatype.A) == 'A') | |
108 | self.assertTrue(dns.rdatatype.to_text(dns.rdatatype.A) == 'A') | |
109 | 109 | |
110 | 110 | def test_type_totext2(self): |
111 | self.failUnless(dns.rdatatype.to_text(999) == 'TYPE999') | |
111 | self.assertTrue(dns.rdatatype.to_text(999) == 'TYPE999') | |
112 | 112 | |
113 | 113 | def test_type_totext_bounds1(self): |
114 | 114 | def bad(): |
115 | 115 | dns.rdatatype.to_text(-1) |
116 | self.failUnlessRaises(ValueError, bad) | |
116 | self.assertRaises(ValueError, bad) | |
117 | 117 | |
118 | 118 | def test_type_totext_bounds2(self): |
119 | 119 | def bad(): |
120 | 120 | dns.rdatatype.to_text(65536) |
121 | self.failUnlessRaises(ValueError, bad) | |
121 | self.assertRaises(ValueError, bad) | |
122 | ||
123 | def test_type0_totext(self): | |
124 | self.assertTrue(dns.rdatatype.to_text(0) == 'TYPE0') | |
122 | 125 | |
123 | 126 | if __name__ == '__main__': |
124 | 127 | unittest.main() |
27 | 27 | good_s = set() #type: Set[str] |
28 | 28 | good_f = 0 |
29 | 29 | from_flags = dns.rdtypes.ANY.DNSKEY.flags_to_text_set(good_f) |
30 | self.failUnless(from_flags == good_s, | |
30 | self.assertTrue(from_flags == good_s, | |
31 | 31 | '"{}" != "{}"'.format(from_flags, good_s)) |
32 | 32 | from_set = dns.rdtypes.ANY.DNSKEY.flags_from_text_set(good_s) |
33 | self.failUnless(from_set == good_f, | |
33 | self.assertTrue(from_set == good_f, | |
34 | 34 | '"0x{:x}" != "0x{:x}"'.format(from_set, good_f)) |
35 | 35 | |
36 | 36 | def testFlagsAll(self): # type: () -> None |
38 | 38 | good_s = {'SEP', 'REVOKE', 'ZONE'} |
39 | 39 | good_f = 0x181 |
40 | 40 | from_flags = dns.rdtypes.ANY.DNSKEY.flags_to_text_set(good_f) |
41 | self.failUnless(from_flags == good_s, | |
41 | self.assertTrue(from_flags == good_s, | |
42 | 42 | '"{}" != "{}"'.format(from_flags, good_s)) |
43 | 43 | from_text = dns.rdtypes.ANY.DNSKEY.flags_from_text_set(good_s) |
44 | self.failUnless(from_text == good_f, | |
44 | self.assertTrue(from_text == good_f, | |
45 | 45 | '"0x{:x}" != "0x{:x}"'.format(from_text, good_f)) |
46 | 46 | |
47 | 47 | def testFlagsUnknownToText(self): # type: () -> None |
48 | 48 | '''Test that undefined flags are returned in hexadecimal notation.''' |
49 | 49 | unk_s = {'0x8000'} |
50 | 50 | flags_s = dns.rdtypes.ANY.DNSKEY.flags_to_text_set(0x8000) |
51 | self.failUnless(flags_s == unk_s, '"{}" != "{}"'.format(flags_s, unk_s)) | |
51 | self.assertTrue(flags_s == unk_s, '"{}" != "{}"'.format(flags_s, unk_s)) | |
52 | 52 | |
53 | 53 | def testFlagsUnknownToFlags(self): # type: () -> None |
54 | 54 | '''Test that conversion from undefined mnemonic raises error.''' |
55 | self.failUnlessRaises(NotImplementedError, | |
55 | self.assertRaises(NotImplementedError, | |
56 | 56 | dns.rdtypes.ANY.DNSKEY.flags_from_text_set, |
57 | 57 | (['0x8000'])) |
58 | 58 | |
61 | 61 | rr = dns.rrset.from_text('foo', 300, 'IN', 'DNSKEY', '257 3 8 KEY=')[0] |
62 | 62 | rr_s = {'ZONE', 'SEP'} |
63 | 63 | flags_s = rr.flags_to_text_set() |
64 | self.failUnless(flags_s == rr_s, '"{}" != "{}"'.format(flags_s, rr_s)) | |
64 | self.assertTrue(flags_s == rr_s, '"{}" != "{}"'.format(flags_s, rr_s)) | |
65 | 65 | |
66 | 66 | |
67 | 67 | if __name__ == '__main__': |
27 | 27 | r2 = dns.rrset.from_text('FOO', 600, 'in', 'loc', |
28 | 28 | '49 11 42.400 N 16 36 29.600 E 227.64m ' |
29 | 29 | '1.00m 10000.00m 10.00m') |
30 | self.failUnless(r1 == r2, '"{}" != "{}"'.format(r1, r2)) | |
30 | self.assertTrue(r1 == r2, '"{}" != "{}"'.format(r1, r2)) | |
31 | 31 | |
32 | 32 | def testEqual2(self): |
33 | 33 | '''Test default values for size, horizontal and vertical precision.''' |
38 | 38 | (16, 36, 29, 600, 1), |
39 | 39 | 22764.0, # centimeters |
40 | 40 | 100.0, 1000000.00, 1000.0) # centimeters |
41 | self.failUnless(r1 == r2, '"{}" != "{}"'.format(r1, r2)) | |
41 | self.assertTrue(r1 == r2, '"{}" != "{}"'.format(r1, r2)) | |
42 | 42 | |
43 | 43 | def testEqual3(self): |
44 | 44 | '''Test size, horizontal and vertical precision parsers: 100 cm == 1 m. |
50 | 50 | r2 = dns.rrset.from_text('FOO', 600, 'in', 'loc', |
51 | 51 | '49 11 42.400 N 16 36 29.600 E 227.64m ' |
52 | 52 | '2.00m 10.00m 2.00m')[0] |
53 | self.failUnless(r1 == r2, '"{}" != "{}"'.format(r1, r2)) | |
53 | self.assertTrue(r1 == r2, '"{}" != "{}"'.format(r1, r2)) | |
54 | 54 | |
55 | 55 | def testEqual4(self): |
56 | 56 | '''Test size, horizontal and vertical precision parsers without unit. |
63 | 63 | r2 = dns.rrset.from_text('FOO', 600, 'in', 'loc', |
64 | 64 | '49 11 42.400 N 16 36 29.600 E 227.64 ' |
65 | 65 | '2 10 2')[0] # meters without explicit unit |
66 | self.failUnless(r1 == r2, '"{}" != "{}"'.format(r1, r2)) | |
66 | self.assertTrue(r1 == r2, '"{}" != "{}"'.format(r1, r2)) | |
67 | 67 | |
68 | 68 | if __name__ == '__main__': |
69 | 69 | unittest.main() |
26 | 26 | import dns.rdataclass |
27 | 27 | import dns.rdatatype |
28 | 28 | import dns.resolver |
29 | from dns._compat import xrange, PY3 | |
30 | 29 | |
31 | 30 | # Some tests require the internet to be available to run, so let's |
32 | 31 | # skip those if it's not there. |
107 | 106 | def testRead(self): |
108 | 107 | f = StringIO(resolv_conf) |
109 | 108 | r = dns.resolver.Resolver(f) |
110 | self.failUnless(r.nameservers == ['10.0.0.1', '10.0.0.2'] and | |
109 | self.assertTrue(r.nameservers == ['10.0.0.1', '10.0.0.2'] and | |
111 | 110 | r.domain == dns.name.from_text('foo')) |
112 | 111 | |
113 | 112 | def testCacheExpiration(self): |
118 | 117 | cache = dns.resolver.Cache() |
119 | 118 | cache.put((name, dns.rdatatype.A, dns.rdataclass.IN), answer) |
120 | 119 | time.sleep(2) |
121 | self.failUnless(cache.get((name, dns.rdatatype.A, dns.rdataclass.IN)) | |
120 | self.assertTrue(cache.get((name, dns.rdatatype.A, dns.rdataclass.IN)) | |
122 | 121 | is None) |
123 | 122 | |
124 | 123 | def testCacheCleaning(self): |
129 | 128 | cache = dns.resolver.Cache(cleaning_interval=1.0) |
130 | 129 | cache.put((name, dns.rdatatype.A, dns.rdataclass.IN), answer) |
131 | 130 | time.sleep(2) |
132 | self.failUnless(cache.get((name, dns.rdatatype.A, dns.rdataclass.IN)) | |
131 | self.assertTrue(cache.get((name, dns.rdatatype.A, dns.rdataclass.IN)) | |
133 | 132 | is None) |
134 | 133 | |
135 | 134 | def testIndexErrorOnEmptyRRsetAccess(self): |
140 | 139 | dns.rdataclass.IN, message, |
141 | 140 | False) |
142 | 141 | return answer[0] |
143 | self.failUnlessRaises(IndexError, bad) | |
142 | self.assertRaises(IndexError, bad) | |
144 | 143 | |
145 | 144 | def testIndexErrorOnEmptyRRsetDelete(self): |
146 | 145 | def bad(): |
150 | 149 | dns.rdataclass.IN, message, |
151 | 150 | False) |
152 | 151 | del answer[0] |
153 | self.failUnlessRaises(IndexError, bad) | |
152 | self.assertRaises(IndexError, bad) | |
154 | 153 | |
155 | 154 | @unittest.skipIf(not _network_available, "Internet not reachable") |
156 | 155 | def testZoneForName1(self): |
157 | 156 | name = dns.name.from_text('www.dnspython.org.') |
158 | 157 | ezname = dns.name.from_text('dnspython.org.') |
159 | 158 | zname = dns.resolver.zone_for_name(name) |
160 | self.failUnless(zname == ezname) | |
159 | self.assertTrue(zname == ezname) | |
161 | 160 | |
162 | 161 | @unittest.skipIf(not _network_available, "Internet not reachable") |
163 | 162 | def testZoneForName2(self): |
164 | 163 | name = dns.name.from_text('a.b.www.dnspython.org.') |
165 | 164 | ezname = dns.name.from_text('dnspython.org.') |
166 | 165 | zname = dns.resolver.zone_for_name(name) |
167 | self.failUnless(zname == ezname) | |
166 | self.assertTrue(zname == ezname) | |
168 | 167 | |
169 | 168 | @unittest.skipIf(not _network_available, "Internet not reachable") |
170 | 169 | def testZoneForName3(self): |
171 | 170 | name = dns.name.from_text('dnspython.org.') |
172 | 171 | ezname = dns.name.from_text('dnspython.org.') |
173 | 172 | zname = dns.resolver.zone_for_name(name) |
174 | self.failUnless(zname == ezname) | |
173 | self.assertTrue(zname == ezname) | |
175 | 174 | |
176 | 175 | def testZoneForName4(self): |
177 | 176 | def bad(): |
178 | 177 | name = dns.name.from_text('dnspython.org', None) |
179 | 178 | dns.resolver.zone_for_name(name) |
180 | self.failUnlessRaises(dns.resolver.NotAbsolute, bad) | |
179 | self.assertRaises(dns.resolver.NotAbsolute, bad) | |
181 | 180 | |
182 | 181 | def testLRUReplace(self): |
183 | 182 | cache = dns.resolver.LRUCache(4) |
184 | for i in xrange(0, 5): | |
183 | for i in range(0, 5): | |
185 | 184 | name = dns.name.from_text('example%d.' % i) |
186 | 185 | answer = FakeAnswer(time.time() + 1) |
187 | 186 | cache.put((name, dns.rdatatype.A, dns.rdataclass.IN), answer) |
188 | for i in xrange(0, 5): | |
187 | for i in range(0, 5): | |
189 | 188 | name = dns.name.from_text('example%d.' % i) |
190 | 189 | if i == 0: |
191 | self.failUnless(cache.get((name, dns.rdatatype.A, | |
190 | self.assertTrue(cache.get((name, dns.rdatatype.A, | |
192 | 191 | dns.rdataclass.IN)) |
193 | 192 | is None) |
194 | 193 | else: |
195 | self.failUnless(not cache.get((name, dns.rdatatype.A, | |
194 | self.assertTrue(not cache.get((name, dns.rdatatype.A, | |
196 | 195 | dns.rdataclass.IN)) |
197 | 196 | is None) |
198 | 197 | |
199 | 198 | def testLRUDoesLRU(self): |
200 | 199 | cache = dns.resolver.LRUCache(4) |
201 | for i in xrange(0, 4): | |
200 | for i in range(0, 4): | |
202 | 201 | name = dns.name.from_text('example%d.' % i) |
203 | 202 | answer = FakeAnswer(time.time() + 1) |
204 | 203 | cache.put((name, dns.rdatatype.A, dns.rdataclass.IN), answer) |
208 | 207 | name = dns.name.from_text('example4.') |
209 | 208 | answer = FakeAnswer(time.time() + 1) |
210 | 209 | cache.put((name, dns.rdatatype.A, dns.rdataclass.IN), answer) |
211 | for i in xrange(0, 5): | |
210 | for i in range(0, 5): | |
212 | 211 | name = dns.name.from_text('example%d.' % i) |
213 | 212 | if i == 1: |
214 | self.failUnless(cache.get((name, dns.rdatatype.A, | |
213 | self.assertTrue(cache.get((name, dns.rdatatype.A, | |
215 | 214 | dns.rdataclass.IN)) |
216 | 215 | is None) |
217 | 216 | else: |
218 | self.failUnless(not cache.get((name, dns.rdatatype.A, | |
217 | self.assertTrue(not cache.get((name, dns.rdatatype.A, | |
219 | 218 | dns.rdataclass.IN)) |
220 | 219 | is None) |
221 | 220 | |
222 | 221 | def testLRUExpiration(self): |
223 | 222 | cache = dns.resolver.LRUCache(4) |
224 | for i in xrange(0, 4): | |
223 | for i in range(0, 4): | |
225 | 224 | name = dns.name.from_text('example%d.' % i) |
226 | 225 | answer = FakeAnswer(time.time() + 1) |
227 | 226 | cache.put((name, dns.rdatatype.A, dns.rdataclass.IN), answer) |
228 | 227 | time.sleep(2) |
229 | for i in xrange(0, 4): | |
230 | name = dns.name.from_text('example%d.' % i) | |
231 | self.failUnless(cache.get((name, dns.rdatatype.A, | |
228 | for i in range(0, 4): | |
229 | name = dns.name.from_text('example%d.' % i) | |
230 | self.assertTrue(cache.get((name, dns.rdatatype.A, | |
232 | 231 | dns.rdataclass.IN)) |
233 | 232 | is None) |
234 | 233 | |
282 | 281 | try: |
283 | 282 | raise dns.resolver.NXDOMAIN |
284 | 283 | except dns.exception.DNSException as e: |
285 | if not PY3: | |
286 | # pylint: disable=exception-message-attribute | |
287 | self.assertTrue((e.message == e.__doc__)) | |
288 | 284 | self.assertTrue((e.args == (e.__doc__,))) |
289 | 285 | self.assertTrue(('kwargs' in dir(e))) |
290 | 286 | self.assertTrue((str(e) == e.__doc__), str(e)) |
294 | 290 | try: |
295 | 291 | raise dns.resolver.NXDOMAIN("errmsg") |
296 | 292 | except dns.exception.DNSException as e: |
297 | if not PY3: | |
298 | # pylint: disable=exception-message-attribute | |
299 | self.assertTrue((e.message == "errmsg")) | |
300 | 293 | self.assertTrue((e.args == ("errmsg",))) |
301 | 294 | self.assertTrue(('kwargs' in dir(e))) |
302 | 295 | self.assertTrue((str(e) == "errmsg"), str(e)) |
306 | 299 | try: |
307 | 300 | raise dns.resolver.NXDOMAIN("errmsg", -1) |
308 | 301 | except dns.exception.DNSException as e: |
309 | if not PY3: | |
310 | # pylint: disable=exception-message-attribute | |
311 | self.assertTrue((e.message == "")) | |
312 | 302 | self.assertTrue((e.args == ("errmsg", -1))) |
313 | 303 | self.assertTrue(('kwargs' in dir(e))) |
314 | 304 | self.assertTrue((str(e) == "('errmsg', -1)"), str(e)) |
334 | 324 | raise dns.resolver.NXDOMAIN(qnames=[n1]) |
335 | 325 | except dns.exception.DNSException as e: |
336 | 326 | MSG = "The DNS query name does not exist: a.b." |
337 | if not PY3: | |
338 | # pylint: disable=exception-message-attribute | |
339 | self.assertTrue((e.message == MSG), e.message) | |
340 | 327 | self.assertTrue((e.args == (MSG,)), repr(e.args)) |
341 | 328 | self.assertTrue(('kwargs' in dir(e))) |
342 | 329 | self.assertTrue((str(e) == MSG), str(e)) |
351 | 338 | e0 = dns.resolver.NXDOMAIN("errmsg") |
352 | 339 | e = e0 + e |
353 | 340 | MSG = "None of DNS query names exist: a.b.s., a.b." |
354 | if not PY3: | |
355 | # pylint: disable=exception-message-attribute | |
356 | self.assertTrue((e.message == MSG), e.message) | |
357 | 341 | self.assertTrue((e.args == (MSG,)), repr(e.args)) |
358 | 342 | self.assertTrue(('kwargs' in dir(e))) |
359 | 343 | self.assertTrue((str(e) == MSG), str(e)) |
371 | 355 | raise dns.resolver.NXDOMAIN(qnames=[n1], responses={n1: 'r1.1'}) |
372 | 356 | except dns.resolver.NXDOMAIN as e: |
373 | 357 | MSG = "The DNS query name does not exist: a.b." |
374 | if not PY3: | |
375 | # pylint: disable=exception-message-attribute | |
376 | self.assertTrue((e.message == MSG), e.message) | |
377 | 358 | self.assertTrue((e.args == (MSG,)), repr(e.args)) |
378 | 359 | self.assertTrue(('kwargs' in dir(e))) |
379 | 360 | self.assertTrue((str(e) == MSG), str(e)) |
23 | 23 | def testEqual1(self): |
24 | 24 | r1 = dns.rrset.from_text('foo', 300, 'in', 'a', '10.0.0.1', '10.0.0.2') |
25 | 25 | r2 = dns.rrset.from_text('FOO', 300, 'in', 'a', '10.0.0.2', '10.0.0.1') |
26 | self.failUnless(r1 == r2) | |
26 | self.assertTrue(r1 == r2) | |
27 | 27 | |
28 | 28 | def testEqual2(self): |
29 | 29 | r1 = dns.rrset.from_text('foo', 300, 'in', 'a', '10.0.0.1', '10.0.0.2') |
30 | 30 | r2 = dns.rrset.from_text('FOO', 600, 'in', 'a', '10.0.0.2', '10.0.0.1') |
31 | self.failUnless(r1 == r2) | |
31 | self.assertTrue(r1 == r2) | |
32 | 32 | |
33 | 33 | def testNotEqual1(self): |
34 | 34 | r1 = dns.rrset.from_text('fooa', 30, 'in', 'a', '10.0.0.1', '10.0.0.2') |
35 | 35 | r2 = dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') |
36 | self.failUnless(r1 != r2) | |
36 | self.assertTrue(r1 != r2) | |
37 | 37 | |
38 | 38 | def testNotEqual2(self): |
39 | 39 | r1 = dns.rrset.from_text('foo', 30, 'in', 'a', '10.0.0.1', '10.0.0.3') |
40 | 40 | r2 = dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') |
41 | self.failUnless(r1 != r2) | |
41 | self.assertTrue(r1 != r2) | |
42 | 42 | |
43 | 43 | def testNotEqual3(self): |
44 | 44 | r1 = dns.rrset.from_text('foo', 30, 'in', 'a', '10.0.0.1', '10.0.0.2', |
45 | 45 | '10.0.0.3') |
46 | 46 | r2 = dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') |
47 | self.failUnless(r1 != r2) | |
47 | self.assertTrue(r1 != r2) | |
48 | 48 | |
49 | 49 | def testNotEqual4(self): |
50 | 50 | r1 = dns.rrset.from_text('foo', 30, 'in', 'a', '10.0.0.1') |
51 | 51 | r2 = dns.rrset.from_text('FOO', 30, 'in', 'a', '10.0.0.2', '10.0.0.1') |
52 | self.failUnless(r1 != r2) | |
52 | self.assertTrue(r1 != r2) | |
53 | 53 | |
54 | 54 | if __name__ == '__main__': |
55 | 55 | unittest.main() |
25 | 25 | |
26 | 26 | def testLen1(self): |
27 | 27 | s1 = S() |
28 | self.failUnless(len(s1) == 0) | |
28 | self.assertTrue(len(s1) == 0) | |
29 | 29 | |
30 | 30 | def testLen2(self): |
31 | 31 | s1 = S([1, 2, 3]) |
32 | self.failUnless(len(s1) == 3) | |
32 | self.assertTrue(len(s1) == 3) | |
33 | 33 | |
34 | 34 | def testLen3(self): |
35 | 35 | s1 = S([1, 2, 3, 3, 3]) |
36 | self.failUnless(len(s1) == 3) | |
36 | self.assertTrue(len(s1) == 3) | |
37 | 37 | |
38 | 38 | def testUnion1(self): |
39 | 39 | s1 = S([1, 2, 3]) |
40 | 40 | s2 = S([1, 2, 3]) |
41 | 41 | e = S([1, 2, 3]) |
42 | self.failUnless(s1 | s2 == e) | |
42 | self.assertTrue(s1 | s2 == e) | |
43 | 43 | |
44 | 44 | def testUnion2(self): |
45 | 45 | s1 = S([1, 2, 3]) |
46 | 46 | s2 = S([]) |
47 | 47 | e = S([1, 2, 3]) |
48 | self.failUnless(s1 | s2 == e) | |
48 | self.assertTrue(s1 | s2 == e) | |
49 | 49 | |
50 | 50 | def testUnion3(self): |
51 | 51 | s1 = S([1, 2, 3]) |
52 | 52 | s2 = S([3, 4]) |
53 | 53 | e = S([1, 2, 3, 4]) |
54 | self.failUnless(s1 | s2 == e) | |
54 | self.assertTrue(s1 | s2 == e) | |
55 | 55 | |
56 | 56 | def testIntersection1(self): |
57 | 57 | s1 = S([1, 2, 3]) |
58 | 58 | s2 = S([1, 2, 3]) |
59 | 59 | e = S([1, 2, 3]) |
60 | self.failUnless(s1 & s2 == e) | |
60 | self.assertTrue(s1 & s2 == e) | |
61 | 61 | |
62 | 62 | def testIntersection2(self): |
63 | 63 | s1 = S([0, 1, 2, 3]) |
64 | 64 | s2 = S([1, 2, 3, 4]) |
65 | 65 | e = S([1, 2, 3]) |
66 | self.failUnless(s1 & s2 == e) | |
66 | self.assertTrue(s1 & s2 == e) | |
67 | 67 | |
68 | 68 | def testIntersection3(self): |
69 | 69 | s1 = S([1, 2, 3]) |
70 | 70 | s2 = S([]) |
71 | 71 | e = S([]) |
72 | self.failUnless(s1 & s2 == e) | |
72 | self.assertTrue(s1 & s2 == e) | |
73 | 73 | |
74 | 74 | def testIntersection4(self): |
75 | 75 | s1 = S([1, 2, 3]) |
76 | 76 | s2 = S([5, 4]) |
77 | 77 | e = S([]) |
78 | self.failUnless(s1 & s2 == e) | |
78 | self.assertTrue(s1 & s2 == e) | |
79 | 79 | |
80 | 80 | def testDifference1(self): |
81 | 81 | s1 = S([1, 2, 3]) |
82 | 82 | s2 = S([5, 4]) |
83 | 83 | e = S([1, 2, 3]) |
84 | self.failUnless(s1 - s2 == e) | |
84 | self.assertTrue(s1 - s2 == e) | |
85 | 85 | |
86 | 86 | def testDifference2(self): |
87 | 87 | s1 = S([1, 2, 3]) |
88 | 88 | s2 = S([]) |
89 | 89 | e = S([1, 2, 3]) |
90 | self.failUnless(s1 - s2 == e) | |
90 | self.assertTrue(s1 - s2 == e) | |
91 | 91 | |
92 | 92 | def testDifference3(self): |
93 | 93 | s1 = S([1, 2, 3]) |
94 | 94 | s2 = S([3, 2]) |
95 | 95 | e = S([1]) |
96 | self.failUnless(s1 - s2 == e) | |
96 | self.assertTrue(s1 - s2 == e) | |
97 | 97 | |
98 | 98 | def testDifference4(self): |
99 | 99 | s1 = S([1, 2, 3]) |
100 | 100 | s2 = S([3, 2, 1]) |
101 | 101 | e = S([]) |
102 | self.failUnless(s1 - s2 == e) | |
102 | self.assertTrue(s1 - s2 == e) | |
103 | 103 | |
104 | 104 | def testSubset1(self): |
105 | 105 | s1 = S([1, 2, 3]) |
106 | 106 | s2 = S([3, 2, 1]) |
107 | self.failUnless(s1.issubset(s2)) | |
107 | self.assertTrue(s1.issubset(s2)) | |
108 | 108 | |
109 | 109 | def testSubset2(self): |
110 | 110 | s1 = S([1, 2, 3]) |
111 | self.failUnless(s1.issubset(s1)) | |
111 | self.assertTrue(s1.issubset(s1)) | |
112 | 112 | |
113 | 113 | def testSubset3(self): |
114 | 114 | s1 = S([]) |
115 | 115 | s2 = S([1, 2, 3]) |
116 | self.failUnless(s1.issubset(s2)) | |
116 | self.assertTrue(s1.issubset(s2)) | |
117 | 117 | |
118 | 118 | def testSubset4(self): |
119 | 119 | s1 = S([1]) |
120 | 120 | s2 = S([1, 2, 3]) |
121 | self.failUnless(s1.issubset(s2)) | |
121 | self.assertTrue(s1.issubset(s2)) | |
122 | 122 | |
123 | 123 | def testSubset5(self): |
124 | 124 | s1 = S([]) |
125 | 125 | s2 = S([]) |
126 | self.failUnless(s1.issubset(s2)) | |
126 | self.assertTrue(s1.issubset(s2)) | |
127 | 127 | |
128 | 128 | def testSubset6(self): |
129 | 129 | s1 = S([1, 4]) |
130 | 130 | s2 = S([1, 2, 3]) |
131 | self.failUnless(not s1.issubset(s2)) | |
131 | self.assertTrue(not s1.issubset(s2)) | |
132 | 132 | |
133 | 133 | def testSuperset1(self): |
134 | 134 | s1 = S([1, 2, 3]) |
135 | 135 | s2 = S([3, 2, 1]) |
136 | self.failUnless(s1.issuperset(s2)) | |
136 | self.assertTrue(s1.issuperset(s2)) | |
137 | 137 | |
138 | 138 | def testSuperset2(self): |
139 | 139 | s1 = S([1, 2, 3]) |
140 | self.failUnless(s1.issuperset(s1)) | |
140 | self.assertTrue(s1.issuperset(s1)) | |
141 | 141 | |
142 | 142 | def testSuperset3(self): |
143 | 143 | s1 = S([1, 2, 3]) |
144 | 144 | s2 = S([]) |
145 | self.failUnless(s1.issuperset(s2)) | |
145 | self.assertTrue(s1.issuperset(s2)) | |
146 | 146 | |
147 | 147 | def testSuperset4(self): |
148 | 148 | s1 = S([1, 2, 3]) |
149 | 149 | s2 = S([1]) |
150 | self.failUnless(s1.issuperset(s2)) | |
150 | self.assertTrue(s1.issuperset(s2)) | |
151 | 151 | |
152 | 152 | def testSuperset5(self): |
153 | 153 | s1 = S([]) |
154 | 154 | s2 = S([]) |
155 | self.failUnless(s1.issuperset(s2)) | |
155 | self.assertTrue(s1.issuperset(s2)) | |
156 | 156 | |
157 | 157 | def testSuperset6(self): |
158 | 158 | s1 = S([1, 2, 3]) |
159 | 159 | s2 = S([1, 4]) |
160 | self.failUnless(not s1.issuperset(s2)) | |
160 | self.assertTrue(not s1.issuperset(s2)) | |
161 | 161 | |
162 | 162 | def testUpdate1(self): |
163 | 163 | s1 = S([1, 2, 3]) |
164 | 164 | u = (4, 5, 6) |
165 | 165 | e = S([1, 2, 3, 4, 5, 6]) |
166 | 166 | s1.update(u) |
167 | self.failUnless(s1 == e) | |
167 | self.assertTrue(s1 == e) | |
168 | 168 | |
169 | 169 | def testUpdate2(self): |
170 | 170 | s1 = S([1, 2, 3]) |
171 | 171 | u = [] |
172 | 172 | e = S([1, 2, 3]) |
173 | 173 | s1.update(u) |
174 | self.failUnless(s1 == e) | |
174 | self.assertTrue(s1 == e) | |
175 | 175 | |
176 | 176 | def testGetitem(self): |
177 | 177 | s1 = S([1, 2, 3]) |
179 | 179 | i1 = s1[1] |
180 | 180 | i2 = s1[2] |
181 | 181 | s2 = S([i0, i1, i2]) |
182 | self.failUnless(s1 == s2) | |
182 | self.assertTrue(s1 == s2) | |
183 | 183 | |
184 | 184 | def testGetslice(self): |
185 | 185 | s1 = S([1, 2, 3]) |
186 | 186 | slice = s1[0:2] |
187 | self.failUnless(len(slice) == 2) | |
187 | self.assertTrue(len(slice) == 2) | |
188 | 188 | item = s1[2] |
189 | 189 | slice.append(item) |
190 | 190 | s2 = S(slice) |
191 | self.failUnless(s1 == s2) | |
191 | self.assertTrue(s1 == s2) | |
192 | 192 | |
193 | 193 | def testDelitem(self): |
194 | 194 | s1 = S([1, 2, 3]) |
195 | 195 | del s1[0] |
196 | 196 | i1 = s1[0] |
197 | 197 | i2 = s1[1] |
198 | self.failUnless(i1 != i2) | |
199 | self.failUnless(i1 == 1 or i1 == 2 or i1 == 3) | |
200 | self.failUnless(i2 == 1 or i2 == 2 or i2 == 3) | |
198 | self.assertTrue(i1 != i2) | |
199 | self.assertTrue(i1 == 1 or i1 == 2 or i1 == 3) | |
200 | self.assertTrue(i2 == 1 or i2 == 2 or i2 == 3) | |
201 | 201 | |
202 | 202 | def testDelslice(self): |
203 | 203 | s1 = S([1, 2, 3]) |
204 | 204 | del s1[0:2] |
205 | 205 | i1 = s1[0] |
206 | self.failUnless(i1 == 1 or i1 == 2 or i1 == 3) | |
206 | self.assertTrue(i1 == 1 or i1 == 2 or i1 == 3) | |
207 | 207 | |
208 | 208 | if __name__ == '__main__': |
209 | 209 | unittest.main() |
26 | 26 | def testStr(self): |
27 | 27 | tok = dns.tokenizer.Tokenizer('foo') |
28 | 28 | token = tok.get() |
29 | self.failUnless(token == Token(dns.tokenizer.IDENTIFIER, 'foo')) | |
30 | ||
31 | def testUnicode(self): | |
32 | tok = dns.tokenizer.Tokenizer(u'foo') | |
33 | token = tok.get() | |
34 | self.failUnless(token == Token(dns.tokenizer.IDENTIFIER, 'foo')) | |
29 | self.assertTrue(token == Token(dns.tokenizer.IDENTIFIER, 'foo')) | |
35 | 30 | |
36 | 31 | def testQuotedString1(self): |
37 | 32 | tok = dns.tokenizer.Tokenizer(r'"foo"') |
38 | 33 | token = tok.get() |
39 | self.failUnless(token == Token(dns.tokenizer.QUOTED_STRING, 'foo')) | |
34 | self.assertTrue(token == Token(dns.tokenizer.QUOTED_STRING, 'foo')) | |
40 | 35 | |
41 | 36 | def testQuotedString2(self): |
42 | 37 | tok = dns.tokenizer.Tokenizer(r'""') |
43 | 38 | token = tok.get() |
44 | self.failUnless(token == Token(dns.tokenizer.QUOTED_STRING, '')) | |
39 | self.assertTrue(token == Token(dns.tokenizer.QUOTED_STRING, '')) | |
45 | 40 | |
46 | 41 | def testQuotedString3(self): |
47 | 42 | tok = dns.tokenizer.Tokenizer(r'"\"foo\""') |
48 | 43 | token = tok.get() |
49 | self.failUnless(token == Token(dns.tokenizer.QUOTED_STRING, '"foo"')) | |
44 | self.assertTrue(token == Token(dns.tokenizer.QUOTED_STRING, '"foo"')) | |
50 | 45 | |
51 | 46 | def testQuotedString4(self): |
52 | 47 | tok = dns.tokenizer.Tokenizer(r'"foo\010bar"') |
53 | 48 | token = tok.get() |
54 | self.failUnless(token == Token(dns.tokenizer.QUOTED_STRING, 'foo\x0abar')) | |
49 | self.assertTrue(token == Token(dns.tokenizer.QUOTED_STRING, 'foo\x0abar')) | |
55 | 50 | |
56 | 51 | def testQuotedString5(self): |
57 | 52 | def bad(): |
58 | 53 | tok = dns.tokenizer.Tokenizer(r'"foo') |
59 | 54 | tok.get() |
60 | self.failUnlessRaises(dns.exception.UnexpectedEnd, bad) | |
55 | self.assertRaises(dns.exception.UnexpectedEnd, bad) | |
61 | 56 | |
62 | 57 | def testQuotedString6(self): |
63 | 58 | def bad(): |
64 | 59 | tok = dns.tokenizer.Tokenizer(r'"foo\01') |
65 | 60 | tok.get() |
66 | self.failUnlessRaises(dns.exception.SyntaxError, bad) | |
61 | self.assertRaises(dns.exception.SyntaxError, bad) | |
67 | 62 | |
68 | 63 | def testQuotedString7(self): |
69 | 64 | def bad(): |
70 | 65 | tok = dns.tokenizer.Tokenizer('"foo\nbar"') |
71 | 66 | tok.get() |
72 | self.failUnlessRaises(dns.exception.SyntaxError, bad) | |
67 | self.assertRaises(dns.exception.SyntaxError, bad) | |
73 | 68 | |
74 | 69 | def testEmpty1(self): |
75 | 70 | tok = dns.tokenizer.Tokenizer('') |
76 | 71 | token = tok.get() |
77 | self.failUnless(token.is_eof()) | |
72 | self.assertTrue(token.is_eof()) | |
78 | 73 | |
79 | 74 | def testEmpty2(self): |
80 | 75 | tok = dns.tokenizer.Tokenizer('') |
81 | 76 | token1 = tok.get() |
82 | 77 | token2 = tok.get() |
83 | self.failUnless(token1.is_eof() and token2.is_eof()) | |
78 | self.assertTrue(token1.is_eof() and token2.is_eof()) | |
84 | 79 | |
85 | 80 | def testEOL(self): |
86 | 81 | tok = dns.tokenizer.Tokenizer('\n') |
87 | 82 | token1 = tok.get() |
88 | 83 | token2 = tok.get() |
89 | self.failUnless(token1.is_eol() and token2.is_eof()) | |
84 | self.assertTrue(token1.is_eol() and token2.is_eof()) | |
90 | 85 | |
91 | 86 | def testWS1(self): |
92 | 87 | tok = dns.tokenizer.Tokenizer(' \n') |
93 | 88 | token1 = tok.get() |
94 | self.failUnless(token1.is_eol()) | |
89 | self.assertTrue(token1.is_eol()) | |
95 | 90 | |
96 | 91 | def testWS2(self): |
97 | 92 | tok = dns.tokenizer.Tokenizer(' \n') |
98 | 93 | token1 = tok.get(want_leading=True) |
99 | self.failUnless(token1.is_whitespace()) | |
94 | self.assertTrue(token1.is_whitespace()) | |
100 | 95 | |
101 | 96 | def testComment1(self): |
102 | 97 | tok = dns.tokenizer.Tokenizer(' ;foo\n') |
103 | 98 | token1 = tok.get() |
104 | self.failUnless(token1.is_eol()) | |
99 | self.assertTrue(token1.is_eol()) | |
105 | 100 | |
106 | 101 | def testComment2(self): |
107 | 102 | tok = dns.tokenizer.Tokenizer(' ;foo\n') |
108 | 103 | token1 = tok.get(want_comment=True) |
109 | 104 | token2 = tok.get() |
110 | self.failUnless(token1 == Token(dns.tokenizer.COMMENT, 'foo') and | |
105 | self.assertTrue(token1 == Token(dns.tokenizer.COMMENT, 'foo') and | |
111 | 106 | token2.is_eol()) |
112 | 107 | |
113 | 108 | def testComment3(self): |
114 | 109 | tok = dns.tokenizer.Tokenizer(' ;foo bar\n') |
115 | 110 | token1 = tok.get(want_comment=True) |
116 | 111 | token2 = tok.get() |
117 | self.failUnless(token1 == Token(dns.tokenizer.COMMENT, 'foo bar') and | |
112 | self.assertTrue(token1 == Token(dns.tokenizer.COMMENT, 'foo bar') and | |
118 | 113 | token2.is_eol()) |
119 | 114 | |
120 | 115 | def testMultiline1(self): |
121 | 116 | tok = dns.tokenizer.Tokenizer('( foo\n\n bar\n)') |
122 | 117 | tokens = list(iter(tok)) |
123 | self.failUnless(tokens == [Token(dns.tokenizer.IDENTIFIER, 'foo'), | |
118 | self.assertTrue(tokens == [Token(dns.tokenizer.IDENTIFIER, 'foo'), | |
124 | 119 | Token(dns.tokenizer.IDENTIFIER, 'bar')]) |
125 | 120 | |
126 | 121 | def testMultiline2(self): |
127 | 122 | tok = dns.tokenizer.Tokenizer('( foo\n\n bar\n)\n') |
128 | 123 | tokens = list(iter(tok)) |
129 | self.failUnless(tokens == [Token(dns.tokenizer.IDENTIFIER, 'foo'), | |
124 | self.assertTrue(tokens == [Token(dns.tokenizer.IDENTIFIER, 'foo'), | |
130 | 125 | Token(dns.tokenizer.IDENTIFIER, 'bar'), |
131 | 126 | Token(dns.tokenizer.EOL, '\n')]) |
132 | 127 | def testMultiline3(self): |
133 | 128 | def bad(): |
134 | 129 | tok = dns.tokenizer.Tokenizer('foo)') |
135 | 130 | list(iter(tok)) |
136 | self.failUnlessRaises(dns.exception.SyntaxError, bad) | |
131 | self.assertRaises(dns.exception.SyntaxError, bad) | |
137 | 132 | |
138 | 133 | def testMultiline4(self): |
139 | 134 | def bad(): |
140 | 135 | tok = dns.tokenizer.Tokenizer('((foo)') |
141 | 136 | list(iter(tok)) |
142 | self.failUnlessRaises(dns.exception.SyntaxError, bad) | |
137 | self.assertRaises(dns.exception.SyntaxError, bad) | |
143 | 138 | |
144 | 139 | def testUnget1(self): |
145 | 140 | tok = dns.tokenizer.Tokenizer('foo') |
146 | 141 | t1 = tok.get() |
147 | 142 | tok.unget(t1) |
148 | 143 | t2 = tok.get() |
149 | self.failUnless(t1 == t2 and t1.ttype == dns.tokenizer.IDENTIFIER and \ | |
144 | self.assertTrue(t1 == t2 and t1.ttype == dns.tokenizer.IDENTIFIER and \ | |
150 | 145 | t1.value == 'foo') |
151 | 146 | |
152 | 147 | def testUnget2(self): |
155 | 150 | t1 = tok.get() |
156 | 151 | tok.unget(t1) |
157 | 152 | tok.unget(t1) |
158 | self.failUnlessRaises(dns.tokenizer.UngetBufferFull, bad) | |
153 | self.assertRaises(dns.tokenizer.UngetBufferFull, bad) | |
159 | 154 | |
160 | 155 | def testGetEOL1(self): |
161 | 156 | tok = dns.tokenizer.Tokenizer('\n') |
162 | 157 | t = tok.get_eol() |
163 | self.failUnless(t == '\n') | |
158 | self.assertTrue(t == '\n') | |
164 | 159 | |
165 | 160 | def testGetEOL2(self): |
166 | 161 | tok = dns.tokenizer.Tokenizer('') |
167 | 162 | t = tok.get_eol() |
168 | self.failUnless(t == '') | |
163 | self.assertTrue(t == '') | |
169 | 164 | |
170 | 165 | def testEscapedDelimiter1(self): |
171 | 166 | tok = dns.tokenizer.Tokenizer(r'ch\ ld') |
172 | 167 | t = tok.get() |
173 | self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\ ld') | |
168 | self.assertTrue(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\ ld') | |
174 | 169 | |
175 | 170 | def testEscapedDelimiter2(self): |
176 | 171 | tok = dns.tokenizer.Tokenizer(r'ch\032ld') |
177 | 172 | t = tok.get() |
178 | self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\032ld') | |
173 | self.assertTrue(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\032ld') | |
179 | 174 | |
180 | 175 | def testEscapedDelimiter3(self): |
181 | 176 | tok = dns.tokenizer.Tokenizer(r'ch\ild') |
182 | 177 | t = tok.get() |
183 | self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\ild') | |
178 | self.assertTrue(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\ild') | |
184 | 179 | |
185 | 180 | def testEscapedDelimiter1u(self): |
186 | 181 | tok = dns.tokenizer.Tokenizer(r'ch\ ld') |
187 | 182 | t = tok.get().unescape() |
188 | self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch ld') | |
183 | self.assertTrue(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch ld') | |
189 | 184 | |
190 | 185 | def testEscapedDelimiter2u(self): |
191 | 186 | tok = dns.tokenizer.Tokenizer(r'ch\032ld') |
192 | 187 | t = tok.get().unescape() |
193 | self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == 'ch ld') | |
188 | self.assertTrue(t.ttype == dns.tokenizer.IDENTIFIER and t.value == 'ch ld') | |
194 | 189 | |
195 | 190 | def testEscapedDelimiter3u(self): |
196 | 191 | tok = dns.tokenizer.Tokenizer(r'ch\ild') |
197 | 192 | t = tok.get().unescape() |
198 | self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'child') | |
193 | self.assertTrue(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'child') | |
199 | 194 | |
200 | 195 | if __name__ == '__main__': |
201 | 196 | unittest.main() |
0 | # Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license | |
1 | ||
2 | import base64 | |
3 | import unittest | |
4 | ||
5 | import dns.tsigkeyring | |
6 | ||
7 | text_keyring = { | |
8 | 'keyname.' : 'NjHwPsMKjdN++dOfE5iAiQ==' | |
9 | } | |
10 | ||
11 | rich_keyring = { | |
12 | dns.name.from_text('keyname.') : \ | |
13 | base64.decodebytes('NjHwPsMKjdN++dOfE5iAiQ=='.encode()) | |
14 | } | |
15 | ||
16 | class TSIGKeyRingTestCase(unittest.TestCase): | |
17 | ||
18 | def test_from_text(self): | |
19 | """text keyring -> rich keyring""" | |
20 | rkeyring = dns.tsigkeyring.from_text(text_keyring) | |
21 | self.assertEqual(rkeyring, rich_keyring) | |
22 | ||
23 | def test_to_text(self): | |
24 | """text keyring -> rich keyring -> text keyring""" | |
25 | tkeyring = dns.tsigkeyring.to_text(rich_keyring) | |
26 | self.assertEqual(tkeyring, text_keyring) | |
27 | ||
28 | def test_from_and_to_text(self): | |
29 | """text keyring -> rich keyring -> text keyring""" | |
30 | rkeyring = dns.tsigkeyring.from_text(text_keyring) | |
31 | tkeyring = dns.tsigkeyring.to_text(rkeyring) | |
32 | self.assertEqual(tkeyring, text_keyring) |
74 | 74 | update.delete('bar', 'a', '10.0.0.4') |
75 | 75 | update.delete('blaz', 'a') |
76 | 76 | update.delete('blaz2') |
77 | self.failUnless(update.to_wire() == goodwire) | |
77 | self.assertTrue(update.to_wire() == goodwire) | |
78 | 78 | |
79 | 79 | def test_to_wire2(self): # type: () -> None |
80 | 80 | update = dns.update.Update('example') |
89 | 89 | update.delete('bar', 'a', '10.0.0.4') |
90 | 90 | update.delete('blaz', 'a') |
91 | 91 | update.delete('blaz2') |
92 | self.failUnless(update.to_wire() == goodwire) | |
92 | self.assertTrue(update.to_wire() == goodwire) | |
93 | 93 | |
94 | 94 | def test_to_wire3(self): # type: () -> None |
95 | 95 | update = dns.update.Update('example') |
104 | 104 | update.delete('bar', 'a', '10.0.0.4') |
105 | 105 | update.delete('blaz', 'a') |
106 | 106 | update.delete('blaz2') |
107 | self.failUnless(update.to_wire() == goodwire) | |
107 | self.assertTrue(update.to_wire() == goodwire) | |
108 | 108 | |
109 | 109 | def test_from_text1(self): # type: () -> None |
110 | 110 | update = dns.message.from_text(update_text) |
111 | 111 | w = update.to_wire(origin=dns.name.from_text('example'), |
112 | 112 | want_shuffle=False) |
113 | self.failUnless(w == goodwire) | |
113 | self.assertTrue(w == goodwire) | |
114 | 114 | |
115 | 115 | if __name__ == '__main__': |
116 | 116 | unittest.main() |
58 | 58 | """Get data one by one item""" |
59 | 59 | data = b'0123456789' |
60 | 60 | inst = WireData(data) |
61 | for i, byte in enumerate(bytearray(data)): | |
61 | for i, byte in enumerate(data): | |
62 | 62 | self.assertEqual(inst[i], byte) |
63 | 63 | for i in range(-1, len(data) * -1, -1): |
64 | self.assertEqual(inst[i], bytearray(data)[i]) | |
64 | self.assertEqual(inst[i], data[i]) | |
65 | 65 | |
66 | 66 | def testEmptySlice(self): |
67 | 67 | """Test empty slice""" |
146 | 146 | finally: |
147 | 147 | if not _keep_output: |
148 | 148 | os.unlink(here('example1.out')) |
149 | self.failUnless(ok) | |
149 | self.assertTrue(ok) | |
150 | 150 | |
151 | 151 | def testFromFile2(self): # type: () -> None |
152 | 152 | z = dns.zone.from_file(here('example'), 'example', relativize=False) |
158 | 158 | finally: |
159 | 159 | if not _keep_output: |
160 | 160 | os.unlink(here('example2.out')) |
161 | self.failUnless(ok) | |
161 | self.assertTrue(ok) | |
162 | 162 | |
163 | 163 | def testToFileTextualStream(self): # type: () -> None |
164 | 164 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
187 | 187 | finally: |
188 | 188 | if not _keep_output: |
189 | 189 | os.unlink(here('example3-textual.out')) |
190 | self.failUnless(ok) | |
190 | self.assertTrue(ok) | |
191 | 191 | |
192 | 192 | def testToFileBinary(self): # type: () -> None |
193 | 193 | z = dns.zone.from_file(here('example'), 'example') |
200 | 200 | finally: |
201 | 201 | if not _keep_output: |
202 | 202 | os.unlink(here('example3-binary.out')) |
203 | self.failUnless(ok) | |
203 | self.assertTrue(ok) | |
204 | 204 | |
205 | 205 | def testToFileFilename(self): # type: () -> None |
206 | 206 | z = dns.zone.from_file(here('example'), 'example') |
211 | 211 | finally: |
212 | 212 | if not _keep_output: |
213 | 213 | os.unlink(here('example3-filename.out')) |
214 | self.failUnless(ok) | |
214 | self.assertTrue(ok) | |
215 | 215 | |
216 | 216 | def testToText(self): # type: () -> None |
217 | 217 | z = dns.zone.from_file(here('example'), 'example') |
226 | 226 | finally: |
227 | 227 | if not _keep_output: |
228 | 228 | os.unlink(here('example3.out')) |
229 | self.failUnless(ok) | |
229 | self.assertTrue(ok) | |
230 | 230 | |
231 | 231 | def testFromText(self): # type: () -> None |
232 | 232 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
235 | 235 | names.sort() |
236 | 236 | for n in names: |
237 | 237 | f.write(z[n].to_text(n)) |
238 | f.write(u'\n') | |
238 | f.write('\n') | |
239 | 239 | self.assertEqual(f.getvalue(), example_text_output) |
240 | 240 | |
241 | 241 | def testTorture1(self): # type: () -> None |
257 | 257 | rd2 = dns.rdata.from_wire(rds.rdclass, rds.rdtype, |
258 | 258 | wire, 0, len(wire), |
259 | 259 | origin=o) |
260 | self.failUnless(rd == rd2) | |
260 | self.assertTrue(rd == rd2) | |
261 | 261 | |
262 | 262 | def testEqual(self): # type: () -> None |
263 | 263 | z1 = dns.zone.from_text(example_text, 'example.', relativize=True) |
264 | 264 | z2 = dns.zone.from_text(example_text_output, 'example.', |
265 | 265 | relativize=True) |
266 | self.failUnless(z1 == z2) | |
266 | self.assertTrue(z1 == z2) | |
267 | 267 | |
268 | 268 | def testNotEqual1(self): # type: () -> None |
269 | 269 | z1 = dns.zone.from_text(example_text, 'example.', relativize=True) |
270 | 270 | z2 = dns.zone.from_text(something_quite_similar, 'example.', |
271 | 271 | relativize=True) |
272 | self.failUnless(z1 != z2) | |
272 | self.assertTrue(z1 != z2) | |
273 | 273 | |
274 | 274 | def testNotEqual2(self): # type: () -> None |
275 | 275 | z1 = dns.zone.from_text(example_text, 'example.', relativize=True) |
276 | 276 | z2 = dns.zone.from_text(something_different, 'example.', |
277 | 277 | relativize=True) |
278 | self.failUnless(z1 != z2) | |
278 | self.assertTrue(z1 != z2) | |
279 | 279 | |
280 | 280 | def testNotEqual3(self): # type: () -> None |
281 | 281 | z1 = dns.zone.from_text(example_text, 'example.', relativize=True) |
282 | 282 | z2 = dns.zone.from_text(something_different, 'example2.', |
283 | 283 | relativize=True) |
284 | self.failUnless(z1 != z2) | |
284 | self.assertTrue(z1 != z2) | |
285 | 285 | |
286 | 286 | def testFindRdataset1(self): # type: () -> None |
287 | 287 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
288 | 288 | rds = z.find_rdataset('@', 'soa') |
289 | 289 | exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') |
290 | self.failUnless(rds == exrds) | |
290 | self.assertTrue(rds == exrds) | |
291 | 291 | |
292 | 292 | def testFindRdataset2(self): # type: () -> None |
293 | 293 | def bad(): # type: () -> None |
294 | 294 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
295 | 295 | z.find_rdataset('@', 'loc') |
296 | self.failUnlessRaises(KeyError, bad) | |
296 | self.assertRaises(KeyError, bad) | |
297 | 297 | |
298 | 298 | def testFindRRset1(self): # type: () -> None |
299 | 299 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
300 | 300 | rrs = z.find_rrset('@', 'soa') |
301 | 301 | exrrs = dns.rrset.from_text('@', 300, 'IN', 'SOA', 'foo bar 1 2 3 4 5') |
302 | self.failUnless(rrs == exrrs) | |
302 | self.assertTrue(rrs == exrrs) | |
303 | 303 | |
304 | 304 | def testFindRRset2(self): # type: () -> None |
305 | 305 | def bad(): # type: () -> None |
306 | 306 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
307 | 307 | z.find_rrset('@', 'loc') |
308 | self.failUnlessRaises(KeyError, bad) | |
308 | self.assertRaises(KeyError, bad) | |
309 | 309 | |
310 | 310 | def testGetRdataset1(self): # type: () -> None |
311 | 311 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
312 | 312 | rds = z.get_rdataset('@', 'soa') |
313 | 313 | exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') |
314 | self.failUnless(rds == exrds) | |
314 | self.assertTrue(rds == exrds) | |
315 | 315 | |
316 | 316 | def testGetRdataset2(self): # type: () -> None |
317 | 317 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
318 | 318 | rds = z.get_rdataset('@', 'loc') |
319 | self.failUnless(rds is None) | |
319 | self.assertTrue(rds is None) | |
320 | 320 | |
321 | 321 | def testGetRRset1(self): # type: () -> None |
322 | 322 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
323 | 323 | rrs = z.get_rrset('@', 'soa') |
324 | 324 | exrrs = dns.rrset.from_text('@', 300, 'IN', 'SOA', 'foo bar 1 2 3 4 5') |
325 | self.failUnless(rrs == exrrs) | |
325 | self.assertTrue(rrs == exrrs) | |
326 | 326 | |
327 | 327 | def testGetRRset2(self): # type: () -> None |
328 | 328 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
329 | 329 | rrs = z.get_rrset('@', 'loc') |
330 | self.failUnless(rrs is None) | |
330 | self.assertTrue(rrs is None) | |
331 | 331 | |
332 | 332 | def testReplaceRdataset1(self): # type: () -> None |
333 | 333 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
334 | 334 | rdataset = dns.rdataset.from_text('in', 'ns', 300, 'ns3', 'ns4') |
335 | 335 | z.replace_rdataset('@', rdataset) |
336 | 336 | rds = z.get_rdataset('@', 'ns') |
337 | self.failUnless(rds is rdataset) | |
337 | self.assertTrue(rds is rdataset) | |
338 | 338 | |
339 | 339 | def testReplaceRdataset2(self): # type: () -> None |
340 | 340 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
341 | 341 | rdataset = dns.rdataset.from_text('in', 'txt', 300, '"foo"') |
342 | 342 | z.replace_rdataset('@', rdataset) |
343 | 343 | rds = z.get_rdataset('@', 'txt') |
344 | self.failUnless(rds is rdataset) | |
344 | self.assertTrue(rds is rdataset) | |
345 | 345 | |
346 | 346 | def testDeleteRdataset1(self): # type: () -> None |
347 | 347 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
348 | 348 | z.delete_rdataset('@', 'ns') |
349 | 349 | rds = z.get_rdataset('@', 'ns') |
350 | self.failUnless(rds is None) | |
350 | self.assertTrue(rds is None) | |
351 | 351 | |
352 | 352 | def testDeleteRdataset2(self): # type: () -> None |
353 | 353 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
354 | 354 | z.delete_rdataset('ns1', 'a') |
355 | 355 | node = z.get_node('ns1') |
356 | self.failUnless(node is None) | |
356 | self.assertTrue(node is None) | |
357 | 357 | |
358 | 358 | def testNodeFindRdataset1(self): # type: () -> None |
359 | 359 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
360 | 360 | node = z['@'] |
361 | 361 | rds = node.find_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) |
362 | 362 | exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') |
363 | self.failUnless(rds == exrds) | |
363 | self.assertTrue(rds == exrds) | |
364 | 364 | |
365 | 365 | def testNodeFindRdataset2(self): # type: () -> None |
366 | 366 | def bad(): # type: () -> None |
367 | 367 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
368 | 368 | node = z['@'] |
369 | 369 | node.find_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) |
370 | self.failUnlessRaises(KeyError, bad) | |
370 | self.assertRaises(KeyError, bad) | |
371 | 371 | |
372 | 372 | def testNodeGetRdataset1(self): # type: () -> None |
373 | 373 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
374 | 374 | node = z['@'] |
375 | 375 | rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) |
376 | 376 | exrds = dns.rdataset.from_text('IN', 'SOA', 300, 'foo bar 1 2 3 4 5') |
377 | self.failUnless(rds == exrds) | |
377 | self.assertTrue(rds == exrds) | |
378 | 378 | |
379 | 379 | def testNodeGetRdataset2(self): # type: () -> None |
380 | 380 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
381 | 381 | node = z['@'] |
382 | 382 | rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) |
383 | self.failUnless(rds is None) | |
383 | self.assertTrue(rds is None) | |
384 | 384 | |
385 | 385 | def testNodeDeleteRdataset1(self): # type: () -> None |
386 | 386 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
387 | 387 | node = z['@'] |
388 | 388 | node.delete_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) |
389 | 389 | rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) |
390 | self.failUnless(rds is None) | |
390 | self.assertTrue(rds is None) | |
391 | 391 | |
392 | 392 | def testNodeDeleteRdataset2(self): # type: () -> None |
393 | 393 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
394 | 394 | node = z['@'] |
395 | 395 | node.delete_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) |
396 | 396 | rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) |
397 | self.failUnless(rds is None) | |
397 | self.assertTrue(rds is None) | |
398 | 398 | |
399 | 399 | def testIterateRdatasets(self): # type: () -> None |
400 | 400 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
401 | 401 | ns = [n for n, r in z.iterate_rdatasets('A')] |
402 | 402 | ns.sort() |
403 | self.failUnless(ns == [dns.name.from_text('ns1', None), | |
403 | self.assertTrue(ns == [dns.name.from_text('ns1', None), | |
404 | 404 | dns.name.from_text('ns2', None)]) |
405 | 405 | |
406 | 406 | def testIterateAllRdatasets(self): # type: () -> None |
407 | 407 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
408 | 408 | ns = [n for n, r in z.iterate_rdatasets()] |
409 | 409 | ns.sort() |
410 | self.failUnless(ns == [dns.name.from_text('@', None), | |
410 | self.assertTrue(ns == [dns.name.from_text('@', None), | |
411 | 411 | dns.name.from_text('@', None), |
412 | 412 | dns.name.from_text('bar.foo', None), |
413 | 413 | dns.name.from_text('ns1', None), |
425 | 425 | 3600, |
426 | 426 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, |
427 | 427 | '10.0.0.2'))] |
428 | self.failUnless(l == exl) | |
428 | self.assertTrue(l == exl) | |
429 | 429 | |
430 | 430 | def testIterateAllRdatas(self): # type: () -> None |
431 | 431 | z = dns.zone.from_text(example_text, 'example.', relativize=True) |
456 | 456 | dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, |
457 | 457 | '10.0.0.2'))] |
458 | 458 | exl.sort(key=_rdata_sort) |
459 | self.failUnless(l == exl) | |
459 | self.assertTrue(l == exl) | |
460 | 460 | |
461 | 461 | def testTTLs(self): # type: () -> None |
462 | 462 | z = dns.zone.from_text(ttl_example_text, 'example.', relativize=True) |
463 | 463 | n = z['@'] # type: dns.node.Node |
464 | 464 | rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA)) |
465 | self.failUnless(rds.ttl == 3600) | |
465 | self.assertTrue(rds.ttl == 3600) | |
466 | 466 | n = z['ns1'] |
467 | 467 | rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A)) |
468 | self.failUnless(rds.ttl == 86401) | |
468 | self.assertTrue(rds.ttl == 86401) | |
469 | 469 | n = z['ns2'] |
470 | 470 | rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A)) |
471 | self.failUnless(rds.ttl == 694861) | |
471 | self.assertTrue(rds.ttl == 694861) | |
472 | 472 | |
473 | 473 | def testTTLFromSOA(self): # type: () -> None |
474 | 474 | z = dns.zone.from_text(ttl_from_soa_text, 'example.', relativize=True) |
475 | 475 | n = z['@'] |
476 | 476 | rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA)) |
477 | self.failUnless(rds.ttl == 3600) | |
477 | self.assertTrue(rds.ttl == 3600) | |
478 | 478 | soa_rd = rds[0] |
479 | 479 | n = z['ns1'] |
480 | 480 | rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A)) |
481 | self.failUnless(rds.ttl == 694861) | |
481 | self.assertTrue(rds.ttl == 694861) | |
482 | 482 | n = z['ns2'] |
483 | 483 | rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A)) |
484 | self.failUnless(rds.ttl == soa_rd.minimum) | |
484 | self.assertTrue(rds.ttl == soa_rd.minimum) | |
485 | 485 | |
486 | 486 | def testTTLFromLast(self): # type: () -> None |
487 | 487 | z = dns.zone.from_text(ttl_from_last_text, 'example.', check_origin=False) |
488 | 488 | n = z['@'] |
489 | 489 | rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.NS)) |
490 | self.failUnless(rds.ttl == 3600) | |
490 | self.assertTrue(rds.ttl == 3600) | |
491 | 491 | n = z['ns1'] |
492 | 492 | rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A)) |
493 | self.failUnless(rds.ttl == 3600) | |
493 | self.assertTrue(rds.ttl == 3600) | |
494 | 494 | n = z['ns2'] |
495 | 495 | rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A)) |
496 | self.failUnless(rds.ttl == 694861) | |
496 | self.assertTrue(rds.ttl == 694861) | |
497 | 497 | |
498 | 498 | def testNoTTL(self): # type: () -> None |
499 | 499 | def bad(): # type: () -> None |
500 | 500 | dns.zone.from_text(no_ttl_text, 'example.', check_origin=False) |
501 | self.failUnlessRaises(dns.exception.SyntaxError, bad) | |
501 | self.assertRaises(dns.exception.SyntaxError, bad) | |
502 | 502 | |
503 | 503 | def testNoSOA(self): # type: () -> None |
504 | 504 | def bad(): # type: () -> None |
505 | 505 | dns.zone.from_text(no_soa_text, 'example.', relativize=True) |
506 | self.failUnlessRaises(dns.zone.NoSOA, bad) | |
506 | self.assertRaises(dns.zone.NoSOA, bad) | |
507 | 507 | |
508 | 508 | def testNoNS(self): # type: () -> None |
509 | 509 | def bad(): # type: () -> None |
510 | 510 | dns.zone.from_text(no_ns_text, 'example.', relativize=True) |
511 | self.failUnlessRaises(dns.zone.NoNS, bad) | |
511 | self.assertRaises(dns.zone.NoNS, bad) | |
512 | 512 | |
513 | 513 | def testInclude(self): # type: () -> None |
514 | 514 | z1 = dns.zone.from_text(include_text, 'example.', relativize=True, |
515 | 515 | allow_include=True) |
516 | 516 | z2 = dns.zone.from_file(here('example'), 'example.', relativize=True) |
517 | self.failUnless(z1 == z2) | |
517 | self.assertTrue(z1 == z2) | |
518 | 518 | |
519 | 519 | def testBadDirective(self): # type: () -> None |
520 | 520 | def bad(): # type: () -> None |
521 | 521 | dns.zone.from_text(bad_directive_text, 'example.', relativize=True) |
522 | self.failUnlessRaises(dns.exception.SyntaxError, bad) | |
522 | self.assertRaises(dns.exception.SyntaxError, bad) | |
523 | 523 | |
524 | 524 | def testFirstRRStartsWithWhitespace(self): # type: () -> None |
525 | 525 | # no name is specified, so default to the initial origin |
527 | 527 | check_origin=False) |
528 | 528 | n = z['@'] |
529 | 529 | rds = cast(dns.rdataset.Rdataset, n.get_rdataset(dns.rdataclass.IN, dns.rdatatype.A)) |
530 | self.failUnless(rds.ttl == 300) | |
530 | self.assertTrue(rds.ttl == 300) | |
531 | 531 | |
532 | 532 | def testZoneOrigin(self): # type: () -> None |
533 | 533 | z = dns.zone.Zone('example.') |
534 | self.failUnless(z.origin == dns.name.from_text('example.')) | |
534 | self.assertTrue(z.origin == dns.name.from_text('example.')) | |
535 | 535 | def bad1(): # type: () -> None |
536 | 536 | o = dns.name.from_text('example', None) |
537 | 537 | dns.zone.Zone(o) |
538 | self.failUnlessRaises(ValueError, bad1) | |
538 | self.assertRaises(ValueError, bad1) | |
539 | 539 | def bad2(): # type: () -> None |
540 | 540 | dns.zone.Zone(cast(str, 1.0)) |
541 | self.failUnlessRaises(ValueError, bad2) | |
541 | self.assertRaises(ValueError, bad2) | |
542 | 542 | |
543 | 543 | def testZoneOriginNone(self): # type: () -> None |
544 | 544 | dns.zone.Zone(cast(str, None)) |