opcode.py 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. # Copyright (C) 2001-2007, 2009-2011 Nominum, Inc.
  2. #
  3. # Permission to use, copy, modify, and distribute this software and its
  4. # documentation for any purpose with or without fee is hereby granted,
  5. # provided that the above copyright notice and this permission notice
  6. # appear in all copies.
  7. #
  8. # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
  9. # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
  11. # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  14. # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. """DNS Opcodes."""
  16. import dns.exception
  17. QUERY = 0
  18. IQUERY = 1
  19. STATUS = 2
  20. NOTIFY = 4
  21. UPDATE = 5
  22. _by_text = {
  23. 'QUERY': QUERY,
  24. 'IQUERY': IQUERY,
  25. 'STATUS': STATUS,
  26. 'NOTIFY': NOTIFY,
  27. 'UPDATE': UPDATE
  28. }
  29. # We construct the inverse mapping programmatically to ensure that we
  30. # cannot make any mistakes (e.g. omissions, cut-and-paste errors) that
  31. # would cause the mapping not to be true inverse.
  32. _by_value = dict((y, x) for x, y in _by_text.items())
  33. class UnknownOpcode(dns.exception.DNSException):
  34. """An DNS opcode is unknown."""
  35. def from_text(text):
  36. """Convert text into an opcode.
  37. @param text: the textual opcode
  38. @type text: string
  39. @raises UnknownOpcode: the opcode is unknown
  40. @rtype: int
  41. """
  42. if text.isdigit():
  43. value = int(text)
  44. if value >= 0 and value <= 15:
  45. return value
  46. value = _by_text.get(text.upper())
  47. if value is None:
  48. raise UnknownOpcode
  49. return value
  50. def from_flags(flags):
  51. """Extract an opcode from DNS message flags.
  52. @param flags: int
  53. @rtype: int
  54. """
  55. return (flags & 0x7800) >> 11
  56. def to_flags(value):
  57. """Convert an opcode to a value suitable for ORing into DNS message
  58. flags.
  59. @rtype: int
  60. """
  61. return (value << 11) & 0x7800
  62. def to_text(value):
  63. """Convert an opcode to text.
  64. @param value: the opcdoe
  65. @type value: int
  66. @raises UnknownOpcode: the opcode is unknown
  67. @rtype: string
  68. """
  69. text = _by_value.get(value)
  70. if text is None:
  71. text = str(value)
  72. return text
  73. def is_update(flags):
  74. """True if the opcode in flags is UPDATE.
  75. @param flags: DNS flags
  76. @type flags: int
  77. @rtype: bool
  78. """
  79. return from_flags(flags) == UPDATE