diff --git a/CHANGELOG b/CHANGELOG index 5bcce38..851612b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -35,7 +35,19 @@ version 2.77 is destroyed and recreated in the kernel. Thanks to Beniamino Galvani for the patch. + Allow wildcard CNAME records in authoritative zones. + For example --cname=*.example.com,default.example.com + Thanks to Pro Backup for sponsoring this development. + Bump the allowed backlog of TCP connections from 5 to 32, + and make this a compile-time configurable option. Thanks + to Donatas Abraitis for diagnosing this as a potential + problem. + + Add DNSMASQ_REQUESTED_OPTIONS environment variable to the + lease-change script. Thanks to ZHAO Yu for the patch. + + version 2.76 Include 0.0.0.0/8 in DNS rebind checks. This range translates to hosts on the local network, or, at diff --git a/debian/changelog b/debian/changelog index 3a3fcca..cc721bd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,7 +2,24 @@ dnsmasq (2.77-1) unstable; urgency=low * New upstream. - -- Simon Kelley Wed, 31 Aug 2016 21:48:10 +0000 + -- Simon Kelley Wed, 14 Dec 2016 18:01:40 +0000 + +dnsmasq (2.76-5) unstable; urgency=medium + + * Nail libnettle dependency to avoid ABI incompatibility. + (closes: #846642) + + -- Simon Kelley Wed, 14 Dec 2016 17:58:10 +0000 + +dnsmasq (2.76-4.1) unstable; urgency=medium + + * Non-maintainer upload. + * Add two upstream patches to fix binding to an interface being + destroyed and recreated. Closes: #834722. + + 2675f2061525bc954be14988d64384b74aa7bf8b + + 16800ea072dd0cdf14d951c4bb8d2808b3dfe53d + + -- Vincent Bernat Sat, 26 Nov 2016 20:15:34 +0100 dnsmasq (2.76-4) unstable; urgency=medium diff --git a/debian/shlibs.local b/debian/shlibs.local new file mode 100644 index 0000000..850b717 --- /dev/null +++ b/debian/shlibs.local @@ -0,0 +1 @@ +libnettle 6 libnettle6 (>= 3.3) diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index a13e4f5..2b46098 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -581,7 +581,7 @@ Return a PTR DNS record. .B --naptr-record=,,,,,[,] Return an NAPTR DNS record, as specified in RFC3403. .TP -.B --cname=,[,] +.B --cname=,[,][,] Return a CNAME record which indicates that is really . There are significant limitations on the target; it must be a DNS name which is known to dnsmasq from /etc/hosts (or additional @@ -589,7 +589,9 @@ hosts files), from DHCP, from --interface-name or from another .B --cname. If the target does not satisfy this criteria, the whole cname is ignored. The cname must be unique, but it -is permissable to have more than one cname pointing to the same target. +is permissable to have more than one cname pointing to the same target. Indeed +it's possible to declare multiple cnames to a target in a single line, like so: +.B --cname=cname1,cname2,target If the time-to-live is given, it overrides the default, which is zero or the value of -local-ttl. The value is a positive integer and gives @@ -1541,6 +1543,8 @@ DHCP relay-agent added any of these options. If the client provides vendor-class, DNSMASQ_VENDOR_CLASS. +DNSMASQ_REQUESTED_OPTIONS a string containing the decimal values in the Parameter Request List option, comma separated, if the parameter request list option is provided by the client. + For IPv6 only: If the client provides vendor-class, DNSMASQ_VENDOR_CLASS_ID, @@ -2206,7 +2210,12 @@ following data is used to populate the authoritative zone. .B --cname as long as the record name is in the authoritative domain. If the target of the CNAME is unqualified, then it is qualified with the -authoritative zone name. +authoritative zone name. CNAME used in this way (only) may be wildcards, as in + +.nf +.B cname=*.example.com,default.example.com +.fi + .PP IPv4 and IPv6 addresses from /etc/hosts (and .B --addn-hosts diff --git a/src/auth.c b/src/auth.c index f1ca2f5..21c5f8c 100644 --- a/src/auth.c +++ b/src/auth.c @@ -116,7 +116,8 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n struct interface_name *intr; struct naptr *na; struct all_addr addr; - struct cname *a; + struct cname *a, *candidate; + unsigned int wclen; /* Clear buffer beyond request to avoid risk of information disclosure. */ @@ -137,6 +138,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n { unsigned short flag = 0; int found = 0; + int cname_wildcard = 0; /* save pointer to name for copying into answers */ nameoffset = p - (unsigned char *)header; @@ -411,25 +413,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n } } - for (a = daemon->cnames; a; a = a->next) - if (hostname_isequal(name, a->alias) ) - { - log_query(F_CONFIG | F_CNAME, name, NULL, NULL); - strcpy(name, a->target); - if (!strchr(name, '.')) - { - strcat(name, "."); - strcat(name, zone->domain); - } - found = 1; - if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, - daemon->auth_ttl, &nameoffset, - T_CNAME, C_IN, "d", name)) - anscount++; - - goto cname_restart; - } - if (!cut) { nxdomain = 0; @@ -536,7 +519,60 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n } if (!found) - log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL); + { + /* Check for possible wildcard match against *.domain + return length of match, to get longest. + Note that if return length of wildcard section, so + we match b.simon to _both_ *.simon and b.simon + but return a longer (better) match to b.simon. + */ + for (wclen = 0, candidate = NULL, a = daemon->cnames; a; a = a->next) + if (a->alias[0] == '*') + { + char *test = name; + + while ((test = strchr(test+1, '.'))) + { + if (hostname_isequal(test, &(a->alias[1]))) + { + if (strlen(test) > wclen && !cname_wildcard) + { + wclen = strlen(test); + candidate = a; + cname_wildcard = 1; + } + break; + } + } + + } + else if (hostname_isequal(a->alias, name) && strlen(a->alias) > wclen) + { + /* Simple case, no wildcard */ + wclen = strlen(a->alias); + candidate = a; + } + + if (candidate) + { + log_query(F_CONFIG | F_CNAME, name, NULL, NULL); + strcpy(name, candidate->target); + if (!strchr(name, '.')) + { + strcat(name, "."); + strcat(name, zone->domain); + } + found = 1; + if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, + daemon->auth_ttl, &nameoffset, + T_CNAME, C_IN, "d", name)) + anscount++; + + goto cname_restart; + } + + log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL); + } } diff --git a/src/cache.c b/src/cache.c index eca56c8..9684a70 100644 --- a/src/cache.c +++ b/src/cache.c @@ -774,7 +774,8 @@ static void add_hosts_cname(struct crec *target) struct cname *a; for (a = daemon->cnames; a; a = a->next) - if (hostname_isequal(cache_get_name(target), a->target) && + if (a->alias[1] != '*' && + hostname_isequal(cache_get_name(target), a->target) && (crec = whine_malloc(sizeof(struct crec)))) { crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME; @@ -1056,7 +1057,8 @@ void cache_reload(void) /* Add CNAMEs to interface_names to the cache */ for (a = daemon->cnames; a; a = a->next) for (intr = daemon->int_names; intr; intr = intr->next) - if (hostname_isequal(a->target, intr->name) && + if (a->alias[1] != '*' && + hostname_isequal(a->target, intr->name) && ((cache = whine_malloc(sizeof(struct crec))))) { cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG; @@ -1177,7 +1179,8 @@ static void add_dhcp_cname(struct crec *target, time_t ttd) struct cname *a; for (a = daemon->cnames; a; a = a->next) - if (hostname_isequal(cache_get_name(target), a->target)) + if (a->alias[1] != '*' && + hostname_isequal(cache_get_name(target), a->target)) { if ((aliasc = dhcp_spare)) dhcp_spare = dhcp_spare->next; diff --git a/src/config.h b/src/config.h index 700729e..cd4636d 100644 --- a/src/config.h +++ b/src/config.h @@ -18,6 +18,7 @@ #define MAX_PROCS 20 /* max no children for TCP requests */ #define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */ #define TCP_MAX_QUERIES 100 /* Maximum number of queries per incoming TCP connection */ +#define TCP_BACKLOG 32 /* kernel backlog limit for TCP connections */ #define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */ #define SAFE_PKTSZ 1280 /* "go anywhere" UDP packet size */ #define KEYBLOCK_LEN 40 /* choose to mininise fragmentation when storing DNSSEC keys */ diff --git a/src/helper.c b/src/helper.c index 9c37e37..34a1c8f 100644 --- a/src/helper.c +++ b/src/helper.c @@ -556,6 +556,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) buf = grab_extradata(buf, end, "DNSMASQ_CIRCUIT_ID", &err); buf = grab_extradata(buf, end, "DNSMASQ_SUBSCRIBER_ID", &err); buf = grab_extradata(buf, end, "DNSMASQ_REMOTE_ID", &err); + buf = grab_extradata(buf, end, "DNSMASQ_REQUESTED_OPTIONS", &err); } buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err); diff --git a/src/network.c b/src/network.c index d87d08f..6169827 100644 --- a/src/network.c +++ b/src/network.c @@ -746,7 +746,7 @@ static int make_sock(union mysockaddr *addr, int type, int dienow) if (type == SOCK_STREAM) { - if (listen(fd, 5) == -1) + if (listen(fd, TCP_BACKLOG) == -1) goto err; } else if (family == AF_INET) diff --git a/src/option.c b/src/option.c index d0d9509..50d26ba 100644 --- a/src/option.c +++ b/src/option.c @@ -3730,22 +3730,27 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma case LOPT_CNAME: /* --cname */ { struct cname *new; - char *alias, *target, *ttls; + char *alias, *target, *last, *pen; int ttl = -1; - if (!(comma = split(arg))) - ret_err(gen_err); - - if ((ttls = split(comma)) && !atoi_check(ttls, &ttl)) - ret_err(_("bad TTL")); - - alias = canonicalise_opt(arg); - target = canonicalise_opt(comma); - - if (!alias || !target) - ret_err(_("bad CNAME")); - else + for (last = pen = NULL, comma = arg; comma; comma = split(comma)) { + pen = last; + last = comma; + } + + if (!pen) + ret_err(_("bad CNAME")); + + if (pen != arg && atoi_check(last, &ttl)) + last = pen; + + target = canonicalise_opt(last); + + while (arg != last) + { + alias = canonicalise_opt(arg); + for (new = daemon->cnames; new; new = new->next) if (hostname_isequal(new->alias, arg)) ret_err(_("duplicate CNAME")); @@ -3755,6 +3760,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma new->alias = alias; new->target = target; new->ttl = ttl; + + arg += strlen(arg)+1; } break; diff --git a/src/rfc2131.c b/src/rfc2131.c index 8b99d4b..491c3ca 100644 --- a/src/rfc2131.c +++ b/src/rfc2131.c @@ -1304,6 +1304,24 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, add_extradata_opt(lease, NULL); } + /* DNSMASQ_REQUESTED_OPTIONS */ + if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 1))) + { + int len = option_len(opt); + unsigned char *rop = option_ptr(opt, 0); + char *q = daemon->namebuff; + int i; + for (i = 0; i < len; i++) + { + q += snprintf(q, MAXDNAME - (q - daemon->namebuff), "%d%s", rop[i], i + 1 == len ? "" : ","); + } + lease_add_extradata(lease, (unsigned char *)daemon->namebuff, (q - daemon->namebuff), 0); + } + else + { + add_extradata_opt(lease, NULL); + } + /* space-concat tag set */ if (!tagif_netid) add_extradata_opt(lease, NULL); diff --git a/src/util.c b/src/util.c index 211690e..c99eb0d 100644 --- a/src/util.c +++ b/src/util.c @@ -323,7 +323,7 @@ int hostname_isequal(const char *a, const char *b) return 1; } - + time_t dnsmasq_time(void) { #ifdef HAVE_BROKEN_RTC