Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/dns/name.py: 50%

619 statements  

« prev     ^ index     » next       coverage.py v7.4.1, created at 2024-02-02 06:07 +0000

1# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license 

2 

3# Copyright (C) 2001-2017 Nominum, Inc. 

4# 

5# Permission to use, copy, modify, and distribute this software and its 

6# documentation for any purpose with or without fee is hereby granted, 

7# provided that the above copyright notice and this permission notice 

8# appear in all copies. 

9# 

10# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES 

11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 

12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR 

13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 

14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 

15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 

16# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 

17 

18"""DNS Names. 

19""" 

20 

21import copy 

22import encodings.idna # type: ignore 

23import functools 

24import struct 

25from typing import Any, Callable, Dict, Iterable, Optional, Tuple, Union 

26 

27try: 

28 import idna # type: ignore 

29 

30 have_idna_2008 = True 

31except ImportError: # pragma: no cover 

32 have_idna_2008 = False 

33 

34import dns.enum 

35import dns.exception 

36import dns.immutable 

37import dns.wire 

38 

39CompressType = Dict["Name", int] 

40 

41 

42class NameRelation(dns.enum.IntEnum): 

43 """Name relation result from fullcompare().""" 

44 

45 # This is an IntEnum for backwards compatibility in case anyone 

46 # has hardwired the constants. 

47 

48 #: The compared names have no relationship to each other. 

49 NONE = 0 

50 #: the first name is a superdomain of the second. 

51 SUPERDOMAIN = 1 

52 #: The first name is a subdomain of the second. 

53 SUBDOMAIN = 2 

54 #: The compared names are equal. 

55 EQUAL = 3 

56 #: The compared names have a common ancestor. 

57 COMMONANCESTOR = 4 

58 

59 @classmethod 

60 def _maximum(cls): 

61 return cls.COMMONANCESTOR 

62 

63 @classmethod 

64 def _short_name(cls): 

65 return cls.__name__ 

66 

67 

68# Backwards compatibility 

69NAMERELN_NONE = NameRelation.NONE 

70NAMERELN_SUPERDOMAIN = NameRelation.SUPERDOMAIN 

71NAMERELN_SUBDOMAIN = NameRelation.SUBDOMAIN 

72NAMERELN_EQUAL = NameRelation.EQUAL 

73NAMERELN_COMMONANCESTOR = NameRelation.COMMONANCESTOR 

74 

75 

76class EmptyLabel(dns.exception.SyntaxError): 

77 """A DNS label is empty.""" 

78 

79 

80class BadEscape(dns.exception.SyntaxError): 

81 """An escaped code in a text format of DNS name is invalid.""" 

82 

83 

84class BadPointer(dns.exception.FormError): 

85 """A DNS compression pointer points forward instead of backward.""" 

86 

87 

88class BadLabelType(dns.exception.FormError): 

89 """The label type in DNS name wire format is unknown.""" 

90 

91 

92class NeedAbsoluteNameOrOrigin(dns.exception.DNSException): 

93 """An attempt was made to convert a non-absolute name to 

94 wire when there was also a non-absolute (or missing) origin.""" 

95 

96 

97class NameTooLong(dns.exception.FormError): 

98 """A DNS name is > 255 octets long.""" 

99 

100 

101class LabelTooLong(dns.exception.SyntaxError): 

102 """A DNS label is > 63 octets long.""" 

103 

104 

105class AbsoluteConcatenation(dns.exception.DNSException): 

106 """An attempt was made to append anything other than the 

107 empty name to an absolute DNS name.""" 

108 

109 

110class NoParent(dns.exception.DNSException): 

111 """An attempt was made to get the parent of the root name 

112 or the empty name.""" 

113 

114 

115class NoIDNA2008(dns.exception.DNSException): 

116 """IDNA 2008 processing was requested but the idna module is not 

117 available.""" 

118 

119 

120class IDNAException(dns.exception.DNSException): 

121 """IDNA processing raised an exception.""" 

122 

123 supp_kwargs = {"idna_exception"} 

124 fmt = "IDNA processing exception: {idna_exception}" 

125 

126 # We do this as otherwise mypy complains about unexpected keyword argument 

127 # idna_exception 

128 def __init__(self, *args, **kwargs): 

129 super().__init__(*args, **kwargs) 

130 

131 

132class NeedSubdomainOfOrigin(dns.exception.DNSException): 

133 """An absolute name was provided that is not a subdomain of the specified origin.""" 

134 

135 

136_escaped = b'"().;\\@$' 

137_escaped_text = '"().;\\@$' 

138 

139 

140def _escapify(label: Union[bytes, str]) -> str: 

141 """Escape the characters in label which need it. 

142 @returns: the escaped string 

143 @rtype: string""" 

144 if isinstance(label, bytes): 

145 # Ordinary DNS label mode. Escape special characters and values 

146 # < 0x20 or > 0x7f. 

147 text = "" 

148 for c in label: 

149 if c in _escaped: 

150 text += "\\" + chr(c) 

151 elif c > 0x20 and c < 0x7F: 

152 text += chr(c) 

153 else: 

154 text += "\\%03d" % c 

155 return text 

156 

157 # Unicode label mode. Escape only special characters and values < 0x20 

158 text = "" 

159 for uc in label: 

160 if uc in _escaped_text: 

161 text += "\\" + uc 

162 elif uc <= "\x20": 

163 text += "\\%03d" % ord(uc) 

164 else: 

165 text += uc 

166 return text 

167 

168 

169class IDNACodec: 

170 """Abstract base class for IDNA encoder/decoders.""" 

171 

172 def __init__(self): 

173 pass 

174 

175 def is_idna(self, label: bytes) -> bool: 

176 return label.lower().startswith(b"xn--") 

177 

