statistics.cc.pre 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <auth/statistics.h>
  15. #include <auth/statistics_items.h>
  16. #include <auth/auth_log.h>
  17. #include <cc/data.h>
  18. #include <dns/message.h>
  19. #include <dns/opcode.h>
  20. #include <dns/rcode.h>
  21. #include <statistics/counter.h>
  22. #include <boost/optional.hpp>
  23. using namespace isc::dns;
  24. using namespace isc::auth;
  25. using namespace isc::statistics;
  26. using namespace isc::auth::statistics;
  27. namespace {
  28. /// \brief Fill isc::data::ElementPtr with given counter.
  29. /// \param counter Counter which stores values to fill
  30. /// \param type_tree CounterSpec corresponding to counter for building item
  31. /// name
  32. /// \param trees isc::data::ElementPtr to be filled in; caller has ownership of
  33. /// isc::data::ElementPtr
  34. void
  35. fillNodes(const Counter& counter,
  36. const struct isc::auth::statistics::CounterSpec type_tree[],
  37. isc::data::ElementPtr& trees)
  38. {
  39. using namespace isc::data;
  40. for (int i = 0; type_tree[i].name != NULL; ++i) {
  41. if (type_tree[i].sub_counters != NULL) {
  42. isc::data::ElementPtr sub_counters = Element::createMap();
  43. trees->set(type_tree[i].name, sub_counters);
  44. fillNodes(counter, type_tree[i].sub_counters, sub_counters);
  45. } else {
  46. trees->set(type_tree[i].name,
  47. Element::create(static_cast<long int>(
  48. counter.get(type_tree[i].counter_id)))
  49. );
  50. }
  51. }
  52. }
  53. // ### STATISTICS ITEMS DEFINITION ###
  54. } // anonymous namespace
  55. namespace isc {
  56. namespace auth {
  57. namespace statistics {
  58. // Note: opcode in this array must be start with 0 and be sequential
  59. const int opcode_to_msgcounter[] = {
  60. MSG_OPCODE_QUERY, // Opcode = 0: Query
  61. MSG_OPCODE_IQUERY, // Opcode = 1: IQuery
  62. MSG_OPCODE_STATUS, // Opcode = 2: Status
  63. MSG_OPCODE_OTHER, // Opcode = 3: (Unassigned)
  64. MSG_OPCODE_NOTIFY, // Opcode = 4: Notify
  65. MSG_OPCODE_UPDATE, // Opcode = 5: Update
  66. MSG_OPCODE_OTHER, // Opcode = 6: (Unassigned)
  67. MSG_OPCODE_OTHER, // Opcode = 7: (Unassigned)
  68. MSG_OPCODE_OTHER, // Opcode = 8: (Unassigned)
  69. MSG_OPCODE_OTHER, // Opcode = 9: (Unassigned)
  70. MSG_OPCODE_OTHER, // Opcode = 10: (Unassigned)
  71. MSG_OPCODE_OTHER, // Opcode = 11: (Unassigned)
  72. MSG_OPCODE_OTHER, // Opcode = 12: (Unassigned)
  73. MSG_OPCODE_OTHER, // Opcode = 13: (Unassigned)
  74. MSG_OPCODE_OTHER, // Opcode = 14: (Unassigned)
  75. MSG_OPCODE_OTHER // Opcode = 15: (Unassigned)
  76. };
  77. const size_t num_opcode_to_msgcounter =
  78. sizeof(opcode_to_msgcounter) / sizeof(opcode_to_msgcounter[0]);
  79. // Note: rcode in this array must be start with 0 and be sequential
  80. const int rcode_to_msgcounter[] = {
  81. MSG_RCODE_NOERROR, // Rcode = 0: NoError
  82. MSG_RCODE_FORMERR, // Rcode = 1: FormErr
  83. MSG_RCODE_SERVFAIL, // Rcode = 2: ServFail
  84. MSG_RCODE_NXDOMAIN, // Rcode = 3: NXDomain
  85. MSG_RCODE_NOTIMP, // Rcode = 4: NotImp
  86. MSG_RCODE_REFUSED, // Rcode = 5: Refused
  87. MSG_RCODE_YXDOMAIN, // Rcode = 6: YXDomain
  88. MSG_RCODE_YXRRSET, // Rcode = 7: YXRRSet
  89. MSG_RCODE_NXRRSET, // Rcode = 8: NXRRSet
  90. MSG_RCODE_NOTAUTH, // Rcode = 9: NotAuth
  91. MSG_RCODE_NOTZONE, // Rcode = 10: NotZone
  92. MSG_RCODE_OTHER, // Rcode = 11: (Unassigned)
  93. MSG_RCODE_OTHER, // Rcode = 12: (Unassigned)
  94. MSG_RCODE_OTHER, // Rcode = 13: (Unassigned)
  95. MSG_RCODE_OTHER, // Rcode = 14: (Unassigned)
  96. MSG_RCODE_OTHER, // Rcode = 15: (Unassigned)
  97. MSG_RCODE_BADVERS // Rcode = 16: BADVERS
  98. };
  99. const size_t num_rcode_to_msgcounter =
  100. sizeof(rcode_to_msgcounter) / sizeof(rcode_to_msgcounter[0]);
  101. Counters::Counters() :
  102. server_msg_counter_(MSG_COUNTER_TYPES)
  103. {}
  104. void
  105. Counters::incRequest(const MessageAttributes& msgattrs) {
  106. // protocols carrying request
  107. if (msgattrs.getRequestIPVersion() == AF_INET) {
  108. server_msg_counter_.inc(MSG_REQUEST_IPV4);
  109. } else if (msgattrs.getRequestIPVersion() == AF_INET6) {
  110. server_msg_counter_.inc(MSG_REQUEST_IPV6);
  111. }
  112. if (msgattrs.getRequestTransportProtocol() == IPPROTO_UDP) {
  113. server_msg_counter_.inc(MSG_REQUEST_UDP);
  114. } else if (msgattrs.getRequestTransportProtocol() == IPPROTO_TCP) {
  115. server_msg_counter_.inc(MSG_REQUEST_TCP);
  116. }
  117. // Opcode
  118. const boost::optional<isc::dns::Opcode>& opcode =
  119. msgattrs.getRequestOpCode();
  120. // Increment opcode counter only if the opcode exists; opcode can be empty
  121. // if a short message which does not contain DNS header is received, or
  122. // a response message (i.e. QR bit is set) is received.
  123. if (opcode) {
  124. server_msg_counter_.inc(opcode_to_msgcounter[opcode->getCode()]);
  125. if (opcode.get() == Opcode::QUERY()) {
  126. // Recursion Desired bit
  127. if (msgattrs.requestHasRD()) {
  128. server_msg_counter_.inc(MSG_QRYRECURSION);
  129. }
  130. }
  131. }
  132. // TSIG
  133. if (msgattrs.requestHasTSIG()) {
  134. server_msg_counter_.inc(MSG_REQUEST_TSIG);
  135. }
  136. if (msgattrs.requestHasBadSig()) {
  137. server_msg_counter_.inc(MSG_REQUEST_BADSIG);
  138. // If signature validation failed, no other request attributes (except
  139. // for opcode) are reliable. Skip processing of the rest of request
  140. // counters.
  141. return;
  142. }
  143. // EDNS0
  144. if (msgattrs.requestHasEDNS0()) {
  145. server_msg_counter_.inc(MSG_REQUEST_EDNS0);
  146. }
  147. // DNSSEC OK bit
  148. if (msgattrs.requestHasDO()) {
  149. server_msg_counter_.inc(MSG_REQUEST_DNSSEC_OK);
  150. }
  151. }
  152. void
  153. Counters::incResponse(const MessageAttributes& msgattrs,
  154. const Message& response)
  155. {
  156. // responded
  157. server_msg_counter_.inc(MSG_RESPONSE);
  158. // response truncated
  159. if (msgattrs.responseIsTruncated()) {
  160. server_msg_counter_.inc(MSG_RESPONSE_TRUNCATED);
  161. }
  162. // response EDNS
  163. ConstEDNSPtr response_edns = response.getEDNS();
  164. if (response_edns && response_edns->getVersion() == 0) {
  165. server_msg_counter_.inc(MSG_RESPONSE_EDNS0);
  166. }
  167. // response TSIG
  168. if (msgattrs.responseHasTSIG()) {
  169. server_msg_counter_.inc(MSG_RESPONSE_TSIG);
  170. }
  171. // response SIG(0) is currently not implemented
  172. // RCODE
  173. const unsigned int rcode = response.getRcode().getCode();
  174. const unsigned int rcode_type =
  175. rcode < num_rcode_to_msgcounter ?
  176. rcode_to_msgcounter[rcode] : MSG_RCODE_OTHER;
  177. server_msg_counter_.inc(rcode_type);
  178. // Unsupported EDNS version
  179. if (rcode == Rcode::BADVERS().getCode()) {
  180. server_msg_counter_.inc(MSG_REQUEST_BADEDNSVER);
  181. }
  182. const boost::optional<isc::dns::Opcode>& opcode =
  183. msgattrs.getRequestOpCode();
  184. if (!opcode) {
  185. isc_throw(isc::Unexpected, "Opcode of the request is empty while it is"
  186. " responded");
  187. }
  188. if (!msgattrs.requestHasBadSig() && opcode.get() == Opcode::QUERY()) {
  189. // compound attributes
  190. const unsigned int answer_rrs =
  191. response.getRRCount(Message::SECTION_ANSWER);
  192. const bool is_aa_set =
  193. response.getHeaderFlag(Message::HEADERFLAG_AA);
  194. if (is_aa_set) {
  195. // QryAuthAns
  196. server_msg_counter_.inc(MSG_QRYAUTHANS);
  197. } else {
  198. // QryNoAuthAns
  199. server_msg_counter_.inc(MSG_QRYNOAUTHANS);
  200. }
  201. if (rcode == Rcode::NOERROR_CODE) {
  202. if (answer_rrs > 0) {
  203. // QrySuccess
  204. server_msg_counter_.inc(MSG_QRYSUCCESS);
  205. } else {
  206. if (is_aa_set) {
  207. // QryNxrrset
  208. server_msg_counter_.inc(MSG_QRYNXRRSET);
  209. } else {
  210. // QryReferral
  211. server_msg_counter_.inc(MSG_QRYREFERRAL);
  212. }
  213. }
  214. } else if (rcode == Rcode::REFUSED_CODE) {
  215. if (!response.getHeaderFlag(Message::HEADERFLAG_RD)) {
  216. // AuthRej
  217. server_msg_counter_.inc(MSG_QRYREJECT);
  218. }
  219. }
  220. }
  221. }
  222. void
  223. Counters::inc(const MessageAttributes& msgattrs, const Message& response,
  224. const bool done)
  225. {
  226. // increment request counters
  227. incRequest(msgattrs);
  228. if (done) {
  229. // increment response counters if answer was sent
  230. incResponse(msgattrs, response);
  231. }
  232. }
  233. Counters::ConstItemTreePtr
  234. Counters::get() const {
  235. using namespace isc::data;
  236. isc::data::ElementPtr item_tree = Element::createMap();
  237. isc::data::ElementPtr zones = Element::createMap();
  238. item_tree->set("zones", zones);
  239. isc::data::ElementPtr server = Element::createMap();
  240. fillNodes(server_msg_counter_, msg_counter_tree, server);
  241. zones->set("_SERVER_", server);
  242. return (item_tree);
  243. }
  244. } // namespace statistics
  245. } // namespace auth
  246. } // namespace isc