xref: /netbsd-src/external/bsd/unbound/dist/pythonmod/pythonmod_utils.c (revision 91f7d55fb697b5e0475da4718fa34c3a3ebeac85)
1 /*
2  * pythonmod_utils.c: utilities used by wrapper
3  *
4  * Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
5  *                     Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)
6  *
7  * This software is open source.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  *    * Redistributions of source code must retain the above copyright notice,
14  *      this list of conditions and the following disclaimer.
15  *
16  *    * Redistributions in binary form must reproduce the above copyright notice,
17  *      this list of conditions and the following disclaimer in the documentation
18  *      and/or other materials provided with the distribution.
19  *
20  *    * Neither the name of the organization nor the names of its
21  *      contributors may be used to endorse or promote products derived from this
22  *      software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
28  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  */
36 /**
37  * \file
38  * Utility functions for the python module that perform stores and loads and
39  * conversions.
40  */
41 #include "config.h"
42 #include "pythonmod/pythonmod_utils.h"
43 #include "util/module.h"
44 #include "util/netevent.h"
45 #include "util/net_help.h"
46 #include "services/cache/dns.h"
47 #include "services/cache/rrset.h"
48 #include "util/data/msgparse.h"
49 #include "util/data/msgreply.h"
50 #include "util/storage/slabhash.h"
51 #include "util/regional.h"
52 #include "iterator/iter_delegpt.h"
53 #include "sldns/sbuffer.h"
54 
55 #undef _POSIX_C_SOURCE
56 #undef _XOPEN_SOURCE
57 #include <Python.h>
58 
59 /* Store the reply_info and query_info pair in message cache
60  * (qstate->msg_cache) */
storeQueryInCache(struct module_qstate * qstate,struct query_info * qinfo,struct reply_info * msgrep,int is_referral)61 int storeQueryInCache(struct module_qstate* qstate, struct query_info* qinfo,
62 	struct reply_info* msgrep, int is_referral)
63 {
64 	if (!msgrep)
65 		return 0;
66 
67 	/* authoritative answer can't be stored in cache */
68 	if (msgrep->authoritative) {
69 		PyErr_SetString(PyExc_ValueError,
70 			"Authoritative answer can't be stored");
71 		return 0;
72 	}
73 
74 	return dns_cache_store(qstate->env, qinfo, msgrep, is_referral,
75 		qstate->prefetch_leeway, 0, NULL, qstate->query_flags,
76 		qstate->qstarttime);
77 }
78 
79 /* Invalidate the message associated with query_info stored in message cache */
invalidateQueryInCache(struct module_qstate * qstate,struct query_info * qinfo)80 void invalidateQueryInCache(struct module_qstate* qstate,
81 	struct query_info* qinfo)
82 {
83 	hashvalue_type h;
84 	struct lruhash_entry* e;
85 	struct reply_info *r;
86 	size_t i, j;
87 
88 	h = query_info_hash(qinfo, qstate->query_flags);
89 	if ((e=slabhash_lookup(qstate->env->msg_cache, h, qinfo, 0))) {
90 		r = (struct reply_info*)(e->data);
91 		if (r) {
92 			r->ttl = 0;
93 			if(rrset_array_lock(r->ref, r->rrset_count, *qstate->env->now)) {
94 				for(i=0; i< r->rrset_count; i++) {
95 					struct packed_rrset_data* data =
96 						(struct packed_rrset_data*) r->ref[i].key->entry.data;
97 					if(i>0 && r->ref[i].key == r->ref[i-1].key)
98 						continue;
99 
100 					data->ttl = r->ttl;
101 					for(j=0; j<data->count + data->rrsig_count; j++)
102 						data->rr_ttl[j] = r->ttl;
103 				}
104 				rrset_array_unlock(r->ref, r->rrset_count);
105 			}
106 		}
107 		lock_rw_unlock(&e->lock);
108 	} else {
109 		log_info("invalidateQueryInCache: qinfo is not in cache");
110 	}
111 }
112 
113 /* Create response according to the ldns packet content */
createResponse(struct module_qstate * qstate,sldns_buffer * pkt)114 int createResponse(struct module_qstate* qstate, sldns_buffer* pkt)
115 {
116 	struct msg_parse* prs;
117 	struct edns_data edns;
118 
119 	/* parse message */
120 	prs = (struct msg_parse*) regional_alloc(qstate->env->scratch,
121 		sizeof(struct msg_parse));
122 	if(!prs) {
123 		log_err("createResponse: out of memory on incoming message");
124 		return 0;
125 	}
126 
127 	memset(prs, 0, sizeof(*prs));
128 	memset(&edns, 0, sizeof(edns));
129 
130 	sldns_buffer_set_position(pkt, 0);
131 	if(parse_packet(pkt, prs, qstate->env->scratch) != LDNS_RCODE_NOERROR) {
132 		verbose(VERB_ALGO, "createResponse: parse error on reply packet");
133 		return 0;
134 	}
135 	/* edns is not examined, but removed from message to help cache */
136 	if(parse_extract_edns_from_response_msg(prs, &edns, qstate->env->scratch) !=
137 		LDNS_RCODE_NOERROR)
138 		return 0;
139 
140 	/* remove CD-bit, we asked for in case we handle validation ourself */
141 	prs->flags &= ~BIT_CD;
142 
143 	/* allocate response dns_msg in region */
144 	qstate->return_msg = (struct dns_msg*) regional_alloc(qstate->region,
145 		sizeof(struct dns_msg));
146 	if(!qstate->return_msg)
147 		return 0;
148 
149 	memset(qstate->return_msg, 0, sizeof(*qstate->return_msg));
150 	if(!parse_create_msg(pkt, prs, NULL, &(qstate->return_msg)->qinfo,
151 		&(qstate->return_msg)->rep, qstate->region)) {
152 		log_err("createResponse: malloc failure: allocating incoming dns_msg");
153 		return 0;
154 	}
155 
156 	/* Make sure that the RA flag is set (since the presence of
157 	* this module means that recursion is available) */
158 	/* qstate->return_msg->rep->flags |= BIT_RA; */
159 
160 	/* Clear the AA flag */
161 	/* FIXME: does this action go here or in some other module? */
162 	/*qstate->return_msg->rep->flags &= ~BIT_AA; */
163 
164 	/* make sure QR flag is on */
165 	/*qstate->return_msg->rep->flags |= BIT_QR; */
166 
167 	if(verbosity >= VERB_ALGO)
168 		log_dns_msg("createResponse: packet:", &qstate->return_msg->qinfo,
169 			qstate->return_msg->rep);
170 
171 	return 1;
172 }
173 
174 
175 /* Convert reply->client_addr to string */
reply_addr2str(struct comm_reply * reply,char * dest,int maxlen)176 void reply_addr2str(struct comm_reply* reply, char* dest, int maxlen)
177 {
178 	int af = (int)((struct sockaddr_in*) &(reply->client_addr))->sin_family;
179 	void* sinaddr = &((struct sockaddr_in*) &(reply->client_addr))->sin_addr;
180 
181 	if(af == AF_INET6)
182 		sinaddr = &((struct sockaddr_in6*)&(reply->client_addr))->sin6_addr;
183 	dest[0] = 0;
184 	if (inet_ntop(af, sinaddr, dest, (socklen_t)maxlen) == 0)
185 		return;
186 	dest[maxlen-1] = 0;
187 }
188 
189 /* Convert target->addr to string */
delegpt_addr_addr2str(struct delegpt_addr * target,char * dest,int maxlen)190 void delegpt_addr_addr2str(struct delegpt_addr* target, char *dest, int maxlen)
191 {
192 	int af = (int)((struct sockaddr_in*) &(target->addr))->sin_family;
193 	void* sinaddr = &((struct sockaddr_in*) &(target->addr))->sin_addr;
194 
195 	if(af == AF_INET6)
196 		sinaddr = &((struct sockaddr_in6*)&(target->addr))->sin6_addr;
197 	dest[0] = 0;
198 	if (inet_ntop(af, sinaddr, dest, (socklen_t)maxlen) == 0)
199 		return;
200 	dest[maxlen-1] = 0;
201 }
202