--- gvpe/src/vpn_dns.C 2005/03/04 08:15:04 1.10 +++ gvpe/src/vpn_dns.C 2005/03/05 03:47:05 1.17 @@ -45,26 +45,25 @@ #include "vpn.h" -#define MIN_POLL_INTERVAL .2 // how often to poll minimally when the server is having data +#define MIN_POLL_INTERVAL .02 // how often to poll minimally when the server has data #define MAX_POLL_INTERVAL 6. // how often to poll minimally when the server has no data #define ACTIVITY_INTERVAL 5. -#define INITIAL_TIMEOUT 1. -#define INITIAL_SYN_TIMEOUT 2. +#define INITIAL_TIMEOUT 0.1 // retry timeouts +#define INITIAL_SYN_TIMEOUT 10. // retry timeout for initial syn -#define MIN_SEND_INTERVAL (1./1000.) +#define MIN_SEND_INTERVAL 0.01 // wait at least this time between sending requests #define MAX_SEND_INTERVAL 0.5 // optimistic? -#define MAX_OUTSTANDING 400 // max. outstanding requests -#define MAX_WINDOW 1000 // max. for MAX_OUTSTANDING -#define MAX_RATE 100 // requests/s -#define MAX_BACKLOG (100*1024) // size of protocol backlog, must be > MAXSIZE +#define MAX_OUTSTANDING 10 // max. outstanding requests +#define MAX_WINDOW 1000 // max. for MAX_OUTSTANDING, and backlog +#define MAX_BACKLOG (100*1024) // size of gvpe protocol backlog (bytes), must be > MAXSIZE #define MAX_DOMAIN_SIZE 220 // 255 is legal limit, but bind doesn't compress well // 240 leaves about 4 bytes of server reply data -// every two request byte sless give room for one reply byte +// every two request bytes less give room for one reply byte -#define SEQNO_MASK 0xffff +#define SEQNO_MASK 0x3fff #define SEQNO_EQ(a,b) ( 0 == ( ((a) ^ (b)) & SEQNO_MASK) ) #define MAX_LBL_SIZE 63 @@ -268,9 +267,15 @@ #define HDRSIZE 6 -inline void encode_header (char *data, int clientid, int seqno) +inline void encode_header (char *data, int clientid, int seqno, int retry = 0) { - u8 hdr[3] = { clientid, seqno >> 8, seqno }; + seqno &= SEQNO_MASK; + + u8 hdr[3] = { + clientid, + (seqno >> 8) | (retry << 6), + seqno, + }; assert (clientid < 256); @@ -284,7 +289,7 @@ cdc26.decode (hdr, data, HDRSIZE); clientid = hdr[0]; - seqno = (hdr[1] << 8) | hdr[2]; + seqno = ((hdr[1] << 8) | hdr[2]) & SEQNO_MASK; } ///////////////////////////////////////////////////////////////////////////// @@ -323,7 +328,7 @@ void byte_stream::remove (int count) { if (count > fill) - abort (); + assert (count <= fill); memmove (data, data + count, fill -= count); } @@ -353,10 +358,10 @@ vpn_packet *byte_stream::get () { - int len = (data [0] << 8) | data [1]; + unsigned int len = (data [0] << 8) | data [1]; if (len > MAXSIZE && fill >= 2) - abort (); // TODO handle this gracefully, connection reset + assert (len <= MAXSIZE || fill < 2); // TODO handle this gracefully, connection reset if (fill < len + 2) return 0; @@ -425,7 +430,7 @@ rrtype = RR_TYPE_TXT; flags = 0; - def_ttl = 0; + def_ttl = 1; rcv_cdc = 0; snd_cdc = 62; max_size = ntohs (MAX_PKT_SIZE); @@ -502,10 +507,13 @@ int retry; struct dns_connection *dns; int seqno; + bool stdhdr; - dns_snd (dns_connection *dns); void gen_stream_req (int seqno, byte_stream &stream); void gen_syn_req (const dns_cfg &cfg); + + dns_snd (dns_connection *dns); + ~dns_snd (); }; static u16 dns_id = 12098; // TODO: should be per-vpn @@ -528,12 +536,19 @@ timeout = 0; retry = 0; seqno = 0; + sent = NOW; + stdhdr = false; pkt = new dns_packet; pkt->id = next_id (); } +dns_snd::~dns_snd () +{ + delete pkt; +} + static void append_domain (dns_packet &pkt, int &offs, const char *domain) { // add tunnel domain @@ -559,6 +574,7 @@ void dns_snd::gen_stream_req (int seqno, byte_stream &stream) { + stdhdr = true; this->seqno = seqno; timeout = NOW + INITIAL_TIMEOUT; @@ -663,6 +679,7 @@ tstamp last_received; tstamp last_sent; + double last_latency; double poll_interval, send_interval; vector rcvpq; @@ -691,7 +708,8 @@ last_sent = last_received = 0; poll_interval = MIN_POLL_INTERVAL; - send_interval = 0.2; // starting rate + send_interval = 0.5; // starting rate + last_latency = INITIAL_TIMEOUT; } dns_connection::~dns_connection () @@ -709,13 +727,11 @@ last_received = NOW; tw.trigger (); - poll_interval *= 0.99; - if (poll_interval > MIN_POLL_INTERVAL) - poll_interval = MIN_POLL_INTERVAL; + poll_interval = send_interval; } else { - poll_interval *= 1.1; + poll_interval *= 1.5; if (poll_interval > MAX_POLL_INTERVAL) poll_interval = MAX_POLL_INTERVAL; } @@ -743,7 +759,10 @@ rcvseq = (rcvseq + 1) & SEQNO_MASK; if (!rcvdq.put (r->data, r->datalen)) - abort (); // MUST never overflow, can be caused by data corruption, TODO + { + slog (L_ERR, "DNS: !rcvdq.put (r->data, r->datalen)"); + abort (); // MUST never overflow, can be caused by data corruption, TODO + } while (vpn_packet *pkt = rcvdq.get ()) { @@ -751,6 +770,8 @@ si.host = 0; si.port = 0; si.prot = PROT_DNSv4; vpn->recv_vpn_packet (pkt, si); + + delete pkt; } // check for further packets @@ -781,7 +802,7 @@ pkt.nscount = 0; // should be self, as other nameservers reply like this pkt.arcount = 0; // a record for self, as other nameservers reply like this - pkt.flags = htons (DEFAULT_SERVER_FLAGS | FLAG_RCODE_NXDOMAIN); + pkt.flags = htons (DEFAULT_SERVER_FLAGS | FLAG_RCODE_SERVFAIL); int dlen = strlen (THISNODE->domain); @@ -810,6 +831,7 @@ connection *c = conns [client - 1]; dns_connection *dns = c->dns; dns_rcv *rcv; + bool in_seq; if (dns) { @@ -819,13 +841,19 @@ // already seen that request: simply reply with the cached reply dns_rcv *r = *i; - printf ("DUPLICATE %d\n", htons (r->pkt->id));//D + slog (L_DEBUG, "DNS: duplicate packet received ID %d, SEQ %d", htons (r->pkt->id), seqno); + + // refresh header & id, as the retry count could have changed + memcpy (r->pkt->at (6 * 2 + 1), pkt.at (6 * 2 + 1), HDRSIZE); + r->pkt->id = pkt.id; memcpy (pkt.at (0), r->pkt->at (0), offs = r->pkt->len); - pkt.id = r->pkt->id; + goto duplicate_request; } + in_seq = dns->rcvseq == seqno; + // new packet, queue rcv = new dns_rcv (seqno, data, datalen); dns->receive_rep (rcv); @@ -833,16 +861,11 @@ pkt [offs++] = 0xc0; pkt [offs++] = 6 * 2; // refer to name in query section - // type int rtype = dns ? dns->cfg.rrtype : RR_TYPE_A; - pkt [offs++] = rtype >> 8; pkt [offs++] = rtype; - - // class - pkt [offs++] = RR_CLASS_IN >> 8; pkt [offs++] = RR_CLASS_IN; - - // TTL + pkt [offs++] = rtype >> 8; pkt [offs++] = rtype; // type + pkt [offs++] = RR_CLASS_IN >> 8; pkt [offs++] = RR_CLASS_IN; // class pkt [offs++] = 0; pkt [offs++] = 0; - pkt [offs++] = 0; pkt [offs++] = dns ? dns->cfg.def_ttl : 0; + pkt [offs++] = 0; pkt [offs++] = dns ? dns->cfg.def_ttl : 0; // TTL int rdlen_offs = offs += 2; @@ -852,7 +875,10 @@ if (dns) { - while (dlen > 1 && !dns->snddq.empty ()) + // only put data into in-order sequence packets, if + // we receive out-of-order packets we generate empty + // replies + while (dlen > 1 && !dns->snddq.empty () && in_seq) { int txtlen = dlen <= 255 ? dlen - 1 : 255; @@ -870,6 +896,8 @@ // avoid empty TXT rdata if (offs == rdlen_offs) pkt[offs++] = 0; + + slog (L_NOISE, "DNS: snddq %d", dns->snddq.size ()); } else { @@ -910,7 +938,7 @@ pkt [offs++] = 0; pkt [offs++] = cfg.def_ttl; // TTL pkt [offs++] = 0; pkt [offs++] = 4; // rdlength - slog (L_INFO, _("DNS tunnel: client %d tries to connect"), client); + slog (L_INFO, _("DNS: client %d tries to connect"), client); pkt [offs++] = CMD_IP_1; pkt [offs++] = CMD_IP_2; pkt [offs++] = CMD_IP_3; pkt [offs++] = CMD_IP_REJ; @@ -951,25 +979,31 @@ if ((*i)->pkt->id == pkt.id) { dns_connection *dns = (*i)->dns; + connection *c = dns->c; int seqno = (*i)->seqno; u8 data[MAXSIZE], *datap = data; if ((*i)->retry) { dns->send_interval *= 1.01; - if (dns->send_interval < MAX_SEND_INTERVAL) + if (dns->send_interval > MAX_SEND_INTERVAL) dns->send_interval = MAX_SEND_INTERVAL; } else { - dns->send_interval *= 0.99; +#if 1 + dns->send_interval *= 0.999; +#endif if (dns->send_interval < MIN_SEND_INTERVAL) dns->send_interval = MIN_SEND_INTERVAL; // the latency surely puts an upper bound on // the minimum send interval - if (dns->send_interval > NOW - (*i)->sent) - dns->send_interval = NOW - (*i)->sent; + double latency = NOW - (*i)->sent; + dns->last_latency = latency; + + if (dns->send_interval > latency) + dns->send_interval = latency; } delete *i; @@ -1029,24 +1063,31 @@ && ip [1] == CMD_IP_2 && ip [2] == CMD_IP_3) { - slog (L_TRACE, _("got tunnel meta command %02x"), ip [3]); + slog (L_TRACE, _("DNS: got tunnel meta command %02x"), ip [3]); if (ip [3] == CMD_IP_RST) { - slog (L_DEBUG, _("got tunnel RST request")); + slog (L_DEBUG, _("DNS: got tunnel RST request")); - connection *c = dns->c; - delete c->dns; c->dns = 0; + delete dns; c->dns = 0; return; } else if (ip [3] == CMD_IP_SYN) - dns->established = true; + { + slog (L_DEBUG, _("DNS: got tunnel SYN reply, server likes us.")); + dns->established = true; + } + else if (ip [3] == CMD_IP_REJ) + { + slog (L_DEBUG, _("DNS: got tunnel REJ reply, server does not like us, aborting.")); + abort (); + } else - slog (L_INFO, _("got unknown meta command %02x"), ip [3]); + slog (L_INFO, _("DNS: got unknown meta command %02x"), ip [3]); } else - slog (L_INFO, _("got spurious a record %d.%d.%d.%d"), + slog (L_INFO, _("DNS: got spurious a record %d.%d.%d.%d"), ip [0], ip [1], ip [2], ip [3]); return; @@ -1057,12 +1098,12 @@ if (client != THISNODE->id) { - slog (L_INFO, _("got dns tunnel response with wrong clientid, ignoring")); + slog (L_INFO, _("DNS: got dns tunnel response with wrong clientid, ignoring")); datap = 0; } else if (rseqno != seqno) { - slog (L_DEBUG, _("got dns tunnel response with wrong seqno, badly caching nameserver?")); + slog (L_DEBUG, _("DNS: got dns tunnel response with wrong seqno, badly caching nameserver?")); datap = 0; } } @@ -1116,6 +1157,12 @@ return true; } +void +connection::dnsv4_reset_connection () +{ + //delete dns; dns = 0; //TODO +} + #define NEXT(w) do { if (next > (w)) next = w; } while (0) void @@ -1142,10 +1189,18 @@ send = r; r->retry++; - r->timeout = NOW + r->retry; + r->timeout = NOW + (r->retry * last_latency * 8.); + + // the following code changes the query section a bit, forcing + // the forwarder to generate a new request + if (r->stdhdr) + { + //printf ("reencoded header for ID %d retry %d:%d:%d\n", htons (r->pkt->id), THISNODE->id, r->seqno, r->retry);printf ("reencoded header for ID %d retry %d:%d:%d\n", htons (r->pkt->id), THISNODE->id, r->seqno, r->retry); + //encode_header ((char *)r->pkt->at (6 * 2 + 1), THISNODE->id, r->seqno, r->retry); + } } } - else if (r->timeout < next) + else NEXT (r->timeout); } @@ -1165,10 +1220,18 @@ send->gen_syn_req (cfg); } } - else if (vpn->dns_sndpq.size () < MAX_OUTSTANDING) + else if (vpn->dns_sndpq.size () < MAX_OUTSTANDING + && !SEQNO_EQ (rcvseq, sndseq - (MAX_WINDOW - 1))) { + if (!snddq.empty ()) + { + poll_interval = send_interval; + NEXT (NOW + send_interval); + } + send = new dns_snd (this); send->gen_stream_req (sndseq, snddq); + send->timeout = NOW + last_latency * 8.; sndseq = (sndseq + 1) & SEQNO_MASK; } @@ -1179,12 +1242,7 @@ if (send) { - printf ("send pkt\n"); last_sent = NOW; - - if (!send->retry) - send->sent = NOW; - sendto (vpn->dnsv4_fd, send->pkt->at (0), send->pkt->len, 0, vpn->dns_forwarder.sav4 (), vpn->dns_forwarder.salenv4 ()); @@ -1193,7 +1251,13 @@ else NEXT (last_sent + send_interval); - printf ("pi %f si %f N %f (%d:%d)\n", poll_interval, send_interval, next - NOW, vpn->dns_sndpq.size (), snddq.size ()); + slog (L_NOISE, "DNS: pi %f si %f N %f (%d:%d)", + poll_interval, send_interval, next - NOW, + vpn->dns_sndpq.size (), snddq.size ()); + + // TODO: no idea when this happens, but when next < NOW, we have a problem + if (next < NOW + 0.0001) + next = NOW + 0.1; w.start (next); }