Codebase list massdns / 7f02cb6
New upstream version 1.0.0 Steev Klimaszewski 1 year, 6 months ago
42 changed file(s) with 5670 addition(s) and 5623 deletion(s). Raw diff Collapse all Expand all
22
33 set(CMAKE_C_STANDARD 11)
44
5 set(SOURCE_FILES main.c module.h list.h hashmap.h massdns.h security.h mixed_list.h net.h string.h buffers.h dns.h
6 timed_ring.h random.h cmd.h flow.h)
7 add_executable(massdns ${SOURCE_FILES})
5 set(SOURCE_FILES src/main.c src/list.h src/hashmap.h src/massdns.h src/security.h src/net.h src/string.h src/buffers.h src/dns.h
6 src/timed_ring.h src/random.h src/cmd.h src/flow.h)
7 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
8 add_executable(massdns ${SOURCE_FILES})
0 FROM ubuntu:16.04
1 LABEL maintainer Aditya Gujar (@aditya_gujar)
0 FROM alpine:edge
21
3 RUN apt-get update
4
5 RUN apt-get install -y libldns-dev git build-essential
6
7 RUN apt-get install -y python
8
9 RUN git clone https://github.com/blechschmidt/massdns.git
2 RUN apk --update --no-cache --virtual .build-deps add git build-base \
3 && git clone --depth=1 https://github.com/blechschmidt/massdns.git \
4 && cd massdns && make && apk del .build-deps
105
116 WORKDIR /massdns/
127
13 RUN make
14
158 ENTRYPOINT ["./bin/massdns"]
0
1
20 GNU GENERAL PUBLIC LICENSE
31 Version 3, 29 June 2007
42
5 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
3 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
64 Everyone is permitted to copy and distribute verbatim copies
75 of this license document, but changing it is not allowed.
86
632630 state the exclusion of warranty; and each file should have at least
633631 the "copyright" line and a pointer to where the full notice is found.
634632
635 {one line to give the program's name and a brief idea of what it does.}
636 Copyright (C) {year} {name of author}
633 <one line to give the program's name and a brief idea of what it does.>
634 Copyright (C) <year> <name of author>
637635
638636 This program is free software: you can redistribute it and/or modify
639637 it under the terms of the GNU General Public License as published by
646644 GNU General Public License for more details.
647645
648646 You should have received a copy of the GNU General Public License
649 along with this program. If not, see <http://www.gnu.org/licenses/>.
647 along with this program. If not, see <https://www.gnu.org/licenses/>.
650648
651649 Also add information on how to contact you by electronic and paper mail.
652650
653651 If the program does terminal interaction, make it output a short
654652 notice like this when it starts in an interactive mode:
655653
656 {project} Copyright (C) {year} {fullname}
654 <program> Copyright (C) <year> <name of author>
657655 This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
658656 This is free software, and you are welcome to redistribute it
659657 under certain conditions; type `show c' for details.
665663 You should also get your employer (if you work as a programmer) or school,
666664 if any, to sign a "copyright disclaimer" for the program, if necessary.
667665 For more information on this, and how to apply and follow the GNU GPL, see
668 <http://www.gnu.org/licenses/>.
666 <https://www.gnu.org/licenses/>.
669667
670668 The GNU General Public License does not permit incorporating your program
671669 into proprietary programs. If your program is a subroutine library, you
672670 may consider it more useful to permit linking proprietary applications with
673671 the library. If this is what you want to do, use the GNU Lesser General
674672 Public License instead of this License. But first, please read
675 <http://www.gnu.org/philosophy/why-not-lgpl.html>.
676
677 Copy license text to clipboard
678 How to apply this license
679
680 Create a text file (typically named LICENSE or LICENSE.txt) in the root of your source code and copy the text of the license into the file.
681
682 Note: The Free Software Foundation recommends taking the additional step of adding a boilerplate notice to the top of each file. The boilerplate can be found at the end of the license.
683 Source
684 Required
685
686 Disclose Source
687 License and copyright notice
688 State Changes
689
690 Permitted
691
692 Commercial Use
693 Distribution
694 Modification
695 Patent Grant
696 Private Use
697
698 Forbidden
699
700 Hold Liable
701 Sublicensing
702
703
673 <https://www.gnu.org/licenses/why-not-lgpl.html>.
11
22 all:
33 mkdir -p bin
4 $(CC) $(CFLAGS) -O3 -std=c11 -DHAVE_EPOLL -DHAVE_SYSINFO -Wall -fstack-protector-strong main.c -o bin/massdns
4 $(CC) $(CFLAGS) -O3 -std=c11 -DHAVE_EPOLL -DHAVE_SYSINFO -Wall -fstack-protector-strong src/main.c -o bin/massdns
55 debug:
66 mkdir -p bin
7 $(CC) $(CFLAGS) -O0 -std=c11 -DHAVE_EPOLL -DHAVE_SYSINFO -Wall -g -DDEBUG main.c -o bin/massdns
7 $(CC) $(CFLAGS) -O0 -std=c11 -DHAVE_EPOLL -DHAVE_SYSINFO -Wall -g -DDEBUG src/main.c -o bin/massdns
88 nolinux:
99 mkdir -p bin
10 $(CC) $(CFLAGS) -O3 -std=c11 -Wall -fstack-protector-strong main.c -o bin/massdns
10 $(CC) $(CFLAGS) -O3 -std=c11 -Wall -fstack-protector-strong src/main.c -o bin/massdns
1111 debugnolinux:
1212 mkdir -p bin
13 $(CC) $(CFLAGS) -O0 -std=c11 -Wall -fstack-protector-strong -g -DDEBUG main.c -o bin/massdns
13 $(CC) $(CFLAGS) -O0 -std=c11 -Wall -fstack-protector-strong -g -DDEBUG src/main.c -o bin/massdns
1414 install:
1515 test -d $(PREFIX) || mkdir $(PREFIX)
1616 test -d $(PREFIX)/bin || mkdir $(PREFIX)/bin
2222 -c --resolve-count Number of resolves for a name before giving up. (Default: 50)
2323 --drop-group Group to drop privileges to when running as root. (Default: nogroup)
2424 --drop-user User to drop privileges to when running as root. (Default: nobody)
25 --filter Only output packets with the specified response code.
2526 --flush Flush the output file whenever a response was received.
2627 -h --help Show this help.
28 --ignore Do not output packets with the specified response code.
2729 -i --interval Interval in milliseconds to wait between multiple resolves of the same
2830 domain. (Default: 500)
2931 -l --error-log Error log file path. (Default: /dev/stderr)
5860 m - Only output reply records that match the question name.
5961 n - Include records from the answer section.
6062 q - Print the question.
61 r - Prepend resolver IP address, Unix timestamp and return code to the question line.
63 r - Print the question with resolver IP address, Unix timestamp and return code prepended.
6264 s - Separate packet sections using a line feed.
6365 t - Include TTL and record class within the output.
6466 u - Include records from the authority section.
+0
-14
buffers.h less more
0 #ifndef INC_BUFFERS
1 #define INC_BUFFERS
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6
7 typedef struct buffer
8 {
9 void *data;
10 size_t len;
11 } buffer_t;
12
13 #endif
+0
-30
cmd.h less more
0 #include "massdns.h"
1
2 #ifndef MASSDNS_CMD_H
3 #define MASSDNS_CMD_H
4
5 void expect_arg(int i)
6 {
7 if (i + 1 >= context.cmd_args.argc)
8 {
9 fprintf(stderr, "Missing argument value for %s.\n", context.cmd_args.argv[i]);
10 context.cmd_args.help_function();
11 exit(1);
12 }
13 }
14
15 unsigned long long expect_arg_nonneg(int i, unsigned long long min, unsigned long long max)
16 {
17 expect_arg(i);
18 char *endptr;
19 unsigned long long result = strtoull(context.cmd_args.argv[i + 1], &endptr, 10);
20 if(*endptr != 0 || result < min || result > max)
21 {
22 fprintf(stderr, "The argument %s requires a value between %llu and %llu.\n",
23 context.cmd_args.argv[i], min, max);
24 exit(1);
25 }
26 return result;
27 }
28
29 #endif
+0
-1530
dns.h less more
0 #ifndef MASSRESOLVER_DNS_H
1 #define MASSRESOLVER_DNS_H
2
3 #include <stdlib.h>
4 #include <stdbool.h>
5 #include <stdint.h>
6 #include <strings.h>
7 #include <string.h>
8 #include <inttypes.h>
9 #include <ctype.h>
10
11 #define min(a, b) ((a) < (b) ? (a) : (b))
12 #define max(a, b) ((a) > (b) ? (a) : (b))
13 #define elements(a) (sizeof(a) / sizeof((a)[0]))
14
15 typedef enum
16 {
17 DNS_REC_INVALID = -1, // Error code
18
19 DNS_REC_A = 1,
20 DNS_REC_AAAA = 28,
21 DNS_REC_AFSDB = 18,
22 DNS_REC_ANY = 255,
23 DNS_REC_APL = 42,
24 DNS_REC_CAA = 257,
25 DNS_REC_CDNSKEY = 60,
26 DNS_REC_CDS = 59,
27 DNS_REC_CERT = 37,
28 DNS_REC_CNAME = 5,
29 DNS_REC_DHCID = 49,
30 DNS_REC_DLV = 32769,
31 DNS_REC_DNAME = 39,
32 DNS_REC_DNSKEY = 48,
33 DNS_REC_DS = 43,
34 DNS_REC_HIP = 55,
35 DNS_REC_IPSECKEY = 45,
36 DNS_REC_KEY = 25,
37 DNS_REC_KX = 36,
38 DNS_REC_LOC = 29,
39 DNS_REC_MX = 15,
40 DNS_REC_NAPTR = 35,
41 DNS_REC_NS = 2,
42 DNS_REC_NSEC = 47,
43 DNS_REC_NSEC3 = 50,
44 DNS_REC_NSEC3PARAM = 51,
45 DNS_REC_OPENPGPKEY = 61,
46 DNS_REC_PTR = 12,
47 DNS_REC_RP = 17,
48 DNS_REC_RRSIG = 46,
49 DNS_REC_SIG = 24,
50 DNS_REC_SOA = 6,
51 DNS_REC_SRV = 33,
52 DNS_REC_SSHFP = 44,
53 DNS_REC_TA = 32768,
54 DNS_REC_TKEY = 249,
55 DNS_REC_TLSA = 52,
56 DNS_REC_TSIG = 250,
57 DNS_REC_TXT = 16,
58 DNS_REC_URI = 256
59 } dns_record_type;
60
61 typedef enum
62 {
63 DNS_SECTION_QUESTION = 0,
64 DNS_SECTION_ANSWER = 1,
65 DNS_SECTION_AUTHORITY = 2,
66 DNS_SECTION_ADDITIONAL = 3
67 } dns_section_t;
68
69 dns_record_type dns_str_to_record_type(const char *str)
70 {
71 // Performance is important here because we may want to use this when reading
72 // large numbers of DNS queries from a file.
73
74 switch (tolower(str[0]))
75 {
76 case 'a':
77 switch (tolower(str[1]))
78 {
79 case 0:
80 return DNS_REC_A;
81 case 'a':
82 if (tolower(str[2]) == 'a' && tolower(str[3]) == 'a' && str[4] == 0)
83 {
84 return DNS_REC_AAAA;
85 }
86 return DNS_REC_INVALID;
87 case 'f':
88 if (tolower(str[2]) == 's' && tolower(str[3]) == 'd' && tolower(str[4]) == 'b' && str[5] == 0)
89 {
90 return DNS_REC_AFSDB;
91 }
92 return DNS_REC_INVALID;
93 case 'n':
94 if (tolower(str[2]) == 'y' && str[3] == 0)
95 {
96 return DNS_REC_ANY;
97 }
98 return DNS_REC_INVALID;
99 case 'p':
100 if (tolower(str[2]) == 'l' && str[3] == 0)
101 {
102 return DNS_REC_APL;
103 }
104 return DNS_REC_INVALID;
105 default:
106 return DNS_REC_INVALID;
107 }
108 case 'c':
109 switch (tolower(str[1]))
110 {
111 case 'a':
112 if (tolower(str[2]) == 'a' && str[3] == 0)
113 {
114 return DNS_REC_CAA;
115 }
116 return DNS_REC_INVALID;
117 case 'd':
118 switch(tolower(str[2]))
119 {
120 case 's':
121 if(str[3] == 0)
122 {
123 return DNS_REC_CDS;
124 }
125 return DNS_REC_INVALID;
126 case 'n':
127 if(tolower(str[3]) == 's' && tolower(str[4]) == 'k' && tolower(str[5]) == 'e'
128 && tolower(str[6]) == 'y' && str[7] == 0)
129 {
130 return DNS_REC_CDNSKEY;
131 }
132 default:
133 return DNS_REC_INVALID;
134 }
135 case 'e':
136 if(tolower(str[2]) == 'r' && tolower(str[3]) == 't' && str[4] == 0)
137 {
138 return DNS_REC_CERT;
139 }
140 return DNS_REC_INVALID;
141 case 'n':
142 if(tolower(str[2]) == 'a' && tolower(str[3]) == 'm' && tolower(str[4]) == 'e' && str[5] == 0)
143 {
144 return DNS_REC_CNAME;
145 }
146 return DNS_REC_INVALID;
147 default:
148 return DNS_REC_INVALID;
149 }
150 case 'd':
151 switch (tolower(str[1]))
152 {
153 case 'h':
154 if(tolower(str[2]) == 'c' && tolower(str[3]) == 'i' && tolower(str[4]) == 'd' && str[5] == 0)
155 {
156 return DNS_REC_DHCID;
157 }
158 return DNS_REC_INVALID;
159 case 'l':
160 if(tolower(str[2]) == 'v' && str[3] == 0)
161 {
162 return DNS_REC_DLV;
163 }
164 return DNS_REC_INVALID;
165 case 'n':
166 switch(tolower(str[2]))
167 {
168 case 'a':
169 if(tolower(str[3]) == 'm' && tolower(str[4]) == 'e' && str[5] == 0)
170 {
171 return DNS_REC_DNAME;
172 }
173 return DNS_REC_INVALID;
174 case 's':
175 if(tolower(str[3]) == 'k' && tolower(str[4]) == 'e' && tolower(str[5]) == 'y' && str[6] == 0)
176 {
177 return DNS_REC_DNSKEY;
178 }
179 return DNS_REC_INVALID;
180 default:
181 return DNS_REC_INVALID;
182 }
183 case 's':
184 if(str[2] == 0)
185 {
186 return DNS_REC_DS;
187 }
188 return DNS_REC_INVALID;
189 default:
190 return DNS_REC_INVALID;
191 }
192 case 'h':
193 if (tolower(str[1]) == 'i' && tolower(str[2]) == 'p' && str[3] == 0)
194 {
195 return DNS_REC_HIP;
196 }
197 return DNS_REC_INVALID;
198 case 'i':
199 if (tolower(str[1]) == 'p' && tolower(str[2]) == 's' && tolower(str[3]) == 'e' && tolower(str[4]) == 'c'
200 && tolower(str[5]) == 'k' && tolower(str[6]) == 'e' && tolower(str[7]) == 'y' && str[8] == 0)
201 {
202 return DNS_REC_IPSECKEY;
203 }
204 return DNS_REC_INVALID;
205 case 'k':
206 switch(tolower(str[1]))
207 {
208 case 'e':
209 if (tolower(str[2]) == 'y' && str[3] == 0)
210 {
211 return DNS_REC_KEY;
212 }
213 return DNS_REC_INVALID;
214 case 'x':
215 if (str[2] == 0)
216 {
217 return DNS_REC_KX;
218 }
219 return DNS_REC_INVALID;
220 default:
221 return DNS_REC_INVALID;
222 }
223 case 'l':
224 if (tolower(str[1]) == 'o' && tolower(str[2]) == 'c' && str[3] == 0)
225 {
226 return DNS_REC_LOC;
227 }
228 return DNS_REC_INVALID;
229 case 'm':
230 if (tolower(str[1]) == 'x' && str[2] == 0)
231 {
232 return DNS_REC_MX;
233 }
234 return DNS_REC_INVALID;
235 case 'n':
236 switch(tolower(str[1]))
237 {
238 case 'a':
239 if (tolower(str[2]) == 'p' && tolower(str[3]) == 't' && tolower(str[4]) == 'r' && str[5] == 0)
240 {
241 return DNS_REC_NAPTR;
242 }
243 return DNS_REC_INVALID;
244 case 's':
245 switch(tolower(str[2]))
246 {
247 case 0:
248 return DNS_REC_NS;
249 case 'e':
250 if(tolower(str[3]) == 'c')
251 {
252 switch(tolower(str[4]))
253 {
254 case 0:
255 return DNS_REC_NSEC;
256 case '3':
257 if(str[5] == 0)
258 {
259 return DNS_REC_NSEC3;
260 }
261 if(tolower(str[5]) == 'p' && tolower(str[6]) == 'a' && tolower(str[7]) == 'r'
262 && tolower(str[8]) == 'a' && tolower(str[9]) == 'm' && str[10] == 0)
263 {
264 return DNS_REC_NSEC3PARAM;
265 }
266 return DNS_REC_INVALID;
267 default:
268 return DNS_REC_INVALID;
269 }
270 }
271 return DNS_REC_INVALID;
272 default:
273 return DNS_REC_INVALID;
274 }
275 default:
276 return DNS_REC_INVALID;
277 }
278 case 'o':
279 if (tolower(str[1]) == 'p' && tolower(str[2]) == 'e' && tolower(str[3]) == 'n' && tolower(str[4]) == 'p'
280 && tolower(str[5]) == 'g' && tolower(str[6]) == 'p' && tolower(str[7]) == 'k' && tolower(str[8]) == 'e'
281 && tolower(str[9]) == 'y' && str[10] == 0)
282 {
283 return DNS_REC_OPENPGPKEY;
284 }
285 return DNS_REC_INVALID;
286 case 'p':
287 if (tolower(str[1]) == 't' && tolower(str[2]) == 'r' && str[3] == 0)
288 {
289 return DNS_REC_PTR;
290 }
291 return DNS_REC_INVALID;
292 case 'r':
293 switch(tolower(str[1]))
294 {
295 case 'p':
296 if(str[2] == 0)
297 {
298 return DNS_REC_RP;
299 }
300 return DNS_REC_INVALID;
301 case 'r':
302 if (tolower(str[2]) == 's' && tolower(str[3]) == 'i' && tolower(str[4]) == 'g' && str[5] == 0)
303 {
304 return DNS_REC_RRSIG;
305 }
306 return DNS_REC_INVALID;
307 default:
308 return DNS_REC_INVALID;
309 }
310 case 's':
311 switch (tolower(str[1]))
312 {
313 case 'i':
314 if (tolower(str[2]) == 'g' && tolower(str[3]) == 0)
315 {
316 return DNS_REC_SIG;
317 }
318 return DNS_REC_INVALID;
319 case 'o':
320 if (tolower(str[2]) == 'a' && tolower(str[3]) == 0)
321 {
322 return DNS_REC_SOA;
323 }
324 return DNS_REC_INVALID;
325 case 'r':
326 if (tolower(str[2]) == 'v' && tolower(str[3]) == 0)
327 {
328 return DNS_REC_SRV;
329 }
330 return DNS_REC_INVALID;
331 case 's':
332 if (tolower(str[2]) == 'h' && tolower(str[3]) == 'f' && tolower(str[4]) == 'p' && str[5] == 0)
333 {
334 return DNS_REC_SSHFP;
335 }
336 return DNS_REC_INVALID;
337 default:
338 return DNS_REC_INVALID;
339 }
340 case 't':
341 switch (tolower(str[1]))
342 {
343 case 'a':
344 if(str[2] == 0)
345 {
346 return DNS_REC_TA;
347 }
348 return DNS_REC_INVALID;
349 case 'k':
350 if (tolower(str[2]) == 'e' && tolower(str[3]) == 'y' && str[4] == 0)
351 {
352 return DNS_REC_TKEY;
353 }
354 return DNS_REC_INVALID;
355 case 'l':
356 if (tolower(str[2]) == 's' && tolower(str[3]) == 'a' && str[4] == 0)
357 {
358 return DNS_REC_TLSA;
359 }
360 return DNS_REC_INVALID;
361 case 's':
362 if (tolower(str[2]) == 'i' && tolower(str[3]) == 'g' && str[4] == 0)
363 {
364 return DNS_REC_TSIG;
365 }
366 return DNS_REC_INVALID;
367 case 'x':
368 if (tolower(str[2]) == 't' && str[3] == 0)
369 {
370 return DNS_REC_TXT;
371 }
372 return DNS_REC_INVALID;
373 default:
374 return DNS_REC_INVALID;
375 }
376 case 'u':
377 switch (tolower(str[1]))
378 {
379 case 'r':
380 if (tolower(str[2]) == 'i' && str[3] == 0)
381 {
382 return DNS_REC_URI;
383 }
384 return DNS_REC_INVALID;
385 default:
386 return DNS_REC_INVALID;
387 }
388 case '0':
389 case '1':
390 case '2':
391 case '3':
392 case '4':
393 case '5':
394 case '6':
395 case '7':
396 case '8':
397 case '9':
398 return (dns_record_type)atoi(str);
399 default:
400 return DNS_REC_INVALID;
401 }
402 }
403
404 typedef enum
405 {
406 DNS_CLS_IN = 1,
407 DNS_CLS_CH = 3,
408 DNS_CLS_HS = 4,
409 DNS_CLS_QCLASS_NONE = 254,
410 DNS_CLS_QCLASS_ANY = 255
411 } dns_class;
412
413 #define DNS_RCODE_BADSIG DNS_RCODE_BADVERS
414
415 typedef enum
416 {
417 DNS_RCODE_OK = 0,
418 DNS_RCODE_FORMERR = 1,
419 DNS_RCODE_SERVFAIL = 2,
420 DNS_RCODE_NXDOMAIN = 3,
421 DNS_RCODE_NOTIMP = 4,
422 DNS_RCODE_REFUSED = 5,
423 DNS_RCODE_YXDOMAIN = 6,
424 DNS_RCODE_YXRRSET = 7,
425 DNS_RCODE_NOTAUTH = 9,
426 DNS_RCODE_NOTZONE = 10,
427 DNS_RCODE_BADVERS = 16,
428 DNS_RCODE_BADKEY = 17,
429 DNS_RCODE_BADTIME = 18,
430 DNS_RCODE_BADMODE = 19,
431 DNS_RCODE_BADNAME = 20,
432 DNS_RCODE_BADALG = 21,
433 DNS_RCODE_BADTRUNC = 22,
434 DNS_RCODE_BADCOOKIE = 23
435 } dns_rcode;
436
437 bool dns_str2rcode(char *str, dns_rcode *code)
438 {
439 if(strcasecmp(str, "ok") == 0 || strcasecmp(str, "noerror") == 0)
440 {
441 *code = DNS_RCODE_OK;
442 return true;
443 }
444 else if(strcasecmp(str, "formerr") == 0)
445 {
446 *code = DNS_RCODE_FORMERR;
447 return true;
448 }
449 else if(strcasecmp(str, "servfail") == 0)
450 {
451 *code = DNS_RCODE_SERVFAIL;
452 return true;
453 }
454 else if(strcasecmp(str, "nxdomain") == 0)
455 {
456 *code = DNS_RCODE_NXDOMAIN;
457 return true;
458 }
459 else if(strcasecmp(str, "notimp") == 0)
460 {
461 *code = DNS_RCODE_NOTIMP;
462 return true;
463 }
464 else if(strcasecmp(str, "refused") == 0)
465 {
466 *code = DNS_RCODE_REFUSED;
467 return true;
468 }
469 else if(strcasecmp(str, "yxdomain") == 0)
470 {
471 *code = DNS_RCODE_YXDOMAIN;
472 return true;
473 }
474 else if(strcasecmp(str, "yxrrset") == 0)
475 {
476 *code = DNS_RCODE_YXRRSET;
477 return true;
478 }
479 else if(strcasecmp(str, "notauth") == 0)
480 {
481 *code = DNS_RCODE_NOTAUTH;
482 return true;
483 }
484 else if(strcasecmp(str, "notzone") == 0)
485 {
486 *code = DNS_RCODE_NOTZONE;
487 return true;
488 }
489 else if(strcasecmp(str, "badvers") == 0 || strcasecmp(str, "badsig") == 0)
490 {
491 *code = DNS_RCODE_BADVERS;
492 return true;
493 }
494 else if(strcasecmp(str, "badkey") == 0)
495 {
496 *code = DNS_RCODE_BADKEY;
497 return true;
498 }
499 else if(strcasecmp(str, "badtime") == 0)
500 {
501 *code = DNS_RCODE_BADTIME;
502 return true;
503 }
504 else if(strcasecmp(str, "badmode") == 0)
505 {
506 *code = DNS_RCODE_BADMODE;
507 return true;
508 }
509 else if(strcasecmp(str, "badname") == 0)
510 {
511 *code = DNS_RCODE_BADNAME;
512 return true;
513 }
514 else if(strcasecmp(str, "badalg") == 0)
515 {
516 *code = DNS_RCODE_BADALG;
517 return true;
518 }
519 else if(strcasecmp(str, "badtrunc") == 0)
520 {
521 *code = DNS_RCODE_BADTRUNC;
522 return true;
523 }
524 else if(strcasecmp(str, "badcookie") == 0)
525 {
526 *code = DNS_RCODE_BADCOOKIE;
527 return true;
528 }
529 else
530 {
531 char *endptr;
532 unsigned long result = strtoul(str, &endptr, 10);
533 if(*endptr != 0 || result > UINT16_MAX)
534 {
535 return false;
536 }
537 *code = (dns_rcode)result;
538 }
539 return false;
540 }
541
542 typedef enum
543 {
544 DNS_OPCODE_QUERY = 0,
545 DNS_OPCODE_IQUERY = 1,
546 DNS_OPCODE_STATUS = 2,
547 DNS_OPCODE_NOTIFY = 4,
548 DNS_OPCODE_UPDATE = 5
549 } dns_opcode;
550
551 const size_t DNS_PACKET_MINIMUM_SIZE = 17; // as we handle them
552 // 12 bytes header + 1 byte question name + 2 bytes question class + 2 bytes question type
553
554 typedef struct
555 {
556 uint16_t id;
557 bool rd;
558 bool tc;
559 bool aa;
560 uint8_t opcode;
561 bool qr;
562 uint8_t rcode;
563 bool ad;
564 bool z;
565 bool cd;
566 bool ra;
567
568 uint16_t q_count;
569 uint16_t ans_count;
570 uint16_t auth_count;
571 uint16_t add_count;
572
573 } dns_header_t;
574
575 typedef struct
576 {
577 uint8_t name[0xFF];
578 uint8_t length;
579 } dns_name_t;
580
581 typedef struct
582 {
583 dns_name_t name;
584 dns_record_type type;
585 unsigned int class;
586 } dns_question_t;
587
588 typedef struct
589 {
590 dns_header_t header;
591 dns_question_t question;
592 } dns_head_t;
593
594 typedef struct
595 {
596 dns_name_t name;
597 uint16_t type;
598 uint16_t class;
599 uint32_t ttl;
600 uint16_t length;
601 union
602 {
603 uint8_t *raw;
604 dns_name_t name;
605 struct in_addr in_addr;
606 struct in6_addr in6_addr;
607 } data;
608 } dns_record_t;
609
610 typedef struct
611 {
612 dns_record_t ans[0x100];
613 dns_record_t auth[0x100];
614 dns_record_t add[0x100];
615 } dns_filtered_body_t;
616
617 typedef struct
618 {
619 dns_head_t head;
620 dns_filtered_body_t body;
621 } dns_pkt_t;
622
623 typedef struct
624 {
625 uint8_t length;
626 uint8_t *data;
627 } dns_character_string_ptr_t;
628
629 typedef struct
630 {
631 uint16_t preference;
632 dns_name_t name;
633 } dns_mx_t;
634
635 typedef struct
636 {
637 uint8_t flags;
638 uint8_t taglen;
639 uint8_t *tag;
640 uint8_t *value;
641 } dns_caa_t;
642
643 static inline bool is_valid_label_char(int c)
644 {
645 return isalnum(c) || c == '-' || c == '_';
646 }
647
648 static bool parse_name(uint8_t *begin, uint8_t *buf, const uint8_t *end, uint8_t *name, uint8_t *len, uint8_t **next)
649 {
650 static uint8_t first;
651 static int label_type;
652 static int label_len;
653 static int name_len;
654 static uint8_t *pointer;
655
656 label_len = 0;
657 pointer = NULL;
658 name_len = 0;
659 while (true)
660 {
661 if (buf >= end)
662 {
663 return false;
664 }
665 first = *buf;
666 label_type = (first & 0xC0);
667 if (label_type == 0xC0) // Compressed
668 {
669 if (next && !pointer)
670 {
671 *next = buf + 2;
672 }
673 pointer = begin + (htons(*((uint16_t *) buf)) & 0x3FFF);
674 if (pointer >= buf)
675 {
676 return false;
677 }
678 buf = pointer;
679 }
680 else if (label_type == 0x00) // Uncompressed
681 {
682 label_len = (first & 0x3F);
683 name_len += label_len + 1;
684 if (name_len >= 0xFF)
685 {
686 return false;
687 }
688 if (label_len == 0)
689 {
690 if (name_len == 1)
691 {
692 *(name++) = '.';
693 }
694 *name = 0;
695 if (next && !pointer)
696 {
697 *next = buf + label_len + 1;
698 }
699 if (name_len <= 1)
700 {
701 *len = (uint8_t) name_len;
702 }
703 else
704 {
705 *len = (uint8_t) (name_len - 1);
706 }
707 return true;
708 }
709 else
710 {
711 if (buf + label_len + 1 > end)
712 {
713 return false;
714 }
715 memcpy(name, buf + 1, (size_t)label_len);
716 *(name + label_len) = '.';
717 name += label_len + 1;
718 buf += label_len + 1;
719 }
720 }
721 else
722 {
723 return false;
724 }
725 }
726 }
727
728 static inline void dns_buffer_set_id(uint8_t *buf, uint16_t id)
729 {
730 *((uint16_t *) buf) = htons(id);
731 }
732
733 char *dns_class2str(dns_class cls)
734 {
735 static char numbuf[16];
736
737 switch(cls)
738 {
739 case DNS_CLS_IN:
740 return "IN";
741 case DNS_CLS_CH:
742 return "H";
743 case DNS_CLS_HS:
744 return "HS";
745 case DNS_CLS_QCLASS_NONE:
746 return "QNONE";
747 case DNS_CLS_QCLASS_ANY:
748 return "QANY";
749 default:
750 snprintf(numbuf, sizeof(numbuf), "%" PRIu16, (uint16_t)cls);
751 return numbuf;
752 }
753 }
754
755 char *dns_opcode2str(dns_opcode opcode)
756 {
757 static char numbuf[16];
758
759 switch(opcode)
760 {
761 case DNS_OPCODE_QUERY:
762 return "QUERY";
763 case DNS_OPCODE_IQUERY:
764 return "IQUERY";
765 case DNS_OPCODE_STATUS:
766 return "STATUS";
767 case DNS_OPCODE_NOTIFY:
768 return "NOTIFY";
769 case DNS_OPCODE_UPDATE:
770 return "UPDATE";
771 default:
772 snprintf(numbuf, sizeof(numbuf), "%" PRIu16, (uint16_t)opcode);
773 return numbuf;
774 }
775 }
776
777 char *dns_rcode2str(dns_rcode rcode)
778 {
779 static char numbuf[16];
780
781 switch (rcode)
782 {
783 case DNS_RCODE_OK:
784 return "NOERROR";
785 case DNS_RCODE_FORMERR:
786 return "FORMERR";
787 case DNS_RCODE_SERVFAIL:
788 return "SERVFAIL";
789 case DNS_RCODE_NXDOMAIN:
790 return "NXDOMAIN";
791 case DNS_RCODE_NOTIMP:
792 return "NOTIMP";
793 case DNS_RCODE_REFUSED:
794 return "REFUSED";
795 case DNS_RCODE_YXDOMAIN:
796 return "YXDOMAIN";
797 case DNS_RCODE_YXRRSET:
798 return "YXRRSET";
799 case DNS_RCODE_NOTAUTH:
800 return "NOTAUTH";
801 case DNS_RCODE_NOTZONE:
802 return "NOTZONE";
803 case DNS_RCODE_BADVERS:
804 return "BADVERS";
805 case DNS_RCODE_BADKEY:
806 return "BADKEY";
807 case DNS_RCODE_BADTIME:
808 return "BADTIME";
809 case DNS_RCODE_BADMODE:
810 return "BADMODE";
811 case DNS_RCODE_BADNAME:
812 return "BADNAME";
813 case DNS_RCODE_BADALG:
814 return "BADALG";
815 case DNS_RCODE_BADTRUNC:
816 return "BADTRUNC";
817 case DNS_RCODE_BADCOOKIE:
818 return "BADCOOKIE";
819 default:
820 snprintf(numbuf, sizeof(numbuf), "%" PRIu16, (uint16_t)rcode);
821 return numbuf;
822 }
823 }
824
825 char *dns_record_type2str(dns_record_type type)
826 {
827 static char numbuf[16];
828
829 switch (type)
830 {
831 case DNS_REC_A:
832 return "A";
833 case DNS_REC_AAAA:
834 return "AAAA";
835 case DNS_REC_AFSDB:
836 return "AFSDB";
837 case DNS_REC_ANY:
838 return "ANY";
839 case DNS_REC_APL:
840 return "APL";
841 case DNS_REC_CAA:
842 return "CAA";
843 case DNS_REC_CDNSKEY:
844 return "CDNSKEY";
845 case DNS_REC_CDS:
846 return "CDS";
847 case DNS_REC_CERT:
848 return "CERT";
849 case DNS_REC_CNAME:
850 return "CNAME";
851 case DNS_REC_DHCID:
852 return "DHCID";
853 case DNS_REC_DLV:
854 return "DLV";
855 case DNS_REC_DNAME:
856 return "DNAME";
857 case DNS_REC_DNSKEY:
858 return "DNSKEY";
859 case DNS_REC_DS:
860 return "DS";
861 case DNS_REC_HIP:
862 return "HIP";
863 case DNS_REC_IPSECKEY:
864 return "IPSECKEY";
865 case DNS_REC_KEY:
866 return "KEY";
867 case DNS_REC_KX:
868 return "KX";
869 case DNS_REC_LOC:
870 return "LOC";
871 case DNS_REC_MX:
872 return "MX";
873 case DNS_REC_NAPTR:
874 return "NAPTR";
875 case DNS_REC_NS:
876 return "NS";
877 case DNS_REC_NSEC:
878 return "NSEC";
879 case DNS_REC_NSEC3:
880 return "NSEC3";
881 case DNS_REC_NSEC3PARAM:
882 return "NSEC3PARAM";
883 case DNS_REC_OPENPGPKEY:
884 return "OPENPGPKEY";
885 case DNS_REC_PTR:
886 return "PTR";
887 case DNS_REC_RRSIG:
888 return "RRSIG";
889 case DNS_REC_RP:
890 return "RP";
891 case DNS_REC_SIG:
892 return "SIG";
893 case DNS_REC_SOA:
894 return "SOA";
895 case DNS_REC_SRV:
896 return "SRV";
897 case DNS_REC_SSHFP:
898 return "SSHFP";
899 case DNS_REC_TA:
900 return "TA";
901 case DNS_REC_TKEY:
902 return "TKEY";
903 case DNS_REC_TLSA:
904 return "TLSA";
905 case DNS_REC_TSIG:
906 return "TSIG";
907 case DNS_REC_TXT:
908 return "TXT";
909 case DNS_REC_URI:
910 return "URI";
911 default:
912 snprintf(numbuf, sizeof(numbuf), "%" PRIu16, (uint16_t)type);
913 return numbuf;
914 }
915 }
916
917 ssize_t dns_str2namebuf(const char *name, uint8_t *buffer)
918 {
919 static uint8_t *bufname;
920 static uint8_t *lenptr;
921 static uint8_t total_len;
922 static uint8_t label_len;
923
924 lenptr = buffer; // points to the byte containing the label length
925 bufname = buffer + 1; // points to the first byte of the actual name
926 total_len = 0;
927 label_len = 0;
928
929 while (true)
930 {
931 char c = *(name++);
932 total_len++;
933 if (total_len > 254)
934 {
935 return -1;
936 }
937 if (c == '.')
938 {
939 *lenptr = label_len;
940 if (total_len == 1)
941 {
942 total_len--;
943 break;
944 }
945 if (*name == 0)
946 {
947 *(bufname++) = 0;
948 break;
949 }
950 lenptr = bufname++;
951 label_len = 0;
952 }
953 else if (c == 0)
954 {
955 *lenptr = label_len;
956 *(bufname++) = 0;
957 break;
958 }
959 else
960 {
961 *(bufname++) = (uint8_t) c;
962 label_len++;
963 if (label_len >= 64)
964 {
965 return -1;
966 }
967 }
968 }
969 return total_len + 1;
970 }
971
972 ssize_t dns_question_create_from_name(uint8_t *buffer, dns_name_t *name, dns_record_type type, uint16_t id)
973 {
974 static uint8_t *aftername;
975
976 memcpy(buffer + 12, name->name, name->length);
977 aftername = buffer + 12 + name->length;
978 dns_buffer_set_id(buffer, id);
979 *((uint16_t *) (buffer + 2)) = 0;
980 *((uint16_t *) aftername) = htons(type);
981 *((uint16_t *) (aftername + 2)) = htons(DNS_CLS_IN);
982 *((uint16_t *) (buffer + 4)) = htons(0x0001);
983 return aftername + 4 - buffer;
984 }
985
986 // Requires a buffer of at least 272 bytes to be supplied
987 static ssize_t dns_question_create(uint8_t *buffer, char *name, dns_record_type type, uint16_t id)
988 {
989 static uint8_t *aftername;
990
991 ssize_t name_len = dns_str2namebuf(name, buffer + 12);
992 if(name_len < 0)
993 {
994 return -1;
995 }
996 aftername = buffer + 12 + name_len;
997
998 dns_buffer_set_id(buffer, id);
999 *((uint16_t *) (buffer + 2)) = 0;
1000 *((uint16_t *) aftername) = htons(type);
1001 *((uint16_t *) (aftername + 2)) = htons(DNS_CLS_IN);
1002 *((uint16_t *) (buffer + 4)) = htons(0x0001);
1003 return aftername + 4 - buffer;
1004 }
1005
1006 bool dns_send_question(uint8_t *buffer, char *name, dns_record_type type, uint16_t id, int fd, struct sockaddr_storage *addr)
1007 {
1008 ssize_t result = dns_question_create(buffer, name, type, id);
1009 if (result < DNS_PACKET_MINIMUM_SIZE)
1010 {
1011 return false;
1012 }
1013 sendto(fd,
1014 buffer,
1015 (size_t) result,
1016 0,
1017 (struct sockaddr *) addr,
1018 addr->ss_family == PF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
1019 return true;
1020 }
1021
1022 bool dns_parse_question(uint8_t *buf, size_t len, dns_head_t *head, uint8_t **body_begin)
1023 {
1024 static uint8_t *end; // exclusive
1025 static bool name_parsed;
1026 static uint8_t *qname_end;
1027
1028 end = buf + len;
1029 if (len < DNS_PACKET_MINIMUM_SIZE)
1030 {
1031 return false;
1032 }
1033
1034 head->header.id = ntohs((*(uint16_t *) buf));
1035 head->header.qr = (bool) (buf[2] & 0x80);
1036 head->header.opcode = (uint8_t) ((buf[2] & (0x78)) >> 3);
1037 head->header.aa = (bool) (buf[2] & 0x04);
1038 head->header.tc = (bool) (buf[2] & 0x02);
1039 head->header.rd = (bool) (buf[2] & 0x01);
1040 head->header.ra = (bool) (buf[3] & 0x80);
1041 head->header.z = (bool) (buf[4] & 0x40);
1042 head->header.ad = (bool) (buf[3] & 0x20);
1043 head->header.cd = (bool) (buf[3] & 0x10);
1044 head->header.rcode = (uint8_t) (buf[3] & 0x0F);
1045
1046 head->header.ans_count = ntohs((*(uint16_t *) (buf + 6)));
1047 head->header.auth_count = ntohs((*(uint16_t *) (buf + 8)));
1048 head->header.add_count = ntohs((*(uint16_t *) (buf + 10)));
1049 head->header.q_count = ntohs((*(uint16_t *) (buf + 4)));
1050 if (head->header.q_count != 1)
1051 {
1052 return false;
1053 }
1054 name_parsed = parse_name(buf, buf + 12, end, head->question.name.name, &head->question.name.length, &qname_end);
1055 if (qname_end + 2 > end)
1056 {
1057 return false;
1058 }
1059 if (!name_parsed)
1060 {
1061 return false;
1062 }
1063 head->question.type = (dns_record_type) ntohs((*(uint16_t *) qname_end));
1064 head->question.class = ntohs((*(uint16_t *) (qname_end + 2)));
1065 if (body_begin)
1066 {
1067 *body_begin = qname_end + 4;
1068 }
1069 return true;
1070 }
1071
1072 bool dns_names_eq(dns_name_t *name1, dns_name_t *name2)
1073 {
1074 if(name1->length != name2->length)
1075 {
1076 return false;
1077 }
1078 for(uint8_t i = 0; i < name1->length; i++)
1079 {
1080 if(tolower(name1->name[i]) != tolower(name2->name[i]))
1081 {
1082 return false;
1083 }
1084 }
1085 return true;
1086 }
1087
1088 bool dns_raw_names_eq(dns_name_t *name1, dns_name_t *name2)
1089 {
1090 return name1->length == name2->length && memcmp(name1->name, name2->name, name1->length) == 0;
1091 }
1092
1093 bool dns_parse_record_raw(uint8_t *begin, uint8_t *buf, const uint8_t *end, uint8_t **next, dns_record_t *record)
1094 {
1095 if (!parse_name(begin, buf, end, record->name.name, &record->name.length, next))
1096 {
1097 return false;
1098 }
1099 if (*next + 10 > end)
1100 {
1101 return false;
1102 }
1103
1104 record->type = ntohs((*(uint16_t *) (*next)));
1105 record->class = ntohs((*(uint16_t *) (*next + 2)));
1106 record->ttl = ntohl((*(uint32_t *) (*next + 4)));
1107 record->length = ntohs((*(uint16_t *) (*next + 8)));
1108 *next = *next + 10;
1109
1110 record->data.raw = *next;
1111
1112 *next = *next + record->length;
1113 if (*next > end)
1114 {
1115 return false;
1116 }
1117 return true;
1118 }
1119
1120 bool dns_parse_record(uint8_t *begin, uint8_t *buf, const uint8_t *end, uint8_t **next, dns_record_t *record)
1121 {
1122 if(!dns_parse_record_raw(begin, buf, end, next, record))
1123 {
1124 return false;
1125 }
1126
1127 if (record->type == DNS_REC_A)
1128 {
1129 if (record->length != 4)
1130 {
1131 return false;
1132 }
1133 memcpy(&record->data.in_addr, record->data.raw, 4);
1134 }
1135 else if (record->type == DNS_REC_AAAA)
1136 {
1137 if (record->length != 16)
1138 {
1139 return false;
1140 }
1141 memcpy(&record->data.in6_addr, record->data.raw, 16);
1142 }
1143 else if (record->type == DNS_REC_NS)
1144 {
1145 if (record->length > 0xFF)
1146 {
1147 return false;
1148 }
1149 if (!parse_name(begin, record->data.raw, end, record->data.name.name, &record->data.name.length, NULL))
1150 {
1151 return false;
1152 }
1153 }
1154
1155 // We don't care about any other records.
1156
1157 return true;
1158 }
1159
1160 bool dns_parse_body(uint8_t *buf, uint8_t *begin, const uint8_t *end, dns_pkt_t *packet)
1161 {
1162 static uint8_t *next;
1163 static uint16_t i;
1164
1165 next = buf;
1166 for (i = 0; i < min(packet->head.header.ans_count, elements(packet->body.ans) - 1); i++)
1167 {
1168 if (!dns_parse_record(begin, next, end, &next, &packet->body.ans[i]))
1169 {
1170 return false;
1171 }
1172 }
1173 packet->body.ans[i].type = 0;
1174
1175 for (i = 0; i < min(packet->head.header.auth_count, elements(packet->body.auth) - 1); i++)
1176 {
1177 if (!dns_parse_record(begin, next, end, &next, &packet->body.auth[i]))
1178 {
1179 return false;
1180 }
1181 }
1182 packet->body.auth[i].type = 0;
1183
1184 for (i = 0; i < min(packet->head.header.add_count, elements(packet->body.add) - 1); i++)
1185 {
1186 if (!dns_parse_record(begin, next, end, &next, &packet->body.add[i]))
1187 {
1188 return false;
1189 }
1190 }
1191 packet->body.add[i].type = 0;
1192
1193 // TODO: Check whether overly long packets are valid. If not, discard them here.
1194
1195 return true;
1196 }
1197
1198 bool dns_parse_reply(uint8_t *buf, size_t len, dns_pkt_t *packet)
1199 {
1200 uint8_t *body_begin;
1201 if (!dns_parse_question(buf, len, &packet->head, &body_begin))
1202 {
1203 return false;
1204 }
1205 return dns_parse_body(body_begin, buf, buf + len, packet);
1206 }
1207
1208 void dns_buf_set_qr(uint8_t *buf, bool value)
1209 {
1210 buf[2] &= 0x7F;
1211 buf[2] |= value << 7;
1212 }
1213
1214 void dns_buf_set_rd(uint8_t *buf, bool value)
1215 {
1216 buf[2] &= 0xFE;
1217 buf[2] |= value;
1218 }
1219
1220 void dns_buf_set_rcode(uint8_t *buf, uint8_t code)
1221 {
1222 buf[3] &= 0xF0;
1223 buf[3] |= code;
1224 }
1225
1226 void dns_send_reply(uint8_t *buffer, size_t len, int fd, struct sockaddr_storage *addr)
1227 {
1228 sendto(fd,
1229 buffer,
1230 len,
1231 0,
1232 (struct sockaddr *) addr,
1233 addr->ss_family == PF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
1234 }
1235
1236 bool dns_create_reply(uint8_t *buffer, size_t *len, char *name, dns_record_type type, uint16_t id, dns_rcode code)
1237 {
1238 ssize_t result = dns_question_create(buffer, name, type, id);
1239 if (result < DNS_PACKET_MINIMUM_SIZE)
1240 {
1241 return false;
1242 }
1243 *len = (size_t) result;
1244 dns_buf_set_qr(buffer, true);
1245 dns_buf_set_rcode(buffer, code);
1246 return true;
1247 }
1248
1249 bool dns_print_readable(char **buf, size_t buflen, const uint8_t *source, size_t len)
1250 {
1251 char *endbuf = *buf + buflen;
1252 for(size_t i = 0; i < len; i++)
1253 {
1254 if(source[i] >= ' ' && source[i] <= '~' && source[i] != '\\')
1255 {
1256 if(*buf >= endbuf - 1)
1257 {
1258 **buf = 0;
1259 return false;
1260 }
1261 *((*buf)++) = source[i];
1262 }
1263 else
1264 {
1265 if(*buf >= endbuf - 4)
1266 {
1267 **buf = 0;
1268 return false;
1269 }
1270 *((*buf)++) = '\\';
1271 *((*buf)++) = 'x';
1272 char hex1 = (char)((source[i] >> 8) & 0xF);
1273 char hex2 = (char)(source[i] & 0xF);
1274 *((*buf)++) = (char)(hex1 + (hex1 < 10 ? '0' : ('a' - 10)));
1275 *((*buf)++) = (char)(hex2 + (hex2 < 10 ? '0' : ('a' - 10)));
1276 }
1277 }
1278 **buf = 0;
1279 return true;
1280 }
1281
1282 char* dns_name2str(dns_name_t *name)
1283 {
1284 static char buf[0xFF * 4];
1285
1286 char *ptr = buf;
1287 dns_print_readable(&ptr, sizeof(buf), name->name, name->length);
1288 return buf;
1289 }
1290
1291 void dns_question2str(dns_question_t *question, char *buf, size_t len)
1292 {
1293 snprintf(buf, len, "%s %s %s",
1294 dns_name2str(&question->name),
1295 dns_class2str((dns_class)question->class),
1296 dns_record_type2str(question->type));
1297 }
1298
1299 char* dns_raw_record_data2str(dns_record_t *record, uint8_t *begin, uint8_t *end)
1300 {
1301 static char buf[0xFFFF0];
1302 static dns_name_t name;
1303
1304 char *ptr = buf;
1305
1306 switch(record->type)
1307 {
1308 case DNS_REC_NS:
1309 case DNS_REC_CNAME:
1310 case DNS_REC_DNAME:
1311 case DNS_REC_PTR:
1312 parse_name(begin, record->data.raw, end, name.name, &name.length, NULL);
1313 dns_print_readable(&ptr, sizeof(buf), name.name, name.length);
1314 break;
1315 case DNS_REC_MX:
1316 if(record->length < 3)
1317 {
1318 goto raw;
1319 }
1320 parse_name(begin, record->data.raw + 2, end, name.name, &name.length, NULL);
1321 int no = sprintf(buf, "%" PRIu16 " ", ntohs(*((uint16_t*)record->data.raw)));
1322 ptr += no;
1323 dns_print_readable(&ptr, sizeof(buf), name.name, name.length);
1324 break;
1325 case DNS_REC_TXT:
1326 {
1327 uint8_t *record_end = record->data.raw + record->length;
1328 uint8_t *data_ptr = record->data.raw;
1329 while(data_ptr < record_end)
1330 {
1331 uint8_t length = *(data_ptr++);
1332 if (data_ptr + length <= record_end)
1333 {
1334 *(ptr++) = '"';
1335 dns_print_readable(&ptr, sizeof(buf), data_ptr, length);
1336 data_ptr += length;
1337 *(ptr++) = '"';
1338 *(ptr++) = ' ';
1339 }
1340 else
1341 {
1342 break;
1343 }
1344 }
1345 *ptr = 0;
1346 break;
1347 }
1348 case DNS_REC_SOA:
1349 {
1350 uint8_t *next;
1351 // We have 5 32-bit values plus two names.
1352 if (record->length < 22)
1353 {
1354 goto raw;
1355 }
1356
1357 parse_name(begin, record->data.raw, end, name.name, &name.length, &next);
1358 dns_print_readable(&ptr, sizeof(buf), name.name, name.length);
1359 *(ptr++) = ' ';
1360
1361 if(next + 20 >= record->data.raw + record->length)
1362 {
1363 goto raw;
1364 }
1365 parse_name(begin, next, end, name.name, &name.length, &next);
1366 dns_print_readable(&ptr, sizeof(buf), name.name, name.length);
1367 *(ptr++) = ' ';
1368 if(next + 20 > record->data.raw + record->length)
1369 {
1370 goto raw;
1371 }
1372
1373 sprintf(ptr, "%" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32,
1374 ntohl(*((uint32_t*)next)),
1375 ntohl(*(((uint32_t*)next) + 1)),
1376 ntohl(*(((uint32_t*)next) + 2)),
1377 ntohl(*(((uint32_t*)next) + 3)),
1378 ntohl(*(((uint32_t*)next) + 4)));
1379 break;
1380 }
1381 case DNS_REC_A:
1382 if(record->length != 4)
1383 {
1384 goto raw;
1385 }
1386 inet_ntop(AF_INET, record->data.raw, buf, sizeof(buf));
1387 break;
1388 case DNS_REC_AAAA:
1389 if(record->length != 16)
1390 {
1391 goto raw;
1392 }
1393 inet_ntop(AF_INET6, record->data.raw, buf, sizeof(buf));
1394 break;
1395 case DNS_REC_CAA:
1396 if(record->length < 2 || record->data.raw[1] < 1 || record->data.raw[1] > 15
1397 || record->data.raw[1] + 2 > record->length)
1398 {
1399 goto raw;
1400 }
1401 int written = sprintf(ptr, "%" PRIu8 " ", (uint8_t)(record->data.raw[0] >> 7));
1402 if(written < 0)
1403 {
1404 return buf;
1405 }
1406 ptr += written;
1407 dns_print_readable(&ptr, sizeof(buf), record->data.raw + 2, record->data.raw[1]);
1408 *(ptr++) = ' ';
1409 *(ptr++) = '"';
1410 dns_print_readable(&ptr, sizeof(buf), record->data.raw + 2 + record->data.raw[1],
1411 (size_t)(record->length - record->data.raw[1] - 2));
1412 *(ptr++) = '"';
1413 *ptr = 0;
1414 break;
1415 raw:
1416 default:
1417 dns_print_readable(&ptr, sizeof(buf), record->data.raw, record->length);
1418 *ptr = 0;
1419 }
1420 return buf;
1421 }
1422
1423 dns_section_t dns_get_section(uint16_t index, dns_header_t *header)
1424 {
1425 if(index < header->ans_count)
1426 {
1427 return DNS_SECTION_ANSWER;
1428 }
1429 else if(index < header->ans_count + header->auth_count)
1430 {
1431 return DNS_SECTION_AUTHORITY;
1432 }
1433 else
1434 {
1435 return DNS_SECTION_ADDITIONAL;
1436 }
1437 }
1438
1439 char *dns_section2str(dns_section_t section)
1440 {
1441 switch(section)
1442 {
1443 case DNS_SECTION_ANSWER:
1444 return "ANSWER";
1445 case DNS_SECTION_ADDITIONAL:
1446 return "ADDITIONAL";
1447 case DNS_SECTION_AUTHORITY:
1448 return "AUTHORITY";
1449 case DNS_SECTION_QUESTION:
1450 return "QUESTION";
1451 }
1452 return "UNKNOWN";
1453 }
1454
1455 char *dns_section2str_lower_plural(dns_section_t section)
1456 {
1457 switch(section)
1458 {
1459 case DNS_SECTION_ANSWER:
1460 return "answers";
1461 case DNS_SECTION_ADDITIONAL:
1462 return "additionals";
1463 case DNS_SECTION_AUTHORITY:
1464 return "authorities";
1465 case DNS_SECTION_QUESTION:
1466 return "questions";
1467 }
1468 return "unknowns";
1469 }
1470
1471 bool dns_in_zone(dns_name_t *name, dns_name_t *zone)
1472 {
1473 return zone->length == 1 // Provided that the label is a FQDN, this is the root zone containing everything else
1474 || (zone->length == name->length
1475 && strcasecmp((char*)name->name + name->length - zone->length, (char*)zone->name) == 0)
1476 || (zone->length < name->length
1477 && strcasecmp((char*)name->name + name->length - zone->length, (char*)zone->name) == 0
1478 && *(name->name + name->length - zone->length - 1) == '.');
1479
1480 }
1481
1482 void dns_print_packet(FILE *f, dns_pkt_t *packet, uint8_t *begin, size_t len, uint8_t *next)
1483 {
1484 static char buf[0xFFFF];
1485 static dns_record_t rec;
1486
1487 fprintf(f,
1488 ";; ->>HEADER<<- opcode: %s, status: %s, id: %"PRIu16"\n"
1489 ";; flags: %s%s%s%s%s; QUERY: %" PRIu16 ", ANSWER: %" PRIu16 ", AUTHORITY: %" PRIu16 ", ADDITIONAL: %" PRIu16 "\n\n"
1490 ";; QUESTION SECTION:\n",
1491 dns_opcode2str((dns_opcode)packet->head.header.opcode),
1492 dns_rcode2str((dns_rcode)packet->head.header.rcode),
1493 packet->head.header.id,
1494 packet->head.header.qr ? "qr " : "",
1495 packet->head.header.ad ? "ad " : "",
1496 packet->head.header.aa ? "aa " : "",
1497 packet->head.header.rd ? "rd " : "",
1498 packet->head.header.ra ? "ra " : "",
1499 packet->head.header.q_count,
1500 packet->head.header.ans_count,
1501 packet->head.header.auth_count,
1502 packet->head.header.add_count
1503 );
1504
1505 dns_question2str(&packet->head.question, buf, sizeof(buf));
1506 fprintf(f, "%s\n", buf);
1507
1508 uint16_t i = 0;
1509 dns_section_t section = DNS_SECTION_QUESTION;
1510 while(dns_parse_record_raw(begin, next, begin + len, &next, &rec))
1511 {
1512 dns_section_t new_section = dns_get_section(i++, &packet->head.header);
1513 if(new_section != section)
1514 {
1515 fprintf(f, "\n;; %s SECTION:\n", dns_section2str(new_section));
1516 section = new_section;
1517 }
1518 fprintf(f,
1519 "%s %" PRIu32 " %s %s %s\n",
1520 dns_name2str(&rec.name),
1521 rec.ttl,
1522 dns_class2str((dns_class)rec.class),
1523 dns_record_type2str((dns_record_type) rec.type),
1524 dns_raw_record_data2str(&rec, begin, begin + len));
1525 }
1526 fprintf(f, "\n\n");
1527 }
1528
1529 #endif //MASSRESOLVER_DNS_H
+0
-66
flow.h less more
0 #ifndef MASSDNS_FLOW_H
1 #define MASSDNS_FLOW_H
2
3 #include <signal.h>
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <sys/types.h>
8
9 static void kill_process_group(int sig)
10 {
11 static int received_termination = 0;
12
13 if(received_termination)
14 {
15 return;
16 }
17 received_termination = 1;
18 kill(0, sig);
19 exit(0);
20 }
21
22 static void handle_termination()
23 {
24 signal(SIGINT, kill_process_group);
25 signal(SIGTERM, kill_process_group);
26 }
27
28 // times is the number of resulting processes, i.e. if times is two, the process will fork once
29 size_t split_process(size_t times, pid_t *pids)
30 {
31 if(pids != NULL)
32 {
33 pids[0] = getpid();
34 }
35 for (size_t i = 0; i < times - 1; i++)
36 {
37 pid_t child = fork();
38 switch (child)
39 {
40 case -1:
41 {
42 perror("Failed to fork");
43 exit(EXIT_FAILURE);
44 }
45 case 0:
46 {
47 handle_termination();
48 return i + 1;
49 }
50 default:
51 if(pids != NULL)
52 {
53 pids[i + 1] = child;
54 }
55 break;
56 }
57 }
58 if(times > 1)
59 {
60 handle_termination();
61 }
62 return 0;
63 }
64
65 #endif
+0
-339
hashmap.h less more
0 #ifndef MASSDNS_HASHMAP_H
1 #define MASSDNS_HASHMAP_H
2 /*
3 * Copyright (C) 2007 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 #include <assert.h>
18 #include <errno.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdbool.h>
22 #include <sys/types.h>
23
24 // http://www.cse.yorku.ca/~oz/hash.html
25 unsigned long hash_djb2(unsigned char *str)
26 {
27 unsigned long hash = 5381;
28 int c;
29 while ((c = *str++) != 0)
30 {
31 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
32 }
33 return hash;
34 }
35
36 int hash_string(void *str)
37 {
38 return (int) hash_djb2((unsigned char *) str);
39 }
40
41
42 typedef struct Entry Entry;
43 struct Entry {
44 void* key;
45 int hash;
46 void* value;
47 Entry* next;
48 };
49 typedef struct Hashmap {
50 Entry** buckets;
51 size_t bucketCount;
52 int (*hash)(void* key);
53 bool (*equals)(void* keyA, void* keyB);
54 size_t size;
55 } Hashmap;
56 Hashmap* hashmapCreate(size_t initialCapacity,
57 int (*hash)(void* key), bool (*equals)(void* keyA, void* keyB)) {
58 assert(hash != NULL);
59 assert(equals != NULL);
60
61 Hashmap* map = malloc(sizeof(Hashmap));
62 if (map == NULL) {
63 return NULL;
64 }
65
66 // 0.75 load factor.
67 size_t minimumBucketCount = initialCapacity * 4 / 3;
68 map->bucketCount = 1;
69 while (map->bucketCount <= minimumBucketCount) {
70 // Bucket count must be power of 2.
71 map->bucketCount <<= 1;
72 }
73 map->buckets = calloc(map->bucketCount, sizeof(Entry*));
74 if (map->buckets == NULL) {
75 free(map);
76 return NULL;
77 }
78
79 map->size = 0;
80 map->hash = hash;
81 map->equals = equals;
82
83 return map;
84 }
85 /**
86 * Hashes the given key.
87 */
88 #ifdef __clang__
89 __attribute__((no_sanitize("integer")))
90 #endif
91 static inline int hashKey(Hashmap* map, void* key) {
92 int h = map->hash(key);
93 // We apply this secondary hashing discovered by Doug Lea to defend
94 // against bad hashes.
95 h += ~(h << 9);
96 h ^= (((unsigned int) h) >> 14);
97 h += (h << 4);
98 h ^= (((unsigned int) h) >> 10);
99
100 return h;
101 }
102 size_t hashmapSize(Hashmap* map) {
103 return map->size;
104 }
105 static inline size_t calculateIndex(size_t bucketCount, int hash) {
106 return ((size_t) hash) & (bucketCount - 1);
107 }
108 static void expandIfNecessary(Hashmap* map) {
109 // If the load factor exceeds 0.75...
110 if (map->size > (map->bucketCount * 3 / 4)) {
111 // Start off with a 0.33 load factor.
112 size_t newBucketCount = map->bucketCount << 1;
113 Entry** newBuckets = calloc(newBucketCount, sizeof(Entry*));
114 if (newBuckets == NULL) {
115 // Abort expansion.
116 return;
117 }
118
119 // Move over existing entries.
120 size_t i;
121 for (i = 0; i < map->bucketCount; i++) {
122 Entry* entry = map->buckets[i];
123 while (entry != NULL) {
124 Entry* next = entry->next;
125 size_t index = calculateIndex(newBucketCount, entry->hash);
126 entry->next = newBuckets[index];
127 newBuckets[index] = entry;
128 entry = next;
129 }
130 }
131 // Copy over internals.
132 free(map->buckets);
133 map->buckets = newBuckets;
134 map->bucketCount = newBucketCount;
135 }
136 }
137
138 void hashmapFree(Hashmap* map) {
139 size_t i;
140 for (i = 0; i < map->bucketCount; i++) {
141 Entry* entry = map->buckets[i];
142 while (entry != NULL) {
143 Entry* next = entry->next;
144 free(entry);
145 entry = next;
146 }
147 }
148 free(map->buckets);
149 free(map);
150 }
151 #ifdef __clang__
152 __attribute__((no_sanitize("integer")))
153 #endif
154 /* FIXME: relies on signed integer overflow, which is undefined behavior */
155 int hashmapHash(void* key, size_t keySize) {
156 int h = keySize;
157 char* data = (char*) key;
158 size_t i;
159 for (i = 0; i < keySize; i++) {
160 h = h * 31 + *data;
161 data++;
162 }
163 return h;
164 }
165 static Entry* createEntry(void* key, int hash, void* value) {
166 Entry* entry = malloc(sizeof(Entry));
167 if (entry == NULL) {
168 return NULL;
169 }
170 entry->key = key;
171 entry->hash = hash;
172 entry->value = value;
173 entry->next = NULL;
174 return entry;
175 }
176 static inline bool equalKeys(void* keyA, int hashA, void* keyB, int hashB,
177 bool (*equals)(void*, void*)) {
178 if (keyA == keyB) {
179 return true;
180 }
181 if (hashA != hashB) {
182 return false;
183 }
184 return equals(keyA, keyB);
185 }
186 void* hashmapPut(Hashmap* map, void* key, void* value) {
187 int hash = hashKey(map, key);
188 size_t index = calculateIndex(map->bucketCount, hash);
189 Entry** p = &(map->buckets[index]);
190 while (true) {
191 Entry* current = *p;
192 // Add a new entry.
193 if (current == NULL) {
194 *p = createEntry(key, hash, value);
195 if (*p == NULL) {
196 errno = ENOMEM;
197 return NULL;
198 }
199 map->size++;
200 expandIfNecessary(map);
201 return NULL;
202 }
203 // Replace existing entry.
204 if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
205 void* oldValue = current->value;
206 current->value = value;
207 return oldValue;
208 }
209 // Move to next entry.
210 p = &current->next;
211 }
212 }
213 void* hashmapGet(Hashmap* map, void* key) {
214 int hash = hashKey(map, key);
215 size_t index = calculateIndex(map->bucketCount, hash);
216 Entry* entry = map->buckets[index];
217 while (entry != NULL) {
218 if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) {
219 return entry->value;
220 }
221 entry = entry->next;
222 }
223 return NULL;
224 }
225 void* hashmapGetWithKey(Hashmap* map, void* key, void **originalKey) {
226 int hash = hashKey(map, key);
227 size_t index = calculateIndex(map->bucketCount, hash);
228 Entry* entry = map->buckets[index];
229 while (entry != NULL) {
230 if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) {
231 *originalKey = entry->key;
232 return entry->value;
233 }
234 entry = entry->next;
235 }
236 return NULL;
237 }
238 bool hashmapContainsKey(Hashmap* map, void* key) {
239 int hash = hashKey(map, key);
240 size_t index = calculateIndex(map->bucketCount, hash);
241 Entry* entry = map->buckets[index];
242 while (entry != NULL) {
243 if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) {
244 return true;
245 }
246 entry = entry->next;
247 }
248 return false;
249 }
250 void* hashmapMemoize(Hashmap* map, void* key,
251 void* (*initialValue)(void* key, void* context), void* context) {
252 int hash = hashKey(map, key);
253 size_t index = calculateIndex(map->bucketCount, hash);
254 Entry** p = &(map->buckets[index]);
255 while (true) {
256 Entry* current = *p;
257 // Add a new entry.
258 if (current == NULL) {
259 *p = createEntry(key, hash, NULL);
260 if (*p == NULL) {
261 errno = ENOMEM;
262 return NULL;
263 }
264 void* value = initialValue(key, context);
265 (*p)->value = value;
266 map->size++;
267 expandIfNecessary(map);
268 return value;
269 }
270 // Return existing value.
271 if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
272 return current->value;
273 }
274 // Move to next entry.
275 p = &current->next;
276 }
277 }
278 void* hashmapRemove(Hashmap* map, void* key) {
279 int hash = hashKey(map, key);
280 size_t index = calculateIndex(map->bucketCount, hash);
281 // Pointer to the current entry.
282 Entry** p = &(map->buckets[index]);
283 Entry* current;
284 while ((current = *p) != NULL) {
285 if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
286 void* value = current->value;
287 *p = current->next;
288 free(current);
289 map->size--;
290 return value;
291 }
292 p = &current->next;
293 }
294 return NULL;
295 }
296 void hashmapForEach(Hashmap* map,
297 bool (*callback)(void* key, void* value, void* context),
298 void* context) {
299 size_t i;
300 for (i = 0; i < map->bucketCount; i++) {
301 Entry* entry = map->buckets[i];
302 while (entry != NULL) {
303 Entry *next = entry->next;
304 if (!callback(entry->key, entry->value, context)) {
305 return;
306 }
307 entry = next;
308 }
309 }
310 }
311 size_t hashmapCurrentCapacity(Hashmap* map) {
312 size_t bucketCount = map->bucketCount;
313 return bucketCount * 3 / 4;
314 }
315 size_t hashmapCountCollisions(Hashmap* map) {
316 size_t collisions = 0;
317 size_t i;
318 for (i = 0; i < map->bucketCount; i++) {
319 Entry* entry = map->buckets[i];
320 while (entry != NULL) {
321 if (entry->next != NULL) {
322 collisions++;
323 }
324 entry = entry->next;
325 }
326 }
327 return collisions;
328 }
329 int hashmapIntHash(void* key) {
330 // Return the key value itself.
331 return *((int*) key);
332 }
333 bool hashmapIntEquals(void* keyA, void* keyB) {
334 int a = *((int*) keyA);
335 int b = *((int*) keyB);
336 return a == b;
337 }
338 #endif
+0
-352
list.h less more
0 #ifndef INC_LIST
1 #define INC_LIST
2
3 #include "buffers.h"
4 #include "security.h"
5 #include <stdbool.h>
6
7 #define single_list_foreach(list, element) for (single_list_element_t *(element) = (list).first; (element) != NULL; (element) = (element)->next)
8 #define single_list_ref_foreach(list, element) for (single_list_element_t *(element) = (list)->first; (element) != NULL; (element) = (element)->next)
9 #define single_list_foreach_free(list, element) for (single_list_element_t *(element) = (list).first; (element) != NULL; (element) = single_list_free_and_next(element))
10 #define single_list_ref_foreach_free(list, element) for (single_list_element_t *(element) = (list)->first; (element) != NULL; (element) = single_list_free_and_next(element))
11
12 #define double_list_foreach_free(list, element) for (double_list_element_t *(element) = (list).first; (element) != NULL; (element) = double_list_free_and_next(element))
13
14 typedef struct single_list_element
15 {
16 void *data;
17 struct single_list_element *next;
18 } single_list_element_t;
19
20 typedef struct
21 {
22 size_t count;
23 single_list_element_t *first;
24 single_list_element_t *last;
25 } single_list_t;
26
27 typedef struct double_list_element
28 {
29 void *data;
30 struct double_list_element *previous;
31 struct double_list_element *next;
32 } double_list_element_t;
33
34 typedef struct
35 {
36 size_t count;
37 double_list_element_t *first;
38 double_list_element_t *last;
39 } double_list_t;
40
41 size_t single_list_count(single_list_t* list)
42 {
43 return list->count;
44 }
45
46 bool single_list_iterate(single_list_t *list, bool (*f)(void *, void *), void *param)
47 {
48 single_list_element_t* element = list->first;
49 while (element != NULL)
50 {
51 single_list_element_t *next = element->next;
52 if(!f(element->data, param))
53 {
54 return false;
55 }
56 element = next;
57 }
58 return true;
59 }
60
61 bool single_list_iterate_free(single_list_t *list, bool (*f)(void *, void *), void *param)
62 {
63 single_list_element_t* element = list->first;
64 while (element != NULL)
65 {
66 single_list_element_t *next = element->next;
67 if(!f(element->data, param))
68 {
69 return false;
70 }
71 free(element);
72 list->first = next;
73 list->count--;
74 element = next;
75 }
76 list->last = NULL;
77 return true;
78 }
79
80 bool single_list_element_set_array_element(void *element, void *param)
81 {
82 buffer_t *buffer = param;
83 void **data = buffer->data;
84 data[buffer->len++] = element;
85 return true;
86 }
87
88 buffer_t single_list_to_array(single_list_t *list)
89 {
90 buffer_t buf;
91 buf.len = 0;
92 buf.data = safe_malloc(sizeof(buf.data) * list->count);
93 single_list_iterate(list, single_list_element_set_array_element, &buf);
94 return buf;
95 }
96
97 buffer_t single_list_to_array_copy(single_list_t *list, size_t element_size)
98 {
99 buffer_t buf;
100 buf.len = list->count;
101 buf.data = safe_malloc(element_size * list->count);
102 size_t i = 0;
103 single_list_ref_foreach(list, element)
104 {
105 memcpy(((uint8_t*)buf.data) + (i++) * element_size, element->data, element_size);
106 }
107 return buf;
108 }
109
110 single_list_t *single_list_new()
111 {
112 single_list_t *list = safe_calloc(sizeof(*list));
113 return list;
114 }
115
116 void single_list_init(single_list_t *list)
117 {
118 bzero(list, sizeof(*list));
119 }
120
121 void single_list_cat(single_list_t* left, single_list_t* right)
122 {
123 if(left->last != NULL)
124 {
125 left->last->next = right->first;
126 }
127 else
128 {
129 left->first = right->first;
130 left->last = right->last;
131 }
132 left->count += right->count;
133 left->last = right->last;
134 }
135
136 void single_list_clear(single_list_t *list)
137 {
138 single_list_element_t *element = list->first;
139 while (element != NULL)
140 {
141 single_list_element_t *next = element->next;
142 free(element);
143 element = next;
144 }
145 single_list_init(list);
146 }
147
148 void single_list_free(single_list_t *list)
149 {
150 if(list != NULL)
151 {
152 single_list_clear(list);
153 }
154 free(list);
155 }
156
157 void single_list_free_elements(single_list_t *list)
158 {
159 if(list == NULL)
160 {
161 return;
162 }
163 single_list_element_t *current = list->first;
164 while(current != NULL)
165 {
166 single_list_element_t *next = current->next;
167 free(current->data);
168 free(current);
169 current = next;
170 }
171 }
172
173 void single_list_free_with_elements(single_list_t *list)
174 {
175 single_list_free_elements(list);
176 free(list);
177 }
178
179 void single_list_push_front(single_list_t *list, void *data)
180 {
181 single_list_element_t *new_element = safe_malloc(sizeof(*new_element));
182 new_element->data = data;
183 new_element->next = list->first;
184 if (list->last == NULL)
185 {
186 list->last = new_element;
187 }
188 list->first = new_element;
189 list->count++;
190 }
191
192 single_list_element_t *single_list_push_back(single_list_t *list, void *data)
193 {
194 single_list_element_t *new_element = safe_malloc(sizeof(*new_element));
195 new_element->data = data;
196 new_element->next = NULL;
197 list->count++;
198 if (list->last)
199 {
200 list->last->next = new_element;
201 }
202 else
203 {
204 list->first = new_element;
205 }
206 list->last = new_element;
207 return new_element;
208 }
209
210 /**
211 * Pop the first element from a list and push it to the back.
212 *
213 * @param list The list to be wrapped.
214 */
215 void single_list_wrap_first(single_list_t *list)
216 {
217 if(list->first == NULL)
218 {
219 return;
220 }
221 list->last->next = list->first;
222 list->last = list->first;
223 list->first = list->first->next;
224 list->last->next = NULL;
225 }
226
227 double_list_t* double_list_new()
228 {
229 double_list_t *list = safe_calloc(sizeof(*list));
230 return list;
231 }
232
233 void double_list_init(double_list_t *list)
234 {
235 bzero(list, sizeof(*list));
236 }
237
238 void double_list_free(double_list_t *list_holder)
239 {
240 double_list_element_t *list = list_holder->first;
241 while (list != NULL)
242 {
243 double_list_element_t *next = list->next;
244 free(list);
245 list = next;
246 }
247 }
248
249 void double_list_push_front(double_list_t *list, void *data)
250 {
251 double_list_element_t *new_element = safe_malloc(sizeof(*new_element));
252 new_element->data = data;
253 new_element->next = list->first;
254 new_element->previous = NULL;
255 if (list->last == NULL)
256 {
257 list->last = new_element;
258 }
259 list->first = new_element;
260 list->count++;
261 }
262
263 double_list_element_t *double_list_push_back(double_list_t *list, void *data)
264 {
265 double_list_element_t *new_element = safe_malloc(sizeof(*new_element));
266 new_element->data = data;
267 new_element->next = NULL;
268 new_element->previous = list->last;
269 list->count++;
270 if (list->last)
271 {
272 list->last->next = new_element;
273 }
274 else
275 {
276 list->first = new_element;
277 }
278 list->last = new_element;
279 return new_element;
280 }
281
282 void double_list_clear(double_list_t *list)
283 {
284 double_list_element_t *element = list->first;
285 while (element != NULL)
286 {
287 double_list_element_t *next = element->next;
288 free(element);
289 element = next;
290 }
291 double_list_init(list);
292 }
293
294 void double_list_iterate(double_list_t *list, void (*f)(double_list_element_t *, size_t, void *), void *param)
295 {
296 double_list_element_t* element = list->first;
297 size_t counter = 0;
298 while (element != NULL)
299 {
300 double_list_element_t *next = element->next;
301 f(element, counter++, param);
302 element = next;
303 }
304 }
305
306 double_list_element_t* double_list_free_and_next(double_list_element_t *element)
307 {
308 double_list_element_t *next = element->next;
309 free(element);
310 return next;
311 }
312
313 single_list_element_t* single_list_free_and_next(single_list_element_t *element)
314 {
315 single_list_element_t *next = element->next;
316 free(element);
317 return next;
318 }
319
320 void single_list_remove(single_list_t* list, void *value)
321 {
322 single_list_element_t *last = NULL;
323 single_list_element_t *element = list->first;
324 while (element != NULL)
325 {
326 if(element->data == value)
327 {
328 if(last == NULL)
329 {
330 list->first = list->first->next;
331 }
332 else
333 {
334 last->next = element->next;
335 }
336 if(element == list->last)
337 {
338 list->last = last;
339 }
340 list->count--;
341 element = single_list_free_and_next(element);
342 }
343 else
344 {
345 last = element;
346 element = element->next;
347 }
348 }
349 }
350
351 #endif
+0
-2247
main.c less more
0 #define _GNU_SOURCE
1
2 #ifdef DEBUG
3 #include <sys/resource.h>
4 #endif
5
6 #include "massdns.h"
7 #include "string.h"
8 #include "random.h"
9 #include "net.h"
10 #include "cmd.h"
11 #include "dns.h"
12 #include "list.h"
13 #include "flow.h"
14 #include <unistd.h>
15 #include <pwd.h>
16 #include <grp.h>
17 #include <sys/ioctl.h>
18 #include <stddef.h>
19 #ifdef HAVE_SYSINFO
20 #include <sys/sysinfo.h>
21 #endif
22 #include <limits.h>
23 #include <stdarg.h>
24
25 #ifdef PCAP_SUPPORT
26 #include <net/ethernet.h>
27 #include <netinet/ip.h>
28 #include <netinet/ip6.h>
29 #include <netinet/udp.h>
30 #include <net/if.h>
31 #endif
32
33 static char json_buffer[5 * 0xFFFF];
34
35 void print_help()
36 {
37 fprintf(stderr, ""
38 "Usage: %s [options] [domainlist]\n"
39 " -b --bindto Bind to IP address and port. (Default: 0.0.0.0:0)\n"
40 #ifdef HAVE_EPOLL
41 " --busy-poll Use busy-wait polling instead of epoll.\n"
42 #endif
43 " -c --resolve-count Number of resolves for a name before giving up. (Default: 50)\n"
44 " --drop-group Group to drop privileges to when running as root. (Default: nogroup)\n"
45 " --drop-user User to drop privileges to when running as root. (Default: nobody)\n"
46 " --flush Flush the output file whenever a response was received.\n"
47 " -h --help Show this help.\n"
48 " -i --interval Interval in milliseconds to wait between multiple resolves of the same\n"
49 " domain. (Default: 500)\n"
50 " -l --error-log Error log file path. (Default: /dev/stderr)\n"
51 " --norecurse Use non-recursive queries. Useful for DNS cache snooping.\n"
52 " -o --output Flags for output formatting.\n"
53 " --predictable Use resolvers incrementally. Useful for resolver tests.\n"
54 " --processes Number of processes to be used for resolving. (Default: 1)\n"
55 " -q --quiet Quiet mode.\n"
56 " --rcvbuf Size of the receive buffer in bytes.\n"
57 " --retry Unacceptable DNS response codes. (Default: REFUSED)\n"
58 " -r --resolvers Text file containing DNS resolvers.\n"
59 " --root Do not drop privileges when running as root. Not recommended.\n"
60 " -s --hashmap-size Number of concurrent lookups. (Default: 10000)\n"
61 " --sndbuf Size of the send buffer in bytes.\n"
62 " --status-format Format for real-time status updates, json or ansi (Default: ansi)\n"
63 " --sticky Do not switch the resolver when retrying.\n"
64 " --socket-count Socket count per process. (Default: 1)\n"
65 " -t --type Record type to be resolved. (Default: A)\n"
66 #ifdef PCAP_SUPPORT
67 " --use-pcap Enable pcap usage.\n"
68 #endif
69 " --verify-ip Verify IP addresses of incoming replies.\n"
70 " -w --outfile Write to the specified output file instead of standard output.\n"
71 "\n"
72 "Output flags:\n"
73 " S - simple text output\n"
74 " F - full text output\n"
75 " B - binary output\n"
76 " J - ndjson output\n"
77 "\n"
78 "Advanced flags for the simple output mode:\n"
79 " d - Include records from the additional section.\n"
80 " i - Indent any reply record.\n"
81 " l - Separate replies using a line feed.\n"
82 " m - Only output reply records that match the question name.\n"
83 " n - Include records from the answer section.\n"
84 " q - Print the question.\n"
85 " r - Prepend resolver IP address, Unix timestamp and return code to the question line.\n"
86 " s - Separate packet sections using a line feed.\n"
87 " t - Include TTL and record class within the output.\n"
88 " u - Include records from the authority section.\n",
89 context.cmd_args.argv[0] ? context.cmd_args.argv[0] : "massdns"
90 );
91 }
92
93
94 /* The default real-time status output, human reeadable, very granular stats */
95 static const char* stats_fmt_ansi = "\033[H\033[2J" // Clear screen (probably simplest and most portable solution)
96 "Processed queries: %zu\n"
97 "Received packets: %zu\n"
98 "Progress: %.2f%% (%02lld h %02lld min %02lld sec / %02lld h %02lld min %02lld sec)\n"
99 "Current incoming rate: %zu pps, average: %zu pps\n"
100 "Current success rate: %zu pps, average: %zu pps\n"
101 "Finished total: %zu, success: %zu (%.2f%%)\n"
102 "Mismatched domains: %zu (%.2f%%), IDs: %zu (%.2f%%)\n"
103 "Failures: %s\n"
104 "Response: | Success: | Total:\n"
105 "OK: | %12zu (%6.2f%%) | %12zu (%6.2f%%)\n"
106 "NXDOMAIN: | %12zu (%6.2f%%) | %12zu (%6.2f%%)\n"
107 "SERVFAIL: | %12zu (%6.2f%%) | %12zu (%6.2f%%)\n"
108 "REFUSED: | %12zu (%6.2f%%) | %12zu (%6.2f%%)\n"
109 "FORMERR: | %12zu (%6.2f%%) | %12zu (%6.2f%%)\n";
110
111 /* Optional real-time status output, all stats on a single line as valid JSON */
112 static const char* stats_fmt_json =
113 "{"
114 "\"processed_queries\": %zu,"
115 "\"received_packets\": %zu, "
116 "\"progress\":"
117 "{"
118 "\"percent\": \"%.2f%%\"" ","
119 "\"eta\":" "{"
120 "\"hours\": %lld, \"minutes\": %lld, \"seconds\": %lld, \"total_hours\": %lld, \"total_minutes\": %lld, \"total_seconds\": %lld"
121 "}"
122 "},"
123 "\"incoming_pps\": %zu, "
124 "\"average_incoming_pps\": %zu, "
125 "\"success_rate_pps\": %zu, \"average_success_rate_pps\": %zu, "
126 "\"finished_total\": %zu, "
127 "\"success_total\": %zu, "
128 "\"success_total_percent\": \"%.2f%%\", "
129 "\"mismatched_domains\": %zu,"
130 "\"mismatched_domains_pct\": \"%.2f%%\","
131 "\"IDs\": %zu, \"IDs pct\": \"%.2f%%\","
132 "\"failures\": \"%s\","
133 "\"response\": {"
134 "\"OK\": {"
135 "\"success_number\": %12zu,"
136 "\"success_pct\": \"%6.2f%%\","
137 "\"total_number\": %12zu,"
138 "\"total_pct\": \"%6.2f%%\"},"
139 "\"NXDOMAIN\": { "
140 "\"success_number\": %12zu,"
141 "\"success_pct\": \"%6.2f%%\","
142 "\"total_number\": %12zu,"
143 "\"total_pct\": \"%6.2f%%\"},"
144 "\"SERVFAIL\": {"
145 "\"success_number\": %zu,"
146 "\"success_pct\": \"%6.2f%%\","
147 "\"total_number\": %zu, "
148 "\"total_pct\": \"%6.2f%%\"},"
149 "\"REFUSED\": { "
150 "\"success_number\": %12zu,"
151 "\"success_pct\": \"%6.2f%%\","
152 "\"total_number\": %zu,"
153 "\"total_pct\": \"%6.2f%%\"},"
154 "\"FORMERR\": {"
155 "\"success_number\": %zu,"
156 "\"success_pct\": \"%6.2f%%\","
157 "\"total_number\": %zu,"
158 "\"total_pct\": \"%6.2f%%\"}"
159 "}"
160 "}\n";
161
162 void cleanup()
163 {
164 #ifdef PCAP_SUPPORT
165 if(context.pcap != NULL)
166 {
167 pcap_close(context.pcap);
168 }
169 #endif
170 if(context.map)
171 {
172 hashmapFree(context.map);
173 }
174
175 if(context.resolver_map)
176 {
177 hashmapFree(context.resolver_map);
178 }
179
180 timed_ring_destroy(&context.ring);
181
182 free(context.resolvers.data);
183
184 free(context.sockets.interfaces4.data);
185 free(context.sockets.interfaces6.data);
186
187 urandom_close();
188
189 if(context.domainfile)
190 {
191 fclose(context.domainfile);
192 }
193 if(context.outfile)
194 {
195 fclose(context.outfile);
196 }
197 if(context.logfile)
198 {
199 fclose(context.logfile);
200 }
201
202 free(context.stat_messages);
203
204
205 free(context.lookup_pool.data);
206 free(context.lookup_space);
207
208 for (size_t i = 0; i < context.cmd_args.num_processes * 2; i++)
209 {
210 if(context.sockets.pipes && context.sockets.pipes[i] >= 0)
211 {
212 close(context.sockets.pipes[i]);
213 }
214 }
215 free(context.sockets.pipes);
216 free(context.sockets.master_pipes_read);
217 free(context.pids);
218 free(context.done);
219 }
220
221 void log_msg(const char* format, ...)
222 {
223 if(context.logfile != stderr)
224 {
225 va_list args;
226 va_start(args, format);
227 vfprintf(stderr, format, args);
228 va_end(args);
229 }
230 if(context.logfile)
231 {
232 va_list args;
233 va_start(args, format);
234 vfprintf(context.logfile, format, args);
235 va_end(args);
236 }
237 }
238
239 void clean_exit(int status)
240 {
241 cleanup();
242 exit(status);
243 }
244
245 // Adaption of djb2 for sockaddr_storage
246 int hash_address(void *param)
247 {
248 struct sockaddr_storage *address = param;
249
250 unsigned long hash = 5381;
251 uint8_t *addr_ptr;
252 uint8_t *addr_end;
253
254 if(address->ss_family == AF_INET)
255 {
256 struct sockaddr_in *addr4 = param;
257 addr_ptr = (uint8_t*)&addr4->sin_addr;
258 addr_end = addr_ptr + sizeof(addr4->sin_addr);
259 hash = ((hash << 5) + hash) + ((addr4->sin_port & 0xFF00) >> 8);
260 hash = ((hash << 5) + hash) + (addr4->sin_port & 0x00FF);
261 }
262 else if(address->ss_family == AF_INET6)
263 {
264 struct sockaddr_in6 *addr6 = param;
265 addr_ptr = (uint8_t*)&addr6->sin6_addr;
266 addr_end = addr_ptr + sizeof(addr6->sin6_addr);
267 hash = ((hash << 5) + hash) + ((addr6->sin6_port & 0xFF00) >> 8);
268 hash = ((hash << 5) + hash) + (addr6->sin6_port & 0x00FF);
269 }
270 else
271 {
272 log_msg("Unsupported address for hashing.\n");
273 abort();
274 }
275
276 while (addr_ptr < addr_end)
277 {
278 hash = ((hash << 5) + hash) + *addr_ptr; /* hash * 33 + c */
279 addr_ptr++;
280 }
281 return (int)hash;
282 }
283
284 // Expects valid (non-NULL) pointers to sockaddr storages of family AF_INET / AF_INET6
285 bool addresses_equal(void *param1, void *param2)
286 {
287 struct sockaddr_storage *addr1 = param1;
288 struct sockaddr_storage *addr2 = param2;
289
290 if(addr1->ss_family != addr2->ss_family)
291 {
292 return false;
293 }
294
295 if(addr1->ss_family == AF_INET)
296 {
297 return memcmp(&((struct sockaddr_in*)addr1)->sin_addr,
298 &((struct sockaddr_in*)addr2)->sin_addr, sizeof(((struct sockaddr_in*)addr1)->sin_addr)) == 0
299 && ((struct sockaddr_in*)addr1)->sin_port == ((struct sockaddr_in*)addr2)->sin_port;
300 }
301 else // Must be AF_INET6
302 {
303 return memcmp(&((struct sockaddr_in6*)addr1)->sin6_addr,
304 &((struct sockaddr_in6*)addr2)->sin6_addr, sizeof(((struct sockaddr_in6*)addr1)->sin6_addr)) == 0
305 && ((struct sockaddr_in6*)addr1)->sin6_port == ((struct sockaddr_in6*)addr2)->sin6_port;
306 }
307 return false;
308 }
309
310 buffer_t massdns_resolvers_from_file(char *filename)
311 {
312 char line[4096];
313 FILE *f = fopen(filename, "r");
314 if (f == NULL)
315 {
316 log_msg("Failed to open resolver file: %s\n", strerror(errno));
317 clean_exit(EXIT_FAILURE);
318 }
319 single_list_t *list = single_list_new();
320 while (!feof(f))
321 {
322 if (fgets(line, sizeof(line), f))
323 {
324 trim_end(line);
325 resolver_t *resolver = safe_calloc(sizeof(*resolver));
326 struct sockaddr_storage *addr = &resolver->address;
327 if (str_to_addr(line, 53, addr))
328 {
329 if((addr->ss_family == AF_INET && context.sockets.interfaces4.len > 0)
330 || (addr->ss_family == AF_INET6 && context.sockets.interfaces6.len > 0))
331 {
332 single_list_push_back(list, resolver);
333 }
334 else
335 {
336 log_msg("No query socket for resolver \"%s\" found.\n", line);
337 }
338 }
339 else
340 {
341 log_msg("\"%s\" is not a valid resolver. Skipped.\n", line);
342 }
343 }
344 }
345 fclose(f);
346 buffer_t resolvers = single_list_to_array_copy(list, sizeof(resolver_t));
347 if(single_list_count(list) == 0)
348 {
349 log_msg("No usable resolvers were found. Terminating.\n");
350 clean_exit(EXIT_FAILURE);
351 }
352
353 if(context.cmd_args.verify_ip)
354 {
355 context.resolver_map = hashmapCreate(resolvers.len, hash_address, addresses_equal);
356 if(!context.resolver_map)
357 {
358 log_msg("Failed to create resolver lookup map: %s\n", strerror(errno));
359 abort();
360 }
361
362 for (size_t i = 0; i < resolvers.len; i++)
363 {
364 resolver_t *resolver = ((resolver_t*)resolvers.data) + i;
365
366 errno = 0;
367 hashmapPut(context.resolver_map, &resolver->address, resolver);
368 if (errno != 0)
369 {
370 log_msg("Error putting resolver into hashmap: %s\n", strerror(errno));
371 abort();
372 }
373 }
374 }
375
376 single_list_free_with_elements(list);
377 return resolvers;
378 }
379
380 void set_sndbuf(int fd)
381 {
382 if(context.cmd_args.sndbuf
383 && setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &context.cmd_args.sndbuf, sizeof(context.cmd_args.sndbuf)) != 0)
384 {
385 log_msg("Failed to adjust send buffer size: %s\n", strerror(errno));
386 }
387 }
388
389 void set_rcvbuf(int fd)
390 {
391 if(context.cmd_args.rcvbuf
392 && setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &context.cmd_args.rcvbuf, sizeof(context.cmd_args.rcvbuf)) != 0)
393 {
394 log_msg("Failed to adjust receive buffer size: %s\n", strerror(errno));
395 }
396 }
397
398 void add_default_socket(int version)
399 {
400 socket_info_t info;
401
402 info.descriptor = socket(version == 4 ? PF_INET : PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
403 info.protocol = version == 4 ? PROTO_IPV4 : PROTO_IPV6;
404 info.type = SOCKET_TYPE_QUERY;
405 if(info.descriptor >= 0)
406 {
407 buffer_t *buffer = version == 4 ? &context.sockets.interfaces4 : &context.sockets.interfaces6;
408 buffer->data = safe_realloc(buffer->data, (buffer->len + 1) * sizeof(info));
409 ((socket_info_t*)buffer->data)[buffer->len++] = info;
410 set_rcvbuf(info.descriptor);
411 set_sndbuf(info.descriptor);
412 }
413 else
414 {
415 log_msg("Failed to create IPv%d socket: %s\n", version, strerror(errno));
416 }
417 }
418
419 void set_user_sockets(single_list_t *bind_addrs, buffer_t *buffer)
420 {
421 single_list_t sockets;
422 single_list_init(&sockets);
423 single_list_ref_foreach_free(bind_addrs, element)
424 {
425 struct sockaddr_storage* addr = element->data;
426 socket_info_t info;
427 info.descriptor = socket(addr->ss_family, SOCK_DGRAM, IPPROTO_UDP);
428 info.protocol = addr->ss_family == AF_INET ? PROTO_IPV4 : PROTO_IPV6;
429 info.type = SOCKET_TYPE_QUERY;
430 if(info.descriptor >= 0)
431 {
432 if(bind(info.descriptor, (struct sockaddr*)addr, sizeof(*addr)) != 0)
433 {
434 log_msg("Not adding socket %s due to bind failure: %s\n", sockaddr2str(addr), strerror(errno));
435 }
436 else
437 {
438 set_rcvbuf(info.descriptor);
439 set_sndbuf(info.descriptor);
440 single_list_push_back(&sockets, flatcopy(&info, sizeof(info)));
441 }
442 }
443 else
444 {
445 log_msg("Failed to create IPv%d socket: %s\n", info.protocol, strerror(errno));
446 }
447 free(element->data);
448 }
449 single_list_init(bind_addrs);
450 *buffer = single_list_to_array_copy(&sockets, sizeof(socket_info_t));
451 single_list_clear(&sockets);
452 }
453
454 void query_sockets_setup()
455 {
456 if(single_list_count(&context.cmd_args.bind_addrs4) == 0 && single_list_count(&context.cmd_args.bind_addrs6) == 0)
457 {
458 for(size_t i = 0; i < context.cmd_args.socket_count; i++)
459 {
460 add_default_socket(4);
461 add_default_socket(6);
462 }
463 }
464 else
465 {
466 set_user_sockets(&context.cmd_args.bind_addrs4, &context.sockets.interfaces4);
467 set_user_sockets(&context.cmd_args.bind_addrs6, &context.sockets.interfaces6);
468 }
469 }
470
471 bool next_query(char **qname)
472 {
473 static char line[512];
474 static size_t line_index = 0;
475
476 while (fgets(line, sizeof(line), context.domainfile))
477 {
478 if(line_index >= context.cmd_args.num_processes)
479 {
480 line_index = 0;
481 }
482 if (context.fork_index != line_index++)
483 {
484 continue;
485 }
486 trim_end(line);
487 if (*line == 0)
488 {
489 continue;
490 }
491 *qname = line;
492
493 return true;
494 }
495 return false;
496 }
497
498
499 // This is the djb2 hashing method treating the DNS type as two extra characters
500 int hash_lookup_key(void *key)
501 {
502 unsigned long hash = 5381;
503 uint8_t *entry = ((lookup_key_t *)key)->name.name;
504 int c;
505 while ((c = *entry++) != 0)
506 {
507 hash = ((hash << 5) + hash) + tolower(c); /* hash * 33 + c */
508 }
509 hash = ((hash << 5) + hash) + ((((lookup_key_t *)key)->type & 0xFF00) >> 8);
510 hash = ((hash << 5) + hash) + (((lookup_key_t *)key)->type & 0x00FF);
511 hash = ((hash << 5) + hash) + ((lookup_key_t *)key)->name.length;
512 return (int)hash;
513 }
514
515 void end_warmup()
516 {
517 context.state = STATE_QUERYING;
518 if(context.cmd_args.extreme <= 1 && !context.cmd_args.busypoll)
519 {
520 // Reduce our CPU load from epoll interrupts by removing the EPOLLOUT event
521 #ifdef PCAP_SUPPORT
522 if(!context.pcap)
523 #endif
524 #ifdef HAVE_EPOLL
525 {
526 add_sockets(context.epollfd, EPOLLIN, EPOLL_CTL_MOD, &context.sockets.interfaces4);
527 add_sockets(context.epollfd, EPOLLIN, EPOLL_CTL_MOD, &context.sockets.interfaces6);
528 }
529 #endif
530 }
531 }
532
533 lookup_t *new_lookup(const char *qname, dns_record_type type, bool *new)
534 {
535 if(context.lookup_pool.len == 0)
536 {
537 log_msg("Empty lookup pool.\n");
538 clean_exit(EXIT_FAILURE);
539 }
540 lookup_entry_t *entry = ((lookup_entry_t**)context.lookup_pool.data)[--context.lookup_pool.len];
541 lookup_key_t *key = &entry->key;
542
543 key->name.length = (uint8_t)string_copy((char*)key->name.name, qname, sizeof(key->name.name));
544 if(key->name.name[key->name.length - 1] != '.')
545 {
546 key->name.name[key->name.length] = '.';
547 key->name.name[++key->name.length] = 0;
548 }
549
550 key->type = type;
551 if(hashmapGet(context.map, key) != NULL)
552 {
553 context.lookup_pool.len++;
554 *new = false;
555 return NULL;
556 }
557 *new = true;
558 lookup_t *value = &entry->value;
559 bzero(value, sizeof(*value));
560
561 value->ring_entry = timed_ring_add(&context.ring, context.cmd_args.interval_ms * TIMED_RING_MS, value);
562 urandom_get(&value->transaction, sizeof(value->transaction));
563 value->key = key;
564
565 errno = 0;
566 hashmapPut(context.map, key, value);
567 if(errno != 0)
568 {
569 log_msg("Error putting lookup into hashmap: %s\n", strerror(errno));
570 abort();
571 }
572
573 context.lookup_index++;
574 context.stats.timeouts[0]++;
575 if(context.lookup_index >= context.cmd_args.hashmap_size)
576 {
577 end_warmup();
578 }
579
580 return value;
581 }
582
583 void send_query(lookup_t *lookup)
584 {
585 static uint8_t query_buffer[0x200];
586
587 // Choose random resolver
588 // Pool of resolvers cannot be empty due to check after parsing resolvers.
589 if(!context.cmd_args.sticky || lookup->resolver == NULL)
590 {
591 if(context.cmd_args.predictable_resolver)
592 {
593 lookup->resolver = ((resolver_t *) context.resolvers.data) + context.lookup_index % context.resolvers.len;
594 }
595 else
596 {
597 lookup->resolver = ((resolver_t *) context.resolvers.data) + urandom_size_t() % context.resolvers.len;
598 }
599 }
600
601 // We need to select the correct socket pool: IPv4 socket pool for IPv4 resolver/IPv6 socket pool for IPv6 resolver
602 buffer_t *interfaces;
603 if(lookup->resolver->address.ss_family == AF_INET)
604 {
605 interfaces = &context.sockets.interfaces4;
606 }
607 else
608 {
609 interfaces = &context.sockets.interfaces6;
610 }
611
612 if(lookup->socket == NULL)
613 {
614 // Pick a random socket from that pool
615 // Pool of sockets cannot be empty due to check when parsing resolvers. Socket creation must have succeeded.
616 size_t socket_index = urandom_size_t() % interfaces->len;
617 lookup->socket = (socket_info_t *) interfaces->data + socket_index;
618 }
619
620 ssize_t result = dns_question_create(query_buffer, (char*)lookup->key->name.name, lookup->key->type,
621 lookup->transaction);
622 if (result < DNS_PACKET_MINIMUM_SIZE)
623 {
624 log_msg("Failed to create DNS question for query \"%s\".", lookup->key->name.name);
625 return;
626 }
627
628 // Set or unset the QD bit based on user preference
629 dns_buf_set_rd(query_buffer, !context.cmd_args.norecurse);
630
631 errno = 0;
632 ssize_t sent = sendto(lookup->socket->descriptor, query_buffer, (size_t) result, 0,
633 (struct sockaddr *) &lookup->resolver->address,
634 sockaddr_storage_size(&lookup->resolver->address));
635 if(sent != result)
636 {
637 if(errno != EAGAIN && errno != EWOULDBLOCK)
638 {
639 log_msg("Error sending: %s\n", strerror(errno));
640 }
641 }
642 }
643
644 #define STAT_IDX_OK 0
645 #define STAT_IDX_NXDOMAIN 1
646 #define STAT_IDX_SERVFAIL 2
647 #define STAT_IDX_REFUSED 3
648 #define STAT_IDX_FORMERR 4
649
650 void my_stats_to_msg(stats_exchange_t *stats_msg)
651 {
652 stats_msg->finished = context.stats.finished;
653 stats_msg->finished_success = context.stats.finished_success;
654 stats_msg->fork_index = context.fork_index;
655 stats_msg->mismatch_domain = context.stats.mismatch_domain;
656 stats_msg->mismatch_id = context.stats.mismatch_id;
657 stats_msg->numdomains = context.stats.numdomains;
658 stats_msg->numreplies = context.stats.numreplies;
659 stats_msg->all_rcodes[STAT_IDX_OK] = context.stats.all_rcodes[DNS_RCODE_OK];
660 stats_msg->all_rcodes[STAT_IDX_NXDOMAIN] = context.stats.all_rcodes[DNS_RCODE_NXDOMAIN];
661 stats_msg->all_rcodes[STAT_IDX_SERVFAIL] = context.stats.all_rcodes[DNS_RCODE_SERVFAIL];
662 stats_msg->all_rcodes[STAT_IDX_REFUSED] = context.stats.all_rcodes[DNS_RCODE_REFUSED];
663 stats_msg->all_rcodes[STAT_IDX_FORMERR] = context.stats.all_rcodes[DNS_RCODE_FORMERR];
664 stats_msg->final_rcodes[STAT_IDX_OK] = context.stats.final_rcodes[DNS_RCODE_OK];
665 stats_msg->final_rcodes[STAT_IDX_NXDOMAIN] = context.stats.final_rcodes[DNS_RCODE_NXDOMAIN];
666 stats_msg->final_rcodes[STAT_IDX_SERVFAIL] = context.stats.final_rcodes[DNS_RCODE_SERVFAIL];
667 stats_msg->final_rcodes[STAT_IDX_REFUSED] = context.stats.final_rcodes[DNS_RCODE_REFUSED];
668 stats_msg->final_rcodes[STAT_IDX_FORMERR] = context.stats.final_rcodes[DNS_RCODE_FORMERR];
669 stats_msg->current_rate = context.stats.current_rate;
670 stats_msg->success_rate = context.stats.success_rate;
671 stats_msg->numparsed = context.stats.numparsed;
672 stats_msg->done = (context.state >= STATE_DONE);
673 for(size_t i = 0; i <= context.cmd_args.resolve_count; i++)
674 {
675 stats_msg->timeouts[i] = context.stats.timeouts[i];
676 }
677 }
678
679 void send_stats()
680 {
681 static stats_exchange_t stats_msg;
682
683 my_stats_to_msg(&stats_msg);
684
685 if(write(context.sockets.write_pipe.descriptor, &stats_msg, sizeof(stats_msg)) != sizeof(stats_msg))
686 {
687 log_msg("Could not send stats atomically.\n");
688 }
689 }
690
691 void check_progress()
692 {
693 static struct timespec last_time;
694 static char timeouts[4096];
695 static struct timespec now;
696
697 clock_gettime(CLOCK_MONOTONIC, &now);
698
699 time_t elapsed_ns = (now.tv_sec - last_time.tv_sec) * 1000000000 + (now.tv_nsec - last_time.tv_nsec);
700 size_t rate_pps = elapsed_ns == 0 ? 0 : context.stats.current_rate * TIMED_RING_S / elapsed_ns;
701 size_t rate_success = elapsed_ns == 0 ? 0 : context.stats.success_rate * TIMED_RING_S / elapsed_ns;
702 last_time = now;
703
704 // Send the stats of the child to the parent process
705 if(context.cmd_args.num_processes > 1 && context.fork_index != 0)
706 {
707 send_stats();
708 goto end_stats;
709 }
710
711 if(context.cmd_args.quiet)
712 {
713 return;
714 }
715
716 // Go on with printing stats.
717
718 float progress = context.state == STATE_DONE ? 1 : 0;
719 if(context.domainfile_size > 0) // If the domain file is not a real file, the progress cannot be estimated.
720 {
721 // Get a rough estimate of the progress, only roughly proportional to the number of domains.
722 // Will be very inaccurate if the domain file is sorted per domain name length.
723 long int domain_file_position = ftell(context.domainfile);
724 if (domain_file_position >= 0)
725 {
726 progress = domain_file_position / (float)context.domainfile_size;
727 }
728 }
729
730 time_t total_elapsed_ns = (now.tv_sec - context.stats.start_time.tv_sec) * 1000000000
731 + (now.tv_nsec - context.stats.start_time.tv_nsec); // since last output
732 long long elapsed = now.tv_sec - context.stats.start_time.tv_sec; // resolution of one second should be okay
733 long long sec = elapsed % 60;
734 long long min = (elapsed / 60) % 60;
735 long long h = elapsed / 3600;
736
737 long long estimated_time = progress == 0 ? 0 : (long long)(elapsed / progress);
738 if(estimated_time < elapsed)
739 {
740 estimated_time = elapsed;
741 }
742 long long prog_sec = estimated_time % 60;
743 long long prog_min = (estimated_time / 60) % 60;
744 long long prog_h = (estimated_time / 3600);
745
746 #define stats_percent(a, b) ((b) == 0 ? 0 : (a) / (float) (b) * 100)
747 #define stat_abs_share(a, b) a, stats_percent(a, b)
748 #define rcode_stat(code) stat_abs_share(context.stats.final_rcodes[(code)], context.stats.finished_success),\
749 stat_abs_share(context.stats.all_rcodes[(code)], context.stats.numparsed)
750 #define rcode_stat_multi(code) stat_abs_share(context.stat_messages[0].final_rcodes[(code)], \
751 context.stat_messages[0].finished_success),\
752 stat_abs_share(context.stat_messages[0].all_rcodes[(code)], context.stat_messages[0].numparsed)
753
754 if(context.cmd_args.num_processes == 1)
755 {
756 size_t average_pps = elapsed == 0 ? rate_pps : context.stats.numreplies * TIMED_RING_S / total_elapsed_ns;
757 size_t average_success = elapsed == 0 ? rate_success : context.stats.finished_success * TIMED_RING_S / total_elapsed_ns;
758
759 // Print the detailed timeout stats (number of tries before timeout) to the timeouts buffer.
760 int offset = 0;
761 for (size_t i = 0; i <= context.cmd_args.resolve_count; i++)
762 {
763 float share = stats_percent(context.stats.timeouts[i], context.stats.finished);
764 int result = snprintf(timeouts + offset, sizeof(timeouts) - offset, "%zu: %.2f%%, ", i, share);
765 if (result <= 0 || result >= sizeof(timeouts) - offset)
766 {
767 break;
768 }
769 offset += result;
770 }
771
772 fprintf(stderr,
773 context.status_fmt,
774 context.stats.numdomains,
775 context.stats.numreplies,
776 progress * 100, h, min, sec, prog_h, prog_min, prog_sec, rate_pps, average_pps,
777 rate_success, average_success,
778 context.stats.finished,
779 stat_abs_share(context.stats.finished_success, context.stats.finished),
780 stat_abs_share(context.stats.mismatch_domain, context.stats.numparsed),
781 stat_abs_share(context.stats.mismatch_id, context.stats.numparsed),
782 timeouts,
783
784 rcode_stat(DNS_RCODE_OK),
785 rcode_stat(DNS_RCODE_NXDOMAIN),
786 rcode_stat(DNS_RCODE_SERVFAIL),
787 rcode_stat(DNS_RCODE_REFUSED),
788 rcode_stat(DNS_RCODE_FORMERR)
789 );
790 fflush(stderr);
791 }
792 else
793 {
794 my_stats_to_msg(&context.stat_messages[0]);
795
796 for(size_t j = 1; j < context.cmd_args.num_processes; j++)
797 {
798 for (size_t i = 0; i <= context.cmd_args.resolve_count; i++)
799 {
800 context.stat_messages[0].timeouts[i] += context.stat_messages[j].timeouts[i];
801 }
802 context.stat_messages[0].numreplies += context.stat_messages[j].numreplies;
803 context.stat_messages[0].numparsed += context.stat_messages[j].numparsed;
804 context.stat_messages[0].numdomains += context.stat_messages[j].numdomains;
805 context.stat_messages[0].mismatch_id += context.stat_messages[j].mismatch_id;
806 context.stat_messages[0].mismatch_domain += context.stat_messages[j].mismatch_domain;
807 context.stat_messages[0].finished_success += context.stat_messages[j].finished_success;
808 context.stat_messages[0].finished += context.stat_messages[j].finished;
809 for(size_t i = 0; i < 5; i++)
810 {
811 context.stat_messages[0].all_rcodes[i] += context.stat_messages[j].all_rcodes[i];
812 }
813 for(size_t i = 0; i < 5; i++)
814 {
815 context.stat_messages[0].final_rcodes[i] += context.stat_messages[j].final_rcodes[i];
816 }
817 rate_pps += context.stat_messages[j].current_rate;
818 rate_success += context.stat_messages[j].success_rate;
819 }
820
821 size_t average_pps = elapsed == 0 ? rate_pps :
822 context.stat_messages[0].numreplies * TIMED_RING_S / total_elapsed_ns;
823 size_t average_success = elapsed == 0 ? rate_pps :
824 context.stat_messages[0].finished_success * TIMED_RING_S / total_elapsed_ns;
825
826
827 // Print the detailed timeout stats (number of tries before timeout) to the timeouts buffer.
828 int offset = 0;
829 for (size_t i = 0; i <= context.cmd_args.resolve_count; i++)
830 {
831 float share = stats_percent(context.stat_messages[0].timeouts[i], context.stat_messages[0].finished);
832 int result = snprintf(timeouts + offset, sizeof(timeouts) - offset, "%zu: %.2f%%, ", i, share);
833 if (result <= 0 || result >= sizeof(timeouts) - offset)
834 {
835 break;
836 }
837 offset += result;
838 }
839
840 fprintf(stderr,
841 context.status_fmt,
842 context.stat_messages[0].numdomains,
843 context.stat_messages[0].numreplies,
844 progress * 100, h, min, sec, prog_h, prog_min, prog_sec, rate_pps, average_pps,
845 rate_success, average_success,
846 context.stat_messages[0].finished,
847 stat_abs_share(context.stat_messages[0].finished_success, context.stat_messages[0].finished),
848 stat_abs_share(context.stat_messages[0].mismatch_domain, context.stat_messages[0].numparsed),
849 stat_abs_share(context.stat_messages[0].mismatch_id, context.stat_messages[0].numparsed),
850 timeouts,
851
852 rcode_stat_multi(STAT_IDX_OK),
853 rcode_stat_multi(STAT_IDX_NXDOMAIN),
854 rcode_stat_multi(STAT_IDX_SERVFAIL),
855 rcode_stat_multi(STAT_IDX_REFUSED),
856 rcode_stat_multi(STAT_IDX_FORMERR)
857 );
858 }
859
860 end_stats:
861 context.stats.current_rate = 0;
862 context.stats.success_rate = 0;
863 // Call this function in about one second again
864 timed_ring_add(&context.ring, TIMED_RING_S, check_progress);
865 }
866
867 void done()
868 {
869 context.done[context.fork_index] = true;
870 if(context.fork_index != 0 || context.cmd_args.num_processes == 1)
871 {
872 context.state = STATE_DONE;
873 }
874 else
875 {
876 context.finished++;
877 context.state = (context.finished < context.cmd_args.num_processes ? STATE_WAIT_CHILDREN : STATE_DONE);
878 }
879 if(context.cmd_args.num_processes > 1 && context.fork_index != 0)
880 {
881 send_stats();
882 }
883 check_progress();
884 }
885
886 void can_send()
887 {
888 char *qname;
889 bool new;
890
891 while (hashmapSize(context.map) < context.cmd_args.hashmap_size && context.state <= STATE_QUERYING)
892 {
893 if(!next_query(&qname))
894 {
895 if(hashmapSize(context.map) <= 0)
896 {
897 done();
898 return;
899 }
900 context.state = STATE_COOLDOWN; // We will not create any new queries
901 break;
902 }
903 context.stats.numdomains++;
904 lookup_t *lookup = new_lookup(qname, context.cmd_args.record_type, &new);
905 if(!new)
906 {
907 continue;
908 }
909 send_query(lookup);
910 }
911 }
912
913 bool is_unacceptable(dns_pkt_t *packet)
914 {
915 return context.cmd_args.retry_codes[packet->head.header.rcode];
916 }
917
918 void write_exhausted_tries(lookup_t *lookup, char *status)
919 {
920 if(context.cmd_args.output == OUTPUT_NDJSON && context.format.write_exhausted_tries) {
921 json_escape(json_buffer, sizeof(json_buffer), lookup->key->name.name, lookup->key->name.length);
922 fprintf(context.outfile,
923 "{\"name\":\"%s\",\"type\":\"%s\",\"class\":\"%s\",\"error\":\"%s\"}\n", json_buffer,
924 dns_record_type2str(lookup->key->type), "IN", status);
925 }
926 }
927
928 void lookup_done(lookup_t *lookup)
929 {
930 context.stats.finished++;
931
932 hashmapRemove(context.map, lookup->key);
933
934 // Return lookup to pool.
935 // According to ISO/IEC 9899:TC2 §6.7.2.1 (13), structs are not padded at the beginning
936 ((lookup_key_t**)context.lookup_pool.data)[context.lookup_pool.len++] = lookup->key;
937
938
939 // When transmission is not aggressive, we only start a new lookup after another one has finished.
940 // When our transmission is very aggressive, we also start a new lookup, although we listen for EPOLLOUT
941 // events as well.
942 if(context.cmd_args.extreme == 0 || context.cmd_args.extreme == 2)
943 {
944 can_send();
945 }
946
947 if(context.state == STATE_COOLDOWN && hashmapSize(context.map) <= 0)
948 {
949 done();
950 }
951 }
952
953 bool retry(lookup_t *lookup)
954 {
955 context.stats.timeouts[lookup->tries]--;
956 context.stats.timeouts[++lookup->tries]++;
957 if(lookup->tries < context.cmd_args.resolve_count)
958 {
959 lookup->ring_entry = timed_ring_add(&context.ring, context.cmd_args.interval_ms * TIMED_RING_MS, lookup);
960 send_query(lookup);
961 return true;
962 }
963 return false;
964 }
965
966 void ring_timeout(void *param)
967 {
968 if(param == check_progress)
969 {
970 check_progress();
971 return;
972 }
973
974 lookup_t *lookup = param;
975 if(!retry(lookup))
976 {
977 write_exhausted_tries(lookup, "TIMEOUT");
978 lookup_done(lookup);
979 }
980 }
981
982 void do_read(uint8_t *offset, size_t len, struct sockaddr_storage *recvaddr)
983 {
984 static dns_pkt_t packet;
985 static uint8_t *parse_offset;
986 static lookup_t *lookup;
987 static resolver_t* resolver;
988
989 context.stats.current_rate++;
990 context.stats.numreplies++;
991
992 if(context.cmd_args.verify_ip)
993 {
994 resolver = hashmapGet(context.resolver_map, recvaddr);
995 if(resolver == NULL)
996 {
997 //log_msg("Fake/NAT reply from %s\n", sockaddr2str(recvaddr));
998 return;
999 }
1000 }
1001
1002 if(!dns_parse_question(offset, len, &packet.head, &parse_offset))
1003 {
1004 return;
1005 }
1006
1007 context.stats.numparsed++;
1008 context.stats.all_rcodes[packet.head.header.rcode]++;
1009
1010 // TODO: Remove unnecessary copy.
1011 //search_key.domain = (char*)packet.head.question.name.name;
1012 lookup = hashmapGet(context.map, &packet.head.question);
1013 if(!lookup) // Most likely reason: delayed response after duplicate query
1014 {
1015 context.stats.mismatch_domain++;
1016 return;
1017 }
1018
1019 if(lookup->transaction != packet.head.header.id)
1020 {
1021 context.stats.mismatch_id++;
1022 return;
1023 }
1024
1025 timed_ring_remove(&context.ring, lookup->ring_entry); // Clear timeout trigger
1026
1027 // Check whether we want to retry resending the packet
1028 if(is_unacceptable(&packet))
1029 {
1030 // We may have tried to many times already.
1031 if(!retry(lookup))
1032 {
1033 write_exhausted_tries(lookup, "MAXRETRIES");
1034 // If this is the case, we will not try again.
1035 lookup_done(lookup);
1036 }
1037 }
1038 else
1039 {
1040 // We are done with the lookup because we received an acceptable reply.
1041 context.stats.finished_success++;
1042 context.stats.final_rcodes[packet.head.header.rcode]++;
1043 context.stats.success_rate++;
1044
1045 // Print packet
1046 time_t now = time(NULL);
1047 uint16_t short_len = (uint16_t) len;
1048 uint8_t *next = parse_offset;
1049 dns_record_t rec;
1050 size_t non_add_count = packet.head.header.ans_count + packet.head.header.auth_count;
1051 dns_section_t section = DNS_SECTION_ANSWER;
1052 size_t section_index = 0;
1053 bool section_emitted = false;
1054
1055 switch(context.cmd_args.output)
1056 {
1057 case OUTPUT_BINARY:
1058 // The output file is platform dependent for performance reasons.
1059 fwrite(&now, sizeof(now), 1, context.outfile);
1060 fwrite(recvaddr, sizeof(*recvaddr), 1, context.outfile);
1061 fwrite(&short_len, sizeof(short_len), 1, context.outfile);
1062 fwrite(offset, short_len, 1, context.outfile);
1063 break;
1064
1065 case OUTPUT_TEXT_FULL: // Print packet similar to dig style
1066 // Resolver and timestamp are not part of the packet, we therefore have to print it manually
1067 fprintf(context.outfile, ";; Server: %s\n;; Size: %" PRIu16 "\n;; Unix time: %lu\n",
1068 sockaddr2str(recvaddr), short_len, now);
1069 dns_print_packet(context.outfile, &packet, offset, len, next);
1070 break;
1071
1072 case OUTPUT_NDJSON: // Only print records from answer section that match the query name (in ndjson)
1073 json_escape(json_buffer, sizeof(json_buffer), packet.head.question.name.name, packet.head.question.name.length);
1074 fprintf(context.outfile,
1075 "{\"name\":\"%s\",\"type\":\"%s\",\"class\":\"%s\",\"status\":\"%s\",\"data\":{",
1076 json_buffer,
1077 dns_record_type2str((dns_record_type) packet.head.question.type),
1078 dns_class2str((dns_class) packet.head.question.class),
1079 dns_rcode2str((dns_rcode) packet.head.header.rcode));
1080 for(size_t rec_index = 0; dns_parse_record_raw(offset, next, offset + len, &next, &rec); rec_index++, section_index++)
1081 {
1082 if(section == DNS_SECTION_ANSWER && section_index >= packet.head.header.ans_count) {
1083 section_index = 0;
1084 section++;
1085 }
1086 if(section == DNS_SECTION_AUTHORITY && section_index >= packet.head.header.auth_count) {
1087 section_index = 0;
1088 section++;
1089 }
1090 if(section == DNS_SECTION_ADDITIONAL && section_index >= packet.head.header.add_count) {
1091 section_index = 0;
1092 section++;
1093 }
1094 if(section_index == 0) {
1095 fprintf(context.outfile, "%s\"%s\":[", section_emitted ? "]," : "",
1096 dns_section2str_lower_plural(section));
1097 }
1098 else
1099 {
1100 fputs(",", context.outfile);
1101 }
1102 json_escape(json_buffer, sizeof(json_buffer), rec.name.name, rec.name.length);
1103
1104 fprintf(context.outfile,
1105 "{\"ttl\":%" PRIu32 ",\"type\":\"%s\",\"class\":\"%s\",\"name\":\"%s\",\"data\":\"",
1106 rec.ttl,
1107 dns_record_type2str((dns_record_type) rec.type),
1108 dns_class2str((dns_class) rec.class),
1109 json_buffer);
1110 section_emitted = true;
1111 json_escape_str(json_buffer, sizeof(json_buffer),
1112 dns_raw_record_data2str(&rec, offset, offset + short_len));
1113 fputs(json_buffer, context.outfile);
1114 fprintf(context.outfile, "\"}");
1115 }
1116 fprintf(context.outfile, "%s},\"resolver\":\"%s\"}\n", section_emitted ? "]" : "",
1117 sockaddr2str(recvaddr));
1118
1119 break;
1120
1121 case OUTPUT_TEXT_SIMPLE: // Only print records from answer section that match the query name
1122 if(context.format.print_question)
1123 {
1124 if(!context.format.include_meta)
1125 {
1126 fprintf(context.outfile,
1127 "%s %s %s\n",
1128 dns_name2str(&packet.head.question.name),
1129 context.format.ttl ? dns_class2str((dns_class) packet.head.question.class) : "",
1130 dns_record_type2str((dns_record_type) packet.head.question.type));
1131 }
1132 else
1133 {
1134 fprintf(context.outfile,
1135 "%s %lu %s %s %s %s\n",
1136 sockaddr2str(recvaddr),
1137 now,
1138 dns_rcode2str((dns_rcode)packet.head.header.rcode),
1139 dns_name2str(&packet.head.question.name),
1140 context.format.ttl ? dns_class2str((dns_class) packet.head.question.class) : "",
1141 dns_record_type2str((dns_record_type) packet.head.question.type));
1142 }
1143 }
1144 for(size_t rec_index = 0; dns_parse_record_raw(offset, next, offset + len, &next, &rec); rec_index++)
1145 {
1146 char *section_separator = "";
1147 if(rec_index >= packet.head.header.ans_count)
1148 {
1149 if(rec_index >= non_add_count)
1150 {
1151 // We are entering a new section
1152 if(context.format.separate_sections && section != DNS_SECTION_ADDITIONAL)
1153 {
1154 section_separator = "\n";
1155 }
1156 section = DNS_SECTION_ADDITIONAL;
1157 }
1158 else
1159 {
1160 // We are entering a new section
1161 if(context.format.separate_sections && section != DNS_SECTION_AUTHORITY)
1162 {
1163 section_separator = "\n";
1164 }
1165 section = DNS_SECTION_AUTHORITY;
1166 }
1167 }
1168
1169 if((context.format.match_name && !dns_names_eq(&rec.name, &packet.head.question.name))
1170 || !context.format.sections[section])
1171 {
1172 continue;
1173 }
1174 if(!context.format.ttl)
1175 {
1176 fprintf(context.outfile,
1177 "%s%s%s %s %s\n",
1178 section_separator,
1179 context.format.indent_sections ? "\t" : "",
1180 dns_name2str(&rec.name),
1181 dns_record_type2str((dns_record_type) rec.type),
1182 dns_raw_record_data2str(&rec, offset, offset + short_len));
1183 }
1184 else
1185 {
1186 fprintf(context.outfile,
1187 "%s%s%s %s %" PRIu32 " %s %s\n",
1188 section_separator,
1189 context.format.indent_sections ? "\t" : "",
1190 dns_name2str(&rec.name),
1191 dns_class2str((dns_class)rec.class),
1192 rec.ttl,
1193 dns_record_type2str((dns_record_type) rec.type),
1194 dns_raw_record_data2str(&rec, offset, offset + short_len));
1195 }
1196 }
1197 if(context.format.separate_queries)
1198 {
1199 fprintf(context.outfile, "\n");
1200 }
1201 break;
1202 }
1203
1204 lookup_done(lookup);
1205
1206 // Sometimes, users may want to obtain results immediately.
1207 if(context.cmd_args.flush)
1208 {
1209 fflush(context.outfile);
1210 }
1211 }
1212 }
1213
1214 #ifdef PCAP_SUPPORT
1215 void pcap_callback(u_char *arg, const struct pcap_pkthdr *header, const u_char *packet)
1216 {
1217 static struct sockaddr_storage addr;
1218 static size_t len;
1219 static const uint8_t *frame;
1220 static ssize_t remaining;
1221
1222 // We expect at least an Ethernet header + IPv4/IPv6 header (>= 20) + UDP header
1223 if(header->len < 42)
1224 {
1225 return;
1226 }
1227 frame = ((uint8_t*)packet) + 14;
1228 remaining = header->len - 14;
1229
1230 if(((struct ether_header*)packet)->ether_type == context.ether_type_ip)
1231 {
1232 unsigned int ip_hdr_len = ((struct iphdr *) frame)->ihl * 4;
1233 remaining -= ip_hdr_len;
1234
1235 // Check whether the packet is long enough to still contain a UDP frame
1236 if(((struct iphdr *) frame)->protocol != 17
1237 || remaining < 0)
1238 {
1239 return;
1240 }
1241 frame += ip_hdr_len;
1242 len = (size_t)remaining;
1243 remaining -= ntohs(((struct udphdr *) frame)->len);
1244 if(remaining != 0)
1245 {
1246 return;
1247 }
1248 frame += 8;
1249 addr.ss_family = AF_INET;
1250 }
1251 else
1252 {
1253 return;
1254 }
1255 do_read((uint8_t*)frame, len, &addr);
1256 }
1257
1258 void pcap_can_read()
1259 {
1260 pcap_dispatch(context.pcap, 1, pcap_callback, NULL);
1261 }
1262 #endif
1263
1264 void can_read(socket_info_t *info)
1265 {
1266 static uint8_t readbuf[0xFFFF];
1267 static struct sockaddr_storage recvaddr;
1268 static socklen_t fromlen;
1269 static ssize_t num_received;
1270
1271
1272
1273 fromlen = sizeof(recvaddr);
1274 num_received = recvfrom(info->descriptor, readbuf, sizeof(readbuf), 0, (struct sockaddr *) &recvaddr, &fromlen);
1275 if(num_received <= 0)
1276 {
1277 return;
1278 }
1279
1280 do_read(readbuf, (size_t)num_received, &recvaddr);
1281 }
1282
1283 bool cmp_lookup(void *lookup1, void *lookup2)
1284 {
1285 return dns_names_eq(&((lookup_key_t *) lookup1)->name, &((lookup_key_t *) lookup2)->name);
1286 //return strcasecmp(((lookup_key_t *) lookup1)->domain,((lookup_key_t *) lookup2)->domain) == 0;
1287 }
1288
1289 void binfile_write_head()
1290 {
1291 // Write file type signature including null character
1292 char signature[] = "massdns";
1293 fwrite(signature, sizeof(signature), 1, context.outfile);
1294
1295 // Write a uint32_t integer in native byte order to allow detection of endianness
1296 uint32_t endianness = 0x12345678;
1297 fwrite(&endianness, sizeof(endianness), 1, context.outfile);
1298
1299 // Write uint32_t file version number
1300 // Number is to be incremented if file format is changed
1301 fwrite(&OUTPUT_BINARY_VERSION, sizeof(OUTPUT_BINARY_VERSION), 1, context.outfile);
1302
1303 // Write byte length of native size_t type
1304 uint8_t size_t_len = sizeof(size_t);
1305 fwrite(&size_t_len, sizeof(size_t_len), 1, context.outfile);
1306
1307 // Write size of time_t
1308 size_t time_t_len = sizeof(time_t);
1309 fwrite(&time_t_len, sizeof(time_t_len), 1, context.outfile);
1310
1311 // Write byte length of sockaddr_storage size
1312 size_t sockaddr_storage_len = sizeof(struct sockaddr_storage);
1313 fwrite(&sockaddr_storage_len, sizeof(sockaddr_storage_len), 1, context.outfile);
1314
1315 // Write offset of ss_family within sockaddr_storage
1316 size_t ss_family_offset = offsetof(struct sockaddr_storage, ss_family);
1317 fwrite(&ss_family_offset, sizeof(ss_family_offset), 1, context.outfile);
1318
1319 // Write size of sa_family_size within sockaddr_storage
1320 size_t sa_family_size = sizeof(sa_family_t);
1321 fwrite(&sa_family_size, sizeof(sa_family_size), 1, context.outfile);
1322
1323 // Write size of in_port_t
1324 size_t sin_port_len = sizeof(in_port_t);
1325 fwrite(&sin_port_len, sizeof(sin_port_len), 1, context.outfile);
1326
1327
1328 // Write IPv4 family constant
1329 sa_family_t family_inet = AF_INET;
1330 fwrite(&family_inet, sizeof(family_inet), 1, context.outfile);
1331
1332 // Write offset of sin_addr within sockaddr_in
1333 size_t sin_addr_offset = offsetof(struct sockaddr_in, sin_addr);
1334 fwrite(&sin_addr_offset, sizeof(sin_addr_offset), 1, context.outfile);
1335
1336 // Write offset of sin_port within sockaddr_in
1337 size_t sin_port_offset = offsetof(struct sockaddr_in, sin_port);
1338 fwrite(&sin_port_offset, sizeof(sin_port_offset), 1, context.outfile);
1339
1340
1341 // Write IPv6 family constant
1342 sa_family_t family_inet6 = AF_INET6;
1343 fwrite(&family_inet6, sizeof(family_inet6), 1, context.outfile);
1344
1345 // Write offset of sin6_addr within sockaddr_in6
1346 size_t sin6_addr_offset = offsetof(struct sockaddr_in6, sin6_addr);
1347 fwrite(&sin6_addr_offset, sizeof(sin6_addr_offset), 1, context.outfile);
1348
1349 // Write offset of sin6_port within sockaddr_in6
1350 size_t sin6_port_offset = offsetof(struct sockaddr_in6, sin6_port);
1351 fwrite(&sin6_port_offset, sizeof(sin6_port_offset), 1, context.outfile);
1352 }
1353
1354 void privilege_drop()
1355 {
1356 if (geteuid() != 0)
1357 {
1358 return;
1359 }
1360 char *username = context.cmd_args.drop_user ? context.cmd_args.drop_user : COMMON_UNPRIVILEGED_USER;
1361 char *groupname = context.cmd_args.drop_group ? context.cmd_args.drop_group : COMMON_UNPRIVILEGED_GROUP;
1362 if(!context.cmd_args.root)
1363 {
1364 struct passwd *drop_user = getpwnam(username);
1365 struct group *drop_group = getgrnam(groupname);
1366 if (drop_group && drop_user && setgid(drop_group->gr_gid) == 0 && setuid(drop_user->pw_uid) == 0)
1367 {
1368 if (!context.cmd_args.quiet)
1369 {
1370 log_msg("Privileges have been dropped to \"%s:%s\" for security reasons.\n", username, groupname);
1371 }
1372 }
1373 else
1374 {
1375 log_msg("Privileges could not be dropped to \"%s:%s\".\n"
1376 "For security reasons, this program will only run as root user when supplied with --root, "
1377 "which is not recommended.\n"
1378 "It is better practice to run this program as a different user.\n", username, groupname);
1379 clean_exit(EXIT_FAILURE);
1380 }
1381 }
1382 else
1383 {
1384 if (!context.cmd_args.quiet)
1385 {
1386 log_msg("[WARNING] Privileges were not dropped. This is not recommended.\n");
1387 }
1388 }
1389 }
1390
1391 #ifdef PCAP_SUPPORT
1392 void pcap_setup()
1393 {
1394 context.pcap_dev = pcap_lookupdev(context.pcap_error);
1395 if(context.pcap_dev == NULL)
1396 {
1397 goto pcap_error;
1398 }
1399 log_msg("Default pcap device: %s", context.pcap_dev);
1400
1401
1402 char mac_filter[sizeof("ether dst ") - 1 + MAC_READABLE_BUFLEN];
1403 char *mac_readable = mac_filter + sizeof("ether dst ") - 1;
1404 strcpy(mac_filter, "ether dst ");
1405
1406 if(get_iface_hw_addr_readable(context.pcap_dev, mac_readable) != 0)
1407 {
1408 log_msg("\nFailed to determine the hardware address of the device.\n");
1409 goto pcap_error_noprint;
1410 }
1411 log_msg(", address: %s\n", mac_readable);
1412
1413
1414 context.pcap = pcap_create(context.pcap_dev, context.pcap_error);
1415 if(context.pcap == NULL)
1416 {
1417 goto pcap_error;
1418 }
1419
1420 if(pcap_set_snaplen(context.pcap, 0xFFFF) != 0)
1421 {
1422 goto pcap_error;
1423 }
1424
1425 if(pcap_setnonblock(context.pcap, 1, context.pcap_error) == -1)
1426 {
1427 goto pcap_error;
1428 }
1429
1430 if(pcap_set_buffer_size(context.pcap, 1024 * 1024) != 0)
1431 {
1432 goto pcap_error;
1433 }
1434
1435 int activation_status = pcap_activate(context.pcap);
1436 if(activation_status != 0)
1437 {
1438 log_msg("Error during pcap activation: %s\n", pcap_statustostr(activation_status));
1439 goto pcap_error_noprint;
1440 }
1441
1442 if(pcap_compile(context.pcap, &context.pcap_filter, mac_filter, 0, PCAP_NETMASK_UNKNOWN) != 0)
1443 {
1444 log_msg("Error during pcap filter compilation: %s\n", pcap_geterr(context.pcap));
1445 goto pcap_error_noprint;
1446 }
1447
1448 if(pcap_setfilter(context.pcap, &context.pcap_filter) != 0)
1449 {
1450 log_msg("Error setting pcap filter: %s\n", pcap_geterr(context.pcap));
1451 goto pcap_error_noprint;
1452 }
1453
1454 context.pcap_info.descriptor = pcap_get_selectable_fd(context.pcap);
1455 if(context.pcap_info.descriptor < 0)
1456 {
1457 goto pcap_error;
1458 }
1459 #ifdef HAVE_EPOLL
1460 struct epoll_event ev;
1461 bzero(&ev, sizeof(ev));
1462 ev.data.ptr = &context.pcap_info;
1463 ev.events = EPOLLIN;
1464 if (epoll_ctl(context.epollfd, EPOLL_CTL_ADD, context.pcap_info.descriptor, &ev) != 0)
1465 {
1466 log_msg("Failed to add epoll event: %s\n", strerror(errno));
1467 clean_exit(EXIT_FAILURE);
1468 }
1469 #endif
1470 return;
1471
1472 pcap_error:
1473 log_msg("Error during pcap setup: %s\n", context.pcap_error);
1474 pcap_error_noprint:
1475 cleanup();
1476 clean_exit(EXIT_FAILURE);
1477 }
1478 #endif
1479
1480 void init_pipes()
1481 {
1482 // We don't need any pipes if the process is not forked
1483 if(context.cmd_args.num_processes <= 1)
1484 {
1485 return;
1486 }
1487
1488 // Otherwise create a unidirectional pipe for reading and writing from every fork
1489 context.sockets.pipes = safe_malloc(sizeof(*context.sockets.pipes) * 2 * context.cmd_args.num_processes);
1490 for(size_t i = 0; i < context.cmd_args.num_processes; i++)
1491 {
1492 if(pipe(context.sockets.pipes + i * 2) != 0)
1493 {
1494 log_msg("Pipe failed: %s\n", strerror(errno));
1495 clean_exit(EXIT_FAILURE);
1496 }
1497 }
1498
1499 }
1500
1501 void setup_pipes()
1502 {
1503 if(context.fork_index == 0) // We are in the main process
1504 {
1505 context.sockets.master_pipes_read = safe_calloc(sizeof(socket_info_t) * context.cmd_args.num_processes);
1506
1507 // Close all pipes that the children use to write
1508 for (size_t i = 0; i < context.cmd_args.num_processes; i++)
1509 {
1510 close(context.sockets.pipes[2 * i + 1]);
1511 context.sockets.pipes[2 * i + 1] = -1;
1512
1513 context.sockets.master_pipes_read[i].descriptor = context.sockets.pipes[2 * i];
1514 context.sockets.master_pipes_read[i].type = SOCKET_TYPE_CONTROL;
1515 context.sockets.master_pipes_read[i].data = (void*)i;
1516
1517 if(context.cmd_args.busypoll)
1518 {
1519 continue;
1520 }
1521
1522 #ifdef HAVE_EPOLL
1523 // Add all pipes the main process can read from to the epoll descriptor
1524 struct epoll_event ev;
1525 bzero(&ev, sizeof(ev));
1526 ev.data.ptr = &context.sockets.master_pipes_read[i];
1527 ev.events = EPOLLIN;
1528 if (epoll_ctl(context.epollfd, EPOLL_CTL_ADD, context.sockets.master_pipes_read[i].descriptor, &ev) != 0)
1529 {
1530 log_msg("Failed to add epoll event: %s\n", strerror(errno));
1531 clean_exit(EXIT_FAILURE);
1532 }
1533 #endif
1534 }
1535 }
1536 else // It's a child process
1537 {
1538 // Close all pipes except the two belonging to the current process
1539 for (size_t i = 0; i < context.cmd_args.num_processes; i++)
1540 {
1541 if (i == context.fork_index)
1542 {
1543 continue;
1544 }
1545 close(context.sockets.pipes[2 * i]);
1546 close(context.sockets.pipes[2 * i + 1]);
1547 context.sockets.pipes[2 * i] = -1;
1548 context.sockets.pipes[2 * i + 1] = -1;
1549 }
1550 context.sockets.write_pipe.descriptor = context.sockets.pipes[2 * context.fork_index + 1];
1551 context.sockets.write_pipe.type = SOCKET_TYPE_CONTROL;
1552 close(context.sockets.pipes[2 * context.fork_index]);
1553 context.sockets.pipes[2 * context.fork_index] = -1;
1554 }
1555 }
1556
1557 void read_control_message(socket_info_t *socket_info)
1558 {
1559 size_t process = (size_t)socket_info->data;
1560 ssize_t read_result = read(socket_info->descriptor, context.stat_messages + process, sizeof(stats_exchange_t));
1561 if(read_result > 0 && read_result < sizeof(stats_exchange_t))
1562 {
1563 log_msg("Atomic read failed: Read %ld bytes.\n", read_result);
1564 }
1565 if(!context.done[process] && context.stat_messages[process].done)
1566 {
1567 context.finished++;
1568 context.done[process] = true;
1569 }
1570 }
1571
1572 void make_query_sockets_nonblocking()
1573 {
1574 for(size_t i = 0; i < context.sockets.interfaces4.len; i++)
1575 {
1576 socket_noblock(((socket_info_t*)context.sockets.interfaces4.data) + i);
1577 }
1578 for(size_t i = 0; i < context.sockets.interfaces6.len; i++)
1579 {
1580 socket_noblock(((socket_info_t*)context.sockets.interfaces6.data) + i);
1581 }
1582 }
1583
1584 void run()
1585 {
1586 static char multiproc_outfile_name[8192];
1587
1588 if(!urandom_init())
1589 {
1590 log_msg("Failed to open /dev/urandom: %s\n", strerror(errno));
1591 clean_exit(EXIT_FAILURE);
1592 }
1593
1594 context.map = hashmapCreate(context.cmd_args.hashmap_size, hash_lookup_key, cmp_lookup);
1595 if(context.map == NULL)
1596 {
1597 log_msg("Failed to create hashmap.\n");
1598 clean_exit(EXIT_FAILURE);
1599 }
1600
1601 context.lookup_pool.len = context.cmd_args.hashmap_size;
1602 context.lookup_pool.data = safe_calloc(context.lookup_pool.len * sizeof(void*));
1603 context.lookup_space = safe_calloc(context.lookup_pool.len * sizeof(*context.lookup_space));
1604 for(size_t i = 0; i < context.lookup_pool.len; i++)
1605 {
1606 ((lookup_entry_t**)context.lookup_pool.data)[i] = context.lookup_space + i;
1607 }
1608
1609 timed_ring_init(&context.ring, max(context.cmd_args.interval_ms, 1000), 2 * TIMED_RING_MS, context.cmd_args.timed_ring_buckets);
1610
1611 #ifdef HAVE_EPOLL
1612 uint32_t socket_events = EPOLLOUT;
1613
1614 struct epoll_event pevents[100000];
1615 bzero(pevents, sizeof(pevents));
1616 #endif
1617
1618 init_pipes();
1619 context.pids = safe_calloc(context.cmd_args.num_processes * sizeof(*context.pids));
1620 context.done = safe_calloc(context.cmd_args.num_processes * sizeof(*context.done));
1621 context.fork_index = split_process(context.cmd_args.num_processes, context.pids);
1622 #ifdef HAVE_EPOLL
1623 if(!context.cmd_args.busypoll)
1624 {
1625 context.epollfd = epoll_create(1);
1626 }
1627 #endif
1628 #ifdef PCAP_SUPPORT
1629 if(context.cmd_args.use_pcap)
1630 {
1631 pcap_setup();
1632 }
1633 else
1634 #endif
1635 #ifdef HAVE_EPOLL
1636 {
1637 socket_events |= EPOLLIN;
1638 }
1639 #endif
1640 if(context.cmd_args.num_processes > 1)
1641 {
1642 setup_pipes();
1643 if(context.fork_index == 0)
1644 {
1645 context.stat_messages = safe_calloc(context.cmd_args.num_processes * sizeof(stats_exchange_t));
1646 }
1647 }
1648
1649 if(strcmp(context.cmd_args.outfile_name, "-") != 0)
1650 {
1651 if(context.cmd_args.num_processes > 1)
1652 {
1653 snprintf(multiproc_outfile_name, sizeof(multiproc_outfile_name), "%s%zd", context.cmd_args.outfile_name,
1654 context.fork_index);
1655 context.outfile = fopen(multiproc_outfile_name, "w");
1656 }
1657 else
1658 {
1659 context.outfile = fopen(context.cmd_args.outfile_name, "w");
1660 }
1661 if(!context.outfile)
1662 {
1663 log_msg("Failed to open output file: %s\n", strerror(errno));
1664 clean_exit(EXIT_FAILURE);
1665 }
1666 }
1667 else
1668 {
1669 if(context.cmd_args.num_processes > 1)
1670 {
1671 log_msg("Multiprocessing is currently only supported through the -w parameter.\n");
1672 clean_exit(EXIT_FAILURE);
1673 }
1674 }
1675
1676 if(context.domainfile != stdin)
1677 {
1678 context.domainfile = fopen(context.cmd_args.domains, "r");
1679 if (context.domainfile == NULL)
1680 {
1681 log_msg("Failed to open domain file \"%s\".\n", context.cmd_args.domains);
1682 clean_exit(EXIT_FAILURE);
1683 }
1684 }
1685
1686 if(context.cmd_args.output == OUTPUT_BINARY)
1687 {
1688 binfile_write_head();
1689 }
1690
1691
1692 // It is important to call default interface sockets setup before reading the resolver list
1693 // because that way we can warn if the socket creation for a certain IP protocol failed although a resolver
1694 // requires the protocol.
1695 query_sockets_setup();
1696 context.resolvers = massdns_resolvers_from_file(context.cmd_args.resolvers);
1697
1698 privilege_drop();
1699
1700 #ifdef HAVE_EPOLL
1701 if(!context.cmd_args.busypoll)
1702 {
1703 add_sockets(context.epollfd, socket_events, EPOLL_CTL_ADD, &context.sockets.interfaces4);
1704 add_sockets(context.epollfd, socket_events, EPOLL_CTL_ADD, &context.sockets.interfaces6);
1705 }
1706 #endif
1707 if(context.cmd_args.busypoll)
1708 {
1709 make_query_sockets_nonblocking();
1710 }
1711
1712
1713 clock_gettime(CLOCK_MONOTONIC, &context.stats.start_time);
1714 check_progress();
1715
1716 if(!context.cmd_args.busypoll)
1717 {
1718 #ifdef HAVE_EPOLL
1719 while(context.state < STATE_DONE)
1720 {
1721
1722 int ready = epoll_wait(context.epollfd, pevents, sizeof(pevents) / sizeof(pevents[0]), 1);
1723 if (ready < 0)
1724 {
1725 log_msg("Epoll failure: %s\n", strerror(errno));
1726 }
1727 else if (ready == 0) // Epoll timeout
1728 {
1729 timed_ring_handle(&context.ring, ring_timeout);
1730 }
1731 else if (ready > 0)
1732 {
1733 for (int i = 0; i < ready; i++)
1734 {
1735 socket_info_t *socket_info = pevents[i].data.ptr;
1736 if ((pevents[i].events & EPOLLOUT) && socket_info->type == SOCKET_TYPE_QUERY)
1737 {
1738 can_send();
1739 timed_ring_handle(&context.ring, ring_timeout);
1740 }
1741 if ((pevents[i].events & EPOLLIN) && socket_info->type == SOCKET_TYPE_QUERY)
1742 {
1743 can_read(socket_info);
1744 }
1745 #ifdef PCAP_SUPPORT
1746 else if((pevents[i].events & EPOLLIN) && socket_info == &context.pcap_info)
1747 {
1748 pcap_can_read();
1749 }
1750 #endif
1751 else if ((pevents[i].events & EPOLLIN) && socket_info->type == SOCKET_TYPE_CONTROL)
1752 {
1753 read_control_message(socket_info);
1754 if(context.finished >= context.cmd_args.num_processes)
1755 {
1756 context.state = STATE_DONE;
1757 break;
1758 }
1759 }
1760 }
1761 timed_ring_handle(&context.ring, ring_timeout);
1762 }
1763 }
1764 #endif
1765 }
1766 else
1767 {
1768 while(context.state < STATE_DONE)
1769 {
1770 can_send();
1771 for(size_t i = 0; i < context.sockets.interfaces4.len; i++)
1772 {
1773 can_read(((socket_info_t*)context.sockets.interfaces4.data) + i);
1774 }
1775 for(size_t i = 0; i < context.sockets.interfaces6.len; i++)
1776 {
1777 can_read(((socket_info_t*)context.sockets.interfaces6.data) + i);
1778 }
1779 timed_ring_handle(&context.ring, ring_timeout);
1780
1781 if(context.cmd_args.num_processes > 1 && context.fork_index == 0)
1782 {
1783 for (size_t i = 1; i < context.cmd_args.num_processes; i++)
1784 {
1785 read_control_message(context.sockets.master_pipes_read + i);
1786 }
1787 if(context.finished >= context.cmd_args.num_processes)
1788 {
1789 context.state = STATE_DONE;
1790 break;
1791 }
1792 }
1793 }
1794 }
1795 }
1796
1797 #define STATUS_FORMAT_OPTIONS 2
1798 // Set the real-time status format string. The ansi format is used by default
1799 const char * get_status_format_string(char *arg) {
1800 status_format_map_t status_fmt_map[STATUS_FORMAT_OPTIONS] = {
1801 { "ansi", stats_fmt_ansi },
1802 { "json", stats_fmt_json }};
1803 int i;
1804
1805 for (i=0; i<STATUS_FORMAT_OPTIONS; i++) {
1806 if (!strcmp(arg, status_fmt_map[i].name))
1807 return status_fmt_map[i].status_fmt;
1808 }
1809 log_msg("Invalid status format specified.\n");
1810 clean_exit(EXIT_FAILURE);
1811 return NULL;
1812 }
1813
1814 void use_stdin()
1815 {
1816 if (!context.cmd_args.quiet)
1817 {
1818 log_msg("Reading domain list from stdin.\n");
1819 }
1820 context.domainfile = stdin;
1821 }
1822
1823 int parse_cmd(int argc, char **argv)
1824 {
1825 bool domain_param = false;
1826
1827 context.cmd_args.argc = argc;
1828 context.cmd_args.argv = argv;
1829 context.cmd_args.help_function = print_help;
1830
1831 if (argc <= 1)
1832 {
1833 print_help();
1834 clean_exit(EXIT_FAILURE);
1835 }
1836
1837 #ifdef PCAP_SUPPORT
1838 // Precompute values so we do not have to call htons for each incoming packet
1839 context.ether_type_ip = htons(ETHERTYPE_IP);
1840 context.ether_type_ip6 = htons(ETHERTYPE_IPV6);
1841 #endif
1842
1843 context.cmd_args.record_type = DNS_REC_INVALID;
1844 context.domainfile_size = -1;
1845 context.state = STATE_WARMUP;
1846 context.logfile = stderr;
1847 context.outfile = stdout;
1848 context.cmd_args.outfile_name = "-";
1849
1850 context.format.match_name = true;
1851 context.format.sections[DNS_SECTION_ANSWER] = true;
1852
1853 context.status_fmt = stats_fmt_ansi;
1854
1855 context.cmd_args.resolve_count = 50;
1856 context.cmd_args.hashmap_size = 10000;
1857 context.cmd_args.interval_ms = 500;
1858 context.cmd_args.timed_ring_buckets = 10000;
1859 context.cmd_args.output = OUTPUT_TEXT_FULL;
1860 context.cmd_args.retry_codes[DNS_RCODE_REFUSED] = true;
1861 context.cmd_args.num_processes = 1;
1862 context.cmd_args.socket_count = 1;
1863 #ifndef HAVE_EPOLL
1864 context.cmd_args.busypoll = true;
1865 #endif
1866
1867 for (int i = 1; i < argc; i++)
1868 {
1869 if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0)
1870 {
1871 print_help();
1872 clean_exit(EXIT_SUCCESS);
1873 }
1874 else if (strcmp(argv[i], "--busypoll") == 0 || strcmp(argv[i], "--busy-poll") == 0)
1875 {
1876 context.cmd_args.busypoll = true;
1877 }
1878 else if (strcmp(argv[i], "--resolvers") == 0 || strcmp(argv[i], "-r") == 0)
1879 {
1880 if (context.cmd_args.resolvers == NULL)
1881 {
1882 expect_arg(i);
1883 context.cmd_args.resolvers = argv[++i];
1884 }
1885 else
1886 {
1887 log_msg("Resolvers may only be supplied once.\n");
1888 clean_exit(EXIT_FAILURE);
1889 }
1890 }
1891 else if(strcmp(argv[i], "--retry") == 0)
1892 {
1893 expect_arg(i);
1894 dns_rcode rcode;
1895 if(dns_str2rcode(argv[++i], &rcode))
1896 {
1897 if(!context.cmd_args.retry_codes_set)
1898 {
1899 context.cmd_args.retry_codes[DNS_RCODE_REFUSED] = false;
1900 context.cmd_args.retry_codes_set = true;
1901 }
1902 context.cmd_args.retry_codes[rcode] = true;
1903 }
1904 else if(strcasecmp(argv[i], "never") == 0)
1905 {
1906 context.cmd_args.retry_codes[DNS_RCODE_REFUSED] = false;
1907 context.cmd_args.retry_codes_set = true;
1908 }
1909 else
1910 {
1911 log_msg("Invalid retry code: %s.\n", argv[i]);
1912 }
1913 }
1914 else if (strcmp(argv[i], "--bindto") == 0 || strcmp(argv[i], "-b") == 0)
1915 {
1916 expect_arg(i);
1917 struct sockaddr_storage *addr = safe_malloc(sizeof(addr));
1918 if (!str_to_addr(argv[++i], 0, addr))
1919 {
1920 free(addr);
1921 log_msg("Invalid address for socket binding: %s\n", argv[i]);
1922 clean_exit(EXIT_FAILURE);
1923
1924 }
1925 single_list_push_back(addr->ss_family == AF_INET ? &context.cmd_args.bind_addrs4 :
1926 &context.cmd_args.bind_addrs6, addr);
1927 }
1928 else if (strcmp(argv[i], "--outfile") == 0 || strcmp(argv[i], "-w") == 0)
1929 {
1930 expect_arg(i);
1931 context.cmd_args.outfile_name = argv[++i];
1932
1933 }
1934 else if (strcmp(argv[i], "--error-log") == 0 || strcmp(argv[i], "-l") == 0)
1935 {
1936 expect_arg(i);
1937 char *filename = argv[++i];
1938 if(strcmp(filename, "-") != 0)
1939 {
1940 context.logfile = fopen(filename, "w");
1941 if(!context.logfile)
1942 {
1943 log_msg("Failed to open log file: %s\n", strerror(errno));
1944 clean_exit(EXIT_FAILURE);
1945 }
1946 }
1947 }
1948 else if (strcmp(argv[i], "--types") == 0 || strcmp(argv[i], "--type") == 0 || strcmp(argv[i], "-t") == 0)
1949 {
1950 expect_arg(i);
1951 if (context.cmd_args.record_type != DNS_REC_INVALID)
1952 {
1953 log_msg("Currently, only one record type is supported.\n");
1954 clean_exit(EXIT_FAILURE);
1955 }
1956 dns_record_type rtype = dns_str_to_record_type(argv[++i]);
1957 if (rtype == DNS_REC_INVALID)
1958 {
1959 log_msg("Unsupported record type: %s\n", argv[i]);
1960 clean_exit(EXIT_FAILURE);
1961 }
1962 context.cmd_args.record_type = rtype;
1963 }
1964 else if (strcmp(argv[i], "--drop-group") == 0)
1965 {
1966 expect_arg(i);
1967 context.cmd_args.drop_group = argv[++i];
1968 }
1969 else if (strcmp(argv[i], "--drop-user") == 0)
1970 {
1971 expect_arg(i);
1972 context.cmd_args.drop_user = argv[++i];
1973 }
1974 else if (strcmp(argv[i], "--status-format") == 0)
1975 {
1976 expect_arg(i);
1977 context.status_fmt = get_status_format_string(argv[++i]);
1978 }
1979 else if (strcmp(argv[i], "--root") == 0)
1980 {
1981 context.cmd_args.root = true;
1982 }
1983 else if (strcmp(argv[i], "--norecurse") == 0 || strcmp(argv[i], "-n") == 0)
1984 {
1985 context.cmd_args.norecurse = true;
1986 }
1987 else if (strcmp(argv[i], "--output") == 0 || strcmp(argv[i], "-o") == 0)
1988 {
1989 expect_arg(i++);
1990 switch(argv[i][0])
1991 {
1992 case 'B':
1993 context.cmd_args.output = OUTPUT_BINARY;
1994 break;
1995
1996 case 'J':
1997 context.cmd_args.output = OUTPUT_NDJSON;
1998
1999 for(char *output_option = argv[i] + 1; *output_option != 0; output_option++)
2000 {
2001 switch(*output_option)
2002 {
2003 case 'e':
2004 context.format.write_exhausted_tries = true;
2005 break;
2006 default:
2007 log_msg("Unrecognized output option: %c\n", *output_option);
2008 clean_exit(EXIT_FAILURE);
2009 }
2010 }
2011 break;
2012
2013 case 'S':
2014 context.cmd_args.output = OUTPUT_TEXT_SIMPLE;
2015
2016 if(strcmp(argv[i], "S") != 0)
2017 {
2018 context.format.sections[DNS_SECTION_ANSWER] = false;
2019 context.format.match_name = false;
2020 }
2021 for(char *output_option = argv[i] + 1; *output_option != 0; output_option++)
2022 {
2023 switch(*output_option)
2024 {
2025 case 'u':
2026 context.format.sections[DNS_SECTION_AUTHORITY] = true;
2027 break;
2028 case 'd':
2029 context.format.sections[DNS_SECTION_ADDITIONAL] = true;
2030 break;
2031 case 'n':
2032 context.format.sections[DNS_SECTION_ANSWER] = true;
2033 break;
2034 case 'm':
2035 context.format.match_name = true;
2036 break;
2037 case 't':
2038 context.format.ttl = true;
2039 break;
2040 case 'l':
2041 context.format.separate_queries = true;
2042 break;
2043 case 'i':
2044 context.format.indent_sections = true;
2045 break;
2046 case 's':
2047 context.format.separate_sections = true;
2048 break;
2049 case 'q':
2050 context.format.print_question = true;
2051 break;
2052 case 'r':
2053 context.format.include_meta = true;
2054 break;
2055 default:
2056 log_msg("Unrecognized output option: %c\n", *output_option);
2057 clean_exit(EXIT_FAILURE);
2058 }
2059 }
2060 break;
2061
2062 case 'F':
2063 context.cmd_args.output = OUTPUT_TEXT_FULL;
2064 break;
2065
2066 default:
2067 log_msg("Unrecognized output format.\n");
2068 clean_exit(EXIT_FAILURE);
2069 }
2070 }
2071 #ifdef PCAP_SUPPORT
2072 else if (strcmp(argv[i], "--use-pcap") == 0)
2073 {
2074 context.cmd_args.use_pcap = true;
2075 }
2076 #endif
2077 else if (strcmp(argv[i], "--predictable") == 0)
2078 {
2079 context.cmd_args.predictable_resolver = true;
2080 }
2081 else if (strcmp(argv[i], "--sticky") == 0)
2082 {
2083 context.cmd_args.sticky = true;
2084 }
2085 else if (strcmp(argv[i], "--quiet") == 0 || strcmp(argv[i], "-q") == 0)
2086 {
2087 context.cmd_args.quiet = true;
2088 }
2089 else if (strcmp(argv[i], "--extreme") == 0)
2090 {
2091 context.cmd_args.extreme = (int) expect_arg_nonneg(i++, 0, 2);
2092 }
2093 else if (strcmp(argv[i], "--resolve-count") == 0 || strcmp(argv[i], "-c") == 0)
2094 {
2095 context.cmd_args.resolve_count = (uint8_t) expect_arg_nonneg(i++, 1, UINT8_MAX);
2096 }
2097 else if (strcmp(argv[i], "--hashmap-size") == 0 || strcmp(argv[i], "-s") == 0)
2098 {
2099 context.cmd_args.hashmap_size = (size_t) expect_arg_nonneg(i++, 1, SIZE_MAX);
2100 }
2101 else if (strcmp(argv[i], "--processes") == 0)
2102 {
2103 context.cmd_args.num_processes = (size_t) expect_arg_nonneg(i++, 0, SIZE_MAX);
2104 if(context.cmd_args.num_processes == 0)
2105 {
2106 #ifndef HAVE_SYSINFO
2107 log_msg("No support for detecting the number of cores automatically.\n");
2108 clean_exit(EXIT_FAILURE);
2109 #else
2110 int cores = get_nprocs_conf();
2111 if(cores <= 0)
2112 {
2113 log_msg("Failed to determine number of processor cores.\n");
2114 clean_exit(EXIT_FAILURE);
2115 }
2116 context.cmd_args.num_processes = (size_t)cores;
2117 #endif
2118 }
2119 }
2120 else if (strcmp(argv[i], "--socket-count") == 0)
2121 {
2122 context.cmd_args.socket_count = (size_t) expect_arg_nonneg(i++, 1, SIZE_MAX);
2123 }
2124 else if (strcmp(argv[i], "--interval") == 0 || strcmp(argv[i], "-i") == 0)
2125 {
2126 context.cmd_args.interval_ms = (unsigned int) expect_arg_nonneg(i++, 1, UINT_MAX);
2127 }
2128 else if (strcmp(argv[i], "--sndbuf") == 0)
2129 {
2130 context.cmd_args.sndbuf = (int) expect_arg_nonneg(i++, 0, INT_MAX);
2131 }
2132 else if (strcmp(argv[i], "--rcvbuf") == 0)
2133 {
2134 context.cmd_args.rcvbuf = (int) expect_arg_nonneg(i++, 0, INT_MAX);
2135 }
2136 else if (strcmp(argv[i], "--flush") == 0)
2137 {
2138 context.cmd_args.flush = true;
2139 }
2140 else if (strcmp(argv[i], "--verify-ip") == 0)
2141 {
2142 context.cmd_args.verify_ip = true;
2143 }
2144 else
2145 {
2146 if (context.cmd_args.domains == NULL)
2147 {
2148 context.cmd_args.domains = argv[i];
2149 domain_param = true;
2150 if (strcmp(argv[i], "-") == 0)
2151 {
2152 use_stdin();
2153 }
2154 else
2155 {
2156 // If we can seek through the domain file, we seek to the end and store the file size
2157 // in order to be able to report an estimate progress of resolving.
2158 context.domainfile = fopen(context.cmd_args.domains, "r");
2159 if (context.domainfile == NULL)
2160 {
2161 log_msg("Failed to open domain file \"%s\".\n", argv[i]);
2162 clean_exit(EXIT_FAILURE);
2163 }
2164 if(fseek(context.domainfile, 0, SEEK_END) != 0)
2165 {
2166 // Not a seekable stream.
2167 context.domainfile_size = -1;
2168 }
2169 else
2170 {
2171 context.domainfile_size = ftell(context.domainfile);
2172 if(fseek(context.domainfile, 0, SEEK_SET) != 0)
2173 {
2174 // Should never happen because seeking was possible before but we can still recover.
2175 context.domainfile_size = -1;
2176 }
2177 }
2178 fclose(context.domainfile);
2179 context.domainfile = NULL;
2180 }
2181 }
2182 else
2183 {
2184 log_msg("The domain list may only be supplied once.\n");
2185 clean_exit(EXIT_FAILURE);
2186 }
2187 }
2188 }
2189 if (context.cmd_args.record_type == DNS_REC_INVALID)
2190 {
2191 context.cmd_args.record_type = DNS_REC_A;
2192 }
2193 if (context.cmd_args.record_type == DNS_REC_ANY)
2194 {
2195 // Some operators will not reply to ANY requests:
2196 // https://blog.cloudflare.com/deprecating-dns-any-meta-query-type/
2197 // https://lists.dns-oarc.net/pipermail/dns-operations/2013-January/009501.html
2198 log_msg("Note that DNS ANY scans might be unreliable.\n");
2199 }
2200 if (context.cmd_args.resolvers == NULL)
2201 {
2202 log_msg("Resolvers are required to be supplied.\n");
2203 clean_exit(EXIT_FAILURE);
2204 }
2205 if (!domain_param)
2206 {
2207 if(!isatty(STDIN_FILENO))
2208 {
2209 use_stdin();
2210 }
2211 else
2212 {
2213 log_msg("The domain list is required to be supplied.\n");
2214 clean_exit(EXIT_FAILURE);
2215 }
2216 }
2217
2218 if(context.domainfile == stdin && context.cmd_args.num_processes > 1)
2219 {
2220 log_msg("In order to use multiprocessing, the domain list needs to be supplied as file.\n");
2221 clean_exit(EXIT_FAILURE);
2222 }
2223
2224 return 0;
2225 }
2226
2227 int main(int argc, char **argv)
2228 {
2229 #ifdef DEBUG
2230 // Create core dump on crash in debug mode
2231 struct rlimit core_limits;
2232 core_limits.rlim_cur = core_limits.rlim_max = RLIM_INFINITY;
2233 setrlimit(RLIMIT_CORE, &core_limits);
2234 #endif
2235
2236 int rcode = parse_cmd(argc, argv);
2237 if(rcode != 0)
2238 {
2239 return rcode;
2240 }
2241
2242 run();
2243 cleanup();
2244
2245 return 0;
2246 }
+0
-241
massdns.h less more
0 #ifndef MASSDNS_MASSDNS_H
1 #define MASSDNS_MASSDNS_H
2
3 #include <stdint.h>
4 #include <time.h>
5 #include <sys/socket.h>
6 #ifdef HAVE_EPOLL
7 #include <sys/epoll.h>
8 #endif
9 #include <netinet/in.h>
10 #include <arpa/inet.h>
11 //#define PCAP_SUPPORT
12 #ifdef PCAP_SUPPORT
13 #include <pcap.h>
14 #endif
15
16 #include "list.h"
17 #include "module.h"
18 #include "net.h"
19 #include "hashmap.h"
20 #include "dns.h"
21 #include "timed_ring.h"
22
23 #define MAXIMUM_MODULE_COUNT 0xFF
24 #define COMMON_UNPRIVILEGED_USER "nobody"
25 #define COMMON_UNPRIVILEGED_GROUP "nogroup"
26
27 const uint32_t OUTPUT_BINARY_VERSION = 0x00;
28
29 typedef struct
30 {
31 size_t answers;
32 size_t noerr;
33 size_t formerr;
34 size_t servfail;
35 size_t nxdomain;
36 size_t notimp;
37 size_t refused;
38 size_t yxdomain;
39 size_t yxrrset;
40 size_t nxrrset;
41 size_t notauth;
42 size_t notzone;
43 size_t timeout;
44 size_t mismatch;
45 size_t other;
46 size_t qsent;
47 size_t numreplies;
48 size_t fakereplies; // used for resolver plausibility checks (wrong records)
49 } resolver_stats_t;
50
51 typedef struct {
52 size_t fork_index;
53 size_t numdomains;
54 size_t numreplies;
55 size_t finished;
56 size_t finished_success;
57 size_t mismatch_domain;
58 size_t mismatch_id;
59 size_t timeouts[0x100];
60 size_t all_rcodes[5];
61 size_t final_rcodes[5];
62 size_t current_rate;
63 size_t success_rate;
64 size_t numparsed;
65 bool done;
66 } stats_exchange_t;
67
68 typedef struct
69 {
70 struct sockaddr_storage address;
71 resolver_stats_t stats; // To be used to track resolver bans or non-replying resolvers
72 } resolver_t;
73
74 typedef struct
75 {
76 dns_name_t name;
77 dns_record_type type;
78 } lookup_key_t;
79
80 typedef struct
81 {
82 unsigned char tries;
83 uint16_t transaction;
84 void **ring_entry; // pointer to the entry within the timed ring for entry invalidation
85 resolver_t *resolver;
86 lookup_key_t *key;
87 socket_info_t *socket;
88 } lookup_t;
89
90 typedef struct
91 {
92 lookup_key_t key;
93 lookup_t value;
94 } lookup_entry_t;
95
96 typedef enum
97 {
98 STATE_WARMUP, // Before the hash map size has been reached
99 STATE_QUERYING,
100 STATE_COOLDOWN,
101 STATE_WAIT_CHILDREN,
102 STATE_DONE
103 } state_t;
104
105 typedef enum
106 {
107 OUTPUT_TEXT_FULL,
108 OUTPUT_TEXT_SIMPLE,
109 OUTPUT_BINARY,
110 OUTPUT_NDJSON
111 } output_t;
112
113 typedef struct {
114 const char *name;
115 const char *status_fmt;
116 } status_format_map_t;
117
118 const char *default_interfaces[] = {""};
119
120 typedef struct
121 {
122 buffer_t resolvers;
123 lookup_entry_t *lookup_space;
124 buffer_t lookup_pool;
125 Hashmap *resolver_map;
126
127 struct
128 {
129 massdns_module_t handlers[MAXIMUM_MODULE_COUNT]; // we only support up to 255 modules
130 size_t count;
131 } modules;
132
133 struct
134 {
135 bool sections[4];
136 bool match_name;
137 bool ttl;
138 bool separate_queries;
139 bool separate_sections;
140 bool include_meta;
141 bool indent_sections;
142 bool print_question;
143 bool write_exhausted_tries;
144 } format;
145
146 struct cmd_args
147 {
148 bool root;
149 bool verify_ip;
150 char *resolvers;
151 char *domains;
152 char *outfile_name;
153 uint8_t resolve_count;
154 size_t hashmap_size;
155 unsigned int interval_ms;
156 bool norecurse;
157 bool quiet;
158 int sndbuf;
159 int rcvbuf;
160 char *drop_user;
161 char *drop_group;
162 dns_record_type record_type;
163 size_t timed_ring_buckets;
164 int extreme; // Do not remove EPOLLOUT after warmup
165 output_t output;
166 bool retry_codes[0xFFFF]; // Fast lookup map for DNS reply codes that are unacceptable and require a retry
167 bool retry_codes_set;
168 single_list_t bind_addrs4;
169 single_list_t bind_addrs6;
170 bool sticky;
171 int argc;
172 char **argv;
173 void (*help_function)();
174 bool flush;
175 bool predictable_resolver;
176 bool use_pcap;
177 size_t num_processes;
178 size_t socket_count;
179 bool busypoll;
180 } cmd_args;
181
182 struct
183 {
184 buffer_t interfaces4; // Sockets used for receiving queries
185 buffer_t interfaces6; // Sockets used for receiving queries
186 int *pipes;
187 socket_info_t write_pipe;
188 socket_info_t *master_pipes_read;
189 } sockets;
190
191 // Processes
192 size_t finished;
193 pid_t *pids;
194 bool *done;
195 const char *status_fmt;
196 FILE* outfile;
197 FILE* logfile;
198 FILE* domainfile;
199 ssize_t domainfile_size;
200 int epollfd;
201 Hashmap *map;
202 state_t state;
203 timed_ring_t ring; // handles timeouts
204 size_t lookup_index;
205 size_t fork_index;
206 struct
207 {
208 struct timespec start_time;
209 size_t mismatch;
210 size_t other;
211 size_t qsent;
212 size_t numreplies;
213 size_t numparsed;
214 size_t numdomains;
215 struct timespec last_print;
216 size_t current_rate;
217 size_t success_rate;
218 size_t timeouts[0x100];
219 size_t final_rcodes[0x10000];
220 size_t all_rcodes[0x10000];
221 size_t finished;
222 size_t finished_success;
223 size_t mismatch_id;
224 size_t mismatch_domain;
225 } stats;
226 stats_exchange_t *stat_messages;
227 #ifdef PCAP_SUPPORT
228 pcap_t *pcap;
229 char pcap_error[PCAP_ERRBUF_SIZE];
230 char *pcap_dev;
231 socket_info_t pcap_info;
232 uint16_t ether_type_ip;
233 uint16_t ether_type_ip6;
234 struct bpf_program pcap_filter;
235 #endif
236 } massdns_context_t;
237
238 massdns_context_t context;
239
240 #endif //MASSDNS_MASSDNS_H
+0
-6
mixed_list.h less more
0 #ifndef MASSDNS_MIXED_LIST_H
1 #define MASSDNS_MIXED_LIST_H
2
3 #include "stdint.h"
4
5 #endif //MASSDNS_MIXED_LIST_H
+0
-8
module.h less more
0 #ifndef MASSDNS_MODULE_H
1 #define MASSDNS_MODULE_H
2
3 typedef struct {
4
5 } massdns_module_t;
6
7 #endif //MASSDNS_MODULE_H
+0
-19
modules/binary_output/CMakeLists.txt less more
0 cmake_minimum_required(VERSION 3.2)
1 project(massdns_binary_output)
2
3 link_directories(/usr/lib)
4
5 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c11")
6
7 link_libraries(libldns.so)
8
9 set(LDNS_DIR /usr/include/ldns)
10
11 set(LDNS_FILES
12 ${LDNS_DIR}/packet.h)
13
14 set(SOURCE_FILES main.c)
15
16 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ../../bin)
17
18 add_library(mod_binary_output SHARED ${SOURCE_FILES} ${LDNS_FILES})
+0
-2
modules/binary_output/Makefile less more
0 all:
1 gcc -shared -Wall -Werror -fpic main.c -o ../../bin/mod_binary_output.so
+0
-30
modules/binary_output/main.c less more
0 #include <arpa/inet.h>
1 #include <stdlib.h>
2
3 #include <ldns/packet.h>
4 #include <ldns/host2wire.h>
5
6 #include "../../massdns.h"
7
8 extern void massdns_handle_response(massdns_context_t *context, ldns_pkt *packet, struct sockaddr_storage *address)
9 {
10 uint8_t *buffer;
11 size_t len;
12 if(LDNS_STATUS_OK == ldns_pkt2wire(&buffer, packet, &len))
13 {
14 if(len <= 0xFFFF)
15 {
16 struct timeval now;
17 if(0 != gettimeofday(&now, NULL))
18 {
19 bzero(&now, sizeof(now));
20 }
21 uint16_t shortlen = len;
22 fwrite(&now, sizeof(now), 1, context->outfile);
23 fwrite(address, sizeof(*address), 1, context->outfile);
24 fwrite(&shortlen, sizeof(shortlen), 1, context->outfile);
25 fwrite(buffer, sizeof(*buffer), len, context->outfile);
26 }
27 free(buffer);
28 }
29 }
+0
-223
net.h less more
0 #ifndef MASSRESOLVER_NET_H
1 #define MASSRESOLVER_NET_H
2
3 #include <stdbool.h>
4 #include <fcntl.h>
5 #include <net/if.h>
6 #include <sys/socket.h>
7 #include <unistd.h>
8 #ifdef PCAP_SUPPORT
9 #include <sys/ioctl.h>
10 #endif
11 #include <inttypes.h>
12
13 #define loop_sockets(sockets) \
14 for (socket_info_t *socket = (sockets)->data; socket < ((socket_info_t*)(sockets)->data) + (sockets)->len; socket++)
15
16 typedef enum
17 {
18 PROTO_IPV4 = 1 << 0,
19 PROTO_IPV6 = 1 << 1
20 } ip_support_t;
21
22 typedef enum
23 {
24 SOCKET_TYPE_INTERFACE,
25 SOCKET_TYPE_QUERY,
26 SOCKET_TYPE_CONTROL
27 } socket_type_t;
28
29 typedef enum
30 {
31 NETMODE_EPOLL,
32 NETMODE_BUSYPOLL
33 } netmode_t;
34
35 typedef struct
36 {
37 ip_support_t protocol;
38 int descriptor;
39 socket_type_t type;
40 void *data;
41 } socket_info_t;
42
43 void socket_noblock(socket_info_t* socket)
44 {
45 int sd = socket->descriptor;
46 int flags = fcntl(sd, F_GETFL, 0);
47 fcntl(sd, F_SETFL, flags | O_NONBLOCK);
48 }
49
50 socklen_t sockaddr_storage_size(struct sockaddr_storage *storage)
51 {
52 if(storage->ss_family == AF_INET)
53 {
54 return sizeof(struct sockaddr_in);
55 }
56 else if(storage->ss_family == AF_INET6)
57 {
58 return sizeof(struct sockaddr_in6);
59 }
60 return 0;
61 }
62
63 #ifdef HAVE_EPOLL
64 void add_sockets(int epollfd, uint32_t events, int op, buffer_t *sockets)
65 {
66 socket_info_t *interface_sockets = sockets->data;
67 for (size_t i = 0; i < sockets->len; i++)
68 {
69 struct epoll_event ev;
70 bzero(&ev, sizeof(ev));
71 ev.data.ptr = &interface_sockets[i];
72 ev.events = events;
73 if (epoll_ctl(epollfd, op, interface_sockets[i].descriptor, &ev) != 0)
74 {
75 perror("Failed to add epoll event");
76 exit(EXIT_FAILURE);
77 }
78 }
79 }
80 #endif
81
82 bool str_to_addr(char *str, uint16_t default_port, struct sockaddr_storage *addr)
83 {
84 if(str == NULL || str[0] == 0)
85 {
86 return false;
87 }
88 while(*str == ' ' || *str == '\t') // Skip whitespaces ("trim left")
89 {
90 str++;
91 }
92 unsigned long int port = default_port;
93
94 if(str[0] == '[')
95 {
96 str++;
97 char *closing_bracket = strstr(str, "]");
98 if(!closing_bracket)
99 {
100 return false;
101 }
102 if(closing_bracket[1] == ':') // Is there a port separator?
103 {
104 *closing_bracket = 0;
105 char *invalid_char;
106 port = strtoul(closing_bracket + 2, &invalid_char, 10);
107 if (*invalid_char != 0 || port >= UINT16_MAX)
108 {
109 return false;
110 }
111 }
112 }
113 else // We either have an IPv6 address without square brackets or an IPv4 address
114 {
115 bool v4 = false;
116 char *colon = NULL;
117 for(char *c = str; *c != 0; c++)
118 {
119 if(*c == '.' && colon == NULL) // dot before colon
120 {
121 v4 = true;
122 }
123 if(*c == ':')
124 {
125 colon = c;
126 }
127 }
128 if(v4 && colon) // We found the port separator
129 {
130 *colon = 0;
131 char *invalid_char;
132 port = strtoul(colon + 1, &invalid_char, 10);
133 if (*invalid_char != 0 || port >= UINT16_MAX)
134 {
135 return false;
136 }
137 }
138
139 }
140 if (inet_pton(AF_INET, str, &((struct sockaddr_in*)addr)->sin_addr) == 1)
141 {
142 ((struct sockaddr_in*)addr)->sin_port = htons((uint16_t )port);
143 ((struct sockaddr_in*)addr)->sin_family = AF_INET;
144 return true;
145 }
146 else if (inet_pton(AF_INET6, str, &((struct sockaddr_in6*)addr)->sin6_addr) == 1)
147 {
148 ((struct sockaddr_in6*)addr)->sin6_port = htons((uint16_t )port);
149 ((struct sockaddr_in6*)addr)->sin6_family = AF_INET6;
150 return true;
151 }
152 return false;
153 }
154
155 #ifdef PCAP_SUPPORT
156 int get_iface_hw_addr(char *iface, uint8_t *hw_mac)
157 {
158 int s;
159 struct ifreq buffer;
160
161 s = socket(PF_INET, SOCK_DGRAM, 0);
162 if (s < 0)
163 {
164 return EXIT_FAILURE;
165 }
166 bzero(&buffer, sizeof(buffer));
167 strncpy(buffer.ifr_name, iface, IFNAMSIZ);
168 ioctl(s, SIOCGIFHWADDR, &buffer);
169 close(s);
170 memcpy(hw_mac, buffer.ifr_hwaddr.sa_data, 6);
171 return EXIT_SUCCESS;
172 }
173
174 #define MAC_READABLE_BUFLEN 18
175
176 int get_iface_hw_addr_readable(char *iface, char *hw_mac)
177 {
178 uint8_t buffer[6];
179 int result = get_iface_hw_addr(iface, buffer);
180 for(uint8_t *b = buffer; b < buffer + 6; b++)
181 {
182 sprintf(hw_mac, "%02x:", *b);
183 hw_mac += 3;
184 if(b == buffer + 5)
185 {
186 *(hw_mac - 1) = 0;
187 }
188 }
189 return result;
190 }
191 #endif
192
193 char *sockaddr2str(struct sockaddr_storage *addr)
194 {
195 static char str[INET6_ADDRSTRLEN + sizeof(":65535") + 2]; // + 2 for [ and ]
196 static uint16_t port;
197 size_t len;
198
199 if(addr->ss_family == AF_INET)
200 {
201 port = ntohs(((struct sockaddr_in*)addr)->sin_port);
202 inet_ntop(addr->ss_family, &((struct sockaddr_in*)addr)->sin_addr, str, sizeof(str));
203 len = strlen(str);
204 // inet_ntop does not allow us to determine, how long the printed string was.
205 // Thus, we have to use strlen.
206 }
207 else
208 {
209 str[0] = '[';
210 port = ntohs(((struct sockaddr_in6*)addr)->sin6_port);
211 inet_ntop(addr->ss_family, &((struct sockaddr_in6*)addr)->sin6_addr, str + 1, sizeof(str) - 1);
212 len = strlen(str);
213 str[len++] = ']';
214 str[len] = 0;
215 }
216
217 snprintf(str + len, sizeof(str) - len, ":%" PRIu16, port);
218
219 return str;
220 }
221
222 #endif //MASSRESOLVER_NET_H
+0
-40
random.h less more
0 #ifndef MASSRESOLVER_RANDOM_H
1 #define MASSRESOLVER_RANDOM_H
2
3 #include <stdio.h>
4 #include <stdbool.h>
5
6 static FILE *randomness;
7
8 bool urandom_init()
9 {
10 randomness = fopen("/dev/urandom", "r");
11 return randomness != NULL;
12 }
13
14 void urandom_get(void *dst, size_t len)
15 {
16 size_t read = 0;
17 while(read < len)
18 {
19 read += fread(dst, len - read, 1, randomness);
20 }
21 }
22
23 size_t urandom_size_t()
24 {
25 size_t result;
26 urandom_get(&result, sizeof(result));
27 return result;
28 }
29
30 int urandom_close()
31 {
32 if(!randomness)
33 {
34 return 0;
35 }
36 return fclose(randomness);
37 }
38
39 #endif //MASSRESOLVER_RANDOM_H
22 import sys
33 import urllib.request
44 import urllib.parse
5 import re
5 import json
66
77
88 if len(sys.argv) == 1:
1111
1212 for i, arg in enumerate(sys.argv, 1):
1313 domains = set()
14 with urllib.request.urlopen('https://crt.sh/?q=' + urllib.parse.quote('%.' + arg)) as f:
15 code = f.read().decode('utf-8')
16 for cert, domain in re.findall('<tr>(?:\s|\S)*?href="\?id=([0-9]+?)"(?:\s|\S)*?<td>([*_a-zA-Z0-9.-]+?\.' + re.escape(arg) + ')</td>(?:\s|\S)*?</tr>', code, re.IGNORECASE):
17 domain = domain.split('@')[-1]
18 if not domain in domains:
19 domains.add(domain)
20 print(domain)
14 with urllib.request.urlopen('https://crt.sh/?output=json&q=' + urllib.parse.quote('%.' + arg)) as f:
15 data = json.loads(f.read().decode('utf-8'))
16 for crt in data:
17 for domain in crt['name_value'].split('\n'):
18 if not domain in domains:
19 domains.add(domain)
20 print(domain)
0 #
1 # $ jq -r -f massdnsA.jq < results.json
2 # www.xxxxxxxx.com 1.2.3.4
3 # www.xxxxxxxx.com 1.2.3.4
4 # www.yyyyyy.com 3.4.5.6
5 # www.zzzzzz.com 4.5.6.7
6 #
7 # Easy to modify for AAAA and other record types
8 #
9 . |
10 select(
11 .class == "IN" and
12 .status == "NOERROR") |
13 (.name|rtrimstr(".")) + " " + (.data.answers[] | select(.type == "A") .data)?
14
0 . |
1 select(
2 .class == "IN" and
3 .status == "NOERROR") |
4 (.name|rtrimstr(".")) + "," + (.data.answers[] | select(.type == "AAAA") .data)?
+0
-81
security.h less more
0 #ifndef INC_SECURITY
1 #define INC_SECURITY
2
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stdio.h>
6 #include <assert.h>
7
8 /**
9 * Safely allocate memory on the heap by aborting on failure.
10 *
11 * @param n The size of the memory block.
12 * @return A pointer that points to the allocated block, NULL when requesting a block of zero bytes.
13 */
14 void *safe_malloc(size_t n)
15 {
16 if(n == 0)
17 {
18 return NULL;
19 }
20 void *ptr = malloc(n);
21 // Check for successful allocation
22 if(ptr == NULL)
23 {
24 perror("Memory allocation failed");
25 abort();
26 }
27 return ptr;
28 }
29
30 void *safe_realloc(void *orig, size_t n)
31 {
32 void *ptr = realloc(orig, n);
33 // Check for successful allocation
34 if(ptr == NULL)
35 {
36 perror("Memory allocation failed");
37 abort();
38 }
39 return ptr;
40 }
41
42 /**
43 * Safely allocate memory on the heap and initialize it with zeroes by aborting on failure.
44 *
45 * @param n The size of the memory block.
46 * @return A pointer that points to the allocated block, NULL when requesting a block of zero bytes.
47 */
48 void *safe_calloc(size_t n)
49 {
50 if(n == 0)
51 {
52 return NULL;
53 }
54 void *ptr = calloc(n, 1);
55 // Check for successful allocation
56 if(ptr == NULL)
57 {
58 perror("Memory allocation failed");
59 abort();
60 }
61 return ptr;
62 }
63
64 /**
65 * Safely free a memory allocation on the heap at the cost of a NULL assignment. Aims to prevent double free attacks.
66 *
67 * Example:
68 * char *x = malloc(10);
69 * safe_free(&x); // x == NULL
70 *
71 * @param ptr A pointer to a pointer that has been obtained using (safe_)malloc.
72 */
73 void safe_free(void **ptr)
74 {
75 free(*ptr);
76 *ptr = NULL;
77 }
78
79
80 #endif
0 // SPDX-License-Identifier: GPL-3.0-only
1
2 #ifndef INC_BUFFERS
3 #define INC_BUFFERS
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 typedef struct buffer
10 {
11 void *data;
12 size_t len;
13 } buffer_t;
14
15 #endif
0 // SPDX-License-Identifier: GPL-3.0-only
1
2 #include "massdns.h"
3
4 #ifndef MASSDNS_CMD_H
5 #define MASSDNS_CMD_H
6
7 void expect_arg(int i)
8 {
9 if (i + 1 >= context.cmd_args.argc)
10 {
11 fprintf(stderr, "Missing argument value for %s.\n", context.cmd_args.argv[i]);
12 context.cmd_args.help_function();
13 exit(1);
14 }
15 }
16
17 unsigned long long expect_arg_nonneg(int i, unsigned long long min, unsigned long long max)
18 {
19 expect_arg(i);
20 char *endptr;
21 unsigned long long result = strtoull(context.cmd_args.argv[i + 1], &endptr, 10);
22 if(*endptr != 0 || result < min || result > max)
23 {
24 fprintf(stderr, "The argument %s requires a value between %llu and %llu.\n",
25 context.cmd_args.argv[i], min, max);
26 exit(1);
27 }
28 return result;
29 }
30
31 #endif
0 // SPDX-License-Identifier: GPL-3.0-only
1
2 #ifndef MASSRESOLVER_DNS_H
3 #define MASSRESOLVER_DNS_H
4
5 #include <stdlib.h>
6 #include <stdbool.h>
7 #include <stdint.h>
8 #include <strings.h>
9 #include <string.h>
10 #include <inttypes.h>
11 #include <ctype.h>
12
13 #define min(a, b) ((a) < (b) ? (a) : (b))
14 #define max(a, b) ((a) > (b) ? (a) : (b))
15 #define elements(a) (sizeof(a) / sizeof((a)[0]))
16
17 typedef enum
18 {
19 DNS_REC_INVALID = -1, // Error code
20
21 DNS_REC_A = 1,
22 DNS_REC_AAAA = 28,
23 DNS_REC_AFSDB = 18,
24 DNS_REC_ANY = 255,
25 DNS_REC_APL = 42,
26 DNS_REC_CAA = 257,
27 DNS_REC_CDNSKEY = 60,
28 DNS_REC_CDS = 59,
29 DNS_REC_CERT = 37,
30 DNS_REC_CNAME = 5,
31 DNS_REC_DHCID = 49,
32 DNS_REC_DLV = 32769,
33 DNS_REC_DNAME = 39,
34 DNS_REC_DNSKEY = 48,
35 DNS_REC_DS = 43,
36 DNS_REC_HIP = 55,
37 DNS_REC_IPSECKEY = 45,
38 DNS_REC_KEY = 25,
39 DNS_REC_KX = 36,
40 DNS_REC_LOC = 29,
41 DNS_REC_MX = 15,
42 DNS_REC_NAPTR = 35,
43 DNS_REC_NS = 2,
44 DNS_REC_NSEC = 47,
45 DNS_REC_NSEC3 = 50,
46 DNS_REC_NSEC3PARAM = 51,
47 DNS_REC_OPENPGPKEY = 61,
48 DNS_REC_PTR = 12,
49 DNS_REC_RP = 17,
50 DNS_REC_RRSIG = 46,
51 DNS_REC_SIG = 24,
52 DNS_REC_SOA = 6,
53 DNS_REC_SRV = 33,
54 DNS_REC_SSHFP = 44,
55 DNS_REC_TA = 32768,
56 DNS_REC_TKEY = 249,
57 DNS_REC_TLSA = 52,
58 DNS_REC_TSIG = 250,
59 DNS_REC_TXT = 16,
60 DNS_REC_URI = 256
61 } dns_record_type;
62
63 typedef enum
64 {
65 DNS_SECTION_QUESTION = 0,
66 DNS_SECTION_ANSWER = 1,
67 DNS_SECTION_AUTHORITY = 2,
68 DNS_SECTION_ADDITIONAL = 3
69 } dns_section_t;
70
71 dns_record_type dns_str_to_record_type(const char *str)
72 {
73 // Performance is important here because we may want to use this when reading
74 // large numbers of DNS queries from a file.
75 long int code;
76
77 switch (tolower(str[0]))
78 {
79 case 'a':
80 switch (tolower(str[1]))
81 {
82 case 0:
83 return DNS_REC_A;
84 case 'a':
85 if (tolower(str[2]) == 'a' && tolower(str[3]) == 'a' && str[4] == 0)
86 {
87 return DNS_REC_AAAA;
88 }
89 return DNS_REC_INVALID;
90 case 'f':
91 if (tolower(str[2]) == 's' && tolower(str[3]) == 'd' && tolower(str[4]) == 'b' && str[5] == 0)
92 {
93 return DNS_REC_AFSDB;
94 }
95 return DNS_REC_INVALID;
96 case 'n':
97 if (tolower(str[2]) == 'y' && str[3] == 0)
98 {
99 return DNS_REC_ANY;
100 }
101 return DNS_REC_INVALID;
102 case 'p':
103 if (tolower(str[2]) == 'l' && str[3] == 0)
104 {
105 return DNS_REC_APL;
106 }
107 return DNS_REC_INVALID;
108 default:
109 return DNS_REC_INVALID;
110 }
111 case 'c':
112 switch (tolower(str[1]))
113 {
114 case 'a':
115 if (tolower(str[2]) == 'a' && str[3] == 0)
116 {
117 return DNS_REC_CAA;
118 }
119 return DNS_REC_INVALID;
120 case 'd':
121 switch(tolower(str[2]))
122 {
123 case 's':
124 if(str[3] == 0)
125 {
126 return DNS_REC_CDS;
127 }
128 return DNS_REC_INVALID;
129 case 'n':
130 if(tolower(str[3]) == 's' && tolower(str[4]) == 'k' && tolower(str[5]) == 'e'
131 && tolower(str[6]) == 'y' && str[7] == 0)
132 {
133 return DNS_REC_CDNSKEY;
134 }
135 default:
136 return DNS_REC_INVALID;
137 }
138 case 'e':
139 if(tolower(str[2]) == 'r' && tolower(str[3]) == 't' && str[4] == 0)
140 {
141 return DNS_REC_CERT;
142 }
143 return DNS_REC_INVALID;
144 case 'n':
145 if(tolower(str[2]) == 'a' && tolower(str[3]) == 'm' && tolower(str[4]) == 'e' && str[5] == 0)
146 {
147 return DNS_REC_CNAME;
148 }
149 return DNS_REC_INVALID;
150 default:
151 return DNS_REC_INVALID;
152 }
153 case 'd':
154 switch (tolower(str[1]))
155 {
156 case 'h':
157 if(tolower(str[2]) == 'c' && tolower(str[3]) == 'i' && tolower(str[4]) == 'd' && str[5] == 0)
158 {
159 return DNS_REC_DHCID;
160 }
161 return DNS_REC_INVALID;
162 case 'l':
163 if(tolower(str[2]) == 'v' && str[3] == 0)
164 {
165 return DNS_REC_DLV;
166 }
167 return DNS_REC_INVALID;
168 case 'n':
169 switch(tolower(str[2]))
170 {
171 case 'a':
172 if(tolower(str[3]) == 'm' && tolower(str[4]) == 'e' && str[5] == 0)
173 {
174 return DNS_REC_DNAME;
175 }
176 return DNS_REC_INVALID;
177 case 's':
178 if(tolower(str[3]) == 'k' && tolower(str[4]) == 'e' && tolower(str[5]) == 'y' && str[6] == 0)
179 {
180 return DNS_REC_DNSKEY;
181 }
182 return DNS_REC_INVALID;
183 default:
184 return DNS_REC_INVALID;
185 }
186 case 's':
187 if(str[2] == 0)
188 {
189 return DNS_REC_DS;
190 }
191 return DNS_REC_INVALID;
192 default:
193 return DNS_REC_INVALID;
194 }
195 case 'h':
196 if (tolower(str[1]) == 'i' && tolower(str[2]) == 'p' && str[3] == 0)
197 {
198 return DNS_REC_HIP;
199 }
200 return DNS_REC_INVALID;
201 case 'i':
202 if (tolower(str[1]) == 'p' && tolower(str[2]) == 's' && tolower(str[3]) == 'e' && tolower(str[4]) == 'c'
203 && tolower(str[5]) == 'k' && tolower(str[6]) == 'e' && tolower(str[7]) == 'y' && str[8] == 0)
204 {
205 return DNS_REC_IPSECKEY;
206 }
207 return DNS_REC_INVALID;
208 case 'k':
209 switch(tolower(str[1]))
210 {
211 case 'e':
212 if (tolower(str[2]) == 'y' && str[3] == 0)
213 {
214 return DNS_REC_KEY;
215 }
216 return DNS_REC_INVALID;
217 case 'x':
218 if (str[2] == 0)
219 {
220 return DNS_REC_KX;
221 }
222 return DNS_REC_INVALID;
223 default:
224 return DNS_REC_INVALID;
225 }
226 case 'l':
227 if (tolower(str[1]) == 'o' && tolower(str[2]) == 'c' && str[3] == 0)
228 {
229 return DNS_REC_LOC;
230 }
231 return DNS_REC_INVALID;
232 case 'm':
233 if (tolower(str[1]) == 'x' && str[2] == 0)
234 {
235 return DNS_REC_MX;
236 }
237 return DNS_REC_INVALID;
238 case 'n':
239 switch(tolower(str[1]))
240 {
241 case 'a':
242 if (tolower(str[2]) == 'p' && tolower(str[3]) == 't' && tolower(str[4]) == 'r' && str[5] == 0)
243 {
244 return DNS_REC_NAPTR;
245 }
246 return DNS_REC_INVALID;
247 case 's':
248 switch(tolower(str[2]))
249 {
250 case 0:
251 return DNS_REC_NS;
252 case 'e':
253 if(tolower(str[3]) == 'c')
254 {
255 switch(tolower(str[4]))
256 {
257 case 0:
258 return DNS_REC_NSEC;
259 case '3':
260 if(str[5] == 0)
261 {
262 return DNS_REC_NSEC3;
263 }
264 if(tolower(str[5]) == 'p' && tolower(str[6]) == 'a' && tolower(str[7]) == 'r'
265 && tolower(str[8]) == 'a' && tolower(str[9]) == 'm' && str[10] == 0)
266 {
267 return DNS_REC_NSEC3PARAM;
268 }
269 return DNS_REC_INVALID;
270 default:
271 return DNS_REC_INVALID;
272 }
273 }
274 return DNS_REC_INVALID;
275 default:
276 return DNS_REC_INVALID;
277 }
278 default:
279 return DNS_REC_INVALID;
280 }
281 case 'o':
282 if (tolower(str[1]) == 'p' && tolower(str[2]) == 'e' && tolower(str[3]) == 'n' && tolower(str[4]) == 'p'
283 && tolower(str[5]) == 'g' && tolower(str[6]) == 'p' && tolower(str[7]) == 'k' && tolower(str[8]) == 'e'
284 && tolower(str[9]) == 'y' && str[10] == 0)
285 {
286 return DNS_REC_OPENPGPKEY;
287 }
288 return DNS_REC_INVALID;
289 case 'p':
290 if (tolower(str[1]) == 't' && tolower(str[2]) == 'r' && str[3] == 0)
291 {
292 return DNS_REC_PTR;
293 }
294 return DNS_REC_INVALID;
295 case 'r':
296 switch(tolower(str[1]))
297 {
298 case 'p':
299 if(str[2] == 0)
300 {
301 return DNS_REC_RP;
302 }
303 return DNS_REC_INVALID;
304 case 'r':
305 if (tolower(str[2]) == 's' && tolower(str[3]) == 'i' && tolower(str[4]) == 'g' && str[5] == 0)
306 {
307 return DNS_REC_RRSIG;
308 }
309 return DNS_REC_INVALID;
310 default:
311 return DNS_REC_INVALID;
312 }
313 case 's':
314 switch (tolower(str[1]))
315 {
316 case 'i':
317 if (tolower(str[2]) == 'g' && tolower(str[3]) == 0)
318 {
319 return DNS_REC_SIG;
320 }
321 return DNS_REC_INVALID;
322 case 'o':
323 if (tolower(str[2]) == 'a' && tolower(str[3]) == 0)
324 {
325 return DNS_REC_SOA;
326 }
327 return DNS_REC_INVALID;
328 case 'r':
329 if (tolower(str[2]) == 'v' && tolower(str[3]) == 0)
330 {
331 return DNS_REC_SRV;
332 }
333 return DNS_REC_INVALID;
334 case 's':
335 if (tolower(str[2]) == 'h' && tolower(str[3]) == 'f' && tolower(str[4]) == 'p' && str[5] == 0)
336 {
337 return DNS_REC_SSHFP;
338 }
339 return DNS_REC_INVALID;
340 default:
341 return DNS_REC_INVALID;
342 }
343 case 't':
344 switch (tolower(str[1]))
345 {
346 case 'a':
347 if(str[2] == 0)
348 {
349 return DNS_REC_TA;
350 }
351 return DNS_REC_INVALID;
352 case 'k':
353 if (tolower(str[2]) == 'e' && tolower(str[3]) == 'y' && str[4] == 0)
354 {
355 return DNS_REC_TKEY;
356 }
357 return DNS_REC_INVALID;
358 case 'l':
359 if (tolower(str[2]) == 's' && tolower(str[3]) == 'a' && str[4] == 0)
360 {
361 return DNS_REC_TLSA;
362 }
363 return DNS_REC_INVALID;
364 case 's':
365 if (tolower(str[2]) == 'i' && tolower(str[3]) == 'g' && str[4] == 0)
366 {
367 return DNS_REC_TSIG;
368 }
369 return DNS_REC_INVALID;
370 case 'x':
371 if (tolower(str[2]) == 't' && str[3] == 0)
372 {
373 return DNS_REC_TXT;
374 }
375 return DNS_REC_INVALID;
376 default:
377 return DNS_REC_INVALID;
378 }
379 case 'u':
380 switch (tolower(str[1]))
381 {
382 case 'r':
383 if (tolower(str[2]) == 'i' && str[3] == 0)
384 {
385 return DNS_REC_URI;
386 }
387 return DNS_REC_INVALID;
388 default:
389 return DNS_REC_INVALID;
390 }
391 case '0':
392 case '1':
393 case '2':
394 case '3':
395 case '4':
396 case '5':
397 case '6':
398 case '7':
399 case '8':
400 case '9':
401 errno = 0;
402 code = strtol(str, NULL, 10);
403 if(code < 0 || code > 0xFFFF || errno != 0)
404 {
405 return DNS_REC_INVALID;
406 }
407 return (dns_record_type)code;
408 default:
409 return DNS_REC_INVALID;
410 }
411 }
412
413 typedef enum
414 {
415 DNS_CLS_IN = 1,
416 DNS_CLS_CH = 3,
417 DNS_CLS_HS = 4,
418 DNS_CLS_QCLASS_NONE = 254,
419 DNS_CLS_QCLASS_ANY = 255
420 } dns_class;
421
422 typedef enum
423 {
424 DNS_RCODE_OK = 0,
425 DNS_RCODE_FORMERR = 1,
426 DNS_RCODE_SERVFAIL = 2,
427 DNS_RCODE_NXDOMAIN = 3,
428 DNS_RCODE_NOTIMP = 4,
429 DNS_RCODE_REFUSED = 5,
430 DNS_RCODE_YXDOMAIN = 6,
431 DNS_RCODE_YXRRSET = 7,
432 DNS_RCODE_NOTAUTH = 9,
433 DNS_RCODE_NOTZONE = 10,
434 DNS_RCODE_BADVERS = 16,
435 DNS_RCODE_BADKEY = 17,
436 DNS_RCODE_BADTIME = 18,
437 DNS_RCODE_BADMODE = 19,
438 DNS_RCODE_BADNAME = 20,
439 DNS_RCODE_BADALG = 21,
440 DNS_RCODE_BADTRUNC = 22,
441 DNS_RCODE_BADCOOKIE = 23
442 } dns_rcode;
443
444 bool dns_str2rcode(char *str, dns_rcode *code)
445 {
446 if(strcasecmp(str, "ok") == 0 || strcasecmp(str, "noerror") == 0)
447 {
448 *code = DNS_RCODE_OK;
449 return true;
450 }
451 else if(strcasecmp(str, "formerr") == 0)
452 {
453 *code = DNS_RCODE_FORMERR;
454 return true;
455 }
456 else if(strcasecmp(str, "servfail") == 0)
457 {
458 *code = DNS_RCODE_SERVFAIL;
459 return true;
460 }
461 else if(strcasecmp(str, "nxdomain") == 0)
462 {
463 *code = DNS_RCODE_NXDOMAIN;
464 return true;
465 }
466 else if(strcasecmp(str, "notimp") == 0)
467 {
468 *code = DNS_RCODE_NOTIMP;
469 return true;
470 }
471 else if(strcasecmp(str, "refused") == 0)
472 {
473 *code = DNS_RCODE_REFUSED;
474 return true;
475 }
476 else if(strcasecmp(str, "yxdomain") == 0)
477 {
478 *code = DNS_RCODE_YXDOMAIN;
479 return true;
480 }
481 else if(strcasecmp(str, "yxrrset") == 0)
482 {
483 *code = DNS_RCODE_YXRRSET;
484 return true;
485 }
486 else if(strcasecmp(str, "notauth") == 0)
487 {
488 *code = DNS_RCODE_NOTAUTH;
489 return true;
490 }
491 else if(strcasecmp(str, "notzone") == 0)
492 {
493 *code = DNS_RCODE_NOTZONE;
494 return true;
495 }
496 else if(strcasecmp(str, "badvers") == 0 || strcasecmp(str, "badsig") == 0)
497 {
498 *code = DNS_RCODE_BADVERS;
499 return true;
500 }
501 else if(strcasecmp(str, "badkey") == 0)
502 {
503 *code = DNS_RCODE_BADKEY;
504 return true;
505 }
506 else if(strcasecmp(str, "badtime") == 0)
507 {
508 *code = DNS_RCODE_BADTIME;
509 return true;
510 }
511 else if(strcasecmp(str, "badmode") == 0)
512 {
513 *code = DNS_RCODE_BADMODE;
514 return true;
515 }
516 else if(strcasecmp(str, "badname") == 0)
517 {
518 *code = DNS_RCODE_BADNAME;
519 return true;
520 }
521 else if(strcasecmp(str, "badalg") == 0)
522 {
523 *code = DNS_RCODE_BADALG;
524 return true;
525 }
526 else if(strcasecmp(str, "badtrunc") == 0)
527 {
528 *code = DNS_RCODE_BADTRUNC;
529 return true;
530 }
531 else if(strcasecmp(str, "badcookie") == 0)
532 {
533 *code = DNS_RCODE_BADCOOKIE;
534 return true;
535 }
536 else
537 {
538 char *endptr;
539 unsigned long result = strtoul(str, &endptr, 10);
540 if(*endptr != 0 || result > UINT16_MAX)
541 {
542 return false;
543 }
544 *code = (dns_rcode)result;
545 }
546 return false;
547 }
548
549 typedef enum
550 {
551 DNS_OPCODE_QUERY = 0,
552 DNS_OPCODE_IQUERY = 1,
553 DNS_OPCODE_STATUS = 2,
554 DNS_OPCODE_NOTIFY = 4,
555 DNS_OPCODE_UPDATE = 5
556 } dns_opcode;
557
558 const size_t DNS_PACKET_MINIMUM_SIZE = 17; // as we handle them
559 // 12 bytes header + 1 byte question name + 2 bytes question class + 2 bytes question type
560
561 typedef struct
562 {
563 uint16_t id;
564 bool rd;
565 bool tc;
566 bool aa;
567 uint8_t opcode;
568 bool qr;
569 uint8_t rcode;
570 bool ad;
571 bool z;
572 bool cd;
573 bool ra;
574
575 uint16_t q_count;
576 uint16_t ans_count;
577 uint16_t auth_count;
578 uint16_t add_count;
579
580 } dns_header_t;
581
582 typedef struct
583 {
584 uint8_t name[0xFF];
585 uint8_t length;
586 } dns_name_t;
587
588 typedef struct
589 {
590 dns_name_t name;
591 dns_record_type type;
592 unsigned int class;
593 } dns_question_t;
594
595 typedef struct
596 {
597 dns_header_t header;
598 dns_question_t question;
599 } dns_head_t;
600
601 typedef struct
602 {
603 dns_name_t name;
604 uint16_t type;
605 uint16_t class;
606 uint32_t ttl;
607 uint16_t length;
608 union
609 {
610 uint8_t *raw;
611 dns_name_t name;
612 struct in_addr in_addr;
613 struct in6_addr in6_addr;
614 } data;
615 } dns_record_t;
616
617 typedef struct
618 {
619 dns_record_t ans[0x100];
620 dns_record_t auth[0x100];
621 dns_record_t add[0x100];
622 } dns_filtered_body_t;
623
624 typedef struct
625 {
626 dns_head_t head;
627 dns_filtered_body_t body;
628 } dns_pkt_t;
629
630 typedef struct
631 {
632 uint8_t length;
633 uint8_t *data;
634 } dns_character_string_ptr_t;
635
636 typedef struct
637 {
638 uint16_t preference;
639 dns_name_t name;
640 } dns_mx_t;
641
642 typedef struct
643 {
644 uint8_t flags;
645 uint8_t taglen;
646 uint8_t *tag;
647 uint8_t *value;
648 } dns_caa_t;
649
650 static inline bool is_valid_label_char(int c)
651 {
652 return isalnum(c) || c == '-' || c == '_';
653 }
654
655 /**
656 * Parse a DNS name from a DNS packet into a buffer.
657 *
658 * @param begin A pointer to the first byte of the DNS packet.
659 * @param buf A pointer to the first byte of the name to be parsed.
660 * @param end A pointer to the first byte succeeding the DNS packet.
661 * @param name The buffer which the name is read into.
662 * @param len Pointer to an integer which is filled with the total length of the name.
663 * @param next Will be set to the byte succeeding the first DNS pointer if applicable or the entire DNS name otherwise.
664 * @return Whether the name was parsed successfully.
665 */
666 static bool parse_name(uint8_t *begin, uint8_t *buf, const uint8_t *end, uint8_t *name, uint8_t *len, uint8_t **next)
667 {
668 int label_type;
669 int label_len;
670 int name_len = 0;
671 uint8_t *pointer = NULL;
672
673 while (true)
674 {
675 if (buf >= end)
676 {
677 return false;
678 }
679 label_type = (*buf & 0xC0);
680 if (label_type == 0xC0) // Compressed
681 {
682 if(end - buf < 2)
683 {
684 return false;
685 }
686
687 // Set the next parameter if it has not been set yet
688 if (next && !pointer)
689 {
690 *next = buf + 2;
691 }
692
693 // Parse pointer address
694 pointer = begin + (htons(*((uint16_t *) buf)) & 0x3FFF);
695
696 // Address must be smaller than the current position
697 if (pointer >= buf)
698 {
699 return false;
700 }
701
702 // Continue parsing at the pointer location.
703 buf = pointer;
704 }
705 else if (label_type == 0x00) // Uncompressed
706 {
707 label_len = (*buf & 0x3F) + 1;
708 name_len += label_len;
709 if (name_len >= 0xFF || end - buf < label_len)
710 {
711 return false;
712 }
713 if (label_len == 1)
714 {
715 *name = 0;
716 if (next && !pointer)
717 {
718 *next = buf + 1;
719 }
720 *len = (uint8_t) name_len;
721 return true;
722 }
723 else
724 {
725 memcpy(name, buf, (size_t)label_len);
726 name += label_len;
727 buf += label_len;
728 }
729 }
730 else
731 {
732 return false;
733 }
734 }
735 }
736
737 static inline void dns_buffer_set_id(uint8_t *buf, uint16_t id)
738 {
739 *((uint16_t *) buf) = htons(id);
740 }
741
742 char *dns_class2str(dns_class cls)
743 {
744 static char numbuf[16];
745
746 switch(cls)
747 {
748 case DNS_CLS_IN:
749 return "IN";
750 case DNS_CLS_CH:
751 return "H";
752 case DNS_CLS_HS:
753 return "HS";
754 case DNS_CLS_QCLASS_NONE:
755 return "QNONE";
756 case DNS_CLS_QCLASS_ANY:
757 return "QANY";
758 default:
759 snprintf(numbuf, sizeof(numbuf), "%" PRIu16, (uint16_t)cls);
760 return numbuf;
761 }
762 }
763
764 char *dns_opcode2str(dns_opcode opcode)
765 {
766 static char numbuf[16];
767
768 switch(opcode)
769 {
770 case DNS_OPCODE_QUERY:
771 return "QUERY";
772 case DNS_OPCODE_IQUERY:
773 return "IQUERY";
774 case DNS_OPCODE_STATUS:
775 return "STATUS";
776 case DNS_OPCODE_NOTIFY:
777 return "NOTIFY";
778 case DNS_OPCODE_UPDATE:
779 return "UPDATE";
780 default:
781 snprintf(numbuf, sizeof(numbuf), "%" PRIu16, (uint16_t)opcode);
782 return numbuf;
783 }
784 }
785
786 char *dns_rcode2str(dns_rcode rcode)
787 {
788 static char numbuf[16];
789
790 switch (rcode)
791 {
792 case DNS_RCODE_OK:
793 return "NOERROR";
794 case DNS_RCODE_FORMERR:
795 return "FORMERR";
796 case DNS_RCODE_SERVFAIL:
797 return "SERVFAIL";
798 case DNS_RCODE_NXDOMAIN:
799 return "NXDOMAIN";
800 case DNS_RCODE_NOTIMP:
801 return "NOTIMP";
802 case DNS_RCODE_REFUSED:
803 return "REFUSED";
804 case DNS_RCODE_YXDOMAIN:
805 return "YXDOMAIN";
806 case DNS_RCODE_YXRRSET:
807 return "YXRRSET";
808 case DNS_RCODE_NOTAUTH:
809 return "NOTAUTH";
810 case DNS_RCODE_NOTZONE:
811 return "NOTZONE";
812 case DNS_RCODE_BADVERS:
813 return "BADVERS";
814 case DNS_RCODE_BADKEY:
815 return "BADKEY";
816 case DNS_RCODE_BADTIME:
817 return "BADTIME";
818 case DNS_RCODE_BADMODE:
819 return "BADMODE";
820 case DNS_RCODE_BADNAME:
821 return "BADNAME";
822 case DNS_RCODE_BADALG:
823 return "BADALG";
824 case DNS_RCODE_BADTRUNC:
825 return "BADTRUNC";
826 case DNS_RCODE_BADCOOKIE:
827 return "BADCOOKIE";
828 default:
829 snprintf(numbuf, sizeof(numbuf), "%" PRIu16, (uint16_t)rcode);
830 return numbuf;
831 }
832 }
833
834 char *dns_record_type2str(dns_record_type type)
835 {
836 static char numbuf[16];
837
838 switch (type)
839 {
840 case DNS_REC_A:
841 return "A";
842 case DNS_REC_AAAA:
843 return "AAAA";
844 case DNS_REC_AFSDB:
845 return "AFSDB";
846 case DNS_REC_ANY:
847 return "ANY";
848 case DNS_REC_APL:
849 return "APL";
850 case DNS_REC_CAA:
851 return "CAA";
852 case DNS_REC_CDNSKEY:
853 return "CDNSKEY";
854 case DNS_REC_CDS:
855 return "CDS";
856 case DNS_REC_CERT:
857 return "CERT";
858 case DNS_REC_CNAME:
859 return "CNAME";
860 case DNS_REC_DHCID:
861 return "DHCID";
862 case DNS_REC_DLV:
863 return "DLV";
864 case DNS_REC_DNAME:
865 return "DNAME";
866 case DNS_REC_DNSKEY:
867 return "DNSKEY";
868 case DNS_REC_DS:
869 return "DS";
870 case DNS_REC_HIP:
871 return "HIP";
872 case DNS_REC_IPSECKEY:
873 return "IPSECKEY";
874 case DNS_REC_KEY:
875 return "KEY";
876 case DNS_REC_KX:
877 return "KX";
878 case DNS_REC_LOC:
879 return "LOC";
880 case DNS_REC_MX:
881 return "MX";
882 case DNS_REC_NAPTR:
883 return "NAPTR";
884 case DNS_REC_NS:
885 return "NS";
886 case DNS_REC_NSEC:
887 return "NSEC";
888 case DNS_REC_NSEC3:
889 return "NSEC3";
890 case DNS_REC_NSEC3PARAM:
891 return "NSEC3PARAM";
892 case DNS_REC_OPENPGPKEY:
893 return "OPENPGPKEY";
894 case DNS_REC_PTR:
895 return "PTR";
896 case DNS_REC_RRSIG:
897 return "RRSIG";
898 case DNS_REC_RP:
899 return "RP";
900 case DNS_REC_SIG:
901 return "SIG";
902 case DNS_REC_SOA:
903 return "SOA";
904 case DNS_REC_SRV:
905 return "SRV";
906 case DNS_REC_SSHFP:
907 return "SSHFP";
908 case DNS_REC_TA:
909 return "TA";
910 case DNS_REC_TKEY:
911 return "TKEY";
912 case DNS_REC_TLSA:
913 return "TLSA";
914 case DNS_REC_TSIG:
915 return "TSIG";
916 case DNS_REC_TXT:
917 return "TXT";
918 case DNS_REC_URI:
919 return "URI";
920 default:
921 snprintf(numbuf, sizeof(numbuf), "%" PRIu16, (uint16_t)type);
922 return numbuf;
923 }
924 }
925
926 ssize_t dns_str2namebuf(const char *name, uint8_t *buffer)
927 {
928 static uint8_t *bufname;
929 static uint8_t *lenptr;
930 static uint8_t total_len;
931 static uint8_t label_len;
932
933 lenptr = buffer; // points to the byte containing the label length
934 bufname = buffer + 1; // points to the first byte of the actual name
935 total_len = 0;
936 label_len = 0;
937
938 while (true)
939 {
940 char c = *(name++);
941 total_len++;
942 if (total_len > 254)
943 {
944 return -1;
945 }
946 if (c == '.')
947 {
948 *lenptr = label_len;
949 if (total_len == 1)
950 {
951 total_len--;
952 break;
953 }
954 if (*name == 0)
955 {
956 *(bufname++) = 0;
957 break;
958 }
959 lenptr = bufname++;
960 label_len = 0;
961 }
962 else if (c == 0)
963 {
964 *lenptr = label_len;
965 *(bufname++) = 0;
966 break;
967 }
968 else
969 {
970 *(bufname++) = (uint8_t) c;
971 label_len++;
972 if (label_len >= 64)
973 {
974 return -1;
975 }
976 }
977 }
978 return total_len + 1;
979 }
980
981 ssize_t dns_question_create_from_name(uint8_t *buffer, dns_name_t *name, dns_record_type type, uint16_t id)
982 {
983 static uint8_t *aftername;
984
985 memcpy(buffer + 12, name->name, name->length);
986 aftername = buffer + 12 + name->length;
987 dns_buffer_set_id(buffer, id);
988 *((uint16_t *) (buffer + 2)) = 0;
989 *((uint16_t *) aftername) = htons(type);
990 *((uint16_t *) (aftername + 2)) = htons(DNS_CLS_IN);
991 *((uint16_t *) (buffer + 4)) = htons(0x0001);
992 return aftername + 4 - buffer;
993 }
994
995 // Requires a buffer of at least 272 bytes to be supplied
996 static ssize_t dns_question_create(uint8_t *buffer, char *name, dns_record_type type, uint16_t id)
997 {
998 static uint8_t *aftername;
999
1000 ssize_t name_len = dns_str2namebuf(name, buffer + 12);
1001 if(name_len < 0)
1002 {
1003 return -1;
1004 }
1005 aftername = buffer + 12 + name_len;
1006
1007 dns_buffer_set_id(buffer, id);
1008 *((uint16_t *) (buffer + 2)) = 0;
1009 *((uint16_t *) aftername) = htons(type);
1010 *((uint16_t *) (aftername + 2)) = htons(DNS_CLS_IN);
1011 *((uint16_t *) (buffer + 4)) = htons(0x0001);
1012 return aftername + 4 - buffer;
1013 }
1014
1015 bool dns_send_question(uint8_t *buffer, char *name, dns_record_type type, uint16_t id, int fd, struct sockaddr_storage *addr)
1016 {
1017 ssize_t result = dns_question_create(buffer, name, type, id);
1018 if (result < DNS_PACKET_MINIMUM_SIZE)
1019 {
1020 return false;
1021 }
1022 sendto(fd,
1023 buffer,
1024 (size_t) result,
1025 0,
1026 (struct sockaddr *) addr,
1027 addr->ss_family == PF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
1028 return true;
1029 }
1030
1031 bool dns_parse_question(uint8_t *buf, size_t len, dns_head_t *head, uint8_t **body_begin)
1032 {
1033 static uint8_t *end; // exclusive
1034 static bool name_parsed;
1035 static uint8_t *qname_end;
1036
1037 end = buf + len;
1038 if (len < DNS_PACKET_MINIMUM_SIZE)
1039 {
1040 return false;
1041 }
1042
1043 head->header.id = ntohs((*(uint16_t *) buf));
1044 head->header.qr = (bool) (buf[2] & 0x80);
1045 head->header.opcode = (uint8_t) ((buf[2] & (0x78)) >> 3);
1046 head->header.aa = (bool) (buf[2] & 0x04);
1047 head->header.tc = (bool) (buf[2] & 0x02);
1048 head->header.rd = (bool) (buf[2] & 0x01);
1049 head->header.ra = (bool) (buf[3] & 0x80);
1050 head->header.z = (bool) (buf[4] & 0x40);
1051 head->header.ad = (bool) (buf[3] & 0x20);
1052 head->header.cd = (bool) (buf[3] & 0x10);
1053 head->header.rcode = (uint8_t) (buf[3] & 0x0F);
1054
1055 head->header.ans_count = ntohs((*(uint16_t *) (buf + 6)));
1056 head->header.auth_count = ntohs((*(uint16_t *) (buf + 8)));
1057 head->header.add_count = ntohs((*(uint16_t *) (buf + 10)));
1058 head->header.q_count = ntohs((*(uint16_t *) (buf + 4)));
1059 if (head->header.q_count != 1)
1060 {
1061 return false;
1062 }
1063 name_parsed = parse_name(buf, buf + 12, end, head->question.name.name, &head->question.name.length, &qname_end);
1064 if (qname_end + 2 > end)
1065 {
1066 return false;
1067 }
1068 if (!name_parsed)
1069 {
1070 return false;
1071 }
1072 head->question.type = (dns_record_type) ntohs((*(uint16_t *) qname_end));
1073 head->question.class = ntohs((*(uint16_t *) (qname_end + 2)));
1074 if (body_begin)
1075 {
1076 *body_begin = qname_end + 4;
1077 }
1078 return true;
1079 }
1080
1081 /**
1082 * Check whether two DNS names are equal (case-insensitive).
1083 *
1084 * @param name1 Valid DNS name 1.
1085 * @param name2 Valid DNS name 2.
1086 * @return The result of the comparison as a boolean.
1087 */
1088 bool dns_names_eq(dns_name_t *name1, dns_name_t *name2)
1089 {
1090 if(name1->length != name2->length)
1091 {
1092 return false;
1093 }
1094 uint_fast8_t label_length_offset = 0;
1095 for(uint_fast8_t i = 0; i < name1->length; i++)
1096 {
1097 if (i == label_length_offset)
1098 {
1099 if (name1->name[i] != name2->name[i])
1100 {
1101 return false;
1102 }
1103 label_length_offset += name1->name[i];
1104 }
1105 else
1106 {
1107 if (tolower(name1->name[i]) != tolower(name2->name[i]))
1108 {
1109 return false;
1110 }
1111 }
1112 }
1113 return true;
1114 }
1115
1116 bool dns_raw_names_eq(dns_name_t *name1, dns_name_t *name2)
1117 {
1118 return name1->length == name2->length && memcmp(name1->name, name2->name, name1->length) == 0;
1119 }
1120
1121 bool dns_parse_record_raw(uint8_t *begin, uint8_t *buf, const uint8_t *end, uint8_t **next, dns_record_t *record)
1122 {
1123 if (!parse_name(begin, buf, end, record->name.name, &record->name.length, next))
1124 {
1125 return false;
1126 }
1127 if (*next + 10 > end)
1128 {
1129 return false;
1130 }
1131
1132 record->type = ntohs((*(uint16_t *) (*next)));
1133 record->class = ntohs((*(uint16_t *) (*next + 2)));
1134 record->ttl = ntohl((*(uint32_t *) (*next + 4)));
1135 record->length = ntohs((*(uint16_t *) (*next + 8)));
1136 *next = *next + 10;
1137
1138 record->data.raw = *next;
1139
1140 *next = *next + record->length;
1141 if (*next > end)
1142 {
1143 return false;
1144 }
1145 return true;
1146 }
1147
1148 bool dns_parse_record(uint8_t *begin, uint8_t *buf, const uint8_t *end, uint8_t **next, dns_record_t *record)
1149 {
1150 if(!dns_parse_record_raw(begin, buf, end, next, record))
1151 {
1152 return false;
1153 }
1154
1155 if (record->type == DNS_REC_A)
1156 {
1157 if (record->length != 4)
1158 {
1159 return false;
1160 }
1161 memcpy(&record->data.in_addr, record->data.raw, 4);
1162 }
1163 else if (record->type == DNS_REC_AAAA)
1164 {
1165 if (record->length != 16)
1166 {
1167 return false;
1168 }
1169 memcpy(&record->data.in6_addr, record->data.raw, 16);
1170 }
1171 else if (record->type == DNS_REC_NS)
1172 {
1173 if (record->length > 0xFF)
1174 {
1175 return false;
1176 }
1177 if (!parse_name(begin, record->data.raw, end, record->data.name.name, &record->data.name.length, NULL))
1178 {
1179 return false;
1180 }
1181 }
1182
1183 // We don't care about any other records.
1184
1185 return true;
1186 }
1187
1188 bool dns_parse_body(uint8_t *buf, uint8_t *begin, const uint8_t *end, dns_pkt_t *packet)
1189 {
1190 uint8_t *next;
1191 int_fast32_t i;
1192
1193 next = buf;
1194 for (i = 0; i < min(packet->head.header.ans_count, elements(packet->body.ans) - 1); i++)
1195 {
1196 if (!dns_parse_record(begin, next, end, &next, &packet->body.ans[i]))
1197 {
1198 return false;
1199 }
1200 }
1201 packet->body.ans[i].type = 0;
1202
1203 for (i = 0; i < min(packet->head.header.auth_count, elements(packet->body.auth) - 1); i++)
1204 {
1205 if (!dns_parse_record(begin, next, end, &next, &packet->body.auth[i]))
1206 {
1207 return false;
1208 }
1209 }
1210 packet->body.auth[i].type = 0;
1211
1212 for (i = 0; i < min(packet->head.header.add_count, elements(packet->body.add) - 1); i++)
1213 {
1214 if (!dns_parse_record(begin, next, end, &next, &packet->body.add[i]))
1215 {
1216 return false;
1217 }
1218 }
1219 packet->body.add[i].type = 0;
1220
1221 // TODO: Check whether overly long packets are valid. If not, discard them here.
1222
1223 return true;
1224 }
1225
1226 bool dns_parse_reply(uint8_t *buf, size_t len, dns_pkt_t *packet)
1227 {
1228 uint8_t *body_begin;
1229 if (!dns_parse_question(buf, len, &packet->head, &body_begin))
1230 {
1231 return false;
1232 }
1233 return dns_parse_body(body_begin, buf, buf + len, packet);
1234 }
1235
1236 void dns_buf_set_qr(uint8_t *buf, bool value)
1237 {
1238 buf[2] &= 0x7F;
1239 buf[2] |= value << 7;
1240 }
1241
1242 void dns_buf_set_rd(uint8_t *buf, bool value)
1243 {
1244 buf[2] &= 0xFE;
1245 buf[2] |= value;
1246 }
1247
1248 void dns_buf_set_rcode(uint8_t *buf, uint8_t code)
1249 {
1250 buf[3] &= 0xF0;
1251 buf[3] |= code;
1252 }
1253
1254 void dns_send_reply(uint8_t *buffer, size_t len, int fd, struct sockaddr_storage *addr)
1255 {
1256 sendto(fd,
1257 buffer,
1258 len,
1259 0,
1260 (struct sockaddr *) addr,
1261 addr->ss_family == PF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
1262 }
1263
1264 bool dns_create_reply(uint8_t *buffer, size_t *len, char *name, dns_record_type type, uint16_t id, dns_rcode code)
1265 {
1266 ssize_t result = dns_question_create(buffer, name, type, id);
1267 if (result < DNS_PACKET_MINIMUM_SIZE)
1268 {
1269 return false;
1270 }
1271 *len = (size_t) result;
1272 dns_buf_set_qr(buffer, true);
1273 dns_buf_set_rcode(buffer, code);
1274 return true;
1275 }
1276
1277 bool dns_print_readable(char **buf, size_t buflen, const uint8_t *source, size_t len)
1278 {
1279 char *endbuf = *buf + buflen;
1280 size_t label_length_offset = 0;
1281
1282 for(size_t i = 0; i < len; i++)
1283 {
1284 if(i == label_length_offset)
1285 {
1286 if(endbuf - *buf <= 1)
1287 {
1288 **buf = 0;
1289 return false;
1290 }
1291 if(i != 0 || len == 1)
1292 {
1293 *((*buf)++) = '.';
1294 }
1295 label_length_offset += source[i] + 1;
1296 continue;
1297 }
1298 if(source[i] >= ' ' && source[i] <= '~' && source[i] != '\\' && source[i] != '.')
1299 {
1300 if(endbuf - *buf <= 1)
1301 {
1302 **buf = 0;
1303 return false;
1304 }
1305 *((*buf)++) = source[i];
1306 }
1307 else
1308 {
1309 if(*buf >= endbuf - 4)
1310 {
1311 **buf = 0;
1312 return false;
1313 }
1314 *((*buf)++) = '\\';
1315 *((*buf)++) = 'x';
1316 char hex1 = (char)((source[i] >> 4) & 0xF);
1317 char hex2 = (char)(source[i] & 0xF);
1318 *((*buf)++) = (char)(hex1 + (hex1 < 10 ? '0' : ('a' - 10)));
1319 *((*buf)++) = (char)(hex2 + (hex2 < 10 ? '0' : ('a' - 10)));
1320 }
1321 }
1322 **buf = 0;
1323 return true;
1324 }
1325
1326 char* dns_name2str(dns_name_t *name)
1327 {
1328 static char buf[0xFF * 4];
1329
1330 char *ptr = buf;
1331 dns_print_readable(&ptr, sizeof(buf), name->name, name->length);
1332 return buf;
1333 }
1334
1335 void dns_question2str(dns_question_t *question, char *buf, size_t len)
1336 {
1337 snprintf(buf, len, "%s %s %s",
1338 dns_name2str(&question->name),
1339 dns_class2str((dns_class)question->class),
1340 dns_record_type2str(question->type));
1341 }
1342
1343 char* dns_raw_record_data2str(dns_record_t *record, uint8_t *begin, uint8_t *end)
1344 {
1345 static char buf[0xFFFF0];
1346 static dns_name_t name;
1347
1348 char *ptr = buf;
1349
1350 switch(record->type)
1351 {
1352 case DNS_REC_NS:
1353 case DNS_REC_CNAME:
1354 case DNS_REC_DNAME:
1355 case DNS_REC_PTR:
1356 parse_name(begin, record->data.raw, end, name.name, &name.length, NULL);
1357 dns_print_readable(&ptr, sizeof(buf), name.name, name.length);
1358 break;
1359 case DNS_REC_MX:
1360 if(record->length < 3)
1361 {
1362 goto raw;
1363 }
1364 parse_name(begin, record->data.raw + 2, end, name.name, &name.length, NULL);
1365 int no = sprintf(buf, "%" PRIu16 " ", ntohs(*((uint16_t*)record->data.raw)));
1366 ptr += no;
1367 dns_print_readable(&ptr, sizeof(buf), name.name, name.length);
1368 break;
1369 case DNS_REC_TXT:
1370 {
1371 uint8_t *record_end = record->data.raw + record->length;
1372 uint8_t *data_ptr = record->data.raw;
1373 while(data_ptr < record_end)
1374 {
1375 uint8_t length = *(data_ptr++);
1376 if (data_ptr + length <= record_end)
1377 {
1378 *(ptr++) = '"';
1379 dns_print_readable(&ptr, sizeof(buf), data_ptr, length);
1380 data_ptr += length;
1381 *(ptr++) = '"';
1382 *(ptr++) = ' ';
1383 }
1384 else
1385 {
1386 break;
1387 }
1388 }
1389 *ptr = 0;
1390 break;
1391 }
1392 case DNS_REC_SOA:
1393 {
1394 uint8_t *next;
1395 // We have 5 32-bit values plus two names.
1396 if (record->length < 22)
1397 {
1398 goto raw;
1399 }
1400
1401 parse_name(begin, record->data.raw, end, name.name, &name.length, &next);
1402 dns_print_readable(&ptr, sizeof(buf), name.name, name.length);
1403 *(ptr++) = ' ';
1404
1405 if(next + 20 >= record->data.raw + record->length)
1406 {
1407 goto raw;
1408 }
1409 parse_name(begin, next, end, name.name, &name.length, &next);
1410 dns_print_readable(&ptr, sizeof(buf), name.name, name.length);
1411 *(ptr++) = ' ';
1412 if(next + 20 > record->data.raw + record->length)
1413 {
1414 goto raw;
1415 }
1416
1417 sprintf(ptr, "%" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32,
1418 ntohl(*((uint32_t*)next)),
1419 ntohl(*(((uint32_t*)next) + 1)),
1420 ntohl(*(((uint32_t*)next) + 2)),
1421 ntohl(*(((uint32_t*)next) + 3)),
1422 ntohl(*(((uint32_t*)next) + 4)));
1423 break;
1424 }
1425 case DNS_REC_A:
1426 if(record->length != 4)
1427 {
1428 goto raw;
1429 }
1430 inet_ntop(AF_INET, record->data.raw, buf, sizeof(buf));
1431 break;
1432 case DNS_REC_AAAA:
1433 if(record->length != 16)
1434 {
1435 goto raw;
1436 }
1437 inet_ntop(AF_INET6, record->data.raw, buf, sizeof(buf));
1438 break;
1439 case DNS_REC_CAA:
1440 if(record->length < 2 || record->data.raw[1] < 1 || record->data.raw[1] > 15
1441 || record->data.raw[1] + 2 > record->length)
1442 {
1443 goto raw;
1444 }
1445 int written = sprintf(ptr, "%" PRIu8 " ", (uint8_t)(record->data.raw[0] >> 7));
1446 if(written < 0)
1447 {
1448 return buf;
1449 }
1450 ptr += written;
1451 dns_print_readable(&ptr, sizeof(buf), record->data.raw + 2, record->data.raw[1]);
1452 *(ptr++) = ' ';
1453 *(ptr++) = '"';
1454 dns_print_readable(&ptr, sizeof(buf), record->data.raw + 2 + record->data.raw[1],
1455 (size_t)(record->length - record->data.raw[1] - 2));
1456 *(ptr++) = '"';
1457 *ptr = 0;
1458 break;
1459 raw:
1460 default:
1461 dns_print_readable(&ptr, sizeof(buf), record->data.raw, record->length);
1462 *ptr = 0;
1463 }
1464 return buf;
1465 }
1466
1467 dns_section_t dns_get_section(uint16_t index, dns_header_t *header)
1468 {
1469 if(index < header->ans_count)
1470 {
1471 return DNS_SECTION_ANSWER;
1472 }
1473 else if(index < header->ans_count + header->auth_count)
1474 {
1475 return DNS_SECTION_AUTHORITY;
1476 }
1477 else
1478 {
1479 return DNS_SECTION_ADDITIONAL;
1480 }
1481 }
1482
1483 char *dns_section2str(dns_section_t section)
1484 {
1485 switch(section)
1486 {
1487 case DNS_SECTION_ANSWER:
1488 return "ANSWER";
1489 case DNS_SECTION_ADDITIONAL:
1490 return "ADDITIONAL";
1491 case DNS_SECTION_AUTHORITY:
1492 return "AUTHORITY";
1493 case DNS_SECTION_QUESTION:
1494 return "QUESTION";
1495 default:
1496 return "UNKNOWN";
1497 }
1498 }
1499
1500 char *dns_section2str_lower_plural(dns_section_t section)
1501 {
1502 switch(section)
1503 {
1504 case DNS_SECTION_ANSWER:
1505 return "answers";
1506 case DNS_SECTION_ADDITIONAL:
1507 return "additionals";
1508 case DNS_SECTION_AUTHORITY:
1509 return "authorities";
1510 case DNS_SECTION_QUESTION:
1511 return "questions";
1512 default:
1513 return "unknowns";
1514 }
1515 }
1516
1517 bool dns_in_zone(dns_name_t *name, dns_name_t *zone)
1518 {
1519 return zone->length == 1 // Provided that the label is a FQDN, this is the root zone containing everything else
1520 || (zone->length == name->length
1521 && strcasecmp((char*)name->name + name->length - zone->length, (char*)zone->name) == 0)
1522 || (zone->length < name->length
1523 && strcasecmp((char*)name->name + name->length - zone->length, (char*)zone->name) == 0
1524 && *(name->name + name->length - zone->length - 1) == '.');
1525
1526 }
1527
1528 void dns_print_packet(FILE *f, dns_pkt_t *packet, uint8_t *begin, size_t len, uint8_t *next)
1529 {
1530 static char buf[0xFFFF];
1531 static dns_record_t rec;
1532
1533 fprintf(f,
1534 ";; ->>HEADER<<- opcode: %s, status: %s, id: %"PRIu16"\n"
1535 ";; flags: %s%s%s%s%s; QUERY: %" PRIu16 ", ANSWER: %" PRIu16 ", AUTHORITY: %" PRIu16 ", ADDITIONAL: %" PRIu16 "\n\n"
1536 ";; QUESTION SECTION:\n",
1537 dns_opcode2str((dns_opcode)packet->head.header.opcode),
1538 dns_rcode2str((dns_rcode)packet->head.header.rcode),
1539 packet->head.header.id,
1540 packet->head.header.qr ? "qr " : "",
1541 packet->head.header.ad ? "ad " : "",
1542 packet->head.header.aa ? "aa " : "",
1543 packet->head.header.rd ? "rd " : "",
1544 packet->head.header.ra ? "ra " : "",
1545 packet->head.header.q_count,
1546 packet->head.header.ans_count,
1547 packet->head.header.auth_count,
1548 packet->head.header.add_count
1549 );
1550
1551 dns_question2str(&packet->head.question, buf, sizeof(buf));
1552 fprintf(f, "%s\n", buf);
1553
1554 uint16_t i = 0;
1555 dns_section_t section = DNS_SECTION_QUESTION;
1556 while(dns_parse_record_raw(begin, next, begin + len, &next, &rec))
1557 {
1558 dns_section_t new_section = dns_get_section(i++, &packet->head.header);
1559 if(new_section != section)
1560 {
1561 fprintf(f, "\n;; %s SECTION:\n", dns_section2str(new_section));
1562 section = new_section;
1563 }
1564 fprintf(f,
1565 "%s %" PRIu32 " %s %s %s\n",
1566 dns_name2str(&rec.name),
1567 rec.ttl,
1568 dns_class2str((dns_class)rec.class),
1569 dns_record_type2str((dns_record_type) rec.type),
1570 dns_raw_record_data2str(&rec, begin, begin + len));
1571 }
1572 fprintf(f, "\n\n");
1573 }
1574
1575 #endif //MASSRESOLVER_DNS_H
0 // SPDX-License-Identifier: GPL-3.0-only
1
2 #ifndef MASSDNS_FLOW_H
3 #define MASSDNS_FLOW_H
4
5 #include <signal.h>
6 #include <unistd.h>
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <sys/types.h>
10
11 static void kill_process_group(int sig)
12 {
13 static int received_termination = 0;
14
15 if(received_termination)
16 {
17 return;
18 }
19 received_termination = 1;
20 kill(0, sig);
21 exit(0);
22 }
23
24 static void handle_termination()
25 {
26 signal(SIGINT, kill_process_group);
27 signal(SIGTERM, kill_process_group);
28 }
29
30 // times is the number of resulting processes, i.e. if times is two, the process will fork once
31 size_t split_process(size_t times, pid_t *pids)
32 {
33 if(pids != NULL)
34 {
35 pids[0] = getpid();
36 }
37 for (size_t i = 0; i < times - 1; i++)
38 {
39 pid_t child = fork();
40 switch (child)
41 {
42 case -1:
43 {
44 perror("Failed to fork");
45 exit(EXIT_FAILURE);
46 }
47 case 0:
48 {
49 handle_termination();
50 return i + 1;
51 }
52 default:
53 if(pids != NULL)
54 {
55 pids[i + 1] = child;
56 }
57 break;
58 }
59 }
60 if(times > 1)
61 {
62 handle_termination();
63 }
64 return 0;
65 }
66
67 #endif
0 // SPDX-License-Identifier: Apache-2.0
1
2 #ifndef MASSDNS_HASHMAP_H
3 #define MASSDNS_HASHMAP_H
4 /*
5 * Copyright (C) 2007 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19 #include <assert.h>
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdbool.h>
24 #include <sys/types.h>
25
26 // http://www.cse.yorku.ca/~oz/hash.html
27 unsigned long hash_djb2(unsigned char *str)
28 {
29 unsigned long hash = 5381;
30 int c;
31 while ((c = *str++) != 0)
32 {
33 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
34 }
35 return hash;
36 }
37
38 int hash_string(void *str)
39 {
40 return (int) hash_djb2((unsigned char *) str);
41 }
42
43
44 typedef struct Entry Entry;
45 struct Entry {
46 void* key;
47 int hash;
48 void* value;
49 Entry* next;
50 };
51 typedef struct Hashmap {
52 Entry** buckets;
53 size_t bucketCount;
54 int (*hash)(void* key);
55 bool (*equals)(void* keyA, void* keyB);
56 size_t size;
57 } Hashmap;
58 Hashmap* hashmapCreate(size_t initialCapacity,
59 int (*hash)(void* key), bool (*equals)(void* keyA, void* keyB)) {
60 assert(hash != NULL);
61 assert(equals != NULL);
62
63 Hashmap* map = malloc(sizeof(Hashmap));
64 if (map == NULL) {
65 return NULL;
66 }
67
68 // 0.75 load factor.
69 size_t minimumBucketCount = initialCapacity * 4 / 3;
70 map->bucketCount = 1;
71 while (map->bucketCount <= minimumBucketCount) {
72 // Bucket count must be power of 2.
73 map->bucketCount <<= 1;
74 }
75 map->buckets = calloc(map->bucketCount, sizeof(Entry*));
76 if (map->buckets == NULL) {
77 free(map);
78 return NULL;
79 }
80
81 map->size = 0;
82 map->hash = hash;
83 map->equals = equals;
84
85 return map;
86 }
87 /**
88 * Hashes the given key.
89 */
90 #ifdef __clang__
91 __attribute__((no_sanitize("integer")))
92 #endif
93 static inline int hashKey(Hashmap* map, void* key) {
94 int h = map->hash(key);
95 // We apply this secondary hashing discovered by Doug Lea to defend
96 // against bad hashes.
97 h += ~(h << 9);
98 h ^= (((unsigned int) h) >> 14);
99 h += (h << 4);
100 h ^= (((unsigned int) h) >> 10);
101
102 return h;
103 }
104 size_t hashmapSize(Hashmap* map) {
105 return map->size;
106 }
107 static inline size_t calculateIndex(size_t bucketCount, int hash) {
108 return ((size_t) hash) & (bucketCount - 1);
109 }
110 static void expandIfNecessary(Hashmap* map) {
111 // If the load factor exceeds 0.75...
112 if (map->size > (map->bucketCount * 3 / 4)) {
113 // Start off with a 0.33 load factor.
114 size_t newBucketCount = map->bucketCount << 1;
115 Entry** newBuckets = calloc(newBucketCount, sizeof(Entry*));
116 if (newBuckets == NULL) {
117 // Abort expansion.
118 return;
119 }
120
121 // Move over existing entries.
122 size_t i;
123 for (i = 0; i < map->bucketCount; i++) {
124 Entry* entry = map->buckets[i];
125 while (entry != NULL) {
126 Entry* next = entry->next;
127 size_t index = calculateIndex(newBucketCount, entry->hash);
128 entry->next = newBuckets[index];
129 newBuckets[index] = entry;
130 entry = next;
131 }
132 }
133 // Copy over internals.
134 free(map->buckets);
135 map->buckets = newBuckets;
136 map->bucketCount = newBucketCount;
137 }
138 }
139
140 void hashmapFree(Hashmap* map) {
141 size_t i;
142 for (i = 0; i < map->bucketCount; i++) {
143 Entry* entry = map->buckets[i];
144 while (entry != NULL) {
145 Entry* next = entry->next;
146 free(entry);
147 entry = next;
148 }
149 }
150 free(map->buckets);
151 free(map);
152 }
153 #ifdef __clang__
154 __attribute__((no_sanitize("integer")))
155 #endif
156 /* FIXME: relies on signed integer overflow, which is undefined behavior */
157 int hashmapHash(void* key, size_t keySize) {
158 int h = keySize;
159 char* data = (char*) key;
160 size_t i;
161 for (i = 0; i < keySize; i++) {
162 h = h * 31 + *data;
163 data++;
164 }
165 return h;
166 }
167 static Entry* createEntry(void* key, int hash, void* value) {
168 Entry* entry = malloc(sizeof(Entry));
169 if (entry == NULL) {
170 return NULL;
171 }
172 entry->key = key;
173 entry->hash = hash;
174 entry->value = value;
175 entry->next = NULL;
176 return entry;
177 }
178 static inline bool equalKeys(void* keyA, int hashA, void* keyB, int hashB,
179 bool (*equals)(void*, void*)) {
180 if (keyA == keyB) {
181 return true;
182 }
183 if (hashA != hashB) {
184 return false;
185 }
186 return equals(keyA, keyB);
187 }
188 void* hashmapPut(Hashmap* map, void* key, void* value) {
189 int hash = hashKey(map, key);
190 size_t index = calculateIndex(map->bucketCount, hash);
191 Entry** p = &(map->buckets[index]);
192 while (true) {
193 Entry* current = *p;
194 // Add a new entry.
195 if (current == NULL) {
196 *p = createEntry(key, hash, value);
197 if (*p == NULL) {
198 errno = ENOMEM;
199 return NULL;
200 }
201 map->size++;
202 expandIfNecessary(map);
203 return NULL;
204 }
205 // Replace existing entry.
206 if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
207 void* oldValue = current->value;
208 current->value = value;
209 return oldValue;
210 }
211 // Move to next entry.
212 p = &current->next;
213 }
214 }
215 void* hashmapGet(Hashmap* map, void* key) {
216 int hash = hashKey(map, key);
217 size_t index = calculateIndex(map->bucketCount, hash);
218 Entry* entry = map->buckets[index];
219 while (entry != NULL) {
220 if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) {
221 return entry->value;
222 }
223 entry = entry->next;
224 }
225 return NULL;
226 }
227 void* hashmapGetWithKey(Hashmap* map, void* key, void **originalKey) {
228 int hash = hashKey(map, key);
229 size_t index = calculateIndex(map->bucketCount, hash);
230 Entry* entry = map->buckets[index];
231 while (entry != NULL) {
232 if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) {
233 *originalKey = entry->key;
234 return entry->value;
235 }
236 entry = entry->next;
237 }
238 return NULL;
239 }
240 bool hashmapContainsKey(Hashmap* map, void* key) {
241 int hash = hashKey(map, key);
242 size_t index = calculateIndex(map->bucketCount, hash);
243 Entry* entry = map->buckets[index];
244 while (entry != NULL) {
245 if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) {
246 return true;
247 }
248 entry = entry->next;
249 }
250 return false;
251 }
252 void* hashmapMemoize(Hashmap* map, void* key,
253 void* (*initialValue)(void* key, void* context), void* context) {
254 int hash = hashKey(map, key);
255 size_t index = calculateIndex(map->bucketCount, hash);
256 Entry** p = &(map->buckets[index]);
257 while (true) {
258 Entry* current = *p;
259 // Add a new entry.
260 if (current == NULL) {
261 *p = createEntry(key, hash, NULL);
262 if (*p == NULL) {
263 errno = ENOMEM;
264 return NULL;
265 }
266 void* value = initialValue(key, context);
267 (*p)->value = value;
268 map->size++;
269 expandIfNecessary(map);
270 return value;
271 }
272 // Return existing value.
273 if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
274 return current->value;
275 }
276 // Move to next entry.
277 p = &current->next;
278 }
279 }
280 void* hashmapRemove(Hashmap* map, void* key) {
281 int hash = hashKey(map, key);
282 size_t index = calculateIndex(map->bucketCount, hash);
283 // Pointer to the current entry.
284 Entry** p = &(map->buckets[index]);
285 Entry* current;
286 while ((current = *p) != NULL) {
287 if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
288 void* value = current->value;
289 *p = current->next;
290 free(current);
291 map->size--;
292 return value;
293 }
294 p = &current->next;
295 }
296 return NULL;
297 }
298 void hashmapForEach(Hashmap* map,
299 bool (*callback)(void* key, void* value, void* context),
300 void* context) {
301 size_t i;
302 for (i = 0; i < map->bucketCount; i++) {
303 Entry* entry = map->buckets[i];
304 while (entry != NULL) {
305 Entry *next = entry->next;
306 if (!callback(entry->key, entry->value, context)) {
307 return;
308 }
309 entry = next;
310 }
311 }
312 }
313 size_t hashmapCurrentCapacity(Hashmap* map) {
314 size_t bucketCount = map->bucketCount;
315 return bucketCount * 3 / 4;
316 }
317 size_t hashmapCountCollisions(Hashmap* map) {
318 size_t collisions = 0;
319 size_t i;
320 for (i = 0; i < map->bucketCount; i++) {
321 Entry* entry = map->buckets[i];
322 while (entry != NULL) {
323 if (entry->next != NULL) {
324 collisions++;
325 }
326 entry = entry->next;
327 }
328 }
329 return collisions;
330 }
331 int hashmapIntHash(void* key) {
332 // Return the key value itself.
333 return *((int*) key);
334 }
335 bool hashmapIntEquals(void* keyA, void* keyB) {
336 int a = *((int*) keyA);
337 int b = *((int*) keyB);
338 return a == b;
339 }
340 #endif
0 // SPDX-License-Identifier: GPL-3.0-only
1
2 #ifndef INC_LIST
3 #define INC_LIST
4
5 #include "buffers.h"
6 #include "security.h"
7 #include <stdbool.h>
8
9 #define single_list_foreach(list, element) for (single_list_element_t *(element) = (list).first; (element) != NULL; (element) = (element)->next)
10 #define single_list_ref_foreach(list, element) for (single_list_element_t *(element) = (list)->first; (element) != NULL; (element) = (element)->next)
11 #define single_list_foreach_free(list, element) for (single_list_element_t *(element) = (list).first; (element) != NULL; (element) = single_list_free_and_next(element))
12 #define single_list_ref_foreach_free(list, element) for (single_list_element_t *(element) = (list)->first; (element) != NULL; (element) = single_list_free_and_next(element))
13
14 #define double_list_foreach_free(list, element) for (double_list_element_t *(element) = (list).first; (element) != NULL; (element) = double_list_free_and_next(element))
15
16 typedef struct single_list_element
17 {
18 void *data;
19 struct single_list_element *next;
20 } single_list_element_t;
21
22 typedef struct
23 {
24 size_t count;
25 single_list_element_t *first;
26 single_list_element_t *last;
27 } single_list_t;
28
29 typedef struct double_list_element
30 {
31 void *data;
32 struct double_list_element *previous;
33 struct double_list_element *next;
34 } double_list_element_t;
35
36 typedef struct
37 {
38 size_t count;
39 double_list_element_t *first;
40 double_list_element_t *last;
41 } double_list_t;
42
43 size_t single_list_count(single_list_t* list)
44 {
45 return list->count;
46 }
47
48 bool single_list_iterate(single_list_t *list, bool (*f)(void *, void *), void *param)
49 {
50 single_list_element_t* element = list->first;
51 while (element != NULL)
52 {
53 single_list_element_t *next = element->next;
54 if(!f(element->data, param))
55 {
56 return false;
57 }
58 element = next;
59 }
60 return true;
61 }
62
63 bool single_list_iterate_free(single_list_t *list, bool (*f)(void *, void *), void *param)
64 {
65 single_list_element_t* element = list->first;
66 while (element != NULL)
67 {
68 single_list_element_t *next = element->next;
69 if(!f(element->data, param))
70 {
71 return false;
72 }
73 free(element);
74 list->first = next;
75 list->count--;
76 element = next;
77 }
78 list->last = NULL;
79 return true;
80 }
81
82 bool single_list_element_set_array_element(void *element, void *param)
83 {
84 buffer_t *buffer = param;
85 void **data = buffer->data;
86 data[buffer->len++] = element;
87 return true;
88 }
89
90 buffer_t single_list_to_array(single_list_t *list)
91 {
92 buffer_t buf;
93 buf.len = 0;
94 buf.data = safe_malloc(sizeof(buf.data) * list->count);
95 single_list_iterate(list, single_list_element_set_array_element, &buf);
96 return buf;
97 }
98
99 buffer_t single_list_to_array_copy(single_list_t *list, size_t element_size)
100 {
101 buffer_t buf;
102 buf.len = list->count;
103 buf.data = safe_malloc(element_size * list->count);
104 size_t i = 0;
105 single_list_ref_foreach(list, element)
106 {
107 memcpy(((uint8_t*)buf.data) + (i++) * element_size, element->data, element_size);
108 }
109 return buf;
110 }
111
112 single_list_t *single_list_new()
113 {
114 single_list_t *list = safe_calloc(sizeof(*list));
115 return list;
116 }
117
118 void single_list_init(single_list_t *list)
119 {
120 bzero(list, sizeof(*list));
121 }
122
123 void single_list_cat(single_list_t* left, single_list_t* right)
124 {
125 if(left->last != NULL)
126 {
127 left->last->next = right->first;
128 }
129 else
130 {
131 left->first = right->first;
132 left->last = right->last;
133 }
134 left->count += right->count;
135 left->last = right->last;
136 }
137
138 void single_list_clear(single_list_t *list)
139 {
140 single_list_element_t *element = list->first;
141 while (element != NULL)
142 {
143 single_list_element_t *next = element->next;
144 free(element);
145 element = next;
146 }
147 single_list_init(list);
148 }
149
150 void single_list_free(single_list_t *list)
151 {
152 if(list != NULL)
153 {
154 single_list_clear(list);
155 }
156 free(list);
157 }
158
159 void single_list_free_elements(single_list_t *list)
160 {
161 if(list == NULL)
162 {
163 return;
164 }
165 single_list_element_t *current = list->first;
166 while(current != NULL)
167 {
168 single_list_element_t *next = current->next;
169 free(current->data);
170 free(current);
171 current = next;
172 }
173 }
174
175 void single_list_free_with_elements(single_list_t *list)
176 {
177 single_list_free_elements(list);
178 free(list);
179 }
180
181 void single_list_push_front(single_list_t *list, void *data)
182 {
183 single_list_element_t *new_element = safe_malloc(sizeof(*new_element));
184 new_element->data = data;
185 new_element->next = list->first;
186 if (list->last == NULL)
187 {
188 list->last = new_element;
189 }
190 list->first = new_element;
191 list->count++;
192 }
193
194 single_list_element_t *single_list_push_back(single_list_t *list, void *data)
195 {
196 single_list_element_t *new_element = safe_malloc(sizeof(*new_element));
197 new_element->data = data;
198 new_element->next = NULL;
199 list->count++;
200 if (list->last)
201 {
202 list->last->next = new_element;
203 }
204 else
205 {
206 list->first = new_element;
207 }
208 list->last = new_element;
209 return new_element;
210 }
211
212 /**
213 * Pop the first element from a list and push it to the back.
214 *
215 * @param list The list to be wrapped.
216 */
217 void single_list_wrap_first(single_list_t *list)
218 {
219 if(list->first == NULL)
220 {
221 return;
222 }
223 list->last->next = list->first;
224 list->last = list->first;
225 list->first = list->first->next;
226 list->last->next = NULL;
227 }
228
229 double_list_t* double_list_new()
230 {
231 double_list_t *list = safe_calloc(sizeof(*list));
232 return list;
233 }
234
235 void double_list_init(double_list_t *list)
236 {
237 bzero(list, sizeof(*list));
238 }
239
240 void double_list_free(double_list_t *list_holder)
241 {
242 double_list_element_t *list = list_holder->first;
243 while (list != NULL)
244 {
245 double_list_element_t *next = list->next;
246 free(list);
247 list = next;
248 }
249 }
250
251 void double_list_push_front(double_list_t *list, void *data)
252 {
253 double_list_element_t *new_element = safe_malloc(sizeof(*new_element));
254 new_element->data = data;
255 new_element->next = list->first;
256 new_element->previous = NULL;
257 if (list->last == NULL)
258 {
259 list->last = new_element;
260 }
261 list->first = new_element;
262 list->count++;
263 }
264
265 double_list_element_t *double_list_push_back(double_list_t *list, void *data)
266 {
267 double_list_element_t *new_element = safe_malloc(sizeof(*new_element));
268 new_element->data = data;
269 new_element->next = NULL;
270 new_element->previous = list->last;
271 list->count++;
272 if (list->last)
273 {
274 list->last->next = new_element;
275 }
276 else
277 {
278 list->first = new_element;
279 }
280 list->last = new_element;
281 return new_element;
282 }
283
284 void double_list_clear(double_list_t *list)
285 {
286 double_list_element_t *element = list->first;
287 while (element != NULL)
288 {
289 double_list_element_t *next = element->next;
290 free(element);
291 element = next;
292 }
293 double_list_init(list);
294 }
295
296 void double_list_iterate(double_list_t *list, void (*f)(double_list_element_t *, size_t, void *), void *param)
297 {
298 double_list_element_t* element = list->first;
299 size_t counter = 0;
300 while (element != NULL)
301 {
302 double_list_element_t *next = element->next;
303 f(element, counter++, param);
304 element = next;
305 }
306 }
307
308 double_list_element_t* double_list_free_and_next(double_list_element_t *element)
309 {
310 double_list_element_t *next = element->next;
311 free(element);
312 return next;
313 }
314
315 single_list_element_t* single_list_free_and_next(single_list_element_t *element)
316 {
317 single_list_element_t *next = element->next;
318 free(element);
319 return next;
320 }
321
322 void single_list_remove(single_list_t* list, void *value)
323 {
324 single_list_element_t *last = NULL;
325 single_list_element_t *element = list->first;
326 while (element != NULL)
327 {
328 if(element->data == value)
329 {
330 if(last == NULL)
331 {
332 list->first = list->first->next;
333 }
334 else
335 {
336 last->next = element->next;
337 }
338 if(element == list->last)
339 {
340 list->last = last;
341 }
342 list->count--;
343 element = single_list_free_and_next(element);
344 }
345 else
346 {
347 last = element;
348 element = element->next;
349 }
350 }
351 }
352
353 #endif
0 // SPDX-License-Identifier: GPL-3.0-only
1
2 #define _GNU_SOURCE
3
4 #ifdef DEBUG
5 #include <sys/resource.h>
6 #endif
7
8 #include "massdns.h"
9 #include "string.h"
10 #include "random.h"
11 #include "net.h"
12 #include "cmd.h"
13 #include "dns.h"
14 #include "list.h"
15 #include "flow.h"
16 #include <unistd.h>
17 #include <pwd.h>
18 #include <grp.h>
19 #include <sys/ioctl.h>
20 #include <stddef.h>
21 #ifdef HAVE_SYSINFO
22 #include <sys/sysinfo.h>
23 #endif
24 #include <limits.h>
25 #include <stdarg.h>
26
27 #ifdef PCAP_SUPPORT
28 #include <net/ethernet.h>
29 #include <netinet/ip.h>
30 #include <netinet/ip6.h>
31 #include <netinet/udp.h>
32 #include <net/if.h>
33 #endif
34
35 static char json_buffer[5 * 0xFFFF];
36
37 void print_help()
38 {
39 fprintf(stderr, ""
40 "Usage: %s [options] [domainlist]\n"
41 " -b --bindto Bind to IP address and port. (Default: 0.0.0.0:0)\n"
42 #ifdef HAVE_EPOLL
43 " --busy-poll Use busy-wait polling instead of epoll.\n"
44 #endif
45 " -c --resolve-count Number of resolves for a name before giving up. (Default: 50)\n"
46 " --drop-group Group to drop privileges to when running as root. (Default: nogroup)\n"
47 " --drop-user User to drop privileges to when running as root. (Default: nobody)\n"
48 " --filter Only output packets with the specified response code.\n"
49 " --flush Flush the output file whenever a response was received.\n"
50 " -h --help Show this help.\n"
51 " --ignore Do not output packets with the specified response code.\n"
52 " -i --interval Interval in milliseconds to wait between multiple resolves of the same\n"
53 " domain. (Default: 500)\n"
54 " -l --error-log Error log file path. (Default: /dev/stderr)\n"
55 " --norecurse Use non-recursive queries. Useful for DNS cache snooping.\n"
56 " -o --output Flags for output formatting.\n"
57 " --predictable Use resolvers incrementally. Useful for resolver tests.\n"
58 " --processes Number of processes to be used for resolving. (Default: 1)\n"
59 " -q --quiet Quiet mode.\n"
60 " --rcvbuf Size of the receive buffer in bytes.\n"
61 " --retry Unacceptable DNS response codes. (Default: REFUSED)\n"
62 " -r --resolvers Text file containing DNS resolvers.\n"
63 " --root Do not drop privileges when running as root. Not recommended.\n"
64 " -s --hashmap-size Number of concurrent lookups. (Default: 10000)\n"
65 " --sndbuf Size of the send buffer in bytes.\n"
66 " --status-format Format for real-time status updates, json or ansi (Default: ansi)\n"
67 " --sticky Do not switch the resolver when retrying.\n"
68 " --socket-count Socket count per process. (Default: 1)\n"
69 " -t --type Record type to be resolved. (Default: A)\n"
70 #ifdef PCAP_SUPPORT
71 " --use-pcap Enable pcap usage.\n"
72 #endif
73 " --verify-ip Verify IP addresses of incoming replies.\n"
74 " -w --outfile Write to the specified output file instead of standard output.\n"
75 "\n"
76 "Output flags:\n"
77 " S - simple text output\n"
78 " F - full text output\n"
79 " B - binary output\n"
80 " J - ndjson output\n"
81 "\n"
82 "Advanced flags for the simple output mode:\n"
83 " d - Include records from the additional section.\n"
84 " i - Indent any reply record.\n"
85 " l - Separate replies using a line feed.\n"
86 " m - Only output reply records that match the question name.\n"
87 " n - Include records from the answer section.\n"
88 " q - Print the question.\n"
89 " r - Print the question with resolver IP address, Unix timestamp and return code prepended.\n"
90 " s - Separate packet sections using a line feed.\n"
91 " t - Include TTL and record class within the output.\n"
92 " u - Include records from the authority section.\n",
93 context.cmd_args.argv[0] ? context.cmd_args.argv[0] : "massdns"
94 );
95 }
96
97
98 /* The default real-time status output, human reeadable, very granular stats */
99 static const char* stats_fmt_ansi = "\033[H\033[2J" // Clear screen (probably simplest and most portable solution)
100 "Processed queries: %zu\n"
101 "Received packets: %zu\n"
102 "Progress: %.2f%% (%02lld h %02lld min %02lld sec / %02lld h %02lld min %02lld sec)\n"
103 "Current incoming rate: %zu pps, average: %zu pps\n"
104 "Current success rate: %zu pps, average: %zu pps\n"
105 "Finished total: %zu, success: %zu (%.2f%%)\n"
106 "Mismatched domains: %zu (%.2f%%), IDs: %zu (%.2f%%)\n"
107 "Failures: %s\n"
108 "Response: | Success: | Total:\n"
109 "OK: | %12zu (%6.2f%%) | %12zu (%6.2f%%)\n"
110 "NXDOMAIN: | %12zu (%6.2f%%) | %12zu (%6.2f%%)\n"
111 "SERVFAIL: | %12zu (%6.2f%%) | %12zu (%6.2f%%)\n"
112 "REFUSED: | %12zu (%6.2f%%) | %12zu (%6.2f%%)\n"
113 "FORMERR: | %12zu (%6.2f%%) | %12zu (%6.2f%%)\n";
114
115 /* Optional real-time status output, all stats on a single line as valid JSON */
116 static const char* stats_fmt_json =
117 "{"
118 "\"processed_queries\":%zu,"
119 "\"received_packets\":%zu,"
120 "\"progress\":"
121 "{"
122 "\"percent\":%.2f,"
123 "\"eta\":{"
124 "\"hours\":%lld,"
125 "\"minutes\":%lld,"
126 "\"seconds\":%lld,"
127 "\"total_hours\":%lld,"
128 "\"total_minutes\":%lld,"
129 "\"total_seconds\":%lld"
130 "}"
131 "},"
132 "\"incoming_pps\":%zu,"
133 "\"average_incoming_pps\":%zu,"
134 "\"success_rate_pps\":%zu,"
135 "\"average_success_rate_pps\":%zu,"
136 "\"finished_total\":%zu,"
137 "\"success_total\":%zu,"
138 "\"success_total_pct\":%.2f,"
139 "\"mismatched_domains\":%zu,"
140 "\"mismatched_domains_pct\":%.2f,"
141 "\"ids\":%zu,"
142 "\"ids_pct\":%.2f,"
143 "\"failures\":\"%s\","
144 "\"response\":{"
145 "\"OK\":{"
146 "\"success_number\":%zu,"
147 "\"success_pct\":%.2f,"
148 "\"total_number\":%zu,"
149 "\"total_pct\":%.2f},"
150 "\"NXDOMAIN\":{"
151 "\"success_number\":%zu,"
152 "\"success_pct\":%.2f,"
153 "\"total_number\":%zu,"
154 "\"total_pct\":%.2f},"
155 "\"SERVFAIL\":{"
156 "\"success_number\":%zu,"
157 "\"success_pct\":%.2f,"
158 "\"total_number\":%zu, "
159 "\"total_pct\":%.2f},"
160 "\"REFUSED\":{ "
161 "\"success_number\":%zu,"
162 "\"success_pct\":%.2f,"
163 "\"total_number\":%zu,"
164 "\"total_pct\":%.2f},"
165 "\"FORMERR\":{"
166 "\"success_number\":%zu,"
167 "\"success_pct\":%.2f,"
168 "\"total_number\":%zu,"
169 "\"total_pct\":%.2f}"
170 "}"
171 "}\n";
172
173 void cleanup()
174 {
175 #ifdef PCAP_SUPPORT
176 if(context.pcap != NULL)
177 {
178 pcap_close(context.pcap);
179 }
180 #endif
181 if(context.map)
182 {
183 hashmapFree(context.map);
184 }
185
186 if(context.resolver_map)
187 {
188 hashmapFree(context.resolver_map);
189 }
190
191 timed_ring_destroy(&context.ring);
192
193 free(context.resolvers.data);
194
195 free(context.sockets.interfaces4.data);
196 free(context.sockets.interfaces6.data);
197
198 urandom_close();
199
200 if(context.domainfile)
201 {
202 fclose(context.domainfile);
203 }
204 if(context.outfile)
205 {
206 fclose(context.outfile);
207 }
208 if(context.logfile)
209 {
210 fclose(context.logfile);
211 }
212
213 free(context.stat_messages);
214
215
216 free(context.lookup_pool.data);
217 free(context.lookup_space);
218
219 for (size_t i = 0; i < context.cmd_args.num_processes * 2; i++)
220 {
221 if(context.sockets.pipes && context.sockets.pipes[i] >= 0)
222 {
223 close(context.sockets.pipes[i]);
224 }
225 }
226 free(context.sockets.pipes);
227 free(context.sockets.master_pipes_read);
228 free(context.pids);
229 free(context.done);
230 }
231
232 void log_msg(const char* format, ...)
233 {
234 if(context.logfile != stderr)
235 {
236 va_list args;
237 va_start(args, format);
238 vfprintf(stderr, format, args);
239 va_end(args);
240 }
241 if(context.logfile)
242 {
243 va_list args;
244 va_start(args, format);
245 vfprintf(context.logfile, format, args);
246 va_end(args);
247 }
248 }
249
250 void clean_exit(int status)
251 {
252 cleanup();
253 exit(status);
254 }
255
256 // Adaption of djb2 for sockaddr_storage
257 int hash_address(void *param)
258 {
259 struct sockaddr_storage *address = param;
260
261 unsigned long hash = 5381;
262 uint8_t *addr_ptr;
263 uint8_t *addr_end;
264
265 if(address->ss_family == AF_INET)
266 {
267 struct sockaddr_in *addr4 = param;
268 addr_ptr = (uint8_t*)&addr4->sin_addr;
269 addr_end = addr_ptr + sizeof(addr4->sin_addr);
270 hash = ((hash << 5) + hash) + ((addr4->sin_port & 0xFF00) >> 8);
271 hash = ((hash << 5) + hash) + (addr4->sin_port & 0x00FF);
272 }
273 else if(address->ss_family == AF_INET6)
274 {
275 struct sockaddr_in6 *addr6 = param;
276 addr_ptr = (uint8_t*)&addr6->sin6_addr;
277 addr_end = addr_ptr + sizeof(addr6->sin6_addr);
278 hash = ((hash << 5) + hash) + ((addr6->sin6_port & 0xFF00) >> 8);
279 hash = ((hash << 5) + hash) + (addr6->sin6_port & 0x00FF);
280 }
281 else
282 {
283 log_msg("Unsupported address for hashing.\n");
284 abort();
285 }
286
287 while (addr_ptr < addr_end)
288 {
289 hash = ((hash << 5) + hash) + *addr_ptr; /* hash * 33 + c */
290 addr_ptr++;
291 }
292 return (int)hash;
293 }
294
295 // Expects valid (non-NULL) pointers to sockaddr storages of family AF_INET / AF_INET6
296 bool addresses_equal(void *param1, void *param2)
297 {
298 struct sockaddr_storage *addr1 = param1;
299 struct sockaddr_storage *addr2 = param2;
300
301 if(addr1->ss_family != addr2->ss_family)
302 {
303 return false;
304 }
305
306 if(addr1->ss_family == AF_INET)
307 {
308 return memcmp(&((struct sockaddr_in*)addr1)->sin_addr,
309 &((struct sockaddr_in*)addr2)->sin_addr, sizeof(((struct sockaddr_in*)addr1)->sin_addr)) == 0
310 && ((struct sockaddr_in*)addr1)->sin_port == ((struct sockaddr_in*)addr2)->sin_port;
311 }
312 else // Must be AF_INET6
313 {
314 return memcmp(&((struct sockaddr_in6*)addr1)->sin6_addr,
315 &((struct sockaddr_in6*)addr2)->sin6_addr, sizeof(((struct sockaddr_in6*)addr1)->sin6_addr)) == 0
316 && ((struct sockaddr_in6*)addr1)->sin6_port == ((struct sockaddr_in6*)addr2)->sin6_port;
317 }
318 return false;
319 }
320
321 buffer_t massdns_resolvers_from_file(char *filename)
322 {
323 char line[4096];
324 FILE *f = fopen(filename, "r");
325 if (f == NULL)
326 {
327 log_msg("Failed to open resolver file: %s\n", strerror(errno));
328 clean_exit(EXIT_FAILURE);
329 }
330 single_list_t *list = single_list_new();
331 while (!feof(f))
332 {
333 if (fgets(line, sizeof(line), f))
334 {
335 trim_end(line);
336 resolver_t *resolver = safe_calloc(sizeof(*resolver));
337 struct sockaddr_storage *addr = &resolver->address;
338 if (str_to_addr(line, 53, addr))
339 {
340 if((addr->ss_family == AF_INET && context.sockets.interfaces4.len > 0)
341 || (addr->ss_family == AF_INET6 && context.sockets.interfaces6.len > 0))
342 {
343 single_list_push_back(list, resolver);
344 }
345 else
346 {
347 log_msg("No query socket for resolver \"%s\" found.\n", line);
348 }
349 }
350 else
351 {
352 log_msg("\"%s\" is not a valid resolver. Skipped.\n", line);
353 }
354 }
355 }
356 fclose(f);
357 buffer_t resolvers = single_list_to_array_copy(list, sizeof(resolver_t));
358 if(single_list_count(list) == 0)
359 {
360 log_msg("No usable resolvers were found. Terminating.\n");
361 clean_exit(EXIT_FAILURE);
362 }
363
364 if(context.cmd_args.verify_ip)
365 {
366 context.resolver_map = hashmapCreate(resolvers.len, hash_address, addresses_equal);
367 if(!context.resolver_map)
368 {
369 log_msg("Failed to create resolver lookup map: %s\n", strerror(errno));
370 abort();
371 }
372
373 for (size_t i = 0; i < resolvers.len; i++)
374 {
375 resolver_t *resolver = ((resolver_t*)resolvers.data) + i;
376
377 errno = 0;
378 hashmapPut(context.resolver_map, &resolver->address, resolver);
379 if (errno != 0)
380 {
381 log_msg("Error putting resolver into hashmap: %s\n", strerror(errno));
382 abort();
383 }
384 }
385 }
386
387 single_list_free_with_elements(list);
388 return resolvers;
389 }
390
391 void set_sndbuf(int fd)
392 {
393 if(context.cmd_args.sndbuf
394 && setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &context.cmd_args.sndbuf, sizeof(context.cmd_args.sndbuf)) != 0)
395 {
396 log_msg("Failed to adjust send buffer size: %s\n", strerror(errno));
397 }
398 }
399
400 void set_rcvbuf(int fd)
401 {
402 if(context.cmd_args.rcvbuf
403 && setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &context.cmd_args.rcvbuf, sizeof(context.cmd_args.rcvbuf)) != 0)
404 {
405 log_msg("Failed to adjust receive buffer size: %s\n", strerror(errno));
406 }
407 }
408
409 void add_default_socket(int version)
410 {
411 socket_info_t info;
412
413 info.descriptor = socket(version == 4 ? PF_INET : PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
414 info.protocol = version == 4 ? PROTO_IPV4 : PROTO_IPV6;
415 info.type = SOCKET_TYPE_QUERY;
416 if(info.descriptor >= 0)
417 {
418 buffer_t *buffer = version == 4 ? &context.sockets.interfaces4 : &context.sockets.interfaces6;
419 buffer->data = safe_realloc(buffer->data, (buffer->len + 1) * sizeof(info));
420 ((socket_info_t*)buffer->data)[buffer->len++] = info;
421 set_rcvbuf(info.descriptor);
422 set_sndbuf(info.descriptor);
423 }
424 else
425 {
426 log_msg("Failed to create IPv%d socket: %s\n", version, strerror(errno));
427 }
428 }
429
430 void set_user_sockets(single_list_t *bind_addrs, buffer_t *buffer)
431 {
432 single_list_t sockets;
433 single_list_init(&sockets);
434 single_list_ref_foreach_free(bind_addrs, element)
435 {
436 struct sockaddr_storage* addr = element->data;
437 socket_info_t info;
438 info.descriptor = socket(addr->ss_family, SOCK_DGRAM, IPPROTO_UDP);
439 info.protocol = addr->ss_family == AF_INET ? PROTO_IPV4 : PROTO_IPV6;
440 info.type = SOCKET_TYPE_QUERY;
441 if(info.descriptor >= 0)
442 {
443 if(bind(info.descriptor, (struct sockaddr*)addr, sizeof(*addr)) != 0)
444 {
445 log_msg("Not adding socket %s due to bind failure: %s\n", sockaddr2str(addr), strerror(errno));
446 }
447 else
448 {
449 set_rcvbuf(info.descriptor);
450 set_sndbuf(info.descriptor);
451 single_list_push_back(&sockets, flatcopy(&info, sizeof(info)));
452 }
453 }
454 else
455 {
456 log_msg("Failed to create IPv%d socket: %s\n", info.protocol, strerror(errno));
457 }
458 free(element->data);
459 }
460 single_list_init(bind_addrs);
461 *buffer = single_list_to_array_copy(&sockets, sizeof(socket_info_t));
462 single_list_clear(&sockets);
463 }
464
465 void query_sockets_setup()
466 {
467 if(single_list_count(&context.cmd_args.bind_addrs4) == 0 && single_list_count(&context.cmd_args.bind_addrs6) == 0)
468 {
469 for(size_t i = 0; i < context.cmd_args.socket_count; i++)
470 {
471 add_default_socket(4);
472 add_default_socket(6);
473 }
474 }
475 else
476 {
477 set_user_sockets(&context.cmd_args.bind_addrs4, &context.sockets.interfaces4);
478 set_user_sockets(&context.cmd_args.bind_addrs6, &context.sockets.interfaces6);
479 }
480 }
481
482 bool next_query(char **qname)
483 {
484 static char line[512];
485 static size_t line_index = 0;
486
487 while (fgets(line, sizeof(line), context.domainfile))
488 {
489 if(line_index >= context.cmd_args.num_processes)
490 {
491 line_index = 0;
492 }
493 if (context.fork_index != line_index++)
494 {
495 continue;
496 }
497 trim_end(line);
498 if (*line == 0)
499 {
500 continue;
501 }
502 *qname = line;
503
504 return true;
505 }
506 return false;
507 }
508
509
510 // This is the djb2 hashing method treating the DNS type as two extra characters
511 int hash_lookup_key(void *key)
512 {
513 unsigned long hash = 5381;
514 uint8_t *entry = ((lookup_key_t *)key)->name.name;
515 int c;
516 while ((c = *entry++) != 0)
517 {
518 hash = ((hash << 5) + hash) + tolower(c); /* hash * 33 + c */
519 }
520 hash = ((hash << 5) + hash) + ((((lookup_key_t *)key)->type & 0xFF00) >> 8);
521 hash = ((hash << 5) + hash) + (((lookup_key_t *)key)->type & 0x00FF);
522 hash = ((hash << 5) + hash) + ((lookup_key_t *)key)->name.length;
523 return (int)hash;
524 }
525
526 void end_warmup()
527 {
528 context.state = STATE_QUERYING;
529 if(context.cmd_args.extreme <= 1 && !context.cmd_args.busypoll)
530 {
531 // Reduce our CPU load from epoll interrupts by removing the EPOLLOUT event
532 #ifdef PCAP_SUPPORT
533 if(!context.pcap)
534 #endif
535 #ifdef HAVE_EPOLL
536 {
537 add_sockets(context.epollfd, EPOLLIN, EPOLL_CTL_MOD, &context.sockets.interfaces4);
538 add_sockets(context.epollfd, EPOLLIN, EPOLL_CTL_MOD, &context.sockets.interfaces6);
539 }
540 #endif
541 }
542 }
543
544 lookup_t *new_lookup(const char *qname, dns_record_type type, bool *new)
545 {
546 if(context.lookup_pool.len == 0)
547 {
548 log_msg("Empty lookup pool.\n");
549 clean_exit(EXIT_FAILURE);
550 }
551 lookup_entry_t *entry = ((lookup_entry_t**)context.lookup_pool.data)[--context.lookup_pool.len];
552 lookup_key_t *key = &entry->key;
553
554 ssize_t name_length = dns_str2namebuf(qname, key->name.name);
555 if(name_length < 0)
556 {
557 key->name.length = 1;
558 key->name.name[0] = 0;
559 }
560 else
561 {
562 key->name.length = name_length;
563 }
564
565 key->type = type;
566 if(hashmapGet(context.map, key) != NULL)
567 {
568 context.lookup_pool.len++;
569 *new = false;
570 return NULL;
571 }
572 *new = true;
573 lookup_t *value = &entry->value;
574 bzero(value, sizeof(*value));
575
576 value->ring_entry = timed_ring_add(&context.ring, context.cmd_args.interval_ms * TIMED_RING_MS, value);
577 urandom_get(&value->transaction, sizeof(value->transaction));
578 value->key = key;
579
580 errno = 0;
581 hashmapPut(context.map, key, value);
582 if(errno != 0)
583 {
584 log_msg("Error putting lookup into hashmap: %s\n", strerror(errno));
585 abort();
586 }
587
588 context.lookup_index++;
589 context.stats.timeouts[0]++;
590 if(context.lookup_index >= context.cmd_args.hashmap_size)
591 {
592 end_warmup();
593 }
594
595 return value;
596 }
597
598 void send_query(lookup_t *lookup)
599 {
600 static uint8_t query_buffer[0x200];
601
602 // Choose random resolver
603 // Pool of resolvers cannot be empty due to check after parsing resolvers.
604 if(!context.cmd_args.sticky || lookup->resolver == NULL)
605 {
606 if(context.cmd_args.predictable_resolver)
607 {
608 lookup->resolver = ((resolver_t *) context.resolvers.data) + context.lookup_index % context.resolvers.len;
609 }
610 else
611 {
612 lookup->resolver = ((resolver_t *) context.resolvers.data) + urandom_size_t() % context.resolvers.len;
613 }
614 }
615
616 // We need to select the correct socket pool: IPv4 socket pool for IPv4 resolver/IPv6 socket pool for IPv6 resolver
617 buffer_t *interfaces;
618 if(lookup->resolver->address.ss_family == AF_INET)
619 {
620 interfaces = &context.sockets.interfaces4;
621 }
622 else
623 {
624 interfaces = &context.sockets.interfaces6;
625 }
626
627 if(lookup->socket == NULL)
628 {
629 // Pick a random socket from that pool
630 // Pool of sockets cannot be empty due to check when parsing resolvers. Socket creation must have succeeded.
631 size_t socket_index = urandom_size_t() % interfaces->len;
632 lookup->socket = (socket_info_t *) interfaces->data + socket_index;
633 }
634
635 ssize_t result = dns_question_create_from_name(query_buffer, &lookup->key->name, lookup->key->type,
636 lookup->transaction);
637 if (result < DNS_PACKET_MINIMUM_SIZE)
638 {
639 log_msg("Failed to create DNS question for query \"%s\".", dns_name2str(&lookup->key->name));
640 return;
641 }
642
643 // Set or unset the QD bit based on user preference
644 dns_buf_set_rd(query_buffer, !context.cmd_args.norecurse);
645
646 errno = 0;
647 ssize_t sent = sendto(lookup->socket->descriptor, query_buffer, (size_t) result, 0,
648 (struct sockaddr *) &lookup->resolver->address,
649 sockaddr_storage_size(&lookup->resolver->address));
650 if(sent != result)
651 {
652 if(errno != EAGAIN && errno != EWOULDBLOCK)
653 {
654 log_msg("Error sending: %s\n", strerror(errno));
655 }
656 }
657 }
658
659 #define STAT_IDX_OK 0
660 #define STAT_IDX_NXDOMAIN 1
661 #define STAT_IDX_SERVFAIL 2
662 #define STAT_IDX_REFUSED 3
663 #define STAT_IDX_FORMERR 4
664
665 void my_stats_to_msg(stats_exchange_t *stats_msg)
666 {
667 stats_msg->finished = context.stats.finished;
668 stats_msg->finished_success = context.stats.finished_success;
669 stats_msg->fork_index = context.fork_index;
670 stats_msg->mismatch_domain = context.stats.mismatch_domain;
671 stats_msg->mismatch_id = context.stats.mismatch_id;
672 stats_msg->numdomains = context.stats.numdomains;
673 stats_msg->numreplies = context.stats.numreplies;
674 stats_msg->all_rcodes[STAT_IDX_OK] = context.stats.all_rcodes[DNS_RCODE_OK];
675 stats_msg->all_rcodes[STAT_IDX_NXDOMAIN] = context.stats.all_rcodes[DNS_RCODE_NXDOMAIN];
676 stats_msg->all_rcodes[STAT_IDX_SERVFAIL] = context.stats.all_rcodes[DNS_RCODE_SERVFAIL];
677 stats_msg->all_rcodes[STAT_IDX_REFUSED] = context.stats.all_rcodes[DNS_RCODE_REFUSED];
678 stats_msg->all_rcodes[STAT_IDX_FORMERR] = context.stats.all_rcodes[DNS_RCODE_FORMERR];
679 stats_msg->final_rcodes[STAT_IDX_OK] = context.stats.final_rcodes[DNS_RCODE_OK];
680 stats_msg->final_rcodes[STAT_IDX_NXDOMAIN] = context.stats.final_rcodes[DNS_RCODE_NXDOMAIN];
681 stats_msg->final_rcodes[STAT_IDX_SERVFAIL] = context.stats.final_rcodes[DNS_RCODE_SERVFAIL];
682 stats_msg->final_rcodes[STAT_IDX_REFUSED] = context.stats.final_rcodes[DNS_RCODE_REFUSED];
683 stats_msg->final_rcodes[STAT_IDX_FORMERR] = context.stats.final_rcodes[DNS_RCODE_FORMERR];
684 stats_msg->current_rate = context.stats.current_rate;
685 stats_msg->success_rate = context.stats.success_rate;
686 stats_msg->numparsed = context.stats.numparsed;
687 stats_msg->done = (context.state >= STATE_DONE);
688 for(size_t i = 0; i <= context.cmd_args.resolve_count; i++)
689 {
690 stats_msg->timeouts[i] = context.stats.timeouts[i];
691 }
692 }
693
694 void send_stats()
695 {
696 static stats_exchange_t stats_msg;
697
698 my_stats_to_msg(&stats_msg);
699
700 if(write(context.sockets.write_pipe.descriptor, &stats_msg, sizeof(stats_msg)) != sizeof(stats_msg))
701 {
702 log_msg("Could not send stats atomically.\n");
703 }
704 }
705
706 void check_progress()
707 {
708 static struct timespec last_time;
709 static char timeouts[4096];
710 static struct timespec now;
711
712 clock_gettime(CLOCK_MONOTONIC, &now);
713
714 time_t elapsed_ns = (now.tv_sec - last_time.tv_sec) * 1000000000 + (now.tv_nsec - last_time.tv_nsec);
715 size_t rate_pps = elapsed_ns == 0 ? 0 : context.stats.current_rate * TIMED_RING_S / elapsed_ns;
716 size_t rate_success = elapsed_ns == 0 ? 0 : context.stats.success_rate * TIMED_RING_S / elapsed_ns;
717 last_time = now;
718
719 // Send the stats of the child to the parent process
720 if(context.cmd_args.num_processes > 1 && context.fork_index != 0)
721 {
722 send_stats();
723 goto end_stats;
724 }
725
726 if(context.cmd_args.quiet)
727 {
728 return;
729 }
730
731 // Go on with printing stats.
732
733 float progress = context.state == STATE_DONE ? 1 : 0;
734 if(context.domainfile_size > 0) // If the domain file is not a real file, the progress cannot be estimated.
735 {
736 // Get a rough estimate of the progress, only roughly proportional to the number of domains.
737 // Will be very inaccurate if the domain file is sorted per domain name length.
738 long int domain_file_position = ftell(context.domainfile);
739 if (domain_file_position >= 0)
740 {
741 progress = domain_file_position / (float)context.domainfile_size;
742 }
743 }
744
745 time_t total_elapsed_ns = (now.tv_sec - context.stats.start_time.tv_sec) * 1000000000
746 + (now.tv_nsec - context.stats.start_time.tv_nsec); // since last output
747 long long elapsed = now.tv_sec - context.stats.start_time.tv_sec; // resolution of one second should be okay
748 long long sec = elapsed % 60;
749 long long min = (elapsed / 60) % 60;
750 long long h = elapsed / 3600;
751
752 long long estimated_time = progress == 0 ? 0 : (long long)(elapsed / progress);
753 if(estimated_time < elapsed)
754 {
755 estimated_time = elapsed;
756 }
757 long long prog_sec = estimated_time % 60;
758 long long prog_min = (estimated_time / 60) % 60;
759 long long prog_h = (estimated_time / 3600);
760
761 #define stats_percent(a, b) ((b) == 0 ? 0 : (a) / (float) (b) * 100)
762 #define stat_abs_share(a, b) a, stats_percent(a, b)
763 #define rcode_stat(code) stat_abs_share(context.stats.final_rcodes[(code)], context.stats.finished_success),\
764 stat_abs_share(context.stats.all_rcodes[(code)], context.stats.numparsed)
765 #define rcode_stat_multi(code) stat_abs_share(context.stat_messages[0].final_rcodes[(code)], \
766 context.stat_messages[0].finished_success),\
767 stat_abs_share(context.stat_messages[0].all_rcodes[(code)], context.stat_messages[0].numparsed)
768
769 if(context.cmd_args.num_processes == 1)
770 {
771 size_t average_pps = elapsed == 0 ? rate_pps : context.stats.numreplies * TIMED_RING_S / total_elapsed_ns;
772 size_t average_success = elapsed == 0 ? rate_success : context.stats.finished_success * TIMED_RING_S / total_elapsed_ns;
773
774 // Print the detailed timeout stats (number of tries before timeout) to the timeouts buffer.
775 int offset = 0;
776 for (size_t i = 0; i <= context.cmd_args.resolve_count; i++)
777 {
778 float share = stats_percent(context.stats.timeouts[i], context.stats.finished);
779 int result = snprintf(timeouts + offset, sizeof(timeouts) - offset, "%zu: %.2f%%, ", i, share);
780 if (result <= 0 || result >= sizeof(timeouts) - offset)
781 {
782 break;
783 }
784 offset += result;
785 }
786
787 fprintf(stderr,
788 context.status_fmt,
789 context.stats.numdomains,
790 context.stats.numreplies,
791 progress * 100, h, min, sec, prog_h, prog_min, prog_sec, rate_pps, average_pps,
792 rate_success, average_success,
793 context.stats.finished,
794 stat_abs_share(context.stats.finished_success, context.stats.finished),
795 stat_abs_share(context.stats.mismatch_domain, context.stats.numparsed),
796 stat_abs_share(context.stats.mismatch_id, context.stats.numparsed),
797 timeouts,
798
799 rcode_stat(DNS_RCODE_OK),
800 rcode_stat(DNS_RCODE_NXDOMAIN),
801 rcode_stat(DNS_RCODE_SERVFAIL),
802 rcode_stat(DNS_RCODE_REFUSED),
803 rcode_stat(DNS_RCODE_FORMERR)
804 );
805 fflush(stderr);
806 }
807 else
808 {
809 my_stats_to_msg(&context.stat_messages[0]);
810
811 for(size_t j = 1; j < context.cmd_args.num_processes; j++)
812 {
813 for (size_t i = 0; i <= context.cmd_args.resolve_count; i++)
814 {
815 context.stat_messages[0].timeouts[i] += context.stat_messages[j].timeouts[i];
816 }
817 context.stat_messages[0].numreplies += context.stat_messages[j].numreplies;
818 context.stat_messages[0].numparsed += context.stat_messages[j].numparsed;
819 context.stat_messages[0].numdomains += context.stat_messages[j].numdomains;
820 context.stat_messages[0].mismatch_id += context.stat_messages[j].mismatch_id;
821 context.stat_messages[0].mismatch_domain += context.stat_messages[j].mismatch_domain;
822 context.stat_messages[0].finished_success += context.stat_messages[j].finished_success;
823 context.stat_messages[0].finished += context.stat_messages[j].finished;
824 for(size_t i = 0; i < 5; i++)
825 {
826 context.stat_messages[0].all_rcodes[i] += context.stat_messages[j].all_rcodes[i];
827 }
828 for(size_t i = 0; i < 5; i++)
829 {
830 context.stat_messages[0].final_rcodes[i] += context.stat_messages[j].final_rcodes[i];
831 }
832 rate_pps += context.stat_messages[j].current_rate;
833 rate_success += context.stat_messages[j].success_rate;
834 }
835
836 size_t average_pps = elapsed == 0 ? rate_pps :
837 context.stat_messages[0].numreplies * TIMED_RING_S / total_elapsed_ns;
838 size_t average_success = elapsed == 0 ? rate_pps :
839 context.stat_messages[0].finished_success * TIMED_RING_S / total_elapsed_ns;
840
841
842 // Print the detailed timeout stats (number of tries before timeout) to the timeouts buffer.
843 int offset = 0;
844 for (size_t i = 0; i <= context.cmd_args.resolve_count; i++)
845 {
846 float share = stats_percent(context.stat_messages[0].timeouts[i], context.stat_messages[0].finished);
847 int result = snprintf(timeouts + offset, sizeof(timeouts) - offset, "%zu: %.2f%%, ", i, share);
848 if (result <= 0 || result >= sizeof(timeouts) - offset)
849 {
850 break;
851 }
852 offset += result;
853 }
854
855 fprintf(stderr,
856 context.status_fmt,
857 context.stat_messages[0].numdomains,
858 context.stat_messages[0].numreplies,
859 progress * 100, h, min, sec, prog_h, prog_min, prog_sec, rate_pps, average_pps,
860 rate_success, average_success,
861 context.stat_messages[0].finished,
862 stat_abs_share(context.stat_messages[0].finished_success, context.stat_messages[0].finished),
863 stat_abs_share(context.stat_messages[0].mismatch_domain, context.stat_messages[0].numparsed),
864 stat_abs_share(context.stat_messages[0].mismatch_id, context.stat_messages[0].numparsed),
865 timeouts,
866
867 rcode_stat_multi(STAT_IDX_OK),
868 rcode_stat_multi(STAT_IDX_NXDOMAIN),
869 rcode_stat_multi(STAT_IDX_SERVFAIL),
870 rcode_stat_multi(STAT_IDX_REFUSED),
871 rcode_stat_multi(STAT_IDX_FORMERR)
872 );
873 }
874
875 end_stats:
876 context.stats.current_rate = 0;
877 context.stats.success_rate = 0;
878 // Call this function in about one second again
879 timed_ring_add(&context.ring, TIMED_RING_S, check_progress);
880 }
881
882 void done()
883 {
884 context.done[context.fork_index] = true;
885 if(context.fork_index != 0 || context.cmd_args.num_processes == 1)
886 {
887 context.state = STATE_DONE;
888 }
889 else
890 {
891 context.finished++;
892 context.state = (context.finished < context.cmd_args.num_processes ? STATE_WAIT_CHILDREN : STATE_DONE);
893 }
894 if(context.cmd_args.num_processes > 1 && context.fork_index != 0)
895 {
896 send_stats();
897 }
898 check_progress();
899 }
900
901 void can_send()
902 {
903 char *qname;
904 bool new;
905
906 while (hashmapSize(context.map) < context.cmd_args.hashmap_size && context.state <= STATE_QUERYING)
907 {
908 if(!next_query(&qname))
909 {
910 if(hashmapSize(context.map) <= 0)
911 {
912 done();
913 return;
914 }
915 context.state = STATE_COOLDOWN; // We will not create any new queries
916 break;
917 }
918 context.stats.numdomains++;
919 lookup_t *lookup = new_lookup(qname, context.cmd_args.record_type, &new);
920 if(!new)
921 {
922 continue;
923 }
924 send_query(lookup);
925 }
926 }
927
928 bool is_unacceptable(dns_pkt_t *packet)
929 {
930 return context.cmd_args.retry_codes[packet->head.header.rcode];
931 }
932
933 void write_exhausted_tries(lookup_t *lookup, char *status)
934 {
935 if(context.cmd_args.output == OUTPUT_NDJSON && context.format.write_exhausted_tries) {
936 json_escape_str(json_buffer, sizeof(json_buffer), dns_name2str(&lookup->key->name));
937 fprintf(context.outfile,
938 "{\"name\":\"%s\",\"type\":\"%s\",\"class\":\"%s\",\"error\":\"%s\"}\n", json_buffer,
939 dns_record_type2str(lookup->key->type), "IN", status);
940 }
941 }
942
943 void lookup_done(lookup_t *lookup)
944 {
945 context.stats.finished++;
946
947 hashmapRemove(context.map, lookup->key);
948
949 // Return lookup to pool.
950 // According to ISO/IEC 9899:TC2 §6.7.2.1 (13), structs are not padded at the beginning
951 ((lookup_key_t**)context.lookup_pool.data)[context.lookup_pool.len++] = lookup->key;
952
953
954 // When transmission is not aggressive, we only start a new lookup after another one has finished.
955 // When our transmission is very aggressive, we also start a new lookup, although we listen for EPOLLOUT
956 // events as well.
957 if(context.cmd_args.extreme == 0 || context.cmd_args.extreme == 2)
958 {
959 can_send();
960 }
961
962 if(context.state == STATE_COOLDOWN && hashmapSize(context.map) <= 0)
963 {
964 done();
965 }
966 }
967
968 bool retry(lookup_t *lookup)
969 {
970 context.stats.timeouts[lookup->tries]--;
971 context.stats.timeouts[++lookup->tries]++;
972 if(lookup->tries < context.cmd_args.resolve_count)
973 {
974 lookup->ring_entry = timed_ring_add(&context.ring, context.cmd_args.interval_ms * TIMED_RING_MS, lookup);
975 send_query(lookup);
976 return true;
977 }
978 return false;
979 }
980
981 void ring_timeout(void *param)
982 {
983 if(param == check_progress)
984 {
985 check_progress();
986 return;
987 }
988
989 lookup_t *lookup = param;
990 if(!retry(lookup))
991 {
992 write_exhausted_tries(lookup, "TIMEOUT");
993 lookup_done(lookup);
994 }
995 }
996
997 void do_read(uint8_t *offset, size_t len, struct sockaddr_storage *recvaddr)
998 {
999 static dns_pkt_t packet;
1000 static uint8_t *parse_offset;
1001 static lookup_t *lookup;
1002 static resolver_t* resolver;
1003
1004 context.stats.current_rate++;
1005 context.stats.numreplies++;
1006
1007 if(context.cmd_args.verify_ip)
1008 {
1009 resolver = hashmapGet(context.resolver_map, recvaddr);
1010 if(resolver == NULL)
1011 {
1012 //log_msg("Fake/NAT reply from %s\n", sockaddr2str(recvaddr));
1013 return;
1014 }
1015 }
1016
1017 if(!dns_parse_question(offset, len, &packet.head, &parse_offset))
1018 {
1019 return;
1020 }
1021
1022 context.stats.numparsed++;
1023 context.stats.all_rcodes[packet.head.header.rcode]++;
1024
1025 // TODO: Remove unnecessary copy.
1026 //search_key.domain = (char*)packet.head.question.name.name;
1027 lookup = hashmapGet(context.map, &packet.head.question);
1028 if(!lookup) // Most likely reason: delayed response after duplicate query
1029 {
1030 context.stats.mismatch_domain++;
1031 return;
1032 }
1033
1034 if(lookup->transaction != packet.head.header.id)
1035 {
1036 context.stats.mismatch_id++;
1037 return;
1038 }
1039
1040 timed_ring_remove(&context.ring, lookup->ring_entry); // Clear timeout trigger
1041
1042 // Check whether we want to retry resending the packet
1043 if(is_unacceptable(&packet))
1044 {
1045 // We may have tried to many times already.
1046 if(!retry(lookup))
1047 {
1048 write_exhausted_tries(lookup, "MAXRETRIES");
1049 // If this is the case, we will not try again.
1050 lookup_done(lookup);
1051 }
1052 }
1053 else
1054 {
1055 // We are done with the lookup because we received an acceptable reply.
1056 context.stats.finished_success++;
1057 context.stats.final_rcodes[packet.head.header.rcode]++;
1058 context.stats.success_rate++;
1059
1060 // Ignore packet as specified by the user
1061 if(context.cmd_args.filter_mode != FILTER_DISABLED &&
1062 ((context.cmd_args.filter_mode == FILTER_NEGATIVE
1063 && context.cmd_args.filter_codes[packet.head.header.rcode])
1064 || (context.cmd_args.filter_mode == FILTER_POSITIVE
1065 && !context.cmd_args.filter_codes[packet.head.header.rcode])))
1066 {
1067 lookup_done(lookup);
1068 return;
1069 }
1070
1071 // Print packet
1072 time_t now = time(NULL);
1073 uint16_t short_len = (uint16_t) len;
1074 uint8_t *next = parse_offset;
1075 dns_record_t rec;
1076 size_t non_add_count = packet.head.header.ans_count + packet.head.header.auth_count;
1077 dns_section_t section = DNS_SECTION_ANSWER;
1078 size_t section_index = 0;
1079 bool section_emitted = false;
1080
1081 switch(context.cmd_args.output)
1082 {
1083 case OUTPUT_BINARY:
1084 // The output file is platform dependent for performance reasons.
1085 fwrite(&now, sizeof(now), 1, context.outfile);
1086 fwrite(recvaddr, sizeof(*recvaddr), 1, context.outfile);
1087 fwrite(&short_len, sizeof(short_len), 1, context.outfile);
1088 fwrite(offset, short_len, 1, context.outfile);
1089 break;
1090
1091 case OUTPUT_TEXT_FULL: // Print packet similar to dig style
1092 // Resolver and timestamp are not part of the packet, we therefore have to print it manually
1093 fprintf(context.outfile, ";; Server: %s\n;; Size: %" PRIu16 "\n;; Unix time: %lu\n",
1094 sockaddr2str(recvaddr), short_len, now);
1095 dns_print_packet(context.outfile, &packet, offset, len, next);
1096 break;
1097
1098 case OUTPUT_NDJSON: // Only print records from answer section that match the query name (in ndjson)
1099 json_escape_str(json_buffer, sizeof(json_buffer), dns_name2str(&packet.head.question.name));
1100 fprintf(context.outfile,
1101 "{\"name\":\"%s\",\"type\":\"%s\",\"class\":\"%s\",\"status\":\"%s\",\"data\":{",
1102 json_buffer,
1103 dns_record_type2str((dns_record_type) packet.head.question.type),
1104 dns_class2str((dns_class) packet.head.question.class),
1105 dns_rcode2str((dns_rcode) packet.head.header.rcode));
1106 for(size_t rec_index = 0; dns_parse_record_raw(offset, next, offset + len, &next, &rec); rec_index++, section_index++)
1107 {
1108 if(section == DNS_SECTION_ANSWER && section_index >= packet.head.header.ans_count) {
1109 section_index = 0;
1110 section++;
1111 }
1112 if(section == DNS_SECTION_AUTHORITY && section_index >= packet.head.header.auth_count) {
1113 section_index = 0;
1114 section++;
1115 }
1116 if(section == DNS_SECTION_ADDITIONAL && section_index >= packet.head.header.add_count) {
1117 section_index = 0;
1118 section++;
1119 }
1120 if(section_index == 0) {
1121 fprintf(context.outfile, "%s\"%s\":[", section_emitted ? "]," : "",
1122 dns_section2str_lower_plural(section));
1123 }
1124 else
1125 {
1126 fputs(",", context.outfile);
1127 }
1128 json_escape_str(json_buffer, sizeof(json_buffer), dns_name2str(&rec.name));
1129
1130 fprintf(context.outfile,
1131 "{\"ttl\":%" PRIu32 ",\"type\":\"%s\",\"class\":\"%s\",\"name\":\"%s\",\"data\":\"",
1132 rec.ttl,
1133 dns_record_type2str((dns_record_type) rec.type),
1134 dns_class2str((dns_class) rec.class),
1135 json_buffer);
1136 section_emitted = true;
1137 json_escape_str(json_buffer, sizeof(json_buffer),
1138 dns_raw_record_data2str(&rec, offset, offset + short_len));
1139 fputs(json_buffer, context.outfile);
1140 fprintf(context.outfile, "\"}");
1141 }
1142 fprintf(context.outfile, "%s},\"resolver\":\"%s\"}\n", section_emitted ? "]" : "",
1143 sockaddr2str(recvaddr));
1144
1145 break;
1146
1147 case OUTPUT_TEXT_SIMPLE: // Only print records from answer section that match the query name
1148 if(context.format.print_question)
1149 {
1150 if(!context.format.include_meta)
1151 {
1152 fprintf(context.outfile,
1153 "%s %s %s\n",
1154 dns_name2str(&packet.head.question.name),
1155 context.format.ttl ? dns_class2str((dns_class) packet.head.question.class) : "",
1156 dns_record_type2str((dns_record_type) packet.head.question.type));
1157 }
1158 else
1159 {
1160 fprintf(context.outfile,
1161 "%s %lu %s %s %s %s\n",
1162 sockaddr2str(recvaddr),
1163 now,
1164 dns_rcode2str((dns_rcode)packet.head.header.rcode),
1165 dns_name2str(&packet.head.question.name),
1166 context.format.ttl ? dns_class2str((dns_class) packet.head.question.class) : "",
1167 dns_record_type2str((dns_record_type) packet.head.question.type));
1168 }
1169 }
1170 for(size_t rec_index = 0; dns_parse_record_raw(offset, next, offset + len, &next, &rec); rec_index++)
1171 {
1172 char *section_separator = "";
1173 if(rec_index >= packet.head.header.ans_count)
1174 {
1175 if(rec_index >= non_add_count)
1176 {
1177 // We are entering a new section
1178 if(context.format.separate_sections && section != DNS_SECTION_ADDITIONAL)
1179 {
1180 section_separator = "\n";
1181 }
1182 section = DNS_SECTION_ADDITIONAL;
1183 }
1184 else
1185 {
1186 // We are entering a new section
1187 if(context.format.separate_sections && section != DNS_SECTION_AUTHORITY)
1188 {
1189 section_separator = "\n";
1190 }
1191 section = DNS_SECTION_AUTHORITY;
1192 }
1193 }
1194
1195 if((context.format.match_name && !dns_names_eq(&rec.name, &packet.head.question.name))
1196 || !context.format.sections[section])
1197 {
1198 continue;
1199 }
1200 if(!context.format.ttl)
1201 {
1202 fprintf(context.outfile,
1203 "%s%s%s %s %s\n",
1204 section_separator,
1205 context.format.indent_sections ? "\t" : "",
1206 dns_name2str(&rec.name),
1207 dns_record_type2str((dns_record_type) rec.type),
1208 dns_raw_record_data2str(&rec, offset, offset + short_len));
1209 }
1210 else
1211 {
1212 fprintf(context.outfile,
1213 "%s%s%s %s %" PRIu32 " %s %s\n",
1214 section_separator,
1215 context.format.indent_sections ? "\t" : "",
1216 dns_name2str(&rec.name),
1217 dns_class2str((dns_class)rec.class),
1218 rec.ttl,
1219 dns_record_type2str((dns_record_type) rec.type),
1220 dns_raw_record_data2str(&rec, offset, offset + short_len));
1221 }
1222 }
1223 if(context.format.separate_queries)
1224 {
1225 fprintf(context.outfile, "\n");
1226 }
1227 break;
1228 }
1229
1230 lookup_done(lookup);
1231
1232 // Sometimes, users may want to obtain results immediately.
1233 if(context.cmd_args.flush)
1234 {
1235 fflush(context.outfile);
1236 }
1237 }
1238 }
1239
1240 #ifdef PCAP_SUPPORT
1241 void pcap_callback(u_char *arg, const struct pcap_pkthdr *header, const u_char *packet)
1242 {
1243 static struct sockaddr_storage addr;
1244 static size_t len;
1245 static const uint8_t *frame;
1246 static ssize_t remaining;
1247
1248 // We expect at least an Ethernet header + IPv4/IPv6 header (>= 20) + UDP header
1249 if(header->len < 42)
1250 {
1251 return;
1252 }
1253 frame = ((uint8_t*)packet) + 14;
1254 remaining = header->len - 14;
1255
1256 if(((struct ether_header*)packet)->ether_type == context.ether_type_ip)
1257 {
1258 unsigned int ip_hdr_len = ((struct iphdr *) frame)->ihl * 4;
1259 remaining -= ip_hdr_len;
1260
1261 // Check whether the packet is long enough to still contain a UDP frame
1262 if(((struct iphdr *) frame)->protocol != 17
1263 || remaining < 0)
1264 {
1265 return;
1266 }
1267 frame += ip_hdr_len;
1268 len = (size_t)remaining;
1269 remaining -= ntohs(((struct udphdr *) frame)->len);
1270 if(remaining != 0)
1271 {
1272 return;
1273 }
1274 frame += 8;
1275 addr.ss_family = AF_INET;
1276 }
1277 else
1278 {
1279 return;
1280 }
1281 do_read((uint8_t*)frame, len, &addr);
1282 }
1283
1284 void pcap_can_read()
1285 {
1286 pcap_dispatch(context.pcap, 1, pcap_callback, NULL);
1287 }
1288 #endif
1289
1290 void can_read(socket_info_t *info)
1291 {
1292 static uint8_t readbuf[0xFFFF];
1293 static struct sockaddr_storage recvaddr;
1294 static socklen_t fromlen;
1295 static ssize_t num_received;
1296
1297
1298
1299 fromlen = sizeof(recvaddr);
1300 num_received = recvfrom(info->descriptor, readbuf, sizeof(readbuf), 0, (struct sockaddr *) &recvaddr, &fromlen);
1301 if(num_received <= 0)
1302 {
1303 return;
1304 }
1305
1306 do_read(readbuf, (size_t)num_received, &recvaddr);
1307 }
1308
1309 bool cmp_lookup(void *lookup1, void *lookup2)
1310 {
1311 return dns_names_eq(&((lookup_key_t *) lookup1)->name, &((lookup_key_t *) lookup2)->name);
1312 }
1313
1314 void binfile_write_head()
1315 {
1316 // Write file type signature including null character
1317 char signature[] = "massdns";
1318 fwrite(signature, sizeof(signature), 1, context.outfile);
1319
1320 // Write a uint32_t integer in native byte order to allow detection of endianness
1321 uint32_t endianness = 0x12345678;
1322 fwrite(&endianness, sizeof(endianness), 1, context.outfile);
1323
1324 // Write uint32_t file version number
1325 // Number is to be incremented if file format is changed
1326 fwrite(&OUTPUT_BINARY_VERSION, sizeof(OUTPUT_BINARY_VERSION), 1, context.outfile);
1327
1328 // Write byte length of native size_t type
1329 uint8_t size_t_len = sizeof(size_t);
1330 fwrite(&size_t_len, sizeof(size_t_len), 1, context.outfile);
1331
1332 // Write size of time_t
1333 size_t time_t_len = sizeof(time_t);
1334 fwrite(&time_t_len, sizeof(time_t_len), 1, context.outfile);
1335
1336 // Write byte length of sockaddr_storage size
1337 size_t sockaddr_storage_len = sizeof(struct sockaddr_storage);
1338 fwrite(&sockaddr_storage_len, sizeof(sockaddr_storage_len), 1, context.outfile);
1339
1340 // Write offset of ss_family within sockaddr_storage
1341 size_t ss_family_offset = offsetof(struct sockaddr_storage, ss_family);
1342 fwrite(&ss_family_offset, sizeof(ss_family_offset), 1, context.outfile);
1343
1344 // Write size of sa_family_size within sockaddr_storage
1345 size_t sa_family_size = sizeof(sa_family_t);
1346 fwrite(&sa_family_size, sizeof(sa_family_size), 1, context.outfile);
1347
1348 // Write size of in_port_t
1349 size_t sin_port_len = sizeof(in_port_t);
1350 fwrite(&sin_port_len, sizeof(sin_port_len), 1, context.outfile);
1351
1352
1353 // Write IPv4 family constant
1354 sa_family_t family_inet = AF_INET;
1355 fwrite(&family_inet, sizeof(family_inet), 1, context.outfile);
1356
1357 // Write offset of sin_addr within sockaddr_in
1358 size_t sin_addr_offset = offsetof(struct sockaddr_in, sin_addr);
1359 fwrite(&sin_addr_offset, sizeof(sin_addr_offset), 1, context.outfile);
1360
1361 // Write offset of sin_port within sockaddr_in
1362 size_t sin_port_offset = offsetof(struct sockaddr_in, sin_port);
1363 fwrite(&sin_port_offset, sizeof(sin_port_offset), 1, context.outfile);
1364
1365
1366 // Write IPv6 family constant
1367 sa_family_t family_inet6 = AF_INET6;
1368 fwrite(&family_inet6, sizeof(family_inet6), 1, context.outfile);
1369
1370 // Write offset of sin6_addr within sockaddr_in6
1371 size_t sin6_addr_offset = offsetof(struct sockaddr_in6, sin6_addr);
1372 fwrite(&sin6_addr_offset, sizeof(sin6_addr_offset), 1, context.outfile);
1373
1374 // Write offset of sin6_port within sockaddr_in6
1375 size_t sin6_port_offset = offsetof(struct sockaddr_in6, sin6_port);
1376 fwrite(&sin6_port_offset, sizeof(sin6_port_offset), 1, context.outfile);
1377 }
1378
1379 void privilege_drop()
1380 {
1381 if (geteuid() != 0)
1382 {
1383 return;
1384 }
1385 char *username = context.cmd_args.drop_user ? context.cmd_args.drop_user : COMMON_UNPRIVILEGED_USER;
1386 char *groupname = context.cmd_args.drop_group ? context.cmd_args.drop_group : COMMON_UNPRIVILEGED_GROUP;
1387 if(!context.cmd_args.root)
1388 {
1389 struct passwd *drop_user = getpwnam(username);
1390 struct group *drop_group = getgrnam(groupname);
1391 if (drop_group && drop_user && setgid(drop_group->gr_gid) == 0 && setuid(drop_user->pw_uid) == 0)
1392 {
1393 if (!context.cmd_args.quiet)
1394 {
1395 log_msg("Privileges have been dropped to \"%s:%s\" for security reasons.\n", username, groupname);
1396 }
1397 }
1398 else
1399 {
1400 log_msg("Privileges could not be dropped to \"%s:%s\".\n"
1401 "For security reasons, this program will only run as root user when supplied with --root, "
1402 "which is not recommended.\n"
1403 "It is better practice to run this program as a different user.\n", username, groupname);
1404 clean_exit(EXIT_FAILURE);
1405 }
1406 }
1407 else
1408 {
1409 if (!context.cmd_args.quiet)
1410 {
1411 log_msg("[WARNING] Privileges were not dropped. This is not recommended.\n");
1412 }
1413 }
1414 }
1415
1416 #ifdef PCAP_SUPPORT
1417 void pcap_setup()
1418 {
1419 context.pcap_dev = pcap_lookupdev(context.pcap_error);
1420 if(context.pcap_dev == NULL)
1421 {
1422 goto pcap_error;
1423 }
1424 log_msg("Default pcap device: %s", context.pcap_dev);
1425
1426
1427 char mac_filter[sizeof("ether dst ") - 1 + MAC_READABLE_BUFLEN];
1428 char *mac_readable = mac_filter + sizeof("ether dst ") - 1;
1429 strcpy(mac_filter, "ether dst ");
1430
1431 if(get_iface_hw_addr_readable(context.pcap_dev, mac_readable) != 0)
1432 {
1433 log_msg("\nFailed to determine the hardware address of the device.\n");
1434 goto pcap_error_noprint;
1435 }
1436 log_msg(", address: %s\n", mac_readable);
1437
1438
1439 context.pcap = pcap_create(context.pcap_dev, context.pcap_error);
1440 if(context.pcap == NULL)
1441 {
1442 goto pcap_error;
1443 }
1444
1445 if(pcap_set_snaplen(context.pcap, 0xFFFF) != 0)
1446 {
1447 goto pcap_error;
1448 }
1449
1450 if(pcap_setnonblock(context.pcap, 1, context.pcap_error) == -1)
1451 {
1452 goto pcap_error;
1453 }
1454
1455 if(pcap_set_buffer_size(context.pcap, 1024 * 1024) != 0)
1456 {
1457 goto pcap_error;
1458 }
1459
1460 int activation_status = pcap_activate(context.pcap);
1461 if(activation_status != 0)
1462 {
1463 log_msg("Error during pcap activation: %s\n", pcap_statustostr(activation_status));
1464 goto pcap_error_noprint;
1465 }
1466
1467 if(pcap_compile(context.pcap, &context.pcap_filter, mac_filter, 0, PCAP_NETMASK_UNKNOWN) != 0)
1468 {
1469 log_msg("Error during pcap filter compilation: %s\n", pcap_geterr(context.pcap));
1470 goto pcap_error_noprint;
1471 }
1472
1473 if(pcap_setfilter(context.pcap, &context.pcap_filter) != 0)
1474 {
1475 log_msg("Error setting pcap filter: %s\n", pcap_geterr(context.pcap));
1476 goto pcap_error_noprint;
1477 }
1478
1479 context.pcap_info.descriptor = pcap_get_selectable_fd(context.pcap);
1480 if(context.pcap_info.descriptor < 0)
1481 {
1482 goto pcap_error;
1483 }
1484 #ifdef HAVE_EPOLL
1485 struct epoll_event ev;
1486 bzero(&ev, sizeof(ev));
1487 ev.data.ptr = &context.pcap_info;
1488 ev.events = EPOLLIN;
1489 if (epoll_ctl(context.epollfd, EPOLL_CTL_ADD, context.pcap_info.descriptor, &ev) != 0)
1490 {
1491 log_msg("Failed to add epoll event: %s\n", strerror(errno));
1492 clean_exit(EXIT_FAILURE);
1493 }
1494 #endif
1495 return;
1496
1497 pcap_error:
1498 log_msg("Error during pcap setup: %s\n", context.pcap_error);
1499 pcap_error_noprint:
1500 cleanup();
1501 clean_exit(EXIT_FAILURE);
1502 }
1503 #endif
1504
1505 void init_pipes()
1506 {
1507 // We don't need any pipes if the process is not forked
1508 if(context.cmd_args.num_processes <= 1)
1509 {
1510 return;
1511 }
1512
1513 // Otherwise create a unidirectional pipe for reading and writing from every fork
1514 context.sockets.pipes = safe_malloc(sizeof(*context.sockets.pipes) * 2 * context.cmd_args.num_processes);
1515 for(size_t i = 0; i < context.cmd_args.num_processes; i++)
1516 {
1517 if(pipe(context.sockets.pipes + i * 2) != 0)
1518 {
1519 log_msg("Pipe failed: %s\n", strerror(errno));
1520 clean_exit(EXIT_FAILURE);
1521 }
1522 }
1523
1524 }
1525
1526 void setup_pipes()
1527 {
1528 if(context.fork_index == 0) // We are in the main process
1529 {
1530 context.sockets.master_pipes_read = safe_calloc(sizeof(socket_info_t) * context.cmd_args.num_processes);
1531
1532 // Close all pipes that the children use to write
1533 for (size_t i = 0; i < context.cmd_args.num_processes; i++)
1534 {
1535 close(context.sockets.pipes[2 * i + 1]);
1536 context.sockets.pipes[2 * i + 1] = -1;
1537
1538 context.sockets.master_pipes_read[i].descriptor = context.sockets.pipes[2 * i];
1539 context.sockets.master_pipes_read[i].type = SOCKET_TYPE_CONTROL;
1540 context.sockets.master_pipes_read[i].data = (void*)i;
1541
1542 if(context.cmd_args.busypoll)
1543 {
1544 continue;
1545 }
1546
1547 #ifdef HAVE_EPOLL
1548 // Add all pipes the main process can read from to the epoll descriptor
1549 struct epoll_event ev;
1550 bzero(&ev, sizeof(ev));
1551 ev.data.ptr = &context.sockets.master_pipes_read[i];
1552 ev.events = EPOLLIN;
1553 if (epoll_ctl(context.epollfd, EPOLL_CTL_ADD, context.sockets.master_pipes_read[i].descriptor, &ev) != 0)
1554 {
1555 log_msg("Failed to add epoll event: %s\n", strerror(errno));
1556 clean_exit(EXIT_FAILURE);
1557 }
1558 #endif
1559 }
1560 }
1561 else // It's a child process
1562 {
1563 // Close all pipes except the two belonging to the current process
1564 for (size_t i = 0; i < context.cmd_args.num_processes; i++)
1565 {
1566 if (i == context.fork_index)
1567 {
1568 continue;
1569 }
1570 close(context.sockets.pipes[2 * i]);
1571 close(context.sockets.pipes[2 * i + 1]);
1572 context.sockets.pipes[2 * i] = -1;
1573 context.sockets.pipes[2 * i + 1] = -1;
1574 }
1575 context.sockets.write_pipe.descriptor = context.sockets.pipes[2 * context.fork_index + 1];
1576 context.sockets.write_pipe.type = SOCKET_TYPE_CONTROL;
1577 close(context.sockets.pipes[2 * context.fork_index]);
1578 context.sockets.pipes[2 * context.fork_index] = -1;
1579 }
1580 }
1581
1582 void read_control_message(socket_info_t *socket_info)
1583 {
1584 size_t process = (size_t)socket_info->data;
1585 ssize_t read_result = read(socket_info->descriptor, context.stat_messages + process, sizeof(stats_exchange_t));
1586 if(read_result > 0 && read_result < sizeof(stats_exchange_t))
1587 {
1588 log_msg("Atomic read failed: Read %ld bytes.\n", read_result);
1589 }
1590 if(!context.done[process] && context.stat_messages[process].done)
1591 {
1592 context.finished++;
1593 context.done[process] = true;
1594 }
1595 }
1596
1597 void make_query_sockets_nonblocking()
1598 {
1599 for(size_t i = 0; i < context.sockets.interfaces4.len; i++)
1600 {
1601 socket_noblock(((socket_info_t*)context.sockets.interfaces4.data) + i);
1602 }
1603 for(size_t i = 0; i < context.sockets.interfaces6.len; i++)
1604 {
1605 socket_noblock(((socket_info_t*)context.sockets.interfaces6.data) + i);
1606 }
1607 }
1608
1609 void run()
1610 {
1611 static char multiproc_outfile_name[8192];
1612
1613 if(!urandom_init())
1614 {
1615 log_msg("Failed to open /dev/urandom: %s\n", strerror(errno));
1616 clean_exit(EXIT_FAILURE);
1617 }
1618
1619 context.map = hashmapCreate(context.cmd_args.hashmap_size, hash_lookup_key, cmp_lookup);
1620 if(context.map == NULL)
1621 {
1622 log_msg("Failed to create hashmap.\n");
1623 clean_exit(EXIT_FAILURE);
1624 }
1625
1626 context.lookup_pool.len = context.cmd_args.hashmap_size;
1627 context.lookup_pool.data = safe_calloc(context.lookup_pool.len * sizeof(void*));
1628 context.lookup_space = safe_calloc(context.lookup_pool.len * sizeof(*context.lookup_space));
1629 for(size_t i = 0; i < context.lookup_pool.len; i++)
1630 {
1631 ((lookup_entry_t**)context.lookup_pool.data)[i] = context.lookup_space + i;
1632 }
1633
1634 timed_ring_init(&context.ring, max(context.cmd_args.interval_ms, 1000), 2 * TIMED_RING_MS, context.cmd_args.timed_ring_buckets);
1635
1636 #ifdef HAVE_EPOLL
1637 uint32_t socket_events = EPOLLOUT;
1638
1639 struct epoll_event pevents[100000];
1640 bzero(pevents, sizeof(pevents));
1641 #endif
1642
1643 init_pipes();
1644 context.pids = safe_calloc(context.cmd_args.num_processes * sizeof(*context.pids));
1645 context.done = safe_calloc(context.cmd_args.num_processes * sizeof(*context.done));
1646 context.fork_index = split_process(context.cmd_args.num_processes, context.pids);
1647 #ifdef HAVE_EPOLL
1648 if(!context.cmd_args.busypoll)
1649 {
1650 context.epollfd = epoll_create(1);
1651 }
1652 #endif
1653 #ifdef PCAP_SUPPORT
1654 if(context.cmd_args.use_pcap)
1655 {
1656 pcap_setup();
1657 }
1658 else
1659 #endif
1660 #ifdef HAVE_EPOLL
1661 {
1662 socket_events |= EPOLLIN;
1663 }
1664 #endif
1665 if(context.cmd_args.num_processes > 1)
1666 {
1667 setup_pipes();
1668 if(context.fork_index == 0)
1669 {
1670 context.stat_messages = safe_calloc(context.cmd_args.num_processes * sizeof(stats_exchange_t));
1671 }
1672 }
1673
1674 if(strcmp(context.cmd_args.outfile_name, "-") != 0)
1675 {
1676 if(context.cmd_args.num_processes > 1)
1677 {
1678 snprintf(multiproc_outfile_name, sizeof(multiproc_outfile_name), "%s%zd", context.cmd_args.outfile_name,
1679 context.fork_index);
1680 context.outfile = fopen(multiproc_outfile_name, "w");
1681 }
1682 else
1683 {
1684 context.outfile = fopen(context.cmd_args.outfile_name, "w");
1685 }
1686 if(!context.outfile)
1687 {
1688 log_msg("Failed to open output file: %s\n", strerror(errno));
1689 clean_exit(EXIT_FAILURE);
1690 }
1691 }
1692 else
1693 {
1694 if(context.cmd_args.num_processes > 1)
1695 {
1696 log_msg("Multiprocessing is currently only supported through the -w parameter.\n");
1697 clean_exit(EXIT_FAILURE);
1698 }
1699 }
1700
1701 if(context.domainfile != stdin)
1702 {
1703 context.domainfile = fopen(context.cmd_args.domains, "r");
1704 if (context.domainfile == NULL)
1705 {
1706 log_msg("Failed to open domain file \"%s\".\n", context.cmd_args.domains);
1707 clean_exit(EXIT_FAILURE);
1708 }
1709 }
1710
1711 if(context.cmd_args.output == OUTPUT_BINARY)
1712 {
1713 binfile_write_head();
1714 }
1715
1716
1717 // It is important to call default interface sockets setup before reading the resolver list
1718 // because that way we can warn if the socket creation for a certain IP protocol failed although a resolver
1719 // requires the protocol.
1720 query_sockets_setup();
1721 context.resolvers = massdns_resolvers_from_file(context.cmd_args.resolvers);
1722
1723 privilege_drop();
1724
1725 #ifdef HAVE_EPOLL
1726 if(!context.cmd_args.busypoll)
1727 {
1728 add_sockets(context.epollfd, socket_events, EPOLL_CTL_ADD, &context.sockets.interfaces4);
1729 add_sockets(context.epollfd, socket_events, EPOLL_CTL_ADD, &context.sockets.interfaces6);
1730 }
1731 #endif
1732 if(context.cmd_args.busypoll)
1733 {
1734 make_query_sockets_nonblocking();
1735 }
1736
1737
1738 clock_gettime(CLOCK_MONOTONIC, &context.stats.start_time);
1739 check_progress();
1740
1741 if(!context.cmd_args.busypoll)
1742 {
1743 #ifdef HAVE_EPOLL
1744 while(context.state < STATE_DONE)
1745 {
1746
1747 int ready = epoll_wait(context.epollfd, pevents, sizeof(pevents) / sizeof(pevents[0]), 1);
1748 if (ready < 0)
1749 {
1750 log_msg("Epoll failure: %s\n", strerror(errno));
1751 }
1752 else if (ready == 0) // Epoll timeout
1753 {
1754 timed_ring_handle(&context.ring, ring_timeout);
1755 }
1756 else if (ready > 0)
1757 {
1758 for (int i = 0; i < ready; i++)
1759 {
1760 socket_info_t *socket_info = pevents[i].data.ptr;
1761 if ((pevents[i].events & EPOLLOUT) && socket_info->type == SOCKET_TYPE_QUERY)
1762 {
1763 can_send();
1764 timed_ring_handle(&context.ring, ring_timeout);
1765 }
1766 if ((pevents[i].events & EPOLLIN) && socket_info->type == SOCKET_TYPE_QUERY)
1767 {
1768 can_read(socket_info);
1769 }
1770 #ifdef PCAP_SUPPORT
1771 else if((pevents[i].events & EPOLLIN) && socket_info == &context.pcap_info)
1772 {
1773 pcap_can_read();
1774 }
1775 #endif
1776 else if ((pevents[i].events & EPOLLIN) && socket_info->type == SOCKET_TYPE_CONTROL)
1777 {
1778 read_control_message(socket_info);
1779 if(context.finished >= context.cmd_args.num_processes)
1780 {
1781 context.state = STATE_DONE;
1782 break;
1783 }
1784 }
1785 }
1786 timed_ring_handle(&context.ring, ring_timeout);
1787 }
1788 }
1789 #endif
1790 }
1791 else
1792 {
1793 while(context.state < STATE_DONE)
1794 {
1795 can_send();
1796 for(size_t i = 0; i < context.sockets.interfaces4.len; i++)
1797 {
1798 can_read(((socket_info_t*)context.sockets.interfaces4.data) + i);
1799 }
1800 for(size_t i = 0; i < context.sockets.interfaces6.len; i++)
1801 {
1802 can_read(((socket_info_t*)context.sockets.interfaces6.data) + i);
1803 }
1804 timed_ring_handle(&context.ring, ring_timeout);
1805
1806 if(context.cmd_args.num_processes > 1 && context.fork_index == 0)
1807 {
1808 for (size_t i = 1; i < context.cmd_args.num_processes; i++)
1809 {
1810 read_control_message(context.sockets.master_pipes_read + i);
1811 }
1812 if(context.finished >= context.cmd_args.num_processes)
1813 {
1814 context.state = STATE_DONE;
1815 break;
1816 }
1817 }
1818 }
1819 }
1820 }
1821
1822 #define STATUS_FORMAT_OPTIONS 2
1823 // Set the real-time status format string. The ansi format is used by default
1824 const char * get_status_format_string(char *arg) {
1825 status_format_map_t status_fmt_map[STATUS_FORMAT_OPTIONS] = {
1826 { "ansi", stats_fmt_ansi },
1827 { "json", stats_fmt_json }};
1828 int i;
1829
1830 for (i=0; i<STATUS_FORMAT_OPTIONS; i++) {
1831 if (!strcmp(arg, status_fmt_map[i].name))
1832 return status_fmt_map[i].status_fmt;
1833 }
1834 log_msg("Invalid status format specified.\n");
1835 clean_exit(EXIT_FAILURE);
1836 return NULL;
1837 }
1838
1839 void use_stdin()
1840 {
1841 if (!context.cmd_args.quiet)
1842 {
1843 log_msg("Reading domain list from stdin.\n");
1844 }
1845 context.domainfile = stdin;
1846 }
1847
1848 int parse_cmd(int argc, char **argv)
1849 {
1850 bool domain_param = false;
1851
1852 context.cmd_args.argc = argc;
1853 context.cmd_args.argv = argv;
1854 context.cmd_args.help_function = print_help;
1855
1856 if (argc <= 1)
1857 {
1858 print_help();
1859 clean_exit(EXIT_FAILURE);
1860 }
1861
1862 #ifdef PCAP_SUPPORT
1863 // Precompute values so we do not have to call htons for each incoming packet
1864 context.ether_type_ip = htons(ETHERTYPE_IP);
1865 context.ether_type_ip6 = htons(ETHERTYPE_IPV6);
1866 #endif
1867
1868 context.cmd_args.record_type = DNS_REC_INVALID;
1869 context.domainfile_size = -1;
1870 context.state = STATE_WARMUP;
1871 context.logfile = stderr;
1872 context.outfile = stdout;
1873 context.cmd_args.outfile_name = "-";
1874
1875 context.format.match_name = true;
1876 context.format.sections[DNS_SECTION_ANSWER] = true;
1877
1878 context.status_fmt = stats_fmt_ansi;
1879
1880 context.cmd_args.resolve_count = 50;
1881 context.cmd_args.hashmap_size = 10000;
1882 context.cmd_args.interval_ms = 500;
1883 context.cmd_args.timed_ring_buckets = 10000;
1884 context.cmd_args.output = OUTPUT_TEXT_FULL;
1885 context.cmd_args.retry_codes[DNS_RCODE_REFUSED] = true;
1886 context.cmd_args.num_processes = 1;
1887 context.cmd_args.socket_count = 1;
1888 #ifndef HAVE_EPOLL
1889 context.cmd_args.busypoll = true;
1890 #endif
1891
1892 for (int i = 1; i < argc; i++)
1893 {
1894 if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0)
1895 {
1896 print_help();
1897 clean_exit(EXIT_SUCCESS);
1898 }
1899 else if (strcmp(argv[i], "--busypoll") == 0 || strcmp(argv[i], "--busy-poll") == 0)
1900 {
1901 context.cmd_args.busypoll = true;
1902 }
1903 else if (strcmp(argv[i], "--resolvers") == 0 || strcmp(argv[i], "-r") == 0)
1904 {
1905 if (context.cmd_args.resolvers == NULL)
1906 {
1907 expect_arg(i);
1908 context.cmd_args.resolvers = argv[++i];
1909 }
1910 else
1911 {
1912 log_msg("Resolvers may only be supplied once.\n");
1913 clean_exit(EXIT_FAILURE);
1914 }
1915 }
1916 else if(strcmp(argv[i], "--retry") == 0)
1917 {
1918 expect_arg(i);
1919 dns_rcode rcode;
1920 if(dns_str2rcode(argv[++i], &rcode))
1921 {
1922 if(!context.cmd_args.retry_codes_set)
1923 {
1924 context.cmd_args.retry_codes[DNS_RCODE_REFUSED] = false;
1925 context.cmd_args.retry_codes_set = true;
1926 }
1927 context.cmd_args.retry_codes[rcode] = true;
1928 }
1929 else if(strcasecmp(argv[i], "never") == 0)
1930 {
1931 context.cmd_args.retry_codes[DNS_RCODE_REFUSED] = false;
1932 context.cmd_args.retry_codes_set = true;
1933 }
1934 else
1935 {
1936 log_msg("Invalid retry code: %s.\n", argv[i]);
1937 clean_exit(EXIT_FAILURE);
1938 }
1939 }
1940 else if(strcmp(argv[i], "--ignore") == 0 || strcmp(argv[i], "--filter") == 0)
1941 {
1942 expect_arg(i);
1943 dns_rcode rcode;
1944
1945 filter_mode_t filter_mode = strcmp(argv[i], "--ignore") == 0 ? FILTER_NEGATIVE : FILTER_POSITIVE;
1946 if(context.cmd_args.filter_mode != filter_mode && context.cmd_args.filter_mode != FILTER_DISABLED) {
1947 log_msg("Cannot combine --filter and --ignore.\n");
1948 clean_exit(EXIT_FAILURE);
1949 }
1950
1951 if(dns_str2rcode(argv[++i], &rcode))
1952 {
1953 context.cmd_args.filter_mode = filter_mode;
1954 context.cmd_args.filter_codes[rcode] = true;
1955 }
1956 else
1957 {
1958 log_msg("Invalid filter/ignore code: %s.\n", argv[i]);
1959 clean_exit(EXIT_FAILURE);
1960 }
1961 }
1962 else if (strcmp(argv[i], "--bindto") == 0 || strcmp(argv[i], "-b") == 0)
1963 {
1964 expect_arg(i);
1965 struct sockaddr_storage *addr = safe_malloc(sizeof(addr));
1966 if (!str_to_addr(argv[++i], 0, addr))
1967 {
1968 free(addr);
1969 log_msg("Invalid address for socket binding: %s\n", argv[i]);
1970 clean_exit(EXIT_FAILURE);
1971
1972 }
1973 single_list_push_back(addr->ss_family == AF_INET ? &context.cmd_args.bind_addrs4 :
1974 &context.cmd_args.bind_addrs6, addr);
1975 }
1976 else if (strcmp(argv[i], "--outfile") == 0 || strcmp(argv[i], "-w") == 0)
1977 {
1978 expect_arg(i);
1979 context.cmd_args.outfile_name = argv[++i];
1980
1981 }
1982 else if (strcmp(argv[i], "--error-log") == 0 || strcmp(argv[i], "-l") == 0)
1983 {
1984 expect_arg(i);
1985 char *filename = argv[++i];
1986 if(strcmp(filename, "-") != 0)
1987 {
1988 context.logfile = fopen(filename, "w");
1989 if(!context.logfile)
1990 {
1991 log_msg("Failed to open log file: %s\n", strerror(errno));
1992 clean_exit(EXIT_FAILURE);
1993 }
1994 }
1995 }
1996 else if (strcmp(argv[i], "--types") == 0 || strcmp(argv[i], "--type") == 0 || strcmp(argv[i], "-t") == 0)
1997 {
1998 expect_arg(i);
1999 if (context.cmd_args.record_type != DNS_REC_INVALID)
2000 {
2001 log_msg("Currently, only one record type is supported.\n");
2002 clean_exit(EXIT_FAILURE);
2003 }
2004 dns_record_type rtype = dns_str_to_record_type(argv[++i]);
2005 if (rtype == DNS_REC_INVALID)
2006 {
2007 log_msg("Unsupported record type: %s\n", argv[i]);
2008 clean_exit(EXIT_FAILURE);
2009 }
2010 context.cmd_args.record_type = rtype;
2011 }
2012 else if (strcmp(argv[i], "--drop-group") == 0)
2013 {
2014 expect_arg(i);
2015 context.cmd_args.drop_group = argv[++i];
2016 }
2017 else if (strcmp(argv[i], "--drop-user") == 0)
2018 {
2019 expect_arg(i);
2020 context.cmd_args.drop_user = argv[++i];
2021 }
2022 else if (strcmp(argv[i], "--status-format") == 0)
2023 {
2024 expect_arg(i);
2025 context.status_fmt = get_status_format_string(argv[++i]);
2026 }
2027 else if (strcmp(argv[i], "--root") == 0)
2028 {
2029 context.cmd_args.root = true;
2030 }
2031 else if (strcmp(argv[i], "--norecurse") == 0 || strcmp(argv[i], "-n") == 0)
2032 {
2033 context.cmd_args.norecurse = true;
2034 }
2035 else if (strcmp(argv[i], "--output") == 0 || strcmp(argv[i], "-o") == 0)
2036 {
2037 expect_arg(i++);
2038 switch(argv[i][0])
2039 {
2040 case 'B':
2041 context.cmd_args.output = OUTPUT_BINARY;
2042 break;
2043
2044 case 'J':
2045 context.cmd_args.output = OUTPUT_NDJSON;
2046
2047 for(char *output_option = argv[i] + 1; *output_option != 0; output_option++)
2048 {
2049 switch(*output_option)
2050 {
2051 case 'e':
2052 context.format.write_exhausted_tries = true;
2053 break;
2054 default:
2055 log_msg("Unrecognized output option: %c\n", *output_option);
2056 clean_exit(EXIT_FAILURE);
2057 }
2058 }
2059 break;
2060
2061 case 'S':
2062 context.cmd_args.output = OUTPUT_TEXT_SIMPLE;
2063
2064 if(strcmp(argv[i], "S") != 0)
2065 {
2066 context.format.sections[DNS_SECTION_ANSWER] = false;
2067 context.format.match_name = false;
2068 }
2069 for(char *output_option = argv[i] + 1; *output_option != 0; output_option++)
2070 {
2071 switch(*output_option)
2072 {
2073 case 'u':
2074 context.format.sections[DNS_SECTION_AUTHORITY] = true;
2075 break;
2076 case 'd':
2077 context.format.sections[DNS_SECTION_ADDITIONAL] = true;
2078 break;
2079 case 'n':
2080 context.format.sections[DNS_SECTION_ANSWER] = true;
2081 break;
2082 case 'm':
2083 context.format.match_name = true;
2084 break;
2085 case 't':
2086 context.format.ttl = true;
2087 break;
2088 case 'l':
2089 context.format.separate_queries = true;
2090 break;
2091 case 'i':
2092 context.format.indent_sections = true;
2093 break;
2094 case 's':
2095 context.format.separate_sections = true;
2096 break;
2097 case 'q':
2098 context.format.print_question = true;
2099 break;
2100 case 'r':
2101 context.format.print_question = true;
2102 context.format.include_meta = true;
2103 break;
2104 default:
2105 log_msg("Unrecognized output option: %c\n", *output_option);
2106 clean_exit(EXIT_FAILURE);
2107 }
2108 }
2109 break;
2110
2111 case 'F':
2112 context.cmd_args.output = OUTPUT_TEXT_FULL;
2113 break;
2114
2115 default:
2116 log_msg("Unrecognized output format.\n");
2117 clean_exit(EXIT_FAILURE);
2118 }
2119 }
2120 #ifdef PCAP_SUPPORT
2121 else if (strcmp(argv[i], "--use-pcap") == 0)
2122 {
2123 context.cmd_args.use_pcap = true;
2124 }
2125 #endif
2126 else if (strcmp(argv[i], "--predictable") == 0)
2127 {
2128 context.cmd_args.predictable_resolver = true;
2129 }
2130 else if (strcmp(argv[i], "--sticky") == 0)
2131 {
2132 context.cmd_args.sticky = true;
2133 }
2134 else if (strcmp(argv[i], "--quiet") == 0 || strcmp(argv[i], "-q") == 0)
2135 {
2136 context.cmd_args.quiet = true;
2137 }
2138 else if (strcmp(argv[i], "--extreme") == 0)
2139 {
2140 context.cmd_args.extreme = (int) expect_arg_nonneg(i++, 0, 2);
2141 }
2142 else if (strcmp(argv[i], "--resolve-count") == 0 || strcmp(argv[i], "-c") == 0)
2143 {
2144 context.cmd_args.resolve_count = (uint8_t) expect_arg_nonneg(i++, 1, UINT8_MAX);
2145 }
2146 else if (strcmp(argv[i], "--hashmap-size") == 0 || strcmp(argv[i], "-s") == 0)
2147 {
2148 context.cmd_args.hashmap_size = (size_t) expect_arg_nonneg(i++, 1, SIZE_MAX);
2149 }
2150 else if (strcmp(argv[i], "--processes") == 0)
2151 {
2152 context.cmd_args.num_processes = (size_t) expect_arg_nonneg(i++, 0, SIZE_MAX);
2153 if(context.cmd_args.num_processes == 0)
2154 {
2155 #ifndef HAVE_SYSINFO
2156 log_msg("No support for detecting the number of cores automatically.\n");
2157 clean_exit(EXIT_FAILURE);
2158 #else
2159 int cores = get_nprocs_conf();
2160 if(cores <= 0)
2161 {
2162 log_msg("Failed to determine number of processor cores.\n");
2163 clean_exit(EXIT_FAILURE);
2164 }
2165 context.cmd_args.num_processes = (size_t)cores;
2166 #endif
2167 }
2168 }
2169 else if (strcmp(argv[i], "--socket-count") == 0)
2170 {
2171 context.cmd_args.socket_count = (size_t) expect_arg_nonneg(i++, 1, SIZE_MAX);
2172 }
2173 else if (strcmp(argv[i], "--interval") == 0 || strcmp(argv[i], "-i") == 0)
2174 {
2175 context.cmd_args.interval_ms = (unsigned int) expect_arg_nonneg(i++, 1, UINT_MAX);
2176 }
2177 else if (strcmp(argv[i], "--sndbuf") == 0)
2178 {
2179 context.cmd_args.sndbuf = (int) expect_arg_nonneg(i++, 0, INT_MAX);
2180 }
2181 else if (strcmp(argv[i], "--rcvbuf") == 0)
2182 {
2183 context.cmd_args.rcvbuf = (int) expect_arg_nonneg(i++, 0, INT_MAX);
2184 }
2185 else if (strcmp(argv[i], "--flush") == 0)
2186 {
2187 context.cmd_args.flush = true;
2188 }
2189 else if (strcmp(argv[i], "--verify-ip") == 0)
2190 {
2191 context.cmd_args.verify_ip = true;
2192 }
2193 else
2194 {
2195 if (context.cmd_args.domains == NULL)
2196 {
2197 context.cmd_args.domains = argv[i];
2198 domain_param = true;
2199 if (strcmp(argv[i], "-") == 0)
2200 {
2201 use_stdin();
2202 }
2203 else
2204 {
2205 // If we can seek through the domain file, we seek to the end and store the file size
2206 // in order to be able to report an estimate progress of resolving.
2207 context.domainfile = fopen(context.cmd_args.domains, "r");
2208 if (context.domainfile == NULL)
2209 {
2210 log_msg("Failed to open domain file \"%s\".\n", argv[i]);
2211 clean_exit(EXIT_FAILURE);
2212 }
2213 if(fseek(context.domainfile, 0, SEEK_END) != 0)
2214 {
2215 // Not a seekable stream.
2216 context.domainfile_size = -1;
2217 }
2218 else
2219 {
2220 context.domainfile_size = ftell(context.domainfile);
2221 if(fseek(context.domainfile, 0, SEEK_SET) != 0)
2222 {
2223 // Should never happen because seeking was possible before but we can still recover.
2224 context.domainfile_size = -1;
2225 }
2226 }
2227 fclose(context.domainfile);
2228 context.domainfile = NULL;
2229 }
2230 }
2231 else
2232 {
2233 log_msg("The domain list may only be supplied once.\n");
2234 clean_exit(EXIT_FAILURE);
2235 }
2236 }
2237 }
2238 if (context.cmd_args.record_type == DNS_REC_INVALID)
2239 {
2240 context.cmd_args.record_type = DNS_REC_A;
2241 }
2242 if (context.cmd_args.record_type == DNS_REC_ANY)
2243 {
2244 // Some operators will not reply to ANY requests:
2245 // https://blog.cloudflare.com/deprecating-dns-any-meta-query-type/
2246 // https://lists.dns-oarc.net/pipermail/dns-operations/2013-January/009501.html
2247 log_msg("Note that DNS ANY scans might be unreliable.\n");
2248 }
2249 if (context.cmd_args.resolvers == NULL)
2250 {
2251 log_msg("Resolvers are required to be supplied.\n");
2252 clean_exit(EXIT_FAILURE);
2253 }
2254 if (!domain_param)
2255 {
2256 if(!isatty(STDIN_FILENO))
2257 {
2258 use_stdin();
2259 }
2260 else
2261 {
2262 log_msg("The domain list is required to be supplied.\n");
2263 clean_exit(EXIT_FAILURE);
2264 }
2265 }
2266
2267 if(context.domainfile == stdin && context.cmd_args.num_processes > 1)
2268 {
2269 log_msg("In order to use multiprocessing, the domain list needs to be supplied as file.\n");
2270 clean_exit(EXIT_FAILURE);
2271 }
2272
2273 return 0;
2274 }
2275
2276 int main(int argc, char **argv)
2277 {
2278 #ifdef DEBUG
2279 // Create core dump on crash in debug mode
2280 struct rlimit core_limits;
2281 core_limits.rlim_cur = core_limits.rlim_max = RLIM_INFINITY;
2282 setrlimit(RLIMIT_CORE, &core_limits);
2283 #endif
2284
2285 int rcode = parse_cmd(argc, argv);
2286 if(rcode != 0)
2287 {
2288 return rcode;
2289 }
2290
2291 run();
2292 cleanup();
2293
2294 return 0;
2295 }
0 // SPDX-License-Identifier: GPL-3.0-only
1
2 #ifndef MASSDNS_MASSDNS_H
3 #define MASSDNS_MASSDNS_H
4
5 #include <stdint.h>
6 #include <time.h>
7 #include <sys/socket.h>
8 #ifdef HAVE_EPOLL
9 #include <sys/epoll.h>
10 #endif
11 #include <netinet/in.h>
12 #include <arpa/inet.h>
13 //#define PCAP_SUPPORT
14 #ifdef PCAP_SUPPORT
15 #include <pcap.h>
16 #endif
17
18 #include "list.h"
19 #include "net.h"
20 #include "hashmap.h"
21 #include "dns.h"
22 #include "timed_ring.h"
23
24 #define MAXIMUM_MODULE_COUNT 0xFF
25 #define COMMON_UNPRIVILEGED_USER "nobody"
26 #define COMMON_UNPRIVILEGED_GROUP "nogroup"
27
28 const uint32_t OUTPUT_BINARY_VERSION = 0x00;
29
30 typedef struct
31 {
32 size_t answers;
33 size_t noerr;
34 size_t formerr;
35 size_t servfail;
36 size_t nxdomain;
37 size_t notimp;
38 size_t refused;
39 size_t yxdomain;
40 size_t yxrrset;
41 size_t nxrrset;
42 size_t notauth;
43 size_t notzone;
44 size_t timeout;
45 size_t mismatch;
46 size_t other;
47 size_t qsent;
48 size_t numreplies;
49 size_t fakereplies; // used for resolver plausibility checks (wrong records)
50 } resolver_stats_t;
51
52 typedef struct {
53 size_t fork_index;
54 size_t numdomains;
55 size_t numreplies;
56 size_t finished;
57 size_t finished_success;
58 size_t mismatch_domain;
59 size_t mismatch_id;
60 size_t timeouts[0x100];
61 size_t all_rcodes[5];
62 size_t final_rcodes[5];
63 size_t current_rate;
64 size_t success_rate;
65 size_t numparsed;
66 bool done;
67 } stats_exchange_t;
68
69 typedef struct
70 {
71 struct sockaddr_storage address;
72 resolver_stats_t stats; // To be used to track resolver bans or non-replying resolvers
73 } resolver_t;
74
75 typedef struct
76 {
77 dns_name_t name;
78 dns_record_type type;
79 } lookup_key_t;
80
81 typedef struct
82 {
83 unsigned char tries;
84 uint16_t transaction;
85 void **ring_entry; // pointer to the entry within the timed ring for entry invalidation
86 resolver_t *resolver;
87 lookup_key_t *key;
88 socket_info_t *socket;
89 } lookup_t;
90
91 typedef struct
92 {
93 lookup_key_t key;
94 lookup_t value;
95 } lookup_entry_t;
96
97 typedef enum
98 {
99 STATE_WARMUP, // Before the hash map size has been reached
100 STATE_QUERYING,
101 STATE_COOLDOWN,
102 STATE_WAIT_CHILDREN,
103 STATE_DONE
104 } state_t;
105
106 typedef enum
107 {
108 OUTPUT_TEXT_FULL,
109 OUTPUT_TEXT_SIMPLE,
110 OUTPUT_BINARY,
111 OUTPUT_NDJSON
112 } output_t;
113
114 typedef enum {
115 FILTER_DISABLED = 0,
116 FILTER_POSITIVE,
117 FILTER_NEGATIVE
118 } filter_mode_t;
119
120 typedef struct {
121 const char *name;
122 const char *status_fmt;
123 } status_format_map_t;
124
125 const char *default_interfaces[] = {""};
126
127 typedef struct
128 {
129 buffer_t resolvers;
130 lookup_entry_t *lookup_space;
131 buffer_t lookup_pool;
132 Hashmap *resolver_map;
133
134 struct
135 {
136 bool sections[4];
137 bool match_name;
138 bool ttl;
139 bool separate_queries;
140 bool separate_sections;
141 bool include_meta;
142 bool indent_sections;
143 bool print_question;
144 bool write_exhausted_tries;
145 } format;
146
147 struct cmd_args
148 {
149 bool root;
150 bool verify_ip;
151 char *resolvers;
152 char *domains;
153 char *outfile_name;
154 uint8_t resolve_count;
155 size_t hashmap_size;
156 unsigned int interval_ms;
157 bool norecurse;
158 bool quiet;
159 int sndbuf;
160 int rcvbuf;
161 char *drop_user;
162 char *drop_group;
163 dns_record_type record_type;
164 size_t timed_ring_buckets;
165 int extreme; // Do not remove EPOLLOUT after warmup
166 output_t output;
167 bool retry_codes[0xFFFF]; // Fast lookup map for DNS reply codes that are unacceptable and require a retry
168 bool retry_codes_set;
169 bool filter_codes[0xFFFF];
170 filter_mode_t filter_mode;
171 single_list_t bind_addrs4;
172 single_list_t bind_addrs6;
173 bool sticky;
174 int argc;
175 char **argv;
176 void (*help_function)();
177 bool flush;
178 bool predictable_resolver;
179 bool use_pcap;
180 size_t num_processes;
181 size_t socket_count;
182 bool busypoll;
183 } cmd_args;
184
185 struct
186 {
187 buffer_t interfaces4; // Sockets used for receiving queries
188 buffer_t interfaces6; // Sockets used for receiving queries
189 int *pipes;
190 socket_info_t write_pipe;
191 socket_info_t *master_pipes_read;
192 } sockets;
193
194 // Processes
195 size_t finished;
196 pid_t *pids;
197 bool *done;
198 const char *status_fmt;
199 FILE* outfile;
200 FILE* logfile;
201 FILE* domainfile;
202 ssize_t domainfile_size;
203 int epollfd;
204 Hashmap *map;
205 state_t state;
206 timed_ring_t ring; // handles timeouts
207 size_t lookup_index;
208 size_t fork_index;
209 struct
210 {
211 struct timespec start_time;
212 size_t mismatch;
213 size_t other;
214 size_t qsent;
215 size_t numreplies;
216 size_t numparsed;
217 size_t numdomains;
218 struct timespec last_print;
219 size_t current_rate;
220 size_t success_rate;
221 size_t timeouts[0x100];
222 size_t final_rcodes[0x10000];
223 size_t all_rcodes[0x10000];
224 size_t finished;
225 size_t finished_success;
226 size_t mismatch_id;
227 size_t mismatch_domain;
228 } stats;
229 stats_exchange_t *stat_messages;
230 #ifdef PCAP_SUPPORT
231 pcap_t *pcap;
232 char pcap_error[PCAP_ERRBUF_SIZE];
233 char *pcap_dev;
234 socket_info_t pcap_info;
235 uint16_t ether_type_ip;
236 uint16_t ether_type_ip6;
237 struct bpf_program pcap_filter;
238 #endif
239 } massdns_context_t;
240
241 massdns_context_t context;
242
243 #endif //MASSDNS_MASSDNS_H
0 // SPDX-License-Identifier: GPL-3.0-only
1
2 #ifndef MASSRESOLVER_NET_H
3 #define MASSRESOLVER_NET_H
4
5 #include <stdbool.h>
6 #include <fcntl.h>
7 #include <net/if.h>
8 #include <sys/socket.h>
9 #include <unistd.h>
10 #ifdef PCAP_SUPPORT
11 #include <sys/ioctl.h>
12 #endif
13 #include <inttypes.h>
14
15 #define loop_sockets(sockets) \
16 for (socket_info_t *socket = (sockets)->data; socket < ((socket_info_t*)(sockets)->data) + (sockets)->len; socket++)
17
18 typedef enum
19 {
20 PROTO_IPV4 = 1 << 0,
21 PROTO_IPV6 = 1 << 1
22 } ip_support_t;
23
24 typedef enum
25 {
26 SOCKET_TYPE_INTERFACE,
27 SOCKET_TYPE_QUERY,
28 SOCKET_TYPE_CONTROL
29 } socket_type_t;
30
31 typedef enum
32 {
33 NETMODE_EPOLL,
34 NETMODE_BUSYPOLL
35 } netmode_t;
36
37 typedef struct
38 {
39 ip_support_t protocol;
40 int descriptor;
41 socket_type_t type;
42 void *data;
43 } socket_info_t;
44
45 void socket_noblock(socket_info_t* socket)
46 {
47 int sd = socket->descriptor;
48 int flags = fcntl(sd, F_GETFL, 0);
49 fcntl(sd, F_SETFL, flags | O_NONBLOCK);
50 }
51
52 socklen_t sockaddr_storage_size(struct sockaddr_storage *storage)
53 {
54 if(storage->ss_family == AF_INET)
55 {
56 return sizeof(struct sockaddr_in);
57 }
58 else if(storage->ss_family == AF_INET6)
59 {
60 return sizeof(struct sockaddr_in6);
61 }
62 return 0;
63 }
64
65 #ifdef HAVE_EPOLL
66 void add_sockets(int epollfd, uint32_t events, int op, buffer_t *sockets)
67 {
68 socket_info_t *interface_sockets = sockets->data;
69 for (size_t i = 0; i < sockets->len; i++)
70 {
71 struct epoll_event ev;
72 bzero(&ev, sizeof(ev));
73 ev.data.ptr = &interface_sockets[i];
74 ev.events = events;
75 if (epoll_ctl(epollfd, op, interface_sockets[i].descriptor, &ev) != 0)
76 {
77 perror("Failed to add epoll event");
78 exit(EXIT_FAILURE);
79 }
80 }
81 }
82 #endif
83
84 bool str_to_addr(char *str, uint16_t default_port, struct sockaddr_storage *addr)
85 {
86 if(str == NULL || str[0] == 0)
87 {
88 return false;
89 }
90 while(*str == ' ' || *str == '\t') // Skip whitespaces ("trim left")
91 {
92 str++;
93 }
94 unsigned long int port = default_port;
95
96 if(str[0] == '[')
97 {
98 str++;
99 char *closing_bracket = strstr(str, "]");
100 if(!closing_bracket)
101 {
102 return false;
103 }
104 if(closing_bracket[1] == ':') // Is there a port separator?
105 {
106 *closing_bracket = 0;
107 char *invalid_char;
108 port = strtoul(closing_bracket + 2, &invalid_char, 10);
109 if (*invalid_char != 0 || port >= UINT16_MAX)
110 {
111 return false;
112 }
113 }
114 }
115 else // We either have an IPv6 address without square brackets or an IPv4 address
116 {
117 bool v4 = false;
118 char *colon = NULL;
119 for(char *c = str; *c != 0; c++)
120 {
121 if(*c == '.' && colon == NULL) // dot before colon
122 {
123 v4 = true;
124 }
125 if(*c == ':')
126 {
127 colon = c;
128 }
129 }
130 if(v4 && colon) // We found the port separator
131 {
132 *colon = 0;
133 char *invalid_char;
134 port = strtoul(colon + 1, &invalid_char, 10);
135 if (*invalid_char != 0 || port >= UINT16_MAX)
136 {
137 return false;
138 }
139 }
140
141 }
142 if (inet_pton(AF_INET, str, &((struct sockaddr_in*)addr)->sin_addr) == 1)
143 {
144 ((struct sockaddr_in*)addr)->sin_port = htons((uint16_t )port);
145 ((struct sockaddr_in*)addr)->sin_family = AF_INET;
146 return true;
147 }
148 else if (inet_pton(AF_INET6, str, &((struct sockaddr_in6*)addr)->sin6_addr) == 1)
149 {
150 ((struct sockaddr_in6*)addr)->sin6_port = htons((uint16_t )port);
151 ((struct sockaddr_in6*)addr)->sin6_family = AF_INET6;
152 return true;
153 }
154 return false;
155 }
156
157 #ifdef PCAP_SUPPORT
158 int get_iface_hw_addr(char *iface, uint8_t *hw_mac)
159 {
160 int s;
161 struct ifreq buffer;
162
163 s = socket(PF_INET, SOCK_DGRAM, 0);
164 if (s < 0)
165 {
166 return EXIT_FAILURE;
167 }
168 bzero(&buffer, sizeof(buffer));
169 strncpy(buffer.ifr_name, iface, IFNAMSIZ);
170 buffer.ifr_name[sizeof(buffer.ifr_name) -1] = '\0';
171 ioctl(s, SIOCGIFHWADDR, &buffer);
172 close(s);
173 memcpy(hw_mac, buffer.ifr_hwaddr.sa_data, 6);
174 return EXIT_SUCCESS;
175 }
176
177 #define MAC_READABLE_BUFLEN 18
178
179 int get_iface_hw_addr_readable(char *iface, char *hw_mac)
180 {
181 uint8_t buffer[6];
182 int result = get_iface_hw_addr(iface, buffer);
183 for(uint8_t *b = buffer; b < buffer + 6; b++)
184 {
185 sprintf(hw_mac, "%02x:", *b);
186 hw_mac += 3;
187 if(b == buffer + 5)
188 {
189 *(hw_mac - 1) = 0;
190 }
191 }
192 return result;
193 }
194 #endif
195
196 char *sockaddr2str(struct sockaddr_storage *addr)
197 {
198 static char str[INET6_ADDRSTRLEN + sizeof(":65535") + 2]; // + 2 for [ and ]
199 static uint16_t port;
200 size_t len;
201
202 if(addr->ss_family == AF_INET)
203 {
204 port = ntohs(((struct sockaddr_in*)addr)->sin_port);
205 inet_ntop(addr->ss_family, &((struct sockaddr_in*)addr)->sin_addr, str, sizeof(str));
206 len = strlen(str);
207 // inet_ntop does not allow us to determine, how long the printed string was.
208 // Thus, we have to use strlen.
209 }
210 else
211 {
212 str[0] = '[';
213 port = ntohs(((struct sockaddr_in6*)addr)->sin6_port);
214 inet_ntop(addr->ss_family, &((struct sockaddr_in6*)addr)->sin6_addr, str + 1, sizeof(str) - 1);
215 len = strlen(str);
216 str[len++] = ']';
217 str[len] = 0;
218 }
219
220 snprintf(str + len, sizeof(str) - len, ":%" PRIu16, port);
221
222 return str;
223 }
224
225 #endif //MASSRESOLVER_NET_H
0 // SPDX-License-Identifier: GPL-3.0-only
1
2 #ifndef MASSRESOLVER_RANDOM_H
3 #define MASSRESOLVER_RANDOM_H
4
5 #include <stdio.h>
6 #include <stdbool.h>
7
8 static FILE *randomness;
9
10 bool urandom_init()
11 {
12 randomness = fopen("/dev/urandom", "r");
13 return randomness != NULL;
14 }
15
16 void urandom_get(void *dst, size_t len)
17 {
18 size_t read = 0;
19 while(read < len)
20 {
21 read += fread(dst, len - read, 1, randomness);
22 }
23 }
24
25 size_t urandom_size_t()
26 {
27 size_t result;
28 urandom_get(&result, sizeof(result));
29 return result;
30 }
31
32 int urandom_close()
33 {
34 if(!randomness)
35 {
36 return 0;
37 }
38 return fclose(randomness);
39 }
40
41 #endif //MASSRESOLVER_RANDOM_H
0 // SPDX-License-Identifier: GPL-3.0-only
1
2 #ifndef INC_SECURITY
3 #define INC_SECURITY
4
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdio.h>
8 #include <assert.h>
9
10 /**
11 * Safely allocate memory on the heap by aborting on failure.
12 *
13 * @param n The size of the memory block.
14 * @return A pointer that points to the allocated block, NULL when requesting a block of zero bytes.
15 */
16 void *safe_malloc(size_t n)
17 {
18 if(n == 0)
19 {
20 return NULL;
21 }
22 void *ptr = malloc(n);
23 // Check for successful allocation
24 if(ptr == NULL)
25 {
26 perror("Memory allocation failed");
27 abort();
28 }
29 return ptr;
30 }
31
32 void *safe_realloc(void *orig, size_t n)
33 {
34 void *ptr = realloc(orig, n);
35 // Check for successful allocation
36 if(ptr == NULL)
37 {
38 perror("Memory allocation failed");
39 abort();
40 }
41 return ptr;
42 }
43
44 /**
45 * Safely allocate memory on the heap and initialize it with zeroes by aborting on failure.
46 *
47 * @param n The size of the memory block.
48 * @return A pointer that points to the allocated block, NULL when requesting a block of zero bytes.
49 */
50 void *safe_calloc(size_t n)
51 {
52 if(n == 0)
53 {
54 return NULL;
55 }
56 void *ptr = calloc(n, 1);
57 // Check for successful allocation
58 if(ptr == NULL)
59 {
60 perror("Memory allocation failed");
61 abort();
62 }
63 return ptr;
64 }
65
66 /**
67 * Safely free a memory allocation on the heap at the cost of a NULL assignment. Aims to prevent double free attacks.
68 *
69 * Example:
70 * char *x = malloc(10);
71 * safe_free(&x); // x == NULL
72 *
73 * @param ptr A pointer to a pointer that has been obtained using (safe_)malloc.
74 */
75 void safe_free(void **ptr)
76 {
77 free(*ptr);
78 *ptr = NULL;
79 }
80
81
82 #endif
0 // SPDX-License-Identifier: GPL-3.0-only
1
2 #ifndef INC_STRING
3 #define INC_STRING
4
5 #include "security.h"
6
7 #include <stdbool.h>
8 #include <strings.h>
9 #include <string.h>
10 #include <ctype.h>
11
12 char *strmcpy(const char *str)
13 {
14 size_t len = strlen(str);
15 char *result = safe_malloc(len + 1);
16 memcpy(result, str, len);
17 result[len] = 0;
18 return result;
19 }
20
21 size_t string_copy(char *dest, const char *src, size_t n)
22 {
23 size_t i;
24
25 for (i = 0; i < n - 1 && src[i] != '\0'; i++) {
26 dest[i] = src[i];
27 }
28 dest[i] = 0;
29 return i;
30 }
31
32 void *flatcopy(void *src, size_t len)
33 {
34 void *dst = safe_malloc(len);
35 memcpy(dst, src, len);
36 return dst;
37 }
38
39 void strtolower(char *str)
40 {
41 while (*str != '\0')
42 {
43 if (*str >= 'A' && *str <= 'Z')
44 {
45 *str = (char) (*str | (1 << 5));
46 }
47 str++;
48 }
49 }
50
51 char *trim_start(char *str)
52 {
53 while (0 != *str)
54 {
55 if(!isspace(*str))
56 {
57 return str;
58 }
59 str++;
60 }
61 return str;
62 }
63
64 void trim_end(char* str)
65 {
66 char *last = str + strlen(str) - 1;
67 while (last >= str)
68 {
69 if(!isspace(*last))
70 {
71 return;
72 }
73 *last = 0;
74 last--;
75 }
76 }
77
78 bool endswith(char* haystack, char* needle, bool case_sensitive)
79 {
80 int (*cmp)(const char*, const char*) = strcmp;
81 if(!case_sensitive)
82 {
83 cmp = strcasecmp;
84 }
85 size_t haystack_len = strlen(haystack);
86 size_t needle_len = strlen(needle);
87 return needle_len <= haystack_len && cmp(haystack + haystack_len - needle_len, needle) == 0;
88 }
89
90 bool startswith(char* haystack, char* needle, bool case_sensitive) // Supports ASCII only
91 {
92 while(true)
93 {
94 char nchar = *needle++;
95 char hchar = *haystack++;
96 if(nchar == 0)
97 {
98 return true;
99 }
100 else if(hchar == 0)
101 {
102 return false;
103 }
104 if(case_sensitive)
105 {
106 nchar = (char)tolower(nchar);
107 hchar = (char)tolower(hchar);
108 }
109 if(nchar != hchar)
110 {
111 return false;
112 }
113 }
114 }
115
116 #define require_space(N) if(dst_idx >= dst_len - (N)) goto json_escape_finalize;
117
118 #define json_escape_body(BREAK_COND) \
119 const char complex_chars[] = "abtnvfr"; \
120 size_t dst_idx = 0; \
121 \
122 for(size_t i = 0; (BREAK_COND); i++) \
123 { \
124 size_t complex_idx = 0; \
125 switch(src[i]) \
126 { \
127 case '\\': \
128 case '\"': \
129 require_space(2); \
130 dst[dst_idx++] = '\\'; \
131 dst[dst_idx++] = src[i]; \
132 break; \
133 case '\r': complex_idx++; \
134 case '\f': complex_idx++; \
135 case '\v': complex_idx++; \
136 case '\n': complex_idx++; \
137 case '\t': complex_idx++; \
138 case '\b': complex_idx++; \
139 case '\a': \
140 require_space(2); \
141 dst[dst_idx++] = '\\'; \
142 dst[dst_idx++] = complex_chars[complex_idx]; \
143 break; \
144 default: \
145 if(isprint(src[i])) \
146 { \
147 require_space(1); \
148 dst[dst_idx++] = src[i]; \
149 } \
150 else \
151 { \
152 require_space(4); \
153 dst[dst_idx++] = '\\'; \
154 dst[dst_idx++] = (char)(((src[i] & 0300) >> 6) + '0'); \
155 dst[dst_idx++] = (char)(((src[i] & 0070) >> 3) + '0'); \
156 dst[dst_idx++] = (char)(((src[i] & 0007) >> 0) + '0'); \
157 } \
158 break; \
159 } \
160 } \
161 json_escape_finalize: \
162 dst[dst_idx++] = 0; \
163 return dst_idx;
164
165 size_t json_escape_str(char *dst, size_t dst_len, const char *src)
166 {
167 json_escape_body(src[i] != 0);
168 }
169
170 // Buffer needs to have at least one byte.
171 size_t json_escape(char *dst, size_t dst_len, const uint8_t *src, size_t src_len)
172 {
173 json_escape_body(i != src_len);
174 }
175
176 #undef require_space
177 #undef json_escape_body
178
179 #endif
0 // SPDX-License-Identifier: GPL-3.0-only
1
2 #ifndef MASSRESOLVER_TIMED_RING_H
3 #define MASSRESOLVER_TIMED_RING_H
4
5 #include <time.h>
6 #include <stdint.h>
7
8 #include "hashmap.h"
9 #include "security.h"
10 #include "list.h"
11
12 // The timed ring is a circular buffer allowing to efficiently process time-based events with a certain precision.
13
14 #define TIMED_RING_S 1000000000
15 #define TIMED_RING_MS 1000000
16 #define TIMED_RING_US 1000
17 #define TIMED_RING_NS 1
18
19 typedef struct
20 {
21 void **data;
22 size_t count;
23 single_list_t following; // entries exceeding the bucket capacity
24 } timed_ring_bucket_t;
25
26 typedef struct {
27 size_t bucket_count; // number of buckets
28 size_t precision; // number of nanoseconds per bucket
29 struct timespec last_time;
30 size_t bucket_capacity;
31 size_t next_bucket; // The index of the bucket that is supposed to be executed next.
32 timed_ring_bucket_t *buckets;
33 bool efficient;
34 } timed_ring_t;
35
36
37 // Initialize a timed ring with a time span of bucket_count * precision
38 void timed_ring_init(timed_ring_t* ring, size_t bucket_count, size_t precision, size_t bucket_capacity)
39 {
40 assert(bucket_capacity != 0);
41 assert(1000000000 % precision == 0);
42 ring->bucket_count = bucket_count;
43 ring->precision = precision;
44 ring->bucket_capacity = bucket_capacity;
45 ring->buckets = safe_malloc(sizeof(*ring->buckets) * ring->bucket_count);
46 ring->next_bucket = 0;
47 ring->efficient = false;
48 for(size_t i = 0; i < ring->bucket_count; i++)
49 {
50 ring->buckets[i].count = 0;
51 single_list_init(&ring->buckets[i].following);
52 ring->buckets[i].data = safe_malloc(sizeof(void*) * bucket_capacity);
53 }
54 clock_gettime(CLOCK_MONOTONIC, &ring->last_time);
55 ring->last_time.tv_nsec = (ring->last_time.tv_nsec / precision) * precision;
56 }
57
58 void timed_ring_clear(timed_ring_t* ring)
59 {
60 for(size_t i = 0; i < ring->bucket_count; i++)
61 {
62 ring->buckets[i].count = 0;
63 single_list_clear(&ring->buckets[i].following);
64 }
65 }
66
67 void timed_ring_destroy(timed_ring_t* ring)
68 {
69 if(!ring || !ring->buckets)
70 {
71 return;
72 }
73 for(size_t i = 0; i < ring->bucket_count; i++)
74 {
75 single_list_clear(&ring->buckets[i].following);
76 free(ring->buckets[i].data);
77 }
78 free(ring->buckets);
79 }
80
81 void timed_ring_remove(timed_ring_t *ring, void **add_ptr)
82 {
83 *add_ptr = NULL;
84 }
85
86 void **timed_ring_add(timed_ring_t *ring, time_t in, void *ptr)
87 {
88 struct timespec expiry;
89 clock_gettime(CLOCK_MONOTONIC, &expiry);
90 expiry.tv_nsec += in;
91 expiry.tv_sec += expiry.tv_nsec / 1000000000;
92 expiry.tv_nsec %= 1000000000;
93 expiry.tv_nsec = (expiry.tv_nsec / ring->precision) * ring->precision;
94 time_t elapsed_ns = (expiry.tv_sec - ring->last_time.tv_sec) * 1000000000 + (expiry.tv_nsec - ring->last_time.tv_nsec);
95 size_t elapsed_buckets = elapsed_ns / ring->precision;
96 elapsed_buckets = min(ring->bucket_count - 1, elapsed_buckets);
97 size_t bucket = (ring->next_bucket + elapsed_buckets) % ring->bucket_count;
98 if(ring->buckets[bucket].count < ring->bucket_capacity)
99 {
100 ring->buckets[bucket].data[ring->buckets[bucket].count] = ptr;
101 return &ring->buckets[bucket].data[ring->buckets[bucket].count++];
102 }
103 else
104 {
105 ring->buckets[bucket].count++;
106 return &single_list_push_back(&ring->buckets[bucket].following, ptr)->data;
107 }
108 }
109
110 static inline void timed_ring_handle_helper(timed_ring_t *ring, timed_ring_bucket_t *bucket, void (*callback)(void*))
111 {
112 // Copy everything because the callback function might add another entry to the same bucket
113 // This is an important limitation that needs to be considered:
114 // Re-adding more than one event to the ring per callback call might result in an endless loop.
115 single_list_t iter_list = bucket->following;
116 single_list_init(&bucket->following);
117 size_t count = min(bucket->count, ring->bucket_capacity);
118 bucket->count = 0;
119
120 for(size_t j = 0; j < count; j++)
121 {
122 if(bucket->data[j] != NULL)
123 {
124 callback(bucket->data[j]);
125 }
126 }
127 single_list_foreach_free(iter_list, elm)
128 {
129 if(elm->data != NULL)
130 {
131 callback(elm->data);
132 }
133 }
134 }
135
136 void timed_ring_handle(timed_ring_t *ring, void (*callback)(void*))
137 {
138 struct timespec now;
139 clock_gettime(CLOCK_MONOTONIC, &now);
140 now.tv_nsec = (now.tv_nsec / ring->precision) * ring->precision;
141 time_t elapsed_ns = (now.tv_sec - ring->last_time.tv_sec) * 1000000000 + (now.tv_nsec - ring->last_time.tv_nsec);
142 size_t elapsed_buckets = elapsed_ns / ring->precision;
143 elapsed_buckets = min(ring->bucket_count, elapsed_buckets);
144
145 for(size_t i = 0; i < elapsed_buckets; i++)
146 {
147 timed_ring_handle_helper(ring, &ring->buckets[(ring->next_bucket + i) % ring->bucket_count], callback);
148 }
149 ring->next_bucket = (ring->next_bucket + elapsed_buckets) % ring->bucket_count;
150 ring->last_time = now;
151 }
152
153
154 #endif //MASSRESOLVER_TIMED_RING_H
+0
-178
string.h less more
0 #ifndef INC_STRING
1 #define INC_STRING
2
3 #include "security.h"
4
5 #include <stdbool.h>
6 #include <strings.h>
7 #include <string.h>
8 #include <ctype.h>
9
10 char *strmcpy(const char *str)
11 {
12 size_t len = strlen(str);
13 char *result = safe_malloc(len + 1);
14 memcpy(result, str, len);
15 result[len] = 0;
16 return result;
17 }
18
19 size_t string_copy(char *dest, const char *src, size_t n)
20 {
21 size_t i;
22
23 for (i = 0; i < n - 1 && src[i] != '\0'; i++) {
24 dest[i] = src[i];
25 }
26 dest[i] = 0;
27 return i;
28 }
29
30 void *flatcopy(void *src, size_t len)
31 {
32 void *dst = safe_malloc(len);
33 memcpy(dst, src, len);
34 return dst;
35 }
36
37 void strtolower(char *str)
38 {
39 while (*str != '\0')
40 {
41 if (*str >= 'A' && *str <= 'Z')
42 {
43 *str = (char) (*str | (1 << 5));
44 }
45 str++;
46 }
47 }
48
49 char *trim_start(char *str)
50 {
51 while (0 != *str)
52 {
53 if(!isspace(*str))
54 {
55 return str;
56 }
57 str++;
58 }
59 return str;
60 }
61
62 void trim_end(char* str)
63 {
64 char *last = str + strlen(str) - 1;
65 while (last >= str)
66 {
67 if(!isspace(*last))
68 {
69 return;
70 }
71 *last = 0;
72 last--;
73 }
74 }
75
76 bool endswith(char* haystack, char* needle, bool case_sensitive)
77 {
78 int (*cmp)(const char*, const char*) = strcmp;
79 if(!case_sensitive)
80 {
81 cmp = strcasecmp;
82 }
83 size_t haystack_len = strlen(haystack);
84 size_t needle_len = strlen(needle);
85 return needle_len <= haystack_len && cmp(haystack + haystack_len - needle_len, needle) == 0;
86 }
87
88 bool startswith(char* haystack, char* needle, bool case_sensitive) // Supports ASCII only
89 {
90 while(true)
91 {
92 char nchar = *needle++;
93 char hchar = *haystack++;
94 if(nchar == 0)
95 {
96 return true;
97 }
98 else if(hchar == 0)
99 {
100 return false;
101 }
102 if(case_sensitive)
103 {
104 nchar = (char)tolower(nchar);
105 hchar = (char)tolower(hchar);
106 }
107 if(nchar != hchar)
108 {
109 return false;
110 }
111 }
112 }
113
114 #define require_space(N) if(dst_idx >= dst_len - (N)) goto json_escape_finalize;
115
116 #define json_escape_body(BREAK_COND) \
117 const char complex_chars[] = "abtnvfr"; \
118 size_t dst_idx = 0; \
119 \
120 for(size_t i = 0; (BREAK_COND); i++) \
121 { \
122 size_t complex_idx = 0; \
123 switch(src[i]) \
124 { \
125 case '\\': \
126 case '\"': \
127 require_space(2); \
128 dst[dst_idx++] = '\\'; \
129 dst[dst_idx++] = src[i]; \
130 break; \
131 case '\r': complex_idx++; \
132 case '\f': complex_idx++; \
133 case '\v': complex_idx++; \
134 case '\n': complex_idx++; \
135 case '\t': complex_idx++; \
136 case '\b': complex_idx++; \
137 case '\a': \
138 require_space(2); \
139 dst[dst_idx++] = '\\'; \
140 dst[dst_idx++] = complex_chars[complex_idx]; \
141 break; \
142 default: \
143 if(isprint(src[i])) \
144 { \
145 require_space(1); \
146 dst[dst_idx++] = src[i]; \
147 } \
148 else \
149 { \
150 require_space(4); \
151 dst[dst_idx++] = '\\'; \
152 dst[dst_idx++] = (char)(((src[i] & 0300) >> 6) + '0'); \
153 dst[dst_idx++] = (char)(((src[i] & 0070) >> 3) + '0'); \
154 dst[dst_idx++] = (char)(((src[i] & 0007) >> 0) + '0'); \
155 } \
156 break; \
157 } \
158 } \
159 json_escape_finalize: \
160 dst[dst_idx++] = 0; \
161 return dst_idx;
162
163 size_t json_escape_str(char *dst, size_t dst_len, const char *src)
164 {
165 json_escape_body(src[i] != 0);
166 }
167
168 // Buffer needs to have at least one byte.
169 size_t json_escape(char *dst, size_t dst_len, const uint8_t *src, size_t src_len)
170 {
171 json_escape_body(i != src_len);
172 }
173
174 #undef require_space
175 #undef json_escape_body
176
177 #endif
0 google.com
1 domain.invalid
0 #!/bin/bash
1
2 DIR=$(dirname "$0")
3 "$DIR"/../../bin/massdns -c 3 --quiet -r "$DIR"/google-dns.txt -o J --ignore NOERROR "$DIR"/names.txt | jq .name | grep -q -E "domain.invalid" && "$DIR"/../../bin/massdns -c 3 --quiet -r "$DIR"/google-dns.txt -o J --ignore NXDOMAIN "$DIR"/names.txt | jq .name | grep -q -E "google.com"
+0
-153
timed_ring.h less more
0 #ifndef MASSRESOLVER_TIMED_RING_H
1 #define MASSRESOLVER_TIMED_RING_H
2
3 #include <time.h>
4 #include <stdint.h>
5
6 #include "hashmap.h"
7 #include "security.h"
8 #include "list.h"
9
10 // The timed ring is a circular buffer allowing to efficiently process time-based events with a certain precision.
11
12 #define TIMED_RING_S 1000000000
13 #define TIMED_RING_MS 1000000
14 #define TIMED_RING_US 1000
15 #define TIMED_RING_NS 1
16
17 typedef struct
18 {
19 void **data;
20 size_t count;
21 single_list_t following; // entries exceeding the bucket capacity
22 } timed_ring_bucket_t;
23
24 typedef struct {
25 size_t bucket_count; // number of buckets
26 size_t precision; // number of nanoseconds per bucket
27 struct timespec last_time;
28 size_t bucket_capacity;
29 size_t next_bucket; // The index of the bucket that is supposed to be executed next.
30 timed_ring_bucket_t *buckets;
31 bool efficient;
32 } timed_ring_t;
33
34
35 // Initialize a timed ring with a time span of bucket_count * precision
36 void timed_ring_init(timed_ring_t* ring, size_t bucket_count, size_t precision, size_t bucket_capacity)
37 {
38 assert(bucket_capacity != 0);
39 assert(1000000000 % precision == 0);
40 ring->bucket_count = bucket_count;
41 ring->precision = precision;
42 ring->bucket_capacity = bucket_capacity;
43 ring->buckets = safe_malloc(sizeof(*ring->buckets) * ring->bucket_count);
44 ring->next_bucket = 0;
45 ring->efficient = false;
46 for(size_t i = 0; i < ring->bucket_count; i++)
47 {
48 ring->buckets[i].count = 0;
49 single_list_init(&ring->buckets[i].following);
50 ring->buckets[i].data = safe_malloc(sizeof(void*) * bucket_capacity);
51 }
52 clock_gettime(CLOCK_MONOTONIC, &ring->last_time);
53 ring->last_time.tv_nsec = (ring->last_time.tv_nsec / precision) * precision;
54 }
55
56 void timed_ring_clear(timed_ring_t* ring)
57 {
58 for(size_t i = 0; i < ring->bucket_count; i++)
59 {
60 ring->buckets[i].count = 0;
61 single_list_clear(&ring->buckets[i].following);
62 }
63 }
64
65 void timed_ring_destroy(timed_ring_t* ring)
66 {
67 if(!ring || !ring->buckets)
68 {
69 return;
70 }
71 for(size_t i = 0; i < ring->bucket_count; i++)
72 {
73 single_list_clear(&ring->buckets[i].following);
74 free(ring->buckets[i].data);
75 }
76 free(ring->buckets);
77 }
78
79 void timed_ring_remove(timed_ring_t *ring, void **add_ptr)
80 {
81 *add_ptr = NULL;
82 }
83
84 void **timed_ring_add(timed_ring_t *ring, time_t in, void *ptr)
85 {
86 struct timespec expiry;
87 clock_gettime(CLOCK_MONOTONIC, &expiry);
88 expiry.tv_nsec += in;
89 expiry.tv_sec += expiry.tv_nsec / 1000000000;
90 expiry.tv_nsec %= 1000000000;
91 expiry.tv_nsec = (expiry.tv_nsec / ring->precision) * ring->precision;
92 time_t elapsed_ns = (expiry.tv_sec - ring->last_time.tv_sec) * 1000000000 + (expiry.tv_nsec - ring->last_time.tv_nsec);
93 size_t elapsed_buckets = elapsed_ns / ring->precision;
94 elapsed_buckets = min(ring->bucket_count - 1, elapsed_buckets);
95 size_t bucket = (ring->next_bucket + elapsed_buckets) % ring->bucket_count;
96 if(ring->buckets[bucket].count < ring->bucket_capacity)
97 {
98 ring->buckets[bucket].data[ring->buckets[bucket].count] = ptr;
99 return &ring->buckets[bucket].data[ring->buckets[bucket].count++];
100 }
101 else
102 {
103 ring->buckets[bucket].count++;
104 return &single_list_push_back(&ring->buckets[bucket].following, ptr)->data;
105 }
106 }
107
108 static inline void timed_ring_handle_helper(timed_ring_t *ring, timed_ring_bucket_t *bucket, void (*callback)(void*))
109 {
110 // Copy everything because the callback function might add another entry to the same bucket
111 // This is an important limitation that needs to be considered:
112 // Re-adding more than one event to the ring per callback call might result in an endless loop.
113 single_list_t iter_list = bucket->following;
114 single_list_init(&bucket->following);
115 size_t count = min(bucket->count, ring->bucket_capacity);
116 bucket->count = 0;
117
118 for(size_t j = 0; j < count; j++)
119 {
120 if(bucket->data[j] != NULL)
121 {
122 callback(bucket->data[j]);
123 }
124 }
125 single_list_foreach_free(iter_list, elm)
126 {
127 if(elm->data != NULL)
128 {
129 callback(elm->data);
130 }
131 }
132 }
133
134 void timed_ring_handle(timed_ring_t *ring, void (*callback)(void*))
135 {
136 struct timespec now;
137 clock_gettime(CLOCK_MONOTONIC, &now);
138 now.tv_nsec = (now.tv_nsec / ring->precision) * ring->precision;
139 time_t elapsed_ns = (now.tv_sec - ring->last_time.tv_sec) * 1000000000 + (now.tv_nsec - ring->last_time.tv_nsec);
140 size_t elapsed_buckets = elapsed_ns / ring->precision;
141 elapsed_buckets = min(ring->bucket_count, elapsed_buckets);
142
143 for(size_t i = 0; i < elapsed_buckets; i++)
144 {
145 timed_ring_handle_helper(ring, &ring->buckets[(ring->next_bucket + i) % ring->bucket_count], callback);
146 }
147 ring->next_bucket = (ring->next_bucket + elapsed_buckets) % ring->bucket_count;
148 ring->last_time = now;
149 }
150
151
152 #endif //MASSRESOLVER_TIMED_RING_H