add script that prepares system for use of our wrapper script
[0tDNS.git] / src / receive_respond.c
bloba3b1e8e97c7db4606f2316f6bf6a7ee52e6927ae
1 /*
2 * Copyright (c) 2009 - 2012 Marco Peereboom <marco@peereboom.us>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 /* for strdup() */
18 #define _POSIX_C_SOURCE 200809L
19 #include <string.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <err.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
28 #include <ldns/ldns.h>
30 #define MAXLINE 256
31 #define INBUF_SIZE 4096
33 struct sockaddr paddr;
34 socklen_t plen = (socklen_t)sizeof(paddr);
36 int
37 udp_bind(int sock, uint16_t port)
39 struct sockaddr_in addr;
40 in_addr_t maddr = INADDR_ANY;
42 addr.sin_family = AF_INET;
43 addr.sin_port = (in_port_t) htons((uint16_t)port);
44 addr.sin_addr.s_addr = maddr;
45 return (bind(sock, (struct sockaddr*)&addr, (socklen_t) sizeof(addr)));
48 int
49 socket_create(uint16_t port) {
50 int so = socket(AF_INET, SOCK_DGRAM, 0);
51 if (so == -1)
52 err(1, "can't open socket");
53 if (udp_bind(so, port))
54 err(1, "can't udp bind");
55 return so;
58 void
59 printpacket(ldns_pkt *pkt)
61 char *str = ldns_pkt2str(pkt);
63 if (str) {
64 printf("%s", str);
65 LDNS_FREE(str);
66 } else
67 warnx("could not convert packet to string");
70 ldns_pkt *
71 receive_and_print(int so) {
72 uint8_t inbuf[INBUF_SIZE];
73 ssize_t nb;
74 ldns_status status;
75 ldns_pkt *query_pkt;
77 nb = recvfrom(so, inbuf, INBUF_SIZE, 0, &paddr, &plen);
78 if (nb == -1) {
79 if (errno == EINTR || errno == EAGAIN)
80 return NULL;
81 else
82 err(EXIT_FAILURE, "recvfrom");
85 status = ldns_wire2pkt(&query_pkt, inbuf, (size_t)nb);
86 if (status != LDNS_STATUS_OK) {
87 warnx("bad packet: %s", ldns_get_errorstr_by_id(status));
88 return NULL;
89 } else {
90 puts("received packet:");
91 printpacket(query_pkt);
94 return query_pkt;
97 int
98 send_response(int so, const char *hostname, ldns_pkt *respkt, uint16_t id)
100 size_t answer_size;
101 ldns_status status;
102 uint8_t *outbuf = NULL;
103 int rv = 1;
105 if (hostname == NULL || respkt == NULL) {
106 warnx("send_response: invalid parameters");
107 return (0);
110 ldns_pkt_set_id(respkt, id);
111 status = ldns_pkt2wire(&outbuf, respkt, &answer_size);
112 if (status != LDNS_STATUS_OK)
113 warnx("can't create answer: %s",
114 ldns_get_errorstr_by_id(status));
115 else {
116 puts("response packet:");
117 printpacket(respkt);
119 if (sendto(so, outbuf, answer_size, 0, &paddr, plen) == -1)
120 warn("send_response: sendto");
121 else {
122 rv = 0;
124 printf("send_response: resolved %s", hostname);
128 if (outbuf)
129 LDNS_FREE(outbuf);
131 return (rv);
134 char *
135 hostnamefrompkt(ldns_pkt *pkt, ldns_rr **qrr)
137 ldns_rr *query_rr;
138 ldns_buffer *out = NULL;
139 ldns_rdf *rdf;
140 char *ret = NULL;
142 if (pkt == NULL)
143 return (NULL);
145 query_rr = ldns_rr_list_rr(ldns_pkt_question(pkt), 0);
146 if (query_rr == NULL) {
147 warnx("hostnamefrompkt invalid parameters");
148 goto done;
151 out = ldns_buffer_new(LDNS_MAX_DOMAINLEN);
152 if (out == NULL) {
153 warnx("no memory for out buffer");
154 goto done;
157 rdf = ldns_rr_owner(query_rr);
158 if (ldns_rdf2buffer_str_dname(out, rdf) != LDNS_STATUS_OK) {
159 warnx("can't get hostname");
160 goto done;
163 ret = strdup((char *)ldns_buffer_begin(out));
164 if (ret == NULL) {
165 warn("no memory for hostname");
166 goto done;
169 if (qrr)
170 *qrr = query_rr;
171 done:
172 if (out)
173 ldns_buffer_free(out);
175 return (ret);
179 respond_query(int so, const char *hostname, const char *ipaddr,
180 ldns_rr *query_rr, uint16_t id)
182 ldns_status status;
183 ldns_rr_list *answer_an = NULL;
184 ldns_rr_list *answer_ns = NULL;
185 ldns_rr_list *answer_ad = NULL;
186 ldns_rr_list *answer_qr = NULL;
187 ldns_pkt *answer_pkt = NULL;
188 ldns_rr *myrr = NULL, *myaurr = NULL, *myasrr = NULL;
189 ldns_rdf *prev = NULL;
190 char buf[MAXLINE * 2];
191 uint8_t *outbuf = NULL;
192 int rv = 1;
194 /* answer section */
195 answer_an = ldns_rr_list_new();
196 if (answer_an == NULL)
197 goto unwind;
199 /* authority section */
200 answer_ns = ldns_rr_list_new();
201 if (answer_ns == NULL)
202 goto unwind;
204 /* if we have an ip spoof it there */
205 if (ipaddr) {
206 /* an */
207 snprintf(buf, sizeof buf, "%s\t%d\tIN\tA\t%s",
208 hostname, 259200, ipaddr);
209 status = ldns_rr_new_frm_str(&myrr, buf, 0, NULL, &prev);
210 if (status != LDNS_STATUS_OK) {
211 fprintf(stderr, "can't create answer section: %s\n",
212 ldns_get_errorstr_by_id(status));
213 goto unwind;
215 ldns_rr_list_push_rr(answer_an, myrr);
216 ldns_rdf_deep_free(prev);
217 prev = NULL;
219 /* ns */
220 snprintf(buf, sizeof buf, "%s\t%d\tIN\tNS\t%s.",
221 hostname, 259200, "localhost");
222 status = ldns_rr_new_frm_str(&myaurr, buf, 0, NULL, &prev);
223 if (status != LDNS_STATUS_OK) {
224 fprintf(stderr, "can't create authority section: %s\n",
225 ldns_get_errorstr_by_id(status));
226 goto unwind;
228 ldns_rr_list_push_rr(answer_ns, myaurr);
229 ldns_rdf_deep_free(prev);
230 prev = NULL;
231 } else {
232 snprintf(buf, sizeof buf, "%s\t3600\tIN\tSOA\t%s root.%s %s",
233 hostname,
234 hostname,
235 hostname,
236 "2 3600 900 3600000 3600");
237 status = ldns_rr_new_frm_str(&myaurr, buf, 0, NULL, &prev);
238 if (status != LDNS_STATUS_OK) {
239 fprintf(stderr, "can't create authority section: %s\n",
240 ldns_get_errorstr_by_id(status));
241 goto unwind;
243 ldns_rr_list_push_rr(answer_ns, myaurr);
244 ldns_rdf_deep_free(prev);
245 prev = NULL;
248 /* question section */
249 answer_qr = ldns_rr_list_new();
250 if (answer_qr == NULL)
251 goto unwind;
252 ldns_rr_list_push_rr(answer_qr, ldns_rr_clone(query_rr));
254 /* additional section */
255 answer_ad = ldns_rr_list_new();
256 if (answer_ad == NULL)
257 goto unwind;
258 if (ipaddr) {
259 snprintf(buf, sizeof buf, "%s\t%d\tIN\tA\t%s",
260 "localhost",
261 259200,
262 "127.0.0.1");
263 status = ldns_rr_new_frm_str(&myasrr, buf, 0, NULL, &prev);
264 if (status != LDNS_STATUS_OK) {
265 fprintf(stderr, "can't create additional section: %s\n",
266 ldns_get_errorstr_by_id(status));
267 goto unwind;
269 ldns_rr_list_push_rr(answer_ad, myasrr);
270 ldns_rdf_deep_free(prev);
271 prev = NULL;
273 /* V6 */
274 snprintf(buf, sizeof buf, "%s\t%d\tIN\tAAAA\t%s",
275 "localhost",
276 259200,
277 "::1");
278 status = ldns_rr_new_frm_str(&myasrr, buf, 0, NULL, &prev);
279 if (status != LDNS_STATUS_OK) {
280 fprintf(stderr, "can't create additional section: %s\n",
281 ldns_get_errorstr_by_id(status));
282 goto unwind;
284 ldns_rr_list_push_rr(answer_ad, myasrr);
285 ldns_rdf_deep_free(prev);
286 prev = NULL;
289 /* actual packet */
290 answer_pkt = ldns_pkt_new();
291 if (answer_pkt == NULL)
292 goto unwind;
294 ldns_pkt_set_qr(answer_pkt, 1);
295 ldns_pkt_set_aa(answer_pkt, 1);
296 if (ipaddr == NULL)
297 ldns_pkt_set_rcode(answer_pkt, LDNS_RCODE_NXDOMAIN);
299 ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_QUESTION, answer_qr);
300 ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ANSWER, answer_an);
301 ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_AUTHORITY, answer_ns);
302 ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ADDITIONAL, answer_ad);
304 /* reply to caller */
305 if (send_response(so, hostname, answer_pkt, id))
306 warnx("send_response failed");
308 unwind:
309 if (answer_pkt)
310 ldns_pkt_free(answer_pkt);
311 if (outbuf)
312 LDNS_FREE(outbuf);
313 if (answer_qr)
314 ldns_rr_list_free(answer_qr);
315 if (answer_an)
316 ldns_rr_list_free(answer_an);
317 if (answer_ns)
318 ldns_rr_list_free(answer_ns);
319 if (answer_ad)
320 ldns_rr_list_free(answer_ad);
322 return (rv);