... allowing Squid to advertise a larger UDP reply size than 512 bytes.
Internally Squid has a buffer allocated on demand so there is no
practicable limit on individual packets. Network topology and external
software places stricter boundaries on what works and what does not.
Squid does not parse the additional section of replies so for now the
full auto-negotiation EDNS allows is not used. Instead a configuration
option is provided for admin to configure a desirable packet size in
bytes. EDNS defaults to "none" (disabled) until tested in a wider
environment.
Testing so far has brought to light problems with EDNS adverts on A and
IPv4-PTR queries. So support is limited to AAAA and IPv6-PTR queries only.
EDNS compliant resolvers have the option of caching the info between
requests for a short while so this will hopefully leak over to improve
IPv4 responses as well.
*/
#define RFC1035_MAXHOSTNAMESZ RFC2181_MAXHOSTNAMELEN
+#define RFC1035_DEFAULT_PACKET_SZ 512
typedef struct _rfc1035_rr rfc1035_rr;
struct _rfc1035_rr {
char *buf,
size_t sz,
unsigned short qid,
- rfc1035_query * query);
+ rfc1035_query * query,
+ ssize_t edns_sz);
SQUIDCEXTERN ssize_t rfc1035BuildPTRQuery(const struct in_addr,
char *buf,
size_t sz,
unsigned short qid,
- rfc1035_query * query);
+ rfc1035_query * query,
+ ssize_t edns_sz);
SQUIDCEXTERN void rfc1035SetQueryID(char *, unsigned short qid);
SQUIDCEXTERN int rfc1035MessageUnpack(const char *buf,
size_t sz,
const char *name,
const unsigned short type,
const unsigned short _class);
+SQUIDCEXTERN int rfc1035RRPack(char *buf, size_t sz, const rfc1035_rr * RR);
#endif /* SQUID_RFC1035_H */
--- /dev/null
+/*
+ * $Id$
+ *
+ * AUTHOR: Amos Jeffries
+ *
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
+ *
+ * This code is copyright (C) 2007 by Treehouse Networks Ltd of
+ * New Zealand. It is published and Lisenced as an extension of
+ * squid under the same conditions as the main squid application.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#ifndef SQUID_RFC2671_H
+#define SQUID_RFC2671_H
+
+#include "config.h"
+
+/* RFC2671 section 7 defines new RR type OPT as 41 */
+#define RFC1035_TYPE_OPT 41
+
+SQUIDCEXTERN int rfc2671RROptPack(char *buf, size_t sz, ssize_t edns_sz);
+
+
+#endif /* SQUID_RFC3596_H */
char *buf,
size_t sz,
unsigned short qid,
- rfc1035_query * query);
+ rfc1035_query * query,
+ ssize_t edns_sz);
SQUIDCEXTERN ssize_t rfc3596BuildAAAAQuery(const char *hostname,
char *buf,
size_t sz,
unsigned short qid,
- rfc1035_query * query);
+ rfc1035_query * query,
+ ssize_t edns_sz);
SQUIDCEXTERN ssize_t rfc3596BuildPTRQuery4(const struct in_addr,
char *buf,
size_t sz,
unsigned short qid,
- rfc1035_query * query);
+ rfc1035_query * query,
+ ssize_t edns_sz);
SQUIDCEXTERN ssize_t rfc3596BuildPTRQuery6(const struct in6_addr,
char *buf,
size_t sz,
unsigned short qid,
- rfc1035_query * query);
+ rfc1035_query * query,
+ ssize_t edns_sz);
/* RFC3596 library implements RFC1035 generic host interface */
SQUIDCEXTERN ssize_t rfc3596BuildHostQuery(const char *hostname,
size_t sz,
unsigned short qid,
rfc1035_query * query,
- int qtype);
+ int qtype,
+ ssize_t edns_sz);
/* RFC3596 section 2.1 defines new RR type AAAA as 28 */
#define RFC1035_TYPE_AAAA 28
rfc1123.c \
rfc1738.c \
rfc2617.c \
+ rfc2671.c \
rfc3596.c \
$(SNPRINTFSOURCE) \
Splay.cc \
#endif
#include "rfc1035.h"
+#include "rfc2671.h"
#define RFC1035_MAXLABELSZ 63
#define rfc1035_unpack_error 15
return 0;
}
+/*
+ * rfc1035RRPack()
+ *
+ * Packs a RFC1035 Resource Record into a message buffer from 'RR'.
+ * The caller must allocate and free RR->rdata and RR->name!
+ *
+ * Updates the new message buffer.
+ *
+ * Returns the number of bytes added to the buffer or 0 for error.
+ */
+int
+rfc1035RRPack(char *buf, const size_t sz, const rfc1035_rr * RR)
+{
+ unsigned int off;
+ uint16_t s;
+ uint32_t i;
+
+ off = rfc1035NamePack(buf, sz, RR->name);
+
+ /*
+ * Make sure the remaining message has enough octets for the
+ * rest of the RR fields.
+ */
+ if ((off + sizeof(s)*3 + sizeof(i) + RR->rdlength) > sz) {
+ return 0;
+ }
+ s = htons(RR->type);
+ memcpy(buf + off, &s, sizeof(s));
+ off += sizeof(s);
+ s = htons(RR->_class);
+ memcpy(buf + off, &s, sizeof(s));
+ off += sizeof(s);
+ i = htonl(RR->ttl);
+ memcpy(buf + off, &i, sizeof(i));
+ off += sizeof(i);
+ s = htons(RR->rdlength);
+ memcpy(buf + off, &s, sizeof(s));
+ off += sizeof(s);
+ memcpy(buf + off, &(RR->rdata), RR->rdlength);
+ off += RR->rdlength;
+ assert(off <= sz);
+ return off;
+}
+
/*
* rfc1035RRUnpack()
*
* Returns the size of the query
*/
ssize_t
-rfc1035BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query)
+rfc1035BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
{
static rfc1035_message h;
size_t offset = 0;
h.rd = 1;
h.opcode = 0; /* QUERY */
h.qdcount = (unsigned int) 1;
+ h.arcount = (edns_sz > 0 ? 1 : 0);
offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
offset += rfc1035QuestionPack(buf + offset,
sz - offset,
hostname,
RFC1035_TYPE_A,
RFC1035_CLASS_IN);
+ if (edns_sz > 0)
+ offset += rfc2671RROptPack(buf + offset, sz - offset, edns_sz);
if (query) {
query->qtype = RFC1035_TYPE_A;
query->qclass = RFC1035_CLASS_IN;
* Returns the size of the query
*/
ssize_t
-rfc1035BuildPTRQuery(const struct in_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query)
+rfc1035BuildPTRQuery(const struct in_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
{
static rfc1035_message h;
size_t offset = 0;
h.rd = 1;
h.opcode = 0; /* QUERY */
h.qdcount = (unsigned int) 1;
+ h.arcount = (edns_sz > 0 ? 1 : 0);
offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
offset += rfc1035QuestionPack(buf + offset,
sz - offset,
rev,
RFC1035_TYPE_PTR,
RFC1035_CLASS_IN);
+ if (edns_sz > 0)
+ offset += rfc2671RROptPack(buf + offset, sz - offset, edns_sz);
if (query) {
query->qtype = RFC1035_TYPE_PTR;
query->qclass = RFC1035_CLASS_IN;
int
main(int argc, char *argv[])
{
- char input[512];
- char buf[512];
- char rbuf[512];
- size_t sz = 512;
+ char input[SQUID_DNS_BUFSZ];
+ char buf[SQUID_DNS_BUFSZ];
+ char rbuf[SQUID_DNS_BUFSZ];
+ size_t sz = SQUID_DNS_BUFSZ;
unsigned short sid;
int s;
int rl;
S.sin_family = AF_INET;
S.sin_port = htons(atoi(argv[2]));
S.sin_addr.s_addr = inet_addr(argv[1]);
- while (fgets(input, 512, stdin)) {
+ while (fgets(input, RFC1035_DEFAULT_PACKET_SZ, stdin)) {
struct in_addr junk;
strtok(input, "\r\n");
- memset(buf, '\0', 512);
- sz = 512;
+ memset(buf, '\0', RFC1035_DEFAULT_PACKET_SZ);
+ sz = RFC1035_DEFAULT_PACKET_SZ;
if (inet_pton(AF_INET, input, &junk)) {
sid = rfc1035BuildPTRQuery(junk, buf, &sz);
} else {
printf("TIMEOUT\n");
continue;
}
- memset(rbuf, '\0', 512);
- rl = recv(s, rbuf, 512, 0);
+ memset(rbuf, '\0', RFC1035_DEFAULT_PACKET_SZ);
+ rl = recv(s, rbuf, RFC1035_DEFAULT_PACKET_SZ, 0);
{
unsigned short rid = 0;
int i;
--- /dev/null
+#include "config.h"
+#include "rfc2671.h"
+#include "rfc1035.h"
+
+int
+rfc2671RROptPack(char *buf, size_t sz, ssize_t edns_sz)
+{
+ // set the OPT record correctly. base it on a macro size of the Squid DNS read buffer
+ static rfc1035_rr opt;
+
+ // EDNS OPT record says only what our DNS buffer size is so far.
+ snprintf(opt.name, RFC1035_MAXHOSTNAMESZ, ".");
+ opt.type = RFC1035_TYPE_OPT;
+ opt._class = min(edns_sz, SQUID_UDP_SO_RCVBUF-1);
+ opt.ttl = 0; // relevant?
+ opt.rdata = NULL;
+ opt.rdlength = 0;
+
+ return rfc1035RRPack(buf, sz, &opt);
+}
#endif
#include "rfc3596.h"
+#include "rfc2671.h"
#ifndef SQUID_RFC1035_H
#error RFC3596 Library depends on RFC1035
* Returns the size of the query
*/
ssize_t
-rfc3596BuildHostQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, int qtype)
+rfc3596BuildHostQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, int qtype, ssize_t edns_sz)
{
static rfc1035_message h;
size_t offset = 0;
h.rd = 1;
h.opcode = 0; /* QUERY */
h.qdcount = (unsigned int) 1;
+ h.arcount = (edns_sz > 0 ? 1 : 0);
offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
offset += rfc1035QuestionPack(buf + offset,
sz - offset,
hostname,
qtype,
RFC1035_CLASS_IN);
+ if (edns_sz > 0)
+ offset += rfc2671RROptPack(buf + offset, sz - offset, edns_sz);
if (query) {
query->qtype = qtype;
* \return the size of the query
*/
ssize_t
-rfc3596BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query)
+rfc3596BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
{
- return rfc3596BuildHostQuery(hostname, buf, sz, qid, query, RFC1035_TYPE_A);
+ return rfc3596BuildHostQuery(hostname, buf, sz, qid, query, RFC1035_TYPE_A, edns_sz);
}
/**
* \return the size of the query
*/
ssize_t
-rfc3596BuildAAAAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query)
+rfc3596BuildAAAAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
{
- return rfc3596BuildHostQuery(hostname, buf, sz, qid, query, RFC1035_TYPE_AAAA);
+ return rfc3596BuildHostQuery(hostname, buf, sz, qid, query, RFC1035_TYPE_AAAA, edns_sz);
}
* \return the size of the query
*/
ssize_t
-rfc3596BuildPTRQuery4(const struct in_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query)
+rfc3596BuildPTRQuery4(const struct in_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
{
static char rev[RFC1035_MAXHOSTNAMESZ];
unsigned int i;
(i >> 16) & 255,
(i >> 24) & 255);
- return rfc3596BuildHostQuery(rev, buf, sz, qid, query, RFC1035_TYPE_PTR);
+ return rfc3596BuildHostQuery(rev, buf, sz, qid, query, RFC1035_TYPE_PTR, edns_sz);
}
ssize_t
-rfc3596BuildPTRQuery6(const struct in6_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query)
+rfc3596BuildPTRQuery6(const struct in6_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
{
static char rev[RFC1035_MAXHOSTNAMESZ];
const uint8_t* r = addr.s6_addr;
snprintf(p,10,"ip6.arpa.");
- return rfc3596BuildHostQuery(rev, buf, sz, qid, query, RFC1035_TYPE_PTR);
+ return rfc3596BuildHostQuery(rev, buf, sz, qid, query, RFC1035_TYPE_PTR, edns_sz);
}
int
main(int argc, char *argv[])
{
- char input[512];
- char buf[512];
- char rbuf[512];
- size_t sz = 512;
+#define PACKET_BUFSZ 1024
+ char input[PACKET_BUFSZ];
+ char buf[PACKET_BUFSZ];
+ char rbuf[PACKET_BUFSZ];
+ size_t sz = PACKET_BUFSZ;
unsigned short sid, sidb;
int s;
int rl;
+ ssize_t edns_max = -1;
struct sockaddr* S;
int var = 1;
prefer = AF_INET;
else if (argv[var][1] == '6')
prefer = AF_INET6;
+ else if (argv[var][1] == 'E')
+ edns_max = atoi(argv[var++]);
else {
- fprintf(stderr, "usage: %s [-6|-4] ip port\n", argv[0]);
+ fprintf(stderr, "usage: %s [-6|-4] [-E packet-size] ip port\n", argv[0]);
+ fprintf(stderr, " EDNS packets my be up to %d\n", PACKET_BUFSZ);
return 1;
}
((struct sockaddr_in6 *)S)->sin6_family = AF_INET6;
((struct sockaddr_in6 *)S)->sin6_port = htons(atoi(argv[var+1]));
- if ( ! inet_pton(AF_INET6, argv[var], &((struct sockaddr_in6 *)S)->sin6_addr.s_addr) )
+ if ( ! inet_pton(AF_INET6, argv[var], &((struct sockaddr_in6 *)S)->sin6_addr.s_addr) ) {
perror("listen address");
return 1;
}
}
}
-while (fgets(input, 512, stdin))
+while (fgets(input, PACKET_BUFSZ, stdin))
{
struct in6_addr junk6;
struct in_addr junk4;
strtok(input, "\r\n");
- memset(buf, '\0', 512);
- sz = 512;
+ memset(buf, '\0', PACKET_BUFSZ);
+ sz = PACKET_BUFSZ;
if (inet_pton(AF_INET6, input, &junk6)) {
- sid = rfc1035BuildPTRQuery6(junk6, buf, &sz);
+ sid = rfc1035BuildPTRQuery6(junk6, buf, &sz, edns_max);
sidb=0;
} else if (inet_pton(AF_INET, input, &junk4)) {
- sid = rfc1035BuildPTRQuery4(junk4, buf, &sz);
+ sid = rfc1035BuildPTRQuery4(junk4, buf, &sz, edns_max);
sidb=0;
} else {
- sid = rfc1035BuildAAAAQuery(input, buf, &sz);
- sidb = rfc1035BuildAQuery(input, buf, &sz);
+ sid = rfc1035BuildAAAAQuery(input, buf, &sz, edns_max);
+ sidb = rfc1035BuildAQuery(input, buf, &sz, edns_max);
}
sendto(s, buf, sz, 0, S, sizeof(*S));
continue;
}
- memset(rbuf, '\0', 512);
- rl = recv(s, rbuf, 512, 0);
+ memset(rbuf, '\0', PACKET_BUFSZ);
+ rl = recv(s, rbuf, PACKET_BUFSZ, 0);
{
unsigned short rid = 0;
int i;
/* Being a C library code it is best bodily included and tested with C++ type-safe techniques. */
#include "lib/rfc1035.c"
+#include "lib/rfc2671.c"
CPPUNIT_TEST_SUITE_REGISTRATION( testRFC1035 );
static void defaults_if_none(void);
static int parse_line(char *);
static void parseBytesLine(size_t * bptr, const char *units);
+#if !USE_DNSSERVERS
+static void parseBytesLineSigned(ssize_t * bptr, const char *units);
+#endif
static size_t parseBytesUnits(const char *unit);
static void free_all(void);
void requirePathnameExists(const char *name, const char *path);
self_destruct();
}
+#if !USE_DNSSERVERS
+static void
+parseBytesLineSigned(ssize_t * bptr, const char *units)
+{
+ char *token;
+ double d;
+ int m;
+ int u;
+
+ if ((u = parseBytesUnits(units)) == 0) {
+ self_destruct();
+ return;
+ }
+
+ if ((token = strtok(NULL, w_space)) == NULL) {
+ self_destruct();
+ return;
+ }
+
+ if (strcmp(token, "none") == 0 || token[0] == '-' /* -N */) {
+ *bptr = -1;
+ return;
+ }
+
+ d = xatof(token);
+
+ m = u; /* default to 'units' if none specified */
+
+ if (0.0 == d)
+ (void) 0;
+ else if ((token = strtok(NULL, w_space)) == NULL)
+ debugs(3, 0, "WARNING: No units on '" <<
+ config_input_line << "', assuming " <<
+ d << " " << units );
+ else if ((m = parseBytesUnits(token)) == 0) {
+ self_destruct();
+ return;
+ }
+
+ *bptr = static_cast<size_t>(m * d / u);
+
+ if (static_cast<double>(*bptr) * 2 != m * d / u * 2)
+ self_destruct();
+}
+#endif
+
static size_t
parseBytesUnits(const char *unit)
{
storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
}
+#if !USE_DNSSERVERS
+static void
+dump_b_ssize_t(StoreEntry * entry, const char *name, ssize_t var)
+{
+ storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
+}
+#endif
+
#if UNUSED_CODE
static void
dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
parseBytesLine(var, B_BYTES_STR);
}
+#if !USE_DNSSERVERS
+static void
+parse_b_ssize_t(ssize_t * var)
+{
+ parseBytesLineSigned(var, B_BYTES_STR);
+}
+#endif
+
#if UNUSED_CODE
static void
parse_kb_size_t(size_t * var)
*var = 0;
}
+#if !USE_DNSSERVERS
+static void
+free_ssize_t(ssize_t * var)
+{
+ *var = 0;
+}
+#endif
+
static void
free_b_int64_t(int64_t * var)
{
}
#define free_b_size_t free_size_t
+#define free_b_ssize_t free_ssize_t
#define free_kb_size_t free_size_t
#define free_mb_size_t free_size_t
#define free_gb_size_t free_size_t
authparam
b_int64_t
b_size_t
+b_ssize_t
cachedir cache_replacement_policy
cachemgrpasswd
ConfigAclTos
are assumed to be unavailable.
DOC_END
+NAME: dns_packet_max
+TYPE: b_ssize_t
+DEFAULT: none
+LOC: Config.dns.packet_max
+IFDEF: !USE_DNSSERVERS
+DOC_START
+ Maximum number of bytes packet size to advertise via EDNS.
+ Set to "none" to disable EDNS large packet support.
+
+ For legacy reasons DNS UDP replies will default to 512 bytes which
+ is too small for many responses. EDNS provides a means for Squid to
+ negotiate receiving larger responses back immediately without having
+ to failover with repeat requests. Responses larger than this limit
+ will retain the old behaviour of failover to TCP DNS.
+
+ Squid has no real fixed limit internally, but allowing packet sizes
+ over 1500 bytes requires network jumbogram support and is usually not
+ necessary.
+
+ WARNING: The RFC also indicates that some older resolvers will reply
+ with failure of the whole request if the extension is added. Some
+ resolvers have already been identified which will reply with mangled
+ EDNS response on occasion. Usually in response to many-KB jumbogram
+ sizes being advertised by Squid.
+ Squid will currently treat these both as an unable-to-resolve domain
+ even if it would be resolvable without EDNS.
+DOC_END
+
NAME: dns_defnames
COMMENT: on|off
TYPE: onoff
#endif
#define IDNS_MAX_TRIES 20
-#define MAX_RCODE 6
+#define MAX_RCODE 17
#define MAX_ATTEMPT 3
static int RcodeMatrix[MAX_RCODE][MAX_ATTEMPT];
+// NP: see http://www.iana.org/assignments/dns-parameters
+static const char *Rcodes[] = {
+ /* RFC 1035 */
+ "Success",
+ "Packet Format Error",
+ "DNS Server Failure",
+ "Non-Existent Domain",
+ "Not Implemented",
+ "Query Refused",
+ /* RFC 2136 */
+ "Name Exists when it should not",
+ "RR Set Exists when it should not",
+ "RR Set that should exist does not",
+ "Server Not Authoritative for zone",
+ "Name not contained in zone",
+ /* unassigned */
+ "","","","","",
+ /* RFC 2671 */
+ "Bad OPT Version or TSIG Signature Failure"
+ };
typedef struct _idns_query idns_query;
Ip::Address S;
int nqueries;
int nreplies;
+#if WHEN_EDNS_RESPONSES_ARE_PARSED
+ int last_seen_edns;
+#endif
nsvc *vc;
};
static int event_queued = 0;
static hash_table *idns_lookup_hash = NULL;
+/*
+ * Notes on EDNS:
+ *
+ * IPv4:
+ * EDNS as specified may be sent as an additional record for any request.
+ * early testing has revealed that it works on common devices, but cannot
+ * be reliably used on any A or PTR requet done for IPv4 addresses.
+ *
+ * As such the IPv4 packets are still hard-coded not to contain EDNS (0)
+ *
+ * Squid design:
+ * Squid is optimized to generate one packet and re-send it to all NS
+ * due to this we cannot customize the EDNS size per NS.
+ *
+ * As such we take the configuration option value as fixed.
+ *
+ * FUTURE TODO:
+ * This may not be worth doing, but if/when additional-records are parsed
+ * we will be able to recover the OPT value specific to any one NS and
+ * cache it. Effectively automating the tuning of EDNS advertised to the
+ * size our active NS are capable.
+ * Default would need to start with 512 bytes RFC1035 says every NS must accept.
+ * Responses from the configured NS may cause this to be raised or turned off.
+ */
+#if WHEN_EDNS_RESPONSES_ARE_PARSED
+static int max_shared_edns = RFC1035_DEFAULT_PACKET_SZ;
+#endif
+
static OBJH idnsStats;
static void idnsAddNameserver(const char *buf);
static void idnsAddPathComponent(const char *buf);
static int idnsFromKnownNameserver(Ip::Address const &from);
static idns_query *idnsFindQuery(unsigned short id);
-static void idnsGrokReply(const char *buf, size_t sz);
+static void idnsGrokReply(const char *buf, size_t sz, int from_ns);
static PF idnsRead;
static EVH idnsCheckQueue;
static void idnsTickleQueue(void);
assert(nns < nns_alloc);
A.SetPort(NS_DEFAULTPORT);
nameservers[nns].S = A;
+#if WHEN_EDNS_RESPONSES_ARE_PARSED
+ nameservers[nns].last_seen_edns = RFC1035_DEFAULT_PACKET_SZ;
+ // TODO generate a test packet to probe this NS from EDNS size and ability.
+#endif
debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns << " (" << A << ")");
nns++;
}
tvSubDsec(q->sent_t, current_time));
}
+ if (Config.dns.packet_max > 0)
+ storeAppendPrintf(sentry, "DNS jumbo-grams: %d Bytes\n", Config.dns.packet_max);
+ else
+ storeAppendPrintf(sentry, "DNS jumbo-grams: not working\n");
+
storeAppendPrintf(sentry, "\nNameservers:\n");
storeAppendPrintf(sentry, "IP ADDRESS # QUERIES # REPLIES\n");
storeAppendPrintf(sentry, "---------------------------------------------- --------- ---------\n");
for (i = 0; i < MAX_ATTEMPT; i++)
storeAppendPrintf(sentry, " ATTEMPT%d", i + 1);
- storeAppendPrintf(sentry, "\n");
+ storeAppendPrintf(sentry, " PROBLEM\n");
for (j = 0; j < MAX_RCODE; j++) {
+ if (j > 10 && j < 16)
+ continue; // unassigned by IANA.
+
storeAppendPrintf(sentry, "%5d", j);
for (i = 0; i < MAX_ATTEMPT; i++)
storeAppendPrintf(sentry, " %8d", RcodeMatrix[j][i]);
- storeAppendPrintf(sentry, "\n");
+ storeAppendPrintf(sentry, " : %s\n",Rcodes[j]);
}
if (npc) {
}
static void
-idnsGrokReply(const char *buf, size_t sz)
+idnsGrokReply(const char *buf, size_t sz, int from_ns)
{
int n;
rfc1035_message *message = NULL;
return;
}
+#if WHEN_EDNS_RESPONSES_ARE_PARSED
+// TODO: actually gr the message right here.
+// pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
+// this is overall better than force-feeding A response with AAAA an section later anyway.
+// AND allows us to merge AN+AR sections from both responses (one day)
+
+ if (q->edns_seen >= 0) {
+ if (max_shared_edns == nameservers[from_ns].last_seen_edns && max_shared_edns < q->edns_seen) {
+ nameservers[from_ns].last_seen_edns = q->edns_seen;
+ // the altered NS was limiting the whole group.
+ max_shared_edns = q->edns_seen;
+ // may be limited by one of the others still
+ for (int i = 0; i < nns; i++)
+ max_shared_edns = min(max_shared_edns, nameservers[i].last_seen_edns);
+ } else {
+ nameservers[from_ns].last_seen_edns = q->edns_seen;
+ // maybe reduce the global limit downwards to accomodate this NS
+ max_shared_edns = min(max_shared_edns, q->edns_seen);
+ }
+ if (max_shared_edns < RFC1035_DEFAULT_PACKET_SZ)
+ max_shared_edns = -1;
+ }
+#endif
+
if (message->tc) {
debugs(78, 3, HERE << "Resolver requested TC (" << q->query.name << ")");
dlinkDelete(&q->lru, &lru_list);
rfc1035SetQueryID(q->buf, q->id);
if (Ip::EnableIpv6 && q->query.qtype == RFC1035_TYPE_AAAA) {
debugs(78, 3, "idnsGrokReply: Trying AAAA Query for " << q->name);
- q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query);
+ q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query, Config.dns.packet_max);
} else {
debugs(78, 3, "idnsGrokReply: Trying A Query for " << q->name);
- q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query);
+ // see EDNS notes at top of file why this sends 0
+ q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query, 0);
}
idnsCacheQuery(q);
idnsSendQuery(q);
q->start_t = current_time;
q->id = idnsQueryID();
rfc1035SetQueryID(q->buf, q->id);
- q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query);
+ // see EDNS notes at top of file why this sends 0
+ q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query, 0);
q->need_A = false;
idnsCacheQuery(q);
idnsSendQuery(q);
continue;
}
- idnsGrokReply(rbuf, len);
+ idnsGrokReply(rbuf, len, ns);
}
}
(int) vc->msg->contentSize() << " bytes via tcp from " <<
nameservers[vc->ns].S << ".");
- idnsGrokReply(vc->msg->buf, vc->msg->contentSize());
+ idnsGrokReply(vc->msg->buf, vc->msg->contentSize(), vc->ns);
vc->msg->clean();
comm_read(fd, (char *)&vc->msglen, 2 , idnsReadVCHeader, vc);
}
init++;
}
+#if WHEN_EDNS_RESPONSES_ARE_PARSED
+ if (Config.onoff.ignore_unknown_nameservers && max_shared_edns > 0) {
+ debugs(0, DBG_IMPORTANT, "ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
+ max_shared_edns = -1; // disable if we might receive random replies.
+ }
+#endif
+
idnsRegisterWithCacheManager();
}
}
if (Ip::EnableIpv6) {
- q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query);
+ q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query, Config.dns.packet_max);
q->need_A = true;
} else {
- q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query);
+ // see EDNS notes at top of file why this sends 0
+ q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query, 0);
q->need_A = false;
}
if (Ip::EnableIpv6 && addr.IsIPv6()) {
struct in6_addr addr6;
addr.GetInAddr(addr6);
- q->sz = rfc3596BuildPTRQuery6(addr6, q->buf, sizeof(q->buf), q->id, &q->query);
+ q->sz = rfc3596BuildPTRQuery6(addr6, q->buf, sizeof(q->buf), q->id, &q->query, Config.dns.packet_max);
} else {
struct in_addr addr4;
addr.GetInAddr(addr4);
- q->sz = rfc3596BuildPTRQuery4(addr4, q->buf, sizeof(q->buf), q->id, &q->query);
+ // see EDNS notes at top of file why this sends 0
+ q->sz = rfc3596BuildPTRQuery4(addr4, q->buf, sizeof(q->buf), q->id, &q->query, 0);
}
/* PTR does not do inbound A/AAAA */
#endif
int client_ip_max_connections;
+
+ struct {
+ ssize_t packet_max; ///< maximum size EDNS advertised for DNS replies.
+ } dns;
};
SQUIDCEXTERN SquidConfig Config;