Message.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. <?php
  2. namespace React\Dns\Model;
  3. use React\Dns\Query\Query;
  4. /**
  5. * This class represents an outgoing query message or an incoming response message
  6. *
  7. * @link https://tools.ietf.org/html/rfc1035#section-4.1.1
  8. */
  9. final class Message
  10. {
  11. const TYPE_A = 1;
  12. const TYPE_NS = 2;
  13. const TYPE_CNAME = 5;
  14. const TYPE_SOA = 6;
  15. const TYPE_PTR = 12;
  16. const TYPE_MX = 15;
  17. const TYPE_TXT = 16;
  18. const TYPE_AAAA = 28;
  19. const TYPE_SRV = 33;
  20. const TYPE_SSHFP = 44;
  21. /**
  22. * pseudo-type for EDNS0
  23. *
  24. * These are included in the additional section and usually not in answer section.
  25. * Defined in [RFC 6891](https://tools.ietf.org/html/rfc6891) (or older
  26. * [RFC 2671](https://tools.ietf.org/html/rfc2671)).
  27. *
  28. * The OPT record uses the "class" field to store the maximum size.
  29. *
  30. * The OPT record uses the "ttl" field to store additional flags.
  31. */
  32. const TYPE_OPT = 41;
  33. /**
  34. * Sender Policy Framework (SPF) had a dedicated SPF type which has been
  35. * deprecated in favor of reusing the existing TXT type.
  36. *
  37. * @deprecated https://datatracker.ietf.org/doc/html/rfc7208#section-3.1
  38. * @see self::TYPE_TXT
  39. */
  40. const TYPE_SPF = 99;
  41. const TYPE_ANY = 255;
  42. const TYPE_CAA = 257;
  43. const CLASS_IN = 1;
  44. const OPCODE_QUERY = 0;
  45. const OPCODE_IQUERY = 1; // inverse query
  46. const OPCODE_STATUS = 2;
  47. const RCODE_OK = 0;
  48. const RCODE_FORMAT_ERROR = 1;
  49. const RCODE_SERVER_FAILURE = 2;
  50. const RCODE_NAME_ERROR = 3;
  51. const RCODE_NOT_IMPLEMENTED = 4;
  52. const RCODE_REFUSED = 5;
  53. /**
  54. * The edns-tcp-keepalive EDNS0 Option
  55. *
  56. * Option value contains a `?float` with timeout in seconds (in 0.1s steps)
  57. * for DNS response or `null` for DNS query.
  58. *
  59. * @link https://tools.ietf.org/html/rfc7828
  60. */
  61. const OPT_TCP_KEEPALIVE = 11;
  62. /**
  63. * The EDNS(0) Padding Option
  64. *
  65. * Option value contains a `string` with binary data (usually variable
  66. * number of null bytes)
  67. *
  68. * @link https://tools.ietf.org/html/rfc7830
  69. */
  70. const OPT_PADDING = 12;
  71. /**
  72. * Creates a new request message for the given query
  73. *
  74. * @param Query $query
  75. * @return self
  76. */
  77. public static function createRequestForQuery(Query $query)
  78. {
  79. $request = new Message();
  80. $request->id = self::generateId();
  81. $request->rd = true;
  82. $request->questions[] = $query;
  83. return $request;
  84. }
  85. /**
  86. * Creates a new response message for the given query with the given answer records
  87. *
  88. * @param Query $query
  89. * @param Record[] $answers
  90. * @return self
  91. */
  92. public static function createResponseWithAnswersForQuery(Query $query, array $answers)
  93. {
  94. $response = new Message();
  95. $response->id = self::generateId();
  96. $response->qr = true;
  97. $response->rd = true;
  98. $response->questions[] = $query;
  99. foreach ($answers as $record) {
  100. $response->answers[] = $record;
  101. }
  102. return $response;
  103. }
  104. /**
  105. * generates a random 16 bit message ID
  106. *
  107. * This uses a CSPRNG so that an outside attacker that is sending spoofed
  108. * DNS response messages can not guess the message ID to avoid possible
  109. * cache poisoning attacks.
  110. *
  111. * The `random_int()` function is only available on PHP 7+ or when
  112. * https://github.com/paragonie/random_compat is installed. As such, using
  113. * the latest supported PHP version is highly recommended. This currently
  114. * falls back to a less secure random number generator on older PHP versions
  115. * in the hope that this system is properly protected against outside
  116. * attackers, for example by using one of the common local DNS proxy stubs.
  117. *
  118. * @return int
  119. * @see self::getId()
  120. * @codeCoverageIgnore
  121. */
  122. private static function generateId()
  123. {
  124. if (function_exists('random_int')) {
  125. return random_int(0, 0xffff);
  126. }
  127. return mt_rand(0, 0xffff);
  128. }
  129. /**
  130. * The 16 bit message ID
  131. *
  132. * The response message ID has to match the request message ID. This allows
  133. * the receiver to verify this is the correct response message. An outside
  134. * attacker may try to inject fake responses by "guessing" the message ID,
  135. * so this should use a proper CSPRNG to avoid possible cache poisoning.
  136. *
  137. * @var int 16 bit message ID
  138. * @see self::generateId()
  139. */
  140. public $id = 0;
  141. /**
  142. * @var bool Query/Response flag, query=false or response=true
  143. */
  144. public $qr = false;
  145. /**
  146. * @var int specifies the kind of query (4 bit), see self::OPCODE_* constants
  147. * @see self::OPCODE_QUERY
  148. */
  149. public $opcode = self::OPCODE_QUERY;
  150. /**
  151. *
  152. * @var bool Authoritative Answer
  153. */
  154. public $aa = false;
  155. /**
  156. * @var bool TrunCation
  157. */
  158. public $tc = false;
  159. /**
  160. * @var bool Recursion Desired
  161. */
  162. public $rd = false;
  163. /**
  164. * @var bool Recursion Available
  165. */
  166. public $ra = false;
  167. /**
  168. * @var int response code (4 bit), see self::RCODE_* constants
  169. * @see self::RCODE_OK
  170. */
  171. public $rcode = Message::RCODE_OK;
  172. /**
  173. * An array of Query objects
  174. *
  175. * ```php
  176. * $questions = array(
  177. * new Query(
  178. * 'reactphp.org',
  179. * Message::TYPE_A,
  180. * Message::CLASS_IN
  181. * )
  182. * );
  183. * ```
  184. *
  185. * @var Query[]
  186. */
  187. public $questions = array();
  188. /**
  189. * @var Record[]
  190. */
  191. public $answers = array();
  192. /**
  193. * @var Record[]
  194. */
  195. public $authority = array();
  196. /**
  197. * @var Record[]
  198. */
  199. public $additional = array();
  200. }