New upstream version 2.6.3
Sascha Steinbiss
1 year, 8 months ago
13 | 13 | # limitations under the License. |
14 | 14 | # |
15 | 15 | |
16 | CURLINCL = `curl-config --cflags` | |
17 | JANSINCL = -I/usr/local/include | |
16 | # Base directory for jansson header and libraries | |
17 | JANSBASE=/usr/local | |
18 | # For macOS on M1, use this instead of the above line: | |
19 | #JANSBASE=/opt/homebrew | |
18 | 20 | |
21 | JANSINCL = -I$(JANSBASE)/include | |
22 | ||
23 | JANSLIBS = -L$(JANSBASE)/lib -ljansson | |
24 | # For almost static builds on macOS, use this instead of the above line: | |
25 | #JANSLIBS = $(JANSBASE)/lib/libjansson.a | |
26 | ||
27 | CURLINCL = `curl-config --cflags` | |
19 | 28 | CURLLIBS = `[ ! -z "$$(curl-config --libs)" ] && curl-config --libs || curl-config --static-libs` |
20 | JANSLIBS = -L/usr/local/lib -ljansson | |
21 | 29 | |
22 | 30 | CWARN =-W -Wall -Wextra -Wcast-qual -Wpointer-arith -Wwrite-strings \ |
23 | 31 | -Wmissing-prototypes -Wbad-function-cast -Wnested-externs \ |
32 | 40 | CDEBUG = -g -O3 |
33 | 41 | CFLAGS += $(CGPROF) $(CDEBUG) $(CWARN) $(CDEFS) |
34 | 42 | INCL= $(CURLINCL) $(JANSINCL) |
35 | # freebsd requires that -lresolv _not_ be used here | |
36 | 43 | LIBS= $(CURLLIBS) $(JANSLIBS) -lresolv |
44 | # For freebsd, it requires that -lresolv _not_ be used here, use this instead of the above line: | |
37 | 45 | #LIBS= $(CURLLIBS) $(JANSLIBS) |
38 | 46 | |
39 | 47 | TOOL = dnsdbq |
40 | 48 | TOOL_OBJ = $(TOOL).o ns_ttl.o netio.o \ |
41 | 49 | pdns.o pdns_circl.o pdns_dnsdb.o \ |
42 | sort.o time.o asinfo.o deduper.o | |
50 | sort.o time.o asinfo.o deduper.o \ | |
51 | tokstr.o | |
43 | 52 | TOOL_SRC = $(TOOL).c ns_ttl.c netio.c \ |
44 | 53 | pdns.c pdns_circl.c pdns_dnsdb.c \ |
45 | sort.c time.c asinfo.c deduper.c | |
54 | sort.c time.c asinfo.c deduper.c \ | |
55 | tokstr.c | |
46 | 56 | |
47 | 57 | all: $(TOOL) |
48 | 58 | |
76 | 86 | asinfo.h globals.h defs.h sort.h pdns.h netio.h |
77 | 87 | dnsdbq.o: dnsdbq.c \ |
78 | 88 | defs.h netio.h \ |
79 | pdns.h \ | |
89 | pdns.h tokstr.h \ | |
80 | 90 | pdns_dnsdb.h pdns_circl.h sort.h \ |
81 | 91 | time.h globals.h |
82 | 92 | ns_ttl.o: ns_ttl.c \ |
90 | 100 | netio.h \ |
91 | 101 | pdns.h \ |
92 | 102 | time.h \ |
93 | globals.h sort.h | |
103 | globals.h sort.h tokstr.h | |
94 | 104 | pdns_circl.o: pdns_circl.c \ |
95 | 105 | defs.h \ |
96 | 106 | pdns.h \ |
110 | 120 | globals.h sort.h pdns.h \ |
111 | 121 | netio.h \ |
112 | 122 | ns_ttl.h |
123 | tokstr.o: tokstr.c \ | |
124 | tokstr.h |
107 | 107 | On FreeBSD, you may need to remove -lresolv in the LIBS line of |
108 | 108 | the Makefile. |
109 | 109 | |
110 | On macOS on Apple M1 processors, Homebrew now defaults to be | |
111 | installed in /opt/homebrew instead of /usr/local. If that is the | |
112 | case on your system, in the Makefile, uncomment the line | |
113 | #JANSBASE=/opt/homebrew | |
114 | ||
110 | 115 | On macOS, if you want an almost static dnsdbq binary on macOS, |
111 | that is, one without any non-System library dependencies, you can | |
116 | that is, one with minimal non-System library dependencies, you can | |
112 | 117 | rebuild dnsdbq with a static jansson library. That binary could |
113 | 118 | then be deployed on any identical macOS version and architecture. |
114 | 119 | |
115 | 1. Find the static jansson library, probably | |
116 | /usr/local/lib/libjansson.a as installed by brew. | |
120 | 1. Find the static jansson library, probably as installed by brew | |
121 | /usr/local/lib/libjansson.a or /opt/homebrew/lib/libjansson.a | |
117 | 122 | 2. Change the Makefile's line |
118 | JANSLIBS = -L/usr/local/lib -ljansson | |
123 | JANSLIBS = -L$(JANSBASE)/lib -ljansson | |
119 | 124 | to instead specify the static library location, probably to: |
120 | JANSLIBS = /usr/local/lib/libjansson.a | |
125 | JANSLIBS = $(JANSBASE)/lib/libjansson.a | |
121 | 126 | 3. Then run make |
122 | 127 | |
123 | 128 |
44 | 44 | |
45 | 45 | /* forward. */ |
46 | 46 | |
47 | static const char *asinfo_from_ipv4(const char *, char **, char **); | |
47 | static char *asinfo_from_ipv4(const char *, char **, char **); | |
48 | 48 | #ifdef asinfo_ipv6 |
49 | 49 | static const char *asinfo_from_ipv6(const char *, char **, char **); |
50 | 50 | #endif |
51 | static const char *asinfo_from_dns(const char *, char **, char **); | |
51 | static char *asinfo_from_dns(const char *, char **, char **); | |
52 | 52 | static const char *keep_best(char **, char **, char *, char *); |
53 | 53 | |
54 | 54 | /* public. */ |
55 | 55 | |
56 | 56 | /* asinfo_from_rr(rrtype, rdata, asnum, cidr) -- find ASINFO for A/AAAA string |
57 | 57 | * |
58 | * return NULL on success, or else, reason (string) for failure. | |
59 | * | |
60 | * side effect: on success, *asnum and *cidr will be heap-allocated strings. | |
61 | */ | |
62 | const char * | |
58 | * return NULL on success, or else, reason (malloc'd string) for failure. | |
59 | * | |
60 | * side effect: on success, *asnum and *cidr will be heap-allocated strings. | |
61 | */ | |
62 | char * | |
63 | 63 | asinfo_from_rr(const char *rrtype, const char *rdata, |
64 | 64 | char **asnum, char **cidr) |
65 | 65 | { |
98 | 98 | |
99 | 99 | /* asinfo_from_ipv4(addr, asnum, cidr) -- prepare and use ASINFO IPv4 name |
100 | 100 | * |
101 | * return NULL on success, or else, reason (string) for failure. | |
102 | * | |
103 | * side effect: on success, *asnum and *cidr will be heap-allocated strings. | |
104 | */ | |
105 | static const char * | |
101 | * return NULL on success, or else, reason (malloc'd string) for failure. | |
102 | * | |
103 | * side effect: on success, *asnum and *cidr will be heap-allocated strings. | |
104 | */ | |
105 | static char * | |
106 | 106 | asinfo_from_ipv4(const char *addr, char **asnum, char **cidr) { |
107 | 107 | u_char a4[32/8]; |
108 | 108 | char *dname; |
109 | 109 | |
110 | 110 | if (inet_pton(AF_INET, addr, a4) < 0) |
111 | return strerror(errno); | |
111 | return strdup(strerror(errno)); | |
112 | 112 | int n = asprintf(&dname, "%d.%d.%d.%d.%s", |
113 | 113 | a4[3], a4[2], a4[1], a4[0], asinfo_domain); |
114 | 114 | if (n < 0) |
115 | return strerror(errno); | |
116 | const char *result = asinfo_from_dns(dname, asnum, cidr); | |
115 | return strdup(strerror(errno)); | |
116 | char *result = asinfo_from_dns(dname, asnum, cidr); | |
117 | 117 | free(dname); |
118 | 118 | return result; |
119 | 119 | } |
121 | 121 | #ifdef asinfo_ipv6 |
122 | 122 | /* asinfo_from_ipv6(addr, asnum, cidr) -- prepare and use ASINFO IPv6 name |
123 | 123 | * |
124 | * return NULL on success, or else, reason (string) for failure. | |
124 | * return NULL on success, or else, reason (malloc'd string) for failure. | |
125 | 125 | * |
126 | 126 | * side effect: on success, *asnum and *cidr will be heap-allocated strings. |
127 | 127 | * |
128 | 128 | * NOTE WELL: this is a placeholder, since no ASINFO source has working IPv6. |
129 | 129 | */ |
130 | static const char * | |
130 | static char * | |
131 | 131 | asinfo_from_ipv6(const char *addr, char **asnum, char **cidr) { |
132 | char *result, *dname, *p; | |
132 | 133 | u_char a6[128/8]; |
133 | const char *result; | |
134 | char *dname, *p; | |
135 | 134 | int i; |
136 | 135 | |
137 | 136 | if (inet_pton(AF_INET6, addr, &a6) < 0) |
138 | return strerror(errno); | |
137 | return strdup(strerror(errno)); | |
139 | 138 | dname = malloc(strlen(asinfo_domain) + (128/4)*2); |
140 | 139 | if (dname == NULL) |
141 | return strerror(errno); | |
140 | return strdup(strerror(errno)); | |
142 | 141 | result = NULL; |
143 | 142 | p = dname; |
144 | 143 | for (i = (128/8) - 1; i >= 0; i--) { |
145 | 144 | int n = sprintf(p, "%x.%x.", a6[i] & 0xf, a6[i] >> 4); |
146 | 145 | if (n < 0) { |
147 | result = strerror(errno); | |
146 | result = strdup(strerror(errno)); | |
148 | 147 | break; |
149 | 148 | } |
150 | 149 | p += n; |
161 | 160 | |
162 | 161 | /* asinfo_from_dns(dname, asnum, cidr) -- retrieve and parse a ASINFO DNS TXT |
163 | 162 | * |
164 | * return NULL on success, or else, reason (string) for failure. | |
165 | * | |
166 | * side effect: on success, *asnum and *cidr will be heap-allocated strings. | |
167 | */ | |
168 | static const char * | |
163 | * return NULL on success, or else, reason (malloc'd string) for failure. | |
164 | * | |
165 | * side effect: on success, *asnum and *cidr will be heap-allocated strings. | |
166 | */ | |
167 | static char * | |
169 | 168 | asinfo_from_dns(const char *dname, char **asnum, char **cidr) { |
170 | 169 | u_char buf[NS_PACKETSZ]; |
171 | 170 | int n, an, rrn, rcode; |
172 | const char *result; | |
171 | char *result; | |
173 | 172 | ns_msg msg; |
174 | 173 | ns_rr rr; |
175 | 174 | |
184 | 183 | if (res.res_h_errno == HOST_NOT_FOUND) |
185 | 184 | return NULL; |
186 | 185 | else |
187 | return hstrerror(res.res_h_errno); | |
186 | return strdup(hstrerror(res.res_h_errno)); | |
188 | 187 | } |
189 | 188 | if (ns_initparse(buf, n, &msg) < 0) |
190 | return strerror(errno); | |
189 | return strdup(strerror(errno)); | |
191 | 190 | rcode = ns_msg_getflag(msg, ns_f_rcode); |
192 | if (rcode != ns_r_noerror) | |
193 | return p_rcode(rcode); | |
191 | if (rcode != ns_r_noerror) { | |
192 | if (asprintf(&result, "DNS RCODE 0x%x", rcode) < 0) | |
193 | return strdup(strerror(errno)); | |
194 | return result; | |
195 | } | |
194 | 196 | an = ns_msg_count(msg, ns_s_an); |
195 | 197 | if (an == 0) |
196 | return "ANCOUNT == 0"; | |
198 | return strdup("ANCOUNT == 0"); | |
197 | 199 | /* some ASINFO data sources return multiple TXT RR's, each having |
198 | 200 | * a prefix length measured in bits. we will select the best |
199 | 201 | * (longest match) prefix offered. |
204 | 206 | char *txt[3]; |
205 | 207 | |
206 | 208 | if (ns_parserr(&msg, ns_s_an, rrn, &rr) < 0) { |
207 | result = strerror(errno); | |
209 | result = strdup(strerror(errno)); | |
208 | 210 | break; |
209 | 211 | } |
210 | 212 | rdata = ns_rr_rdata(rr); |
215 | 217 | * more than three TXT segments (<character-strings>). |
216 | 218 | */ |
217 | 219 | if (ntxt == 3) { |
218 | result = "len(TXT[]) > 3"; | |
220 | result = strdup("len(TXT[]) > 3"); | |
219 | 221 | break; |
220 | 222 | } |
221 | 223 | n = *rdata++; |
222 | 224 | rdlen--; |
223 | 225 | if (n > rdlen) { |
224 | result = "TXT overrun"; | |
226 | result = strdup("TXT overrun"); | |
225 | 227 | break; |
226 | 228 | } |
227 | 229 | txt[ntxt] = strndup((const char *)rdata, (size_t)n); |
228 | 230 | if (txt[ntxt] == NULL) { |
229 | result = "strndup FAIL"; | |
231 | result = strdup("strndup FAIL"); | |
230 | 232 | break; |
231 | 233 | } |
232 | 234 | DEBUG(2, true, "TXT[%d] \"%s\"\n", ntxt, txt[ntxt]); |
257 | 259 | new_cidr = strndup(t1 + seplen, (size_t) |
258 | 260 | (t2 - (t1 + seplen))); |
259 | 261 | t1 = t2 = NULL; |
260 | result = keep_best(asnum, cidr, | |
261 | new_asnum, new_cidr); | |
262 | const char *t = keep_best(asnum, cidr, | |
263 | new_asnum, | |
264 | new_cidr); | |
265 | if (t != NULL) | |
266 | result = strdup(t); | |
262 | 267 | } else if (ntxt == 3) { |
263 | 268 | /* routeviews.org format: |
264 | 269 | * |
273 | 278 | txt[1], txt[2]) >= 0) |
274 | 279 | { |
275 | 280 | new_asnum = strdup(txt[0]); |
276 | result = keep_best(asnum, cidr, | |
277 | new_asnum, | |
278 | new_cidr); | |
281 | const char *t = keep_best(asnum, cidr, | |
282 | new_asnum, | |
283 | new_cidr); | |
284 | if (t != NULL) | |
285 | result = strdup(t); | |
279 | 286 | } else { |
280 | result = strerror(errno); | |
287 | result = strdup(strerror(errno)); | |
281 | 288 | } |
282 | 289 | } else { |
283 | result = "unrecognized asinfo TXT format"; | |
290 | result = strdup("unrecognized TXT format"); | |
284 | 291 | } |
285 | 292 | } |
286 | 293 | for (n = 0; n < ntxt; n++) { |
19 | 19 | #include <stdbool.h> |
20 | 20 | |
21 | 21 | #ifndef CRIPPLED_LIBC |
22 | const char * | |
22 | char * | |
23 | 23 | asinfo_from_rr(const char *rrtype, const char *rdata, char **asn, char **cidr); |
24 | 24 | #endif |
25 | 25 |
86 | 86 | deduper_dump(deduper_t me, FILE *out) { |
87 | 87 | for (size_t bucket = 0; bucket < me->buckets; bucket++) |
88 | 88 | if (me->chains[bucket] != NULL) { |
89 | fprintf(out, "[%lu]", bucket); | |
89 | fprintf(out, "[%zu]", bucket); | |
90 | 90 | for (chainlink_t chainlink = me->chains[bucket]; |
91 | 91 | chainlink != NULL; |
92 | 92 | chainlink = chainlink->next) |
51 | 51 | #include "pdns.h" |
52 | 52 | #include "sort.h" |
53 | 53 | #include "time.h" |
54 | #include "tokstr.h" | |
54 | 55 | #include "globals.h" |
55 | 56 | #undef MAIN_PROGRAM |
56 | 57 | |
355 | 356 | if (sorting == no_sort) |
356 | 357 | usage("-k must be preceded by -s or -S"); |
357 | 358 | |
358 | char *saveptr = NULL; | |
359 | const char *tok; | |
360 | for (tok = strtok_r(optarg, ",", &saveptr); | |
361 | tok != NULL; | |
362 | tok = strtok_r(NULL, ",", &saveptr)) | |
359 | struct tokstr *ts = tokstr_string(optarg); | |
360 | for (char *tok; | |
361 | (tok = tokstr_next(ts, ",")) != NULL; | |
362 | free(tok)) | |
363 | 363 | { |
364 | 364 | if (find_sort_key(tok) != NULL) |
365 | 365 | usage("Each sort key may only be " |
368 | 368 | if ((msg = add_sort_key(tok)) != NULL) |
369 | 369 | usage(msg); |
370 | 370 | } |
371 | tokstr_last(&ts); | |
371 | 372 | break; |
372 | 373 | } |
373 | 374 | case 'J': |
401 | 402 | } |
402 | 403 | break; |
403 | 404 | case 'T': { |
404 | char *copy, *walker, *token; | |
405 | copy = walker = strdup(optarg); | |
406 | while ((token = strsep(&walker, ",")) != NULL) | |
405 | struct tokstr *ts = tokstr_string(optarg); | |
406 | for (char *token; | |
407 | (token = tokstr_next(ts, ",")) != NULL; | |
408 | free(token)) | |
409 | { | |
407 | 410 | if (strcasecmp(token, "reverse") == 0) |
408 | 411 | transforms |= TRANS_REVERSE; |
409 | 412 | else if (strcasecmp(token, "datefix") == 0) |
411 | 414 | else if (strcasecmp(token, "chomp") == 0) |
412 | 415 | transforms |= TRANS_CHOMP; |
413 | 416 | else { |
414 | DESTROY(copy); | |
415 | 417 | usage("unrecognized transform in -T"); |
416 | 418 | } |
417 | DESTROY(copy); | |
419 | } | |
420 | tokstr_last(&ts); | |
418 | 421 | break; |
419 | 422 | } |
420 | 423 | case 'm': |
1116 | 1119 | char **opt = optv; |
1117 | 1120 | const char *msg; |
1118 | 1121 | int optc, ch; |
1119 | char *tok; | |
1120 | ||
1121 | char *temp = strdup(optstr); | |
1122 | char *saveptr = NULL; | |
1122 | ||
1123 | 1123 | /* crack the option string based on space or tab delimiters. */ |
1124 | for (tok = strtok_r(temp, "\040\t", &saveptr); | |
1125 | tok != NULL; | |
1126 | tok = strtok_r(NULL, "\040\t", &saveptr)) | |
1124 | struct tokstr *ts = tokstr_string(optstr); | |
1125 | for (char *tok; | |
1126 | (tok = tokstr_next(ts, "\040\011")) != NULL; | |
1127 | free(tok)) | |
1127 | 1128 | { |
1128 | 1129 | /* dispense with extra spaces and tabs (empty fields). */ |
1129 | 1130 | if (*tok == '\0') |
1130 | 1131 | continue; |
1131 | 1132 | *opt++ = tok; |
1132 | 1133 | } |
1134 | tokstr_last(&ts); | |
1133 | 1135 | |
1134 | 1136 | /* if no options were specified (e.g., $options\n), restore defaults. |
1135 | 1137 | */ |
1174 | 1176 | } |
1175 | 1177 | /* done. */ |
1176 | 1178 | DESTROY(optv); |
1177 | DESTROY(temp); | |
1178 | 1179 | return msg; |
1179 | 1180 | } |
1180 | 1181 | |
1362 | 1363 | |
1363 | 1364 | /* ready player one. */ |
1364 | 1365 | CREATE(query, sizeof(struct query)); |
1366 | query->descrip = makepath(qdp); | |
1367 | query->mode = qdp->mode; | |
1368 | query->params = *qpp; | |
1369 | qpp = NULL; | |
1365 | 1370 | |
1366 | 1371 | /* define the fence. */ |
1367 | if (qpp->after != 0) { | |
1368 | if (qpp->complete) { | |
1372 | if (query->params.after != 0) { | |
1373 | if (query->params.complete) { | |
1369 | 1374 | /* each db tuple must begin after the fence-start. */ |
1370 | fence.first_after = qpp->after; | |
1375 | fence.first_after = query->params.after; | |
1371 | 1376 | } else { |
1372 | 1377 | /* each db tuple must end after the fence-start. */ |
1373 | fence.last_after = qpp->after; | |
1374 | } | |
1375 | } | |
1376 | if (qpp->before != 0) { | |
1377 | if (qpp->complete) { | |
1378 | fence.last_after = query->params.after; | |
1379 | } | |
1380 | } | |
1381 | if (query->params.before != 0) { | |
1382 | if (query->params.complete) { | |
1378 | 1383 | /* each db tuple must end before the fence-end. */ |
1379 | fence.last_before = qpp->before; | |
1384 | fence.last_before = query->params.before; | |
1380 | 1385 | } else { |
1381 | 1386 | /* each db tuple must begin before the fence-end. */ |
1382 | fence.first_before = qpp->before; | |
1383 | } | |
1384 | } | |
1385 | ||
1386 | /* branch on rrtype. */ | |
1387 | fence.first_before = query->params.before; | |
1388 | } | |
1389 | } | |
1390 | ||
1391 | /* branch on rrtype; launch (or queue) nec'y fetches. */ | |
1387 | 1392 | if (qdp->rrtype == NULL) { |
1388 | 1393 | /* no rrtype string given, let makepath set it to "any". */ |
1389 | 1394 | char *path = makepath(qdp); |
1396 | 1401 | return NULL; |
1397 | 1402 | } else { |
1398 | 1403 | /* rrtype string was given, parse comma separated list. */ |
1399 | char *rrtypes = strdup(qdp->rrtype); | |
1400 | char *saveptr = NULL; | |
1401 | 1404 | int nfetches = 0; |
1402 | for (char *rrtype = strtok_r(rrtypes, ",", &saveptr); | |
1403 | rrtype != NULL; | |
1404 | rrtype = strtok_r(NULL, ",", &saveptr)) | |
1405 | struct tokstr *ts = tokstr_string(qdp->rrtype); | |
1406 | for (char *rrtype; | |
1407 | (rrtype = tokstr_next(ts, ",")) != NULL; | |
1408 | free(rrtype)) | |
1405 | 1409 | { |
1406 | 1410 | struct qdesc qd = { |
1407 | 1411 | .mode = qdp->mode, |
1415 | 1419 | nfetches++; |
1416 | 1420 | DESTROY(path); |
1417 | 1421 | } |
1422 | tokstr_last(&ts); | |
1418 | 1423 | if (nfetches > 1) |
1419 | 1424 | query->multitype = true; |
1420 | DESTROY(rrtypes); | |
1421 | 1425 | } |
1422 | 1426 | |
1423 | 1427 | /* finish query initialization, link it up, and return it. */ |
1424 | 1428 | query->writer = writer; |
1425 | 1429 | writer = NULL; |
1426 | query->params = *qpp; | |
1427 | 1430 | query->next = query->writer->queries; |
1428 | 1431 | query->writer->queries = query; |
1429 | query->descrip = makepath(qdp); | |
1430 | query->mode = qdp->mode; | |
1431 | 1432 | return query; |
1432 | 1433 | } |
1433 | 1434 | |
1436 | 1437 | static const char * |
1437 | 1438 | rrtype_correctness(const char *input) { |
1438 | 1439 | char **rrtypeset = calloc(MAX_FETCHES, sizeof(char *)); |
1439 | char *rrtypes = strdup(input); | |
1440 | char *saveptr = NULL; | |
1441 | 1440 | const char *ret = NULL; |
1442 | 1441 | int nrrtypeset = 0; |
1443 | 1442 | bool some = false, any = false, |
1444 | 1443 | some_dnssec = false, any_dnssec = false; |
1445 | for (char *rrtype = strtok_r(rrtypes, ",", &saveptr); | |
1446 | rrtype != NULL; | |
1447 | rrtype = strtok_r(NULL, ",", &saveptr)) | |
1444 | struct tokstr *ts = tokstr_string(input); | |
1445 | for (char *rrtype; | |
1446 | (rrtype = tokstr_next(ts, ",")) != NULL; | |
1447 | free(rrtype)) | |
1448 | 1448 | { |
1449 | 1449 | for (char *p = rrtype; *p != '\0'; p++) |
1450 | if (isupper(*p)) | |
1451 | *p = (char) tolower(*p); | |
1450 | if (isupper((int)*p)) | |
1451 | *p = (char) tolower((int)*p); | |
1452 | 1452 | if (nrrtypeset == MAX_FETCHES) { |
1453 | 1453 | ret = "too many rrtypes specified"; |
1454 | 1454 | goto done; |
1458 | 1458 | ret = "duplicate rrtype encountered"; |
1459 | 1459 | goto done; |
1460 | 1460 | } |
1461 | rrtypeset[nrrtypeset++] = rrtype; | |
1461 | rrtypeset[nrrtypeset++] = strdup(rrtype); | |
1462 | 1462 | if (strcmp(rrtype, "any") == 0) |
1463 | 1463 | any = true; |
1464 | 1464 | else if (strcmp(rrtype, "any-dnssec") == 0) |
1473 | 1473 | strcmp(rrtype, "nsec3") == 0 || |
1474 | 1474 | strcmp(rrtype, "nsec3param") == 0 || |
1475 | 1475 | strcmp(rrtype, "dlv") == 0) |
1476 | { | |
1476 | 1477 | some_dnssec = true; |
1477 | else | |
1478 | } else { | |
1478 | 1479 | some = true; |
1480 | } | |
1479 | 1481 | if (any && some) { |
1480 | 1482 | ret = "ANY is redundant when mixed like this"; |
1481 | 1483 | goto done; |
1485 | 1487 | goto done; |
1486 | 1488 | } |
1487 | 1489 | } |
1490 | tokstr_last(&ts); | |
1488 | 1491 | done: |
1489 | DESTROY(rrtypes); | |
1492 | for (int i = 0; i < nrrtypeset; i++) | |
1493 | DESTROY(rrtypeset[i]); | |
1490 | 1494 | DESTROY(rrtypeset); |
1491 | 1495 | return ret; |
1492 | 1496 | } |
1495 | 1499 | */ |
1496 | 1500 | static void |
1497 | 1501 | launch_fetch(query_t query, const char *path, pdns_fence_ct fp) { |
1498 | qparam_ct qpp = &query->params; | |
1499 | char *url; | |
1500 | ||
1501 | url = psys->url(path, NULL, qpp, fp, false); | |
1502 | char *url = psys->url(path, NULL, &query->params, fp, false); | |
1502 | 1503 | if (url == NULL) |
1503 | 1504 | my_exit(1); |
1504 | 1505 |
638 | 638 | If "iso" (the default) then ISO8601 (RFC3339) format is used, for |
639 | 639 | example; "2018-09-06T22:48:00Z". If "csv" then an Excel CSV |
640 | 640 | compatible format is used; for example, "2018-09-06 22:48:00". |
641 | .It Ev HTTPS_PROXY | |
642 | contains the URL of the HTTPS proxy that you wish to use. See | |
643 | .Ic "https://curl.se/libcurl/c/CURLOPT_PROXY.html" | |
644 | for information on its values. | |
641 | 645 | .El |
642 | 646 | .Sh "EXIT STATUS" |
643 | 647 | Success (exit status zero) occurs if a connection could be established |
33 | 33 | #endif |
34 | 34 | |
35 | 35 | EXTERN const char id_swclient[] INIT("dnsdbq"); |
36 | EXTERN const char id_version[] INIT("2.6.0"); | |
36 | EXTERN const char id_version[] INIT("2.6.3"); | |
37 | 37 | EXTERN const char *program_name INIT(NULL); |
38 | 38 | EXTERN const char path_sort[] INIT("/usr/bin/sort"); |
39 | 39 | EXTERN const char json_header[] INIT("Accept: application/json"); |
80 | 80 | } |
81 | 81 | } |
82 | 82 | |
83 | /* fetch -- given a url, tell libcurl to go fetch it. | |
83 | /* fetch -- given a url, tell libcurl to go fetch it, attach fetch to query. | |
84 | 84 | */ |
85 | 85 | fetch_t |
86 | 86 | create_fetch(query_t query, char *url) { |
158 | 158 | curl_slist_free_all(fetch->hdrs); |
159 | 159 | fetch->hdrs = NULL; |
160 | 160 | } |
161 | DESTROY(fetch->saf_msg); | |
161 | 162 | DESTROY(fetch->url); |
162 | 163 | DESTROY(fetch->buf); |
163 | 164 | DESTROY(fetch); |
28 | 28 | #include "ns_ttl.h" |
29 | 29 | #include "pdns.h" |
30 | 30 | #include "time.h" |
31 | #include "tokstr.h" | |
31 | 32 | #include "globals.h" |
32 | 33 | |
33 | 34 | static void present_text_line(const char *, const char *, const char *); |
127 | 128 | */ |
128 | 129 | static void |
129 | 130 | present_text_line(const char *rrname, const char *rrtype, const char *rdata) { |
130 | char *asnum = NULL, *cidr = NULL, *comment = NULL; | |
131 | const char *result = NULL; | |
131 | char *asnum = NULL, *cidr = NULL, *comment = NULL, *result = NULL; | |
132 | 132 | |
133 | 133 | #ifndef CRIPPLED_LIBC |
134 | 134 | result = asinfo_from_rr(rrtype, rdata, &asnum, &cidr); |
135 | 135 | #endif |
136 | 136 | if (result != NULL) { |
137 | comment = strdup(result); | |
137 | comment = result; | |
138 | result = NULL; | |
138 | 139 | } else if (asnum != NULL && cidr != NULL) { |
139 | 140 | const char *src = asnum; |
140 | 141 | bool wordbreak = true; |
368 | 369 | #ifndef CRIPPLED_LIBC |
369 | 370 | static json_t * |
370 | 371 | annotate_asinfo(const char *rrtype, const char *rdata) { |
371 | char *asnum = NULL, *cidr = NULL; | |
372 | char *asnum = NULL, *cidr = NULL, *result = NULL; | |
372 | 373 | json_t *asinfo = NULL; |
373 | const char *result; | |
374 | 374 | |
375 | 375 | if ((result = asinfo_from_rr(rrtype, rdata, &asnum, &cidr)) != NULL) { |
376 | 376 | asinfo = json_object(); |
377 | 377 | json_object_set_new_nocheck(asinfo, "comment", |
378 | 378 | json_string(result)); |
379 | free(result); | |
379 | 380 | } else if (asnum != NULL && cidr != NULL) { |
380 | 381 | json_t *array = json_array(); |
381 | char *copy, *walker, *token; | |
382 | ||
383 | copy = walker = strdup(asnum); | |
384 | while ((token = strsep(&walker, " ")) != NULL) | |
385 | json_array_append(array, json_integer(atol(token))); | |
386 | free(copy); | |
382 | struct tokstr *ts = tokstr_string(asnum); | |
383 | for (char *t; (t = tokstr_next(ts, "\040")) != NULL; free(t)) | |
384 | json_array_append_new(array, json_integer(atol(t))); | |
385 | tokstr_last(&ts); | |
387 | 386 | asinfo = json_object(); |
388 | 387 | json_object_set_new_nocheck(asinfo, "as", array); |
389 | 388 | json_object_set_new_nocheck(asinfo, "cidr", json_string(cidr)); |
390 | free(asnum); | |
391 | free(cidr); | |
392 | } | |
389 | } | |
390 | DESTROY(asnum); | |
391 | DESTROY(cidr); | |
393 | 392 | return asinfo; |
394 | 393 | } |
395 | 394 | #endif |
466 | 465 | printf("\"%s\"", rdata); |
467 | 466 | if (asinfo_lookup && tup->obj.rrtype != NULL && |
468 | 467 | tup->obj.rdata != NULL) { |
469 | char *asnum = NULL, *cidr = NULL; | |
470 | const char *result = NULL; | |
468 | char *asnum = NULL, *cidr = NULL, *result = NULL; | |
471 | 469 | |
472 | 470 | #ifndef CRIPPLED_LIBC |
473 | 471 | result = asinfo_from_rr(tup->rrtype, rdata, &asnum, &cidr); |
474 | 472 | #endif |
475 | 473 | if (result != NULL) { |
476 | 474 | asnum = strdup(result); |
477 | cidr = strdup(result); | |
475 | cidr = result; | |
476 | result = NULL; | |
478 | 477 | } |
479 | 478 | putchar(','); |
480 | 479 | if (asnum != NULL) { |
267 | 267 | // ensure our result buffer is large enough. |
268 | 268 | size_t new_size = buf->size + c->nalnum; |
269 | 269 | if (new_size == 0) { |
270 | DESTROY(c); | |
270 | 271 | buf->base = realloc(buf->base, 1); |
271 | 272 | buf->base[0] = '.'; |
272 | 273 | buf->size = 1; |
0 | // tokstr -- textual token iterator with some input independence | |
1 | // 2022-01-29 [revised during code review, add regions] | |
2 | // 2022-01-25 [initially released inside dnsdbq] | |
3 | ||
4 | /* externals. */ | |
5 | ||
6 | #define _GNU_SOURCE | |
7 | ||
8 | #include <sys/types.h> | |
9 | #include <assert.h> | |
10 | #include <stdlib.h> | |
11 | #include <string.h> | |
12 | ||
13 | #include "tokstr.h" | |
14 | ||
15 | /* private data types. */ | |
16 | ||
17 | enum tokstr_type { ts_buffer, ts_string }; | |
18 | ||
19 | struct tokstr_class { | |
20 | enum tokstr_type type; | |
21 | }; | |
22 | ||
23 | struct tokstr_region { | |
24 | struct tokstr_class class; | |
25 | struct tokstr_reg source; | |
26 | }; | |
27 | ||
28 | struct tokstr_string { | |
29 | struct tokstr_class class; | |
30 | const char *source; | |
31 | }; | |
32 | ||
33 | struct tokstr_pvt { | |
34 | union { | |
35 | struct tokstr_class class; | |
36 | struct tokstr_region region; | |
37 | struct tokstr_string string; | |
38 | } data; | |
39 | }; | |
40 | ||
41 | /* forward. */ | |
42 | ||
43 | static struct tokstr_reg next_region(struct tokstr_region *, const char *); | |
44 | static struct tokstr_reg next_string(struct tokstr_string *, const char *); | |
45 | ||
46 | /* public. */ | |
47 | ||
48 | // tokstr_region -- create an iterator for a counted string | |
49 | struct tokstr * | |
50 | tokstr_region(struct tokstr_reg source) { | |
51 | struct tokstr_region *ts = malloc(sizeof(struct tokstr_region)); | |
52 | if (ts != NULL) { | |
53 | *ts = (struct tokstr_region) { | |
54 | .class = (struct tokstr_class) { | |
55 | .type = ts_buffer, | |
56 | }, | |
57 | .source = source, | |
58 | }; | |
59 | } | |
60 | return (struct tokstr *) ts; | |
61 | } | |
62 | ||
63 | // tokstr_string -- create an iterator for a nul-terminated string | |
64 | struct tokstr * | |
65 | tokstr_string(const char *source) { | |
66 | struct tokstr_string *ts = malloc(sizeof(struct tokstr_string)); | |
67 | if (ts != NULL) { | |
68 | *ts = (struct tokstr_string) { | |
69 | .class = (struct tokstr_class) { | |
70 | .type = ts_string, | |
71 | }, | |
72 | .source = source, | |
73 | }; | |
74 | } | |
75 | return (struct tokstr *) ts; | |
76 | } | |
77 | ||
78 | // tokstr_next -- return next token from an iterator (which must be free()'d) | |
79 | // (NULL means no more tokens are available.) | |
80 | char * | |
81 | tokstr_next(struct tokstr *ts_pub, const char *delims) { | |
82 | struct tokstr_reg reg = tokstr_next_region(ts_pub, delims); | |
83 | if (reg.base == NULL) | |
84 | return NULL; | |
85 | return strndup(reg.base, reg.size); | |
86 | } | |
87 | ||
88 | // tokstr_next_copy -- copy next token from an iterator; return size, 0, or -1 | |
89 | // (0 means no more tokens are available.) | |
90 | ssize_t | |
91 | tokstr_next_copy(struct tokstr *ts, const char *delims, | |
92 | char *buffer, size_t size) | |
93 | { | |
94 | struct tokstr_reg reg = tokstr_next_region(ts, delims); | |
95 | if (reg.base == NULL) | |
96 | return 0; | |
97 | if (reg.size >= size) | |
98 | return -1; | |
99 | memcpy(buffer, reg.base, reg.size); | |
100 | buffer[reg.size] = '\0'; | |
101 | return (ssize_t) reg.size; | |
102 | } | |
103 | ||
104 | // tokstr_next_region -- return next token from an iterator (zero-copy) | |
105 | // (.base == NULL means no more tokens are available.) | |
106 | struct tokstr_reg | |
107 | tokstr_next_region(struct tokstr *ts_pub, const char *delims) { | |
108 | struct tokstr_pvt *ts = (struct tokstr_pvt *) ts_pub; | |
109 | struct tokstr_reg reg = {}; | |
110 | switch (ts->data.class.type) { | |
111 | case ts_buffer: | |
112 | reg = next_region(&ts->data.region, delims); | |
113 | break; | |
114 | case ts_string: | |
115 | reg = next_string(&ts->data.string, delims); | |
116 | break; | |
117 | default: | |
118 | abort(); | |
119 | } | |
120 | assert((reg.base == NULL) == (reg.size == 0)); | |
121 | return reg; | |
122 | } | |
123 | ||
124 | // tokstr_last -- destroy an iterator and release all of its internal resources | |
125 | void | |
126 | tokstr_last(struct tokstr **pts) { | |
127 | free(*pts); | |
128 | *pts = NULL; | |
129 | } | |
130 | ||
131 | /* private functions. */ | |
132 | ||
133 | // next_buffer -- implement tokstr_next for counted string iterators | |
134 | static struct tokstr_reg | |
135 | next_region(struct tokstr_region *reg, const char *delims) { | |
136 | if (reg->source.size != 0) { | |
137 | while (reg->source.size != 0 && | |
138 | strchr(delims, *reg->source.base) != 0) | |
139 | reg->source.size--, reg->source.base++; | |
140 | const char *prev = reg->source.base; | |
141 | while (reg->source.size != 0 && | |
142 | strchr(delims, *reg->source.base) == 0) | |
143 | reg->source.size--, reg->source.base++; | |
144 | size_t size = (size_t) (reg->source.base - prev); | |
145 | if (size != 0) | |
146 | return (struct tokstr_reg) {prev, size}; | |
147 | } | |
148 | return (struct tokstr_reg) {}; | |
149 | } | |
150 | ||
151 | // next_string -- implement tokstr_next for nul-terminated string iterators | |
152 | static struct tokstr_reg | |
153 | next_string(struct tokstr_string *str, const char *delims) { | |
154 | int ch = *str->source; | |
155 | if (ch != '\0') { | |
156 | while (ch != '\0' && strchr(delims, ch) != NULL) | |
157 | ch = *++str->source; | |
158 | const char *prev = str->source; | |
159 | while (ch != '\0' && strchr(delims, ch) == NULL) | |
160 | ch = *++str->source; | |
161 | size_t size = (size_t) (str->source - prev); | |
162 | if (size != 0) | |
163 | return (struct tokstr_reg) {prev, size}; | |
164 | } | |
165 | return (struct tokstr_reg) {}; | |
166 | } |
0 | #ifndef __TOKSTR_H | |
1 | #define __TOKSTR_H | |
2 | ||
3 | // tokstr -- textual token iterator with some input independence | |
4 | // 2022-01-29 [revised during code review, add regions] | |
5 | // 2022-01-25 [initially released inside dnsdbq] | |
6 | ||
7 | /* example using heap-allocated strings: | |
8 | ||
9 | struct tokstr *ts = tokstr_string("this:is+-test"); | |
10 | for (char *t; (t = tokstr_next(ts, "-:+")) != NULL; free(t)) | |
11 | printf("\t\"%s\"\n", t); | |
12 | tokstr_last(&ts); | |
13 | ||
14 | * will output "this", "is", and "test". so will this: | |
15 | ||
16 | struct tokstr *ts = tokstr_string("this:is+-test"); | |
17 | for (char t[100]; tokstr_next_copy(ts, "-:+", t, sizeof t) > 0;) | |
18 | printf("\t\"%s\"\n", t); | |
19 | tokstr_last(&ts); | |
20 | ||
21 | * as will this: | |
22 | ||
23 | struct tokstr *ts = tokstr_string("this:is+-test"); | |
24 | for (;;) { | |
25 | struct tokstr_reg t = tokstr_next_region(ts, "-:+"); | |
26 | if (t.base == NULL) | |
27 | break; | |
28 | printf("\t\"%*s\"\n", t.size, t.base); | |
29 | } | |
30 | tokstr_last(&ts); | |
31 | ||
32 | */ | |
33 | ||
34 | // opaque type for iterator state -- never used | |
35 | struct tokstr; | |
36 | ||
37 | struct tokstr_reg { | |
38 | const char *base; | |
39 | size_t size; | |
40 | }; | |
41 | ||
42 | // tokstr_region -- create an iterator for a counted string | |
43 | struct tokstr *tokstr_region(struct tokstr_reg); | |
44 | ||
45 | // tokstr_string -- create an iterator for a nul-terminated string | |
46 | struct tokstr *tokstr_string(const char *); | |
47 | ||
48 | // tokstr_string -- create an iterator for a nul-terminated string | |
49 | struct tokstr *tokstr_string(const char *); | |
50 | ||
51 | // tokstr_next -- return next token from an iterator (which must be free()'d) | |
52 | // (NULL means no more tokens are available.) | |
53 | char *tokstr_next(struct tokstr *, const char *); | |
54 | ||
55 | // tokstr_next_copy -- copy next token from an iterator; return size, 0, or -1 | |
56 | // (0 means no more tokens are available.) | |
57 | ssize_t tokstr_next_copy(struct tokstr *, const char *, char *, size_t); | |
58 | ||
59 | // tokstr_next_region -- return next token from iterator (zero-copy) | |
60 | // (.base == NULL means no more tokens are available.) | |
61 | // NOTE WELL: if program state becomes undefined here, can assert() or abort() | |
62 | struct tokstr_reg tokstr_next_region(struct tokstr *, const char *); | |
63 | ||
64 | // tokstr_last -- destroy an iterator and release all of its internal resources | |
65 | void tokstr_last(struct tokstr **); | |
66 | ||
67 | #endif /*__TOKSTR_H*/ |