You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
2.8 KiB

4 years ago
  1. # Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
  2. # Copyright (C) 2001-2017 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. """DNS Opcodes."""
  17. import dns.exception
  18. #: Query
  19. QUERY = 0
  20. #: Inverse Query (historical)
  21. IQUERY = 1
  22. #: Server Status (unspecified and unimplemented anywhere)
  23. STATUS = 2
  24. #: Notify
  25. NOTIFY = 4
  26. #: Dynamic Update
  27. UPDATE = 5
  28. _by_text = {
  29. 'QUERY': QUERY,
  30. 'IQUERY': IQUERY,
  31. 'STATUS': STATUS,
  32. 'NOTIFY': NOTIFY,
  33. 'UPDATE': UPDATE
  34. }
  35. # We construct the inverse mapping programmatically to ensure that we
  36. # cannot make any mistakes (e.g. omissions, cut-and-paste errors) that
  37. # would cause the mapping not to be true inverse.
  38. _by_value = {y: x for x, y in _by_text.items()}
  39. class UnknownOpcode(dns.exception.DNSException):
  40. """An DNS opcode is unknown."""
  41. def from_text(text):
  42. """Convert text into an opcode.
  43. *text*, a ``text``, the textual opcode
  44. Raises ``dns.opcode.UnknownOpcode`` if the opcode is unknown.
  45. Returns an ``int``.
  46. """
  47. if text.isdigit():
  48. value = int(text)
  49. if value >= 0 and value <= 15:
  50. return value
  51. value = _by_text.get(text.upper())
  52. if value is None:
  53. raise UnknownOpcode
  54. return value
  55. def from_flags(flags):
  56. """Extract an opcode from DNS message flags.
  57. *flags*, an ``int``, the DNS flags.
  58. Returns an ``int``.
  59. """
  60. return (flags & 0x7800) >> 11
  61. def to_flags(value):
  62. """Convert an opcode to a value suitable for ORing into DNS message
  63. flags.
  64. *value*, an ``int``, the DNS opcode value.
  65. Returns an ``int``.
  66. """
  67. return (value << 11) & 0x7800
  68. def to_text(value):
  69. """Convert an opcode to text.
  70. *value*, an ``int`` the opcode value,
  71. Raises ``dns.opcode.UnknownOpcode`` if the opcode is unknown.
  72. Returns a ``text``.
  73. """
  74. text = _by_value.get(value)
  75. if text is None:
  76. text = str(value)
  77. return text
  78. def is_update(flags):
  79. """Is the opcode in flags UPDATE?
  80. *flags*, an ``int``, the DNS message flags.
  81. Returns a ``bool``.
  82. """
  83. return from_flags(flags) == UPDATE