Sync
This commit is contained in:
parent
167f6f25d6
commit
083b63d1f4
|
@ -1,5 +1,5 @@
|
|||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: dhcp.c,v 1.11 2014/03/01 11:04:21 roy Exp $");
|
||||
__RCSID("$NetBSD: dhcp.c,v 1.12 2014/03/14 11:31:11 roy Exp $");
|
||||
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
|
@ -1064,8 +1064,12 @@ read_lease(struct interface *ifp)
|
|||
free(dhcp);
|
||||
return NULL;
|
||||
}
|
||||
syslog(LOG_DEBUG, "%s: validated using 0x%08" PRIu32,
|
||||
ifp->name, state->auth.token->secretid);
|
||||
if (state->auth.token)
|
||||
syslog(LOG_DEBUG, "%s: validated using 0x%08" PRIu32,
|
||||
ifp->name, state->auth.token->secretid);
|
||||
else
|
||||
syslog(LOG_DEBUG, "%s: accepted reconfigure key",
|
||||
ifp->name);
|
||||
}
|
||||
|
||||
return dhcp;
|
||||
|
@ -1347,7 +1351,7 @@ dhcp_close(struct interface *ifp)
|
|||
state->raw_fd = -1;
|
||||
}
|
||||
if (state->udp_fd != -1) {
|
||||
/* we don't listen to events on the udp */
|
||||
eloop_event_delete(ifp->ctx->eloop, state->udp_fd);
|
||||
close(state->udp_fd);
|
||||
state->udp_fd = -1;
|
||||
}
|
||||
|
@ -2200,8 +2204,12 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp,
|
|||
iface, dhcp, from, 0);
|
||||
return;
|
||||
}
|
||||
syslog(LOG_DEBUG, "%s: validated using 0x%08" PRIu32,
|
||||
iface->name, state->auth.token->secretid);
|
||||
if (state->auth.token)
|
||||
syslog(LOG_DEBUG, "%s: validated using 0x%08" PRIu32,
|
||||
iface->name, state->auth.token->secretid);
|
||||
else
|
||||
syslog(LOG_DEBUG, "%s: accepted reconfigure key",
|
||||
iface->name);
|
||||
} else if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) {
|
||||
log_dhcp1(LOG_ERR, "no authentication", iface, dhcp, from, 0);
|
||||
return;
|
||||
|
@ -2614,7 +2622,7 @@ dhcp_handleudp(void *arg)
|
|||
|
||||
/* Just read what's in the UDP fd and discard it as we always read
|
||||
* from the raw fd */
|
||||
read(ctx->udp_fd, buffer, sizeof(buffer));
|
||||
(void)read(ctx->udp_fd, buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2629,7 +2637,7 @@ dhcp_handleifudp(void *arg)
|
|||
|
||||
/* Just read what's in the UDP fd and discard it as we always read
|
||||
* from the raw fd */
|
||||
read(state->udp_fd, buffer, sizeof(buffer));
|
||||
(void)read(state->udp_fd, buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -2673,25 +2681,23 @@ dhcp_open(struct interface *ifp)
|
|||
}
|
||||
|
||||
int
|
||||
dhcp_dump(const char *ifname)
|
||||
dhcp_dump(struct dhcpcd_ctx *ctx, const char *ifname)
|
||||
{
|
||||
struct dhcpcd_ctx ctx;
|
||||
struct interface *ifp;
|
||||
struct dhcp_state *state;
|
||||
int r;
|
||||
|
||||
ifp = NULL;
|
||||
if (ctx->ifaces == NULL) {
|
||||
ctx->ifaces = malloc(sizeof(*ctx->ifaces));
|
||||
if (ctx->ifaces == NULL)
|
||||
return -1;
|
||||
TAILQ_INIT(ctx->ifaces);
|
||||
}
|
||||
state = NULL;
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.ifaces = malloc(sizeof(*ctx.ifaces));
|
||||
if (ctx.ifaces == NULL)
|
||||
goto eexit;
|
||||
TAILQ_INIT(ctx.ifaces);
|
||||
ifp = calloc(1, sizeof(*ifp));
|
||||
if (ifp == NULL)
|
||||
goto eexit;
|
||||
ifp->ctx = &ctx;
|
||||
TAILQ_INSERT_HEAD(ctx.ifaces, ifp, next);
|
||||
ifp->ctx = ctx;
|
||||
TAILQ_INSERT_HEAD(ctx->ifaces, ifp, next);
|
||||
ifp->if_data[IF_DATA_DHCP] = state = calloc(1, sizeof(*state));
|
||||
if (state == NULL)
|
||||
goto eexit;
|
||||
|
@ -2701,7 +2707,6 @@ dhcp_dump(const char *ifname)
|
|||
strlcpy(ifp->name, ifname, sizeof(ifp->name));
|
||||
snprintf(state->leasefile, sizeof(state->leasefile),
|
||||
LEASEFILE, ifp->name);
|
||||
strlcpy(ifp->options->script, SCRIPT, sizeof(ifp->options->script));
|
||||
state->new = read_lease(ifp);
|
||||
if (state->new == NULL && errno == ENOENT) {
|
||||
strlcpy(state->leasefile, ifname, sizeof(state->leasefile));
|
||||
|
@ -2710,28 +2715,14 @@ dhcp_dump(const char *ifname)
|
|||
if (state->new == NULL) {
|
||||
if (errno == ENOENT)
|
||||
syslog(LOG_ERR, "%s: no lease to dump", ifname);
|
||||
r = -1;
|
||||
goto cexit;
|
||||
return -1;
|
||||
}
|
||||
state->reason = "DUMP";
|
||||
r = script_runreason(ifp, state->reason);
|
||||
goto cexit;
|
||||
return script_runreason(ifp, state->reason);
|
||||
|
||||
eexit:
|
||||
syslog(LOG_ERR, "%s: %m", __func__);
|
||||
r = -1;
|
||||
|
||||
cexit:
|
||||
if (state) {
|
||||
free(state->new);
|
||||
free(state);
|
||||
}
|
||||
if (ifp) {
|
||||
free(ifp->options);
|
||||
free(ifp);
|
||||
}
|
||||
free(ctx.ifaces);
|
||||
return r;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: dhcpcd.8.in,v 1.26 2014/02/25 13:20:23 roy Exp $
|
||||
.\" $NetBSD: dhcpcd.8.in,v 1.27 2014/03/14 11:31:11 roy Exp $
|
||||
.\" Copyright (c) 2006-2014 Roy Marples
|
||||
.\" All rights reserved
|
||||
.\"
|
||||
|
@ -23,7 +23,7 @@
|
|||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd February 25, 2014
|
||||
.Dd March 7, 2014
|
||||
.Dt DHCPCD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -31,7 +31,7 @@
|
|||
.Nd a DHCP client
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl 46ABbDdEGgHJKLpqTV
|
||||
.Op Fl 46ABbDdEGgHJKLMpqTV
|
||||
.Op Fl C , Fl Fl nohook Ar hook
|
||||
.Op Fl c , Fl Fl script Ar script
|
||||
.Op Fl e , Fl Fl env Ar value
|
||||
|
@ -327,6 +327,10 @@ By default
|
|||
.Nm
|
||||
does not request any lease time and leaves it in the hands of the
|
||||
DHCP server.
|
||||
.It Fl M , Fl Fl master
|
||||
Start
|
||||
.Nm
|
||||
in master mode even if only one interface specified on the command line.
|
||||
.It Fl m , Fl Fl metric Ar metric
|
||||
Metrics are used to prefer an interface over another one, lowest wins.
|
||||
.Nm
|
||||
|
@ -639,11 +643,11 @@ lease and use the files mtime as when it was issued.
|
|||
Stores the monotonic counter used in the
|
||||
.Ar replay
|
||||
field in Authentication Options.
|
||||
.It Pa @RUNDIR@dhcpcd.pid
|
||||
.It Pa @RUNDIR@/dhcpcd.pid
|
||||
Stores the PID of
|
||||
.Nm
|
||||
running on all interfaces.
|
||||
.It Pa @RUNDIR@dhcpcd\- Ns Ar interface Ns .pid
|
||||
.It Pa @RUNDIR@/dhcpcd\- Ns Ar interface Ns .pid
|
||||
Stores the PID of
|
||||
.Nm
|
||||
running on the
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: dhcpcd.c,v 1.3 2014/03/01 11:04:21 roy Exp $");
|
||||
__RCSID("$NetBSD: dhcpcd.c,v 1.4 2014/03/14 11:31:11 roy Exp $");
|
||||
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
|
@ -300,9 +300,11 @@ find_interface(struct dhcpcd_ctx *ctx, const char *ifname)
|
|||
{
|
||||
struct interface *ifp;
|
||||
|
||||
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
|
||||
if (strcmp(ifp->name, ifname) == 0)
|
||||
return ifp;
|
||||
if (ctx != NULL && ctx->ifaces != NULL) {
|
||||
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
|
||||
if (strcmp(ifp->name, ifname) == 0)
|
||||
return ifp;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -522,7 +524,8 @@ handle_carrier(struct dhcpcd_ctx *ctx, int carrier, int flags,
|
|||
* them as some OS's will remove, mark tentative or
|
||||
* do nothing. */
|
||||
ipv6_free_ll_callbacks(ifp);
|
||||
dhcp_drop(ifp, "NOCARRIER");
|
||||
dhcp_drop(ifp, "EXPIRE");
|
||||
script_runreason(ifp, "NOCARRIER");
|
||||
}
|
||||
} else if (carrier == LINK_UP && ifp->flags & IFF_UP) {
|
||||
if (ifp->carrier != LINK_UP) {
|
||||
|
@ -578,7 +581,8 @@ start_interface(void *arg)
|
|||
size_t i;
|
||||
char buf[DUID_LEN * 3];
|
||||
|
||||
handle_carrier(ifp->ctx, LINK_UNKNOWN, 0, ifp->name);
|
||||
if (ifp->carrier == LINK_UNKNOWN)
|
||||
handle_carrier(ifp->ctx, LINK_UNKNOWN, 0, ifp->name);
|
||||
if (ifp->carrier == LINK_DOWN) {
|
||||
syslog(LOG_INFO, "%s: waiting for carrier", ifp->name);
|
||||
return;
|
||||
|
@ -852,6 +856,7 @@ struct dhcpcd_siginfo {
|
|||
pid_t pid;
|
||||
} dhcpcd_siginfo;
|
||||
|
||||
#define sigmsg "received signal %s from PID %d, %s"
|
||||
static void
|
||||
handle_signal1(void *arg)
|
||||
{
|
||||
|
@ -866,17 +871,17 @@ handle_signal1(void *arg)
|
|||
do_release = 0;
|
||||
switch (si->signo) {
|
||||
case SIGINT:
|
||||
syslog(LOG_INFO, "received SIGINT from PID %d, stopping",
|
||||
(int)si->pid);
|
||||
syslog(LOG_INFO, sigmsg, "INT", (int)si->pid, "stopping");
|
||||
break;
|
||||
case SIGTERM:
|
||||
syslog(LOG_INFO, "received SIGTERM from PID %d, stopping",
|
||||
(int)si->pid);
|
||||
syslog(LOG_INFO, sigmsg, "TERM", (int)si->pid, "stopping");
|
||||
break;
|
||||
case SIGALRM:
|
||||
syslog(LOG_INFO, "received SIGALRM from PID %d, rebinding",
|
||||
(int)si->pid);
|
||||
|
||||
syslog(LOG_INFO, sigmsg, "ALRM", (int)si->pid, "releasing");
|
||||
do_release = 1;
|
||||
break;
|
||||
case SIGHUP:
|
||||
syslog(LOG_INFO, sigmsg, "HUP", (int)si->pid, "rebinding");
|
||||
free_globals(ctx);
|
||||
ifo = read_config(ctx, NULL, NULL, NULL);
|
||||
add_options(ctx, NULL, ifo, ctx->argc, ctx->argv);
|
||||
|
@ -892,20 +897,14 @@ handle_signal1(void *arg)
|
|||
reconf_reboot(ctx, 1, ctx->argc, ctx->argv,
|
||||
ctx->argc - ctx->ifc);
|
||||
return;
|
||||
case SIGHUP:
|
||||
syslog(LOG_INFO, "received SIGHUP from PID %d, releasing",
|
||||
(int)si->pid);
|
||||
do_release = 1;
|
||||
break;
|
||||
case SIGUSR1:
|
||||
syslog(LOG_INFO, "received SIGUSR from PID %d, reconfiguring",
|
||||
(int)si->pid);
|
||||
syslog(LOG_INFO, sigmsg, "USR1", (int)si->pid, "reconfiguring");
|
||||
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
|
||||
ipv4_applyaddr(ifp);
|
||||
}
|
||||
return;
|
||||
case SIGPIPE:
|
||||
syslog(LOG_WARNING, "received SIGPIPE");
|
||||
syslog(LOG_WARNING, "received signal PIPE");
|
||||
return;
|
||||
default:
|
||||
syslog(LOG_ERR,
|
||||
|
@ -921,14 +920,14 @@ handle_signal1(void *arg)
|
|||
}
|
||||
|
||||
static void
|
||||
handle_signal(__unused int sig, siginfo_t *siginfo, __unused void *context)
|
||||
handle_signal(int sig, siginfo_t *siginfo, __unused void *context)
|
||||
{
|
||||
|
||||
/* So that we can operate safely under a signal we instruct
|
||||
* eloop to pass a copy of the siginfo structure to handle_signal1
|
||||
* as the very first thing to do. */
|
||||
dhcpcd_siginfo.signo = siginfo->si_signo;
|
||||
dhcpcd_siginfo.pid = siginfo->si_pid;
|
||||
dhcpcd_siginfo.signo = sig;
|
||||
dhcpcd_siginfo.pid = siginfo ? siginfo->si_pid : 0;
|
||||
eloop_timeout_add_now(dhcpcd_ctx->eloop,
|
||||
handle_signal1, &dhcpcd_siginfo);
|
||||
}
|
||||
|
@ -1118,6 +1117,7 @@ main(int argc, char **argv)
|
|||
#endif
|
||||
#ifdef USE_SIGNALS
|
||||
int sig;
|
||||
const char *siga;
|
||||
#endif
|
||||
struct timespec ts;
|
||||
|
||||
|
@ -1125,6 +1125,7 @@ main(int argc, char **argv)
|
|||
#ifdef USE_SIGNALS
|
||||
dhcpcd_ctx = &ctx;
|
||||
sig = 0;
|
||||
siga = NULL;
|
||||
#endif
|
||||
closefrom(3);
|
||||
openlog(PACKAGE, LOG_PERROR | LOG_PID, LOG_DAEMON);
|
||||
|
@ -1166,15 +1167,19 @@ main(int argc, char **argv)
|
|||
#ifdef USE_SIGNALS
|
||||
case 'g':
|
||||
sig = SIGUSR1;
|
||||
siga = "USR1";
|
||||
break;
|
||||
case 'k':
|
||||
sig = SIGHUP;
|
||||
sig = SIGALRM;
|
||||
siga = "ARLM";
|
||||
break;
|
||||
case 'n':
|
||||
sig = SIGALRM;
|
||||
sig = SIGHUP;
|
||||
siga = "HUP";
|
||||
break;
|
||||
case 'x':
|
||||
sig = SIGTERM;
|
||||
siga = "TERM";;
|
||||
break;
|
||||
#endif
|
||||
case 'T':
|
||||
|
@ -1194,6 +1199,9 @@ main(int argc, char **argv)
|
|||
|
||||
ctx.argv = argv;
|
||||
ctx.argc = argc;
|
||||
ctx.ifc = argc - optind;
|
||||
ctx.ifv = argv + optind;
|
||||
|
||||
ifo = read_config(&ctx, NULL, NULL, NULL);
|
||||
opt = add_options(&ctx, NULL, ifo, argc, argv);
|
||||
if (opt != 1) {
|
||||
|
@ -1247,7 +1255,7 @@ main(int argc, char **argv)
|
|||
if (!(ctx.options & (DHCPCD_TEST | DHCPCD_DUMPLEASE))) {
|
||||
/* If we have any other args, we should run as a single dhcpcd
|
||||
* instance for that interface. */
|
||||
if (optind == argc - 1) {
|
||||
if (optind == argc - 1 && !(ctx.options & DHCPCD_MASTER)) {
|
||||
if (strlen(argv[optind]) > IF_NAMESIZE) {
|
||||
syslog(LOG_ERR, "%s: interface name too long",
|
||||
argv[optind]);
|
||||
|
@ -1270,13 +1278,15 @@ main(int argc, char **argv)
|
|||
syslog(LOG_ERR, "dumplease requires an interface");
|
||||
goto exit_failure;
|
||||
}
|
||||
if (dhcp_dump(argv[optind]) == -1)
|
||||
if (dhcp_dump(&ctx, argv[optind]) == -1)
|
||||
goto exit_failure;
|
||||
goto exit_success;
|
||||
}
|
||||
|
||||
#ifdef USE_SIGNALS
|
||||
if (!(ctx.options & (DHCPCD_MASTER | DHCPCD_TEST))) {
|
||||
if (!(ctx.options & DHCPCD_TEST) &&
|
||||
(sig == 0 || ctx.ifc != 0))
|
||||
{
|
||||
#endif
|
||||
if (ctx.options & DHCPCD_MASTER)
|
||||
i = -1;
|
||||
|
@ -1318,20 +1328,20 @@ main(int argc, char **argv)
|
|||
if (sig != 0) {
|
||||
pid = read_pid(pidfile);
|
||||
if (pid != 0)
|
||||
syslog(LOG_INFO, "sending signal %d to pid %d",
|
||||
sig, pid);
|
||||
syslog(LOG_INFO, "sending signal %s to pid %d",
|
||||
siga, pid);
|
||||
if (pid == 0 || kill(pid, sig) != 0) {
|
||||
if (sig != SIGALRM && errno != EPERM)
|
||||
if (sig != SIGHUP && errno != EPERM)
|
||||
syslog(LOG_ERR, ""PACKAGE" not running");
|
||||
if (pid != 0 && errno != ESRCH) {
|
||||
syslog(LOG_ERR, "kill: %m");
|
||||
goto exit_failure;
|
||||
}
|
||||
unlink(pidfile);
|
||||
if (sig != SIGALRM)
|
||||
if (sig != SIGHUP)
|
||||
goto exit_failure;
|
||||
} else {
|
||||
if (sig == SIGALRM || sig == SIGUSR1)
|
||||
if (sig == SIGHUP || sig == SIGUSR1)
|
||||
goto exit_success;
|
||||
/* Spin until it exits */
|
||||
syslog(LOG_INFO, "waiting for pid %d to exit", pid);
|
||||
|
@ -1405,8 +1415,10 @@ main(int argc, char **argv)
|
|||
}
|
||||
#endif
|
||||
|
||||
ctx.ifc = argc - optind;
|
||||
ctx.ifv = argv + optind;
|
||||
#ifdef __FreeBSD__
|
||||
syslog(LOG_WARNING, "FreeBSD errors that are worked around:");
|
||||
syslog(LOG_WARNING, "IPv4 subnet routes cannot be deleted");
|
||||
#endif
|
||||
|
||||
/* When running dhcpcd against a single interface, we need to retain
|
||||
* the old behaviour of waiting for an IP address */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: if-bsd.c,v 1.4 2014/02/25 13:20:23 roy Exp $");
|
||||
__RCSID("$NetBSD: if-bsd.c,v 1.5 2014/03/14 11:31:11 roy Exp $");
|
||||
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
|
@ -50,6 +50,7 @@
|
|||
#elif __APPLE__
|
||||
/* FIXME: Add apple includes so we can work out SSID */
|
||||
#else
|
||||
# include <net80211/ieee80211.h>
|
||||
# include <net80211/ieee80211_ioctl.h>
|
||||
#endif
|
||||
|
||||
|
@ -285,19 +286,24 @@ if_route(const struct rt *rt, int action)
|
|||
memset(&rtm, 0, sizeof(rtm));
|
||||
rtm.hdr.rtm_version = RTM_VERSION;
|
||||
rtm.hdr.rtm_seq = 1;
|
||||
rtm.hdr.rtm_addrs = RTA_DST;
|
||||
if (action == 0)
|
||||
rtm.hdr.rtm_type = RTM_CHANGE;
|
||||
else if (action > 0)
|
||||
else if (action > 0) {
|
||||
rtm.hdr.rtm_type = RTM_ADD;
|
||||
else
|
||||
rtm.hdr.rtm_addrs |= RTA_GATEWAY;
|
||||
} else
|
||||
rtm.hdr.rtm_type = RTM_DELETE;
|
||||
rtm.hdr.rtm_flags = RTF_UP;
|
||||
#ifdef SIOCGIFPRIORITY
|
||||
rtm.hdr.rtm_priority = rt->metric;
|
||||
#endif
|
||||
|
||||
/* None interface subnet routes are static. */
|
||||
if (rt->gate.s_addr != INADDR_ANY ||
|
||||
rt->net.s_addr != state->net.s_addr ||
|
||||
rt->dest.s_addr != (state->addr.s_addr & state->net.s_addr))
|
||||
rtm.hdr.rtm_flags |= RTF_STATIC;
|
||||
rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
|
||||
if (rt->dest.s_addr == rt->gate.s_addr &&
|
||||
rt->net.s_addr == INADDR_BROADCAST)
|
||||
rtm.hdr.rtm_flags |= RTF_HOST;
|
||||
|
@ -313,17 +319,19 @@ if_route(const struct rt *rt, int action)
|
|||
}
|
||||
|
||||
ADDADDR(&rt->dest);
|
||||
if ((rtm.hdr.rtm_flags & RTF_HOST &&
|
||||
rt->gate.s_addr != htonl(INADDR_LOOPBACK)) ||
|
||||
!(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(rt->iface->name, &su.sdl);
|
||||
ADDSU;
|
||||
} else
|
||||
ADDADDR(&rt->gate);
|
||||
if (rtm.hdr.rtm_addrs & RTA_GATEWAY) {
|
||||
if ((rtm.hdr.rtm_flags & RTF_HOST &&
|
||||
rt->gate.s_addr != htonl(INADDR_LOOPBACK)) ||
|
||||
!(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(rt->iface->name, &su.sdl);
|
||||
ADDSU;
|
||||
} else
|
||||
ADDADDR(&rt->gate);
|
||||
}
|
||||
|
||||
if (rtm.hdr.rtm_addrs & RTA_NETMASK)
|
||||
ADDADDR(&rt->net);
|
||||
|
@ -411,7 +419,7 @@ if_route6(const struct rt6 *rt, int action)
|
|||
char *bp = rtm.buffer;
|
||||
size_t l;
|
||||
int s, retval;
|
||||
const struct ipv6_addr_l *lla;
|
||||
const struct ipv6_addr *lla;
|
||||
|
||||
if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
|
||||
return -1;
|
||||
|
@ -456,8 +464,11 @@ if_route6(const struct rt6 *rt, int action)
|
|||
rtm.hdr.rtm_type = RTM_ADD;
|
||||
else
|
||||
rtm.hdr.rtm_type = RTM_DELETE;
|
||||
|
||||
rtm.hdr.rtm_flags = RTF_UP;
|
||||
rtm.hdr.rtm_addrs = RTA_DST | RTA_NETMASK;
|
||||
#ifdef SIOCGIFPRIORITY
|
||||
rtm.hdr.rtm_priority = rt->metric;
|
||||
#endif
|
||||
/* None interface subnet routes are static. */
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&rt->dest) &&
|
||||
IN6_IS_ADDR_UNSPECIFIED(&rt->net))
|
||||
|
@ -467,19 +478,21 @@ if_route6(const struct rt6 *rt, int action)
|
|||
rtm.hdr.rtm_flags |= RTF_CLONING;
|
||||
#endif
|
||||
|
||||
rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
|
||||
if (action >= 0)
|
||||
rtm.hdr.rtm_addrs |= RTA_IFP | RTA_IFA;
|
||||
rtm.hdr.rtm_addrs |= RTA_GATEWAY | RTA_IFP | RTA_IFA;
|
||||
|
||||
ADDADDR(&rt->dest);
|
||||
if (!(rtm.hdr.rtm_flags & RTF_GATEWAY)) {
|
||||
lla = ipv6_linklocal(rt->iface);
|
||||
if (lla == NULL) /* unlikely as we need a LL to get here */
|
||||
return -1;
|
||||
ADDADDRS(&lla->addr, rt->iface->index);
|
||||
} else {
|
||||
lla = NULL;
|
||||
ADDADDRS(&rt->gate, rt->iface->index);
|
||||
lla = NULL;
|
||||
if (rtm.hdr.rtm_addrs & RTA_GATEWAY) {
|
||||
if (!(rtm.hdr.rtm_flags & RTF_GATEWAY)) {
|
||||
lla = ipv6_linklocal(rt->iface);
|
||||
if (lla == NULL) /* unlikely */
|
||||
return -1;
|
||||
ADDADDRS(&lla->addr, rt->iface->index);
|
||||
} else {
|
||||
lla = NULL;
|
||||
ADDADDRS(&rt->gate, rt->iface->index);
|
||||
}
|
||||
}
|
||||
|
||||
if (rtm.hdr.rtm_addrs & RTA_NETMASK) {
|
||||
|
@ -582,7 +595,7 @@ manage_link(struct dhcpcd_ctx *ctx)
|
|||
#ifdef INET
|
||||
struct rt rt;
|
||||
#endif
|
||||
#if defined(INET6) && !defined(LISTEN_DAD)
|
||||
#ifdef INET6
|
||||
struct in6_addr ia6;
|
||||
struct sockaddr_in6 *sin6;
|
||||
int ifa_flags;
|
||||
|
@ -701,7 +714,7 @@ manage_link(struct dhcpcd_ctx *ctx)
|
|||
&rt.dest, &rt.net, &rt.gate);
|
||||
break;
|
||||
#endif
|
||||
#if defined(INET6) && !defined(LISTEN_DAD)
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
sin6 = (struct sockaddr_in6*)(void *)
|
||||
rti_info[RTAX_IFA];
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: if-options.c,v 1.7 2014/03/01 11:04:21 roy Exp $");
|
||||
__RCSID("$NetBSD: if-options.c,v 1.8 2014/03/14 11:31:11 roy Exp $");
|
||||
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
|
@ -127,6 +127,7 @@ const struct option cf_options[] = {
|
|||
{"broadcast", no_argument, NULL, 'J'},
|
||||
{"nolink", no_argument, NULL, 'K'},
|
||||
{"noipv4ll", no_argument, NULL, 'L'},
|
||||
{"master", no_argument, NULL, 'M'},
|
||||
{"nooption", optional_argument, NULL, 'O'},
|
||||
{"require", required_argument, NULL, 'Q'},
|
||||
{"static", required_argument, NULL, 'S'},
|
||||
|
@ -929,6 +930,9 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
|
|||
case 'L':
|
||||
ifo->options &= ~DHCPCD_IPV4LL;
|
||||
break;
|
||||
case 'M':
|
||||
ifo->options |= DHCPCD_MASTER;
|
||||
break;
|
||||
case 'O':
|
||||
arg = set_option_space(ctx, arg, &d, &dl, ifo,
|
||||
&request, &require, &no);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: ipv6nd.c,v 1.6 2014/03/01 11:04:21 roy Exp $");
|
||||
__RCSID("$NetBSD: ipv6nd.c,v 1.7 2014/03/14 11:31:11 roy Exp $");
|
||||
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
|
@ -49,14 +49,6 @@
|
|||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Currently, no known kernel allows us to send from the unspecified address
|
||||
* which is required for DAD to work. This isn't that much of a problem as
|
||||
* the kernel will do DAD for us correctly, however we don't know the exact
|
||||
* randomness the kernel applies to the timeouts. So we just follow the same
|
||||
* logic and have a little faith.
|
||||
* This define is purely for completeness */
|
||||
// #define IPV6_SEND_DAD
|
||||
|
||||
#define ELOOP_QUEUE 2
|
||||
#include "common.h"
|
||||
#include "dhcpcd.h"
|
||||
|
@ -66,11 +58,6 @@
|
|||
#include "ipv6nd.h"
|
||||
#include "script.h"
|
||||
|
||||
#if defined(LISTEN_DAD) && defined(INET6)
|
||||
# warning kernel does not report DAD results to userland
|
||||
# warning listening to duplicated addresses on the wire
|
||||
#endif
|
||||
|
||||
/* Debugging Router Solicitations is a lot of spam, so disable it */
|
||||
//#define DEBUG_RS
|
||||
|
||||
|
@ -172,16 +159,10 @@ ipv6nd_open(struct dhcpcd_ctx *dctx)
|
|||
struct ipv6_ctx *ctx;
|
||||
int on;
|
||||
struct icmp6_filter filt;
|
||||
#ifdef IPV6_SEND_DAD
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in6 sin;
|
||||
} su;
|
||||
#endif
|
||||
|
||||
ctx = dctx->ipv6;
|
||||
if (ctx->nd_fd != -1)
|
||||
goto unspec;
|
||||
return ctx->nd_fd;
|
||||
#ifdef SOCK_CLOEXEC
|
||||
ctx->nd_fd = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
||||
IPPROTO_ICMPV6);
|
||||
|
@ -206,6 +187,12 @@ ipv6nd_open(struct dhcpcd_ctx *dctx)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* RFC4861 4.1 */
|
||||
on = 255;
|
||||
if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
|
||||
&on, sizeof(on)) == -1)
|
||||
goto eexit;
|
||||
|
||||
on = 1;
|
||||
if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
|
||||
&on, sizeof(on)) == -1)
|
||||
|
@ -224,62 +211,6 @@ ipv6nd_open(struct dhcpcd_ctx *dctx)
|
|||
goto eexit;
|
||||
|
||||
eloop_event_add(dctx->eloop, ctx->nd_fd, ipv6nd_handledata, dctx);
|
||||
|
||||
unspec:
|
||||
#ifdef IPV6_SEND_DAD
|
||||
if (ctx->unspec_fd != -1)
|
||||
return ctx->nd_fd;
|
||||
|
||||
ICMP6_FILTER_SETBLOCKALL(&filt);
|
||||
|
||||
/* We send DAD requests from the unspecified address. */
|
||||
#ifdef SOCK_CLOEXEC
|
||||
ctx->unspec_fd = socket(AF_INET6,
|
||||
SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
||||
IPPROTO_ICMPV6);
|
||||
if (ctx->unspec_fd == -1)
|
||||
return -1;
|
||||
#else
|
||||
if ((ctx->unspec_fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1)
|
||||
return -1;
|
||||
if ((on = fcntl(ctx->unspec_fd, F_GETFD, 0)) == -1 ||
|
||||
fcntl(ctx->unspec_fd, F_SETFD, on | FD_CLOEXEC) == -1)
|
||||
{
|
||||
close(ctx->unspec_fd);
|
||||
ctx->unspec_fd = -1;
|
||||
return -1;
|
||||
}
|
||||
if ((on = fcntl(ctx->unspec_fd, F_GETFL, 0)) == -1 ||
|
||||
fcntl(ctx->unspec_fd, F_SETFL, on | O_NONBLOCK) == -1)
|
||||
{
|
||||
close(ctx->unspec_fd);
|
||||
ctx->unspec_fd = -1;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (setsockopt(ctx->unspec_fd, IPPROTO_ICMPV6, ICMP6_FILTER,
|
||||
&filt, sizeof(filt)) == -1)
|
||||
goto eexit;
|
||||
memset(&su, 0, sizeof(su));
|
||||
su.sin.sin6_family = AF_INET6;
|
||||
#ifdef SIN6_LEN
|
||||
su.sin.sin6_len = sizeof(su.sin);
|
||||
#endif
|
||||
if (bind(ctx->unspec_fd, &su.sa, sizeof(su.sin)) == -1)
|
||||
goto eexit;
|
||||
#endif
|
||||
|
||||
#ifdef LISTEN_DAD
|
||||
if (!ctx->dad_warned) {
|
||||
syslog(LOG_WARNING,
|
||||
"kernel does not report DAD results to userland");
|
||||
syslog(LOG_WARNING,
|
||||
"warning listening to duplicated addresses on the wire");
|
||||
ctx->dad_warned = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ctx->nd_fd;
|
||||
|
||||
eexit:
|
||||
|
@ -288,12 +219,6 @@ eexit:
|
|||
close(ctx->nd_fd);
|
||||
ctx->nd_fd = -1;
|
||||
}
|
||||
#ifdef IPV6_SEND_DAD
|
||||
if (ctx->unpsec_fd != -1) {
|
||||
close(ctx->unspec_fd);
|
||||
ctx->unspec_fd = -1;
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -331,7 +256,6 @@ ipv6nd_sendrsprobe(void *arg)
|
|||
struct sockaddr_in6 dst;
|
||||
struct cmsghdr *cm;
|
||||
struct in6_pktinfo pi;
|
||||
int hoplimit = HOPLIMIT;
|
||||
|
||||
if (ipv6_linklocal(ifp) == NULL) {
|
||||
syslog(LOG_DEBUG,
|
||||
|
@ -369,15 +293,6 @@ ipv6nd_sendrsprobe(void *arg)
|
|||
pi.ipi6_ifindex = ifp->index;
|
||||
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
|
||||
|
||||
/* Hop limit */
|
||||
cm = CMSG_NXTHDR(&ctx->sndhdr, cm);
|
||||
if (cm == NULL) /* unlikely */
|
||||
return;
|
||||
cm->cmsg_level = IPPROTO_IPV6;
|
||||
cm->cmsg_type = IPV6_HOPLIMIT;
|
||||
cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
|
||||
memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
|
||||
|
||||
syslog(LOG_DEBUG, "%s: sending Router Solicitation", ifp->name);
|
||||
if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) {
|
||||
syslog(LOG_ERR, "%s: %s: sendmsg: %m", ifp->name, __func__);
|
||||
|
@ -581,16 +496,11 @@ ipv6nd_dadcallback(void *arg)
|
|||
int wascompleted, found;
|
||||
|
||||
wascompleted = (ap->flags & IPV6_AF_DADCOMPLETED);
|
||||
ipv6nd_cancelprobeaddr(ap);
|
||||
ap->flags |= IPV6_AF_DADCOMPLETED;
|
||||
if (ap->flags & IPV6_AF_DUPLICATED)
|
||||
/* No idea what how to try and make another address :( */
|
||||
syslog(LOG_WARNING, "%s: DAD detected %s",
|
||||
ap->iface->name, ap->saddr);
|
||||
#ifdef IPV6_SEND_DAD
|
||||
else
|
||||
ipv6_addaddr(ap);
|
||||
#endif
|
||||
|
||||
if (!wascompleted) {
|
||||
ifp = ap->iface;
|
||||
|
@ -611,7 +521,7 @@ ipv6nd_dadcallback(void *arg)
|
|||
found = 1;
|
||||
}
|
||||
|
||||
if (wascompleted && found && rap->lifetime) {
|
||||
if (wascompleted && found) {
|
||||
syslog(LOG_DEBUG,
|
||||
"%s: Router Advertisement DAD completed",
|
||||
rap->iface->name);
|
||||
|
@ -687,11 +597,6 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
|
|||
}
|
||||
|
||||
nd_ra = (struct nd_router_advert *)icp;
|
||||
/* Don't bother doing anything if we don't know about a router
|
||||
* expiring */
|
||||
if ((rap == NULL || rap->lifetime == 0)
|
||||
&& nd_ra->nd_ra_router_lifetime == 0)
|
||||
return;
|
||||
|
||||
/* We don't want to spam the log with the fact we got an RA every
|
||||
* 30 seconds or so, so only spam the log if it's different. */
|
||||
|
@ -860,13 +765,13 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
|
|||
ntohl(pi->nd_opt_pi_preferred_time);
|
||||
ap->nsprobes = 0;
|
||||
if (opt) {
|
||||
l = strlen(opt);
|
||||
tmp = realloc(opt,
|
||||
l + strlen(ap->saddr) + 2);
|
||||
l = strlen(opt) + 1;
|
||||
m = strlen(ap->saddr) + 1;
|
||||
tmp = realloc(opt, l + m);
|
||||
if (tmp) {
|
||||
opt = tmp;
|
||||
opt[l] = ' ';
|
||||
strcpy(opt + l + 1, ap->saddr);
|
||||
opt[l - 1] = ' ';
|
||||
strlcpy(opt + l, ap->saddr, m);
|
||||
}
|
||||
} else
|
||||
opt = strdup(ap->saddr);
|
||||
|
@ -1001,14 +906,10 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
|
|||
script_runreason(ifp, "TEST");
|
||||
goto handle_flag;
|
||||
}
|
||||
ipv6nd_probeaddrs(&rap->addrs);
|
||||
ipv6_addaddrs(&rap->addrs);
|
||||
ipv6_buildroutes(ifp->ctx);
|
||||
|
||||
/* We will get run by the expire function */
|
||||
if (rap->lifetime) {
|
||||
if (ipv6nd_scriptrun(rap))
|
||||
return;
|
||||
}
|
||||
if (ipv6nd_scriptrun(rap))
|
||||
return;
|
||||
|
||||
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
|
||||
eloop_timeout_delete(ifp->ctx->eloop, NULL, rap); /* reachable timer */
|
||||
|
@ -1025,15 +926,13 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
|
|||
|
||||
handle_flag:
|
||||
if (rap->flags & ND_RA_FLAG_MANAGED) {
|
||||
if (rap->lifetime && new_data &&
|
||||
dhcp6_start(ifp, DH6S_INIT) == -1)
|
||||
if (new_data && dhcp6_start(ifp, DH6S_INIT) == -1)
|
||||
syslog(LOG_ERR, "dhcp6_start: %s: %m", ifp->name);
|
||||
} else if (rap->flags & ND_RA_FLAG_OTHER) {
|
||||
if (rap->lifetime && new_data &&
|
||||
dhcp6_start(ifp, DH6S_INFORM) == -1)
|
||||
if (new_data && dhcp6_start(ifp, DH6S_INFORM) == -1)
|
||||
syslog(LOG_ERR, "dhcp6_start: %s: %m", ifp->name);
|
||||
} else {
|
||||
if (rap->lifetime && new_data)
|
||||
if (new_data)
|
||||
syslog(LOG_DEBUG, "%s: No DHCPv6 instruction in RA",
|
||||
ifp->name);
|
||||
if (ifp->ctx->options & DHCPCD_TEST) {
|
||||
|
@ -1132,24 +1031,25 @@ ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
|
|||
if (new) {
|
||||
**var = new;
|
||||
new = strchr(**var, '=');
|
||||
if (new)
|
||||
strcpy(new + 1,
|
||||
rao->option);
|
||||
else
|
||||
if (new) {
|
||||
len -= (new - **var);
|
||||
strlcpy(new + 1,
|
||||
rao->option,
|
||||
len - 1);
|
||||
} else
|
||||
syslog(LOG_ERR,
|
||||
"new is null");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
new = realloc(**var,
|
||||
strlen(**var) + 1 +
|
||||
strlen(rao->option) + 1);
|
||||
len = strlen(rao->option) + 1;
|
||||
new = realloc(**var, strlen(**var) + 1 + len);
|
||||
if (new == NULL)
|
||||
return -1;
|
||||
**var = new;
|
||||
new += strlen(new);
|
||||
*new++ = ' ';
|
||||
strcpy(new, rao->option);
|
||||
strlcpy(new, rao->option, len);
|
||||
continue;
|
||||
}
|
||||
if (env) {
|
||||
|
@ -1202,26 +1102,29 @@ ipv6nd_expirera(void *arg)
|
|||
TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) {
|
||||
if (rap->iface != ifp)
|
||||
continue;
|
||||
lt.tv_sec = rap->lifetime;
|
||||
lt.tv_usec = 0;
|
||||
timeradd(&rap->received, <, &expire);
|
||||
if (rap->lifetime == 0 || timercmp(&now, &expire, >)) {
|
||||
valid = 0;
|
||||
if (!rap->expired) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s: %s: router expired",
|
||||
ifp->name, rap->sfrom);
|
||||
rap->expired = expired = 1;
|
||||
ipv6nd_cancelproberouter(rap);
|
||||
valid = 0;
|
||||
if (rap->lifetime) {
|
||||
lt.tv_sec = rap->lifetime;
|
||||
lt.tv_usec = 0;
|
||||
timeradd(&rap->received, <, &expire);
|
||||
if (rap->lifetime == 0 || timercmp(&now, &expire, >)) {
|
||||
if (!rap->expired) {
|
||||
syslog(LOG_WARNING,
|
||||
"%s: %s: router expired",
|
||||
ifp->name, rap->sfrom);
|
||||
rap->expired = expired = 1;
|
||||
ipv6nd_cancelproberouter(rap);
|
||||
}
|
||||
} else {
|
||||
valid = 1;
|
||||
timersub(&expire, &now, <);
|
||||
if (!timerisset(&next) ||
|
||||
timercmp(&next, <, >))
|
||||
next = lt;
|
||||
}
|
||||
} else {
|
||||
valid = 1;
|
||||
timersub(&expire, &now, <);
|
||||
if (!timerisset(&next) || timercmp(&next, <, >))
|
||||
next = lt;
|
||||
}
|
||||
|
||||
/* Addresses are expired in ipv6ns_probeaddrs
|
||||
/* Addresses are expired in ipv6_addaddrs
|
||||
* so that DHCPv6 addresses can be removed also. */
|
||||
TAILQ_FOREACH_SAFE(rao, &rap->options, next, raon) {
|
||||
if (rap->expired) {
|
||||
|
@ -1332,201 +1235,6 @@ ipv6nd_unreachable(void *arg)
|
|||
&tv, ipv6nd_proberouter, rap);
|
||||
}
|
||||
|
||||
#ifdef LISTEN_DAD
|
||||
void
|
||||
ipv6nd_cancelprobeaddr(struct ipv6_addr *ap)
|
||||
{
|
||||
|
||||
eloop_timeout_delete(ap->iface->ctx->eloop, ipv6nd_probeaddr, ap);
|
||||
if (ap->dadcallback)
|
||||
eloop_timeout_delete(ap->iface->ctx->eloop, ap->dadcallback,ap);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
ipv6nd_probeaddr(void *arg)
|
||||
{
|
||||
struct ipv6_addr *ap = arg;
|
||||
#ifdef IPV6_SEND_DAD
|
||||
struct nd_neighbor_solicit *ns;
|
||||
struct nd_opt_hdr *nd;
|
||||
struct sockaddr_in6 dst;
|
||||
struct cmsghdr *cm;
|
||||
struct in6_pktinfo pi;
|
||||
int hoplimit = HOPLIMIT;
|
||||
#else
|
||||
#ifdef LISTEN_DAD
|
||||
struct timeval tv, rtv;
|
||||
struct timeval mtv;
|
||||
int i;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (ap->dadcallback &&
|
||||
((ap->flags & IPV6_AF_NEW) == 0 ||
|
||||
ap->nsprobes >= ap->iface->options->dadtransmits))
|
||||
{
|
||||
#ifdef IPV6_SEND_DAD
|
||||
ap->dadcallback(ap);
|
||||
#else
|
||||
if (!(ap->flags & IPV6_AF_AUTOCONF) ||
|
||||
ap->iface->options->options & DHCPCD_IPV6RA_OWN)
|
||||
ipv6_addaddr(ap);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (ipv6nd_open(ap->iface->ctx) == -1) {
|
||||
syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
ap->flags &= ~IPV6_AF_DADCOMPLETED;
|
||||
|
||||
#ifdef IPV6_SEND_DAD
|
||||
if (!ap->ns) {
|
||||
ap->nslen = sizeof(*ns) + ROUNDUP8(ap->iface->hwlen + 2);
|
||||
ap->ns = calloc(1, ap->nslen);
|
||||
if (ap->ns == NULL) {
|
||||
syslog(LOG_ERR, "%s: %m", __func__);
|
||||
return;
|
||||
}
|
||||
ns = (struct nd_neighbor_solicit *)(void *)ap->ns;
|
||||
ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
|
||||
//ns->nd_ns_cksum = 0;
|
||||
//ns->nd_ns_code = 0;
|
||||
//ns->nd_ns_reserved = 0;
|
||||
ns->nd_ns_target = ap->addr;
|
||||
nd = (struct nd_opt_hdr *)(ap->ns + sizeof(*ns));
|
||||
nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
|
||||
nd->nd_opt_len = (ROUNDUP8(ap->iface->hwlen + 2)) >> 3;
|
||||
memcpy(nd + 1, ap->iface->hwaddr, ap->iface->hwlen);
|
||||
}
|
||||
|
||||
memset(&dst, 0, sizeof(dst));
|
||||
dst.sin6_family = AF_INET6;
|
||||
#ifdef SIN6_LEN
|
||||
dst.sin6_len = sizeof(dst);
|
||||
#endif
|
||||
dst.sin6_addr.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
|
||||
dst.sin6_addr.s6_addr16[1] = 0;
|
||||
dst.sin6_addr.s6_addr32[1] = 0;
|
||||
dst.sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
|
||||
dst.sin6_addr.s6_addr32[3] = ap->addr.s6_addr32[3];
|
||||
dst.sin6_addr.s6_addr[12] = 0xff;
|
||||
|
||||
//memcpy(&dst.sin6_addr, &ap->addr, sizeof(dst.sin6_addr));
|
||||
dst.sin6_scope_id = ap->iface->index;
|
||||
|
||||
ctx = ap->iface->ctx->ipv6;
|
||||
ctx->sndhdr.msg_name = (caddr_t)&dst;
|
||||
ctx->sndhdr.msg_iov[0].iov_base = ap->ns;
|
||||
ctx->sndhdr.msg_iov[0].iov_len = ap->nslen;
|
||||
|
||||
/* Set the outbound interface */
|
||||
cm = CMSG_FIRSTHDR(&ctx->sndhdr);
|
||||
if (cm == NULL) /* unlikely */
|
||||
return;
|
||||
cm->cmsg_level = IPPROTO_IPV6;
|
||||
cm->cmsg_type = IPV6_PKTINFO;
|
||||
cm->cmsg_len = CMSG_LEN(sizeof(pi));
|
||||
memset(&pi, 0, sizeof(pi));
|
||||
pi.ipi6_ifindex = ap->iface->index;
|
||||
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
|
||||
|
||||
/* Hop limit */
|
||||
cm = CMSG_NXTHDR(&sndhdr, cm);
|
||||
if (cm == NULL) /* unlikely */
|
||||
return;
|
||||
cm->cmsg_level = IPPROTO_IPV6;
|
||||
cm->cmsg_type = IPV6_HOPLIMIT;
|
||||
cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
|
||||
memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
|
||||
|
||||
#ifdef DEBUG_NS
|
||||
syslog(LOG_INFO, "%s: sending IPv6 NS for %s",
|
||||
ap->iface->name, ap->saddr);
|
||||
if (ap->dadcallback == NULL)
|
||||
syslog(LOG_WARNING, "%s: no callback!", ap->iface->name);
|
||||
#endif
|
||||
if (sendmsg(unspec_sock, &sndhdr, 0) == -1) {
|
||||
syslog(LOG_ERR, "%s: %s: sendmsg: %m",
|
||||
ap->iface->name, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ap->dadcallback) {
|
||||
ms_to_tv(&tv, RETRANS_TIMER);
|
||||
ms_to_tv(&rtv, MIN_RANDOM_FACTOR);
|
||||
timeradd(&tv, &rtv, &tv);
|
||||
rtv.tv_sec = 0;
|
||||
rtv.tv_usec = arc4random() %
|
||||
(MAX_RANDOM_FACTOR_U - MIN_RANDOM_FACTOR_U);
|
||||
timeradd(&tv, &rtv, &tv);
|
||||
|
||||
eloop_timeout_add_tv(ap->iface->ctx->eloop, &tv,
|
||||
++(ap->nsprobes) < ap->iface->options->dadtransmits ?
|
||||
ipv6nd_probeaddr : ap->dadcallback,
|
||||
ap);
|
||||
}
|
||||
#else /* IPV6_SEND_DAD */
|
||||
|
||||
if (!(ap->flags & IPV6_AF_AUTOCONF) ||
|
||||
ap->iface->options->options & DHCPCD_IPV6RA_OWN)
|
||||
ipv6_addaddr(ap);
|
||||
|
||||
#ifdef LISTEN_DAD
|
||||
/* Let the kernel handle DAD.
|
||||
* We don't know the timings, so just wait for the max */
|
||||
if (ap->dadcallback) {
|
||||
mtv.tv_sec = 0;
|
||||
mtv.tv_usec = 0;
|
||||
for (i = 0; i < ap->iface->options->dadtransmits; i++) {
|
||||
ms_to_tv(&tv, RETRANS_TIMER);
|
||||
ms_to_tv(&rtv, MAX_RANDOM_FACTOR);
|
||||
timeradd(&tv, &rtv, &tv);
|
||||
timeradd(&mtv, &tv, &mtv);
|
||||
}
|
||||
eloop_timeout_add_tv(ap->iface->ctx->eloop,
|
||||
&mtv, ap->dadcallback, ap);
|
||||
}
|
||||
#endif
|
||||
#endif /* IPV6_SEND_DAD */
|
||||
}
|
||||
|
||||
ssize_t
|
||||
ipv6nd_probeaddrs(struct ipv6_addrhead *addrs)
|
||||
{
|
||||
struct ipv6_addr *ap, *apn;
|
||||
ssize_t i;
|
||||
|
||||
i = 0;
|
||||
TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
|
||||
if (ap->prefix_vltime == 0) {
|
||||
TAILQ_REMOVE(addrs, ap, next);
|
||||
if (ap->flags & IPV6_AF_ADDED) {
|
||||
syslog(LOG_INFO, "%s: deleting address %s",
|
||||
ap->iface->name, ap->saddr);
|
||||
i++;
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&ap->addr) &&
|
||||
del_address6(ap) == -1 &&
|
||||
errno != EADDRNOTAVAIL && errno != ENXIO)
|
||||
syslog(LOG_ERR, "del_address6 %m");
|
||||
}
|
||||
if (ap->dadcallback)
|
||||
eloop_q_timeout_delete(ap->iface->ctx->eloop,
|
||||
0, NULL, ap->dadcallback);
|
||||
free(ap);
|
||||
} else if (!IN6_IS_ADDR_UNSPECIFIED(&ap->addr)) {
|
||||
ipv6nd_probeaddr(ap);
|
||||
if (ap->flags & IPV6_AF_NEW)
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void
|
||||
ipv6nd_proberouter(void *arg)
|
||||
{
|
||||
|
@ -1536,7 +1244,6 @@ ipv6nd_proberouter(void *arg)
|
|||
struct sockaddr_in6 dst;
|
||||
struct cmsghdr *cm;
|
||||
struct in6_pktinfo pi;
|
||||
int hoplimit = HOPLIMIT;
|
||||
struct timeval tv, rtv;
|
||||
struct ipv6_ctx *ctx;
|
||||
|
||||
|
@ -1588,15 +1295,6 @@ ipv6nd_proberouter(void *arg)
|
|||
pi.ipi6_ifindex = rap->iface->index;
|
||||
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
|
||||
|
||||
/* Hop limit */
|
||||
cm = CMSG_NXTHDR(&ctx->sndhdr, cm);
|
||||
if (cm == NULL) /* unlikely */
|
||||
return;
|
||||
cm->cmsg_level = IPPROTO_IPV6;
|
||||
cm->cmsg_type = IPV6_HOPLIMIT;
|
||||
cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
|
||||
memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
|
||||
|
||||
#ifdef DEBUG_NS
|
||||
syslog(LOG_INFO, "%s: sending IPv6 NS for %s",
|
||||
rap->iface->name, rap->sfrom);
|
||||
|
@ -1636,16 +1334,8 @@ ipv6nd_handlena(struct ipv6_ctx *ctx, struct interface *ifp,
|
|||
struct nd_neighbor_advert *nd_na;
|
||||
struct ra *rap;
|
||||
int is_router, is_solicited;
|
||||
#ifdef DEBUG_NS
|
||||
int found;
|
||||
#endif
|
||||
struct timeval tv;
|
||||
|
||||
#ifdef LISTEN_DAD
|
||||
struct dhcp6_state *d6state;
|
||||
struct ipv6_addr *ap;
|
||||
#endif
|
||||
|
||||
if ((size_t)len < sizeof(struct nd_neighbor_advert)) {
|
||||
syslog(LOG_ERR, "IPv6 NA packet too short from %s", ctx->sfrom);
|
||||
return;
|
||||
|
@ -1669,55 +1359,16 @@ ipv6nd_handlena(struct ipv6_ctx *ctx, struct interface *ifp,
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_NS
|
||||
found = 0;
|
||||
#endif
|
||||
TAILQ_FOREACH(rap, ctx->ra_routers, next) {
|
||||
if (rap->iface != ifp)
|
||||
continue;
|
||||
if (memcmp(rap->from.s6_addr, nd_na->nd_na_target.s6_addr,
|
||||
if (rap->iface == ifp &&
|
||||
memcmp(rap->from.s6_addr, nd_na->nd_na_target.s6_addr,
|
||||
sizeof(rap->from.s6_addr)) == 0)
|
||||
break;
|
||||
#ifdef LISTEN_DAD
|
||||
TAILQ_FOREACH(ap, &rap->addrs, next) {
|
||||
if (memcmp(ap->addr.s6_addr,
|
||||
nd_na->nd_na_target.s6_addr,
|
||||
sizeof(ap->addr.s6_addr)) == 0)
|
||||
{
|
||||
ap->flags |= IPV6_AF_DUPLICATED;
|
||||
if (ap->dadcallback)
|
||||
ap->dadcallback(ap);
|
||||
#ifdef DEBUG_NS
|
||||
found++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (rap == NULL) {
|
||||
#ifdef LISTEN_DAD
|
||||
d6state = D6_STATE(ifp);
|
||||
if (d6state) {
|
||||
TAILQ_FOREACH(ap, &d6state->addrs, next) {
|
||||
if (memcmp(ap->addr.s6_addr,
|
||||
nd_na->nd_na_target.s6_addr,
|
||||
sizeof(ap->addr.s6_addr)) == 0)
|
||||
{
|
||||
ap->flags |= IPV6_AF_DUPLICATED;
|
||||
if (ap->dadcallback)
|
||||
ap->dadcallback(ap);
|
||||
#ifdef DEBUG_NS
|
||||
found++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_NS
|
||||
if (found == 0)
|
||||
syslog(LOG_DEBUG, "%s: unexpected NA from %s",
|
||||
ifp->name, ctx->sfrom);
|
||||
syslog(LOG_DEBUG, "%s: unexpected NA from s",
|
||||
ifp->name, ctx->sfrom);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
@ -1774,6 +1425,8 @@ ipv6nd_handledata(void *arg)
|
|||
|
||||
dhcpcd_ctx = arg;
|
||||
ctx = dhcpcd_ctx->ipv6;
|
||||
ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
|
||||
CMSG_SPACE(sizeof(int));
|
||||
len = recvmsg(ctx->nd_fd, &ctx->rcvhdr, 0);
|
||||
if (len == -1) {
|
||||
syslog(LOG_ERR, "recvmsg: %m");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: net.c,v 1.5 2014/02/25 13:20:23 roy Exp $");
|
||||
__RCSID("$NetBSD: net.c,v 1.6 2014/03/14 11:31:11 roy Exp $");
|
||||
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
|
@ -253,13 +253,26 @@ discover_interfaces(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
|
|||
#endif
|
||||
#ifdef AF_LINK
|
||||
const struct sockaddr_dl *sdl;
|
||||
#ifdef SIOCGIFPRIORITY
|
||||
struct ifreq ifr;
|
||||
int s_inet;
|
||||
#endif
|
||||
#ifdef IFLR_ACTIVE
|
||||
struct if_laddrreq iflr;
|
||||
int socket_aflink;
|
||||
int s_link;
|
||||
#endif
|
||||
|
||||
socket_aflink = socket(AF_LINK, SOCK_DGRAM, 0);
|
||||
if (socket_aflink == -1)
|
||||
#ifdef SIOCGIFPRIORITY
|
||||
if ((s_inet = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return NULL;
|
||||
#endif
|
||||
#ifdef IFLR_ACTIVE
|
||||
if ((s_link = socket(AF_LINK, SOCK_DGRAM, 0)) == -1) {
|
||||
#ifdef SIOCGIFPRIORITY
|
||||
close(s_inet);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
memset(&iflr, 0, sizeof(iflr));
|
||||
#endif
|
||||
#elif AF_PACKET
|
||||
|
@ -268,7 +281,6 @@ discover_interfaces(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
|
|||
|
||||
if (getifaddrs(&ifaddrs) == -1)
|
||||
return NULL;
|
||||
|
||||
ifs = malloc(sizeof(*ifs));
|
||||
if (ifs == NULL)
|
||||
return NULL;
|
||||
|
@ -342,8 +354,10 @@ discover_interfaces(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
|
|||
}
|
||||
|
||||
ifp = calloc(1, sizeof(*ifp));
|
||||
if (ifp == NULL)
|
||||
return NULL;
|
||||
if (ifp == NULL) {
|
||||
syslog(LOG_ERR, "%s: %m", __func__);
|
||||
break;
|
||||
}
|
||||
ifp->ctx = ctx;
|
||||
strlcpy(ifp->name, p, sizeof(ifp->name));
|
||||
ifp->flags = ifa->ifa_flags;
|
||||
|
@ -381,7 +395,7 @@ discover_interfaces(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
|
|||
MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr)));
|
||||
iflr.flags = IFLR_PREFIX;
|
||||
iflr.prefixlen = sdl->sdl_alen * NBBY;
|
||||
if (ioctl(socket_aflink, SIOCGLIFADDR, &iflr) == -1 ||
|
||||
if (ioctl(s_link, SIOCGLIFADDR, &iflr) == -1 ||
|
||||
!(iflr.flags & IFLR_ACTIVE))
|
||||
{
|
||||
free_interface(ifp);
|
||||
|
@ -466,6 +480,13 @@ discover_interfaces(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
|
|||
continue;
|
||||
}
|
||||
|
||||
#ifdef SIOCGIFPRIORITY
|
||||
/* Respect the interface priority */
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
|
||||
if (ioctl(s_inet, SIOCGIFPRIORITY, &ifr) == 0)
|
||||
ifp->metric = ifr.ifr_metric;
|
||||
#else
|
||||
/* We reserve the 100 range for virtual interfaces, if and when
|
||||
* we can work them out. */
|
||||
ifp->metric = 200 + ifp->index;
|
||||
|
@ -473,6 +494,7 @@ discover_interfaces(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
|
|||
ifp->wireless = 1;
|
||||
ifp->metric += 100;
|
||||
}
|
||||
#endif
|
||||
|
||||
TAILQ_INSERT_TAIL(ifs, ifp, next);
|
||||
}
|
||||
|
@ -515,8 +537,11 @@ discover_interfaces(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
|
|||
|
||||
freeifaddrs(ifaddrs);
|
||||
|
||||
#ifdef SIOCGIFPRIORITY
|
||||
close(s_inet);
|
||||
#endif
|
||||
#ifdef IFLR_ACTIVE
|
||||
close(socket_aflink);
|
||||
close(s_link);
|
||||
#endif
|
||||
|
||||
return ifs;
|
||||
|
|
Loading…
Reference in New Issue