178 def encode(self, label: str) -> bytes: 

179 raise NotImplementedError # pragma: no cover 

180 

181 def decode(self, label: bytes) -> str: 

182 # We do not apply any IDNA policy on decode. 

183 if self.is_idna(label): 

184 try: 

185 slabel = label[4:].decode("punycode") 

186 return _escapify(slabel) 

187 except Exception as e: 

188 raise IDNAException(idna_exception=e) 

189 else: 

190 return _escapify(label) 

191 

192 

193class IDNA2003Codec(IDNACodec): 

194 """IDNA 2003 encoder/decoder.""" 

195 

196 def __init__(self, strict_decode: bool = False): 

197 """Initialize the IDNA 2003 encoder/decoder. 

198 

199 *strict_decode* is a ``bool``. If `True`, then IDNA2003 checking 

200 is done when decoding. This can cause failures if the name 

201 was encoded with IDNA2008. The default is `False`. 

202 """ 

203 

204 super().__init__() 

205 self.strict_decode = strict_decode 

206 

207 def encode(self, label: str) -> bytes: 

208 """Encode *label*.""" 

209 

210 if label == "": 

211 return b"" 

212 try: 

213 return encodings.idna.ToASCII(label) 

214 except UnicodeError: 

215 raise LabelTooLong 

216 

217 def decode(self, label: bytes) -> str: 

218 """Decode *label*.""" 

219 if not self.strict_decode: 

220 return super().decode(label) 

221 if label == b"": 

222 return "" 

223 try: 

224 return _escapify(encodings.idna.ToUnicode(label)) 

225 except Exception as e: 

226 raise IDNAException(idna_exception=e) 

227 

228 

229class IDNA2008Codec(IDNACodec): 

230 """IDNA 2008 encoder/decoder.""" 

231 

232 def __init__( 

233 self, 

234 uts_46: bool = False, 

235 transitional: bool = False, 

236 allow_pure_ascii: bool = False, 

237 strict_decode: bool = False, 

238 ): 

239 """Initialize the IDNA 2008 encoder/decoder. 

240 

241 *uts_46* is a ``bool``. If True, apply Unicode IDNA 

242 compatibility processing as described in Unicode Technical 

243 Standard #46 (https://unicode.org/reports/tr46/). 

244 If False, do not apply the mapping. The default is False. 

245 

246 *transitional* is a ``bool``: If True, use the 

247 "transitional" mode described in Unicode Technical Standard 

248 #46. The default is False. 

249 

250 *allow_pure_ascii* is a ``bool``. If True, then a label which 

251 consists of only ASCII characters is allowed. This is less 

252 strict than regular IDNA 2008, but is also necessary for mixed 

253 names, e.g. a name with starting with "_sip._tcp." and ending 

254 in an IDN suffix which would otherwise be disallowed. The 

255 default is False. 

256 

257 *strict_decode* is a ``bool``: If True, then IDNA2008 checking 

258 is done when decoding. This can cause failures if the name 

259 was encoded with IDNA2003. The default is False. 

260 """ 

261 super().__init__() 

262 self.uts_46 = uts_46 

263 self.transitional = transitional 

264 self.allow_pure_ascii = allow_pure_ascii 

265 self.strict_decode = strict_decode 

266 

267 def encode(self, label: str) -> bytes: 

268 if label == "": 

269 return b"" 

270 if self.allow_pure_ascii and is_all_ascii(label): 

271 encoded = label.encode("ascii") 

272 if len(encoded) > 63: 

273 raise LabelTooLong 

274 return encoded 

275 if not have_idna_2008: 

276 raise NoIDNA2008 

277 try: 

278 if self.uts_46: 

279 label = idna.uts46_remap(label, False, self.transitional) 

280 return idna.alabel(label) 

281 except idna.IDNAError as e: 

282 if e.args[0] == "Label too long": 

283 raise LabelTooLong 

284 else: 

285 raise IDNAException(idna_exception=e) 

286 

287 def decode(self, label: bytes) -> str: 

288 if not self.strict_decode: 

289 return super().decode(label) 

290 if label == b"": 

291 return "" 

292 if not have_idna_2008: 

293 raise NoIDNA2008 

294 try: 

295 ulabel = idna.ulabel(label) 

296 if self.uts_46: 

297 ulabel = idna.uts46_remap(ulabel, False, self.transitional) 

298 return _escapify(ulabel) 

299 except (idna.IDNAError, UnicodeError) as e: 

300 raise IDNAException(idna_exception=e) 

301 

302 

303IDNA_2003_Practical = IDNA2003Codec(False) 

304IDNA_2003_Strict = IDNA2003Codec(True) 

305IDNA_2003 = IDNA_2003_Practical 

306IDNA_2008_Practical = IDNA2008Codec(True, False, True, False) 

307IDNA_2008_UTS_46 = IDNA2008Codec(True, False, False, False) 

308IDNA_2008_Strict = IDNA2008Codec(False, False, False, True) 

309IDNA_2008_Transitional = IDNA2008Codec(True, True, False, False) 

310IDNA_2008 = IDNA_2008_Practical 

311 

312 

313def _validate_labels(labels: Tuple[bytes, ...]) -> None: 

314 """Check for empty labels in the middle of a label sequence, 

315 labels that are too long, and for too many labels. 

316 

317 Raises ``dns.name.NameTooLong`` if the name as a whole is too long. 

318 

319 Raises ``dns.name.EmptyLabel`` if a label is empty (i.e. the root 

320 label) and appears in a position other than the end of the label 

321 sequence 

322 

323 """ 

324 

325 l = len(labels) 

326 total = 0 

327 i = -1 

328 j = 0 

329 for label in labels: 

330 ll = len(label) 

331 total += ll + 1 

332 if ll > 63: 

