Commit Diff
Diff:
0bc2ad624e61a3fa6f25bbbf8b12a2d2ce40d243
6f8190d3bb180a0730396b2efa7553eb9d9f5674
Commit:
6f8190d3bb180a0730396b2efa7553eb9d9f5674
Tree:
073de870c7e16465ab6cb264985f31ec3749c983
Author:
pbug <pbug@delphinusdns.org>
Committer:
pbug <pbug@delphinusdns.org>
Date:
Mon Apr 30 15:34:45 2012 UTC
Message:
* SRV RR support The srv configfile sample would look like this: ; srv record test _sip._udp.centroid.eu,srv,3600,0,0,0,. The first three values after the TTL are in order, priority, weight and port followed by a domain name. Much of this code is based on reply_mx() so any bugs carried over would be carried over. Tested and compiled on OpenBSD/amd64
blob - 2c608e959db7c65a799d3bd40e334f536a571235
blob + 9615ec91041f41220432b327f9b31bb5c42e35fc
--- db.h
+++ db.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2011 Peter J. Philipp
+ * Copyright (c) 2005-2012 Peter J. Philipp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -63,6 +63,14 @@ struct ns {
int nslen; /* length of NS */
} __attribute__((packed));
+struct srv {
+ u_int16_t priority; /* SRV 16 bit priority */
+ u_int16_t weight; /* 16 bit weight */
+ u_int16_t port; /* 16 bit port */
+ char target[DNS_MAXNAME]; /* SRV target name */
+ int targetlen; /* SRV target name length */
+} __attribute__((packed));
+
struct domain {
char zone[DNS_MAXNAME]; /* name of zone in dns name format */
int zonelen; /* length of zone, above */
@@ -78,6 +86,7 @@ struct domain {
#define DOMAIN_HAVE_TXT 0x80
#define DOMAIN_STATIC_ZONE 0x100
#define DOMAIN_NEGATIVE_CACHE 0x200
+#define DOMAIN_HAVE_SRV 0x400
struct soa soa; /* start of authority */
u_int32_t ttl; /* time to live */
time_t created; /* time created, for dynamic zones */
@@ -103,6 +112,8 @@ struct domain {
int ptrlen; /* len of PTR */
char txt[DNS_MAXNAME]; /* TXT string */
int txtlen; /* len of TXT */
+ struct srv srv[RECORD_COUNT]; /* SRV resource record */
+ int srv_count; /* count of SRV resource record */
} __attribute__((packed));
struct sreply {
blob - c7a27d36f218f950165850f65f22e7ae200ddd54
blob + 5179ba6e10d14044a328813f9a57d059c32b7626
--- dns.h
+++ dns.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002-2011 Peter J. Philipp
+ * Copyright (c) 2002-2012 Peter J. Philipp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -134,6 +134,8 @@ struct dns_question_hdr {
#define DNS_TYPE_PTR 12
#define DNS_TYPE_MX 15
#define DNS_TYPE_TXT 16
+
+#define DNS_TYPE_SRV 33 /* RFC 2782, page 8 */
#define DNS_TYPE_TSIG 250 /* RFC 2845, page 3 */
#define DNS_TYPE_IXFR 251 /* RFC 1995, page 2 */
blob - 8f57cef062c7d7dd1d896ccce3fa143daee52d30
blob + b0653c5416bed7ebe72bbacf514cb82bb28e216f
--- main.c
+++ main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002-2011 Peter J. Philipp
+ * Copyright (c) 2002-2012 Peter J. Philipp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -52,6 +52,7 @@ extern void reply_mx(struct sreply *, DB *);
extern void reply_ns(struct sreply *, DB *);
extern void reply_txt(struct sreply *);
extern void reply_any(struct sreply *);
+extern void reply_srv(struct sreply *, DB *);
extern u_int8_t find_region(struct sockaddr_storage *sst, int family);
extern int find_wildcard(struct sockaddr_storage *sst, int family);
extern void init_wildcard(void);
@@ -98,6 +99,7 @@ struct typetable {
{ "TXT", DNS_TYPE_TXT},
{ "AAAA", DNS_TYPE_AAAA},
{ "ANY", DNS_TYPE_ANY },
+ { "SRV", DNS_TYPE_SRV },
{ NULL, 0}
};
@@ -136,7 +138,7 @@ struct tcps {
} *tn1, *tn2, *tnp;
-static const char rcsid[] = "$Id: main.c,v 1.70 2011/09/22 07:52:16 pbug Exp $";
+static const char rcsid[] = "$Id: main.c,v 1.71 2012/04/30 15:34:45 pbug Exp $";
/*
* MAIN - set up arguments, set up database, set up sockets, call mainloop
@@ -1366,6 +1368,12 @@ compress_label(u_char *buf, u_int16_t offset, int labe
p += *p;
p++;
break;
+ case DNS_TYPE_SRV:
+ p += (2 * sizeof(u_int16_t)); /* priority, weight */
+ /* the port will be assumed in the fall through for
+ mx_priority..
+ */
+ /* FALLTHROUGH */
case DNS_TYPE_MX:
p += sizeof(u_int16_t); /* mx_priority */
/* FALLTHROUGH */
@@ -1679,6 +1687,15 @@ lookup_zone(DB *db, struct question *question, struct
}
returnval = DNS_TYPE_SOA;
break;
+
+ case DNS_TYPE_SRV:
+ if ((sd->flags & DOMAIN_HAVE_SRV) != DOMAIN_HAVE_SRV) {
+
+ *lzerrno = ERR_NOERROR;
+ return -1;
+ }
+ returnval = DNS_TYPE_SRV;
+ break;
case DNS_TYPE_CNAME:
if ((sd->flags & DOMAIN_HAVE_CNAME) != DOMAIN_HAVE_CNAME) {
@@ -1825,6 +1842,15 @@ lookup_zone(DB *db, struct question *question, struct
}
returnval = DNS_TYPE_NS;
break;
+
+ case DNS_TYPE_SRV:
+ if ((sd->flags & DOMAIN_HAVE_SRV) != DOMAIN_HAVE_SRV) {
+
+ *lzerrno = ERR_NOERROR;
+ return -1;
+ }
+ returnval = DNS_TYPE_SRV;
+ break;
case DNS_TYPE_CNAME:
if ((sd->flags & DOMAIN_HAVE_CNAME) != DOMAIN_HAVE_CNAME) {
@@ -2498,7 +2524,16 @@ tcpnxdomain:
}
break;
+ case DNS_TYPE_SRV:
+ if (type0 == DNS_TYPE_SRV) {
+ build_reply(&sreply, tnp->so, pbuf, len, question, from, \
+ fromlen, &sd0, NULL, tnp->region, istcp, tnp->wildcard, NULL);
+ reply_srv(&sreply, cfg->db);
+ }
+ break;
+
+
case DNS_TYPE_CNAME:
if (type0 == DNS_TYPE_CNAME) {
build_reply(&sreply, tnp->so, pbuf, len, question, from, \
@@ -2914,6 +2949,13 @@ udpnxdomain:
}
break;
+ case DNS_TYPE_SRV:
+ if (type0 == DNS_TYPE_SRV) {
+ build_reply(&sreply, so, buf, len, question, from, \
+ fromlen, &sd0, NULL, aregion, istcp, wildcard, NULL);
+ reply_srv(&sreply, cfg->db);
+ }
+ break;
case DNS_TYPE_CNAME:
if (type0 == DNS_TYPE_CNAME) {
blob - d372c794c40177892648f189354ef3f1704a11e7
blob + ef4f3b2aacabb9eea82a3ae1b002fa9720225c37
--- parse.c
+++ parse.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2011 Peter J. Philipp
+ * Copyright (c) 2005-2012 Peter J. Philipp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,6 +55,7 @@ struct myrr_lookup {
{ "hint", DNS_TYPE_HINT },
{ "delegate", DNS_TYPE_DELEGATE },
{ "balance", DNS_TYPE_BALANCE },
+ { "srv", DNS_TYPE_SRV },
{ NULL, 0 },
};
@@ -97,7 +98,7 @@ static u_int32_t config = 0;
struct logging logging;
int axfrport = 0;
-static const char rcsid[] = "$Id: parse.c,v 1.33 2012/01/27 21:24:14 pbug Exp $";
+static const char rcsid[] = "$Id: parse.c,v 1.34 2012/04/30 15:34:45 pbug Exp $";
/*
* PARSE_FILE - parse the configfile XXX rewrite me in yacc :(
@@ -645,6 +646,90 @@ parse_file0(char *filename, DB *db, FILE *f)
sdomain.aaaa_ptr = 0;
sdomain.flags |= DOMAIN_HAVE_AAAA;
break;
+
+ case DNS_TYPE_SRV:
+
+ for (p = starttoken; p < endline && *p != ','; p++);
+ if (p >= endline || *p != ',') {
+ syslog(LOG_INFO, "%s: (7a) malformed line %d", filename, line);
+ return -1;
+ }
+
+ tokenlen = (p - starttoken);
+ save = *p;
+ *p = 0;
+
+ if (sdomain.srv_count < RECORD_COUNT) {
+ sdomain.srv[sdomain.srv_count].priority = atoi(starttoken);
+ } else {
+ syslog(LOG_INFO, "%s: too many srv records for zone \"%s\", skipping line %d\n", filename, domainname, line);
+ return (-1);
+ }
+
+ *p = save;
+ starttoken = ++p;
+
+ for (; p < endline && *p != ','; p++);
+ if (p >= endline || *p != ',') {
+ syslog(LOG_INFO, "%s: (7b) malformed line %d", filename, line);
+ return -1;
+ }
+
+ tokenlen = (p - starttoken);
+ save = *p;
+ *p = 0;
+
+ sdomain.srv[sdomain.srv_count].weight = atoi(starttoken);
+ *p = save;
+ starttoken = ++p;
+
+ for (; p < endline && *p != ','; p++);
+ if (p >= endline || *p != ',') {
+ syslog(LOG_INFO, "%s: (7b) malformed line %d", filename, line);
+ return -1;
+ }
+
+ tokenlen = (p - starttoken);
+ save = *p;
+ *p = 0;
+
+ sdomain.srv[sdomain.srv_count].port = atoi(starttoken);
+ if (++p >= endline) {
+ fprintf(stderr, "(XX) malformed line %d", line);
+ break;
+ }
+
+ starttoken = p;
+
+ p = endline;
+ save = *p;
+ *p = 0;
+
+ {
+ char *name;
+ char *n;
+
+ if ((name = dns_label(starttoken, (int *)&sdomain.srv[sdomain.srv_count].targetlen)) == NULL) {
+ fprintf(stderr, "illegal srv server, skipping line %d\n", line);
+ goto skip;
+ }
+ n = (char *)sdomain.srv[sdomain.srv_count].target;
+
+ memcpy((char *)n, name, sdomain.srv[sdomain.srv_count].targetlen);
+ free (name);
+
+ /* XXX bad hack!!!! */
+ if (strcmp(starttoken, ".") == 0 &&
+ sdomain.srv[sdomain.srv_count].targetlen == 2)
+ sdomain.srv[sdomain.srv_count].targetlen = 1;
+ }
+
+ sdomain.srv_count++;
+ *p = save;
+
+ sdomain.flags |= DOMAIN_HAVE_SRV;
+
+ break;
case DNS_TYPE_MX:
for (p = starttoken; p < endline && *p != ','; p++);
blob - 3b596a24db7c435382259c1c84107d56618e58dd
blob + 6551e802fd4e8ffc1cab4e8157422ab3ca45e429
--- reply.c
+++ reply.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2011 Peter J. Philipp
+ * Copyright (c) 2005-2012 Peter J. Philipp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -80,7 +80,7 @@ struct collects {
} *cn1, *cn2, *cnp;
-static const char rcsid[] = "$Id: reply.c,v 1.46 2011/09/19 19:59:23 pbug Exp $";
+static const char rcsid[] = "$Id: reply.c,v 1.47 2012/04/30 15:34:45 pbug Exp $";
/*
* REPLY_A() - replies a DNS question (*q) on socket (so)
@@ -1457,11 +1457,217 @@ reply_txt(struct sreply *sreply)
return;
}
+
+/*
+ * REPLY_SRV() - replies a DNS question (*q) on socket (so)
+ * (based on reply_mx)
+ */
+
+
+void
+reply_srv(struct sreply *sreply, DB *db)
+{
+ char reply[512];
+ struct dns_header *odh;
+ struct domain *sd0;
+ int srv_count;
+ u_int16_t *plen;
+ char *name;
+ u_int16_t outlen;
+ u_int16_t namelen;
+ int additional = 0;
+
+ struct answer {
+ char name[2];
+ u_int16_t type;
+ u_int16_t class;
+ u_int32_t ttl;
+ u_int16_t rdlength; /* 12 */
+ u_int16_t srv_priority;
+ u_int16_t srv_weight;
+ u_int16_t srv_port;
+ char target;
+ } __attribute__((packed));
+
+ struct answer *answer;
+
+ int so = sreply->so;
+ char *buf = sreply->buf;
+ int len = sreply->len;
+ struct question *q = sreply->q;
+ struct sockaddr *sa = sreply->sa;
+ int salen = sreply->salen;
+ struct domain *sd = sreply->sd1;
+ int istcp = sreply->istcp;
+ int wildcard = sreply->wildcard;
+
+
+ odh = (struct dns_header *)&reply[0];
+
+ outlen = sizeof(struct dns_header);
+
+ if (len > sizeof(reply)) {
+ return;
+ }
+
+ memcpy(&reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
+ memset((char *)&odh->query, 0, sizeof(u_int16_t));
+
+ outlen += (q->hdr->namelen + 4);
+
+ SET_DNS_REPLY(odh);
+
+ if (sreply->sr == NULL) {
+ SET_DNS_AUTHORITATIVE(odh);
+ } else
+ SET_DNS_RECURSION_AVAIL(odh);
+
+ HTONS(odh->query);
+
+ odh->question = htons(1);
+ odh->answer = htons(sd->srv_count);
+ odh->nsrr = 0;
+ odh->additional = 0;
+
+ /* skip dns header, question name, qtype and qclass */
+ answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
+ q->hdr->namelen + 4);
+
+ srv_count = 0;
+ do {
+ answer->name[0] = 0xc0;
+ answer->name[1] = 0x0c;
+ answer->type = q->hdr->qtype;
+ answer->class = q->hdr->qclass;
+ if (sreply->sr != NULL)
+ answer->ttl = htonl(sd->ttl - (time(NULL) - sd->created));
+ else
+ answer->ttl = htonl(sd->ttl);
+
+ answer->rdlength = htons((3 * sizeof(u_int16_t)) + sd->srv[srv_count].targetlen);
+
+ answer->srv_priority = htons(sd->srv[srv_count].priority);
+ answer->srv_weight = htons(sd->srv[srv_count].weight);
+ answer->srv_port = htons(sd->srv[srv_count].port);
+
+ memcpy((char *)&answer->target, (char *)sd->srv[srv_count].target, sd->srv[srv_count].targetlen);
+
+ name = sd->srv[srv_count].target;
+ namelen = sd->srv[srv_count].targetlen;
+
+ sd0 = Lookup_zone(db, name, namelen, htons(DNS_TYPE_A), wildcard);
+ if (sd0 != NULL) {
+ cn1 = malloc(sizeof(struct collects));
+ if (cn1 != NULL) {
+ cn1->name = malloc(namelen);
+ if (cn1->name != NULL) {
+ memcpy(cn1->name, name, namelen);
+ cn1->namelen = namelen;
+ cn1->sd = sd0;
+ cn1->type = DNS_TYPE_A;
+
+ SLIST_INSERT_HEAD(&collectshead, cn1, entries);
+ }
+ }
+ }
+ sd0 = Lookup_zone(db, name, namelen, htons(DNS_TYPE_AAAA), wildcard);
+ if (sd0 != NULL) {
+ cn1 = malloc(sizeof(struct collects));
+ if (cn1 != NULL) {
+ cn1->name = malloc(namelen);
+ if (cn1->name != NULL) {
+ memcpy(cn1->name, name, namelen);
+ cn1->namelen = namelen;
+ cn1->sd = sd0;
+ cn1->type = DNS_TYPE_AAAA;
+
+ SLIST_INSERT_HEAD(&collectshead, cn1, entries);
+ }
+ }
+ }
+
+ outlen += (12 + 6 + sd->srv[srv_count].targetlen);
+
+ /* can we afford to write another header? if no truncate */
+ if (sd->srv_count > 1 && (outlen + 12 + 6 + sd->srv[srv_count].targetlen) > DNS_MAXUDP) {
+ NTOHS(odh->query);
+ SET_DNS_TRUNCATION(odh);
+ HTONS(odh->query);
+ goto out;
+ }
+
+ /* set new offset for answer */
+ answer = (struct answer *)&reply[outlen];
+ } while (++srv_count < RECORD_COUNT && --sd->srv_count);
+
+ /* write additional */
+
+ SLIST_FOREACH(cnp, &collectshead, entries) {
+ int addcount;
+ int tmplen;
+
+ switch (cnp->type) {
+ case DNS_TYPE_A:
+ tmplen = additional_a(cnp->name, cnp->namelen, cnp->sd, reply, sizeof(reply), outlen, &addcount);
+ additional += addcount;
+ break;
+ case DNS_TYPE_AAAA:
+ tmplen = additional_aaaa(cnp->name, cnp->namelen, cnp->sd, reply, sizeof(reply), outlen, &addcount);
+ additional += addcount;
+ break;
+ }
+
+ if (tmplen > 0) {
+ outlen = tmplen;
+ }
+ }
+
+ odh->additional = htons(additional);
+
+ while (!SLIST_EMPTY(&collectshead)) {
+ cn1 = SLIST_FIRST(&collectshead);
+ SLIST_REMOVE_HEAD(&collectshead, entries);
+ free(cn1->name);
+ free(cn1->sd);
+ free(cn1);
+ }
+
+out:
+ if (sreply->sr != NULL) {
+ reply_raw2(so, reply, outlen, sreply->sr);
+ } else {
+ if (istcp) {
+ char *tmpbuf;
+
+ tmpbuf = malloc(outlen + 2);
+ if (tmpbuf == NULL) {
+ syslog(LOG_INFO, "malloc: %m");
+ }
+ plen = (u_int16_t *)tmpbuf;
+ *plen = htons(outlen);
+
+ memcpy(&tmpbuf[2], reply, outlen);
+ if (send(so, tmpbuf, outlen + 2, 0) < 0) {
+ syslog(LOG_INFO, "send: %m");
+ }
+ free(tmpbuf);
+ } else {
+ if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
+ }
+ }
+
+ return;
+}
+
+
/*
* REPLY_NOTIMPL - reply "Not Implemented"
*
*/
+
void
reply_notimpl(struct sreply *sreply)
{
@@ -2547,7 +2753,7 @@ reply_any(struct sreply *sreply)
u_int16_t
create_anyreply(struct sreply *sreply, char *reply, int rlen, int offset, int soa)
{
- int a_count, aaaa_count, ns_count, mx_count;
+ int a_count, aaaa_count, ns_count, mx_count, srv_count;
int tmplen, pos, mod;
int ttlhack;
struct answer {
@@ -2566,7 +2772,7 @@ create_anyreply(struct sreply *sreply, char *reply, in
char *label, *plabel;
u_int32_t *soa_val;
u_int16_t namelen;
- u_int16_t *mx_priority;
+ u_int16_t *mx_priority, *srv_priority, *srv_port, *srv_weight;
char *name, *p;
int i;
@@ -2885,6 +3091,73 @@ create_anyreply(struct sreply *sreply, char *reply, in
answer->rdlength = htons(sd->txtlen + 1);
}
+ if (sd->flags & DOMAIN_HAVE_SRV) {
+ srv_count = 0;
+ do {
+ if ((offset + q->hdr->namelen) > rlen) {
+ goto truncate;
+ }
+
+ memcpy(&reply[offset], q->hdr->name, q->hdr->namelen);
+ offset += q->hdr->namelen;
+
+ if ((tmplen = compress_label((u_char*)reply, offset, q->hdr->namelen)) > 0) {
+ offset = tmplen;
+ }
+
+
+ if (offset + 12 > rlen)
+ goto truncate;
+
+ answer = (struct answer *)&reply[offset];
+
+ answer->type = htons(DNS_TYPE_SRV);
+ answer->class = htons(DNS_CLASS_IN);
+ answer->ttl = htonl(sd->ttl);
+ answer->rdlength = htons(3 * sizeof(u_int16_t) + sd->srv[srv_count].targetlen);
+
+ offset += 10; /* up to rdata length */
+
+ srv_priority = (u_int16_t *)&reply[offset];
+ *srv_priority = htons(sd->srv[srv_count].priority);
+
+ offset += 2;
+
+ srv_weight = (u_int16_t *)&reply[offset];
+ *srv_weight = htons(sd->srv[srv_count].weight);
+
+ offset += 2;
+
+ srv_port = (u_int16_t *)&reply[offset];
+ *srv_port = htons(sd->srv[srv_count].port);
+
+ offset += 2;
+
+ if (offset + sd->srv[srv_count].targetlen > rlen)
+ goto truncate;
+
+ memcpy((char *)&reply[offset], (char *)sd->srv[srv_count].target, sd->srv[srv_count].targetlen);
+
+ offset += sd->srv[srv_count].targetlen;
+
+ if ((tmplen = compress_label((u_char*)reply, offset, sd->srv[srv_count].targetlen)) > 0) {
+ offset = tmplen;
+ }
+
+ /* can we afford to write another header? if no truncate */
+ if (sd->srv_count > 1 && (offset + 12 + 6 + sd->srv[srv_count].targetlen) > rlen) {
+ goto truncate;
+ }
+
+ answer->rdlength = htons(&reply[offset] - answer->rdata);
+ } while (++srv_count < RECORD_COUNT && --sd->srv_count);
+
+ NTOHS(odh->answer);
+ odh->answer += srv_count;
+ HTONS(odh->answer);
+
+ }
+
if (sd->flags & DOMAIN_HAVE_CNAME) {
NTOHS(odh->answer);
odh->answer++;
repomaster@centroid.eu