Commit Diff
Diff:
c8c673949bbafeee704dca5557697e9460781a66
50dcdb6776aa3704baf648a20de5b7b9203b6163
Commit:
50dcdb6776aa3704baf648a20de5b7b9203b6163
Tree:
4f952ce9b21eaebef753a45f4d9caad95c364fe3
Author:
pjp <pjp@delphinusdns.org>
Committer:
pjp <pjp@delphinusdns.org>
Date:
Thu Feb 7 11:16:03 2019 UTC
Message:
move quite a few things around, in order to give dddctl a query mode like dig. it's in the early stages and probably bug prone. Here is a sample: beta# dddctl query centroid.eu ; received 132 bytes ;; ANSWER SECTION: centroid.eu.,a,80610,116.202.31.129 ;; AUTHORITY SECTION: centroid.eu.,ns,47921,tau.virgostar.net. centroid.eu.,ns,47921,omega.virgostar.net. ;; ADDITIONAL SECTION: ;; QUERY TIME: 2 ms ;; SERVER: 127.0.0.1#53 ;; WHEN: Thu Feb 7 12:11:28 2019
blob - 76e007a56b3bf2017090433f4723275d78721b0c
blob + 748791aefe7985dd3415ad2e917318037582474f
--- ddd-db.h
+++ ddd-db.h
@@ -27,7 +27,7 @@
*/
/*
- * $Id: ddd-db.h,v 1.10 2019/01/29 16:32:54 pjp Exp $
+ * $Id: ddd-db.h,v 1.11 2019/02/07 11:16:03 pjp Exp $
*/
#ifndef _DB_H
@@ -492,6 +492,12 @@ struct node {
int len; /* length of domain name */
char *data; /* data it points to */
size_t datalen; /* the length of the data */
+};
+
+struct rrtab {
+ char *name;
+ u_int16_t type;
+ int16_t internal_type;
};
blob - d36c5f420328f3b6dabfe40f2cd7a7b49978ecbc
blob + e800249a0c43cf9f8b23d874115bc95116b6952f
--- dddctl.c
+++ dddctl.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: dddctl.c,v 1.31 2019/02/06 18:59:30 pjp Exp $
+ * $Id: dddctl.c,v 1.32 2019/02/07 11:16:03 pjp Exp $
*/
#include "ddd-include.h"
@@ -125,6 +125,7 @@ int start(int argc, char *argv[]);
int restart(int argc, char *argv[]);
int stop(int argc, char *argv[]);
int signmain(int argc, char *argv[]);
+int dig(int argc, char *argv[]);
int configtest(int argc, char *argv[]);
int bindfile(int argc, char *argv[]);
int sshfp(int argc, char *argv[]);
@@ -133,6 +134,8 @@ uint32_t getkeypid(char *);
pid_t getdaemonpid(void);
void debug_bindump(const char *, int);
int command_socket(char *);
+int connect_server(char *, int);
+int lookup_name(FILE *, int, char *, u_int16_t, struct soa *, u_int32_t);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
@@ -155,6 +158,7 @@ struct _mycmdtab {
} mycmdtab[] = {
{ "bindfile", bindfile },
{ "configtest", configtest },
+ { "query", dig },
{ "help", usage },
{ "sign", signmain },
{ "sshfp", sshfp },
@@ -164,6 +168,7 @@ struct _mycmdtab {
{ NULL, NULL }
};
+
#define KEYTYPE_NONE 0
#define KEYTYPE_KSK 1
#define KEYTYPE_ZSK 2
@@ -199,6 +204,14 @@ struct _mycmdtab {
#define MASK_DUMP_DB 0x40
#define MASK_DUMP_BIND 0x80
+/* dig stuff */
+
+#define BIND_FORMAT 0x1
+#define INDENT_FORMAT 0x2
+#define ZONE_FORMAT 0x4
+#define DNSSEC_FORMAT 0x8
+
+
/* glue */
int insert_axfr(char *, char *);
int insert_region(char *, char *);
@@ -244,7 +257,28 @@ extern char * hash_name(char *, int, struct nsec3param
extern char * base32hex_encode(u_char *input, int len);
extern int init_entlist(ddDB *);
extern int check_ent(char *, int);
+extern struct question *build_question(char *, int, int);
+extern int free_question(struct question *);
+struct rrtab *rrlookup(char *);
+
+extern int raxfr_a(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t);
+extern int raxfr_aaaa(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t);
+extern int raxfr_cname(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t);
+extern int raxfr_ns(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t);
+extern int raxfr_ptr(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t);
+extern int raxfr_mx(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t);
+extern int raxfr_txt(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t);
+extern int raxfr_dnskey(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t);
+extern int raxfr_rrsig(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t);
+extern int raxfr_nsec3param(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t);
+extern int raxfr_nsec3(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t);
+extern int raxfr_ds(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t);
+extern int raxfr_sshfp(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t);
+extern u_int16_t raxfr_skip(FILE *, u_char *, u_char *);
+extern int raxfr_soa(FILE *, u_char *, u_char *, u_char *, struct soa *, int);
+extern int raxfr_peek(FILE *, u_char *, u_char *, u_char *, int *, int, u_int16_t *, int);
+
extern int dnssec;
extern int domaincmp(struct node *e1, struct node *e2);
@@ -252,6 +286,28 @@ RB_HEAD(domaintree, node) rbhead;
RB_GENERATE_STATIC(domaintree, node, rbentry, domaincmp)
+static struct raxfr_logic {
+ int rrtype;
+ int dnssec;
+ int (*raxfr)(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t);
+} supported[] = {
+ { DNS_TYPE_A, 0, raxfr_a },
+ { DNS_TYPE_NS, 0, raxfr_ns },
+ { DNS_TYPE_MX, 0, raxfr_mx },
+ { DNS_TYPE_PTR, 0, raxfr_ptr },
+ { DNS_TYPE_AAAA, 0, raxfr_aaaa },
+ { DNS_TYPE_CNAME, 0, raxfr_cname },
+ { DNS_TYPE_TXT, 0, raxfr_txt },
+ { DNS_TYPE_DNSKEY, 1, raxfr_dnskey },
+ { DNS_TYPE_RRSIG, 1, raxfr_rrsig },
+ { DNS_TYPE_NSEC3PARAM, 1, raxfr_nsec3param },
+ { DNS_TYPE_NSEC3, 1, raxfr_nsec3 },
+ { DNS_TYPE_DS, 1, raxfr_ds },
+ { DNS_TYPE_SSHFP, 0, raxfr_sshfp },
+ { 0, 0, NULL }
+};
+
+
int
main(int argc, char *argv[])
{
@@ -6779,12 +6835,26 @@ usage(int argc, char *argv[])
fprintf(stderr, "\t-t ttl\t\ttime-to-live for dnskey's\n");
fprintf(stderr, "\t-z ZSK\t\tuse provided ZSK zone-signing keyname\n");
return 0;
+ } else if (argc == 2 && strcmp(argv[1], "query") == 0) {
+ fprintf(stderr, "usage: dddctl query [-46BDFZ] [-@ server] [-P port] [-p file] name command\n");
+ fprintf(stderr, "\t-@ server\t\tUse server ip.\n");
+ fprintf(stderr, "\t-4\t\tUse IPv4 only.\n");
+ fprintf(stderr, "\t-6\t\tUse IPv6 only.\n");
+ fprintf(stderr, "\t-B\t\tOutput as a BIND file.\n");
+ fprintf(stderr, "\t-D\t\tUse DNSSEC (DO bit) lookup.\n");
+ fprintf(stderr, "\t-F\t\tOutput with formatting.\n");
+ fprintf(stderr, "\t-Z\t\tOutput as a zonefile.\n");
+ fprintf(stderr, "\t-P port\t\tUse specified port.\n");
+ fprintf(stderr, "\t-p file\t\tOutput to file.\n");
+
+ return 0;
} else if (argc == 2) {
retval = 1;
} else {
fprintf(stderr, "usage: command [arg ...]\n");
fprintf(stderr, "\tbindfile zonename zonefile\n");
fprintf(stderr, "\tconfigtest [configfile]\n");
+ fprintf(stderr, "\tquery [-46BDFZ] [-@ server] [-P port] [-p file] name command\n");
fprintf(stderr, "\thelp [command]\n");
fprintf(stderr, "\tsign [-KZ] [-a algorithm] [-B bits] [-e seconds]\n\t\t[-I iterations] [-i inputfile] [-k KSK] [-m mask] [-n zonename]\n\t\t[-o output] [-S pid] [-s salt] [-t ttl] [-z ZSK]\n");
fprintf(stderr, "\tsshfp hostname [-k keyfile] [-t ttl]\n");
@@ -6796,6 +6866,360 @@ usage(int argc, char *argv[])
return (retval);
}
+
+int
+dig(int argc, char *argv[])
+{
+ FILE *f = stdout;
+ struct soa mysoa;
+ struct stat sb;
+ struct rrtab *rt;
+ struct timeval tv, tv0;
+ char *outputfile = NULL;
+ char *domainname = NULL;
+ char *nameserver = "127.0.0.1";
+ int use_v4 = 0, use_v6 = 0;
+ u_int32_t format = 0;
+ u_int16_t port = 53;
+ int ch, so, ms;
+ int type = DNS_TYPE_A;
+ time_t now;
+
+ while ((ch = getopt(argc, argv, "@:46BDFP:Zp:")) != -1) {
+ switch (ch) {
+ case '@':
+ nameserver = optarg;
+ break;
+ case '4':
+ use_v4 = 1;
+ break;
+ case '6':
+ use_v6 = 1;
+ break;
+ case 'B':
+ format |= BIND_FORMAT;
+ break;
+ case 'D':
+ format |= DNSSEC_FORMAT;
+ break;
+ case 'F':
+ format |= INDENT_FORMAT;
+ break;
+ case 'P':
+ port = atoi(optarg);
+ break;
+ case 'Z':
+ format |= ZONE_FORMAT;
+ break;
+ case 'p':
+ outputfile = optarg;
+ break;
+ default:
+ usage(argc, argv);
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (outputfile) {
+ if (lstat(outputfile, &sb) != -1) {
+ fprintf(stderr, "%s exists, not clobbering\n", outputfile);
+ exit(1);
+ }
+
+ f = fopen(outputfile, "w");
+ if (f == NULL) {
+ perror("fopen");
+ exit(1);
+ }
+
+ }
+
+
+ if (argc < 1) {
+ fprintf(stderr, "lookup what?\n");
+ exit(1);
+ }
+
+ if ((rt = rrlookup(argv[0])) != NULL) {
+ domainname = argv[1];
+ type = rt->type;
+ } else {
+ if (strcmp(argv[0], "any") == 0) {
+ domainname = argv[1];
+ type = DNS_TYPE_ANY;
+ } else {
+ if (argc == 2) {
+ if ((rt = rrlookup(argv[1])) != NULL) {
+ domainname = argv[0];
+ type = rt->type;
+ } else {
+ if (strcmp(argv[1], "any") == 0) {
+ domainname = argv[0];
+ type = DNS_TYPE_ANY;
+ }
+ }
+ } else {
+ domainname = argv[0];
+ }
+ }
+ }
+
+ gettimeofday(&tv0, NULL);
+ now = time(NULL);
+
+ so = connect_server(nameserver, port);
+ if (so < 0) {
+ exit(1);
+ }
+
+
+ if (lookup_name(f, so, domainname, type, &mysoa, format) < 0) {
+ exit(1);
+ }
+
+ close(so);
+ gettimeofday(&tv, NULL);
+
+ ms = 0;
+
+ if (tv.tv_usec < tv0.tv_usec) {
+ tv.tv_sec--;
+ ms += (((tv.tv_usec + 1000000) - tv0.tv_usec) / 1000);
+ } else
+ ms += (((tv.tv_usec) - tv0.tv_usec) / 1000);
+
+ if (tv.tv_sec - tv0.tv_sec > 0)
+ ms += 1000 * (tv.tv_sec - tv0.tv_sec);
+
+ printf(";; QUERY TIME: %d ms\n", ms);
+ printf(";; SERVER: %s#%u\n", nameserver, port);
+ printf(";; WHEN: %s", ctime(&now));
+
+
+ return 0;
+}
+
+int
+connect_server(char *nameserver, int port)
+{
+ struct sockaddr_in sin;
+ int so;
+
+ so = socket(AF_INET, SOCK_DGRAM, 0);
+ if (so < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ sin.sin_addr.s_addr = inet_addr(nameserver);
+
+ if (connect(so, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ perror("connect");
+ return -1;
+ }
+
+ return (so);
+}
+
+
+
+int
+lookup_name(FILE *f, int so, char *zonename, u_int16_t myrrtype, struct soa *mysoa, u_int32_t format)
+{
+ int len, i, answers;
+ int numansw, numaddi;
+ int rrtype, soacount = 0;
+ u_int16_t rdlen;
+ char query[512];
+ char *reply;
+ struct raxfr_logic *sr;
+ struct question *q;
+ struct dns_optrr *optrr;
+ struct whole_header {
+ struct dns_header dh;
+ } *wh, *rwh;
+
+ u_char *p, *name;
+
+ u_char *end, *estart;
+ int totallen, zonelen, rrlen;
+ u_int16_t *class, *type;
+
+ memset(&query, 0, sizeof(query));
+
+ wh = (struct whole_header *)&query[0];
+
+ wh->dh.id = htons(arc4random() & 0xffff);
+ wh->dh.query = 0;
+ wh->dh.question = htons(1);
+ wh->dh.answer = 0;
+ wh->dh.nsrr = 0;
+ wh->dh.additional = htons(1);;
+
+ SET_DNS_QUERY(&wh->dh);
+ SET_DNS_RECURSION(&wh->dh);
+
+
+ HTONS(wh->dh.query);
+
+ totallen = sizeof(struct whole_header);
+
+ name = dns_label(zonename, &len);
+ if (name == NULL) {
+ return -1;
+ }
+
+ zonelen = len;
+
+ p = (char *)&wh[1];
+
+ memcpy(p, name, len);
+ totallen += len;
+
+ type = (u_int16_t *)&query[totallen];
+ *type = htons(myrrtype);
+ totallen += sizeof(u_int16_t);
+
+ class = (u_int16_t *)&query[totallen];
+ *class = htons(DNS_CLASS_IN);
+ totallen += sizeof(u_int16_t);
+
+ /* attach EDNS0 */
+
+ optrr = (struct dns_optrr *)&query[totallen];
+
+ optrr->name[0] = 0;
+ optrr->type = htons(DNS_TYPE_OPT);
+ optrr->class = htons(2048);
+ optrr->ttl = htonl(0); /* EDNS version 0 */
+ if (format & DNSSEC_FORMAT)
+ SET_DNS_ERCODE_DNSSECOK(optrr);
+ HTONL(optrr->ttl);
+ optrr->rdlen = 0;
+ optrr->rdata[0] = 0;
+
+ totallen += (sizeof(struct dns_optrr));
+
+ if (send(so, query, totallen, 0) < 0) {
+ return -1;
+ }
+
+ /* catch reply */
+ reply = calloc(1, 2048);
+ if (reply == NULL) {
+ perror("calloc");
+ return -1;
+ }
+
+ if ((len = recv(so, reply, 2048, 0)) < 0) {
+ return -1;
+ }
+
+ rwh = (struct whole_header *)&reply[0];
+ fprintf(stdout, "; received %d bytes\n", len);
+
+ end = &reply[len];
+
+ if (rwh->dh.id != wh->dh.id) {
+ fprintf(stderr, "DNS ID mismatch\n");
+ return -1;
+ }
+
+ if (!(htons(rwh->dh.query) & DNS_REPLY)) {
+ fprintf(stderr, "NOT a DNS reply\n");
+ return -1;
+ }
+
+ numansw = ntohs(rwh->dh.answer);
+ numaddi = ntohs(rwh->dh.nsrr);
+ answers = numansw + numaddi;
+
+ if (answers < 1) {
+ fprintf(stderr, "NO ANSWER provided\n");
+ return -1;
+ }
+
+
+ q = build_question((char *)&wh->dh, len, wh->dh.additional);
+ if (q == NULL) {
+ fprintf(stderr, "failed to build_question\n");
+ return -1;
+ }
+
+ if (memcmp(q->hdr->name, name, q->hdr->namelen) != 0) {
+ fprintf(stderr, "question name not for what we asked\n");
+ return -1;
+ }
+
+ if (q->hdr->qclass != *class || q->hdr->qtype != *type) {
+ fprintf(stderr, "wrong class or type\n");
+ return -1;
+ }
+
+ p = (u_char *)&rwh[1];
+
+ p += q->hdr->namelen;
+ p += sizeof(u_int16_t); /* type */
+ p += sizeof(u_int16_t); /* class */
+
+ /* end of question */
+
+ if (numansw)
+ printf(";; ANSWER SECTION:\n");
+
+ estart = (u_char *)&rwh->dh;
+
+ for (i = answers; i > 0; i--) {
+ if ((rrlen = raxfr_peek(f, p, estart, end, &rrtype, 0, &rdlen, 1)) < 0) {
+ fprintf(stderr, "not a SOA reply, or ERROR\n");
+ return -1;
+ }
+
+ p = (estart + rrlen);
+
+ if (rrtype == DNS_TYPE_SOA) {
+ if ((len = raxfr_soa(f, p, estart, end, mysoa, soacount)) < 0) {
+ fprintf(stderr, "raxxfr_soa failed\n");
+ return -1;
+ }
+ p = (estart + len);
+ soacount++;
+ } else {
+ for (sr = supported; sr->rrtype != 0; sr++) {
+ if (rrtype == sr->rrtype) {
+ if ((len = (*sr->raxfr)(f, p, estart, end, mysoa, rdlen)) < 0) {
+ fprintf(stderr, "error with rrtype %d\n", sr->rrtype);
+ return -1;
+ }
+ p = (estart + len);
+ break;
+ }
+ }
+
+ if (sr->rrtype == 0) {
+ fprintf(stderr, "unsupported RRTYPE\n");
+ return -1;
+ }
+ } /* rrtype == DNS_TYPE_SOA */
+
+ if (--numansw == 0)
+ printf(";; AUTHORITY SECTION:\n");
+ if (numansw <= 0)
+ if (numaddi-- == 0)
+ printf(";; ADDITIONAL SECTION:\n");
+
+ } /* for () */
+
+ return 0;
+}
+
+
int
start(int argc, char *argv[])
blob - 6a7d05e13ed56932b35ed426a3a72b4f2a61c33f
blob + 021ef0f1c5c03e12fe4d19723c71c085f8b063e5
--- delphinusdnsd.c
+++ delphinusdnsd.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: delphinusdnsd.c,v 1.48 2019/01/30 07:36:50 pjp Exp $
+ * $Id: delphinusdnsd.c,v 1.49 2019/02/07 11:16:03 pjp Exp $
*/
#include "ddd-include.h"
@@ -95,12 +95,12 @@ extern char *dns_label(char *, int *);
extern void slave_shutdown(void);
extern int get_record_size(ddDB *, char *, int);
extern void * find_substruct(struct domain *, u_int16_t);
+extern struct question *build_question(char *, int, int);
+extern int free_question(struct question *);
-struct question *build_question(char *, int, int);
struct question *convert_question(struct parsequestion *);
void build_reply(struct sreply *, int, char *, int, struct question *, struct sockaddr *, socklen_t, struct domain *, struct domain *, u_int8_t, int, int, struct recurses *, char *);
int compress_label(u_char *, u_int16_t, int);
-int free_question(struct question *);
struct domain * get_soa(ddDB *, struct question *);
int lookup_type(int);
void mainloop(struct cfg *, struct imsgbuf **);
@@ -1006,237 +1006,6 @@ main(int argc, char *argv[], char *environ[])
}
-/*
- * BUILD_QUESTION - fill the question structure with the DNS query.
- */
-
-struct question *
-build_question(char *buf, int len, int additional)
-{
- u_int i;
- u_int namelen = 0;
- u_int16_t *qtype, *qclass;
- u_int32_t ttl;
- int num_label;
-
- char *p, *end_name = NULL;
-
- struct dns_optrr *opt = NULL;
- struct question *q = NULL;
- struct dns_header *hdr = (struct dns_header *)buf;
-
- /* find the end of name */
- for (i = sizeof(struct dns_header); i < len; i++) {
- /* XXX */
- if (buf[i] == 0) {
- end_name = &buf[i];
- break;
- }
- }
-
- /*
- * implies i >= len , because end_name still points to NULL and not
- * &buf[i]
- */
-
- if (end_name == NULL) {
- dolog(LOG_INFO, "query name is not null terminated\n");
- return NULL;
- }
-
- /* parse the size of the name */
- for (i = sizeof(struct dns_header), num_label = 0; i < len && &buf[i] < end_name;) {
- u_int labellen;
-
- ++num_label;
-
- labellen = (u_int)buf[i];
-
- /*
- * do some checks on the label, if it's 0 or over 63 it's
- * illegal, also if it reaches beyond the entire name it's
- * also illegal.
- */
- if (labellen == 0) {
- dolog(LOG_INFO, "illegal label len (0)\n");
- return NULL;
- }
- if (labellen > DNS_MAXLABEL) {
- dolog(LOG_INFO, "illegal label len (> 63)\n");
- return NULL;
- }
- if (labellen > (end_name - &buf[i])) {
- dolog(LOG_INFO, "label len extends beyond name\n");
- return NULL;
- }
-
- i += (labellen + 1);
- namelen += labellen;
- }
-
- if (&buf[i] != end_name || i >= len) {
- dolog(LOG_INFO, "query name is maliciously malformed\n");
- return NULL;
- }
-
- if (i > DNS_MAXNAME) {
- dolog(LOG_INFO, "query name is too long (%u)\n", i);
- return NULL;
- }
-
-
- /* check if there is space for qtype and qclass */
- if (len < ((end_name - &buf[0]) + (2 * sizeof(u_int16_t)))) {
- dolog(LOG_INFO, "question rr is truncated\n");
- return NULL;
- }
-
-
- q = (void *)calloc(1, sizeof(struct question));
- if (q == NULL) {
- dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
- return NULL;
- }
- q->hdr = (void *)calloc(1, sizeof(struct dns_question_hdr));
- if (q->hdr == NULL) {
- dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
- free(q);
- return NULL;
- }
- q->hdr->namelen = (end_name - &buf[sizeof(struct dns_header)]) + 1; /* XXX */
- q->hdr->name = (void *) calloc(1, q->hdr->namelen);
- if (q->hdr->name == NULL) {
- dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
- free(q->hdr);
- free(q);
- return NULL;
- }
- q->converted_name = (void *)calloc(1, namelen + num_label + 2);
- if (q->converted_name == NULL) {
- dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
- free(q->hdr->name);
- free(q->hdr);
- free(q);
- return NULL;
- }
-
- p = q->converted_name;
-
- /*
- * parse the name again this time filling the labels
- * XXX this is expensive going over the buffer twice
- */
- for (i = sizeof(struct dns_header); i < len && &buf[i] < end_name;) {
- u_int labelend;
-
-
- /* check for compression */
- if ((buf[i] & 0xc0) == 0xc0) {
- dolog(LOG_INFO, "question has compressed name, drop\n");
- free_question(q);
- return NULL; /* XXX should say error */
- }
-
- labelend = (u_int)buf[i] + 1 + i; /* i = offset, plus contents of buf[i], + 1 */
-
- /*
- * i is reused here to count every character, this is not
- * a bug!
- */
-
- for (i++; i < labelend; i++) {
- int c0;
-
- c0 = buf[i];
- *p++ = tolower(c0);
- }
-
- *p++ = '.';
- }
-
- /* XXX */
- if (&buf[sizeof(struct dns_header)] == end_name)
- *p++ = '.';
-
- *p = '\0';
-
- /* check for edns0 opt rr */
- do {
- /* if we don't have an additional section, break */
- if (additional != 1)
- break;
-
- i += (2 * sizeof(u_int16_t)) + 1;
-
- /* check that the minimum optrr fits */
- /* 10 */
- if (i + sizeof(struct dns_optrr) > len)
- break;
-
- opt = (struct dns_optrr *)&buf[i];
- if (opt->name[0] != 0)
- break;
-
- if (ntohs(opt->type) != DNS_TYPE_OPT)
- break;
-
- /* RFC 3225 */
- ttl = ntohl(opt->ttl);
- if (((ttl >> 16) & 0xff) != 0)
- q->ednsversion = (ttl >> 16) & 0xff;
-
- q->edns0len = ntohs(opt->class);
- if (q->edns0len < 512)
- q->edns0len = 512; /* RFC 6891 - page 10 */
-
- if (ttl & DNSSEC_OK)
- q->dnssecok = 1;
- } while (0);
-
- /* fill our name into the dns header struct */
-
- memcpy(q->hdr->name, &buf[sizeof(struct dns_header)], q->hdr->namelen);
-
- /* make it lower case */
-
- for (i = 0; i < q->hdr->namelen; i++) {
- int c0;
-
- c0 = q->hdr->name[i];
- if (isalpha(c0)) {
- q->hdr->name[i] = tolower(c0);
- }
- }
-
- /* parse type and class from the question */
-
- qtype = (u_int16_t *)(end_name + 1);
- qclass = (u_int16_t *)(end_name + sizeof(u_int16_t) + 1);
-
- memcpy((char *)&q->hdr->qtype, (char *)qtype, sizeof(u_int16_t));
- memcpy((char *)&q->hdr->qclass, (char *)qclass, sizeof(u_int16_t));
-
- /* make note of whether recursion is desired */
- q->rd = ((ntohs(hdr->query) & DNS_RECURSE) == DNS_RECURSE);
-
- return (q);
-}
-
-/*
- * FREE_QUESTION - free a question struct
- *
- */
-
-int
-free_question(struct question *q)
-{
- free(q->hdr->name);
- free(q->hdr);
- free(q->converted_name);
- free(q);
-
- return 0;
-}
/*
* COMPRESS_LABEL - compress a DNS name, must be passed an entire reply
blob - 374304ee622a9694c5a92c00042a5d72370cfd46
blob + 4739c5f8ee32df506fa29bfb7b988df79cb62b04
--- parse.y
+++ parse.y
@@ -21,7 +21,7 @@
*/
/*
- * $Id: parse.y,v 1.56 2019/02/04 19:35:44 pjp Exp $
+ * $Id: parse.y,v 1.57 2019/02/07 11:16:03 pjp Exp $
*/
%{
@@ -30,6 +30,7 @@
#include "ddd-db.h"
+extern struct rrtab *rrlookup(char *);
extern int base32hex_decode(u_char *, u_char *);
extern void dolog(int, char *, ...);
extern char *dns_label(char *, int *);
@@ -180,7 +181,6 @@ int lungetc(int);
int parse_file(ddDB *, char *);
struct file *pushfile(const char *, int, int, int);
int popfile(void);
-struct rrtab *rrlookup(char *);
void set_record(struct domain *, int, char *, int);
static int temp_inet_net_pton_ipv6(const char *, void *, size_t);
int yyparse(void);
@@ -188,36 +188,6 @@ static struct rzone * add_rzone(void);
static int pull_remote_zone(struct rzone *);
-struct rrtab {
- char *name;
- u_int16_t type;
- int16_t internal_type;
-} myrrtab[] = {
- { "a", DNS_TYPE_A, INTERNAL_TYPE_A } ,
- { "aaaa", DNS_TYPE_AAAA, INTERNAL_TYPE_AAAA },
- { "cname", DNS_TYPE_CNAME, INTERNAL_TYPE_CNAME },
- { "delegate", DNS_TYPE_DELEGATE, INTERNAL_TYPE_NS },
- { "dnskey", DNS_TYPE_DNSKEY, INTERNAL_TYPE_DNSKEY },
- { "ds", DNS_TYPE_DS, INTERNAL_TYPE_DS },
- { "hint", DNS_TYPE_HINT, INTERNAL_TYPE_NS },
- { "mx", DNS_TYPE_MX, INTERNAL_TYPE_MX },
- { "naptr", DNS_TYPE_NAPTR, INTERNAL_TYPE_NAPTR },
- { "ns", DNS_TYPE_NS, INTERNAL_TYPE_NS },
- { "nsec", DNS_TYPE_NSEC, INTERNAL_TYPE_NSEC },
- { "nsec3", DNS_TYPE_NSEC3, INTERNAL_TYPE_NSEC3 },
- { "nsec3param", DNS_TYPE_NSEC3PARAM, INTERNAL_TYPE_NSEC3PARAM },
- { "ptr", DNS_TYPE_PTR, INTERNAL_TYPE_PTR },
- { "rrsig", DNS_TYPE_RRSIG, -1 },
- { "soa", DNS_TYPE_SOA, INTERNAL_TYPE_SOA },
- { "srv", DNS_TYPE_SRV, INTERNAL_TYPE_SRV },
- { "sshfp", DNS_TYPE_SSHFP, INTERNAL_TYPE_SSHFP },
- { "tlsa", DNS_TYPE_TLSA, INTERNAL_TYPE_TLSA },
- { "txt", DNS_TYPE_TXT, INTERNAL_TYPE_TXT },
-};
-
-
-
-
%}
@@ -1792,26 +1762,6 @@ get_string(char *buf, int n)
return (1);
}
-
-/* probably Copyright 2012 Kenneth R Westerback <krw@openbsd.org> */
-
-int
-kw_cmp(const void *k, const void *e)
-{
- return (strcasecmp(k, ((const struct rrtab *)e)->name));
-}
-
-
-struct rrtab *
-rrlookup(char *keyword)
-{
- static struct rrtab *p;
-
- p = bsearch(keyword, myrrtab, sizeof(myrrtab)/sizeof(myrrtab[0]),
- sizeof(myrrtab[0]), kw_cmp);
-
- return (p);
-}
struct tab *
lookup(struct tab *cmdtab, char *keyword)
blob - 37ec06dd5b0d4859ea295d367f81744298a723f6
blob + df49b891f8ea234fbf75b7a09a7f960c65df3d06
--- raxfr.c
+++ raxfr.c
@@ -26,13 +26,18 @@
*
*/
/*
- * $Id: raxfr.c,v 1.1 2019/02/07 07:34:28 pjp Exp $
+ * $Id: raxfr.c,v 1.2 2019/02/07 11:16:03 pjp Exp $
*/
#include "ddd-include.h"
#include "ddd-dns.h"
#include "ddd-db.h"
+#define BIND_FORMAT 0x1
+#define INDENT_FORMAT 0x2
+#define ZONE_FORMAT 0x4
+
+
int raxfr_a(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t);
int raxfr_aaaa(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t);
int raxfr_cname(FILE *, u_char *, u_char *, u_char *, struct soa *, u_int16_t);
@@ -77,10 +82,9 @@ expand_compression(u_char *p, u_char *estart, u_char *
/* test for compression */
if ((*p & 0xc0) == 0xc0) {
/* do not allow recursive compress pointers */
- if (save) {
- return NULL;
+ if (! save) {
+ save = p + 2;
}
- save = p + 2;
offset = (u_int16_t *)p;
/* do not allow forwards jumping */
if ((p - estart) <= (ntohs(*offset) & (~0xc000)))
@@ -153,6 +157,9 @@ raxfr_peek(FILE *f, u_char *p, u_char *estart, u_char
*rrtype = ntohs(*rtype);
+ if (*rrtype == 41)
+ goto out;
+
humanname = convert_name(expand, elen);
if (humanname == NULL) {
return -1;
@@ -174,6 +181,7 @@ raxfr_peek(FILE *f, u_char *p, u_char *estart, u_char
free(humanname);
+out:
rrlen = (q - estart);
return (rrlen);
}
blob - 14fa67d97a9a412d5aa76521c7443a9e448f0285
blob + 60ab6438fad28734fcee676ad3e066ecf19d30c7
--- util.c
+++ util.c
@@ -27,7 +27,7 @@
*/
/*
- * $Id: util.c,v 1.15 2018/10/19 08:24:48 pjp Exp $
+ * $Id: util.c,v 1.16 2019/02/07 11:16:03 pjp Exp $
*/
#include "ddd-include.h"
@@ -50,6 +50,9 @@ struct question *build_fake_question(char *, int, u_i
extern void dolog(int, char *, ...);
char *get_dns_type(int, int);
int memcasecmp(u_char *, u_char *, int);
+struct question *build_question(char *, int, int);
+int free_question(struct question *);
+struct rrtab *rrlookup(char *);
/* externs */
@@ -83,6 +86,31 @@ struct typetable {
{ NULL, 0}
};
+struct rrtab myrrtab[] = {
+ { "a", DNS_TYPE_A, INTERNAL_TYPE_A } ,
+ { "aaaa", DNS_TYPE_AAAA, INTERNAL_TYPE_AAAA },
+ { "cname", DNS_TYPE_CNAME, INTERNAL_TYPE_CNAME },
+ { "delegate", DNS_TYPE_DELEGATE, INTERNAL_TYPE_NS },
+ { "dnskey", DNS_TYPE_DNSKEY, INTERNAL_TYPE_DNSKEY },
+ { "ds", DNS_TYPE_DS, INTERNAL_TYPE_DS },
+ { "hint", DNS_TYPE_HINT, INTERNAL_TYPE_NS },
+ { "mx", DNS_TYPE_MX, INTERNAL_TYPE_MX },
+ { "naptr", DNS_TYPE_NAPTR, INTERNAL_TYPE_NAPTR },
+ { "ns", DNS_TYPE_NS, INTERNAL_TYPE_NS },
+ { "nsec", DNS_TYPE_NSEC, INTERNAL_TYPE_NSEC },
+ { "nsec3", DNS_TYPE_NSEC3, INTERNAL_TYPE_NSEC3 },
+ { "nsec3param", DNS_TYPE_NSEC3PARAM, INTERNAL_TYPE_NSEC3PARAM },
+ { "ptr", DNS_TYPE_PTR, INTERNAL_TYPE_PTR },
+ { "rrsig", DNS_TYPE_RRSIG, -1 },
+ { "soa", DNS_TYPE_SOA, INTERNAL_TYPE_SOA },
+ { "srv", DNS_TYPE_SRV, INTERNAL_TYPE_SRV },
+ { "sshfp", DNS_TYPE_SSHFP, INTERNAL_TYPE_SSHFP },
+ { "tlsa", DNS_TYPE_TLSA, INTERNAL_TYPE_TLSA },
+ { "txt", DNS_TYPE_TXT, INTERNAL_TYPE_TXT },
+};
+
+
+
/*
* LABEL_COUNT - count the labels and return that number
*/
@@ -770,3 +798,255 @@ memcasecmp(u_char *b1, u_char *b2, int len)
return 1; /* XXX */
}
+
+/*
+ * BUILD_QUESTION - fill the question structure with the DNS query.
+ */
+
+struct question *
+build_question(char *buf, int len, int additional)
+{
+ u_int i;
+ u_int namelen = 0;
+ u_int16_t *qtype, *qclass;
+ u_int32_t ttl;
+ int num_label;
+
+ char *p, *end_name = NULL;
+
+ struct dns_optrr *opt = NULL;
+ struct question *q = NULL;
+ struct dns_header *hdr = (struct dns_header *)buf;
+
+ /* find the end of name */
+ for (i = sizeof(struct dns_header); i < len; i++) {
+ /* XXX */
+ if (buf[i] == 0) {
+ end_name = &buf[i];
+ break;
+ }
+ }
+
+ /*
+ * implies i >= len , because end_name still points to NULL and not
+ * &buf[i]
+ */
+
+ if (end_name == NULL) {
+ dolog(LOG_INFO, "query name is not null terminated\n");
+ return NULL;
+ }
+
+ /* parse the size of the name */
+ for (i = sizeof(struct dns_header), num_label = 0; i < len && &buf[i] < end_name;) {
+ u_int labellen;
+
+ ++num_label;
+
+ labellen = (u_int)buf[i];
+
+ /*
+ * do some checks on the label, if it's 0 or over 63 it's
+ * illegal, also if it reaches beyond the entire name it's
+ * also illegal.
+ */
+ if (labellen == 0) {
+ dolog(LOG_INFO, "illegal label len (0)\n");
+ return NULL;
+ }
+ if (labellen > DNS_MAXLABEL) {
+ dolog(LOG_INFO, "illegal label len (> 63)\n");
+ return NULL;
+ }
+ if (labellen > (end_name - &buf[i])) {
+ dolog(LOG_INFO, "label len extends beyond name\n");
+ return NULL;
+ }
+
+ i += (labellen + 1);
+ namelen += labellen;
+ }
+
+ if (&buf[i] != end_name || i >= len) {
+ dolog(LOG_INFO, "query name is maliciously malformed\n");
+ return NULL;
+ }
+
+ if (i > DNS_MAXNAME) {
+ dolog(LOG_INFO, "query name is too long (%u)\n", i);
+ return NULL;
+ }
+
+
+ /* check if there is space for qtype and qclass */
+ if (len < ((end_name - &buf[0]) + (2 * sizeof(u_int16_t)))) {
+ dolog(LOG_INFO, "question rr is truncated\n");
+ return NULL;
+ }
+
+
+ q = (void *)calloc(1, sizeof(struct question));
+ if (q == NULL) {
+ dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
+ return NULL;
+ }
+ q->hdr = (void *)calloc(1, sizeof(struct dns_question_hdr));
+ if (q->hdr == NULL) {
+ dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
+ free(q);
+ return NULL;
+ }
+ q->hdr->namelen = (end_name - &buf[sizeof(struct dns_header)]) + 1; /* XXX */
+ q->hdr->name = (void *) calloc(1, q->hdr->namelen);
+ if (q->hdr->name == NULL) {
+ dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
+ free(q->hdr);
+ free(q);
+ return NULL;
+ }
+ q->converted_name = (void *)calloc(1, namelen + num_label + 2);
+ if (q->converted_name == NULL) {
+ dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
+ free(q->hdr->name);
+ free(q->hdr);
+ free(q);
+ return NULL;
+ }
+
+ p = q->converted_name;
+
+ /*
+ * parse the name again this time filling the labels
+ * XXX this is expensive going over the buffer twice
+ */
+ for (i = sizeof(struct dns_header); i < len && &buf[i] < end_name;) {
+ u_int labelend;
+
+
+ /* check for compression */
+ if ((buf[i] & 0xc0) == 0xc0) {
+ dolog(LOG_INFO, "question has compressed name, drop\n");
+ free_question(q);
+ return NULL; /* XXX should say error */
+ }
+
+ labelend = (u_int)buf[i] + 1 + i; /* i = offset, plus contents of buf[i], + 1 */
+
+ /*
+ * i is reused here to count every character, this is not
+ * a bug!
+ */
+
+ for (i++; i < labelend; i++) {
+ int c0;
+
+ c0 = buf[i];
+ *p++ = tolower(c0);
+ }
+
+ *p++ = '.';
+ }
+
+ /* XXX */
+ if (&buf[sizeof(struct dns_header)] == end_name)
+ *p++ = '.';
+
+ *p = '\0';
+
+ /* check for edns0 opt rr */
+ do {
+ /* if we don't have an additional section, break */
+ if (additional != 1)
+ break;
+
+ i += (2 * sizeof(u_int16_t)) + 1;
+
+ /* check that the minimum optrr fits */
+ /* 10 */
+ if (i + sizeof(struct dns_optrr) > len)
+ break;
+
+ opt = (struct dns_optrr *)&buf[i];
+ if (opt->name[0] != 0)
+ break;
+
+ if (ntohs(opt->type) != DNS_TYPE_OPT)
+ break;
+
+ /* RFC 3225 */
+ ttl = ntohl(opt->ttl);
+ if (((ttl >> 16) & 0xff) != 0)
+ q->ednsversion = (ttl >> 16) & 0xff;
+
+ q->edns0len = ntohs(opt->class);
+ if (q->edns0len < 512)
+ q->edns0len = 512; /* RFC 6891 - page 10 */
+
+ if (ttl & DNSSEC_OK)
+ q->dnssecok = 1;
+ } while (0);
+
+ /* fill our name into the dns header struct */
+
+ memcpy(q->hdr->name, &buf[sizeof(struct dns_header)], q->hdr->namelen);
+
+ /* make it lower case */
+
+ for (i = 0; i < q->hdr->namelen; i++) {
+ int c0;
+
+ c0 = q->hdr->name[i];
+ if (isalpha(c0)) {
+ q->hdr->name[i] = tolower(c0);
+ }
+ }
+
+ /* parse type and class from the question */
+
+ qtype = (u_int16_t *)(end_name + 1);
+ qclass = (u_int16_t *)(end_name + sizeof(u_int16_t) + 1);
+
+ memcpy((char *)&q->hdr->qtype, (char *)qtype, sizeof(u_int16_t));
+ memcpy((char *)&q->hdr->qclass, (char *)qclass, sizeof(u_int16_t));
+
+ /* make note of whether recursion is desired */
+ q->rd = ((ntohs(hdr->query) & DNS_RECURSE) == DNS_RECURSE);
+
+ return (q);
+}
+
+/*
+ * FREE_QUESTION - free a question struct
+ *
+ */
+
+int
+free_question(struct question *q)
+{
+ free(q->hdr->name);
+ free(q->hdr);
+ free(q->converted_name);
+ free(q);
+
+ return 0;
+}
+
+/* probably Copyright 2012 Kenneth R Westerback <krw@openbsd.org> */
+
+static int
+kw_cmp(const void *k, const void *e)
+{
+ return (strcasecmp(k, ((const struct rrtab *)e)->name));
+}
+
+
+struct rrtab *
+rrlookup(char *keyword)
+{
+ static struct rrtab *p;
+
+ p = bsearch(keyword, myrrtab, sizeof(myrrtab)/sizeof(myrrtab[0]),
+ sizeof(myrrtab[0]), kw_cmp);
+
+ return (p);
+}
repomaster@centroid.eu