333 raise LabelTooLong 

334 if i < 0 and label == b"": 

335 i = j 

336 j += 1 

337 if total > 255: 

338 raise NameTooLong 

339 if i >= 0 and i != l - 1: 

340 raise EmptyLabel 

341 

342 

343def _maybe_convert_to_binary(label: Union[bytes, str]) -> bytes: 

344 """If label is ``str``, convert it to ``bytes``. If it is already 

345 ``bytes`` just return it. 

346 

347 """ 

348 

349 if isinstance(label, bytes): 

350 return label 

351 if isinstance(label, str): 

352 return label.encode() 

353 raise ValueError # pragma: no cover 

354 

355 

356@dns.immutable.immutable 

357class Name: 

358 

359 """A DNS name. 

360 

361 The dns.name.Name class represents a DNS name as a tuple of 

362 labels. Each label is a ``bytes`` in DNS wire format. Instances 

363 of the class are immutable. 

364 """ 

365 

366 __slots__ = ["labels"] 

367 

368 def __init__(self, labels: Iterable[Union[bytes, str]]): 

369 """*labels* is any iterable whose values are ``str`` or ``bytes``.""" 

370 

371 blabels = [_maybe_convert_to_binary(x) for x in labels] 

372 self.labels = tuple(blabels) 

373 _validate_labels(self.labels) 

374 

375 def __copy__(self): 

376 return Name(self.labels) 

377 

378 def __deepcopy__(self, memo): 

379 return Name(copy.deepcopy(self.labels, memo)) 

380 

381 def __getstate__(self): 

382 # Names can be pickled 

383 return {"labels": self.labels} 

384 

385 def __setstate__(self, state): 

386 super().__setattr__("labels", state["labels"]) 

387 _validate_labels(self.labels) 

388 

389 def is_absolute(self) -> bool: 

390 """Is the most significant label of this name the root label? 

391 

392 Returns a ``bool``. 

393 """ 

394 

395 return len(self.labels) > 0 and self.labels[-1] == b"" 

396 

397 def is_wild(self) -> bool: 

398 """Is this name wild? (I.e. Is the least significant label '*'?) 

399 

400 Returns a ``bool``. 

401 """ 

402 

403 return len(self.labels) > 0 and self.labels[0] == b"*" 

404 

405 def __hash__(self) -> int: 

406 """Return a case-insensitive hash of the name. 

407 

408 Returns an ``int``. 

409 """ 

410 

411 h = 0 

412 for label in self.labels: 

413 for c in label.lower(): 

414 h += (h << 3) + c 

415 return h 

416 

417 def fullcompare(self, other: "Name") -> Tuple[NameRelation, int, int]: 

418 """Compare two names, returning a 3-tuple 

419 ``(relation, order, nlabels)``. 

420 

421 *relation* describes the relation ship between the names, 

422 and is one of: ``dns.name.NameRelation.NONE``, 

423 ``dns.name.NameRelation.SUPERDOMAIN``, ``dns.name.NameRelation.SUBDOMAIN``, 

424 ``dns.name.NameRelation.EQUAL``, or ``dns.name.NameRelation.COMMONANCESTOR``. 

425 

426 *order* is < 0 if *self* < *other*, > 0 if *self* > *other*, and == 

427 0 if *self* == *other*. A relative name is always less than an 

428 absolute name. If both names have the same relativity, then 

429 the DNSSEC order relation is used to order them. 

430 

431 *nlabels* is the number of significant labels that the two names 

432 have in common. 

433 

434 Here are some examples. Names ending in "." are absolute names, 

435 those not ending in "." are relative names. 

436 

437 ============= ============= =========== ===== ======= 

438 self other relation order nlabels 

439 ============= ============= =========== ===== ======= 

440 www.example. www.example. equal 0 3 

441 www.example. example. subdomain > 0 2 

442 example. www.example. superdomain < 0 2 

443 example1.com. example2.com. common anc. < 0 2 

444 example1 example2. none < 0 0 

445 example1. example2 none > 0 0 

446 ============= ============= =========== ===== ======= 

447 """ 

448 

449 sabs = self.is_absolute() 

450 oabs = other.is_absolute() 

451 if sabs != oabs: 

452 if sabs: 

453 return (NameRelation.NONE, 1, 0) 

454 else: 

455 return (NameRelation.NONE, -1, 0) 

456 l1 = len(self.labels) 

457 l2 = len(other.labels) 

458 ldiff = l1 - l2 

459 if ldiff < 0: 

460 l = l1 

461 else: 

462 l = l2 

463 

464 order = 0 

465 nlabels = 0 

466 namereln = NameRelation.NONE 

467 while l > 0: 

468 l -= 1 

469 l1 -= 1 

470 l2 -= 1 

471 label1 = self.labels[l1].lower() 

472 label2 = other.labels[l2].lower() 

473 if label1 < label2: 

474 order = -1 

475 if nlabels > 0: 

476 namereln = NameRelation.COMMONANCESTOR 

477 return (namereln, order, nlabels) 

478 elif label1 > label2: 

479 order = 1 

480 if nlabels > 0: 

481 namereln = NameRelation.COMMONANCESTOR 

482 return (namereln, order, nlabels) 

483 nlabels += 1 

484 order = ldiff 

485 if ldiff < 0: 

486 namereln = NameRelation.SUPERDOMAIN 

487 elif ldiff > 0: 

488 namereln = NameRelation.SUBDOMAIN 

489 else: 

490 namereln = NameRelation.EQUAL 

491 return (namereln, order, nlabels) 

492 

493 def is_subdomain(self, other: "Name") -> bool: 

494 """Is self a subdomain of other? 

495 

496 Note that the notion of subdomain includes equality, e.g. 

497 "dnspython.org" is a subdomain of itself. 

498 

499 Returns a ``bool``. 

500 """ 

