Merge branch 'opaque-ports'
[strongswan.git] / src / libstrongswan / plugins / unbound / unbound_response.c
1 /*
2 * Copyright (C) 2012 Reto Guadagnini
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <resolver/resolver_response.h>
17 #include <resolver/rr.h>
18 #include "unbound_rr.h"
19 #include "unbound_response.h"
20
21 #include <library.h>
22 #include <utils/debug.h>
23
24 #include <unbound.h>
25 #include <ldns/ldns.h>
26
27 typedef struct private_unbound_response_t private_unbound_response_t;
28
29 /**
30 * private data of an unbound_response_t object.
31 */
32 struct private_unbound_response_t {
33
34 /**
35 * Public data
36 */
37 unbound_response_t public;
38
39 /**
40 * Original question string
41 */
42 char* query_name;
43
44 /**
45 * Canonical name of the response
46 */
47 char* canon_name;
48
49 /**
50 * Are the some RRs in the RRset of this response?
51 */
52 bool has_data;
53
54 /*
55 * Does the queried name exist?
56 */
57 bool query_name_exist;
58
59 /**
60 * DNSSEC security state
61 */
62 dnssec_status_t security_state;
63
64 /**
65 * RRset
66 */
67 rr_set_t *rr_set;
68 };
69
70 METHOD(resolver_response_t, get_query_name, char*,
71 private_unbound_response_t *this)
72 {
73 return this->query_name;
74 }
75
76 METHOD(resolver_response_t, get_canon_name, char*,
77 private_unbound_response_t *this)
78 {
79 return this->canon_name;
80 }
81
82 METHOD(resolver_response_t, has_data, bool,
83 private_unbound_response_t *this)
84 {
85 return this->has_data;
86 }
87
88 METHOD(resolver_response_t, query_name_exist, bool,
89 private_unbound_response_t *this)
90 {
91 return this->query_name_exist;
92 }
93
94 METHOD(resolver_response_t, get_security_state, dnssec_status_t,
95 private_unbound_response_t *this)
96 {
97 return this->security_state;
98 }
99
100 METHOD(resolver_response_t, get_rr_set, rr_set_t*,
101 private_unbound_response_t *this)
102 {
103 return this->rr_set;
104 }
105
106 METHOD(resolver_response_t, destroy, void,
107 private_unbound_response_t *this)
108 {
109 free(this->query_name);
110 free(this->canon_name);
111 DESTROY_IF(this->rr_set);
112 free(this);
113 }
114
115 /*
116 * Described in header.
117 */
118 unbound_response_t *unbound_response_create_frm_libub_response(
119 struct ub_result *libub_response)
120 {
121 private_unbound_response_t *this = NULL;
122
123 INIT(this,
124 .public = {
125 .interface = {
126 .get_query_name = _get_query_name,
127 .get_canon_name = _get_canon_name,
128 .has_data = _has_data,
129 .query_name_exist = _query_name_exist,
130 .get_security_state = _get_security_state,
131 .get_rr_set = _get_rr_set,
132 .destroy = _destroy,
133 },
134 },
135 );
136
137 this->query_name = strdup(libub_response->qname);
138
139 if (libub_response->canonname)
140 {
141 this->canon_name = strdup(libub_response->canonname);
142 }
143
144 this->has_data = libub_response->havedata;
145
146 this->query_name_exist = !(libub_response->nxdomain);
147
148 if (libub_response->secure)
149 {
150 this->security_state = SECURE;
151 }
152 else if (libub_response->bogus)
153 {
154 this->security_state = BOGUS;
155 }
156 else
157 {
158 this->security_state = INDETERMINATE;
159 }
160
161 /**
162 * Create RRset
163 */
164 if (this->query_name_exist && this->has_data)
165 {
166 ldns_pkt *dns_pkt = NULL;
167 ldns_rr_list *orig_rr_list = NULL;
168 size_t orig_rr_count;
169 ldns_rr *orig_rr = NULL;
170 ldns_rdf *orig_rdf = NULL;
171 ldns_status status;
172 linked_list_t *rr_list = NULL, *rrsig_list = NULL;
173 unbound_rr_t *rr = NULL;
174 int i;
175
176 /**Parse the received DNS packet using the ldns library */
177 status = ldns_wire2pkt(&dns_pkt, libub_response->answer_packet,
178 libub_response->answer_len);
179
180 if (status != LDNS_STATUS_OK)
181 {
182 DBG1(DBG_LIB, "failed to parse DNS packet");
183 destroy(this);
184 return NULL;
185 }
186
187 /* Create a list with the queried RRs. If there are corresponding RRSIGs
188 * create also a list with these.
189 */
190 rr_list = linked_list_create();
191
192 orig_rr_list = ldns_pkt_get_section_clone(dns_pkt, LDNS_SECTION_ANSWER);
193 orig_rr_count = ldns_rr_list_rr_count(orig_rr_list);
194
195 for (i = 0; i < orig_rr_count; i++)
196 {
197 orig_rr = ldns_rr_list_rr(orig_rr_list, i);
198
199 if (ldns_rr_get_type(orig_rr) == libub_response->qtype &&
200 ldns_rr_get_class(orig_rr) == libub_response->qclass)
201 {
202 /* RR is part of the queried RRset.
203 * => add it to the list of Resource Records.
204 */
205 rr = unbound_rr_create_frm_ldns_rr(orig_rr);
206 if (rr)
207 {
208 rr_list->insert_last(rr_list, rr);
209 }
210 else
211 {
212 DBG1(DBG_LIB, "failed to create RR");
213 }
214 }
215
216 if (ldns_rr_get_type(orig_rr) == LDNS_RR_TYPE_RRSIG)
217 {
218 orig_rdf = ldns_rr_rrsig_typecovered(orig_rr);
219 if (!orig_rdf)
220 {
221 DBG1(DBG_LIB, "failed to get the type covered by an RRSIG");
222 }
223 else if (ldns_rdf2native_int16(orig_rdf) == libub_response->qtype)
224 {
225 /* The current RR represent a signature (RRSIG)
226 * which belongs to the queried RRset.
227 * => add it to the list of signatures.
228 */
229 rr = unbound_rr_create_frm_ldns_rr(orig_rr);
230 if (rr)
231 {
232 if (!rrsig_list)
233 {
234 rrsig_list = linked_list_create();
235 }
236 rrsig_list->insert_last(rrsig_list, rr);
237 }
238 else
239 {
240 DBG1(DBG_LIB, "failed to create RRSIG");
241 }
242 }
243 else
244 {
245 DBG1(DBG_LIB, "failed to determine the RR type "
246 "covered by RRSIG RR");
247 }
248 }
249 }
250 /**
251 * Create the RRset for which the query was performed.
252 */
253 this->rr_set = rr_set_create(rr_list, rrsig_list);
254
255 ldns_pkt_free(dns_pkt);
256 ldns_rr_list_free(orig_rr_list);
257 }
258 return &this->public;
259 }