statistics.cc.pre 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  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. server_msg_counter_.inc(
  108. msgattrs.getRequestIPVersion() ==
  109. MessageAttributes::IP_VERSION_IPV4 ?
  110. MSG_REQUEST_IPV4 :
  111. MSG_REQUEST_IPV6);
  112. server_msg_counter_.inc(
  113. msgattrs.getRequestTransportProtocol() ==
  114. MessageAttributes::TRANSPORT_UDP ?
  115. MSG_REQUEST_UDP :
  116. MSG_REQUEST_TCP);
  117. // request TSIG
  118. if (msgattrs.getRequestSigTSIG()) {
  119. server_msg_counter_.inc(MSG_REQUEST_TSIG);
  120. }
  121. if (msgattrs.getRequestSigBadSig()) {
  122. server_msg_counter_.inc(MSG_REQUEST_BADSIG);
  123. // If signature validation is failed, no other query attributes are
  124. // reliable. Skip processing of the rest of query counters.
  125. return;
  126. }
  127. // request EDNS
  128. if (msgattrs.getRequestEDNS0()) {
  129. server_msg_counter_.inc(MSG_REQUEST_EDNS0);
  130. }
  131. // request DNSSEC
  132. if (msgattrs.getRequestDO()) {
  133. server_msg_counter_.inc(MSG_REQUEST_DNSSEC_OK);
  134. }
  135. // OPCODE
  136. const boost::optional<const isc::dns::Opcode&> opcode =
  137. msgattrs.getRequestOpCode();
  138. // Increment opcode counter only if the opcode exists.
  139. if (opcode) {
  140. server_msg_counter_.inc(opcode_to_msgcounter[opcode.get().getCode()]);
  141. }
  142. }
  143. void
  144. Counters::incResponse(const MessageAttributes& msgattrs,
  145. const Message& response)
  146. {
  147. // responded
  148. server_msg_counter_.inc(MSG_RESPONSE);
  149. // response truncated
  150. if (msgattrs.getResponseTruncated()) {
  151. server_msg_counter_.inc(MSG_RESPONSE_TRUNCATED);
  152. }
  153. // response EDNS
  154. ConstEDNSPtr response_edns = response.getEDNS();
  155. if (response_edns && response_edns->getVersion() == 0) {
  156. server_msg_counter_.inc(MSG_RESPONSE_EDNS0);
  157. }
  158. // response TSIG
  159. if (msgattrs.getResponseTSIG()) {
  160. server_msg_counter_.inc(MSG_RESPONSE_TSIG);
  161. }
  162. // response SIG(0) is currently not implemented
  163. // RCODE
  164. const unsigned int rcode = response.getRcode().getCode();
  165. const unsigned int rcode_type =
  166. rcode < num_rcode_to_msgcounter ?
  167. rcode_to_msgcounter[rcode] : MSG_RCODE_OTHER;
  168. server_msg_counter_.inc(rcode_type);
  169. // Unsupported EDNS version
  170. if (rcode == Rcode::BADVERS().getCode()) {
  171. server_msg_counter_.inc(MSG_REQUEST_BADEDNSVER);
  172. }
  173. const boost::optional<const isc::dns::Opcode&> opcode =
  174. msgattrs.getRequestOpCode();
  175. if (opcode && opcode.get() == Opcode::QUERY()) {
  176. // compound attributes
  177. const unsigned int answer_rrs =
  178. response.getRRCount(Message::SECTION_ANSWER);
  179. const bool is_aa_set =
  180. response.getHeaderFlag(Message::HEADERFLAG_AA);
  181. if (is_aa_set) {
  182. // QryAuthAns
  183. server_msg_counter_.inc(MSG_QRYAUTHANS);
  184. } else {
  185. // QryNoAuthAns
  186. server_msg_counter_.inc(MSG_QRYNOAUTHANS);
  187. }
  188. if (rcode == Rcode::NOERROR_CODE) {
  189. if (answer_rrs > 0) {
  190. // QrySuccess
  191. server_msg_counter_.inc(MSG_QRYSUCCESS);
  192. } else {
  193. if (is_aa_set) {
  194. // QryNxrrset
  195. server_msg_counter_.inc(MSG_QRYNXRRSET);
  196. } else {
  197. // QryReferral
  198. server_msg_counter_.inc(MSG_QRYREFERRAL);
  199. }
  200. }
  201. } else if (rcode == Rcode::REFUSED_CODE) {
  202. if (!response.getHeaderFlag(Message::HEADERFLAG_RD)) {
  203. // AuthRej
  204. server_msg_counter_.inc(MSG_QRYREJECT);
  205. }
  206. }
  207. }
  208. }
  209. void
  210. Counters::inc(const MessageAttributes& msgattrs, const Message& response,
  211. const bool done)
  212. {
  213. // increment request counters
  214. incRequest(msgattrs);
  215. if (done) {
  216. // increment response counters if answer was sent
  217. incResponse(msgattrs, response);
  218. }
  219. }
  220. Counters::ConstItemTreePtr
  221. Counters::get() const {
  222. using namespace isc::data;
  223. isc::data::ElementPtr item_tree = Element::createMap();
  224. isc::data::ElementPtr zones = Element::createMap();
  225. item_tree->set("zones", zones);
  226. isc::data::ElementPtr server = Element::createMap();
  227. fillNodes(server_msg_counter_, msg_counter_tree, server);
  228. zones->set("_SERVER_", server);
  229. return (item_tree);
  230. }
  231. } // namespace statistics
  232. } // namespace auth
  233. } // namespace isc