501 

502 (nr, _, _) = self.fullcompare(other) 

503 if nr == NameRelation.SUBDOMAIN or nr == NameRelation.EQUAL: 

504 return True 

505 return False 

506 

507 def is_superdomain(self, other: "Name") -> bool: 

508 """Is self a superdomain of other? 

509 

510 Note that the notion of superdomain includes equality, e.g. 

511 "dnspython.org" is a superdomain of itself. 

512 

513 Returns a ``bool``. 

514 """ 

515 

516 (nr, _, _) = self.fullcompare(other) 

517 if nr == NameRelation.SUPERDOMAIN or nr == NameRelation.EQUAL: 

518 return True 

519 return False 

520 

521 def canonicalize(self) -> "Name": 

522 """Return a name which is equal to the current name, but is in 

523 DNSSEC canonical form. 

524 """ 

525 

526 return Name([x.lower() for x in self.labels]) 

527 

528 def __eq__(self, other): 

529 if isinstance(other, Name): 

530 return self.fullcompare(other)[1] == 0 

531 else: 

532 return False 

533 

534 def __ne__(self, other): 

535 if isinstance(other, Name): 

536 return self.fullcompare(other)[1] != 0 

537 else: 

538 return True 

539 

540 def __lt__(self, other): 

541 if isinstance(other, Name): 

542 return self.fullcompare(other)[1] < 0 

543 else: 

544 return NotImplemented 

545 

546 def __le__(self, other): 

547 if isinstance(other, Name): 

548 return self.fullcompare(other)[1] <= 0 

549 else: 

550 return NotImplemented 

551 

552 def __ge__(self, other): 

553 if isinstance(other, Name): 

554 return self.fullcompare(other)[1] >= 0 

555 else: 

556 return NotImplemented 

557 

558 def __gt__(self, other): 

559 if isinstance(other, Name): 

560 return self.fullcompare(other)[1] > 0 

561 else: 

562 return NotImplemented 

563 

564 def __repr__(self): 

565 return "<DNS name " + self.__str__() + ">" 

566 

567 def __str__(self): 

568 return self.to_text(False) 

569 

570 def to_text(self, omit_final_dot: bool = False) -> str: 

571 """Convert name to DNS text format. 

572 

573 *omit_final_dot* is a ``bool``. If True, don't emit the final 

574 dot (denoting the root label) for absolute names. The default 

575 is False. 

576 

577 Returns a ``str``. 

578 """ 

579 

580 if len(self.labels) == 0: 

581 return "@" 

582 if len(self.labels) == 1 and self.labels[0] == b"": 

583 return "." 

584 if omit_final_dot and self.is_absolute(): 

585 l = self.labels[:-1] 

586 else: 

587 l = self.labels 

588 s = ".".join(map(_escapify, l)) 

589 return s 

590 

591 def to_unicode( 

592 self, omit_final_dot: bool = False, idna_codec: Optional[IDNACodec] = None 

593 ) -> str: 

594 """Convert name to Unicode text format. 

595 

596 IDN ACE labels are converted to Unicode. 

597 

598 *omit_final_dot* is a ``bool``. If True, don't emit the final 

599 dot (denoting the root label) for absolute names. The default 

600 is False. 

601 *idna_codec* specifies the IDNA encoder/decoder. If None, the 

602 dns.name.IDNA_2003_Practical encoder/decoder is used. 

603 The IDNA_2003_Practical decoder does 

604 not impose any policy, it just decodes punycode, so if you 

605 don't want checking for compliance, you can use this decoder 

606 for IDNA2008 as well. 

607 

608 Returns a ``str``. 

609 """ 

610 

611 if len(self.labels) == 0: 

612 return "@" 

613 if len(self.labels) == 1 and self.labels[0] == b"": 

614 return "." 

615 if omit_final_dot and self.is_absolute(): 

616 l = self.labels[:-1] 

617 else: 

618 l = self.labels 

619 if idna_codec is None: 

620 idna_codec = IDNA_2003_Practical 

621 return ".".join([idna_codec.decode(x) for x in l]) 

622 

623 def to_digestable(self, origin: Optional["Name"] = None) -> bytes: 

624 """Convert name to a format suitable for digesting in hashes. 

625 

626 The name is canonicalized and converted to uncompressed wire 

627 format. All names in wire format are absolute. If the name 

628 is a relative name, then an origin must be supplied. 

629 

630 *origin* is a ``dns.name.Name`` or ``None``. If the name is 

631 relative and origin is not ``None``, then origin will be appended 

632 to the name. 

633 

634 Raises ``dns.name.NeedAbsoluteNameOrOrigin`` if the name is 

635 relative and no origin was provided. 

636 

637 Returns a ``bytes``. 

638 """ 

639 

640 digest = self.to_wire(origin=origin, canonicalize=True) 

641 assert digest is not None 

642 return digest 

643 

644 def to_wire( 

645 self, 

646 file: Optional[Any] = None, 

647 compress: Optional[CompressType] = None, 

648 origin: Optional["Name"] = None, 

649 canonicalize: bool = False, 

650 ) -> Optional[bytes]: 

651 """Convert name to wire format, possibly compressing it. 

652 

653 *file* is the file where the name is emitted (typically an 

654 io.BytesIO file). If ``None`` (the default), a ``bytes`` 

655 containing the wire name will be returned. 

656 

657 *compress*, a ``dict``, is the compression table to use. If 

658 ``None`` (the default), names will not be compressed. Note that 

659 the compression code assumes that compression offset 0 is the 

660 start of *file*, and thus compression will not be correct 

661 if this is not the case. 

662 

663 *origin* is a ``dns.name.Name`` or ``None``. If the name is 

664 relative and origin is not ``None``, then *origin* will be appended 

665 to it. 

666 

667 *canonicalize*, a ``bool``, indicates whether the name should 

668 be canonicalized; that is, converted to a format suitable for 

669 digesting in hashes. 

670 

671 Raises ``dns.name.NeedAbsoluteNameOrOrigin`` if the name is 

672 relative and no origin was provided. 

673 

674 Returns a ``bytes`` or ``None``. 

675 """ 

