source: npl/internetserver/djbdns/patches/0007-dnscache-merge-similar-outgoing-udp-packets.patch @ 26ffad7

Last change on this file since 26ffad7 was 37aaf89, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

djbdns patches, so it works correctly with twitter etc

  • Property mode set to 100644
File size: 9.6 KB
  • new file clients.h

    Description: dnscache: merge similar outgoing udp packets
     This patch takes a slightly different approach to merging
     than the previous qmerge patch: rather than merging between
     the "query" and "dns_transmit" layers, it actually
     incorporates the merging into the dns_transmit layer.
     .
     This makes it a much more invasive and messy patch, but
     means that it should correctly handle all situations
     (in particular, ones where sending to two different IPs will
     gives different results, generally because one server is
     down or lame).
     .
     The general strategy is this:
     .
       - when a dns_transmit is about to send() a UDP query, it
         checks for an equivalent inprogress query.
     .
         If it finds one, it marks the inprogress dns_transmit as
         its "master", and itself as a "slave" of the master.
     .
         If it doesn't, it sends the packet and registers itself
         as inprogress.
     .
       - when a dns_transmit recv()s a UDP packet, it creates a
         copy of the packet for each of its slaves
     .
     Two outgoing packets are considered equivalent if:
     .
       1. they are going to the same IP
       2. they have the same qtype
       3. they have the same qname
     .
     Because this change affects the dns library itself, this
     change can potentially affect not just dnscache, but all of
     the diagnostic tools. To address this, merging must be
     enabled explicitly by the caller; dnscache will enable
     merging if the MERGEQUERIES environment variable is set.
     .
     I tried to keep the patch as small and simple as possible so
     that its correctness could be verified by readers.  There
     are a few places where performance might benefit from making
     it more complex:
     .
       - dns_transmit now knows the value of MAXUDP, since it is
         an upper bound on the number of slaves and inprogress
         queries. As a result:
     .
           - each non-merging program which uses the dns library
             wastes MAXUDP*sizeof(pointer) bytes of static memory
             for the inprogress list
     .
           - each dns_transmit uses an extra MAXUDP*sizeof(pointer)
             bytes for its slaves list. For dnscache, this
             translates to 160K total on a 32-bit platform with
             default MAXUDP.
     .
         Both could be avoided by using dynamic allocation.
     .
       - We have to do an O(MAXUDP) linear search to find similar
         inprogress queries (non-merge-enabled users of the
         library avoid paying this price, though).
     .
         This could be avoided by using a data structure with a
         fast key lookup for inprogress.
     .
     This patch is only lightly tested. Use on production servers at your own
     risk (and please report to the list if you have success using it).
    Author: Jeff King <peff () peff ! net>
    Date: Wed, 1 Apr 2009 14:10:54 +0000
    Debian-Bug: https://bugs.debian.org/516394
    Last-Update: 2020-07-26
    
    diff --git a/clients.h b/clients.h
    new file mode 100644
    index 0000000..983a4ad
    - +  
     1#ifndef CLIENTS_H
     2#define CLIENTS_H
     3
     4#define MAXUDP 200
     5#define MAXTCP 20
     6
     7#endif /* CLIENTS_H */
  • dns.h

    diff --git a/dns.h b/dns.h
    index 3849f4c..d1e2ffc 100644
    a b  
    44#include "stralloc.h"
    55#include "iopause.h"
    66#include "taia.h"
     7#include "clients.h"
    78
    89#define DNS_C_IN "\0\1"
    910#define DNS_C_ANY "\0\377"
    struct dns_transmit { 
    3839  const char *servers;
    3940  char localip[4];
    4041  char qtype[2];
     42  struct dns_transmit *master;
     43  struct dns_transmit *slaves[MAXUDP];
     44  int nslaves;
    4145} ;
    4246
     47extern void dns_enable_merge(void (*logger)(const char *, const char *,
     48      const char *));
     49
    4350extern void dns_random_init(const char *);
    4451extern unsigned int dns_random(unsigned int);
    4552
  • dns_transmit.c

    diff --git a/dns_transmit.c b/dns_transmit.c
    index 4d6e39f..3984776 100644
    a b  
    77#include "byte.h"
    88#include "uint16.h"
    99#include "dns.h"
     10#include "strerr.h"
     11
     12static int merge_enable;
     13static void (*merge_logger)(const char *, const char *, const char *);
     14void dns_enable_merge(void (*f)(const char *, const char *, const char *))
     15{
     16  merge_enable = 1;
     17  merge_logger = f;
     18}
     19
     20static int merge_equal(struct dns_transmit *a, struct dns_transmit *b)
     21{
     22  const char *ip1 = a->servers + 4 * a->curserver;
     23  const char *ip2 = b->servers + 4 * b->curserver;
     24  return
     25    byte_equal(ip1, 4, ip2) &&
     26    byte_equal(a->qtype, 2, b->qtype) &&
     27    dns_domain_equal(a->query + 14, b->query + 14);
     28}
     29
     30struct dns_transmit *inprogress[MAXUDP];
     31
     32static int try_merge(struct dns_transmit *d)
     33{
     34  int i;
     35  for (i = 0; i < MAXUDP; i++) {
     36    if (!inprogress[i]) continue;
     37    if (!merge_equal(d, inprogress[i])) continue;
     38    d->master = inprogress[i];
     39    inprogress[i]->slaves[inprogress[i]->nslaves++] = d;
     40    return 1;
     41  }
     42  return 0;
     43}
     44
     45static void register_inprogress(struct dns_transmit *d)
     46{
     47  int i;
     48  for (i = 0; i < MAXUDP; i++) {
     49    if (!inprogress[i]) {
     50      inprogress[i] = d;
     51      return;
     52    }
     53  }
     54  strerr_die1x(100, "BUG: out of inprogress slots");
     55}
     56
     57static void unregister_inprogress(struct dns_transmit *d)
     58{
     59  int i;
     60  for (i = 0; i < MAXUDP; i++) {
     61    if (inprogress[i] == d)
     62      inprogress[i] = 0;
     63  }
     64}
    1065
    1166static int serverwantstcp(const char *buf,unsigned int len)
    1267{
    static void packetfree(struct dns_transmit *d) 
    59114  d->packet = 0;
    60115}
    61116
     117static void mergefree(struct dns_transmit *d)
     118{
     119  int i;
     120  if (merge_enable)
     121    unregister_inprogress(d);
     122  /* unregister us from our master */
     123  if (d->master) {
     124    for (i = 0; i < d->master->nslaves; i++)
     125      if (d->master->slaves[i] == d)
     126        d->master->slaves[i] = 0;
     127  }
     128  /* and unregister all of our slaves from us */
     129  for (i = 0; i < d->nslaves; i++) {
     130    if (d->slaves[i])
     131      d->slaves[i]->master = NULL;
     132  }
     133  d->nslaves = 0;
     134}
     135
    62136static void queryfree(struct dns_transmit *d)
    63137{
     138  mergefree(d);
    64139  if (!d->query) return;
    65140  alloc_free(d->query);
    66141  d->query = 0;
    static int thisudp(struct dns_transmit *d) 
    99174  const char *ip;
    100175
    101176  socketfree(d);
     177  mergefree(d);
    102178
    103179  while (d->udploop < 4) {
    104180    for (;d->curserver < 16;++d->curserver) {
    105181      ip = d->servers + 4 * d->curserver;
    106182      if (byte_diff(ip,4,"\0\0\0\0")) {
     183        if (merge_enable && try_merge(d)) {
     184          if (merge_logger)
     185            merge_logger(ip, d->qtype, d->query + 14);
     186          return 0;
     187        }
     188
    107189        d->query[2] = dns_random(256);
    108190        d->query[3] = dns_random(256);
    109191 
    static int thisudp(struct dns_transmit *d) 
    118200            taia_uint(&d->deadline,timeouts[d->udploop]);
    119201            taia_add(&d->deadline,&d->deadline,&now);
    120202            d->tcpstate = 0;
     203            if (merge_enable)
     204              register_inprogress(d);
    121205            return 0;
    122206          }
    123207 
    void dns_transmit_io(struct dns_transmit *d,iopause_fd *x,struct taia *deadline) 
    226310  x->fd = d->s1 - 1;
    227311
    228312  switch(d->tcpstate) {
    229     case 0: case 3: case 4: case 5:
    230       x->events = IOPAUSE_READ;
     313    case 0:
     314      if (d->master) return;
     315      if (d->packet) { taia_now(deadline); return; }
     316      /* otherwise, fall through */
     317    case 3: case 4: case 5:
     318        x->events = IOPAUSE_READ;
    231319      break;
    232320    case 1: case 2:
    233321      x->events = IOPAUSE_WRITE;
    int dns_transmit_get(struct dns_transmit *d,const iopause_fd *x,const struct tai 
    244332  unsigned char ch;
    245333  int r;
    246334  int fd;
     335  int i;
    247336
    248337  errno = error_io;
    249338  fd = d->s1 - 1;
    250339
     340  if (d->tcpstate == 0 && d->master) return 0;
     341  if (d->tcpstate == 0 && d->packet) return 1;
     342
    251343  if (!x->revents) {
    252344    if (taia_less(when,&d->deadline)) return 0;
    253345    errno = error_timeout;
    have sent query to curserver on UDP socket s 
    279371    d->packet = alloc(d->packetlen);
    280372    if (!d->packet) { dns_transmit_free(d); return -1; }
    281373    byte_copy(d->packet,d->packetlen,udpbuf);
     374
     375    for (i = 0; i < d->nslaves; i++) {
     376      if (!d->slaves[i]) continue;
     377      d->slaves[i]->packetlen = d->packetlen;
     378      d->slaves[i]->packet = alloc(d->packetlen);
     379      if (!d->slaves[i]->packet) { dns_transmit_free(d->slaves[i]); continue; }
     380      byte_copy(d->slaves[i]->packet,d->packetlen,udpbuf);
     381    }
     382
    282383    queryfree(d);
    283384    return 1;
    284385  }
  • dnscache.c

    diff --git a/dnscache.c b/dnscache.c
    index 8c899a3..c8db179 100644
    a b uint64 numqueries = 0; 
    5454
    5555static int udp53;
    5656
    57 #define MAXUDP 200
    5857static struct udpclient {
    5958  struct query q;
    6059  struct taia start;
    void u_new(void) 
    131130
    132131static int tcp53;
    133132
    134 #define MAXTCP 20
    135133struct tcpclient {
    136134  struct query q;
    137135  struct taia start;
    int main() 
    435433    response_hidettl();
    436434  if (env_get("FORWARDONLY"))
    437435    query_forwardonly();
     436  if (env_get("MERGEQUERIES"))
     437    dns_enable_merge(log_merge);
    438438
    439439  if (!roots_init())
    440440    strerr_die2sys(111,FATAL,"unable to read servers: ");
  • log.c

    diff --git a/log.c b/log.c
    index c43e8b0..3e1c674 100644
    a b void log_tx(const char *q,const char qtype[2],const char *control,const char ser 
    150150  line();
    151151}
    152152
     153void log_merge(const char *addr, const char qtype[2], const char *q)
     154{
     155  string("merge "); ip(addr); space(); logtype(qtype); space(); name(q);
     156  line();
     157}
     158
    153159void log_cachedanswer(const char *q,const char type[2])
    154160{
    155161  string("cached "); logtype(type); space();
  • log.h

    diff --git a/log.h b/log.h
    index fe62fa3..dd6408a 100644
    a b extern void log_cachednxdomain(const char *); 
    1818extern void log_cachedns(const char *,const char *);
    1919
    2020extern void log_tx(const char *,const char *,const char *,const char *,unsigned int);
     21extern void log_merge(const char *, const char *, const char *);
    2122
    2223extern void log_nxdomain(const char *,const char *,unsigned int);
    2324extern void log_nodata(const char *,const char *,const char *,unsigned int);
Note: See TracBrowser for help on using the repository browser.