* Fixed a potential segfault with IPv6 option handling

* Add a suffix to all our config files so that RA never stamps on IPv4
* All valgrind errors fixed on FreeBSD (with ./configure --debug=YES)
* When started with an interface list, respect that with signal handling
* Fix a potential route table corruption if we failed to add a route
This commit is contained in:
roy 2012-03-28 10:19:31 +00:00
parent 7035527430
commit f08761da93
11 changed files with 121 additions and 82 deletions

View File

@ -435,9 +435,10 @@ find_route(struct rt *rts, const struct rt *r, struct rt **lrt,
}
static void
desc_route(const char *cmd, const struct rt *rt, const char *ifname)
desc_route(const char *cmd, const struct rt *rt)
{
char addr[sizeof("000.000.000.000") + 1];
const char *ifname = rt->iface->name;
strlcpy(addr, inet_ntoa(rt->dest), sizeof(addr));
if (rt->gate.s_addr == INADDR_ANY)
@ -465,7 +466,7 @@ route_deleted(const struct rt *rt)
f = find_route(routes, rt, &l, NULL);
if (f == NULL)
return 0;
desc_route("removing", f, f->iface->name);
desc_route("removing", f);
if (l)
l->next = f->next;
else
@ -475,59 +476,60 @@ route_deleted(const struct rt *rt)
}
static int
n_route(struct rt *rt, const struct interface *iface)
n_route(struct rt *rt)
{
/* Don't set default routes if not asked to */
if (rt->dest.s_addr == 0 &&
rt->net.s_addr == 0 &&
!(iface->state->options->options & DHCPCD_GATEWAY))
!(rt->iface->state->options->options & DHCPCD_GATEWAY))
return -1;
desc_route("adding", rt, iface->name);
if (!add_route(iface, &rt->dest, &rt->net, &rt->gate, iface->metric))
desc_route("adding", rt);
if (!add_route(rt))
return 0;
if (errno == EEXIST) {
/* Pretend we added the subnet route */
if (rt->dest.s_addr == (iface->addr.s_addr & iface->net.s_addr) &&
rt->net.s_addr == iface->net.s_addr &&
if (rt->dest.s_addr ==
(rt->iface->addr.s_addr & rt->iface->net.s_addr) &&
rt->net.s_addr == rt->iface->net.s_addr &&
rt->gate.s_addr == 0)
return 0;
else
return -1;
}
syslog(LOG_ERR, "%s: add_route: %m", iface->name);
syslog(LOG_ERR, "%s: add_route: %m", rt->iface->name);
return -1;
}
static int
c_route(struct rt *ort, struct rt *nrt, const struct interface *iface)
c_route(struct rt *ort, struct rt *nrt)
{
/* Don't set default routes if not asked to */
if (nrt->dest.s_addr == 0 &&
nrt->net.s_addr == 0 &&
!(iface->state->options->options & DHCPCD_GATEWAY))
!(nrt->iface->state->options->options & DHCPCD_GATEWAY))
return -1;
desc_route("changing", nrt, iface->name);
desc_route("changing", nrt);
/* We delete and add the route so that we can change metric.
* This also has the nice side effect of flushing ARP entries so
* we don't have to do that manually. */
del_route(ort->iface, &ort->dest, &ort->net, &ort->gate, ort->metric);
if (!add_route(iface, &nrt->dest, &nrt->net, &nrt->gate, nrt->metric))
del_route(ort);
if (!add_route(nrt))
return 0;
syslog(LOG_ERR, "%s: add_route: %m", iface->name);
syslog(LOG_ERR, "%s: add_route: %m", nrt->iface->name);
return -1;
}
static int
d_route(struct rt *rt, const struct interface *iface, int metric)
d_route(struct rt *rt)
{
int retval;
desc_route("deleting", rt, iface->name);
retval = del_route(iface, &rt->dest, &rt->net, &rt->gate, metric);
desc_route("deleting", rt);
retval = del_route(rt);
if (retval != 0 && errno != ENOENT && errno != ESRCH)
syslog(LOG_ERR,"%s: del_route: %m", iface->name);
syslog(LOG_ERR,"%s: del_route: %m", rt->iface->name);
return retval;
}
@ -712,7 +714,7 @@ build_routes(void)
rt->gate.s_addr != or->gate.s_addr ||
rt->metric != or->metric)
{
if (c_route(or, rt, ifp) != 0)
if (c_route(or, rt) != 0)
continue;
}
if (rtl != NULL)
@ -721,7 +723,7 @@ build_routes(void)
routes = or->next;
free(or);
} else {
if (n_route(rt, ifp) != 0)
if (n_route(rt) != 0)
continue;
}
if (dnr == rt)
@ -730,6 +732,7 @@ build_routes(void)
lrt->next = rtn;
rt->next = nrs;
nrs = rt;
rt = lrt; /* When we loop this makes lrt correct */
}
free_routes(dnr);
}
@ -737,7 +740,7 @@ build_routes(void)
/* Remove old routes we used to manage */
for (rt = routes; rt; rt = rt->next) {
if (find_route(nrs, rt, NULL, NULL) == NULL)
d_route(rt, rt->iface, rt->iface->metric);
d_route(rt);
}
free_routes(routes);
@ -817,8 +820,9 @@ configure(struct interface *iface)
rt = get_subnet_route(dhcp);
if (rt != NULL) {
rt->iface = iface;
rt->metric = 0;
if (!find_route(routes, rt, NULL, NULL))
del_route(iface, &rt->dest, &rt->net, &rt->gate, 0);
del_route(rt);
free(rt);
}