676 

677 if file is None: 

678 out = bytearray() 

679 for label in self.labels: 

680 out.append(len(label)) 

681 if canonicalize: 

682 out += label.lower() 

683 else: 

684 out += label 

685 if not self.is_absolute(): 

686 if origin is None or not origin.is_absolute(): 

687 raise NeedAbsoluteNameOrOrigin 

688 for label in origin.labels: 

689 out.append(len(label)) 

690 if canonicalize: 

691 out += label.lower() 

692 else: 

693 out += label 

694 return bytes(out) 

695 

696 labels: Iterable[bytes] 

697 if not self.is_absolute(): 

698 if origin is None or not origin.is_absolute(): 

699 raise NeedAbsoluteNameOrOrigin 

700 labels = list(self.labels) 

701 labels.extend(list(origin.labels)) 

702 else: 

703 labels = self.labels 

704 i = 0 

705 for label in labels: 

706 n = Name(labels[i:]) 

707 i += 1 

708 if compress is not None: 

709 pos = compress.get(n) 

710 else: 

711 pos = None 

712 if pos is not None: 

713 value = 0xC000 + pos 

714 s = struct.pack("!H", value) 

715 file.write(s) 

716 break 

717 else: 

718 if compress is not None and len(n) > 1: 

719 pos = file.tell() 

720 if pos <= 0x3FFF: 

721 compress[n] = pos 

722 l = len(label) 

723 file.write(struct.pack("!B", l)) 

724 if l > 0: 

725 if canonicalize: 

726 file.write(label.lower()) 

727 else: 

728 file.write(label) 

729 return None 

730 

731 def __len__(self) -> int: 

732 """The length of the name (in labels). 

733 

734 Returns an ``int``. 

735 """ 

736 

737 return len(self.labels) 

738 

739 def __getitem__(self, index): 

740 return self.labels[index] 

741 

742 def __add__(self, other): 

743 return self.concatenate(other) 

744 

745 def __sub__(self, other): 

746 return self.relativize(other) 

747 

748 def split(self, depth: int) -> Tuple["Name", "Name"]: 

749 """Split a name into a prefix and suffix names at the specified depth. 

750 

751 *depth* is an ``int`` specifying the number of labels in the suffix 

752 

753 Raises ``ValueError`` if *depth* was not >= 0 and <= the length of the 

754 name. 

755 

756 Returns the tuple ``(prefix, suffix)``. 

757 """ 

758 

759 l = len(self.labels) 

760 if depth == 0: 

761 return (self, dns.name.empty) 

762 elif depth == l: 

763 return (dns.name.empty, self) 

764 elif depth < 0 or depth > l: 

765 raise ValueError("depth must be >= 0 and <= the length of the name") 

766 return (Name(self[:-depth]), Name(self[-depth:])) 

767 

768 def concatenate(self, other: "Name") -> "Name": 

769 """Return a new name which is the concatenation of self and other. 

770 

771 Raises ``dns.name.AbsoluteConcatenation`` if the name is 

772 absolute and *other* is not the empty name. 

773 

774 Returns a ``dns.name.Name``. 

775 """ 

776 

777 if self.is_absolute() and len(other) > 0: 

778 raise AbsoluteConcatenation 

779 labels = list(self.labels) 

780 labels.extend(list(other.labels)) 

781 return Name(labels) 

782 

783 def relativize(self, origin: "Name") -> "Name": 

784 """If the name is a subdomain of *origin*, return a new name which is 

785 the name relative to origin. Otherwise return the name. 

786 

787 For example, relativizing ``www.dnspython.org.`` to origin 

788 ``dnspython.org.`` returns the name ``www``. Relativizing ``example.`` 

789 to origin ``dnspython.org.`` returns ``example.``. 

790 

791 Returns a ``dns.name.Name``. 

792 """ 

793 

794 if origin is not None and self.is_subdomain(origin): 

795 return Name(self[: -len(origin)]) 

796 else: 

797 return self 

798 

799 def derelativize(self, origin: "Name") -> "Name": 

800 """If the name is a relative name, return a new name which is the 

801 concatenation of the name and origin. Otherwise return the name. 

802 

803 For example, derelativizing ``www`` to origin ``dnspython.org.`` 

804 returns the name ``www.dnspython.org.``. Derelativizing ``example.`` 

805 to origin ``dnspython.org.`` returns ``example.``. 

806 

807 Returns a ``dns.name.Name``. 

808 """ 

809 

810 if not self.is_absolute(): 

811 return self.concatenate(origin) 

812 else: 

813 return self 

814 

815 def choose_relativity( 

816 self, origin: Optional["Name"] = None, relativize: bool = True 

817 ) -> "Name": 

818 """Return a name with the relativity desired by the caller. 

819 

820 If *origin* is ``None``, then the name is returned. 

821 Otherwise, if *relativize* is ``True`` the name is 

822 relativized, and if *relativize* is ``False`` the name is 

823 derelativized. 

824 

825 Returns a ``dns.name.Name``. 

826 """ 

827 

828 if origin: 

829 if relativize: 

830 return self.relativize(origin) 

831 else: 

832 return self.derelativize(origin) 

833 else: 

834 return self 

835 

836 def parent(self) -> "Name": 

