Compare commits

...
6 Commits
6 changed files with 114 additions and 50 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 --dhcp-client-update set. Thanks to Bernd Krumbroeck for
spotting the problem. 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 version 2.63
Do duplicate dhcp-host address check in --test mode. 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. * 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 dnsmasq (2.63-2) unstable; urgency=low
+2 -2
View File
@@ -7,7 +7,7 @@ Standards-Version: 3.9.3
Package: dnsmasq Package: dnsmasq
Architecture: all Architecture: all
Depends: netbase, adduser, dnsmasq-base(>= ${source:Version}) Depends: netbase, dnsmasq-base(>= ${source:Version})
Suggests: resolvconf Suggests: resolvconf
Conflicts: resolvconf (<<1.15) Conflicts: resolvconf (<<1.15)
Description: Small caching DNS proxy and DHCP/TFTP server 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 Package: dnsmasq-base
Architecture: any Architecture: any
Depends: ${shlibs:Depends} Depends: adduser, ${shlibs:Depends}
Breaks: dnsmasq (<< 2.63-1~) Breaks: dnsmasq (<< 2.63-1~)
Replaces: dnsmasq (<< 2.63-1~) Replaces: dnsmasq (<< 2.63-1~)
Description: Small caching DNS proxy and DHCP/TFTP server Description: Small caching DNS proxy and DHCP/TFTP server
+32 -26
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, void cache_add_dhcp_entry(char *host_name, int prot,
struct all_addr *host_address, time_t ttd) struct all_addr *host_address, time_t ttd)
{ {
struct crec *crec = NULL; struct crec *crec = NULL, *fail_crec = NULL;
unsigned short flags = F_IPV4; unsigned short flags = F_IPV4;
int in_hosts = 0; int in_hosts = 0;
size_t addrlen = sizeof(struct in_addr); size_t addrlen = sizeof(struct in_addr);
@@ -1055,28 +1055,21 @@ void cache_add_dhcp_entry(char *host_name, int prot,
} }
#endif #endif
inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME))) while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
{ {
/* check all addresses associated with name */ /* check all addresses associated with name */
if (crec->flags & F_HOSTS) 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) if (crec->flags & F_CNAME)
my_syslog(MS_DHCP | LOG_WARNING, my_syslog(MS_DHCP | LOG_WARNING,
_("%s is a CNAME, not giving it to the DHCP lease of %s"), _("%s is a CNAME, not giving it to the DHCP lease of %s"),
host_name, daemon->addrbuff); host_name, daemon->addrbuff);
else if (memcmp(&crec->addr.addr, host_address, addrlen) != 0) else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0)
{ in_hosts = 1;
inet_ntop(prot, &crec->addr.addr, daemon->namebuff, MAXDNAME); else
my_syslog(MS_DHCP | LOG_WARNING, fail_crec = crec;
_("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 (!(crec->flags & F_DHCP)) 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; return;
if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags))) /* Name in hosts, address doesn't match */
{ if (fail_crec)
if (crec->flags & F_NEG) {
{ inet_ntop(prot, &fail_crec->addr.addr, daemon->namebuff, MAXDNAME);
flags |= F_REVERSE; my_syslog(MS_DHCP | LOG_WARNING,
cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags); _("not giving name %s to the DHCP lease of %s because "
} "the name exists in %s with address %s"),
} host_name, daemon->addrbuff,
else record_source(fail_crec->uid), daemon->namebuff);
flags |= F_REVERSE; return;
}
if ((crec = dhcp_spare)) 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; dhcp_spare = dhcp_spare->next;
else /* need new one */ else /* need new one */
crec = whine_malloc(sizeof(struct crec)); crec = whine_malloc(sizeof(struct crec));
+44 -13
View File
@@ -383,15 +383,48 @@ int main (int argc, char **argv)
/* write pidfile _after_ forking ! */ /* write pidfile _after_ forking ! */
if (daemon->runfile) if (daemon->runfile)
{ {
FILE *pidfile; int fd, err = 0;
/* only complain if started as root */ sprintf(daemon->namebuff, "%d\n", (int) getpid());
if ((pidfile = fopen(daemon->runfile, "w")))
/* 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);
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()); /* only complain if started as root */
fclose(pidfile); 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); send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
_exit(0); _exit(0);
@@ -607,7 +640,7 @@ int main (int argc, char **argv)
end = &dhcp_tmp->end6; end = &dhcp_tmp->end6;
struct in6_addr subnet = dhcp_tmp->start6; struct in6_addr subnet = dhcp_tmp->start6;
setaddr6part(&subnet, 0); setaddr6part(&subnet, 0);
inet_ntop(AF_INET6, &subnet, daemon->addrbuff, 256); inet_ntop(AF_INET6, &subnet, daemon->dhcp_buff2, 256);
} }
#endif #endif
@@ -620,10 +653,8 @@ int main (int argc, char **argv)
prettyprint_time(p, dhcp_tmp->lease_time); prettyprint_time(p, dhcp_tmp->lease_time);
} }
if (daemon->dhcp_buff) inet_ntop(family, start, daemon->dhcp_buff, 256);
inet_ntop(family, start, daemon->dhcp_buff, 256); inet_ntop(family, end, daemon->dhcp_buff3, 256);
if (daemon->dhcp_buff3)
inet_ntop(family, end, daemon->dhcp_buff3, 256);
if ((dhcp_tmp->flags & CONTEXT_DHCP) || family == AF_INET) if ((dhcp_tmp->flags & CONTEXT_DHCP) || family == AF_INET)
my_syslog(MS_DHCP | LOG_INFO, my_syslog(MS_DHCP | LOG_INFO,
(dhcp_tmp->flags & CONTEXT_RA_STATELESS) ? (dhcp_tmp->flags & CONTEXT_RA_STATELESS) ?
@@ -637,7 +668,7 @@ int main (int argc, char **argv)
if (dhcp_tmp->flags & CONTEXT_RA_NAME) if (dhcp_tmp->flags & CONTEXT_RA_NAME)
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s"), 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_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))
{ {
if (!(dhcp_tmp->flags & CONTEXT_DEPRECATE)) 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); prettyprint_time(p, dhcp_tmp->lease_time > 7200 ? dhcp_tmp->lease_time : 7200);
} }
my_syslog(MS_DHCP | LOG_INFO, _("SLAAC on %s %s"), 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); lease_set_interface(lease, int_index, now);
clear_packet(mess, end); clear_packet(mess, end);
match_vendor_opts(NULL, daemon->dhcp_opts); /* clear flags */
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr), 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; char *pq = daemon->dhcp_buff;
unsigned char *pp, *op = option_ptr(opt, 0); unsigned char *pp, *op = option_ptr(opt, 0);
/* Set an MBZ bit to indicate receipt of FQDN option - cleared later */ fqdn_flags = *op;
fqdn_flags = *op | 0x10;
len -= 3; len -= 3;
op += 3; op += 3;
pp = op; pp = op;
/* Always force update, since the client has no way to do it itself. */ /* NB, the following always sets at least one bit */
if (!option_bool(OPT_FQDN_UPDATE) && !(fqdn_flags & 0x01)) if (option_bool(OPT_FQDN_UPDATE))
fqdn_flags |= 0x03; {
if (fqdn_flags & 0x01)
fqdn_flags &= ~0x08; {
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) if (fqdn_flags & 0x04)
while (*op != 0 && ((op + (*op) + 1) - pp) < len) while (*op != 0 && ((op + (*op) + 1) - pp) < len)