message.py 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152
  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 Messages"""
  16. from __future__ import absolute_import
  17. from io import StringIO
  18. import struct
  19. import time
  20. import dns.edns
  21. import dns.exception
  22. import dns.flags
  23. import dns.name
  24. import dns.opcode
  25. import dns.entropy
  26. import dns.rcode
  27. import dns.rdata
  28. import dns.rdataclass
  29. import dns.rdatatype
  30. import dns.rrset
  31. import dns.renderer
  32. import dns.tsig
  33. import dns.wiredata
  34. from ._compat import long, xrange, string_types
  35. class ShortHeader(dns.exception.FormError):
  36. """The DNS packet passed to from_wire() is too short."""
  37. class TrailingJunk(dns.exception.FormError):
  38. """The DNS packet passed to from_wire() has extra junk at the end of it."""
  39. class UnknownHeaderField(dns.exception.DNSException):
  40. """The header field name was not recognized when converting from text
  41. into a message."""
  42. class BadEDNS(dns.exception.FormError):
  43. """OPT record occurred somewhere other than the start of
  44. the additional data section."""
  45. class BadTSIG(dns.exception.FormError):
  46. """A TSIG record occurred somewhere other than the end of
  47. the additional data section."""
  48. class UnknownTSIGKey(dns.exception.DNSException):
  49. """A TSIG with an unknown key was received."""
  50. class Message(object):
  51. """A DNS message.
  52. @ivar id: The query id; the default is a randomly chosen id.
  53. @type id: int
  54. @ivar flags: The DNS flags of the message. @see: RFC 1035 for an
  55. explanation of these flags.
  56. @type flags: int
  57. @ivar question: The question section.
  58. @type question: list of dns.rrset.RRset objects
  59. @ivar answer: The answer section.
  60. @type answer: list of dns.rrset.RRset objects
  61. @ivar authority: The authority section.
  62. @type authority: list of dns.rrset.RRset objects
  63. @ivar additional: The additional data section.
  64. @type additional: list of dns.rrset.RRset objects
  65. @ivar edns: The EDNS level to use. The default is -1, no Edns.
  66. @type edns: int
  67. @ivar ednsflags: The EDNS flags
  68. @type ednsflags: long
  69. @ivar payload: The EDNS payload size. The default is 0.
  70. @type payload: int
  71. @ivar options: The EDNS options
  72. @type options: list of dns.edns.Option objects
  73. @ivar request_payload: The associated request's EDNS payload size.
  74. @type request_payload: int
  75. @ivar keyring: The TSIG keyring to use. The default is None.
  76. @type keyring: dict
  77. @ivar keyname: The TSIG keyname to use. The default is None.
  78. @type keyname: dns.name.Name object
  79. @ivar keyalgorithm: The TSIG algorithm to use; defaults to
  80. dns.tsig.default_algorithm. Constants for TSIG algorithms are defined
  81. in dns.tsig, and the currently implemented algorithms are
  82. HMAC_MD5, HMAC_SHA1, HMAC_SHA224, HMAC_SHA256, HMAC_SHA384, and
  83. HMAC_SHA512.
  84. @type keyalgorithm: string
  85. @ivar request_mac: The TSIG MAC of the request message associated with
  86. this message; used when validating TSIG signatures. @see: RFC 2845 for
  87. more information on TSIG fields.
  88. @type request_mac: string
  89. @ivar fudge: TSIG time fudge; default is 300 seconds.
  90. @type fudge: int
  91. @ivar original_id: TSIG original id; defaults to the message's id
  92. @type original_id: int
  93. @ivar tsig_error: TSIG error code; default is 0.
  94. @type tsig_error: int
  95. @ivar other_data: TSIG other data.
  96. @type other_data: string
  97. @ivar mac: The TSIG MAC for this message.
  98. @type mac: string
  99. @ivar xfr: Is the message being used to contain the results of a DNS
  100. zone transfer? The default is False.
  101. @type xfr: bool
  102. @ivar origin: The origin of the zone in messages which are used for
  103. zone transfers or for DNS dynamic updates. The default is None.
  104. @type origin: dns.name.Name object
  105. @ivar tsig_ctx: The TSIG signature context associated with this
  106. message. The default is None.
  107. @type tsig_ctx: hmac.HMAC object
  108. @ivar had_tsig: Did the message decoded from wire format have a TSIG
  109. signature?
  110. @type had_tsig: bool
  111. @ivar multi: Is this message part of a multi-message sequence? The
  112. default is false. This variable is used when validating TSIG signatures
  113. on messages which are part of a zone transfer.
  114. @type multi: bool
  115. @ivar first: Is this message standalone, or the first of a multi
  116. message sequence? This variable is used when validating TSIG signatures
  117. on messages which are part of a zone transfer.
  118. @type first: bool
  119. @ivar index: An index of rrsets in the message. The index key is
  120. (section, name, rdclass, rdtype, covers, deleting). Indexing can be
  121. disabled by setting the index to None.
  122. @type index: dict
  123. """
  124. def __init__(self, id=None):
  125. if id is None:
  126. self.id = dns.entropy.random_16()
  127. else:
  128. self.id = id
  129. self.flags = 0
  130. self.question = []
  131. self.answer = []
  132. self.authority = []
  133. self.additional = []
  134. self.edns = -1
  135. self.ednsflags = 0
  136. self.payload = 0
  137. self.options = []
  138. self.request_payload = 0
  139. self.keyring = None
  140. self.keyname = None
  141. self.keyalgorithm = dns.tsig.default_algorithm
  142. self.request_mac = ''
  143. self.other_data = ''
  144. self.tsig_error = 0
  145. self.fudge = 300
  146. self.original_id = self.id
  147. self.mac = ''
  148. self.xfr = False
  149. self.origin = None
  150. self.tsig_ctx = None
  151. self.had_tsig = False
  152. self.multi = False
  153. self.first = True
  154. self.index = {}
  155. def __repr__(self):
  156. return '<DNS message, ID ' + repr(self.id) + '>'
  157. def __str__(self):
  158. return self.to_text()
  159. def to_text(self, origin=None, relativize=True, **kw):
  160. """Convert the message to text.
  161. The I{origin}, I{relativize}, and any other keyword
  162. arguments are passed to the rrset to_wire() method.
  163. @rtype: string
  164. """
  165. s = StringIO()
  166. s.write(u'id %d\n' % self.id)
  167. s.write(u'opcode %s\n' %
  168. dns.opcode.to_text(dns.opcode.from_flags(self.flags)))
  169. rc = dns.rcode.from_flags(self.flags, self.ednsflags)
  170. s.write(u'rcode %s\n' % dns.rcode.to_text(rc))
  171. s.write(u'flags %s\n' % dns.flags.to_text(self.flags))
  172. if self.edns >= 0:
  173. s.write(u'edns %s\n' % self.edns)
  174. if self.ednsflags != 0:
  175. s.write(u'eflags %s\n' %
  176. dns.flags.edns_to_text(self.ednsflags))
  177. s.write(u'payload %d\n' % self.payload)
  178. is_update = dns.opcode.is_update(self.flags)
  179. if is_update:
  180. s.write(u';ZONE\n')
  181. else:
  182. s.write(u';QUESTION\n')
  183. for rrset in self.question:
  184. s.write(rrset.to_text(origin, relativize, **kw))
  185. s.write(u'\n')
  186. if is_update:
  187. s.write(u';PREREQ\n')
  188. else:
  189. s.write(u';ANSWER\n')
  190. for rrset in self.answer:
  191. s.write(rrset.to_text(origin, relativize, **kw))
  192. s.write(u'\n')
  193. if is_update:
  194. s.write(u';UPDATE\n')
  195. else:
  196. s.write(u';AUTHORITY\n')
  197. for rrset in self.authority:
  198. s.write(rrset.to_text(origin, relativize, **kw))
  199. s.write(u'\n')
  200. s.write(u';ADDITIONAL\n')
  201. for rrset in self.additional:
  202. s.write(rrset.to_text(origin, relativize, **kw))
  203. s.write(u'\n')
  204. #
  205. # We strip off the final \n so the caller can print the result without
  206. # doing weird things to get around eccentricities in Python print
  207. # formatting
  208. #
  209. return s.getvalue()[:-1]
  210. def __eq__(self, other):
  211. """Two messages are equal if they have the same content in the
  212. header, question, answer, and authority sections.
  213. @rtype: bool"""
  214. if not isinstance(other, Message):
  215. return False
  216. if self.id != other.id:
  217. return False
  218. if self.flags != other.flags:
  219. return False
  220. for n in self.question:
  221. if n not in other.question:
  222. return False
  223. for n in other.question:
  224. if n not in self.question:
  225. return False
  226. for n in self.answer:
  227. if n not in other.answer:
  228. return False
  229. for n in other.answer:
  230. if n not in self.answer:
  231. return False
  232. for n in self.authority:
  233. if n not in other.authority:
  234. return False
  235. for n in other.authority:
  236. if n not in self.authority:
  237. return False
  238. return True
  239. def __ne__(self, other):
  240. """Are two messages not equal?
  241. @rtype: bool"""
  242. return not self.__eq__(other)
  243. def is_response(self, other):
  244. """Is other a response to self?
  245. @rtype: bool"""
  246. if other.flags & dns.flags.QR == 0 or \
  247. self.id != other.id or \
  248. dns.opcode.from_flags(self.flags) != \
  249. dns.opcode.from_flags(other.flags):
  250. return False
  251. if dns.rcode.from_flags(other.flags, other.ednsflags) != \
  252. dns.rcode.NOERROR:
  253. return True
  254. if dns.opcode.is_update(self.flags):
  255. return True
  256. for n in self.question:
  257. if n not in other.question:
  258. return False
  259. for n in other.question:
  260. if n not in self.question:
  261. return False
  262. return True
  263. def section_number(self, section):
  264. if section is self.question:
  265. return 0
  266. elif section is self.answer:
  267. return 1
  268. elif section is self.authority:
  269. return 2
  270. elif section is self.additional:
  271. return 3
  272. else:
  273. raise ValueError('unknown section')
  274. def find_rrset(self, section, name, rdclass, rdtype,
  275. covers=dns.rdatatype.NONE, deleting=None, create=False,
  276. force_unique=False):
  277. """Find the RRset with the given attributes in the specified section.
  278. @param section: the section of the message to look in, e.g.
  279. self.answer.
  280. @type section: list of dns.rrset.RRset objects
  281. @param name: the name of the RRset
  282. @type name: dns.name.Name object
  283. @param rdclass: the class of the RRset
  284. @type rdclass: int
  285. @param rdtype: the type of the RRset
  286. @type rdtype: int
  287. @param covers: the covers value of the RRset
  288. @type covers: int
  289. @param deleting: the deleting value of the RRset
  290. @type deleting: int
  291. @param create: If True, create the RRset if it is not found.
  292. The created RRset is appended to I{section}.
  293. @type create: bool
  294. @param force_unique: If True and create is also True, create a
  295. new RRset regardless of whether a matching RRset exists already.
  296. @type force_unique: bool
  297. @raises KeyError: the RRset was not found and create was False
  298. @rtype: dns.rrset.RRset object"""
  299. key = (self.section_number(section),
  300. name, rdclass, rdtype, covers, deleting)
  301. if not force_unique:
  302. if self.index is not None:
  303. rrset = self.index.get(key)
  304. if rrset is not None:
  305. return rrset
  306. else:
  307. for rrset in section:
  308. if rrset.match(name, rdclass, rdtype, covers, deleting):
  309. return rrset
  310. if not create:
  311. raise KeyError
  312. rrset = dns.rrset.RRset(name, rdclass, rdtype, covers, deleting)
  313. section.append(rrset)
  314. if self.index is not None:
  315. self.index[key] = rrset
  316. return rrset
  317. def get_rrset(self, section, name, rdclass, rdtype,
  318. covers=dns.rdatatype.NONE, deleting=None, create=False,
  319. force_unique=False):
  320. """Get the RRset with the given attributes in the specified section.
  321. If the RRset is not found, None is returned.
  322. @param section: the section of the message to look in, e.g.
  323. self.answer.
  324. @type section: list of dns.rrset.RRset objects
  325. @param name: the name of the RRset
  326. @type name: dns.name.Name object
  327. @param rdclass: the class of the RRset
  328. @type rdclass: int
  329. @param rdtype: the type of the RRset
  330. @type rdtype: int
  331. @param covers: the covers value of the RRset
  332. @type covers: int
  333. @param deleting: the deleting value of the RRset
  334. @type deleting: int
  335. @param create: If True, create the RRset if it is not found.
  336. The created RRset is appended to I{section}.
  337. @type create: bool
  338. @param force_unique: If True and create is also True, create a
  339. new RRset regardless of whether a matching RRset exists already.
  340. @type force_unique: bool
  341. @rtype: dns.rrset.RRset object or None"""
  342. try:
  343. rrset = self.find_rrset(section, name, rdclass, rdtype, covers,
  344. deleting, create, force_unique)
  345. except KeyError:
  346. rrset = None
  347. return rrset
  348. def to_wire(self, origin=None, max_size=0, **kw):
  349. """Return a string containing the message in DNS compressed wire
  350. format.
  351. Additional keyword arguments are passed to the rrset to_wire()
  352. method.
  353. @param origin: The origin to be appended to any relative names.
  354. @type origin: dns.name.Name object
  355. @param max_size: The maximum size of the wire format output; default
  356. is 0, which means 'the message's request payload, if nonzero, or
  357. 65536'.
  358. @type max_size: int
  359. @raises dns.exception.TooBig: max_size was exceeded
  360. @rtype: string
  361. """
  362. if max_size == 0:
  363. if self.request_payload != 0:
  364. max_size = self.request_payload
  365. else:
  366. max_size = 65535
  367. if max_size < 512:
  368. max_size = 512
  369. elif max_size > 65535:
  370. max_size = 65535
  371. r = dns.renderer.Renderer(self.id, self.flags, max_size, origin)
  372. for rrset in self.question:
  373. r.add_question(rrset.name, rrset.rdtype, rrset.rdclass)
  374. for rrset in self.answer:
  375. r.add_rrset(dns.renderer.ANSWER, rrset, **kw)
  376. for rrset in self.authority:
  377. r.add_rrset(dns.renderer.AUTHORITY, rrset, **kw)
  378. if self.edns >= 0:
  379. r.add_edns(self.edns, self.ednsflags, self.payload, self.options)
  380. for rrset in self.additional:
  381. r.add_rrset(dns.renderer.ADDITIONAL, rrset, **kw)
  382. r.write_header()
  383. if self.keyname is not None:
  384. r.add_tsig(self.keyname, self.keyring[self.keyname],
  385. self.fudge, self.original_id, self.tsig_error,
  386. self.other_data, self.request_mac,
  387. self.keyalgorithm)
  388. self.mac = r.mac
  389. return r.get_wire()
  390. def use_tsig(self, keyring, keyname=None, fudge=300,
  391. original_id=None, tsig_error=0, other_data='',
  392. algorithm=dns.tsig.default_algorithm):
  393. """When sending, a TSIG signature using the specified keyring
  394. and keyname should be added.
  395. @param keyring: The TSIG keyring to use; defaults to None.
  396. @type keyring: dict
  397. @param keyname: The name of the TSIG key to use; defaults to None.
  398. The key must be defined in the keyring. If a keyring is specified
  399. but a keyname is not, then the key used will be the first key in the
  400. keyring. Note that the order of keys in a dictionary is not defined,
  401. so applications should supply a keyname when a keyring is used, unless
  402. they know the keyring contains only one key.
  403. @type keyname: dns.name.Name or string
  404. @param fudge: TSIG time fudge; default is 300 seconds.
  405. @type fudge: int
  406. @param original_id: TSIG original id; defaults to the message's id
  407. @type original_id: int
  408. @param tsig_error: TSIG error code; default is 0.
  409. @type tsig_error: int
  410. @param other_data: TSIG other data.
  411. @type other_data: string
  412. @param algorithm: The TSIG algorithm to use; defaults to
  413. dns.tsig.default_algorithm
  414. """
  415. self.keyring = keyring
  416. if keyname is None:
  417. self.keyname = list(self.keyring.keys())[0]
  418. else:
  419. if isinstance(keyname, string_types):
  420. keyname = dns.name.from_text(keyname)
  421. self.keyname = keyname
  422. self.keyalgorithm = algorithm
  423. self.fudge = fudge
  424. if original_id is None:
  425. self.original_id = self.id
  426. else:
  427. self.original_id = original_id
  428. self.tsig_error = tsig_error
  429. self.other_data = other_data
  430. def use_edns(self, edns=0, ednsflags=0, payload=1280, request_payload=None,
  431. options=None):
  432. """Configure EDNS behavior.
  433. @param edns: The EDNS level to use. Specifying None, False, or -1
  434. means 'do not use EDNS', and in this case the other parameters are
  435. ignored. Specifying True is equivalent to specifying 0, i.e. 'use
  436. EDNS0'.
  437. @type edns: int or bool or None
  438. @param ednsflags: EDNS flag values.
  439. @type ednsflags: int
  440. @param payload: The EDNS sender's payload field, which is the maximum
  441. size of UDP datagram the sender can handle.
  442. @type payload: int
  443. @param request_payload: The EDNS payload size to use when sending
  444. this message. If not specified, defaults to the value of payload.
  445. @type request_payload: int or None
  446. @param options: The EDNS options
  447. @type options: None or list of dns.edns.Option objects
  448. @see: RFC 2671
  449. """
  450. if edns is None or edns is False:
  451. edns = -1
  452. if edns is True:
  453. edns = 0
  454. if request_payload is None:
  455. request_payload = payload
  456. if edns < 0:
  457. ednsflags = 0
  458. payload = 0
  459. request_payload = 0
  460. options = []
  461. else:
  462. # make sure the EDNS version in ednsflags agrees with edns
  463. ednsflags &= long(0xFF00FFFF)
  464. ednsflags |= (edns << 16)
  465. if options is None:
  466. options = []
  467. self.edns = edns
  468. self.ednsflags = ednsflags
  469. self.payload = payload
  470. self.options = options
  471. self.request_payload = request_payload
  472. def want_dnssec(self, wanted=True):
  473. """Enable or disable 'DNSSEC desired' flag in requests.
  474. @param wanted: Is DNSSEC desired? If True, EDNS is enabled if
  475. required, and then the DO bit is set. If False, the DO bit is
  476. cleared if EDNS is enabled.
  477. @type wanted: bool
  478. """
  479. if wanted:
  480. if self.edns < 0:
  481. self.use_edns()
  482. self.ednsflags |= dns.flags.DO
  483. elif self.edns >= 0:
  484. self.ednsflags &= ~dns.flags.DO
  485. def rcode(self):
  486. """Return the rcode.
  487. @rtype: int
  488. """
  489. return dns.rcode.from_flags(self.flags, self.ednsflags)
  490. def set_rcode(self, rcode):
  491. """Set the rcode.
  492. @param rcode: the rcode
  493. @type rcode: int
  494. """
  495. (value, evalue) = dns.rcode.to_flags(rcode)
  496. self.flags &= 0xFFF0
  497. self.flags |= value
  498. self.ednsflags &= long(0x00FFFFFF)
  499. self.ednsflags |= evalue
  500. if self.ednsflags != 0 and self.edns < 0:
  501. self.edns = 0
  502. def opcode(self):
  503. """Return the opcode.
  504. @rtype: int
  505. """
  506. return dns.opcode.from_flags(self.flags)
  507. def set_opcode(self, opcode):
  508. """Set the opcode.
  509. @param opcode: the opcode
  510. @type opcode: int
  511. """
  512. self.flags &= 0x87FF
  513. self.flags |= dns.opcode.to_flags(opcode)
  514. class _WireReader(object):
  515. """Wire format reader.
  516. @ivar wire: the wire-format message.
  517. @type wire: string
  518. @ivar message: The message object being built
  519. @type message: dns.message.Message object
  520. @ivar current: When building a message object from wire format, this
  521. variable contains the offset from the beginning of wire of the next octet
  522. to be read.
  523. @type current: int
  524. @ivar updating: Is the message a dynamic update?
  525. @type updating: bool
  526. @ivar one_rr_per_rrset: Put each RR into its own RRset?
  527. @type one_rr_per_rrset: bool
  528. @ivar ignore_trailing: Ignore trailing junk at end of request?
  529. @type ignore_trailing: bool
  530. @ivar zone_rdclass: The class of the zone in messages which are
  531. DNS dynamic updates.
  532. @type zone_rdclass: int
  533. """
  534. def __init__(self, wire, message, question_only=False,
  535. one_rr_per_rrset=False, ignore_trailing=False):
  536. self.wire = dns.wiredata.maybe_wrap(wire)
  537. self.message = message
  538. self.current = 0
  539. self.updating = False
  540. self.zone_rdclass = dns.rdataclass.IN
  541. self.question_only = question_only
  542. self.one_rr_per_rrset = one_rr_per_rrset
  543. self.ignore_trailing = ignore_trailing
  544. def _get_question(self, qcount):
  545. """Read the next I{qcount} records from the wire data and add them to
  546. the question section.
  547. @param qcount: the number of questions in the message
  548. @type qcount: int"""
  549. if self.updating and qcount > 1:
  550. raise dns.exception.FormError
  551. for i in xrange(0, qcount):
  552. (qname, used) = dns.name.from_wire(self.wire, self.current)
  553. if self.message.origin is not None:
  554. qname = qname.relativize(self.message.origin)
  555. self.current = self.current + used
  556. (rdtype, rdclass) = \
  557. struct.unpack('!HH',
  558. self.wire[self.current:self.current + 4])
  559. self.current = self.current + 4
  560. self.message.find_rrset(self.message.question, qname,
  561. rdclass, rdtype, create=True,
  562. force_unique=True)
  563. if self.updating:
  564. self.zone_rdclass = rdclass
  565. def _get_section(self, section, count):
  566. """Read the next I{count} records from the wire data and add them to
  567. the specified section.
  568. @param section: the section of the message to which to add records
  569. @type section: list of dns.rrset.RRset objects
  570. @param count: the number of records to read
  571. @type count: int"""
  572. if self.updating or self.one_rr_per_rrset:
  573. force_unique = True
  574. else:
  575. force_unique = False
  576. seen_opt = False
  577. for i in xrange(0, count):
  578. rr_start = self.current
  579. (name, used) = dns.name.from_wire(self.wire, self.current)
  580. absolute_name = name
  581. if self.message.origin is not None:
  582. name = name.relativize(self.message.origin)
  583. self.current = self.current + used
  584. (rdtype, rdclass, ttl, rdlen) = \
  585. struct.unpack('!HHIH',
  586. self.wire[self.current:self.current + 10])
  587. self.current = self.current + 10
  588. if rdtype == dns.rdatatype.OPT:
  589. if section is not self.message.additional or seen_opt:
  590. raise BadEDNS
  591. self.message.payload = rdclass
  592. self.message.ednsflags = ttl
  593. self.message.edns = (ttl & 0xff0000) >> 16
  594. self.message.options = []
  595. current = self.current
  596. optslen = rdlen
  597. while optslen > 0:
  598. (otype, olen) = \
  599. struct.unpack('!HH',
  600. self.wire[current:current + 4])
  601. current = current + 4
  602. opt = dns.edns.option_from_wire(
  603. otype, self.wire, current, olen)
  604. self.message.options.append(opt)
  605. current = current + olen
  606. optslen = optslen - 4 - olen
  607. seen_opt = True
  608. elif rdtype == dns.rdatatype.TSIG:
  609. if not (section is self.message.additional and
  610. i == (count - 1)):
  611. raise BadTSIG
  612. if self.message.keyring is None:
  613. raise UnknownTSIGKey('got signed message without keyring')
  614. secret = self.message.keyring.get(absolute_name)
  615. if secret is None:
  616. raise UnknownTSIGKey("key '%s' unknown" % name)
  617. self.message.keyname = absolute_name
  618. (self.message.keyalgorithm, self.message.mac) = \
  619. dns.tsig.get_algorithm_and_mac(self.wire, self.current,
  620. rdlen)
  621. self.message.tsig_ctx = \
  622. dns.tsig.validate(self.wire,
  623. absolute_name,
  624. secret,
  625. int(time.time()),
  626. self.message.request_mac,
  627. rr_start,
  628. self.current,
  629. rdlen,
  630. self.message.tsig_ctx,
  631. self.message.multi,
  632. self.message.first)
  633. self.message.had_tsig = True
  634. else:
  635. if ttl < 0:
  636. ttl = 0
  637. if self.updating and \
  638. (rdclass == dns.rdataclass.ANY or
  639. rdclass == dns.rdataclass.NONE):
  640. deleting = rdclass
  641. rdclass = self.zone_rdclass
  642. else:
  643. deleting = None
  644. if deleting == dns.rdataclass.ANY or \
  645. (deleting == dns.rdataclass.NONE and
  646. section is self.message.answer):
  647. covers = dns.rdatatype.NONE
  648. rd = None
  649. else:
  650. rd = dns.rdata.from_wire(rdclass, rdtype, self.wire,
  651. self.current, rdlen,
  652. self.message.origin)
  653. covers = rd.covers()
  654. if self.message.xfr and rdtype == dns.rdatatype.SOA:
  655. force_unique = True
  656. rrset = self.message.find_rrset(section, name,
  657. rdclass, rdtype, covers,
  658. deleting, True, force_unique)
  659. if rd is not None:
  660. rrset.add(rd, ttl)
  661. self.current = self.current + rdlen
  662. def read(self):
  663. """Read a wire format DNS message and build a dns.message.Message
  664. object."""
  665. l = len(self.wire)
  666. if l < 12:
  667. raise ShortHeader
  668. (self.message.id, self.message.flags, qcount, ancount,
  669. aucount, adcount) = struct.unpack('!HHHHHH', self.wire[:12])
  670. self.current = 12
  671. if dns.opcode.is_update(self.message.flags):
  672. self.updating = True
  673. self._get_question(qcount)
  674. if self.question_only:
  675. return
  676. self._get_section(self.message.answer, ancount)
  677. self._get_section(self.message.authority, aucount)
  678. self._get_section(self.message.additional, adcount)
  679. if not self.ignore_trailing and self.current != l:
  680. raise TrailingJunk
  681. if self.message.multi and self.message.tsig_ctx and \
  682. not self.message.had_tsig:
  683. self.message.tsig_ctx.update(self.wire)
  684. def from_wire(wire, keyring=None, request_mac='', xfr=False, origin=None,
  685. tsig_ctx=None, multi=False, first=True,
  686. question_only=False, one_rr_per_rrset=False,
  687. ignore_trailing=False):
  688. """Convert a DNS wire format message into a message
  689. object.
  690. @param keyring: The keyring to use if the message is signed.
  691. @type keyring: dict
  692. @param request_mac: If the message is a response to a TSIG-signed request,
  693. I{request_mac} should be set to the MAC of that request.
  694. @type request_mac: string
  695. @param xfr: Is this message part of a zone transfer?
  696. @type xfr: bool
  697. @param origin: If the message is part of a zone transfer, I{origin}
  698. should be the origin name of the zone.
  699. @type origin: dns.name.Name object
  700. @param tsig_ctx: The ongoing TSIG context, used when validating zone
  701. transfers.
  702. @type tsig_ctx: hmac.HMAC object
  703. @param multi: Is this message part of a multiple message sequence?
  704. @type multi: bool
  705. @param first: Is this message standalone, or the first of a multi
  706. message sequence?
  707. @type first: bool
  708. @param question_only: Read only up to the end of the question section?
  709. @type question_only: bool
  710. @param one_rr_per_rrset: Put each RR into its own RRset
  711. @type one_rr_per_rrset: bool
  712. @param ignore_trailing: Ignore trailing junk at end of request?
  713. @type ignore_trailing: bool
  714. @raises ShortHeader: The message is less than 12 octets long.
  715. @raises TrailingJunk: There were octets in the message past the end
  716. of the proper DNS message.
  717. @raises BadEDNS: An OPT record was in the wrong section, or occurred more
  718. than once.
  719. @raises BadTSIG: A TSIG record was not the last record of the additional
  720. data section.
  721. @rtype: dns.message.Message object"""
  722. m = Message(id=0)
  723. m.keyring = keyring
  724. m.request_mac = request_mac
  725. m.xfr = xfr
  726. m.origin = origin
  727. m.tsig_ctx = tsig_ctx
  728. m.multi = multi
  729. m.first = first
  730. reader = _WireReader(wire, m, question_only, one_rr_per_rrset,
  731. ignore_trailing)
  732. reader.read()
  733. return m
  734. class _TextReader(object):
  735. """Text format reader.
  736. @ivar tok: the tokenizer
  737. @type tok: dns.tokenizer.Tokenizer object
  738. @ivar message: The message object being built
  739. @type message: dns.message.Message object
  740. @ivar updating: Is the message a dynamic update?
  741. @type updating: bool
  742. @ivar zone_rdclass: The class of the zone in messages which are
  743. DNS dynamic updates.
  744. @type zone_rdclass: int
  745. @ivar last_name: The most recently read name when building a message object
  746. from text format.
  747. @type last_name: dns.name.Name object
  748. """
  749. def __init__(self, text, message):
  750. self.message = message
  751. self.tok = dns.tokenizer.Tokenizer(text)
  752. self.last_name = None
  753. self.zone_rdclass = dns.rdataclass.IN
  754. self.updating = False
  755. def _header_line(self, section):
  756. """Process one line from the text format header section."""
  757. token = self.tok.get()
  758. what = token.value
  759. if what == 'id':
  760. self.message.id = self.tok.get_int()
  761. elif what == 'flags':
  762. while True:
  763. token = self.tok.get()
  764. if not token.is_identifier():
  765. self.tok.unget(token)
  766. break
  767. self.message.flags = self.message.flags | \
  768. dns.flags.from_text(token.value)
  769. if dns.opcode.is_update(self.message.flags):
  770. self.updating = True
  771. elif what == 'edns':
  772. self.message.edns = self.tok.get_int()
  773. self.message.ednsflags = self.message.ednsflags | \
  774. (self.message.edns << 16)
  775. elif what == 'eflags':
  776. if self.message.edns < 0:
  777. self.message.edns = 0
  778. while True:
  779. token = self.tok.get()
  780. if not token.is_identifier():
  781. self.tok.unget(token)
  782. break
  783. self.message.ednsflags = self.message.ednsflags | \
  784. dns.flags.edns_from_text(token.value)
  785. elif what == 'payload':
  786. self.message.payload = self.tok.get_int()
  787. if self.message.edns < 0:
  788. self.message.edns = 0
  789. elif what == 'opcode':
  790. text = self.tok.get_string()
  791. self.message.flags = self.message.flags | \
  792. dns.opcode.to_flags(dns.opcode.from_text(text))
  793. elif what == 'rcode':
  794. text = self.tok.get_string()
  795. self.message.set_rcode(dns.rcode.from_text(text))
  796. else:
  797. raise UnknownHeaderField
  798. self.tok.get_eol()
  799. def _question_line(self, section):
  800. """Process one line from the text format question section."""
  801. token = self.tok.get(want_leading=True)
  802. if not token.is_whitespace():
  803. self.last_name = dns.name.from_text(token.value, None)
  804. name = self.last_name
  805. token = self.tok.get()
  806. if not token.is_identifier():
  807. raise dns.exception.SyntaxError
  808. # Class
  809. try:
  810. rdclass = dns.rdataclass.from_text(token.value)
  811. token = self.tok.get()
  812. if not token.is_identifier():
  813. raise dns.exception.SyntaxError
  814. except dns.exception.SyntaxError:
  815. raise dns.exception.SyntaxError
  816. except Exception:
  817. rdclass = dns.rdataclass.IN
  818. # Type
  819. rdtype = dns.rdatatype.from_text(token.value)
  820. self.message.find_rrset(self.message.question, name,
  821. rdclass, rdtype, create=True,
  822. force_unique=True)
  823. if self.updating:
  824. self.zone_rdclass = rdclass
  825. self.tok.get_eol()
  826. def _rr_line(self, section):
  827. """Process one line from the text format answer, authority, or
  828. additional data sections.
  829. """
  830. deleting = None
  831. # Name
  832. token = self.tok.get(want_leading=True)
  833. if not token.is_whitespace():
  834. self.last_name = dns.name.from_text(token.value, None)
  835. name = self.last_name
  836. token = self.tok.get()
  837. if not token.is_identifier():
  838. raise dns.exception.SyntaxError
  839. # TTL
  840. try:
  841. ttl = int(token.value, 0)
  842. token = self.tok.get()
  843. if not token.is_identifier():
  844. raise dns.exception.SyntaxError
  845. except dns.exception.SyntaxError:
  846. raise dns.exception.SyntaxError
  847. except Exception:
  848. ttl = 0
  849. # Class
  850. try:
  851. rdclass = dns.rdataclass.from_text(token.value)
  852. token = self.tok.get()
  853. if not token.is_identifier():
  854. raise dns.exception.SyntaxError
  855. if rdclass == dns.rdataclass.ANY or rdclass == dns.rdataclass.NONE:
  856. deleting = rdclass
  857. rdclass = self.zone_rdclass
  858. except dns.exception.SyntaxError:
  859. raise dns.exception.SyntaxError
  860. except Exception:
  861. rdclass = dns.rdataclass.IN
  862. # Type
  863. rdtype = dns.rdatatype.from_text(token.value)
  864. token = self.tok.get()
  865. if not token.is_eol_or_eof():
  866. self.tok.unget(token)
  867. rd = dns.rdata.from_text(rdclass, rdtype, self.tok, None)
  868. covers = rd.covers()
  869. else:
  870. rd = None
  871. covers = dns.rdatatype.NONE
  872. rrset = self.message.find_rrset(section, name,
  873. rdclass, rdtype, covers,
  874. deleting, True, self.updating)
  875. if rd is not None:
  876. rrset.add(rd, ttl)
  877. def read(self):
  878. """Read a text format DNS message and build a dns.message.Message
  879. object."""
  880. line_method = self._header_line
  881. section = None
  882. while 1:
  883. token = self.tok.get(True, True)
  884. if token.is_eol_or_eof():
  885. break
  886. if token.is_comment():
  887. u = token.value.upper()
  888. if u == 'HEADER':
  889. line_method = self._header_line
  890. elif u == 'QUESTION' or u == 'ZONE':
  891. line_method = self._question_line
  892. section = self.message.question
  893. elif u == 'ANSWER' or u == 'PREREQ':
  894. line_method = self._rr_line
  895. section = self.message.answer
  896. elif u == 'AUTHORITY' or u == 'UPDATE':
  897. line_method = self._rr_line
  898. section = self.message.authority
  899. elif u == 'ADDITIONAL':
  900. line_method = self._rr_line
  901. section = self.message.additional
  902. self.tok.get_eol()
  903. continue
  904. self.tok.unget(token)
  905. line_method(section)
  906. def from_text(text):
  907. """Convert the text format message into a message object.
  908. @param text: The text format message.
  909. @type text: string
  910. @raises UnknownHeaderField:
  911. @raises dns.exception.SyntaxError:
  912. @rtype: dns.message.Message object"""
  913. # 'text' can also be a file, but we don't publish that fact
  914. # since it's an implementation detail. The official file
  915. # interface is from_file().
  916. m = Message()
  917. reader = _TextReader(text, m)
  918. reader.read()
  919. return m
  920. def from_file(f):
  921. """Read the next text format message from the specified file.
  922. @param f: file or string. If I{f} is a string, it is treated
  923. as the name of a file to open.
  924. @raises UnknownHeaderField:
  925. @raises dns.exception.SyntaxError:
  926. @rtype: dns.message.Message object"""
  927. str_type = string_types
  928. opts = 'rU'
  929. if isinstance(f, str_type):
  930. f = open(f, opts)
  931. want_close = True
  932. else:
  933. want_close = False
  934. try:
  935. m = from_text(f)
  936. finally:
  937. if want_close:
  938. f.close()
  939. return m
  940. def make_query(qname, rdtype, rdclass=dns.rdataclass.IN, use_edns=None,
  941. want_dnssec=False, ednsflags=None, payload=None,
  942. request_payload=None, options=None):
  943. """Make a query message.
  944. The query name, type, and class may all be specified either
  945. as objects of the appropriate type, or as strings.
  946. The query will have a randomly chosen query id, and its DNS flags
  947. will be set to dns.flags.RD.
  948. @param qname: The query name.
  949. @type qname: dns.name.Name object or string
  950. @param rdtype: The desired rdata type.
  951. @type rdtype: int
  952. @param rdclass: The desired rdata class; the default is class IN.
  953. @type rdclass: int
  954. @param use_edns: The EDNS level to use; the default is None (no EDNS).
  955. See the description of dns.message.Message.use_edns() for the possible
  956. values for use_edns and their meanings.
  957. @type use_edns: int or bool or None
  958. @param want_dnssec: Should the query indicate that DNSSEC is desired?
  959. @type want_dnssec: bool
  960. @param ednsflags: EDNS flag values.
  961. @type ednsflags: int
  962. @param payload: The EDNS sender's payload field, which is the maximum
  963. size of UDP datagram the sender can handle.
  964. @type payload: int
  965. @param request_payload: The EDNS payload size to use when sending
  966. this message. If not specified, defaults to the value of payload.
  967. @type request_payload: int or None
  968. @param options: The EDNS options
  969. @type options: None or list of dns.edns.Option objects
  970. @see: RFC 2671
  971. @rtype: dns.message.Message object"""
  972. if isinstance(qname, string_types):
  973. qname = dns.name.from_text(qname)
  974. if isinstance(rdtype, string_types):
  975. rdtype = dns.rdatatype.from_text(rdtype)
  976. if isinstance(rdclass, string_types):
  977. rdclass = dns.rdataclass.from_text(rdclass)
  978. m = Message()
  979. m.flags |= dns.flags.RD
  980. m.find_rrset(m.question, qname, rdclass, rdtype, create=True,
  981. force_unique=True)
  982. # only pass keywords on to use_edns if they have been set to a
  983. # non-None value. Setting a field will turn EDNS on if it hasn't
  984. # been configured.
  985. kwargs = {}
  986. if ednsflags is not None:
  987. kwargs['ednsflags'] = ednsflags
  988. if use_edns is None:
  989. use_edns = 0
  990. if payload is not None:
  991. kwargs['payload'] = payload
  992. if use_edns is None:
  993. use_edns = 0
  994. if request_payload is not None:
  995. kwargs['request_payload'] = request_payload
  996. if use_edns is None:
  997. use_edns = 0
  998. if options is not None:
  999. kwargs['options'] = options
  1000. if use_edns is None:
  1001. use_edns = 0
  1002. kwargs['edns'] = use_edns
  1003. m.use_edns(**kwargs)
  1004. m.want_dnssec(want_dnssec)
  1005. return m
  1006. def make_response(query, recursion_available=False, our_payload=8192,
  1007. fudge=300):
  1008. """Make a message which is a response for the specified query.
  1009. The message returned is really a response skeleton; it has all
  1010. of the infrastructure required of a response, but none of the
  1011. content.
  1012. The response's question section is a shallow copy of the query's
  1013. question section, so the query's question RRsets should not be
  1014. changed.
  1015. @param query: the query to respond to
  1016. @type query: dns.message.Message object
  1017. @param recursion_available: should RA be set in the response?
  1018. @type recursion_available: bool
  1019. @param our_payload: payload size to advertise in EDNS responses; default
  1020. is 8192.
  1021. @type our_payload: int
  1022. @param fudge: TSIG time fudge; default is 300 seconds.
  1023. @type fudge: int
  1024. @rtype: dns.message.Message object"""
  1025. if query.flags & dns.flags.QR:
  1026. raise dns.exception.FormError('specified query message is not a query')
  1027. response = dns.message.Message(query.id)
  1028. response.flags = dns.flags.QR | (query.flags & dns.flags.RD)
  1029. if recursion_available:
  1030. response.flags |= dns.flags.RA
  1031. response.set_opcode(query.opcode())
  1032. response.question = list(query.question)
  1033. if query.edns >= 0:
  1034. response.use_edns(0, 0, our_payload, query.payload)
  1035. if query.had_tsig:
  1036. response.use_tsig(query.keyring, query.keyname, fudge, None, 0, '',
  1037. query.keyalgorithm)
  1038. response.request_mac = query.mac
  1039. return response