837 """Return the parent of the name. 

838 

839 For example, the parent of ``www.dnspython.org.`` is ``dnspython.org``. 

840 

841 Raises ``dns.name.NoParent`` if the name is either the root name or the 

842 empty name, and thus has no parent. 

843 

844 Returns a ``dns.name.Name``. 

845 """ 

846 

847 if self == root or self == empty: 

848 raise NoParent 

849 return Name(self.labels[1:]) 

850 

851 def predecessor(self, origin: "Name", prefix_ok: bool = True) -> "Name": 

852 """Return the maximal predecessor of *name* in the DNSSEC ordering in the zone 

853 whose origin is *origin*, or return the longest name under *origin* if the 

854 name is origin (i.e. wrap around to the longest name, which may still be 

855 *origin* due to length considerations. 

856 

857 The relativity of the name is preserved, so if this name is relative 

858 then the method will return a relative name, and likewise if this name 

859 is absolute then the predecessor will be absolute. 

860 

861 *prefix_ok* indicates if prefixing labels is allowed, and 

862 defaults to ``True``. Normally it is good to allow this, but if computing 

863 a maximal predecessor at a zone cut point then ``False`` must be specified. 

864 """ 

865 return _handle_relativity_and_call( 

866 _absolute_predecessor, self, origin, prefix_ok 

867 ) 

868 

869 def successor(self, origin: "Name", prefix_ok: bool = True) -> "Name": 

870 """Return the minimal successor of *name* in the DNSSEC ordering in the zone 

871 whose origin is *origin*, or return *origin* if the successor cannot be 

872 computed due to name length limitations. 

873 

874 Note that *origin* is returned in the "too long" cases because wrapping 

875 around to the origin is how NSEC records express "end of the zone". 

876 

877 The relativity of the name is preserved, so if this name is relative 

878 then the method will return a relative name, and likewise if this name 

879 is absolute then the successor will be absolute. 

880 

881 *prefix_ok* indicates if prefixing a new minimal label is allowed, and 

882 defaults to ``True``. Normally it is good to allow this, but if computing 

883 a minimal successor at a zone cut point then ``False`` must be specified. 

884 """ 

885 return _handle_relativity_and_call(_absolute_successor, self, origin, prefix_ok) 

886 

887 

888#: The root name, '.' 

889root = Name([b""]) 

890 

891#: The empty name. 

892empty = Name([]) 

893 

894 

895def from_unicode( 

896 text: str, origin: Optional[Name] = root, idna_codec: Optional[IDNACodec] = None 

897) -> Name: 

898 """Convert unicode text into a Name object. 

899 

900 Labels are encoded in IDN ACE form according to rules specified by 

901 the IDNA codec. 

902 

903 *text*, a ``str``, is the text to convert into a name. 

904 

905 *origin*, a ``dns.name.Name``, specifies the origin to 

906 append to non-absolute names. The default is the root name. 

907 

908 *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA 

909 encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder 

910 is used. 

911 

912 Returns a ``dns.name.Name``. 

913 """ 

914 

915 if not isinstance(text, str): 

916 raise ValueError("input to from_unicode() must be a unicode string") 

917 if not (origin is None or isinstance(origin, Name)): 

918 raise ValueError("origin must be a Name or None") 

919 labels = [] 

920 label = "" 

921 escaping = False 

922 edigits = 0 

923 total = 0 

924 if idna_codec is None: 

925 idna_codec = IDNA_2003 

926 if text == "@": 

927 text = "" 

928 if text: 

929 if text in [".", "\u3002", "\uff0e", "\uff61"]: 

930 return Name([b""]) # no Unicode "u" on this constant! 

931 for c in text: 

932 if escaping: 

933 if edigits == 0: 

934 if c.isdigit(): 

935 total = int(c) 

936 edigits += 1 

937 else: 

938 label += c 

939 escaping = False 

940 else: 

941 if not c.isdigit(): 

942 raise BadEscape 

943 total *= 10 

944 total += int(c) 

945 edigits += 1 

946 if edigits == 3: 

947 escaping = False 

948 label += chr(total) 

949 elif c in [".", "\u3002", "\uff0e", "\uff61"]: 

950 if len(label) == 0: 

951 raise EmptyLabel 

952 labels.append(idna_codec.encode(label)) 

953 label = "" 

954 elif c == "\\": 

955 escaping = True 

956 edigits = 0 

957 total = 0 

958 else: 

959 label += c 

960 if escaping: 

961 raise BadEscape 

962 if len(label) > 0: 

963 labels.append(idna_codec.encode(label)) 

964 else: 

965 labels.append(b"") 

966 

967 if (len(labels) == 0 or labels[-1] != b"") and origin is not None: 

968 labels.extend(list(origin.labels)) 

969 return Name(labels) 

970 

971 

972def is_all_ascii(text: str) -> bool: 

973 for c in text: 

974 if ord(c) > 0x7F: 

975 return False 

976 return True 

977 

978 

979def from_text( 

980 text: Union[bytes, str], 

981 origin: Optional[Name] = root, 

982 idna_codec: Optional[IDNACodec] = None, 

983) -> Name: 

984 """Convert text into a Name object. 

985 

986 *text*, a ``bytes`` or ``str``, is the text to convert into a name. 

987 

988 *origin*, a ``dns.name.Name``, specifies the origin to 

989 append to non-absolute names. The default is the root name. 

990 

991 *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA 

992 encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder 

993 is used. 

994 

995 Returns a ``dns.name.Name``. 

996 """ 

997 

998 if isinstance(text, str): 

999 if not is_all_ascii(text): 

1000 # Some codepoint in the input text is > 127, so IDNA applies. 

1001 return from_unicode(text, origin, idna_codec) 

1002 # The input is all ASCII, so treat this like an ordinary non-IDNA 

1003 # domain name. Note that "all ASCII" is about the input text, 

