1 /*
2 * ldns-testns. Light-weight DNS daemon, gives canned replies.
3 *
4 * Tiny dns server, that responds with specially crafted replies
5 * to requests. For testing dns software.
6 *
7 * (c) NLnet Labs, 2005 - 2008
8 * See the file LICENSE for the license
9 */
10
11 /*
12 * This program is a debugging aid. It can is not efficient, especially
13 * with a long config file, but it can give any reply to any query.
14 * This can help the developer pre-script replies for queries.
15 *
16 * It listens to IP4 UDP and TCP by default.
17 * You can specify a packet RR by RR with header flags to return.
18 *
19 * Missing features:
20 * - matching content different from reply content.
21 * - find way to adjust mangled packets?
22 */
23
24 /*
25 The data file format is as follows:
26
27 ; comment.
28 ; a number of entries, these are processed first to last.
29 ; a line based format.
30
31 $ORIGIN origin
32 $TTL default_ttl
33
34 ENTRY_BEGIN
35 ; first give MATCH lines, that say what queries are matched
36 ; by this entry.
37 ; 'opcode' makes the query match the opcode from the reply
38 ; if you leave it out, any opcode matches this entry.
39 ; 'qtype' makes the query match the qtype from the reply
40 ; 'qname' makes the query match the qname from the reply
41 ; 'serial=1023' makes the query match if ixfr serial is 1023.
42 MATCH [opcode] [qtype] [qname] [serial=<value>]
43 MATCH [UDP|TCP]
44 MATCH ...
45 ; Then the REPLY header is specified.
46 REPLY opcode, rcode or flags.
47 (opcode) QUERY IQUERY STATUS NOTIFY UPDATE
48 (rcode) NOERROR FORMERR SERVFAIL NXDOMAIN NOTIMPL YXDOMAIN
49 YXRRSET NXRRSET NOTAUTH NOTZONE
50 (flags) QR AA TC RD CD RA AD
51 REPLY ...
52 ; any additional actions to do.
53 ; 'copy_id' copies the ID from the query to the answer.
54 ADJUST copy_id
55 ; 'sleep=10' sleeps for 10 seconds before giving the answer (TCP is open)
56 ADJUST [sleep=<num>] ; sleep before giving any reply
57 ADJUST [packet_sleep=<num>] ; sleep before this packet in sequence
58 SECTION QUESTION
59 <RRs, one per line> ; the RRcount is determined automatically.
60 SECTION ANSWER
61 <RRs, one per line>
62 SECTION AUTHORITY
63 <RRs, one per line>
64 SECTION ADDITIONAL
65 <RRs, one per line>
66 EXTRA_PACKET ; follow with SECTION, REPLY for more packets.
67 HEX_ANSWER_BEGIN ; follow with hex data
68 ; this replaces any answer packet constructed
69 ; with the SECTION keywords (only SECTION QUERY
70 ; is used to match queries). If the data cannot
71 ; be parsed, ADJUST rules for the answer packet
72 ; are ignored
73 HEX_ANSWER_END
74 ENTRY_END
75 */
76
77 /* Example data file:
78 $ORIGIN nlnetlabs.nl
79 $TTL 3600
80
81 ENTRY_BEGIN
82 MATCH qname
83 REPLY NOERROR
84 ADJUST copy_id
85 SECTION QUESTION
86 www.nlnetlabs.nl. IN A
87 SECTION ANSWER
88 www.nlnetlabs.nl. IN A 195.169.215.155
89 SECTION AUTHORITY
90 nlnetlabs.nl. IN NS www.nlnetlabs.nl.
91 ENTRY_END
92
93 ENTRY_BEGIN
94 MATCH qname
95 REPLY NOERROR
96 ADJUST copy_id
97 SECTION QUESTION
98 www2.nlnetlabs.nl. IN A
99 HEX_ANSWER_BEGIN
100 ; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
101 ;-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
102 00 bf 81 80 00 01 00 01 00 02 00 02 03 77 77 77 0b 6b 61 6e ; 1- 20
103 61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 01 00 01 03 77 77 ; 21- 40
104 77 0b 6b 61 6e 61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 01 ; 41- 60
105 00 01 00 01 50 8b 00 04 52 5e ed 32 0b 6b 61 6e 61 72 69 65 ; 61- 80
106 70 69 65 74 03 63 6f 6d 00 00 02 00 01 00 01 50 8b 00 11 03 ; 81- 100
107 6e 73 31 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 0b 6b 61 6e ; 101- 120
108 61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 02 00 01 00 01 50 ; 121- 140
109 8b 00 11 03 6e 73 32 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 ; 141- 160
110 03 6e 73 31 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 00 01 00 ; 161- 180
111 01 00 00 46 53 00 04 52 5e ed 02 03 6e 73 32 08 68 65 78 6f ; 181- 200
112 6e 2d 69 73 02 6e 6c 00 00 01 00 01 00 00 46 53 00 04 d4 cc ; 201- 220
113 db 5b
114 HEX_ANSWER_END
115 ENTRY_END
116
117
118 */
119
120 struct sockaddr_storage;
121 #include "config.h"
122 #include <ldns/ldns.h>
123 #include "ldns-testpkts.h"
124
125 #ifdef HAVE_SYS_SOCKET_H
126 #include <sys/socket.h>
127 #endif
128 #ifdef HAVE_TIME_H
129 #include <time.h>
130 #endif
131 #ifdef HAVE_SYS_TIME_H
132 #include <sys/time.h>
133 #endif
134 #ifdef HAVE_SYS_SELECT_H
135 #include <sys/select.h>
136 #endif
137 #ifdef HAVE_ARPA_INET_H
138 #include <arpa/inet.h>
139 #endif
140 #ifdef HAVE_NETINET_IN_H
141 #include <netinet/in.h>
142 #endif
143 #ifdef HAVE_NETINET_UDP_H
144 #include <netinet/udp.h>
145 #endif
146 #ifdef HAVE_NETINET_IGMP_H
147 #include <netinet/igmp.h>
148 #endif
149 #include <errno.h>
150 #include <signal.h>
151
152 #ifdef HAVE_TARGETCONDITIONALS_H
153 #include <TargetConditionals.h>
154 #endif
155
156 #if defined(TARGET_OS_TV) || defined(TARGET_OS_WATCH)
157 #undef HAVE_FORK
158 #endif
159
160 #define INBUF_SIZE 4096 /* max size for incoming queries */
161 #define DEFAULT_PORT 53 /* default if no -p port is specified */
162 #define CONN_BACKLOG 256 /* connections queued up for tcp */
163 static const char* prog_name = "ldns-testns";
164 static FILE* logfile = 0;
165 static int do_verbose = 0;
166
usage(void)167 static void usage(void)
168 {
169 printf("Usage: %s [options] <datafile>\n", prog_name);
170 printf(" -r listens on random port. Port number is printed.\n");
171 printf(" -p listens on the specified port, default %d.\n", DEFAULT_PORT);
172 printf(" -f forks given number extra instances, default none.\n");
173 printf(" -v more verbose, prints queries, answers and matching.\n");
174 printf(" -6 listen on IP6 any address, instead of IP4 any address.\n");
175 printf("The program answers queries with canned replies from the datafile.\n");
176 exit(EXIT_FAILURE);
177 }
178
log_msg(const char * msg,...)179 static void log_msg(const char* msg, ...)
180 {
181 va_list args;
182 va_start(args, msg);
183 vfprintf(logfile, msg, args);
184 fflush(logfile);
185 va_end(args);
186 }
187
error(const char * msg,...)188 static void error(const char* msg, ...)
189 {
190 va_list args;
191 va_start(args, msg);
192 fprintf(logfile, "%s error: ", prog_name);
193 vfprintf(logfile, msg, args);
194 fprintf(logfile, "\n");
195 fflush(logfile);
196 va_end(args);
197 exit(EXIT_FAILURE);
198 }
199
200 void verbose(int lvl, const char* msg, ...) ATTR_FORMAT(printf, 2, 3);
verbose(int ATTR_UNUSED (lvl),const char * msg,...)201 void verbose(int ATTR_UNUSED(lvl), const char* msg, ...)
202 {
203 va_list args;
204 va_start(args, msg);
205 if(do_verbose)
206 vfprintf(logfile, msg, args);
207 fflush(logfile);
208 va_end(args);
209 }
210
bind_port(int sock,int port,int fam)211 static int bind_port(int sock, int port, int fam)
212 {
213 struct sockaddr_in addr;
214 #if defined(AF_INET6) && defined(HAVE_GETADDRINFO)
215 if(fam == AF_INET6) {
216 struct sockaddr_in6 addr6;
217 memset(&addr6, 0, sizeof(addr6));
218 addr6.sin6_family = AF_INET6;
219 addr6.sin6_port = (in_port_t)htons((uint16_t)port);
220 # if HAVE_DECL_IN6ADDR_ANY
221 addr6.sin6_addr = in6addr_any;
222 # else
223 memset(&addr6.sin6_addr, 0, sizeof(addr6.sin6_addr));
224 # endif
225 return bind(sock, (struct sockaddr *)&addr6, (socklen_t) sizeof(addr6));
226 }
227 #endif
228
229 #ifndef S_SPLINT_S
230 addr.sin_family = AF_INET;
231 #endif
232 addr.sin_port = (in_port_t)htons((uint16_t)port);
233 addr.sin_addr.s_addr = INADDR_ANY;
234 return bind(sock, (struct sockaddr *)&addr, (socklen_t) sizeof(addr));
235 }
236
237 struct handle_udp_userdata {
238 int udp_sock;
239 struct sockaddr_storage addr_him;
240 socklen_t hislen;
241 };
242 static void
send_udp(uint8_t * buf,size_t len,void * data)243 send_udp(uint8_t* buf, size_t len, void* data)
244 {
245 struct handle_udp_userdata *userdata = (struct handle_udp_userdata*)data;
246 /* udp send reply */
247 ssize_t nb;
248 nb = sendto(userdata->udp_sock, (void*)buf, len, 0,
249 (struct sockaddr*)&userdata->addr_him, userdata->hislen);
250 if(nb == -1)
251 log_msg("sendto(): %s\n", strerror(errno));
252 else if((size_t)nb != len)
253 log_msg("sendto(): only sent %d of %d octets.\n",
254 (int)nb, (int)len);
255 }
256
257 static void
handle_udp(int udp_sock,struct entry * entries,int * count)258 handle_udp(int udp_sock, struct entry* entries, int *count)
259 {
260 ssize_t nb;
261 uint8_t inbuf[INBUF_SIZE];
262 struct handle_udp_userdata userdata;
263 userdata.udp_sock = udp_sock;
264
265 userdata.hislen = (socklen_t)sizeof(userdata.addr_him);
266 /* udp recv */
267 nb = recvfrom(udp_sock, (void*)inbuf, INBUF_SIZE, 0,
268 (struct sockaddr*)&userdata.addr_him, &userdata.hislen);
269 if (nb < 1) {
270 #ifndef USE_WINSOCK
271 log_msg("recvfrom(): %s\n", strerror(errno));
272 #else
273 if(WSAGetLastError() != WSAEINPROGRESS &&
274 WSAGetLastError() != WSAECONNRESET &&
275 WSAGetLastError()!= WSAEWOULDBLOCK)
276 log_msg("recvfrom(): %d\n", WSAGetLastError());
277 #endif
278 return;
279 }
280 handle_query(inbuf, nb, entries, count, transport_udp, send_udp,
281 &userdata, do_verbose?logfile:0);
282 }
283
284 static int
read_n_bytes(int sock,uint8_t * buf,size_t sz)285 read_n_bytes(int sock, uint8_t* buf, size_t sz)
286 {
287 size_t count = 0;
288 while(count < sz) {
289 ssize_t nb = recv(sock, (void*)(buf+count), sz-count, 0);
290 if(nb < 0) {
291 log_msg("recv(): %s\n", strerror(errno));
292 return -1;
293 } else if(nb == 0) {
294 log_msg("recv: remote end closed the channel\n");
295 return sz-count;
296 }
297 count += nb;
298 }
299 return 0;
300 }
301
302 static void
write_n_bytes(int sock,uint8_t * buf,size_t sz)303 write_n_bytes(int sock, uint8_t* buf, size_t sz)
304 {
305 size_t count = 0;
306 while(count < sz) {
307 ssize_t nb = send(sock, (void*)(buf+count), sz-count, 0);
308 if(nb < 0) {
309 log_msg("send(): %s\n", strerror(errno));
310 return;
311 }
312 count += nb;
313 }
314 }
315
316 struct handle_tcp_userdata {
317 int s;
318 };
319 static void
send_tcp(uint8_t * buf,size_t len,void * data)320 send_tcp(uint8_t* buf, size_t len, void* data)
321 {
322 struct handle_tcp_userdata *userdata = (struct handle_tcp_userdata*)data;
323 uint16_t tcplen;
324 /* tcp send reply */
325 tcplen = htons(len);
326 write_n_bytes(userdata->s, (uint8_t*)&tcplen, sizeof(tcplen));
327 write_n_bytes(userdata->s, buf, len);
328 }
329
330 static void
handle_tcp(int tcp_sock,struct entry * entries,int * count)331 handle_tcp(int tcp_sock, struct entry* entries, int *count)
332 {
333 int s;
334 struct sockaddr_storage addr_him;
335 socklen_t hislen;
336 uint8_t inbuf[INBUF_SIZE];
337 uint16_t tcplen = 0;
338 struct handle_tcp_userdata userdata;
339
340 /* accept */
341 hislen = (socklen_t)sizeof(addr_him);
342 if((s = accept(tcp_sock, (struct sockaddr*)&addr_him, &hislen)) < 0) {
343 log_msg("accept(): %s\n", strerror(errno));
344 return;
345 }
346 userdata.s = s;
347
348 while(1) {
349 /* tcp recv */
350 if (read_n_bytes(s, (uint8_t*)&tcplen, sizeof(tcplen))) {
351 #ifndef USE_WINSOCK
352 close(s);
353 #else
354 closesocket(s);
355 #endif
356 return;
357 }
358 tcplen = ntohs(tcplen);
359 if(tcplen >= INBUF_SIZE) {
360 log_msg("query %d bytes too large, buffer %d bytes.\n",
361 tcplen, INBUF_SIZE);
362 #ifndef USE_WINSOCK
363 close(s);
364 #else
365 closesocket(s);
366 #endif
367 return;
368 }
369 if (read_n_bytes(s, inbuf, tcplen)) {
370 #ifndef USE_WINSOCK
371 close(s);
372 #else
373 closesocket(s);
374 #endif
375 return;
376 }
377
378 handle_query(inbuf, (ssize_t) tcplen, entries, count, transport_tcp,
379 send_tcp, &userdata, do_verbose?logfile:0);
380
381 /* another query straight away? */
382 if(1) {
383 fd_set rset;
384 struct timeval tv;
385 int ret;
386 FD_ZERO(&rset);
387 FD_SET(s, &rset);
388 tv.tv_sec = 0;
389 tv.tv_usec = 100*1000;
390 ret = select(s+1, &rset, NULL, NULL, &tv);
391 if(ret < 0) {
392 error("select(): %s\n", strerror(errno));
393 }
394 if(ret == 0) {
395 /* timeout */
396 break;
397 }
398 }
399 }
400 #ifndef USE_WINSOCK
401 close(s);
402 #else
403 closesocket(s);
404 #endif
405
406 }
407
408 /** shared by the service and main routine (forked and threaded) */
409 static int udp_sock, tcp_sock;
410 static struct entry* entries;
411
412 /**
413 * Test DNS server service, uses global udpsock, tcpsock, reply entries
414 * The signature is kept void so the function can be used as a thread function.
415 */
416 static void
service(void)417 service(void)
418 {
419 fd_set rset, wset, eset;
420 int count;
421 int maxfd;
422
423 /* service */
424 count = 0;
425 while (1) {
426 #ifndef S_SPLINT_S
427 FD_ZERO(&rset);
428 FD_ZERO(&wset);
429 FD_ZERO(&eset);
430 FD_SET(udp_sock, &rset);
431 FD_SET(tcp_sock, &rset);
432 #endif
433 maxfd = udp_sock;
434 if(tcp_sock > maxfd)
435 maxfd = tcp_sock;
436 if(select(maxfd+1, &rset, &wset, &eset, NULL) < 0) {
437 error("select(): %s\n", strerror(errno));
438 }
439 if(FD_ISSET(udp_sock, &rset)) {
440 handle_udp(udp_sock, entries, &count);
441 }
442 if(FD_ISSET(tcp_sock, &rset)) {
443 handle_tcp(tcp_sock, entries, &count);
444 }
445 }
446 }
447
448 static void
forkit(int number)449 forkit(int number)
450 {
451 int i;
452 for(i=0; i<number; i++)
453 {
454 #if !defined(HAVE_FORK) || !defined(HAVE_FORK_AVAILABLE)
455 #ifndef USE_WINSOCK
456 log_msg("fork() not available.\n");
457 exit(1);
458 #else /* USE_WINSOCK */
459 DWORD tid;
460 HANDLE id = CreateThread(NULL, 0,
461 (LPTHREAD_START_ROUTINE)service, NULL,
462 0, &tid);
463 if(id == NULL) {
464 log_msg("error CreateThread: %d\n", GetLastError());
465 return;
466 }
467 log_msg("thread id: %d\n", (int)tid);
468 #endif /* USE_WINSOCK */
469 #else /* HAVE_FORK */
470 pid_t pid = fork();
471 if(pid == (pid_t) -1) {
472 log_msg("error forking: %s\n", strerror(errno));
473 return;
474 }
475 if(pid == 0)
476 return; /* child starts serving */
477 log_msg("forked pid: %d\n", (int)pid);
478 #endif /* HAVE_FORK */
479 }
480 }
481
482 int
main(int argc,char ** argv)483 main(int argc, char **argv)
484 {
485 /* arguments */
486 int c;
487 int port = DEFAULT_PORT;
488 const char* datafile;
489 int forknum = 0;
490
491 /* network */
492 int fam = AF_INET;
493 bool random_port_success;
494
495 #ifdef USE_WINSOCK
496 WSADATA wsa_data;
497 #endif
498
499 /* parse arguments */
500 srandom(time(NULL) ^ getpid());
501 logfile = stdout;
502 prog_name = argv[0];
503 log_msg("%s: start\n", prog_name);
504 while((c = getopt(argc, argv, "6f:p:rv")) != -1) {
505 switch(c) {
506 case '6':
507 #ifdef AF_INET6
508 fam = AF_INET6;
509 #else
510 log_msg("cannot -6: no IP6 available\n");
511 exit(1);
512 #endif
513 break;
514 case 'r':
515 port = 0;
516 break;
517 case 'f':
518 forknum = atoi(optarg);
519 if(forknum < 1)
520 error("invalid forkno %s, give number", optarg);
521 break;
522 case 'p':
523 port = atoi(optarg);
524 if (port < 1) {
525 error("Invalid port %s, use a number.", optarg);
526 }
527 break;
528 case 'v':
529 do_verbose++;
530 break;
531 default:
532 usage();
533 break;
534 }
535 }
536 argc -= optind;
537 argv += optind;
538
539 if(argc == 0 || argc > 1)
540 usage();
541
542 datafile = argv[0];
543 log_msg("Reading datafile %s\n", datafile);
544 entries = read_datafile(datafile, 0);
545
546 #ifdef SIGPIPE
547 (void)signal(SIGPIPE, SIG_IGN);
548 #endif
549 #ifdef USE_WINSOCK
550 if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0)
551 error("WSAStartup failed\n");
552 #endif
553
554 if((udp_sock = socket(fam, SOCK_DGRAM, 0)) < 0) {
555 error("udp socket(): %s\n", strerror(errno));
556 }
557 if((tcp_sock = socket(fam, SOCK_STREAM, 0)) < 0) {
558 error("tcp socket(): %s\n", strerror(errno));
559 }
560 c = 1;
561 if(setsockopt(tcp_sock, SOL_SOCKET, SO_REUSEADDR, (void*)&c, (socklen_t) sizeof(int)) < 0) {
562 error("setsockopt(SO_REUSEADDR): %s\n", strerror(errno));
563 }
564
565 /* bind ip4 */
566 if (port > 0) {
567 if (bind_port(udp_sock, port, fam)) {
568 error("cannot bind(): %s\n", strerror(errno));
569 }
570 if (bind_port(tcp_sock, port, fam)) {
571 error("cannot bind(): %s\n", strerror(errno));
572 }
573 if (listen(tcp_sock, CONN_BACKLOG) < 0) {
574 error("listen(): %s\n", strerror(errno));
575 }
576 } else {
577 random_port_success = false;
578 while (!random_port_success) {
579 port = (random() % 64510) + 1025;
580 log_msg("trying to bind to port %d\n", port);
581 random_port_success = true;
582 if (bind_port(udp_sock, port, fam)) {
583 #ifdef EADDRINUSE
584 if (errno != EADDRINUSE) {
585 #elif defined(USE_WINSOCK)
586 if (WSAGetLastError() != WSAEADDRINUSE) {
587 #else
588 if (1) {
589 #endif
590 perror("bind()");
591 return -1;
592 } else {
593 random_port_success = false;
594 }
595 }
596 if (random_port_success) {
597 if (bind_port(tcp_sock, port, fam)) {
598 #ifdef EADDRINUSE
599 if (errno != EADDRINUSE) {
600 #elif defined(USE_WINSOCK)
601 if (WSAGetLastError()!=WSAEADDRINUSE){
602 #else
603 if (1) {
604 #endif
605 perror("bind()");
606 return -1;
607 } else {
608 random_port_success = false;
609 }
610 }
611 }
612 if (random_port_success) {
613 if (listen(tcp_sock, CONN_BACKLOG) < 0) {
614 error("listen(): %s\n", strerror(errno));
615 }
616 }
617
618 }
619 }
620 log_msg("Listening on port %d\n", port);
621
622 /* forky! */
623 if(forknum > 0)
624 forkit(forknum);
625
626 service();
627
628 return 0;
629 }
630