pkgsrc/net/djbdns/files/patch-qmerge2
schmonz c85aed0869 Add DJB's patch to fix the axfrdns bug reported by Matthew Dempsky,
described here:

http://article.gmane.org/gmane.network.djbdns/13864

Add mutually exclusive options, both by Jeff King, to address the
dnscache poisoning weaknesses described in CVE-2008-4392:

* "djbdns-qmerge1" (from http://www.your.org/dnscache/)
* "djbdns-qmerge2" (from http://article.gmane.org/gmane.network.djbdns/13965)

Both options are included because qmerge1 is better tested but has
known shortcomings, while qmerge2 is probably more correct but (as
yet) less well tested.

Bump PKGREVISION.
2009-04-22 04:48:13 +00:00

254 lines
6.6 KiB
Text

--- clients.h.orig 2009-04-21 23:43:02.000000000 -0400
+++ clients.h
@@ -0,0 +1,7 @@
+#ifndef CLIENTS_H
+#define CLIENTS_H
+
+#define MAXUDP 200
+#define MAXTCP 20
+
+#endif /* CLIENTS_H */
--- dns.h.orig 2001-02-11 16:11:45.000000000 -0500
+++ dns.h
@@ -4,6 +4,7 @@
#include "stralloc.h"
#include "iopause.h"
#include "taia.h"
+#include "clients.h"
#define DNS_C_IN "\0\1"
#define DNS_C_ANY "\0\377"
@@ -37,8 +38,14 @@ struct dns_transmit {
const char *servers;
char localip[4];
char qtype[2];
+ struct dns_transmit *master;
+ struct dns_transmit *slaves[MAXUDP];
+ int nslaves;
} ;
+extern void dns_enable_merge(void (*logger)(const char *, const char *,
+ const char *));
+
extern void dns_random_init(const char *);
extern unsigned int dns_random(unsigned int);
--- dns_transmit.c.orig 2001-02-11 16:11:45.000000000 -0500
+++ dns_transmit.c
@@ -7,6 +7,61 @@
#include "byte.h"
#include "uint16.h"
#include "dns.h"
+#include "strerr.h"
+
+static int merge_enable;
+static void (*merge_logger)(const char *, const char *, const char *);
+void dns_enable_merge(void (*f)(const char *, const char *, const char *))
+{
+ merge_enable = 1;
+ merge_logger = f;
+}
+
+static int merge_equal(struct dns_transmit *a, struct dns_transmit *b)
+{
+ const char *ip1 = a->servers + 4 * a->curserver;
+ const char *ip2 = b->servers + 4 * b->curserver;
+ return
+ byte_equal(ip1, 4, ip2) &&
+ byte_equal(a->qtype, 2, b->qtype) &&
+ dns_domain_equal(a->query + 14, b->query + 14);
+}
+
+struct dns_transmit *inprogress[MAXUDP];
+
+static int try_merge(struct dns_transmit *d)
+{
+ int i;
+ for (i = 0; i < MAXUDP; i++) {
+ if (!inprogress[i]) continue;
+ if (!merge_equal(d, inprogress[i])) continue;
+ d->master = inprogress[i];
+ inprogress[i]->slaves[inprogress[i]->nslaves++] = d;
+ return 1;
+ }
+ return 0;
+}
+
+static void register_inprogress(struct dns_transmit *d)
+{
+ int i;
+ for (i = 0; i < MAXUDP; i++) {
+ if (!inprogress[i]) {
+ inprogress[i] = d;
+ return;
+ }
+ }
+ strerr_die1x(100, "BUG: out of inprogress slots");
+}
+
+static void unregister_inprogress(struct dns_transmit *d)
+{
+ int i;
+ for (i = 0; i < MAXUDP; i++) {
+ if (inprogress[i] == d)
+ inprogress[i] = 0;
+ }
+}
static int serverwantstcp(const char *buf,unsigned int len)
{
@@ -59,8 +114,28 @@ static void packetfree(struct dns_transm
d->packet = 0;
}
+static void mergefree(struct dns_transmit *d)
+{
+ int i;
+ if (merge_enable)
+ unregister_inprogress(d);
+ /* unregister us from our master */
+ if (d->master) {
+ for (i = 0; i < d->master->nslaves; i++)
+ if (d->master->slaves[i] == d)
+ d->master->slaves[i] = 0;
+ }
+ /* and unregister all of our slaves from us */
+ for (i = 0; i < d->nslaves; i++) {
+ if (d->slaves[i])
+ d->slaves[i]->master = NULL;
+ }
+ d->nslaves = 0;
+}
+
static void queryfree(struct dns_transmit *d)
{
+ mergefree(d);
if (!d->query) return;
alloc_free(d->query);
d->query = 0;
@@ -99,11 +174,18 @@ static int thisudp(struct dns_transmit *
const char *ip;
socketfree(d);
+ mergefree(d);
while (d->udploop < 4) {
for (;d->curserver < 16;++d->curserver) {
ip = d->servers + 4 * d->curserver;
if (byte_diff(ip,4,"\0\0\0\0")) {
+ if (merge_enable && try_merge(d)) {
+ if (merge_logger)
+ merge_logger(ip, d->qtype, d->query + 14);
+ return 0;
+ }
+
d->query[2] = dns_random(256);
d->query[3] = dns_random(256);
@@ -118,6 +200,8 @@ static int thisudp(struct dns_transmit *
taia_uint(&d->deadline,timeouts[d->udploop]);
taia_add(&d->deadline,&d->deadline,&now);
d->tcpstate = 0;
+ if (merge_enable)
+ register_inprogress(d);
return 0;
}
@@ -226,8 +310,12 @@ void dns_transmit_io(struct dns_transmit
x->fd = d->s1 - 1;
switch(d->tcpstate) {
- case 0: case 3: case 4: case 5:
- x->events = IOPAUSE_READ;
+ case 0:
+ if (d->master) return;
+ if (d->packet) { taia_now(deadline); return; }
+ /* otherwise, fall through */
+ case 3: case 4: case 5:
+ x->events = IOPAUSE_READ;
break;
case 1: case 2:
x->events = IOPAUSE_WRITE;
@@ -244,10 +332,14 @@ int dns_transmit_get(struct dns_transmit
unsigned char ch;
int r;
int fd;
+ int i;
errno = error_io;
fd = d->s1 - 1;
+ if (d->tcpstate == 0 && d->master) return 0;
+ if (d->tcpstate == 0 && d->packet) return 1;
+
if (!x->revents) {
if (taia_less(when,&d->deadline)) return 0;
errno = error_timeout;
@@ -279,6 +371,15 @@ have sent query to curserver on UDP sock
d->packet = alloc(d->packetlen);
if (!d->packet) { dns_transmit_free(d); return -1; }
byte_copy(d->packet,d->packetlen,udpbuf);
+
+ for (i = 0; i < d->nslaves; i++) {
+ if (!d->slaves[i]) continue;
+ d->slaves[i]->packetlen = d->packetlen;
+ d->slaves[i]->packet = alloc(d->packetlen);
+ if (!d->slaves[i]->packet) { dns_transmit_free(d->slaves[i]); continue; }
+ byte_copy(d->slaves[i]->packet,d->packetlen,udpbuf);
+ }
+
queryfree(d);
return 1;
}
--- dnscache.c.orig 2001-02-11 16:11:45.000000000 -0500
+++ dnscache.c
@@ -54,7 +54,6 @@ uint64 numqueries = 0;
static int udp53;
-#define MAXUDP 200
static struct udpclient {
struct query q;
struct taia start;
@@ -131,7 +130,6 @@ void u_new(void)
static int tcp53;
-#define MAXTCP 20
struct tcpclient {
struct query q;
struct taia start;
@@ -435,6 +433,8 @@ int main()
response_hidettl();
if (env_get("FORWARDONLY"))
query_forwardonly();
+ if (env_get("MERGEQUERIES"))
+ dns_enable_merge(log_merge);
if (!roots_init())
strerr_die2sys(111,FATAL,"unable to read servers: ");
--- log.c.orig 2001-02-11 16:11:45.000000000 -0500
+++ log.c
@@ -150,6 +150,12 @@ void log_tx(const char *q,const char qty
line();
}
+void log_merge(const char *addr, const char qtype[2], const char *q)
+{
+ string("merge "); ip(addr); space(); logtype(qtype); space(); name(q);
+ line();
+}
+
void log_cachedanswer(const char *q,const char type[2])
{
string("cached "); logtype(type); space();
--- log.h.orig 2001-02-11 16:11:45.000000000 -0500
+++ log.h
@@ -18,6 +18,7 @@ extern void log_cachednxdomain(const cha
extern void log_cachedns(const char *,const char *);
extern void log_tx(const char *,const char *,const char *,const char *,unsigned int);
+extern void log_merge(const char *, const char *, const char *);
extern void log_nxdomain(const char *,const char *,unsigned int);
extern void log_nodata(const char *,const char *,const char *,unsigned int);