2 * Copyright (C) Jakub Hrozek 2014 <jakub.hrozek@gmail.com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the author nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #include <sys/types.h>
39 #include <sys/socket.h>
42 #include <arpa/inet.h>
43 #include <arpa/nameser.h>
44 #include <netinet/in.h>
60 #define PIDFILE "dns_srv.pid"
71 #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
74 #ifndef discard_const_p
75 #define discard_const_p(type, ptr) ((type *)discard_const(ptr))
79 #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
82 /* The macros below are taken from c-ares */
83 #define DNS__16BIT(p) ((unsigned short)((unsigned int) 0xffff & \
84 (((unsigned int)((unsigned char)(p)[0]) << 8U) | \
85 ((unsigned int)((unsigned char)(p)[1])))))
87 #define DNS__SET16BIT(p, v) (((p)[0] = (unsigned char)(((v) >> 8) & 0xff)), \
88 ((p)[1] = (unsigned char)((v) & 0xff)))
90 #define DNS__SET32BIT(p, v) (((p)[0] = (unsigned char)(((v) >> 24) & 0xff)), \
91 ((p)[1] = (unsigned char)(((v) >> 16) & 0xff)), \
92 ((p)[2] = (unsigned char)(((v) >> 8) & 0xff)), \
93 ((p)[3] = (unsigned char)((v) & 0xff)));
95 /* Macros for parsing a DNS header */
96 #define DNS_HEADER_QID(h) DNS__16BIT(h)
97 #define DNS_HEADER_OPCODE(h) (((h)[2] >> 3) & 0xf)
98 #define DNS_HEADER_TC(h) (((h)[2] >> 1) & 0x1)
99 #define DNS_HEADER_QDCOUNT(h) DNS__16BIT((h) + 4)
101 /* Macros for parsing the fixed part of a DNS question */
102 #define DNS_QUESTION_TYPE(q) DNS__16BIT(q)
103 #define DNS_QUESTION_CLASS(q) DNS__16BIT((q) + 2)
105 /* Macros for constructing a DNS header */
106 #define DNS_HEADER_SET_QID(h, v) DNS__SET16BIT(h, v)
107 #define DNS_HEADER_SET_QR(h, v) ((h)[2] |= (unsigned char)(((v) & 0x1) << 7))
108 #define DNS_HEADER_SET_RD(h, v) ((h)[2] |= (unsigned char)((v) & 0x1))
109 #define DNS_HEADER_SET_RA(h, v) ((h)[3] |= (unsigned char)(((v) & 0x1) << 7))
110 #define DNS_HEADER_SET_QDCOUNT(h, v) DNS__SET16BIT((h) + 4, v)
111 #define DNS_HEADER_SET_ANCOUNT(h, v) DNS__SET16BIT((h) + 6, v)
113 /* Macros for constructing the fixed part of a DNS question */
114 #define DNS_QUESTION_SET_TYPE(q, v) DNS__SET16BIT(q, v)
115 #define DNS_QUESTION_SET_CLASS(q, v) DNS__SET16BIT((q) + 2, v)
117 /* Macros for constructing the fixed part of a DNS resource record */
118 #define DNS_RR_SET_TYPE(r, v) DNS__SET16BIT(r, v)
119 #define DNS_RR_SET_CLASS(r, v) DNS__SET16BIT((r) + 2, v)
120 #define DNS_RR_SET_TTL(r, v) DNS__SET32BIT((r) + 4, v)
121 #define DNS_RR_SET_LEN(r, v) DNS__SET16BIT((r) + 8, v)
123 #define DEFAULT_A_REC "127.0.10.10"
125 struct dns_srv_opts {
139 unsigned char *reply;
143 static void free_dns_query(struct dns_query *query)
147 memset(query, 0, sizeof(struct dns_query));
150 static size_t encode_name(unsigned char *buffer, const char *name)
160 while ((dot = strchr(p, '.')) != NULL) {
168 p = dot + 1; /* move past the dot */
177 static void fake_header(struct dns_query *query)
179 DNS_HEADER_SET_QID(query->reply, query->id);
180 DNS_HEADER_SET_QR(query->reply, 1);
181 DNS_HEADER_SET_RD(query->reply, 1);
182 DNS_HEADER_SET_RA(query->reply, 1);
183 DNS_HEADER_SET_QDCOUNT(query->reply, 1);
184 DNS_HEADER_SET_ANCOUNT(query->reply, 1);
187 static size_t fake_question(struct dns_query *query, unsigned char **pout)
194 len = encode_name(p, query->query);
196 DNS_QUESTION_SET_TYPE(p, query->qtype);
197 len += sizeof(uint16_t);
198 DNS_QUESTION_SET_CLASS(p, query->qclass);
199 len += sizeof(uint16_t);
201 p += 2 * sizeof(uint16_t);
207 static size_t fake_answer(struct dns_query *query, unsigned char **pout)
213 struct in_addr a_rec;
217 len = encode_name(p, query->query);
220 DNS_RR_SET_TYPE(p, query->qtype);
221 len += sizeof(uint16_t);
223 DNS_RR_SET_CLASS(p, query->qclass);
224 len += sizeof(uint16_t);
226 DNS_RR_SET_TTL(p, DFL_TTL);
227 len += sizeof(uint32_t);
229 switch (query->qtype) {
231 val = getenv("RWRAP_TEST_A_REC");
233 val ? val : DEFAULT_A_REC,
235 rlen = sizeof(struct in_addr);
238 /* Unhandled record */
242 DNS_RR_SET_LEN(p, rlen);
243 len += sizeof(uint16_t);
245 /* Move to the RDATA section */
246 p += sizeof(uint16_t) + /* type */
247 sizeof(uint16_t) + /* class */
248 sizeof(uint32_t) + /* ttl */
249 sizeof(uint16_t); /* rlen */
252 memcpy(p, &a_rec, sizeof(struct in_addr));
259 static int fake_reply(struct dns_query *query)
263 query->reply = malloc(BUFSIZE);
264 if (query->reply == NULL) {
268 memset(query->reply, 0, BUFSIZE);
272 query->reply_len = NS_HFIXEDSZ;
275 /* advances p internally */
276 query->reply_len += fake_question(query, &p);
277 query->reply_len += fake_answer(query, &p);
282 static char *extract_name(char **buffer, size_t maxlen)
284 char *query, *qp, *bp;
288 query = malloc(maxlen);
289 if (query == NULL) return NULL;
298 if (len > (maxlen - (qp - query))) {
299 /* label is past the buffer */
304 for (i = 0; i < len; i++) {
319 static int parse_query(unsigned char *buffer,
321 struct dns_query *query)
327 if (len < NS_HFIXEDSZ) {
328 /* Message too short */
332 if (DNS_HEADER_OPCODE(p) != 0) {
333 /* Queries must have the opcode set to 0 */
337 if (DNS_HEADER_QDCOUNT(p) != 1) {
338 /* We only support one query */
342 if (len < NS_HFIXEDSZ + 2 * sizeof(uint16_t)) {
343 /* No room for class and type */
347 /* Need to remember the query to respond with the same */
348 query->id = DNS_HEADER_QID(p);
350 /* Done with the header, move past it */
352 query->query = extract_name((char **) &p, len - NS_HFIXEDSZ);
353 if (query->query == NULL) {
357 query->qclass = DNS_QUESTION_CLASS(p);
358 if (query->qclass != ns_c_in) {
359 /* We only support Internet queries */
363 query->qtype = DNS_QUESTION_TYPE(p);
367 static void dns(int sock)
369 struct sockaddr_storage css;
370 socklen_t addrlen = sizeof(css);
372 unsigned char buf[BUFSIZE];
373 struct dns_query query;
379 free_dns_query(&query);
381 /* for advanced features, use recvmsg here */
383 bret = recvfrom(sock, buf, BUFSIZE, 0,
384 (struct sockaddr *) &css, &addrlen);
391 rv = parse_query(buf, bret, &query);
396 /* Construct the reply */
397 rv = fake_reply(&query);
402 /* send reply back */
403 bret = sendto(sock, query.reply, query.reply_len, 0,
404 (struct sockaddr *) &css, addrlen);
412 static int pidfile(const char *path)
416 char pid_str[32] = { 0 };
420 fd = open(path, O_RDONLY, 0644);
425 } else if (err != ENOENT) {
429 fd = open(path, O_CREAT | O_WRONLY | O_EXCL, 0644);
435 snprintf(pid_str, sizeof(pid_str) -1, "%u\n", (unsigned int) getpid());
436 len = strlen(pid_str);
438 nwritten = write(fd, pid_str, len);
440 if (nwritten != (ssize_t)len) {
447 static int become_daemon(void)
454 if (getppid() == 1) {
459 if (child_pid == -1) {
463 } else if (child_pid > 0) {
467 /* If a working directory was defined, go there */
479 for (fd = getdtablesize(); fd >= 0; --fd) {
483 for (i = 0; i < 3; i++) {
484 fd = open("/dev/null", O_RDWR, 0);
486 fd = open("/dev/null", O_WRONLY, 0);
490 perror("Can't open /dev/null");
494 perror("Didn't get correct fd");
505 * Returns 0 on success, errno on failure.
506 * If successful, sock is a ready to use socket.
508 static int setup_srv(struct dns_srv_opts *opts, int *_sock)
510 struct addrinfo hints;
511 struct addrinfo *res, *ri;
516 memset(&hints, 0, sizeof(hints));
517 hints.ai_family = AF_UNSPEC;
518 hints.ai_socktype = SOCK_DGRAM;
519 hints.ai_flags = AI_PASSIVE;
521 snprintf(svc, sizeof(svc), "%d", opts->port);
523 ret = getaddrinfo(opts->bind, svc, &hints, &res);
528 for (ri = res; ri != NULL; ri = ri->ai_next) {
529 sock = socket(ri->ai_family, ri->ai_socktype, ri->ai_protocol);
537 ret = bind(sock, ri->ai_addr, ri->ai_addrlen);
547 fprintf(stderr, "Could not bind\n");
555 int main(int argc, char **argv)
559 struct dns_srv_opts opts;
562 static struct option long_options[] = {
563 { discard_const_p(char, "bind-addr"), required_argument, 0, 'b' },
564 { discard_const_p(char, "daemon"), no_argument, 0, 'D' },
565 { discard_const_p(char, "port"), required_argument, 0, 'p' },
566 { discard_const_p(char, "pid"), required_argument, 0, 0 },
571 opts.pidfile = PIDFILE;
573 opts.port = DNS_PORT;
575 while ((opt = getopt_long(argc, argv, "Db:p:",
576 long_options, &optindex)) != -1)
581 opts.pidfile = optarg;
591 opts.port = atoi(optarg);
594 fprintf(stderr, "Usage: %s [-p port] [-b bind_addr] "
595 "[-D] [--pid pidfile]\n"
596 "-D tells the server to become a "
597 "deamon and write a PIDfile\n"
598 "The default PIDfile is '%s' "
599 "in the current directory\n",
607 ret = become_daemon();
609 fprintf(stderr, "Cannot become daemon: %s\n",
615 ret = setup_srv(&opts, &sock);
617 fprintf(stderr, "Cannot setup server: %s\n", strerror(ret));
622 if (opts.pidfile == NULL) {
623 fprintf(stderr, "Error: pidfile == NULL\n");
628 ret = pidfile(opts.pidfile);
630 fprintf(stderr, "Cannot create pidfile %s: %s\n",
631 opts.pidfile, strerror(ret));
640 unlink(opts.pidfile);