// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC") // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace isc::dns; using namespace isc::auth; using namespace isc::statistics; using namespace isc::auth::statistics; namespace { void fillNodes(const Counter& counter, const struct isc::auth::statistics::CounterSpec type_tree[], isc::auth::statistics::Counters::ItemTreePtr& trees) { using namespace isc::data; for (int i = 0; type_tree[i].name != NULL; ++i) { if (type_tree[i].sub_counters != NULL) { isc::auth::statistics::Counters::ItemTreePtr sub_counters = Element::createMap(); trees->set(type_tree[i].name, sub_counters); fillNodes(counter, type_tree[i].sub_counters, sub_counters); } else { trees->set(type_tree[i].name, Element::create(static_cast( counter.get(type_tree[i].counter_id))) ); } } } // ### STATISTICS ITEMS DEFINITION ### } // anonymous namespace namespace isc { namespace auth { namespace statistics { // Note: opcode in this array must be start with 0 and be sequential const int opcode_to_msgcounter[] = { MSG_OPCODE_QUERY, // Opcode = 0: Query MSG_OPCODE_IQUERY, // Opcode = 1: Iquery MSG_OPCODE_STATUS, // Opcode = 2: STATUS MSG_OPCODE_OTHER, // Opcode = 3: (Unassigned) MSG_OPCODE_NOTIFY, // Opcode = 4: Notify MSG_OPCODE_UPDATE, // Opcode = 5: Update MSG_OPCODE_OTHER, // Opcode = 6: (Unassigned) MSG_OPCODE_OTHER, // Opcode = 7: (Unassigned) MSG_OPCODE_OTHER, // Opcode = 8: (Unassigned) MSG_OPCODE_OTHER, // Opcode = 9: (Unassigned) MSG_OPCODE_OTHER, // Opcode = 10: (Unassigned) MSG_OPCODE_OTHER, // Opcode = 11: (Unassigned) MSG_OPCODE_OTHER, // Opcode = 12: (Unassigned) MSG_OPCODE_OTHER, // Opcode = 13: (Unassigned) MSG_OPCODE_OTHER, // Opcode = 14: (Unassigned) MSG_OPCODE_OTHER // Opcode = 15: (Unassigned) }; const size_t num_opcode_to_msgcounter = sizeof(opcode_to_msgcounter) / sizeof(opcode_to_msgcounter[0]); // Note: rcode in this array must be start with 0 and be sequential const int rcode_to_msgcounter[] = { MSG_RCODE_NOERROR, // Rcode = 0: NoError MSG_RCODE_FORMERR, // Rcode = 1: FormErr MSG_RCODE_SERVFAIL, // Rcode = 2: ServFail MSG_RCODE_NXDOMAIN, // Rcode = 3: NXDomain MSG_RCODE_NOTIMP, // Rcode = 4: NotImp MSG_RCODE_REFUSED, // Rcode = 5: Refused MSG_RCODE_YXDOMAIN, // Rcode = 6: YXDomain MSG_RCODE_YXRRSET, // Rcode = 7: YXRRSet MSG_RCODE_NXRRSET, // Rcode = 8: NXRRSet MSG_RCODE_NOTAUTH, // Rcode = 9: NotAuth MSG_RCODE_NOTZONE, // Rcode = 10: NotZone MSG_RCODE_OTHER, // Rcode = 11: (Unassigned) MSG_RCODE_OTHER, // Rcode = 12: (Unassigned) MSG_RCODE_OTHER, // Rcode = 13: (Unassigned) MSG_RCODE_OTHER, // Rcode = 14: (Unassigned) MSG_RCODE_OTHER, // Rcode = 15: (Unassigned) MSG_RCODE_BADVERS // Rcode = 16: BADVERS }; const size_t num_rcode_to_msgcounter = sizeof(rcode_to_msgcounter) / sizeof(rcode_to_msgcounter[0]); Counters::Counters() : server_msg_counter_(MSG_COUNTER_TYPES) {} void Counters::incRequest(const MessageAttributes& msgattrs) { // protocols carrying request if (msgattrs.getRequestIPVersion() == AF_INET) { server_msg_counter_.inc(MSG_REQUEST_IPV4); } else if (msgattrs.getRequestIPVersion() == AF_INET6) { server_msg_counter_.inc(MSG_REQUEST_IPV6); } if (msgattrs.getRequestTransportProtocol() == IPPROTO_UDP) { server_msg_counter_.inc(MSG_REQUEST_UDP); } else if (msgattrs.getRequestTransportProtocol() == IPPROTO_TCP) { server_msg_counter_.inc(MSG_REQUEST_TCP); } // request TSIG if (msgattrs.getRequestSigTSIG()) { server_msg_counter_.inc(MSG_REQUEST_TSIG); } if (msgattrs.getRequestSigSIG0()) { server_msg_counter_.inc(MSG_REQUEST_SIG0); } if (msgattrs.getRequestSigBadSig()) { server_msg_counter_.inc(MSG_REQUEST_BADSIG); // If signature validation is failed, no other query attributes are // reliable. Skip processing of the rest of query counters. return; } // request EDNS if (msgattrs.getRequestEDNS0()) { server_msg_counter_.inc(MSG_REQUEST_EDNS0); } if (msgattrs.getRequestEDNSBadVer()) { server_msg_counter_.inc(MSG_REQUEST_BADEDNSVER); } // request DNSSEC if (msgattrs.getRequestDO()) { server_msg_counter_.inc(MSG_REQUEST_DNSSEC_OK); } // OPCODE server_msg_counter_.inc(opcode_to_msgcounter[msgattrs.getRequestOpCode()]); } void Counters::incResponse(const MessageAttributes& msgattrs, const Message& response) { // responded server_msg_counter_.inc(MSG_RESPONSE); // response truncated if (msgattrs.getResponseTruncated()) { server_msg_counter_.inc(MSG_RESPONSE_TRUNCATED); } // response EDNS ConstEDNSPtr response_edns = response.getEDNS(); if (response_edns && response_edns->getVersion() == 0) { server_msg_counter_.inc(MSG_RESPONSE_EDNS0); } // response TSIG if (msgattrs.getRequestSigTSIG()) { // assume response is TSIG signed if request is TSIG signed server_msg_counter_.inc(MSG_RESPONSE_TSIG); } // response SIG(0) is currently not implemented // RCODE const unsigned int rcode = response.getRcode().getCode(); const unsigned int rcode_type = rcode < num_rcode_to_msgcounter ? rcode_to_msgcounter[rcode] : MSG_RCODE_OTHER; server_msg_counter_.inc(rcode_type); // compound attributes const unsigned int answer_rrs = response.getRRCount(Message::SECTION_ANSWER); const bool is_aa_set = response.getHeaderFlag(Message::HEADERFLAG_AA); if (is_aa_set) { // QryAuthAns server_msg_counter_.inc(MSG_QRYAUTHANS); } else { // QryNoAuthAns server_msg_counter_.inc(MSG_QRYNOAUTHANS); } if (rcode == Rcode::NOERROR_CODE) { if (answer_rrs > 0) { // QrySuccess server_msg_counter_.inc(MSG_QRYSUCCESS); } else { if (is_aa_set) { // QryNxrrset server_msg_counter_.inc(MSG_QRYNXRRSET); } else { // QryReferral server_msg_counter_.inc(MSG_QRYREFERRAL); } } } else if (rcode == Rcode::REFUSED_CODE) { // AuthRej server_msg_counter_.inc(MSG_QRYREJECT); } } void Counters::inc(const MessageAttributes& msgattrs, const Message& response, const bool done) { // increment request counters incRequest(msgattrs); if (done) { // increment response counters if answer was sent incResponse(msgattrs, response); } } Counters::ItemTreePtr Counters::get() const { using namespace isc::data; Counters::ItemTreePtr item_tree = Element::createMap(); Counters::ItemTreePtr zones = Element::createMap(); item_tree->set("zones", zones); Counters::ItemTreePtr server = Element::createMap(); fillNodes(server_msg_counter_, msg_counter_tree, server); zones->set("_SERVER_", server); return (item_tree); } } // namespace statistics } // namespace auth } // namespace isc