| /* |
| * Copyright (C) 2012 Reto Guadagnini |
| * HSR Hochschule fuer Technik Rapperswil |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by the |
| * Free Software Foundation; either version 2 of the License, or (at your |
| * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. |
| * |
| * This program is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * for more details. |
| */ |
| |
| #include <resolver/resolver_response.h> |
| #include <resolver/rr.h> |
| #include "unbound_rr.h" |
| #include "unbound_response.h" |
| |
| #include <library.h> |
| #include <utils/debug.h> |
| |
| #include <unbound.h> |
| #include <ldns/ldns.h> |
| |
| typedef struct private_unbound_response_t private_unbound_response_t; |
| |
| /** |
| * private data of an unbound_response_t object. |
| */ |
| struct private_unbound_response_t { |
| |
| /** |
| * Public data |
| */ |
| unbound_response_t public; |
| |
| /** |
| * Original question string |
| */ |
| char* query_name; |
| |
| /** |
| * Canonical name of the response |
| */ |
| char* canon_name; |
| |
| /** |
| * Are the some RRs in the RRset of this response? |
| */ |
| bool has_data; |
| |
| /* |
| * Does the queried name exist? |
| */ |
| bool query_name_exist; |
| |
| /** |
| * DNSSEC security state |
| */ |
| dnssec_status_t security_state; |
| |
| /** |
| * RRset |
| */ |
| rr_set_t *rr_set; |
| }; |
| |
| METHOD(resolver_response_t, get_query_name, char*, |
| private_unbound_response_t *this) |
| { |
| return this->query_name; |
| } |
| |
| METHOD(resolver_response_t, get_canon_name, char*, |
| private_unbound_response_t *this) |
| { |
| return this->canon_name; |
| } |
| |
| METHOD(resolver_response_t, has_data, bool, |
| private_unbound_response_t *this) |
| { |
| return this->has_data; |
| } |
| |
| METHOD(resolver_response_t, query_name_exist, bool, |
| private_unbound_response_t *this) |
| { |
| return this->query_name_exist; |
| } |
| |
| METHOD(resolver_response_t, get_security_state, dnssec_status_t, |
| private_unbound_response_t *this) |
| { |
| return this->security_state; |
| } |
| |
| METHOD(resolver_response_t, get_rr_set, rr_set_t*, |
| private_unbound_response_t *this) |
| { |
| return this->rr_set; |
| } |
| |
| METHOD(resolver_response_t, destroy, void, |
| private_unbound_response_t *this) |
| { |
| free(this->query_name); |
| free(this->canon_name); |
| DESTROY_IF(this->rr_set); |
| free(this); |
| } |
| |
| /* |
| * Described in header. |
| */ |
| unbound_response_t *unbound_response_create_frm_libub_response( |
| struct ub_result *libub_response) |
| { |
| private_unbound_response_t *this = NULL; |
| |
| INIT(this, |
| .public = { |
| .interface = { |
| .get_query_name = _get_query_name, |
| .get_canon_name = _get_canon_name, |
| .has_data = _has_data, |
| .query_name_exist = _query_name_exist, |
| .get_security_state = _get_security_state, |
| .get_rr_set = _get_rr_set, |
| .destroy = _destroy, |
| }, |
| }, |
| ); |
| |
| this->query_name = strdup(libub_response->qname); |
| |
| if (libub_response->canonname) |
| { |
| this->canon_name = strdup(libub_response->canonname); |
| } |
| |
| this->has_data = libub_response->havedata; |
| |
| this->query_name_exist = !(libub_response->nxdomain); |
| |
| if (libub_response->secure) |
| { |
| this->security_state = SECURE; |
| } |
| else if (libub_response->bogus) |
| { |
| this->security_state = BOGUS; |
| } |
| else |
| { |
| this->security_state = INDETERMINATE; |
| } |
| |
| /** |
| * Create RRset |
| */ |
| if (this->query_name_exist && this->has_data) |
| { |
| ldns_pkt *dns_pkt = NULL; |
| ldns_rr_list *orig_rr_list = NULL; |
| size_t orig_rr_count; |
| ldns_rr *orig_rr = NULL; |
| ldns_rdf *orig_rdf = NULL; |
| ldns_status status; |
| linked_list_t *rr_list = NULL, *rrsig_list = NULL; |
| unbound_rr_t *rr = NULL; |
| int i; |
| |
| /**Parse the received DNS packet using the ldns library */ |
| status = ldns_wire2pkt(&dns_pkt, libub_response->answer_packet, |
| libub_response->answer_len); |
| |
| if (status != LDNS_STATUS_OK) |
| { |
| DBG1(DBG_LIB, "failed to parse DNS packet"); |
| destroy(this); |
| return NULL; |
| } |
| |
| /* Create a list with the queried RRs. If there are corresponding RRSIGs |
| * create also a list with these. |
| */ |
| rr_list = linked_list_create(); |
| |
| orig_rr_list = ldns_pkt_answer(dns_pkt); |
| orig_rr_count = ldns_rr_list_rr_count(orig_rr_list); |
| |
| for (i = 0; i < orig_rr_count; i++) |
| { |
| orig_rr = ldns_rr_list_rr(orig_rr_list, i); |
| |
| if (ldns_rr_get_type(orig_rr) == libub_response->qtype && |
| ldns_rr_get_class(orig_rr) == libub_response->qclass) |
| { |
| /* RR is part of the queried RRset. |
| * => add it to the list of Resource Records. |
| */ |
| rr = unbound_rr_create_frm_ldns_rr(orig_rr); |
| if (rr) |
| { |
| rr_list->insert_last(rr_list, rr); |
| } |
| else |
| { |
| DBG1(DBG_LIB, "failed to create RR"); |
| } |
| } |
| |
| if (ldns_rr_get_type(orig_rr) == LDNS_RR_TYPE_RRSIG) |
| { |
| orig_rdf = ldns_rr_rrsig_typecovered(orig_rr); |
| if (!orig_rdf) |
| { |
| DBG1(DBG_LIB, "failed to get the type covered by an RRSIG"); |
| } |
| else if (ldns_rdf2native_int16(orig_rdf) == libub_response->qtype) |
| { |
| /* The current RR represent a signature (RRSIG) |
| * which belongs to the queried RRset. |
| * => add it to the list of signatures. |
| */ |
| rr = unbound_rr_create_frm_ldns_rr(orig_rr); |
| if (rr) |
| { |
| if (!rrsig_list) |
| { |
| rrsig_list = linked_list_create(); |
| } |
| rrsig_list->insert_last(rrsig_list, rr); |
| } |
| else |
| { |
| DBG1(DBG_LIB, "failed to create RRSIG"); |
| } |
| } |
| else |
| { |
| DBG1(DBG_LIB, "failed to determine the RR type " |
| "covered by RRSIG RR"); |
| } |
| } |
| } |
| /** |
| * Create the RRset for which the query was performed. |
| */ |
| this->rr_set = rr_set_create(rr_list, rrsig_list); |
| |
| ldns_pkt_free(dns_pkt); |
| } |
| return &this->public; |
| } |