1004 # not the codepoints in the domain name. E.g. if text has value 

1005 # 

1006 # r'\150\151\152\153\154\155\156\157\158\159' 

1007 # 

1008 # then it's still "all ASCII" even though the domain name has 

1009 # codepoints > 127. 

1010 text = text.encode("ascii") 

1011 if not isinstance(text, bytes): 

1012 raise ValueError("input to from_text() must be a string") 

1013 if not (origin is None or isinstance(origin, Name)): 

1014 raise ValueError("origin must be a Name or None") 

1015 labels = [] 

1016 label = b"" 

1017 escaping = False 

1018 edigits = 0 

1019 total = 0 

1020 if text == b"@": 

1021 text = b"" 

1022 if text: 

1023 if text == b".": 

1024 return Name([b""]) 

1025 for c in text: 

1026 byte_ = struct.pack("!B", c) 

1027 if escaping: 

1028 if edigits == 0: 

1029 if byte_.isdigit(): 

1030 total = int(byte_) 

1031 edigits += 1 

1032 else: 

1033 label += byte_ 

1034 escaping = False 

1035 else: 

1036 if not byte_.isdigit(): 

1037 raise BadEscape 

1038 total *= 10 

1039 total += int(byte_) 

1040 edigits += 1 

1041 if edigits == 3: 

1042 escaping = False 

1043 label += struct.pack("!B", total) 

1044 elif byte_ == b".": 

1045 if len(label) == 0: 

1046 raise EmptyLabel 

1047 labels.append(label) 

1048 label = b"" 

1049 elif byte_ == b"\\": 

1050 escaping = True 

1051 edigits = 0 

1052 total = 0 

1053 else: 

1054 label += byte_ 

1055 if escaping: 

1056 raise BadEscape 

1057 if len(label) > 0: 

1058 labels.append(label) 

1059 else: 

1060 labels.append(b"") 

1061 if (len(labels) == 0 or labels[-1] != b"") and origin is not None: 

1062 labels.extend(list(origin.labels)) 

1063 return Name(labels) 

1064 

1065 

1066# we need 'dns.wire.Parser' quoted as dns.name and dns.wire depend on each other. 

1067 

1068 

1069def from_wire_parser(parser: "dns.wire.Parser") -> Name: 

1070 """Convert possibly compressed wire format into a Name. 

1071 

1072 *parser* is a dns.wire.Parser. 

1073 

1074 Raises ``dns.name.BadPointer`` if a compression pointer did not 

1075 point backwards in the message. 

1076 

1077 Raises ``dns.name.BadLabelType`` if an invalid label type was encountered. 

1078 

1079 Returns a ``dns.name.Name`` 

1080 """ 

1081 

1082 labels = [] 

1083 biggest_pointer = parser.current 

1084 with parser.restore_furthest(): 

1085 count = parser.get_uint8() 

1086 while count != 0: 

1087 if count < 64: 

1088 labels.append(parser.get_bytes(count)) 

1089 elif count >= 192: 

1090 current = (count & 0x3F) * 256 + parser.get_uint8() 

1091 if current >= biggest_pointer: 

1092 raise BadPointer 

1093 biggest_pointer = current 

1094 parser.seek(current) 

1095 else: 

1096 raise BadLabelType 

1097 count = parser.get_uint8() 

1098 labels.append(b"") 

1099 return Name(labels) 

1100 

1101 

1102def from_wire(message: bytes, current: int) -> Tuple[Name, int]: 

1103 """Convert possibly compressed wire format into a Name. 

1104 

1105 *message* is a ``bytes`` containing an entire DNS message in DNS 

1106 wire form. 

1107 

1108 *current*, an ``int``, is the offset of the beginning of the name 

1109 from the start of the message 

1110 

1111 Raises ``dns.name.BadPointer`` if a compression pointer did not 

1112 point backwards in the message. 

1113 

1114 Raises ``dns.name.BadLabelType`` if an invalid label type was encountered. 

1115 

1116 Returns a ``(dns.name.Name, int)`` tuple consisting of the name 

1117 that was read and the number of bytes of the wire format message 

1118 which were consumed reading it. 

1119 """ 

1120 

1121 if not isinstance(message, bytes): 

1122 raise ValueError("input to from_wire() must be a byte string") 

1123 parser = dns.wire.Parser(message, current) 

1124 name = from_wire_parser(parser) 

1125 return (name, parser.current - current) 

1126 

1127 

1128# RFC 4471 Support 

1129 

1130_MINIMAL_OCTET = b"\x00" 

1131_MINIMAL_OCTET_VALUE = ord(_MINIMAL_OCTET) 

1132_SUCCESSOR_PREFIX = Name([_MINIMAL_OCTET]) 

1133_MAXIMAL_OCTET = b"\xff" 

1134_MAXIMAL_OCTET_VALUE = ord(_MAXIMAL_OCTET) 

1135_AT_SIGN_VALUE = ord("@") 

1136_LEFT_SQUARE_BRACKET_VALUE = ord("[") 

1137 

1138 

1139def _wire_length(labels): 

1140 return functools.reduce(lambda v, x: v + len(x) + 1, labels, 0) 

1141 

1142 

1143def _pad_to_max_name(name): 

1144 needed = 255 - _wire_length(name.labels) 

1145 new_labels = [] 

1146 while needed > 64: 

1147 new_labels.append(_MAXIMAL_OCTET * 63) 

1148 needed -= 64 

1149 if needed >= 2: 

1150 new_labels.append(_MAXIMAL_OCTET * (needed - 1)) 

1151 # Note we're already maximal in the needed == 1 case as while we'd like 

1152 # to add one more byte as a new label, we can't, as adding a new non-empty 

1153 # label requires at least 2 bytes. 

