=== modified file 'include/rfc1035.h' --- include/rfc1035.h 2010-05-09 14:21:38 +0000 +++ include/rfc1035.h 2010-09-22 04:47:11 +0000 @@ -57,6 +57,7 @@ */ #define RFC1035_MAXHOSTNAMESZ RFC2181_MAXHOSTNAMELEN +#define RFC1035_DEFAULT_PACKET_SZ 512 typedef struct _rfc1035_rr rfc1035_rr; struct _rfc1035_rr { @@ -97,12 +98,14 @@ 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, @@ -131,5 +134,6 @@ 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 */ === added file 'include/rfc2671.h' --- include/rfc2671.h 1970-01-01 00:00:00 +0000 +++ include/rfc2671.h 2010-09-20 09:42:41 +0000 @@ -0,0 +1,49 @@ +/* + * $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 */ === modified file 'include/rfc3596.h' --- include/rfc3596.h 2010-05-09 14:21:38 +0000 +++ include/rfc3596.h 2010-09-20 09:38:17 +0000 @@ -47,25 +47,29 @@ 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, @@ -73,7 +77,8 @@ 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 === modified file 'include/xstrto.h' --- include/xstrto.h 2010-10-06 03:50:45 +0000 +++ include/xstrto.h 2010-10-07 09:49:12 +0000 @@ -3,7 +3,7 @@ #include "config.h" -#ifdef HAVE_STDBOOL_H +#if HAVE_STDBOOL_H #include #endif === modified file 'lib/Makefile.am' --- lib/Makefile.am 2010-10-06 03:50:45 +0000 +++ lib/Makefile.am 2010-10-06 06:08:23 +0000 @@ -64,6 +64,7 @@ rfc1123.c \ rfc1738.c \ rfc2617.c \ + rfc2671.c \ rfc3596.c \ $(SNPRINTFSOURCE) \ Splay.cc \ === modified file 'lib/rfc1035.c' --- lib/rfc1035.c 2010-08-23 13:15:48 +0000 +++ lib/rfc1035.c 2010-10-07 11:18:12 +0000 @@ -67,6 +67,7 @@ #endif #include "rfc1035.h" +#include "rfc2671.h" #define RFC1035_MAXLABELSZ 63 #define rfc1035_unpack_error 15 @@ -345,6 +346,50 @@ } /* + * 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() * * Unpacks a RFC1035 Resource Record into 'RR' from a message buffer. @@ -647,7 +692,7 @@ * 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; @@ -657,12 +702,15 @@ 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; @@ -683,7 +731,7 @@ * 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; @@ -701,12 +749,15 @@ 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; @@ -733,10 +784,10 @@ 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; @@ -756,11 +807,11 @@ 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 { @@ -780,8 +831,8 @@ 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; === added file 'lib/rfc2671.c' --- lib/rfc2671.c 1970-01-01 00:00:00 +0000 +++ lib/rfc2671.c 2010-09-21 14:29:24 +0000 @@ -0,0 +1,20 @@ +#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); +} === modified file 'lib/rfc3596.c' --- lib/rfc3596.c 2010-05-09 14:21:38 +0000 +++ lib/rfc3596.c 2010-09-20 13:21:27 +0000 @@ -79,6 +79,7 @@ #endif #include "rfc3596.h" +#include "rfc2671.h" #ifndef SQUID_RFC1035_H #error RFC3596 Library depends on RFC1035 @@ -93,7 +94,7 @@ * 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; @@ -103,12 +104,15 @@ 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; @@ -129,9 +133,9 @@ * \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); } /** @@ -143,9 +147,9 @@ * \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); } @@ -158,7 +162,7 @@ * \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; @@ -170,11 +174,11 @@ (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; @@ -189,7 +193,7 @@ 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); } @@ -205,13 +209,15 @@ 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; @@ -229,8 +235,11 @@ 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; } @@ -254,7 +263,7 @@ ((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; } @@ -275,25 +284,25 @@ } } -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)); @@ -314,8 +323,8 @@ 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; === modified file 'src/cache_cf.cc' --- src/cache_cf.cc 2010-10-06 13:03:11 +0000 +++ src/cache_cf.cc 2010-10-07 11:21:41 +0000 @@ -145,6 +145,7 @@ static void defaults_if_none(void); static int parse_line(char *); static void parseBytesLine(size_t * bptr, const char *units); +static void parseBytesLineSigned(ssize_t * bptr, const char *units); static size_t parseBytesUnits(const char *unit); static void free_all(void); void requirePathnameExists(const char *name, const char *path); @@ -1046,6 +1047,50 @@ self_destruct(); } +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(m * d / u); + + if (static_cast(*bptr) * 2 != m * d / u * 2) + self_destruct(); +} + static size_t parseBytesUnits(const char *unit) { @@ -2812,6 +2857,12 @@ storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR); } +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); +} + #if UNUSED_CODE static void dump_kb_size_t(StoreEntry * entry, const char *name, size_t var) @@ -2848,6 +2899,12 @@ parseBytesLine(var, B_BYTES_STR); } +static void +parse_b_ssize_t(ssize_t * var) +{ + parseBytesLineSigned(var, B_BYTES_STR); +} + #if UNUSED_CODE static void parse_kb_size_t(size_t * var) @@ -2875,12 +2932,19 @@ } static void +free_ssize_t(ssize_t * var) +{ + *var = 0; +} + +static void free_b_int64_t(int64_t * var) { *var = 0; } #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 === modified file 'src/cf.data.depend' --- src/cf.data.depend 2010-10-06 03:50:45 +0000 +++ src/cf.data.depend 2010-10-06 06:08:23 +0000 @@ -10,6 +10,7 @@ authparam b_int64_t b_size_t +b_ssize_t cachedir cache_replacement_policy cachemgrpasswd ConfigAclTos === modified file 'src/cf.data.pre' --- src/cf.data.pre 2010-10-06 03:50:45 +0000 +++ src/cf.data.pre 2010-10-06 10:10:02 +0000 @@ -6598,6 +6598,34 @@ 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 === modified file 'src/dns_internal.cc' --- src/dns_internal.cc 2010-09-10 22:01:36 +0000 +++ src/dns_internal.cc 2010-10-07 11:55:31 +0000 @@ -85,9 +85,29 @@ #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; @@ -140,6 +160,9 @@ Ip::Address S; int nqueries; int nreplies; +#if WHEN_EDNS_RESPONSES_ARE_PARSED + int last_seen_edns; +#endif nsvc *vc; }; @@ -162,6 +185,34 @@ 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); @@ -182,7 +233,7 @@ 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); @@ -230,6 +281,10 @@ 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++; } @@ -609,6 +664,11 @@ 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"); @@ -626,15 +686,18 @@ 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) { @@ -953,7 +1016,7 @@ } 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; @@ -982,6 +1045,30 @@ 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); @@ -1040,10 +1127,11 @@ 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); @@ -1081,7 +1169,8 @@ 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); @@ -1205,7 +1294,7 @@ continue; } - idnsGrokReply(rbuf, len); + idnsGrokReply(rbuf, len, ns); } } @@ -1286,7 +1375,7 @@ (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); } @@ -1439,6 +1528,13 @@ 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(); } @@ -1535,10 +1631,11 @@ } 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; } @@ -1579,11 +1676,12 @@ 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 */ === modified file 'src/structs.h' --- src/structs.h 2010-10-06 03:50:45 +0000 +++ src/structs.h 2010-10-06 06:08:23 +0000 @@ -623,6 +623,10 @@ #endif int client_ip_max_connections; + + struct { + ssize_t packet_max; ///< maximum size EDNS advertised for DNS replies. + } dns; }; SQUIDCEXTERN SquidConfig Config;