Commit Diff
Diff:
b6eb929269bfafcdc074838d20b0ef00f7602fc1
f1e3cfca4ec71d43a40b363f5f0d63c141292f35
Commit:
f1e3cfca4ec71d43a40b363f5f0d63c141292f35
Tree:
14757ab7169eed8e4acb659f5b337ae12714eb5d
Author:
pbug <pbug@delphinusdns.org>
Committer:
pbug <pbug@delphinusdns.org>
Date:
Fri Mar 12 21:11:25 2010 UTC
Message:
* TCP support, this _may_ have a memory leak so it will have to be watched closely in a test environment first. compiles and runs on OpenBSD
blob - fd5295d913818ed2f123c976a0775d42a354f1e1
blob + 9490d34431a054fe6d4d10e48faabbc8b9d55d34
--- db.h
+++ db.h
@@ -102,6 +102,7 @@ struct sreply {
struct domain *sd1; /* first resolved domain */
struct domain *sd2; /* CNAME to second resolved domain */
u_int8_t region; /* region of question */
+ int istcp; /* when set it's tcp */
};
/*
@@ -111,7 +112,7 @@ struct sreply {
* (hopefully the only macro in the program !!!!)
*/
-#define BUILD_REPLY(reply, so0, buf0, len0, q0, sa0, salen0, sd10, sd20, aregion) \
+#define BUILD_REPLY(reply, so0, buf0, len0, q0, sa0, salen0, sd10, sd20, aregion, istcp) \
do { \
reply.so = so0; \
reply.buf = buf0; \
@@ -122,6 +123,7 @@ struct sreply {
reply.sd1 = sd10; \
reply.sd2 = sd20; \
reply.region = aregion; \
+ reply.istcp = istcp; \
} while (0);
int parse_file(DB *db, char *);
blob - 801c618c8b58118bf9c98cd81155363a125978b5
blob + ab474795c07ff13e29ef5ab493ac820b4075d383
--- main.c
+++ main.c
@@ -33,7 +33,8 @@
struct question * build_question(char *, int);
struct question * build_fake_question(char *, int, u_int16_t);
-void mainloop(int *, int *, int, char **, DB *);
+void udpmainloop(int *, int, char **, DB *);
+void tcpmainloop(int *, int, char **, DB *);
int free_question(struct question *);
int lookup_zone(DB *, struct question *, struct domain *, int *, char *);
int get_soa(DB *, struct question *, struct domain *);
@@ -83,8 +84,26 @@ extern char *__progname;
static int Wflag = 0;
static int lflag = 0;
-static const char rcsid[] = "$Id: main.c,v 1.33 2010/03/09 15:38:22 pbug Exp $";
+/* singly linked list for tcp operations */
+SLIST_HEAD(listhead, tcps) tcpshead;
+struct tcps {
+ char *input;
+ char *ident;
+ char *address;
+ int offset;
+ int length;
+ int maxlen;
+ int so;
+ int isv6;
+ int region;
+ time_t time;
+ SLIST_ENTRY(tcps) entries;
+} *tn1, *tn2, *tnp;
+
+
+static const char rcsid[] = "$Id: main.c,v 1.34 2010/03/12 21:11:27 pbug Exp $";
+
/*
* MAIN - set up arguments, set up database, set up sockets, call mainloop
*
@@ -93,6 +112,7 @@ static const char rcsid[] = "$Id: main.c,v 1.33 2010/0
int
main(int argc, char *argv[])
{
+ pid_t pid;
int udp[DEFAULT_SOCKET];
int tcp[DEFAULT_SOCKET];
@@ -263,8 +283,36 @@ main(int argc, char *argv[])
}
ident[i] = bind_list[i];
- }
+ /* tcp below */
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_flags = AI_NUMERICHOST;
+
+ snprintf(buf, sizeof(buf) - 1, "%u", port);
+
+ if ((gai_error = getaddrinfo(bind_list[i], buf, &hints, &res0)) != 0) {
+ syslog(LOG_INFO, "getaddrinfo: %s\n", gai_strerror(gai_error));
+ exit (1);
+ }
+
+ res = res0;
+
+ if ((tcp[i] = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) {
+ syslog(LOG_INFO, "tcp socket: %m");
+ exit(1);
+ }
+ if (setsockopt(tcp[i], SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
+ syslog(LOG_INFO, "setsockopt: %m");
+ exit(1);
+ }
+ if (bind(tcp[i], res->ai_addr, res->ai_addrlen) < 0) {
+ syslog(LOG_INFO, "tcp bind: %m");
+ exit(1);
+ }
+
+ } /* for .. bcount */
+
} else {
if (getifaddrs(&ifap) < 0) {
syslog(LOG_INFO, "getifaddrs");
@@ -344,6 +392,20 @@ main(int argc, char *argv[])
ident[i] = pifap->ifa_name;
+ if ((tcp[i] = socket(pifap->ifa_addr->sa_family, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+ syslog(LOG_INFO, "tcp socket: %m");
+ exit(1);
+ }
+ if (setsockopt(tcp[i], SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
+ syslog(LOG_INFO, "setsockopt: %m");
+ exit(1);
+ }
+
+ if (bind(tcp[i], (struct sockaddr *)pifap->ifa_addr, salen) < 0) {
+ syslog(LOG_INFO, "tcp bind: %m");
+ exit(1);
+ }
+
}
if (i >= DEFAULT_SOCKET) {
@@ -402,26 +464,41 @@ main(int argc, char *argv[])
exit(1);
}
#endif
+ pid = fork();
+ switch (pid) {
+ case -1:
+ syslog(LOG_INFO, "fork: %m");
+ exit(1);
+ case 0:
+ for (j = 0; j < i; j++)
+ close(udp[j]);
+ tcpmainloop((int *)&tcp, i, ident, db);
+ break;
+ default:
+ for (j = 0; j < i; j++)
+ close(tcp[j]);
+ udpmainloop((int *)&udp, i, ident, db);
+ break;
+ }
- mainloop((int *)&udp, (int *)&tcp, i, ident, db);
-
/* NOTREACHED */
return 0;
}
/*
- * MAINLOOP - does the polling of descriptors and if ready receives the
+ * UDPMAINLOOP - does the polling of udp descriptors and if ready receives the
* requests, builds the question and calls for replies, loops
*
*/
void
-mainloop(int *udp, int *tcp, int sockcount, char **ident, DB *db)
+udpmainloop(int *udp, int sockcount, char **ident, DB *db)
{
fd_set rset;
int sel;
+ int istcp = 0;
int len;
int is_ipv6;
int i;
@@ -585,7 +662,7 @@ mainloop(int *udp, int *tcp, int sockcount, char **ide
syslog(LOG_INFO, "on descriptor %u interface \"%s\" header from %s has no question, drop", so, ident[i], address);
/* format error */
- BUILD_REPLY(sreply, so, buf, len, NULL, from, fromlen, NULL, NULL, aregion);
+ BUILD_REPLY(sreply, so, buf, len, NULL, from, fromlen, NULL, NULL, aregion, istcp);
reply_fmterror(&sreply);
syslog(LOG_INFO, "question on descriptor %d interface \"%s\" from %s, did not have question of 1 replying format error", so, ident[i], address);
goto drop;
@@ -626,7 +703,7 @@ mainloop(int *udp, int *tcp, int sockcount, char **ide
(void)get_soa(db, question, &sd0);
BUILD_REPLY(sreply, so, buf, len, question, from, \
- fromlen, &sd0, NULL, aregion);
+ fromlen, &sd0, NULL, aregion, istcp);
reply_noerror(&sreply);
goto out;
@@ -652,7 +729,7 @@ nxdomain:
(void)get_soa(db, question, &sd0);
BUILD_REPLY(sreply, so, buf, len, question, from, \
- fromlen, &sd0, NULL, aregion);
+ fromlen, &sd0, NULL, aregion, istcp);
reply_nxdomain(&sreply);
goto out;
case DNS_TYPE_CNAME:
@@ -684,7 +761,7 @@ nxdomain:
break;
default:
BUILD_REPLY(sreply, so, buf, len, question, from, \
- fromlen, NULL, NULL, aregion);
+ fromlen, NULL, NULL, aregion, istcp);
reply_notimpl(&sreply);
snprintf(replystring, DNS_MAXNAME, "NOTIMPL");
goto out;
@@ -695,11 +772,11 @@ nxdomain:
if (type0 == DNS_TYPE_CNAME) {
BUILD_REPLY(sreply, so, buf, len, question, from, \
fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL), \
- aregion);
+ aregion, istcp);
reply_cname(&sreply);
} else if (type0 == DNS_TYPE_A) {
BUILD_REPLY(sreply, so, buf, len, question, from, \
- fromlen, &sd0, NULL, aregion);
+ fromlen, &sd0, NULL, aregion, istcp);
reply_a(&sreply, db);
break; /* must break here */
}
@@ -710,11 +787,11 @@ nxdomain:
if (type0 == DNS_TYPE_CNAME) {
BUILD_REPLY(sreply, so, buf, len, question, from, \
fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL), \
- aregion );
+ aregion, istcp);
reply_cname(&sreply);
} else if (type0 == DNS_TYPE_AAAA) {
BUILD_REPLY(sreply, so, buf, len, question, from,
- fromlen, &sd0, NULL, aregion);
+ fromlen, &sd0, NULL, aregion, istcp);
reply_aaaa(&sreply, db);
break; /* must break here */
}
@@ -725,11 +802,11 @@ nxdomain:
if (type0 == DNS_TYPE_CNAME) {
BUILD_REPLY(sreply, so, buf, len, question, from, \
fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL), \
- aregion );
+ aregion, istcp);
reply_cname(&sreply);
} else if (type0 == DNS_TYPE_MX) {
BUILD_REPLY(sreply, so, buf, len, question, from, \
- fromlen, &sd0, NULL, aregion);
+ fromlen, &sd0, NULL, aregion, istcp);
reply_mx(&sreply);
break; /* must break here */
}
@@ -738,14 +815,14 @@ nxdomain:
case DNS_TYPE_SOA:
if (type0 == DNS_TYPE_SOA) {
BUILD_REPLY(sreply, so, buf, len, question, from, \
- fromlen, &sd0, NULL, aregion);
+ fromlen, &sd0, NULL, aregion, istcp);
reply_soa(&sreply);
}
break;
case DNS_TYPE_NS:
if (type0 == DNS_TYPE_NS) {
BUILD_REPLY(sreply, so, buf, len, question, from, \
- fromlen, &sd0, NULL, aregion);
+ fromlen, &sd0, NULL, aregion, istcp);
reply_ns(&sreply, db);
}
break;
@@ -754,7 +831,7 @@ nxdomain:
case DNS_TYPE_CNAME:
if (type0 == DNS_TYPE_CNAME) {
BUILD_REPLY(sreply, so, buf, len, question, from, \
- fromlen, &sd0, NULL, aregion);
+ fromlen, &sd0, NULL, aregion, istcp);
reply_cname(&sreply);
}
break;
@@ -763,11 +840,11 @@ nxdomain:
if (type0 == DNS_TYPE_CNAME) {
BUILD_REPLY(sreply, so, buf, len, question, from, \
fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL) \
- , aregion );
+ , aregion, istcp);
reply_cname(&sreply);
} else if (type0 == DNS_TYPE_PTR) {
BUILD_REPLY(sreply, so, buf, len, question, from,
- fromlen, &sd0, NULL, aregion);
+ fromlen, &sd0, NULL, aregion, istcp);
reply_ptr(&sreply);
break; /* must break here */
}
@@ -780,7 +857,7 @@ nxdomain:
*/
BUILD_REPLY(sreply, so, buf, len, question, from, \
- fromlen, NULL, NULL, aregion);
+ fromlen, NULL, NULL, aregion, istcp);
reply_notimpl(&sreply);
snprintf(replystring, DNS_MAXNAME, "NOTIMPL");
break;
@@ -1626,3 +1703,476 @@ get_dns_type(int dnstype)
return (type);
}
+/*
+ * TCPMAINLOOP - does the polling of tcp descriptors and if ready receives the
+ * requests, builds the question and calls for replies, loops
+ *
+ */
+
+void
+tcpmainloop(int *tcp, int sockcount, char **ident, DB *db)
+{
+ fd_set rset;
+ int sel;
+ int len;
+ int is_ipv6;
+ int i;
+ int istcp = 1;
+ int maxso;
+ int so;
+ int type0, type1;
+ int lzerrno;
+
+ u_int8_t aregion; /* region where the address comes from */
+
+ char *pbuf;
+ char address[INET6_ADDRSTRLEN];
+ char replystring[DNS_MAXNAME + 1];
+ char fakereplystring[DNS_MAXNAME + 1];
+
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } sockaddr_large;
+
+ int fromlen = sizeof(sockaddr_large);
+
+ struct sockaddr *from = (void *)&sockaddr_large;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+
+ struct dns_header *dh;
+ struct question *question, *fakequestion;
+ struct domain sd0, sd1;
+
+ struct sreply sreply;
+ struct timeval tv = { 10, 0};
+
+ int flag;
+
+ SLIST_INIT(&tcpshead);
+
+ /*
+ * set descriptors nonblocking, and listen on them
+ */
+
+ for (i = 0; i < sockcount; i++) {
+ if ((flag = fcntl(tcp[i], F_GETFL)) < 0) {
+ syslog(LOG_INFO, "fcntl: %m");
+ exit(1);
+ }
+ flag |= O_NONBLOCK;
+ if (fcntl(tcp[i], F_SETFL, &flag) < 0) {
+ syslog(LOG_INFO, "fcntl 2: %m");
+ exit(1);
+ }
+
+ listen(tcp[i], 5);
+ }
+
+ for (;;) {
+ is_ipv6 = 0;
+ maxso = 0;
+ /*
+ * check for timeouts
+ */
+
+ SLIST_FOREACH(tnp, &tcpshead, entries) {
+ if ((tnp->time + 10) < time(NULL)) {
+ free(tnp->input);
+ free(tnp->ident);
+ free(tnp->address);
+ close(tnp->so);
+ SLIST_REMOVE(&tcpshead, tnp, tcps, entries);
+ free(tnp);
+ }
+ }
+
+ FD_ZERO(&rset);
+ for (i = 0; i < sockcount; i++) {
+ if (maxso < tcp[i])
+ maxso = tcp[i];
+
+ FD_SET(tcp[i], &rset);
+ }
+
+ SLIST_FOREACH(tnp, &tcpshead, entries) {
+ if (maxso < tnp->so)
+ maxso = tnp->so;
+
+ FD_SET(tnp->so, &rset);
+ }
+
+ sel = select(maxso + 1, &rset, NULL, NULL, &tv);
+
+ if (sel < 0) {
+ syslog(LOG_INFO, "select: %m");
+ continue;
+ }
+
+ if (sel == 0) {
+ SLIST_FOREACH(tnp, &tcpshead, entries) {
+ if ((tnp->time + 10) < time(NULL)) {
+ free(tnp->input);
+ free(tnp->ident);
+ free(tnp->address);
+ close(tnp->so);
+ SLIST_REMOVE(&tcpshead, tnp, tcps, entries);
+ free(tnp);
+ }
+ }
+ continue;
+ }
+
+ for (i = 0; i < sockcount; i++) {
+ if (FD_ISSET(tcp[i], &rset)) {
+ fromlen = sizeof(sockaddr_large);
+
+ so = accept(tcp[i], (struct sockaddr*)from, &fromlen);
+
+ if (so < 0) {
+ syslog(LOG_INFO, "tcp accept: %m");
+ continue;
+ }
+
+ if (from->sa_family == AF_INET6) {
+ is_ipv6 = 1;
+
+ fromlen = sizeof(struct sockaddr_in6);
+ sin6 = (struct sockaddr_in6 *)from;
+ inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, (char *)&address, sizeof(address));
+ } else if (from->sa_family == AF_INET) {
+ is_ipv6 = 0;
+
+ fromlen = sizeof(struct sockaddr_in);
+ sin = (struct sockaddr_in *)from;
+ inet_ntop(AF_INET, (void *)&sin->sin_addr, (char *)&address, sizeof(address));
+ aregion = find_region(sin->sin_addr.s_addr);
+ } else {
+ syslog(LOG_INFO, "TCP packet received on descriptor %u interface \"%s\" had weird address family (%u), drop", so, ident[i], from->sa_family);
+ close(so);
+ continue;
+ }
+
+ /* fill the tcps struct */
+
+ tn1 = malloc(sizeof(struct tcps));
+ if (tn1 == NULL) {
+ syslog(LOG_INFO, "malloc: %m");
+ close(so);
+ continue;
+ }
+
+ tn1->input = (char *)malloc(0xffff + 2);
+ if (tn1->input == NULL) {
+ syslog(LOG_INFO, "tcp malloc 2: %m");
+ close(so);
+ continue;
+ }
+
+ tn1->offset = 0;
+ tn1->length = 0;
+ tn1->maxlen = 0xffff + 2;
+ tn1->so = so;
+ tn1->isv6 = is_ipv6;
+ tn1->ident = strdup(ident[i]);
+ tn1->address = strdup(address);
+ tn1->region = aregion;
+ tn1->time = time(NULL);
+
+ SLIST_INSERT_HEAD(&tcpshead, tn1, entries);
+
+ } /* FD_ISSET(); */
+ } /* if sockcount */
+
+ SLIST_FOREACH(tnp, &tcpshead, entries) {
+ if (FD_ISSET(tnp->so, &rset)) {
+
+ len = recv(tnp->so, tnp->input + tnp->offset, tnp->maxlen - tnp->offset, 0);
+ if (len < 0) {
+ if (errno == EWOULDBLOCK)
+ continue;
+ else {
+ free(tnp->input);
+ free(tnp->ident);
+ free(tnp->address);
+ close(tnp->so);
+ SLIST_REMOVE(&tcpshead, tnp, tcps, entries);
+ free(tnp);
+ continue;
+ }
+ } /* if len */
+
+ if (len == 0) {
+ free(tnp->input);
+ free(tnp->ident);
+ free(tnp->address);
+ close(tnp->so);
+ SLIST_REMOVE(&tcpshead, tnp, tcps, entries);
+ free(tnp);
+ continue;
+ }
+
+ tnp->offset += len;
+ tnp->time = time(NULL);
+
+ if (tnp->offset >= 2) {
+ tnp->length = ntohs(*((u_int16_t *) tnp->input));
+ }
+
+ /*
+ * only go on if the full packet was written
+ */
+
+ if (tnp->length + 2 != tnp->offset)
+ continue;
+
+ len = tnp->length;
+ pbuf = tnp->input + 2;
+
+ /* if UDP packet check length for minimum / maximum */
+ if (len > DNS_MAXUDP || len < sizeof(struct dns_header)){
+ syslog(LOG_INFO, "on descriptor %u interface \"%s\" illegal dns packet length from %s, drop", so, ident[i], tnp->address);
+ goto drop;
+ }
+
+ dh = (struct dns_header *)&pbuf[0];
+
+ /* check if we're a question or reply, drop replies */
+ if ((ntohs(dh->query) & DNS_REPLY)) {
+ syslog(LOG_INFO, "on descriptor %u interface \"%s\" dns header from %s is not a question, drop", so, ident[i], tnp->address);
+ goto drop;
+ }
+
+ /*
+ * if questions aren't exactly 1 then drop
+ */
+
+ if (ntohs(dh->question) != 1) {
+ syslog(LOG_INFO, "on descriptor %u interface \"%s\" header from %s has no question, drop", so, ident[i], tnp->address);
+
+ /* format error */
+ BUILD_REPLY(sreply, so, pbuf, len, NULL, from, fromlen, NULL, NULL, tnp->region, istcp);
+ reply_fmterror(&sreply);
+ syslog(LOG_INFO, "question on descriptor %d interface \"%s\" from %s, did not have question of 1 replying format error", so, ident[i], tnp->address);
+ goto drop;
+ }
+
+
+ if ((question = build_question(pbuf, len)) == NULL) {
+ syslog(LOG_INFO, "on descriptor %u interface \"%s\" malformed question from %s, drop", so, ident[i], tnp->address);
+ goto drop;
+ }
+
+ /* goto drop beyond this point should goto out instead */
+ fakequestion = NULL;
+
+ if ((type0 = lookup_zone(db, question, &sd0, &lzerrno, (char *)&replystring)) < 0) {
+ switch (lzerrno) {
+ default:
+ syslog(LOG_INFO, "invalid lzerrno! dropping");
+ /* FALLTHROUGH */
+ case ERR_DROP:
+ snprintf(replystring, DNS_MAXNAME, "DROP");
+ goto out;
+
+ case ERR_NXDOMAIN:
+ goto nxdomain;
+ case ERR_NOERROR:
+ /*
+ * this is hackish not sure if this should be here
+ */
+
+ snprintf(replystring, DNS_MAXNAME, "NOERROR");
+
+ /*
+ * lookup an authoritative soa
+ */
+
+ memset(&sd0, 0, sizeof(sd0));
+ (void)get_soa(db, question, &sd0);
+
+ BUILD_REPLY(sreply, so, pbuf, len, question, from, \
+ fromlen, &sd0, NULL, tnp->region, istcp);
+
+ reply_noerror(&sreply);
+ goto out;
+
+ }
+ }
+
+
+ switch (type0) {
+ case 0:
+ /*
+ * lookup_zone could not find an RR for the
+ * question at all -> nxdomain
+ */
+nxdomain:
+ snprintf(replystring, DNS_MAXNAME, "NXDOMAIN");
+
+ /*
+ * lookup an authoritative soa
+ */
+
+ memset(&sd0, 0, sizeof(sd0));
+ (void)get_soa(db, question, &sd0);
+
+ BUILD_REPLY(sreply, so, pbuf, len, question, from, \
+ fromlen, &sd0, NULL, tnp->region, istcp);
+ reply_nxdomain(&sreply);
+ goto out;
+ case DNS_TYPE_CNAME:
+ fakequestion = build_fake_question(sd0.cname, sd0.cnamelen, question->hdr->qtype);
+ if (fakequestion == NULL) {
+ syslog(LOG_INFO, "fakequestion failed");
+ break;
+ }
+
+ type1 = lookup_zone(db, fakequestion, &sd1, &lzerrno, (char *)&fakereplystring);
+ /* break CNAMES pointing to CNAMES */
+ if (type1 == DNS_TYPE_CNAME)
+ type1 = 0;
+
+ break;
+ default:
+
+ break;
+ }
+
+ /*
+ * Allow CLASS IN, CHAOS and others are
+ * not implemented and so we build a reply for
+ * that and go out.
+ */
+
+ switch (ntohs(question->hdr->qclass)) {
+ case DNS_CLASS_IN:
+ break;
+ default:
+ BUILD_REPLY(sreply, so, pbuf, len, question, from, \
+ fromlen, NULL, NULL, tnp->region, istcp);
+ reply_notimpl(&sreply);
+ snprintf(replystring, DNS_MAXNAME, "NOTIMPL");
+ goto out;
+ }
+
+ switch (ntohs(question->hdr->qtype)) {
+ case DNS_TYPE_A:
+ if (type0 == DNS_TYPE_CNAME) {
+ BUILD_REPLY(sreply, so, pbuf, len, question, from, \
+ fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL), \
+ tnp->region, istcp);
+ reply_cname(&sreply);
+ } else if (type0 == DNS_TYPE_A) {
+ BUILD_REPLY(sreply, so, pbuf, len, question, from, \
+ fromlen, &sd0, NULL, tnp->region, istcp);
+ reply_a(&sreply, db);
+ break; /* must break here */
+ }
+
+ break;
+ case DNS_TYPE_AAAA:
+
+ if (type0 == DNS_TYPE_CNAME) {
+ BUILD_REPLY(sreply, so, pbuf, len, question, from, \
+ fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL), \
+ tnp->region, istcp);
+ reply_cname(&sreply);
+ } else if (type0 == DNS_TYPE_AAAA) {
+ BUILD_REPLY(sreply, so, pbuf, len, question, from,
+ fromlen, &sd0, NULL, tnp->region, istcp);
+ reply_aaaa(&sreply, db);
+ break; /* must break here */
+ }
+
+ break;
+ case DNS_TYPE_MX:
+
+ if (type0 == DNS_TYPE_CNAME) {
+ BUILD_REPLY(sreply, so, pbuf, len, question, from, \
+ fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL), \
+ tnp->region, istcp);
+ reply_cname(&sreply);
+ } else if (type0 == DNS_TYPE_MX) {
+ BUILD_REPLY(sreply, so, pbuf, len, question, from, \
+ fromlen, &sd0, NULL, tnp->region, istcp);
+ reply_mx(&sreply);
+ break; /* must break here */
+ }
+
+ break;
+ case DNS_TYPE_SOA:
+ if (type0 == DNS_TYPE_SOA) {
+ BUILD_REPLY(sreply, so, pbuf, len, question, from, \
+ fromlen, &sd0, NULL, tnp->region, istcp);
+ reply_soa(&sreply);
+ }
+ break;
+ case DNS_TYPE_NS:
+ if (type0 == DNS_TYPE_NS) {
+ BUILD_REPLY(sreply, so, pbuf, len, question, from, \
+ fromlen, &sd0, NULL, tnp->region, istcp);
+ reply_ns(&sreply, db);
+ }
+ break;
+
+
+ case DNS_TYPE_CNAME:
+ if (type0 == DNS_TYPE_CNAME) {
+ BUILD_REPLY(sreply, so, pbuf, len, question, from, \
+ fromlen, &sd0, NULL, tnp->region, istcp);
+ reply_cname(&sreply);
+ }
+ break;
+
+ case DNS_TYPE_PTR:
+ if (type0 == DNS_TYPE_CNAME) {
+ BUILD_REPLY(sreply, so, pbuf, len, question, from, \
+ fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL) \
+ , tnp->region, istcp);
+ reply_cname(&sreply);
+ } else if (type0 == DNS_TYPE_PTR) {
+ BUILD_REPLY(sreply, so, pbuf, len, question, from,
+ fromlen, &sd0, NULL, tnp->region, istcp);
+ reply_ptr(&sreply);
+ break; /* must break here */
+ }
+ break;
+
+ default:
+
+ /*
+ * ANY unkown RR TYPE gets a NOTIMPL
+ */
+
+ BUILD_REPLY(sreply, so, pbuf, len, question, from, \
+ fromlen, NULL, NULL, tnp->region, istcp);
+ reply_notimpl(&sreply);
+ snprintf(replystring, DNS_MAXNAME, "NOTIMPL");
+ break;
+ }
+
+ out:
+ if (lflag)
+ syslog(LOG_INFO, "request on descriptor %u interface \"%s\" from %s (ttl=TCP, region=%d) for \"%s\" type=%s class=%u, answering \"%s\"", so, tnp->ident, tnp->address, tnp->region, question->converted_name, get_dns_type(ntohs(question->hdr->qtype)), ntohs(question->hdr->qclass), replystring);
+
+
+ if (fakequestion != NULL) {
+ free_question(fakequestion);
+ }
+
+ free_question(question);
+
+ } /* END ISSET */
+
+ } /* for */
+
+ drop:
+
+ continue;
+ }
+
+ /* NOTREACHED */
+}
blob - 83ae012445f37e081607a81502822d3ab7c7ab4d
blob + cb134eb4a855f259b0fd92835370a67522326f7d
--- reply.c
+++ reply.c
@@ -49,7 +49,7 @@ extern int additional_ptr(char *, int, struct domain *
void update_db(DB *, struct domain *);
-static const char rcsid[] = "$Id: reply.c,v 1.12 2010/03/09 15:38:22 pbug Exp $";
+static const char rcsid[] = "$Id: reply.c,v 1.13 2010/03/12 21:11:27 pbug Exp $";
/*
* REPLY_A() - replies a DNS question (*q) on socket (so)
@@ -65,6 +65,7 @@ reply_a(struct sreply *sreply, DB *db)
int a_count;
int mod, pos;
int ttlhack = 0;
+ u_int16_t *plen;
struct answer {
char name[2];
@@ -86,19 +87,28 @@ reply_a(struct sreply *sreply, DB *db)
struct domain *sd = sreply->sd1;
u_int8_t region = sreply->region;
+ int istcp = sreply->istcp;
#if 0
memset(&reply, 0, sizeof(reply));
#endif
- odh = (struct dns_header *)&reply[0];
+ if (istcp) {
+ plen = (u_int16_t *)&reply[0];
+ odh = (struct dns_header *)&reply[2];
+ } else
+ 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);
+ if (istcp) {
+ memcpy(&reply[2], buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
+ } else
+ 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);
@@ -114,8 +124,12 @@ reply_a(struct sreply *sreply, DB *db)
odh->additional = 0;
/* skip dns header, question name, qtype and qclass */
- answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
+ if (istcp)
+ answer = (struct answer *)(&reply[2] + sizeof(struct dns_header) +
q->hdr->namelen + 4);
+ else
+ answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
+ q->hdr->namelen + 4);
/* if we aren't a balance record our region code is 0xff so check */
if (sd->region[sd->a_ptr] != 0xff) {
@@ -170,10 +184,18 @@ reply_a(struct sreply *sreply, DB *db)
odh->answer = ntohs(a_count);
}
+ if (istcp)
+ *plen = htons(outlen);
out:
- if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
- syslog(LOG_INFO, "sendto: %m");
+ if (istcp) {
+ if (send(so, reply, outlen + 2, 0) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
+ } else {
+ if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
}
/*
@@ -200,6 +222,7 @@ reply_aaaa(struct sreply *sreply, DB *db)
int outlen;
int aaaa_count;
int mod, pos;
+ u_int16_t *plen;
struct answer {
char name[2];
@@ -219,20 +242,29 @@ reply_aaaa(struct sreply *sreply, DB *db)
struct sockaddr *sa = sreply->sa;
int salen = sreply->salen;
struct domain *sd = sreply->sd1;
+ int istcp = sreply->istcp;
#if 0
memset(&reply, 0, sizeof(reply));
#endif
- odh = (struct dns_header *)&reply[0];
+ if (istcp) {
+ plen = (u_int16_t *)&reply[0];
+ odh = (struct dns_header *)&reply[2];
+ } else
+ 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);
+ if (istcp) {
+ memcpy(&reply[2], buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
+ } else
+ 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);
@@ -248,8 +280,13 @@ reply_aaaa(struct sreply *sreply, DB *db)
odh->additional = 0;
/* skip dns header, question name, qtype and qclass */
- answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
- q->hdr->namelen + 4);
+ if (istcp)
+ answer = (struct answer *)(&reply[2] + sizeof(struct dns_header) +
+ q->hdr->namelen + 4);
+ else
+ answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
+ q->hdr->namelen + 4);
+
aaaa_count = 0;
pos = sd->aaaa_ptr;
@@ -282,8 +319,16 @@ reply_aaaa(struct sreply *sreply, DB *db)
} while (aaaa_count < 10 && --sd->aaaa_count);
out:
- if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
- syslog(LOG_INFO, "sendto: %m");
+ if (istcp) {
+ *plen = htons(outlen);
+
+ if (send(so, reply, outlen + 2, 0) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
+ } else {
+ if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
}
sd->aaaa_ptr = (sd->aaaa_ptr + 1) % mod;
@@ -305,6 +350,7 @@ reply_mx(struct sreply *sreply)
struct dns_header *odh;
int outlen;
int mx_count;
+ u_int16_t *plen;
struct answer {
char name[2];
@@ -325,16 +371,25 @@ reply_mx(struct sreply *sreply)
struct sockaddr *sa = sreply->sa;
int salen = sreply->salen;
struct domain *sd = sreply->sd1;
+ int istcp = sreply->istcp;
- odh = (struct dns_header *)&reply[0];
+ if (istcp) {
+ plen = (u_int16_t *)&reply[0];
+ odh = (struct dns_header *)&reply[2];
+ } else
+ 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);
+ if (istcp) {
+ memcpy(&reply[2], buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
+ } else
+ 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);
@@ -350,8 +405,12 @@ reply_mx(struct sreply *sreply)
odh->additional = 0;
/* skip dns header, question name, qtype and qclass */
- answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
+ if (istcp) {
+ answer = (struct answer *)(&reply[2] + sizeof(struct dns_header) +
q->hdr->namelen + 4);
+ } else
+ answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
+ q->hdr->namelen + 4);
mx_count = 0;
do {
@@ -380,8 +439,15 @@ reply_mx(struct sreply *sreply)
} while (++mx_count < 10 && --sd->mx_count);
out:
- if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
- syslog(LOG_INFO, "sendto: %m");
+ if (istcp) {
+ *plen = htons(outlen);
+ if (send(so, reply, outlen + 2, 0) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
+ } else {
+ if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
}
return;
@@ -400,6 +466,7 @@ reply_ns(struct sreply *sreply, DB *db)
int outlen;
int ns_count;
int mod, pos;
+ u_int16_t *plen;
struct answer {
char name[2];
@@ -419,19 +486,29 @@ reply_ns(struct sreply *sreply, DB *db)
struct sockaddr *sa = sreply->sa;
int salen = sreply->salen;
struct domain *sd = sreply->sd1;
+ int istcp = sreply->istcp;
#if 0
memset(&reply, 0, sizeof(reply));
#endif
- odh = (struct dns_header *)&reply[0];
+ if (istcp) {
+ plen = (u_int16_t *)&reply[0];
+ odh = (struct dns_header *)&reply[2];
+ } else
+ 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);
+ if (istcp) {
+ memcpy(&reply[2], buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
+ } else
+ 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);
@@ -447,7 +524,11 @@ reply_ns(struct sreply *sreply, DB *db)
odh->additional = 0;
/* skip dns header, question name, qtype and qclass */
- answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
+ if (istcp) {
+ answer = (struct answer *)(&reply[2] + sizeof(struct dns_header) +
+ q->hdr->namelen + 4);
+ } else
+ answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
q->hdr->namelen + 4);
ns_count = 0;
@@ -482,8 +563,15 @@ reply_ns(struct sreply *sreply, DB *db)
} while (++ns_count < 10 && --sd->ns_count);
out:
- if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
- syslog(LOG_INFO, "sendto: %m");
+ if (istcp) {
+ *plen = htons(outlen);
+ if (send(so, reply, outlen + 2, 0) < 0) {
+ syslog(LOG_INFO, "send: %m");
+ }
+ } else {
+ if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
}
sd->ns_ptr = (sd->ns_ptr + 1) % mod;
@@ -512,6 +600,7 @@ reply_cname(struct sreply *sreply)
int labellen;
char *label, *plabel;
int addcount;
+ u_int16_t *plen;
struct answer {
char name[2];
@@ -532,6 +621,7 @@ reply_cname(struct sreply *sreply)
int salen = sreply->salen;
struct domain *sd = sreply->sd1;
struct domain *sd1 = sreply->sd2;
+ int istcp = sreply->istcp;
odh = (struct dns_header *)&reply[0];
@@ -543,6 +633,7 @@ reply_cname(struct sreply *sreply)
/* copy question to reply */
memcpy(&reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
+
/* blank query */
memset((char *)&odh->query, 0, sizeof(u_int16_t));
@@ -597,8 +688,10 @@ reply_cname(struct sreply *sreply)
answer->rdlength = htons(&reply[outlen] - &answer->rdata);
+
if (ntohs(q->hdr->qtype) == DNS_TYPE_A && sd1 != NULL) {
tmplen = additional_a(sd->cname, sd->cnamelen, sd1, reply, sizeof(reply), outlen, &addcount);
+
if (tmplen > 0)
outlen = tmplen;
@@ -607,6 +700,7 @@ reply_cname(struct sreply *sreply)
HTONS(odh->answer);
} else if (ntohs(q->hdr->qtype) == DNS_TYPE_AAAA && sd1 != NULL) {
tmplen = additional_aaaa(sd->cname, sd->cnamelen, sd1, reply, sizeof(reply), outlen, &addcount);
+
if (tmplen > 0)
outlen = tmplen;
@@ -615,6 +709,7 @@ reply_cname(struct sreply *sreply)
HTONS(odh->answer);
} else if (ntohs(q->hdr->qtype) == DNS_TYPE_MX && sd1 != NULL) {
tmplen = additional_mx(sd->cname, sd->cnamelen, sd1, reply, sizeof(reply), outlen, &addcount);
+
if (tmplen > 0)
outlen = tmplen;
@@ -623,6 +718,7 @@ reply_cname(struct sreply *sreply)
HTONS(odh->answer);
} else if (ntohs(q->hdr->qtype) == DNS_TYPE_PTR && sd1 != NULL) {
tmplen = additional_ptr(sd->cname, sd->cnamelen, sd1, reply, sizeof(reply), outlen, &addcount);
+
if (tmplen > 0)
outlen = tmplen;
@@ -630,9 +726,27 @@ reply_cname(struct sreply *sreply)
odh->answer += addcount;
HTONS(odh->answer);
}
-
- if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
- syslog(LOG_INFO, "sendto: %m");
+
+ 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;
@@ -672,6 +786,7 @@ reply_ptr(struct sreply *sreply)
struct sockaddr *sa = sreply->sa;
int salen = sreply->salen;
struct domain *sd = sreply->sd1;
+ int istcp = sreply->istcp;
odh = (struct dns_header *)&reply[0];
outlen = sizeof(struct dns_header);
@@ -737,8 +852,27 @@ reply_ptr(struct sreply *sreply)
answer->rdlength = htons(&reply[outlen] - &answer->rdata);
- if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
- syslog(LOG_INFO, "sendto: %m");
+ if (istcp) {
+ char *tmpbuf;
+ u_int16_t *plen;
+
+ 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;
@@ -791,6 +925,7 @@ reply_soa(struct sreply *sreply)
struct sockaddr *sa = sreply->sa;
int salen = sreply->salen;
struct domain *sd = sreply->sd1;
+ int istcp = sreply->istcp;
#if 0
struct soa mysoa = { "neptune.solarsail.org.", "pbug.neptune.solarsail.org", 1, 3600, 1800, (14 * 24 * 3600), 0xffffffff };
@@ -930,8 +1065,27 @@ reply_soa(struct sreply *sreply)
answer->rdlength = htons(&reply[outlen] - &answer->rdata);
- if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
- syslog(LOG_INFO, "sendto: %m");
+ if (istcp) {
+ char *tmpbuf;
+ u_int16_t *plen;
+
+ 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;
@@ -948,26 +1102,37 @@ reply_notimpl(struct sreply *sreply)
char reply[512];
struct dns_header *odh;
int outlen;
+ u_int16_t *plen;
int so = sreply->so;
char *buf = sreply->buf;
int len = sreply->len;
struct sockaddr *sa = sreply->sa;
int salen = sreply->salen;
+ int istcp = sreply->istcp;
#if 0
struct domain *sd = sreply->sd1;
struct question *q = sreply->q;
#endif
- odh = (struct dns_header *)&reply[0];
+ if (istcp) {
+ plen = (u_int16_t *)&reply[0];
+ odh = (struct dns_header *)&reply[2];
+ } else
+ odh = (struct dns_header *)&reply[0];
+
outlen = sizeof(struct dns_header);
if (len > sizeof(reply)) {
return;
}
- memcpy(&reply, buf, len);
+ if (istcp) {
+ memcpy(&reply[2], buf, len);
+ } else
+ memcpy(&reply, buf, len);
+
memset((char *)&odh->query, 0, sizeof(u_int16_t));
SET_DNS_REPLY(odh);
@@ -975,8 +1140,15 @@ reply_notimpl(struct sreply *sreply)
HTONS(odh->query);
- if (sendto(so, reply, len, 0, sa, salen) < 0) {
- syslog(LOG_INFO, "sendto: %m");
+ if (istcp) {
+ *plen = htons(len);
+ if (send(so, reply, len + 2, 0) < 0) {
+ syslog(LOG_INFO, "send: %m");
+ }
+ } else {
+ if (sendto(so, reply, len, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
}
return;
@@ -1028,6 +1200,7 @@ reply_nxdomain(struct sreply *sreply)
struct sockaddr *sa = sreply->sa;
int salen = sreply->salen;
struct domain *sd = sreply->sd1;
+ int istcp = sreply->istcp;
odh = (struct dns_header *)&reply[0];
outlen = sizeof(struct dns_header);
@@ -1050,9 +1223,27 @@ reply_nxdomain(struct sreply *sreply)
SET_DNS_RCODE_NAMEERR(odh);
HTONS(odh->query);
+ if (istcp) {
+ char *tmpbuf;
+ u_int16_t *plen;
- if (sendto(so, reply, len, 0, sa, salen) < 0) {
- syslog(LOG_INFO, "sendto: %m");
+ tmpbuf = malloc(len + 2);
+ if (tmpbuf == NULL) {
+ syslog(LOG_INFO, "malloc: %m");
+ }
+ plen = (u_int16_t *)tmpbuf;
+ *plen = htons(len);
+
+ memcpy(&tmpbuf[2], reply, len);
+
+ if (send(so, tmpbuf, len + 2, 0) < 0) {
+ syslog(LOG_INFO, "send: %m");
+ }
+ free(tmpbuf);
+ } else {
+ if (sendto(so, reply, len, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
}
return;
@@ -1181,8 +1372,27 @@ reply_nxdomain(struct sreply *sreply)
answer->rdlength = htons(&reply[outlen] - &answer->rdata);
- if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
- syslog(LOG_INFO, "sendto: %m");
+ if (istcp) {
+ char *tmpbuf;
+ u_int16_t *plen;
+
+ 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;
@@ -1199,15 +1409,23 @@ reply_fmterror(struct sreply *sreply)
char reply[512];
struct dns_header *odh;
int outlen;
+ u_int16_t *plen;
int so = sreply->so;
int len = sreply->len;
char *buf = sreply->buf;
struct sockaddr *sa = sreply->sa;
int salen = sreply->salen;
+ int istcp = sreply->istcp;
memset(&reply, 0, sizeof(reply));
- odh = (struct dns_header *)&reply[0];
+
+ if (istcp) {
+ plen = (u_int16_t *)&reply[0];
+ odh = (struct dns_header *)&reply[2];
+ } else
+ odh = (struct dns_header *)&reply[0];
+
outlen = sizeof(struct dns_header);
if (len > sizeof(reply)) {
@@ -1222,8 +1440,15 @@ reply_fmterror(struct sreply *sreply)
HTONS(odh->query);
- if (sendto(so, reply, sizeof(struct dns_header), 0, sa, salen) < 0) {
- syslog(LOG_INFO, "sendto: %m");
+ if (istcp) {
+ *plen = htons(sizeof(struct dns_header));
+ if (send(so, reply, *plen + 2, 0) < 0) {
+ syslog(LOG_INFO, "send: %m");
+ }
+ } else {
+ if (sendto(so, reply, sizeof(struct dns_header), 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
}
return;
@@ -1276,6 +1501,7 @@ reply_noerror(struct sreply *sreply)
struct sockaddr *sa = sreply->sa;
int salen = sreply->salen;
struct domain *sd = sreply->sd1;
+ int istcp = sreply->istcp;
odh = (struct dns_header *)&reply[0];
outlen = sizeof(struct dns_header);
@@ -1301,8 +1527,27 @@ reply_noerror(struct sreply *sreply)
HTONS(odh->query);
- if (sendto(so, reply, len, 0, sa, salen) < 0) {
- syslog(LOG_INFO, "sendto: %m");
+ if (istcp) {
+ char *tmpbuf;
+ u_int16_t *plen;
+
+ tmpbuf = malloc(len + 2);
+ if (tmpbuf == NULL) {
+ syslog(LOG_INFO, "malloc: %m");
+ }
+ plen = (u_int16_t *)tmpbuf;
+ *plen = htons(len);
+
+ memcpy(&tmpbuf[2], reply, len);
+
+ if (send(so, tmpbuf, len + 2, 0) < 0) {
+ syslog(LOG_INFO, "send: %m");
+ }
+ free(tmpbuf);
+ } else {
+ if (sendto(so, reply, len, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
}
return;
@@ -1433,8 +1678,27 @@ reply_noerror(struct sreply *sreply)
answer->rdlength = htons(&reply[outlen] - &answer->rdata);
- if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
- syslog(LOG_INFO, "sendto: %m");
+ if (istcp) {
+ char *tmpbuf;
+ u_int16_t *plen;
+
+ 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;
repomaster@centroid.eu