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.
18 #define _POSIX_C_SOURCE 200809L
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
28 #include <ldns/ldns.h>
31 #define INBUF_SIZE 4096
33 struct sockaddr paddr
;
34 socklen_t plen
= (socklen_t
)sizeof(paddr
);
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
)));
49 socket_create(uint16_t port
) {
50 int so
= socket(AF_INET
, SOCK_DGRAM
, 0);
52 err(1, "can't open socket");
53 if (udp_bind(so
, port
))
54 err(1, "can't udp bind");
59 printpacket(ldns_pkt
*pkt
)
61 char *str
= ldns_pkt2str(pkt
);
67 warnx("could not convert packet to string");
71 receive_and_print(int so
) {
72 uint8_t inbuf
[INBUF_SIZE
];
77 nb
= recvfrom(so
, inbuf
, INBUF_SIZE
, 0, &paddr
, &plen
);
79 if (errno
== EINTR
|| errno
== EAGAIN
)
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
));
90 puts("received packet:");
91 printpacket(query_pkt
);
98 send_response(int so
, const char *hostname
, ldns_pkt
*respkt
, uint16_t id
)
102 uint8_t *outbuf
= NULL
;
105 if (hostname
== NULL
|| respkt
== NULL
) {
106 warnx("send_response: invalid parameters");
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
));
116 puts("response packet:");
119 if (sendto(so
, outbuf
, answer_size
, 0, &paddr
, plen
) == -1)
120 warn("send_response: sendto");
124 printf("send_response: resolved %s", hostname
);
135 hostnamefrompkt(ldns_pkt
*pkt
, ldns_rr
**qrr
)
138 ldns_buffer
*out
= NULL
;
145 query_rr
= ldns_rr_list_rr(ldns_pkt_question(pkt
), 0);
146 if (query_rr
== NULL
) {
147 warnx("hostnamefrompkt invalid parameters");
151 out
= ldns_buffer_new(LDNS_MAX_DOMAINLEN
);
153 warnx("no memory for out buffer");
157 rdf
= ldns_rr_owner(query_rr
);
158 if (ldns_rdf2buffer_str_dname(out
, rdf
) != LDNS_STATUS_OK
) {
159 warnx("can't get hostname");
163 ret
= strdup((char *)ldns_buffer_begin(out
));
165 warn("no memory for hostname");
173 ldns_buffer_free(out
);
179 respond_query(int so
, const char *hostname
, const char *ipaddr
,
180 ldns_rr
*query_rr
, uint16_t id
)
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
;
195 answer_an
= ldns_rr_list_new();
196 if (answer_an
== NULL
)
199 /* authority section */
200 answer_ns
= ldns_rr_list_new();
201 if (answer_ns
== NULL
)
204 /* if we have an ip spoof it there */
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
));
215 ldns_rr_list_push_rr(answer_an
, myrr
);
216 ldns_rdf_deep_free(prev
);
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
));
228 ldns_rr_list_push_rr(answer_ns
, myaurr
);
229 ldns_rdf_deep_free(prev
);
232 snprintf(buf
, sizeof buf
, "%s\t3600\tIN\tSOA\t%s root.%s %s",
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
));
243 ldns_rr_list_push_rr(answer_ns
, myaurr
);
244 ldns_rdf_deep_free(prev
);
248 /* question section */
249 answer_qr
= ldns_rr_list_new();
250 if (answer_qr
== NULL
)
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
)
259 snprintf(buf
, sizeof buf
, "%s\t%d\tIN\tA\t%s",
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
));
269 ldns_rr_list_push_rr(answer_ad
, myasrr
);
270 ldns_rdf_deep_free(prev
);
274 snprintf(buf
, sizeof buf
, "%s\t%d\tIN\tAAAA\t%s",
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
));
284 ldns_rr_list_push_rr(answer_ad
, myasrr
);
285 ldns_rdf_deep_free(prev
);
290 answer_pkt
= ldns_pkt_new();
291 if (answer_pkt
== NULL
)
294 ldns_pkt_set_qr(answer_pkt
, 1);
295 ldns_pkt_set_aa(answer_pkt
, 1);
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");
310 ldns_pkt_free(answer_pkt
);
314 ldns_rr_list_free(answer_qr
);
316 ldns_rr_list_free(answer_an
);
318 ldns_rr_list_free(answer_ns
);
320 ldns_rr_list_free(answer_ad
);