View File

@ -28,7 +28,7 @@
#define CONFIG_H
#define PACKAGE "dhcpcd"
#define VERSION "5.5.5"
#define VERSION "5.5.6"
#ifndef CONFIG
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"

View File

@ -12,7 +12,7 @@ NL="
build_resolv_conf()
{
local cf="$state_dir/resolv.conf.$interface$if_suffix"
local cf="$state_dir/resolv.conf.$ifname"
local interfaces= header= search= srvs= servers= x=
# Build a list of interfaces
@ -114,25 +114,25 @@ add_resolv_conf()
done
if type resolvconf >/dev/null 2>&1; then
[ -n "$ifmetric" ] && export IF_METRIC="$ifmetric"
printf %s "$conf" | resolvconf -a "$interface$if_suffix"
printf %s "$conf" | resolvconf -a "$ifname"
return $?
fi
if [ -e "$resolv_conf_dir/$interface$if_suffix" ]; then
rm -f "$resolv_conf_dir/$interface$if_suffix"
if [ -e "$resolv_conf_dir/$ifname" ]; then
rm -f "$resolv_conf_dir/$ifname"
fi
[ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir"
printf %s "$conf" > "$resolv_conf_dir/$interface$if_suffix"
printf %s "$conf" > "$resolv_conf_dir/$ifname"
build_resolv_conf
}
remove_resolv_conf()
{
if type resolvconf >/dev/null 2>&1; then
resolvconf -d "$interface$if_suffix" -f
resolvconf -d "$ifname" -f
else
if [ -e "$resolv_conf_dir/$interface$if_suffix" ]; then
rm -f "$resolv_conf_dir/$interface$if_suffix"
if [ -e "$resolv_conf_dir/$ifname" ]; then
rm -f "$resolv_conf_dir/$ifname"
fi
build_resolv_conf
fi

View File

@ -25,7 +25,7 @@ NL="
build_ntp_conf()
{
local cf="$state_dir/ntp.conf.$interface"
local cf="$state_dir/ntp.conf.$ifname"
local interfaces= header= srvs= servers= x=
# Build a list of interfaces
@ -75,7 +75,7 @@ build_ntp_conf()
add_ntp_conf()
{
local cf="$ntp_conf_dir/$interface" x=
local cf="$ntp_conf_dir/$ifname" x=
[ -e "$cf" ] && rm "$cf"
[ -d "$ntp_conf_dir" ] || mkdir -p "$ntp_conf_dir"
@ -89,8 +89,8 @@ add_ntp_conf()
remove_ntp_conf()
{
if [ -e "$ntp_conf_dir/$interface" ]; then
rm "$ntp_conf_dir/$interface"
if [ -e "$ntp_conf_dir/$ifname" ]; then
rm "$ntp_conf_dir/$ifname"
fi
build_ntp_conf
}

View File

@ -20,12 +20,12 @@ best_domain()
make_yp_binding()
{
[ -d "$ypbind_dir" ] || mkdir -p "$ypbind_dir"
echo "$new_nis_domain" >"$ypbind_dir/$interface"
echo "$new_nis_domain" >"$ypbind_dir/$ifname"
local nd="$(best_domain)"
local cf=/var/yp/binding/"$new_nis_domain".ypservers
if [ -n "$new_nis_servers" ]; then
local ncf="$cf.$interface" x=
local ncf="$cf.$ifname" x=
rm -f "$ncf"
for x in $new_nis_servers; do
echo "$x" >>"$ncf"
@ -46,7 +46,7 @@ make_yp_binding()
restore_yp_binding()
{
rm -f "$ypbind_dir/$interface"
rm -f "$ypbind_dir/$ifname"
local nd="$(best_domain)"
# We need to stop ypbind if there is no best domain
# otherwise it will just stall as we cannot set domainname
@ -64,7 +64,7 @@ restore_yp_binding()
}
if [ "$reason" = PREINIT ]; then
rm -f "$ypbind_dir/$interface"
rm -f "$ypbind_dir/$ifname"
elif $if_up || $if_down; then
if [ -n "$new_nis_domain" ]; then
if valid_domainname "$new_nis_domain"; then

View File

@ -2,19 +2,20 @@
# dhcpcd client configuration script
# Handy variables and functions for our hooks to use
if [ "$reason" = ROUTERADVERT ]; then
ifsuffix=":ra"
else
ifsuffix=
fi
ifname="$interface$ifsuffix"
from=from
signature_base="# Generated by dhcpcd"
signature="$signature_base $from $interface"
signature="$signature_base $from $ifname"
signature_base_end="# End of dhcpcd"
signature_end="$signature_base_end $from $interface"
signature_end="$signature_base_end $from $ifname"
state_dir=/var/run/dhcpcd
if [ "$reason" = ROUTERADVERT ]; then
if_suffix=":ra"
else
if_suffix=
fi
# Ensure that all arguments are unique
uniqify()
{

View File

@ -146,15 +146,24 @@ read_pid(void)
static void
usage(void)
{
printf("usage: "PACKAGE" [-dgknpqwxyADEGHJKLOTV] [-c script] [-f file]"
" [-e var=val]\n"
" [-h hostname] [-i classID ] [-l leasetime]"
" [-m metric] [-o option]\n"
" [-r ipaddr] [-s ipaddr] [-t timeout]"
" [-u userclass]\n"
" [-F none|ptr|both] [-I clientID] [-C hookscript]"
" [-Q option]\n"
" [-X ipaddr] <interface>\n");
printf("usage: "PACKAGE"\t[-ABbDdEGgHJKkLnpqTVw]\n"
"\t\t[-C, --nohook hook] [-c, --script script]\n"
"\t\t[-e, --env value] [-F, --fqdn FQDN] [-f, --config file]\n"
"\t\t[-h, --hostname hostname] [-I, --clientid clientid]\n"
"\t\t[-i, --vendorclassid vendorclassid] [-l, --leasetime seconds]\n"
"\t\t[-m, --metric metric] [-O, --nooption option]\n"
"\t\t[-o, --option option] [-Q, --require option]\n"
"\t\t[-r, --request address] [-S, --static value]\n"
"\t\t[-s, --inform address[/cidr]] [-t, --timeout seconds]\n"
"\t\t[-u, --userclass class] [-v, --vendor code, value]\n"
"\t\t[-W, --whitelist address[/cidr]] [-y, --reboot seconds]\n"
"\t\t[-X, --blacklist address[/cidr]] [-Z, --denyinterfaces pattern]\n"
"\t\t[-z, --allowinterfaces pattern] [interface] [...]\n"
" "PACKAGE"\t-k, --release [interface]\n"
" "PACKAGE"\t-U, --dumplease interface\n"
" "PACKAGE"\t-v, --version\n"
" "PACKAGE"\t-x, --exit [interface]\n");
}
static void
@ -1524,7 +1533,7 @@ handle_signal(_unused void *arg)
ifo->options |= DHCPCD_DAEMONISED;
options = ifo->options;
free_options(ifo);
reconf_reboot(1, 0, NULL, 0);
reconf_reboot(1, ifc, ifv, 0);
return;
case SIGHUP:
syslog(LOG_INFO, "received SIGHUP, releasing");

View File

@ -90,6 +90,15 @@ if_conf(_unused struct interface *iface)
return 0;
}
#ifdef DEBUG_MEMORY
static void
cleanup(void)
{
free(link_buf);
}
#endif
int
init_sockets(void)
{
@ -129,6 +138,7 @@ getifssid(const char *ifname, char *ssid)
strlcpy(ireq.i_name, ifname, sizeof(ireq.i_name));
ireq.i_type = IEEE80211_IOC_SSID;
ireq.i_val = -1;
memset(nwid, 0, sizeof(nwid));
ireq.i_data = &nwid;
if (ioctl(socket_afnet, SIOCG80211, &ireq) == 0) {
retval = ireq.i_len;
@ -177,9 +187,7 @@ if_address(const struct interface *iface, const struct in_addr *address,
/* ARGSUSED4 */
int
if_route(const struct interface *iface, const struct in_addr *dest,
const struct in_addr *net, const struct in_addr *gate,
_unused int metric, int action)
if_route(const struct rt *rt, int action)
{
union sockunion {
struct sockaddr sa;
@ -223,12 +231,13 @@ if_route(const struct interface *iface, const struct in_addr *dest,
rtm.hdr.rtm_type = RTM_DELETE;
rtm.hdr.rtm_flags = RTF_UP;
/* None interface subnet routes are static. */
if (gate->s_addr != INADDR_ANY ||
net->s_addr != iface->net.s_addr ||
dest->s_addr != (iface->addr.s_addr & iface->net.s_addr))
if (rt->gate.s_addr != INADDR_ANY ||
rt->net.s_addr != rt->iface->net.s_addr ||
rt->dest.s_addr != (rt->iface->addr.s_addr & rt->iface->net.s_addr))
rtm.hdr.rtm_flags |= RTF_STATIC;
rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
if (dest->s_addr == gate->s_addr && net->s_addr == INADDR_BROADCAST)
if (rt->dest.s_addr == rt->gate.s_addr &&
rt->net.s_addr == INADDR_BROADCAST)
rtm.hdr.rtm_flags |= RTF_HOST;
else {
rtm.hdr.rtm_addrs |= RTA_NETMASK;
@ -238,23 +247,23 @@ if_route(const struct interface *iface, const struct in_addr *dest,
rtm.hdr.rtm_addrs |= RTA_IFA;
}
ADDADDR(dest);
ADDADDR(&rt->dest);
if (rtm.hdr.rtm_flags & RTF_HOST ||
!(rtm.hdr.rtm_flags & RTF_STATIC))
{
/* Make us a link layer socket for the host gateway */
memset(&su, 0, sizeof(su));
su.sdl.sdl_len = sizeof(struct sockaddr_dl);
link_addr(iface->name, &su.sdl);
link_addr(rt->iface->name, &su.sdl);
ADDSU(su);
} else
ADDADDR(gate);
ADDADDR(&rt->gate);
if (rtm.hdr.rtm_addrs & RTA_NETMASK)
ADDADDR(net);
ADDADDR(&rt->net);
if (rtm.hdr.rtm_addrs & RTA_IFA)
ADDADDR(&iface->addr);
ADDADDR(&rt->iface->addr);
rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
if (write(r_fd, &rtm, l) == -1)
@ -267,6 +276,11 @@ open_link_socket(void)
{
int fd;
#ifdef DEBUG_MEMORY
if (link_buf == NULL)
atexit(cleanup);
#endif
fd = socket(PF_ROUTE, SOCK_RAW, 0);
if (fd != -1) {
set_cloexec(fd);

View File

@ -533,7 +533,8 @@ ipv6rs_handledata(_unused void *arg)
rap->options = rao;
rao->type = ndo->nd_opt_type;
rao->option = opt;
}
} else
free(opt);
if (lifetime == ~0U)
timerclear(&rao->expire);
else {
@ -751,7 +752,6 @@ ipv6rs_start(struct interface *ifp)
/* Always make a new probe as the underlying hardware
* address could have changed. */
free(ifp->rs);
ipv6rs_makeprobe(ifp);
if (ifp->rs == NULL)
return -1;

View File

@ -74,6 +74,21 @@ static char hwaddr_buffer[(HWADDR_LEN * 3) + 1];
int socket_afnet = -1;
#if defined(__FreeBSD__) && defined(DEBUG_MEMORY)
/* FreeBSD does not zero the struct, causing valgrind errors */
unsigned int
if_nametoindex(const char *ifname)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
if (ioctl(socket_afnet, SIOCGIFINDEX, &ifr) != -1)
return ifr.ifr_index;
return 0;
}
#endif
int
inet_ntocidr(struct in_addr address)
{
@ -242,6 +257,7 @@ free_interface(struct interface *iface)
free(iface->state->offer);
free(iface->state);
}
free(iface->buffer);
free(iface->clientid);
free(iface);
}

View File

@ -124,16 +124,11 @@ int if_address(const struct interface *,
#define get_address(iface, addr, net, dst) \
do_address(iface, addr, net, dst, 1)
int if_route(const struct interface *, const struct in_addr *,
const struct in_addr *, const struct in_addr *, int, int);
#define add_route(iface, dest, mask, gate, metric) \
if_route(iface, dest, mask, gate, metric, 1)
#define change_route(iface, dest, mask, gate, metric) \
if_route(iface, dest, mask, gate, metric, 0)
#define del_route(iface, dest, mask, gate, metric) \
if_route(iface, dest, mask, gate, metric, -1)
#define del_src_route(iface, dest, mask, gate, metric) \
if_route(iface, dest, mask, gate, metric, -2)
int if_route(const struct rt *rt, int);
#define add_route(rt) if_route(rt, 1)
#define change_route(rt) if_route(rt, 0)
#define del_route(rt) if_route(rt, -1)
#define del_src_route(rt) if_route(rt, -2);
void free_routes(struct rt *);
int open_udp_socket(struct interface *);