Commit Diff


commit - 0bc2ad624e61a3fa6f25bbbf8b12a2d2ce40d243
commit + 6f8190d3bb180a0730396b2efa7553eb9d9f5674
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
@@ -135,6 +135,8 @@ struct dns_question_hdr {
 #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  */
 #define DNS_TYPE_AXFR	252		/* RFC 5936, page 10 */
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) {
@@ -1824,6 +1841,15 @@ lookup_zone(DB *db, struct question *question, struct 
 				return -1;
 			}
 			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:
@@ -2495,10 +2521,19 @@ tcpnxdomain:
 						build_reply(&sreply, tnp->so, pbuf, len, question, from,  \
 							fromlen, &sd0, NULL, tnp->region, istcp, tnp->wildcard, NULL);
 						reply_ns(&sreply, cfg->db);
+					}
+					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)
@@ -1456,12 +1456,218 @@ 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++;