Codebase list dnsdbq / ec51842
New upstream version 2.6.3 Sascha Steinbiss 1 year, 8 months ago
13 changed file(s) with 398 addition(s) and 133 deletion(s). Raw diff Collapse all Expand all
1313 # limitations under the License.
1414 #
1515
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
1820
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`
1928 CURLLIBS = `[ ! -z "$$(curl-config --libs)" ] && curl-config --libs || curl-config --static-libs`
20 JANSLIBS = -L/usr/local/lib -ljansson
2129
2230 CWARN =-W -Wall -Wextra -Wcast-qual -Wpointer-arith -Wwrite-strings \
2331 -Wmissing-prototypes -Wbad-function-cast -Wnested-externs \
3240 CDEBUG = -g -O3
3341 CFLAGS += $(CGPROF) $(CDEBUG) $(CWARN) $(CDEFS)
3442 INCL= $(CURLINCL) $(JANSINCL)
35 # freebsd requires that -lresolv _not_ be used here
3643 LIBS= $(CURLLIBS) $(JANSLIBS) -lresolv
44 # For freebsd, it requires that -lresolv _not_ be used here, use this instead of the above line:
3745 #LIBS= $(CURLLIBS) $(JANSLIBS)
3846
3947 TOOL = dnsdbq
4048 TOOL_OBJ = $(TOOL).o ns_ttl.o netio.o \
4149 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
4352 TOOL_SRC = $(TOOL).c ns_ttl.c netio.c \
4453 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
4656
4757 all: $(TOOL)
4858
7686 asinfo.h globals.h defs.h sort.h pdns.h netio.h
7787 dnsdbq.o: dnsdbq.c \
7888 defs.h netio.h \
79 pdns.h \
89 pdns.h tokstr.h \
8090 pdns_dnsdb.h pdns_circl.h sort.h \
8191 time.h globals.h
8292 ns_ttl.o: ns_ttl.c \
90100 netio.h \
91101 pdns.h \
92102 time.h \
93 globals.h sort.h
103 globals.h sort.h tokstr.h
94104 pdns_circl.o: pdns_circl.c \
95105 defs.h \
96106 pdns.h \
110120 globals.h sort.h pdns.h \
111121 netio.h \
112122 ns_ttl.h
123 tokstr.o: tokstr.c \
124 tokstr.h
107107 On FreeBSD, you may need to remove -lresolv in the LIBS line of
108108 the Makefile.
109109
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
110115 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
112117 rebuild dnsdbq with a static jansson library. That binary could
113118 then be deployed on any identical macOS version and architecture.
114119
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
117122 2. Change the Makefile's line
118 JANSLIBS = -L/usr/local/lib -ljansson
123 JANSLIBS = -L$(JANSBASE)/lib -ljansson
119124 to instead specify the static library location, probably to:
120 JANSLIBS = /usr/local/lib/libjansson.a
125 JANSLIBS = $(JANSBASE)/lib/libjansson.a
121126 3. Then run make
122127
123128
4444
4545 /* forward. */
4646
47 static const char *asinfo_from_ipv4(const char *, char **, char **);
47 static char *asinfo_from_ipv4(const char *, char **, char **);
4848 #ifdef asinfo_ipv6
4949 static const char *asinfo_from_ipv6(const char *, char **, char **);
5050 #endif
51 static const char *asinfo_from_dns(const char *, char **, char **);
51 static char *asinfo_from_dns(const char *, char **, char **);
5252 static const char *keep_best(char **, char **, char *, char *);
5353
5454 /* public. */
5555
5656 /* asinfo_from_rr(rrtype, rdata, asnum, cidr) -- find ASINFO for A/AAAA string
5757 *
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 *
6363 asinfo_from_rr(const char *rrtype, const char *rdata,
6464 char **asnum, char **cidr)
6565 {
9898
9999 /* asinfo_from_ipv4(addr, asnum, cidr) -- prepare and use ASINFO IPv4 name
100100 *
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 *
106106 asinfo_from_ipv4(const char *addr, char **asnum, char **cidr) {
107107 u_char a4[32/8];
108108 char *dname;
109109
110110 if (inet_pton(AF_INET, addr, a4) < 0)
111 return strerror(errno);
111 return strdup(strerror(errno));
112112 int n = asprintf(&dname, "%d.%d.%d.%d.%s",
113113 a4[3], a4[2], a4[1], a4[0], asinfo_domain);
114114 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);
117117 free(dname);
118118 return result;
119119 }
121121 #ifdef asinfo_ipv6
122122 /* asinfo_from_ipv6(addr, asnum, cidr) -- prepare and use ASINFO IPv6 name
123123 *
124 * return NULL on success, or else, reason (string) for failure.
124 * return NULL on success, or else, reason (malloc'd string) for failure.
125125 *
126126 * side effect: on success, *asnum and *cidr will be heap-allocated strings.
127127 *
128128 * NOTE WELL: this is a placeholder, since no ASINFO source has working IPv6.
129129 */
130 static const char *
130 static char *
131131 asinfo_from_ipv6(const char *addr, char **asnum, char **cidr) {
132 char *result, *dname, *p;
132133 u_char a6[128/8];
133 const char *result;
134 char *dname, *p;
135134 int i;
136135
137136 if (inet_pton(AF_INET6, addr, &a6) < 0)
138 return strerror(errno);
137 return strdup(strerror(errno));
139138 dname = malloc(strlen(asinfo_domain) + (128/4)*2);
140139 if (dname == NULL)
141 return strerror(errno);
140 return strdup(strerror(errno));
142141 result = NULL;
143142 p = dname;
144143 for (i = (128/8) - 1; i >= 0; i--) {
145144 int n = sprintf(p, "%x.%x.", a6[i] & 0xf, a6[i] >> 4);
146145 if (n < 0) {
147 result = strerror(errno);
146 result = strdup(strerror(errno));
148147 break;
149148 }
150149 p += n;
161160
162161 /* asinfo_from_dns(dname, asnum, cidr) -- retrieve and parse a ASINFO DNS TXT
163162 *
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 *
169168 asinfo_from_dns(const char *dname, char **asnum, char **cidr) {
170169 u_char buf[NS_PACKETSZ];
171170 int n, an, rrn, rcode;
172 const char *result;
171 char *result;
173172 ns_msg msg;
174173 ns_rr rr;
175174
184183 if (res.res_h_errno == HOST_NOT_FOUND)
185184 return NULL;
186185 else
187 return hstrerror(res.res_h_errno);
186 return strdup(hstrerror(res.res_h_errno));
188187 }
189188 if (ns_initparse(buf, n, &msg) < 0)
190 return strerror(errno);
189 return strdup(strerror(errno));
191190 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 }
194196 an = ns_msg_count(msg, ns_s_an);
195197 if (an == 0)
196 return "ANCOUNT == 0";
198 return strdup("ANCOUNT == 0");
197199 /* some ASINFO data sources return multiple TXT RR's, each having
198200 * a prefix length measured in bits. we will select the best
199201 * (longest match) prefix offered.
204206 char *txt[3];
205207
206208 if (ns_parserr(&msg, ns_s_an, rrn, &rr) < 0) {
207 result = strerror(errno);
209 result = strdup(strerror(errno));
208210 break;
209211 }
210212 rdata = ns_rr_rdata(rr);
215217 * more than three TXT segments (<character-strings>).
216218 */
217219 if (ntxt == 3) {
218 result = "len(TXT[]) > 3";
220 result = strdup("len(TXT[]) > 3");
219221 break;
220222 }
221223 n = *rdata++;
222224 rdlen--;
223225 if (n > rdlen) {
224 result = "TXT overrun";
226 result = strdup("TXT overrun");
225227 break;
226228 }
227229 txt[ntxt] = strndup((const char *)rdata, (size_t)n);
228230 if (txt[ntxt] == NULL) {
229 result = "strndup FAIL";
231 result = strdup("strndup FAIL");
230232 break;
231233 }
232234 DEBUG(2, true, "TXT[%d] \"%s\"\n", ntxt, txt[ntxt]);
257259 new_cidr = strndup(t1 + seplen, (size_t)
258260 (t2 - (t1 + seplen)));
259261 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);
262267 } else if (ntxt == 3) {
263268 /* routeviews.org format:
264269 *
273278 txt[1], txt[2]) >= 0)
274279 {
275280 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);
279286 } else {
280 result = strerror(errno);
287 result = strdup(strerror(errno));
281288 }
282289 } else {
283 result = "unrecognized asinfo TXT format";
290 result = strdup("unrecognized TXT format");
284291 }
285292 }
286293 for (n = 0; n < ntxt; n++) {
1919 #include <stdbool.h>
2020
2121 #ifndef CRIPPLED_LIBC
22 const char *
22 char *
2323 asinfo_from_rr(const char *rrtype, const char *rdata, char **asn, char **cidr);
2424 #endif
2525
8686 deduper_dump(deduper_t me, FILE *out) {
8787 for (size_t bucket = 0; bucket < me->buckets; bucket++)
8888 if (me->chains[bucket] != NULL) {
89 fprintf(out, "[%lu]", bucket);
89 fprintf(out, "[%zu]", bucket);
9090 for (chainlink_t chainlink = me->chains[bucket];
9191 chainlink != NULL;
9292 chainlink = chainlink->next)
5151 #include "pdns.h"
5252 #include "sort.h"
5353 #include "time.h"
54 #include "tokstr.h"
5455 #include "globals.h"
5556 #undef MAIN_PROGRAM
5657
355356 if (sorting == no_sort)
356357 usage("-k must be preceded by -s or -S");
357358
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))
363363 {
364364 if (find_sort_key(tok) != NULL)
365365 usage("Each sort key may only be "
368368 if ((msg = add_sort_key(tok)) != NULL)
369369 usage(msg);
370370 }
371 tokstr_last(&ts);
371372 break;
372373 }
373374 case 'J':
401402 }
402403 break;
403404 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 {
407410 if (strcasecmp(token, "reverse") == 0)
408411 transforms |= TRANS_REVERSE;
409412 else if (strcasecmp(token, "datefix") == 0)
411414 else if (strcasecmp(token, "chomp") == 0)
412415 transforms |= TRANS_CHOMP;
413416 else {
414 DESTROY(copy);
415417 usage("unrecognized transform in -T");
416418 }
417 DESTROY(copy);
419 }
420 tokstr_last(&ts);
418421 break;
419422 }
420423 case 'm':
11161119 char **opt = optv;
11171120 const char *msg;
11181121 int optc, ch;
1119 char *tok;
1120
1121 char *temp = strdup(optstr);
1122 char *saveptr = NULL;
1122
11231123 /* 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))
11271128 {
11281129 /* dispense with extra spaces and tabs (empty fields). */
11291130 if (*tok == '\0')
11301131 continue;
11311132 *opt++ = tok;
11321133 }
1134 tokstr_last(&ts);
11331135
11341136 /* if no options were specified (e.g., $options\n), restore defaults.
11351137 */
11741176 }
11751177 /* done. */
11761178 DESTROY(optv);
1177 DESTROY(temp);
11781179 return msg;
11791180 }
11801181
13621363
13631364 /* ready player one. */
13641365 CREATE(query, sizeof(struct query));
1366 query->descrip = makepath(qdp);
1367 query->mode = qdp->mode;
1368 query->params = *qpp;
1369 qpp = NULL;
13651370
13661371 /* define the fence. */
1367 if (qpp->after != 0) {
1368 if (qpp->complete) {
1372 if (query->params.after != 0) {
1373 if (query->params.complete) {
13691374 /* each db tuple must begin after the fence-start. */
1370 fence.first_after = qpp->after;
1375 fence.first_after = query->params.after;
13711376 } else {
13721377 /* 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) {
13781383 /* each db tuple must end before the fence-end. */
1379 fence.last_before = qpp->before;
1384 fence.last_before = query->params.before;
13801385 } else {
13811386 /* 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. */
13871392 if (qdp->rrtype == NULL) {
13881393 /* no rrtype string given, let makepath set it to "any". */
13891394 char *path = makepath(qdp);
13961401 return NULL;
13971402 } else {
13981403 /* rrtype string was given, parse comma separated list. */
1399 char *rrtypes = strdup(qdp->rrtype);
1400 char *saveptr = NULL;
14011404 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))
14051409 {
14061410 struct qdesc qd = {
14071411 .mode = qdp->mode,
14151419 nfetches++;
14161420 DESTROY(path);
14171421 }
1422 tokstr_last(&ts);
14181423 if (nfetches > 1)
14191424 query->multitype = true;
1420 DESTROY(rrtypes);
14211425 }
14221426
14231427 /* finish query initialization, link it up, and return it. */
14241428 query->writer = writer;
14251429 writer = NULL;
1426 query->params = *qpp;
14271430 query->next = query->writer->queries;
14281431 query->writer->queries = query;
1429 query->descrip = makepath(qdp);
1430 query->mode = qdp->mode;
14311432 return query;
14321433 }
14331434
14361437 static const char *
14371438 rrtype_correctness(const char *input) {
14381439 char **rrtypeset = calloc(MAX_FETCHES, sizeof(char *));
1439 char *rrtypes = strdup(input);
1440 char *saveptr = NULL;
14411440 const char *ret = NULL;
14421441 int nrrtypeset = 0;
14431442 bool some = false, any = false,
14441443 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))
14481448 {
14491449 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);
14521452 if (nrrtypeset == MAX_FETCHES) {
14531453 ret = "too many rrtypes specified";
14541454 goto done;
14581458 ret = "duplicate rrtype encountered";
14591459 goto done;
14601460 }
1461 rrtypeset[nrrtypeset++] = rrtype;
1461 rrtypeset[nrrtypeset++] = strdup(rrtype);
14621462 if (strcmp(rrtype, "any") == 0)
14631463 any = true;
14641464 else if (strcmp(rrtype, "any-dnssec") == 0)
14731473 strcmp(rrtype, "nsec3") == 0 ||
14741474 strcmp(rrtype, "nsec3param") == 0 ||
14751475 strcmp(rrtype, "dlv") == 0)
1476 {
14761477 some_dnssec = true;
1477 else
1478 } else {
14781479 some = true;
1480 }
14791481 if (any && some) {
14801482 ret = "ANY is redundant when mixed like this";
14811483 goto done;
14851487 goto done;
14861488 }
14871489 }
1490 tokstr_last(&ts);
14881491 done:
1489 DESTROY(rrtypes);
1492 for (int i = 0; i < nrrtypeset; i++)
1493 DESTROY(rrtypeset[i]);
14901494 DESTROY(rrtypeset);
14911495 return ret;
14921496 }
14951499 */
14961500 static void
14971501 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);
15021503 if (url == NULL)
15031504 my_exit(1);
15041505
638638 If "iso" (the default) then ISO8601 (RFC3339) format is used, for
639639 example; "2018-09-06T22:48:00Z". If "csv" then an Excel CSV
640640 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.
641645 .El
642646 .Sh "EXIT STATUS"
643647 Success (exit status zero) occurs if a connection could be established
3333 #endif
3434
3535 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");
3737 EXTERN const char *program_name INIT(NULL);
3838 EXTERN const char path_sort[] INIT("/usr/bin/sort");
3939 EXTERN const char json_header[] INIT("Accept: application/json");
8080 }
8181 }
8282
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.
8484 */
8585 fetch_t
8686 create_fetch(query_t query, char *url) {
158158 curl_slist_free_all(fetch->hdrs);
159159 fetch->hdrs = NULL;
160160 }
161 DESTROY(fetch->saf_msg);
161162 DESTROY(fetch->url);
162163 DESTROY(fetch->buf);
163164 DESTROY(fetch);
2828 #include "ns_ttl.h"
2929 #include "pdns.h"
3030 #include "time.h"
31 #include "tokstr.h"
3132 #include "globals.h"
3233
3334 static void present_text_line(const char *, const char *, const char *);
127128 */
128129 static void
129130 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;
132132
133133 #ifndef CRIPPLED_LIBC
134134 result = asinfo_from_rr(rrtype, rdata, &asnum, &cidr);
135135 #endif
136136 if (result != NULL) {
137 comment = strdup(result);
137 comment = result;
138 result = NULL;
138139 } else if (asnum != NULL && cidr != NULL) {
139140 const char *src = asnum;
140141 bool wordbreak = true;
368369 #ifndef CRIPPLED_LIBC
369370 static json_t *
370371 annotate_asinfo(const char *rrtype, const char *rdata) {
371 char *asnum = NULL, *cidr = NULL;
372 char *asnum = NULL, *cidr = NULL, *result = NULL;
372373 json_t *asinfo = NULL;
373 const char *result;
374374
375375 if ((result = asinfo_from_rr(rrtype, rdata, &asnum, &cidr)) != NULL) {
376376 asinfo = json_object();
377377 json_object_set_new_nocheck(asinfo, "comment",
378378 json_string(result));
379 free(result);
379380 } else if (asnum != NULL && cidr != NULL) {
380381 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);
387386 asinfo = json_object();
388387 json_object_set_new_nocheck(asinfo, "as", array);
389388 json_object_set_new_nocheck(asinfo, "cidr", json_string(cidr));
390 free(asnum);
391 free(cidr);
392 }
389 }
390 DESTROY(asnum);
391 DESTROY(cidr);
393392 return asinfo;
394393 }
395394 #endif
466465 printf("\"%s\"", rdata);
467466 if (asinfo_lookup && tup->obj.rrtype != NULL &&
468467 tup->obj.rdata != NULL) {
469 char *asnum = NULL, *cidr = NULL;
470 const char *result = NULL;
468 char *asnum = NULL, *cidr = NULL, *result = NULL;
471469
472470 #ifndef CRIPPLED_LIBC
473471 result = asinfo_from_rr(tup->rrtype, rdata, &asnum, &cidr);
474472 #endif
475473 if (result != NULL) {
476474 asnum = strdup(result);
477 cidr = strdup(result);
475 cidr = result;
476 result = NULL;
478477 }
479478 putchar(',');
480479 if (asnum != NULL) {
267267 // ensure our result buffer is large enough.
268268 size_t new_size = buf->size + c->nalnum;
269269 if (new_size == 0) {
270 DESTROY(c);
270271 buf->base = realloc(buf->base, 1);
271272 buf->base[0] = '.';
272273 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*/