1154 new_labels = list(reversed(new_labels)) 

1155 new_labels.extend(name.labels) 

1156 return Name(new_labels) 

1157 

1158 

1159def _pad_to_max_label(label, suffix_labels): 

1160 length = len(label) 

1161 # We have to subtract one here to account for the length byte of label. 

1162 remaining = 255 - _wire_length(suffix_labels) - length - 1 

1163 if remaining <= 0: 

1164 # Shouldn't happen! 

1165 return label 

1166 needed = min(63 - length, remaining) 

1167 return label + _MAXIMAL_OCTET * needed 

1168 

1169 

1170def _absolute_predecessor(name: Name, origin: Name, prefix_ok: bool) -> Name: 

1171 # This is the RFC 4471 predecessor algorithm using the "absolute method" of section 

1172 # 3.1.1. 

1173 # 

1174 # Our caller must ensure that the name and origin are absolute, and that name is a 

1175 # subdomain of origin. 

1176 if name == origin: 

1177 return _pad_to_max_name(name) 

1178 least_significant_label = name[0] 

1179 if least_significant_label == _MINIMAL_OCTET: 

1180 return name.parent() 

1181 least_octet = least_significant_label[-1] 

1182 suffix_labels = name.labels[1:] 

1183 if least_octet == _MINIMAL_OCTET_VALUE: 

1184 new_labels = [least_significant_label[:-1]] 

1185 else: 

1186 octets = bytearray(least_significant_label) 

1187 octet = octets[-1] 

1188 if octet == _LEFT_SQUARE_BRACKET_VALUE: 

1189 octet = _AT_SIGN_VALUE 

1190 else: 

1191 octet -= 1 

1192 octets[-1] = octet 

1193 least_significant_label = bytes(octets) 

1194 new_labels = [_pad_to_max_label(least_significant_label, suffix_labels)] 

1195 new_labels.extend(suffix_labels) 

1196 name = Name(new_labels) 

1197 if prefix_ok: 

1198 return _pad_to_max_name(name) 

1199 else: 

1200 return name 

1201 

1202 

1203def _absolute_successor(name: Name, origin: Name, prefix_ok: bool) -> Name: 

1204 # This is the RFC 4471 successor algorithm using the "absolute method" of section 

1205 # 3.1.2. 

1206 # 

1207 # Our caller must ensure that the name and origin are absolute, and that name is a 

1208 # subdomain of origin. 

1209 if prefix_ok: 

1210 # Try prefixing \000 as new label 

1211 try: 

1212 return _SUCCESSOR_PREFIX.concatenate(name) 

1213 except NameTooLong: 

1214 pass 

1215 while name != origin: 

1216 # Try extending the least significant label. 

1217 least_significant_label = name[0] 

1218 if len(least_significant_label) < 63: 

1219 # We may be able to extend the least label with a minimal additional byte. 

1220 # This is only "may" because we could have a maximal length name even though 

1221 # the least significant label isn't maximally long. 

1222 new_labels = [least_significant_label + _MINIMAL_OCTET] 

1223 new_labels.extend(name.labels[1:]) 

1224 try: 

1225 return dns.name.Name(new_labels) 

1226 except dns.name.NameTooLong: 

1227 pass 

1228 # We can't extend the label either, so we'll try to increment the least 

1229 # signficant non-maximal byte in it. 

1230 octets = bytearray(least_significant_label) 

1231 # We do this reversed iteration with an explicit indexing variable because 

1232 # if we find something to increment, we're going to want to truncate everything 

1233 # to the right of it. 

1234 for i in range(len(octets) - 1, -1, -1): 

1235 octet = octets[i] 

1236 if octet == _MAXIMAL_OCTET_VALUE: 

1237 # We can't increment this, so keep looking. 

1238 continue 

1239 # Finally, something we can increment. We have to apply a special rule for 

1240 # incrementing "@", sending it to "[", because RFC 4034 6.1 says that when 

1241 # comparing names, uppercase letters compare as if they were their 

1242 # lower-case equivalents. If we increment "@" to "A", then it would compare 

1243 # as "a", which is after "[", "\", "]", "^", "_", and "`", so we would have 

1244 # skipped the most minimal successor, namely "[". 

1245 if octet == _AT_SIGN_VALUE: 

1246 octet = _LEFT_SQUARE_BRACKET_VALUE 

1247 else: 

1248 octet += 1 

1249 octets[i] = octet 

1250 # We can now truncate all of the maximal values we skipped (if any) 

1251 new_labels = [bytes(octets[: i + 1])] 

1252 new_labels.extend(name.labels[1:]) 

1253 # We haven't changed the length of the name, so the Name constructor will 

1254 # always work. 

1255 return Name(new_labels) 

1256 # We couldn't increment, so chop off the least significant label and try 

1257 # again. 

1258 name = name.parent() 

1259 

1260 # We couldn't increment at all, so return the origin, as wrapping around is the 

1261 # DNSSEC way. 

1262 return origin 

1263 

1264 

1265def _handle_relativity_and_call( 

1266 function: Callable[[Name, Name, bool], Name], 

1267 name: Name, 

1268 origin: Name, 

1269 prefix_ok: bool, 

1270) -> Name: 

1271 # Make "name" absolute if needed, ensure that the origin is absolute, 

1272 # call function(), and then relativize the result if needed. 

1273 if not origin.is_absolute(): 

1274 raise NeedAbsoluteNameOrOrigin 

1275 relative = not name.is_absolute() 

1276 if relative: 

1277 name = name.derelativize(origin) 

1278 elif not name.is_subdomain(origin): 

1279 raise NeedSubdomainOfOrigin 

1280 result_name = function(name, origin, prefix_ok) 

1281 if relative: 

1282 result_name = result_name.relativize(origin) 

1283 return result_name