Import dhcpcd-5.6.2 with the following changes:

Disable kernel RA earlier on Linux
* Don't set if_up or if_down as true when testing
* ra%d_prefix is now a space separated array of the finished address/len
* If we fail to open sockets, don't bother sending the request
* Send our NS solicitation directly to the router
* Change the NS times so that we assume reachable until the reachable time
  expires, then send probes at retrans intervals until
  DELAY_FIRST_PROBE_TIME is reached at which point we expire the router
* Remove -v from --version in usage
* Only add our own host or destination routes to the build table when we
  are adding gateways
* Ensure we have correct memory allocation for each prefix in the RA
This commit is contained in:
roy 2012-09-03 09:46:12 +00:00
parent 2b2704572b
commit 363f3bbd25
10 changed files with 122 additions and 89 deletions

View File

@ -37,6 +37,11 @@
#define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
#define timeval_to_double(tv) ((tv)->tv_sec * 1.0 + (tv)->tv_usec * 1.0e-6)
#define ms_to_tv(tv, ms) \
do { \
(tv)->tv_sec = (ms / 1000); \
(tv)->tv_usec = ((ms % 1000) * 1000); \
} while (0 /* CONSTCOND */);
#define timernorm(tvp) \
do { \
while ((tvp)->tv_usec >= 1000000) { \

View File

@ -216,7 +216,10 @@ make_env(const struct interface *iface, const char *reason, char ***argv)
e--;
}
*--p = '\0';
if ((dhcp && iface->state->new) || (ra && ipv6rs_has_ra(iface))) {
if (strcmp(reason, "TEST") == 0) {
env[8] = strdup("if_up=false");
env[9] = strdup("if_down=false");
} else if ((dhcp && iface->state->new) || (ra && ipv6rs_has_ra(iface))){
env[8] = strdup("if_up=true");
env[9] = strdup("if_down=false");
} else {
@ -692,8 +695,10 @@ build_routes(void)
dnr = get_routes(ifp);
dnr = massage_host_routes(dnr, ifp);
dnr = add_subnet_route(dnr, ifp);
dnr = add_router_host_route(dnr, ifp);
dnr = add_destination_route(dnr, ifp);
if (ifp->state->options->options & DHCPCD_GATEWAY) {
dnr = add_router_host_route(dnr, ifp);
dnr = add_destination_route(dnr, ifp);
}
for (rt = dnr; rt && (rtn = rt->next, 1); lrt = rt, rt = rtn) {
rt->iface = ifp;
rt->metric = ifp->metric;

View File

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

View File

@ -163,7 +163,7 @@ printf("usage: "PACKAGE"\t[-ABbDdEGgHJKkLnpqTVw]\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--version\n"
" "PACKAGE"\t-x, --exit [interface]\n");
}
@ -326,7 +326,11 @@ send_message(struct interface *iface, int type,
}
/* Ensure sockets are open. */
open_sockets(iface);
if (open_sockets(iface) == -1) {
if (!(options & DHCPCD_TEST))
drop_dhcp(iface, "FAIL");
return;
}
/* If we couldn't open a UDP port for our IP address
* then we cannot renew.
@ -785,6 +789,12 @@ configure_interface1(struct interface *iface)
if (ifo->metric != -1)
iface->metric = ifo->metric;
/* We want to disable kernel interface RA as early as possible. */
if (options & DHCPCD_IPV6RS && ifo->options & DHCPCD_IPV6RS) {
if (check_ipv6(iface->name) != 1)
ifo->options &= ~DHCPCD_IPV6RS;
}
/* If we haven't specified a ClientID and our hardware address
* length is greater than DHCP_CHADDR_LEN then we enforce a ClientID
* of the hardware address family and the hardware address. */
@ -1167,12 +1177,8 @@ start_interface(void *arg)
free(iface->state->offer);
iface->state->offer = NULL;
if (options & DHCPCD_IPV6RS && ifo->options & DHCPCD_IPV6RS) {
if (check_ipv6(iface->name) == 1)
ipv6rs_start(iface);
else
ifo->options &= ~DHCPCD_IPV6RS;
}
if (options & DHCPCD_IPV6RS && ifo->options & DHCPCD_IPV6RS)
ipv6rs_start(iface);
if (iface->state->arping_index < ifo->arping_len) {
start_arping(iface);
@ -1708,11 +1714,13 @@ handle_args(struct fd_list *fd, int argc, char **argv)
return 0;
}
void
int
open_sockets(struct interface *iface)
{
int r = 0;
if (iface->raw_fd == -1) {
if (open_socket(iface, ETHERTYPE_IP) == -1)
if ((r = open_socket(iface, ETHERTYPE_IP)) == -1)
syslog(LOG_ERR, "%s: open_socket: %m", iface->name);
else
add_event(iface->raw_fd, handle_dhcp_packet, iface);
@ -1723,9 +1731,12 @@ open_sockets(struct interface *iface)
(iface->state->new->cookie == htonl(MAGIC_COOKIE) ||
iface->state->options->options & DHCPCD_INFORM))
{
if (open_udp_socket(iface) == -1 && errno != EADDRINUSE)
if (open_udp_socket(iface) == -1 && errno != EADDRINUSE) {
syslog(LOG_ERR, "%s: open_udp_socket: %m", iface->name);
r = -1;
}
}
return r;
}
void

View File

@ -141,7 +141,7 @@ void start_rebind(void *);
void start_reboot(struct interface *);
void start_expire(void *);
void send_decline(struct interface *);
void open_sockets(struct interface *);
int open_sockets(struct interface *);
void close_sockets(struct interface *);
void drop_dhcp(struct interface *, const char *);
void drop_interface(struct interface *, const char *);

View File

@ -327,6 +327,9 @@ int
ipv6_remove_subnet(struct ra *rap, struct ipv6_addr *addr)
{
struct rt6 *rt;
#if HAVE_ROUTE_METRIC
struct rt6 *ort;
#endif
int r;
/* We need to delete the subnet route to have our metric or
@ -340,7 +343,15 @@ ipv6_remove_subnet(struct ra *rap, struct ipv6_addr *addr)
#else
rt->metric = 0;
#endif
#if HAVE_ROUTE_METRIC
/* For some reason, Linux likes to re-add the subnet
route under the original metric.
I would love to find a way of stopping this! */
if ((ort = find_route6(routes, rt)) == NULL ||
ort->metric != rt->metric)
#else
if (!find_route6(routes, rt))
#endif
r = del_route6(rt);
free(rt);
}
@ -367,12 +378,13 @@ ipv6_build_routes(void)
TAILQ_FOREACH(rap, &ipv6_routers, next) {
if (rap->expired)
continue;
if (options & DHCPCD_IPV6RA_OWN)
if (options & DHCPCD_IPV6RA_OWN) {
TAILQ_FOREACH(addr, &rap->addrs, next) {
rt = make_prefix(rap, addr);
if (rt)
TAILQ_INSERT_TAIL(&dnr, rt, next);
}
}
rt = make_router(rap);
if (rt)
TAILQ_INSERT_TAIL(&dnr, rt, next);

View File

@ -60,7 +60,7 @@
//#define DEBUG_NS
static int sock;
static struct sockaddr_in6 allrouters, from;
static struct sockaddr_in6 from;
static struct msghdr sndhdr;
static struct iovec sndiov[2];
static unsigned char *sndbuf;
@ -87,13 +87,6 @@ ipv6ns_open(void)
int len;
struct icmp6_filter filt;
memset(&allrouters, 0, sizeof(allrouters));
allrouters.sin6_family = AF_INET6;
#ifdef SIN6_LEN
allrouters.sin6_len = sizeof(allrouters);
#endif
if (inet_pton(AF_INET6, ALLROUTERS, &allrouters.sin6_addr.s6_addr) != 1)
return -1;
sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
if (sock == -1)
return -1;
@ -165,6 +158,20 @@ ipv6ns_makeprobe(struct ra *rap)
return 0;
}
static void
ipv6ns_unreachable(void *arg)
{
struct ra *rap = arg;
/* We could add an unreachable flag and persist the information,
* but that is more effort than it's probably worth. */
syslog(LOG_WARNING, "%s: %s is unreachable, expiring it",
rap->iface->name, rap->sfrom);
rap->expired = 1;
ipv6_build_routes();
run_script_reason(rap->iface, "ROUTERADVERT"); /* XXX not RA */
}
void
ipv6ns_sendprobe(void *arg)
{
@ -175,13 +182,18 @@ ipv6ns_sendprobe(void *arg)
int hoplimit = HOPLIMIT;
struct timeval tv, rtv;
if (!rap->nsprobes) {
if (!rap->ns) {
if (ipv6ns_makeprobe(rap) == -1)
return;
}
dst = allrouters;
//dst.sin6_scope_id = ifp->linkid;
memset(&dst, 0, sizeof(dst));
dst.sin6_family = AF_INET6;
#ifdef SIN6_LEN
dst.sin6_len = sizeof(dst);
#endif
memcpy(&dst.sin6_addr, &rap->from, sizeof(dst.sin6_addr));
//dst.sin6_scope_id = rap->iface->index;
sndhdr.msg_name = (caddr_t)&dst;
sndhdr.msg_iov[0].iov_base = rap->ns;
@ -210,26 +222,18 @@ ipv6ns_sendprobe(void *arg)
if (sendmsg(sock, &sndhdr, 0) == -1)
syslog(LOG_ERR, "%s: sendmsg: %m", rap->iface->name);
tv.tv_sec = RETRANS_TIMER;
tv.tv_usec = MIN_RANDOM_FACTOR;
ms_to_tv(&tv, rap->retrans ? rap->retrans : RETRANS_TIMER);
ms_to_tv(&rtv, MIN_RANDOM_FACTOR);
timeradd(&tv, &rtv, &tv);
rtv.tv_sec = 0;
rtv.tv_usec = arc4random() % (MAX_RANDOM_FACTOR - MIN_RANDOM_FACTOR);
timeradd(&tv, &rtv, &tv);
add_timeout_tv(&tv, ipv6ns_sendprobe, rap);
}
void
ipv6ns_unreachable(void *arg)
{
struct ra *rap = arg;
/* We could add an unreachable flag and persist the information,
* but that is more effort than it's probably worth. */
syslog(LOG_WARNING, "%s: %s is unreachable, expiring it",
rap->iface->name, rap->sfrom);
rap->expired = 1;
ipv6_build_routes();
run_script_reason(rap->iface, "ROUTERADVERT"); /* XXX not RA */
if (rap->nsprobes++ == 0)
add_timeout_sec(DELAY_FIRST_PROBE_TIME,
ipv6ns_unreachable, rap);
}
/* ARGSUSED */
@ -246,6 +250,7 @@ ipv6ns_handledata(_unused void *arg)
struct nd_neighbor_advert *nd_na;
struct ra *rap;
int is_router, is_solicited;
struct timeval tv;
len = recvmsg(sock, &rcvhdr, 0);
if (len == -1) {
@ -342,8 +347,14 @@ ipv6ns_handledata(_unused void *arg)
}
if (is_solicited) {
rap->nsprobes = 1;
add_timeout_sec(REACHABLE_TIME, ipv6ns_unreachable, rap);
add_timeout_sec(DELAY_FIRST_PROBE_TIME, ipv6ns_sendprobe, rap);
rap->nsprobes = 0;
if (rap->reachable) {
ms_to_tv(&tv, rap->reachable);
} else {
tv.tv_sec = REACHABLE_TIME;
tv.tv_usec = 0;
}
add_timeout_tv(&tv, ipv6ns_sendprobe, rap);
delete_timeout(ipv6ns_unreachable, rap);
}
}

View File

@ -31,12 +31,12 @@
#include "dhcpcd.h"
#include "ipv6rs.h"
#define MAX_REACHABLE_TIME 3600 /* seconds */
#define REACHABLE_TIME 30 /* seconds */
#define RETRANS_TIMER 1 /* second */
#define DELAY_FIRST_PROBE_TIME 5 /* seconds */
int ipv6ns_open(void);
void ipv6ns_unreachable(void *);
void ipv6ns_sendprobe(void *);
void ipv6ns_handledata(void *);
#endif

View File

@ -447,6 +447,9 @@ ipv6rs_handledata(_unused void *arg)
if (rap) {
free(rap->data);
rap->data_len = 0;
free(rap->ns);
rap->ns = NULL;
rap->nslen = 0;
}
syslog(LOG_INFO, "%s: Router Advertisement from %s",
ifp->name, sfrom);
@ -473,6 +476,13 @@ ipv6rs_handledata(_unused void *arg)
nd_ra = (struct nd_router_advert *)icp;
rap->flags = nd_ra->nd_ra_flags_reserved;
rap->lifetime = ntohs(nd_ra->nd_ra_router_lifetime);
if (nd_ra->nd_ra_reachable) {
rap->reachable = ntohl(nd_ra->nd_ra_reachable);
if (rap->reachable > MAX_REACHABLE_TIME)
rap->reachable = 0;
}
if (nd_ra->nd_ra_retransmit)
rap->retrans = ntohl(nd_ra->nd_ra_retransmit);
rap->expired = 0;
len -= sizeof(struct nd_router_advert);
@ -537,8 +547,8 @@ ipv6rs_handledata(_unused void *arg)
cbp = inet_ntop(AF_INET6, ap->addr.s6_addr,
ntopbuf, INET6_ADDRSTRLEN);
if (cbp)
memcpy(ap->saddr, cbp,
sizeof(ap->saddr));
snprintf(ap->saddr, sizeof(ap->saddr),
"%s/%d", cbp, ap->prefix_len);
else
ap->saddr[0] = '\0';
TAILQ_INSERT_TAIL(&rap->addrs, ap, next);
@ -553,6 +563,15 @@ ipv6rs_handledata(_unused void *arg)
ntohl(pi->nd_opt_pi_valid_time);
ap->prefix_pltime =
ntohl(pi->nd_opt_pi_preferred_time);
if (opt) {
l = strlen(opt);
opt = xrealloc(opt,
l + strlen(ap->saddr) + 2);
opt[l] = ' ';
strcpy(opt + l + 1, ap->saddr);
} else
opt = xstrdup(ap->saddr);
lifetime = ap->prefix_vltime;
break;
case ND_OPT_MTU:
@ -653,7 +672,7 @@ ipv6rs_handledata(_unused void *arg)
if (new_rap)
add_router(rap);
if (options & DHCPCD_IPV6RA_OWN) {
if (options & DHCPCD_IPV6RA_OWN && !(options & DHCPCD_TEST)) {
TAILQ_FOREACH(ap, &rap->addrs, next) {
syslog(ap->new ? LOG_INFO : LOG_DEBUG,
"%s: adding address %s",
@ -669,7 +688,8 @@ ipv6rs_handledata(_unused void *arg)
ap->prefix_pltime);
}
}
ipv6_build_routes();
if (!(options & DHCPCD_TEST))
ipv6_build_routes();
run_script_reason(ifp, options & DHCPCD_TEST ? "TEST" : "ROUTERADVERT");
if (options & DHCPCD_TEST)
exit(EXIT_SUCCESS);
@ -696,8 +716,7 @@ ipv6rs_handledata(_unused void *arg)
options & DHCPCD_IPV6RA_OWN_DEFAULT)
{
rap->nsprobes = 0;
add_timeout_sec(REACHABLE_TIME, ipv6ns_unreachable, rap);
add_timeout_sec(DELAY_FIRST_PROBE_TIME, ipv6ns_sendprobe, rap);
ipv6ns_sendprobe(rap);
}
}
@ -723,7 +742,7 @@ ipv6rs_env(char **env, const char *prefix, const struct interface *ifp)
char buffer[32];
const char *optn;
i = 1;
i = 0;
l = 0;
get_monotonic(&now);
TAILQ_FOREACH(rap, &ipv6_routers, next) {
@ -740,16 +759,9 @@ ipv6rs_env(char **env, const char *prefix, const struct interface *ifp)
TAILQ_FOREACH(rao, &rap->options, next) {
if (rao->option == NULL)
continue;
if (env == NULL) {
switch (rao->type) {
case ND_OPT_PREFIX_INFORMATION:
l += 4;
break;
default:
l++;
}
l++;
if (env == NULL)
continue;
}
switch (rao->type) {
case ND_OPT_PREFIX_INFORMATION:
optn = "prefix";
@ -768,36 +780,11 @@ ipv6rs_env(char **env, const char *prefix, const struct interface *ifp)
}
snprintf(buffer, sizeof(buffer), "ra%d_%s", i, optn);
setvar(&env, prefix, buffer, rao->option);
l++;
#if 0
switch (rao->type) {
case ND_OPT_PREFIX_INFORMATION:
snprintf(buffer, sizeof(buffer),
"ra%d_prefix_len", i);
snprintf(buffer2, sizeof(buffer2),
"%d", rap->prefix_len);
setvar(&env, prefix, buffer, buffer2);
snprintf(buffer, sizeof(buffer),
"ra%d_prefix_vltime", i);
snprintf(buffer2, sizeof(buffer2),
"%d", rap->prefix_vltime);
setvar(&env, prefix, buffer, buffer2);
snprintf(buffer, sizeof(buffer),
"ra%d_prefix_pltime", i);
snprintf(buffer2, sizeof(buffer2),
"%d", rap->prefix_pltime);
setvar(&env, prefix, buffer, buffer2);
l += 3;
break;
}
#endif
}
}
if (env)
setvard(&env, prefix, "ra_count", i - 1);
setvard(&env, prefix, "ra_count", i);
l++;
return l;
}

View File

@ -52,6 +52,8 @@ struct ra {
struct timeval received;
unsigned char flags;
uint32_t lifetime;
uint32_t reachable;
uint32_t retrans;
uint32_t mtu;
TAILQ_HEAD(, ipv6_addr) addrs;
TAILQ_HEAD(, ra_opt) options;