Compare commits

..
6 changed files with 116 additions and 52 deletions

No files matched your search

+10
View File
@@ -3,6 +3,16 @@ version 2.64
--dhcp-client-update set. Thanks to Bernd Krumbroeck for
spotting the problem.
Finesse the check for /etc/hosts names which conflict with
DHCP names. Previously a name/address pair in /etc/hosts
which didn't match the name/address of a DHCP lease would
generate a warning. Now that only happesn if there is not
also a match. This allows multiple addresses for a name in
/etc/hosts with one of them assigned via DHCP.
Fix broken vendor-option processing for BOOTP. Thanks to
Hans-Joachim Baader for the bug report.
version 2.63
Do duplicate dhcp-host address check in --test mode.
+7 -1
View File
@@ -2,7 +2,13 @@ dnsmasq (2.64-1) unstable; urgency=low
* New upstream.
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 28 Aug 2012 16:19:15 +0000
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 4 Sep 2012 21:50:22 +0000
dnsmasq (2.63-3) unstable; urgency=low
* Move adduser dependency to dnsmasq-base. (closes: #686694)
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 4 Sep 2012 21:44:15 +0000
dnsmasq (2.63-2) unstable; urgency=low
+2 -2
View File
@@ -7,7 +7,7 @@ Standards-Version: 3.9.3
Package: dnsmasq
Architecture: all
Depends: netbase, adduser, dnsmasq-base(>= ${source:Version})
Depends: netbase, dnsmasq-base(>= ${source:Version})
Suggests: resolvconf
Conflicts: resolvconf (<<1.15)
Description: Small caching DNS proxy and DHCP/TFTP server
@@ -22,7 +22,7 @@ Description: Small caching DNS proxy and DHCP/TFTP server
Package: dnsmasq-base
Architecture: any
Depends: ${shlibs:Depends}
Depends: adduser, ${shlibs:Depends}
Breaks: dnsmasq (<< 2.63-1~)
Replaces: dnsmasq (<< 2.63-1~)
Description: Small caching DNS proxy and DHCP/TFTP server
+34 -28
View File
@@ -1042,7 +1042,7 @@ static void add_dhcp_cname(struct crec *target, time_t ttd)
void cache_add_dhcp_entry(char *host_name, int prot,
struct all_addr *host_address, time_t ttd)
{
struct crec *crec = NULL;
struct crec *crec = NULL, *fail_crec = NULL;
unsigned short flags = F_IPV4;
int in_hosts = 0;
size_t addrlen = sizeof(struct in_addr);
@@ -1055,28 +1055,21 @@ void cache_add_dhcp_entry(char *host_name, int prot,
}
#endif
inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
{
/* check all addresses associated with name */
if (crec->flags & F_HOSTS)
{
/* if in hosts, don't need DHCP record */
in_hosts = 1;
inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
if (crec->flags & F_CNAME)
my_syslog(MS_DHCP | LOG_WARNING,
_("%s is a CNAME, not giving it to the DHCP lease of %s"),
host_name, daemon->addrbuff);
else if (memcmp(&crec->addr.addr, host_address, addrlen) != 0)
{
inet_ntop(prot, &crec->addr.addr, daemon->namebuff, MAXDNAME);
my_syslog(MS_DHCP | LOG_WARNING,
_("not giving name %s to the DHCP lease of %s because "
"the name exists in %s with address %s"),
host_name, daemon->addrbuff,
record_source(crec->uid), daemon->namebuff);
}
else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0)
in_hosts = 1;
else
fail_crec = crec;
}
else if (!(crec->flags & F_DHCP))
{
@@ -1086,21 +1079,34 @@ void cache_add_dhcp_entry(char *host_name, int prot,
}
}
if (in_hosts)
/* if in hosts, don't need DHCP record */
if (in_hosts)
return;
if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
{
if (crec->flags & F_NEG)
{
flags |= F_REVERSE;
cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
}
}
else
flags |= F_REVERSE;
if ((crec = dhcp_spare))
/* Name in hosts, address doesn't match */
if (fail_crec)
{
inet_ntop(prot, &fail_crec->addr.addr, daemon->namebuff, MAXDNAME);
my_syslog(MS_DHCP | LOG_WARNING,
_("not giving name %s to the DHCP lease of %s because "
"the name exists in %s with address %s"),
host_name, daemon->addrbuff,
record_source(fail_crec->uid), daemon->namebuff);
return;
}
if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
{
if (crec->flags & F_NEG)
{
flags |= F_REVERSE;
cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
}
}
else
flags |= F_REVERSE;
if ((crec = dhcp_spare))
dhcp_spare = dhcp_spare->next;
else /* need new one */
crec = whine_malloc(sizeof(struct crec));
+44 -13
View File
@@ -383,15 +383,48 @@ int main (int argc, char **argv)
/* write pidfile _after_ forking ! */
if (daemon->runfile)
{
FILE *pidfile;
int fd, err = 0;
sprintf(daemon->namebuff, "%d\n", (int) getpid());
/* Explanation: Some installations of dnsmasq (eg Debian/Ubuntu) locate the pid-file
in a directory which is writable by the non-privileged user that dnsmasq runs as. This
allows the daemon to delete the file as part of its shutdown. This is a security hole to the
extent that an attacker running as the unprivileged user could replace the pidfile with a
symlink, and have the target of that symlink overwritten as root next time dnsmasq starts.
The folowing code first deletes any existing file, and then opens it with the O_EXCL flag,
ensuring that the open() fails should there be any existing file (because the unlink() failed,
or an attacker exploited the race between unlink() and open()). This ensures that no symlink
attack can succeed.
Any compromise of the non-privileged user still theoretically allows the pid-file to be
replaced whilst dnsmasq is running. The worst that could allow is that the usual
"shutdown dnsmasq" shell command could be tricked into stopping any other process.
Note that if dnsmasq is started as non-root (eg for testing) it silently ignores
failure to write the pid-file.
*/
unlink(daemon->runfile);
/* only complain if started as root */
if ((pidfile = fopen(daemon->runfile, "w")))
if ((fd = open(daemon->runfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)) == -1)
{
fprintf(pidfile, "%d\n", (int) getpid());
fclose(pidfile);
/* only complain if started as root */
if (getuid() == 0)
err = 1;
}
else if (getuid() == 0)
else
{
if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
err = 1;
while (!err && close(fd) == -1)
if (!retry_send())
err = 1;
}
if (err)
{
send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
_exit(0);
@@ -607,7 +640,7 @@ int main (int argc, char **argv)
end = &dhcp_tmp->end6;
struct in6_addr subnet = dhcp_tmp->start6;
setaddr6part(&subnet, 0);
inet_ntop(AF_INET6, &subnet, daemon->addrbuff, 256);
inet_ntop(AF_INET6, &subnet, daemon->dhcp_buff2, 256);
}
#endif
@@ -620,10 +653,8 @@ int main (int argc, char **argv)
prettyprint_time(p, dhcp_tmp->lease_time);
}
if (daemon->dhcp_buff)
inet_ntop(family, start, daemon->dhcp_buff, 256);
if (daemon->dhcp_buff3)
inet_ntop(family, end, daemon->dhcp_buff3, 256);
inet_ntop(family, start, daemon->dhcp_buff, 256);
inet_ntop(family, end, daemon->dhcp_buff3, 256);
if ((dhcp_tmp->flags & CONTEXT_DHCP) || family == AF_INET)
my_syslog(MS_DHCP | LOG_INFO,
(dhcp_tmp->flags & CONTEXT_RA_STATELESS) ?
@@ -637,7 +668,7 @@ int main (int argc, char **argv)
if (dhcp_tmp->flags & CONTEXT_RA_NAME)
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s"),
daemon->addrbuff);
daemon->dhcp_buff2);
if (dhcp_tmp->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))
{
if (!(dhcp_tmp->flags & CONTEXT_DEPRECATE))
@@ -647,7 +678,7 @@ int main (int argc, char **argv)
prettyprint_time(p, dhcp_tmp->lease_time > 7200 ? dhcp_tmp->lease_time : 7200);
}
my_syslog(MS_DHCP | LOG_INFO, _("SLAAC on %s %s"),
daemon->addrbuff, daemon->namebuff);
daemon->dhcp_buff2, daemon->namebuff);
}
}
+19 -8
View File
@@ -493,8 +493,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease_set_interface(lease, int_index, now);
clear_packet(mess, end);
match_vendor_opts(NULL, daemon->dhcp_opts); /* clear flags */
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
netid, subnet_addr, 0, 0, 0, NULL, 0, now);
netid, subnet_addr, 0, 0, -1, NULL, 0, now);
}
}
@@ -510,17 +511,27 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
char *pq = daemon->dhcp_buff;
unsigned char *pp, *op = option_ptr(opt, 0);
/* Set an MBZ bit to indicate receipt of FQDN option - cleared later */
fqdn_flags = *op | 0x10;
fqdn_flags = *op;
len -= 3;
op += 3;
pp = op;
/* Always force update, since the client has no way to do it itself. */
if (!option_bool(OPT_FQDN_UPDATE) && !(fqdn_flags & 0x01))
fqdn_flags |= 0x03;
fqdn_flags &= ~0x08;
/* NB, the following always sets at least one bit */
if (option_bool(OPT_FQDN_UPDATE))
{
if (fqdn_flags & 0x01)
{
fqdn_flags |= 0x02; /* set O */
fqdn_flags &= ~0x01; /* clear S */
}
fqdn_flags |= 0x08; /* set N */
}
else
{
if (!(fqdn_flags & 0x01))
fqdn_flags |= 0x03; /* set S and O */
fqdn_flags &= ~0x08; /* clear N */
}
if (fqdn_flags & 0x04)
while (*op != 0 && ((op + (*op) + 1) - pp) < len)