Import dhcpcd-7.0.0-rc1 with the following changes:

*  Default to use VLANID>0 for IAID instead of MAC address
  *  Stop sharing the DHCPv6 port in master mode with other processes
  *  Fix some prefix delegation issues when the carrier drops or
     addresses become stale
  *  Fix a crash when starting dhcpcd with -n
  *  Fix test for preferring a fake lease over a real one
  *  Show to real address lifetimes being added when adding IPv6
     addresses
  *  Restore the -G, --nogateway option
This commit is contained in:
roy 2017-05-10 11:00:37 +00:00
parent a0f00732f7
commit d0f9585b51
15 changed files with 317 additions and 138 deletions

View File

@ -28,7 +28,7 @@
#define CONFIG_H
#define PACKAGE "dhcpcd"
#define VERSION "7.0.0-beta3"
#define VERSION "7.0.0-rc1"
#ifndef CONFIG
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"

View File

@ -1353,7 +1353,11 @@ dhcp6_dadcallback(void *arg)
{
struct ipv6_addr *ap2;
#ifdef SMALL
valid = true;
#else
valid = (ap->delegating_prefix == NULL);
#endif
TAILQ_FOREACH(ap2, &state->addrs, next) {
if (ap2->flags & IPV6_AF_ADDED &&
!(ap2->flags & IPV6_AF_DADCOMPLETED))
@ -1366,8 +1370,10 @@ dhcp6_dadcallback(void *arg)
logdebugx("%s: DHCPv6 DAD completed",
ifp->name);
script_runreason(ifp,
ap->delegating_prefix ?
"DELEGATED6" : state->reason);
#ifndef SMALL
ap->delegating_prefix ? "DELEGATED6" :
#endif
state->reason);
if (valid)
dhcpcd_daemonise(ifp->ctx);
}
@ -2039,7 +2045,7 @@ dhcp6_findia(struct interface *ifp, struct dhcp6_message *m, size_t l,
uint16_t nl;
uint8_t iaid[4];
char buf[sizeof(iaid) * 3];
struct ipv6_addr *ap, *nap;
struct ipv6_addr *ap;
if (l < sizeof(*m)) {
/* Should be impossible with guards at packet in
@ -2162,22 +2168,62 @@ dhcp6_findia(struct interface *ifp, struct dhcp6_message *m, size_t l,
i++;
}
TAILQ_FOREACH_SAFE(ap, &state->addrs, next, nap) {
if (ap->flags & IPV6_AF_STALE) {
eloop_q_timeout_delete(ifp->ctx->eloop, 0, NULL, ap);
if (ap->flags & IPV6_AF_REQUEST) {
ap->prefix_vltime = ap->prefix_pltime = 0;
} else {
TAILQ_REMOVE(&state->addrs, ap, next);
free(ap);
}
}
}
if (i == 0 && e)
return -1;
return i;
}
static void
dhcp6_deprecateaddrs(struct ipv6_addrhead *addrs)
{
struct ipv6_addr *ia, *ian;
TAILQ_FOREACH_SAFE(ia, addrs, next, ian) {
if (ia->flags & IPV6_AF_STALE) {
if (ia->prefix_vltime != 0)
logdebugx("%s: %s: became stale",
ia->iface->name, ia->saddr);
ia->prefix_pltime = 0;
} else if (ia->prefix_vltime == 0)
loginfox("%s: %s: no valid lifetime",
ia->iface->name, ia->saddr);
else
continue;
#ifndef SMALL
/* If we delegated from this prefix, deprecate or remove
* the delegations. */
if (ia->flags & IPV6_AF_DELEGATEDPFX) {
struct ipv6_addr *da;
bool touched = false;
TAILQ_FOREACH(da, &ia->pd_pfxs, pd_next) {
if (ia->prefix_vltime == 0) {
if (da->prefix_vltime != 0) {
da->prefix_vltime = 0;
touched = true;
}
} else if (da->prefix_pltime != 0) {
da->prefix_pltime = 0;
touched = true;
}
}
if (touched)
ipv6_addaddrs(&ia->pd_pfxs);
}
#endif
if (ia->flags & IPV6_AF_REQUEST) {
ia->prefix_vltime = ia->prefix_pltime = 0;
eloop_q_timeout_delete(ia->iface->ctx->eloop,
0, NULL, ia);
continue;
}
TAILQ_REMOVE(addrs, ia, next);
ipv6_freeaddr(ia);
}
}
static int
dhcp6_validatelease(struct interface *ifp,
struct dhcp6_message *m, size_t len,
@ -2416,7 +2462,7 @@ dhcp6_ifdelegateaddr(struct interface *ifp, struct ipv6_addr *prefix,
if (strcmp(ifp->name, prefix->iface->name) == 0) {
if (prefix->prefix_exclude_len == 0) {
/* Don't spam the log automatically */
if (sla)
if (sla != NULL)
logwarnx("%s: DHCPv6 server does not support "
"OPTION_PD_EXCLUDE",
ifp->name);
@ -2428,14 +2474,14 @@ dhcp6_ifdelegateaddr(struct interface *ifp, struct ipv6_addr *prefix,
sla, if_ia)) == -1)
return NULL;
if (fls64(sla->suffix) > 128 - pfxlen) {
if (sla != NULL && fls64(sla->suffix) > 128 - pfxlen) {
logerrx("%s: suffix %" PRIu64 " + prefix_len %d > 128",
ifp->name, sla->suffix, pfxlen);
return NULL;
}
/* Add our suffix */
if (sla->suffix) {
if (sla != NULL && sla->suffix != 0) {
daddr = addr;
vl = be64dec(addr.s6_addr + 8);
vl |= sla->suffix;
@ -2510,9 +2556,12 @@ dhcp6_script_try_run(struct interface *ifp, int delegated)
ipv6_iffindaddr(ap->iface, &ap->addr,
IN6_IFF_TENTATIVE))
ap->flags |= IPV6_AF_DADCOMPLETED;
if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0 &&
((delegated && ap->delegating_prefix) ||
(!delegated && !ap->delegating_prefix)))
if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0
#ifndef SMALL
&& ((delegated && ap->delegating_prefix) ||
(!delegated && !ap->delegating_prefix))
#endif
)
{
completed = 0;
break;
@ -3166,6 +3215,7 @@ dhcp6_handledata(void *arg)
eloop_timeout_add_sec(ifp->ctx->eloop,
(time_t)state->expire, dhcp6_startexpire, ifp);
dhcp6_deprecateaddrs(&state->addrs);
ipv6_addaddrs(&state->addrs);
if (state->state == DH6S_INFORMED)
@ -3213,11 +3263,6 @@ dhcp6_open(struct dhcpcd_ctx *ctx)
ctx->dhcp6_fd = xsocket(PF_INET6, SOCK_DGRAM | SOCK_FLAGS, IPPROTO_UDP);
#undef SOCK_FLAGS
if (ctx->dhcp6_fd == -1)
return -1;
n = 1;
if (setsockopt(ctx->dhcp6_fd, SOL_SOCKET, SO_REUSEADDR,
&n, sizeof(n)) == -1)
goto errexit;
n = 1;
@ -3225,13 +3270,6 @@ dhcp6_open(struct dhcpcd_ctx *ctx)
&n, sizeof(n)) == -1)
goto errexit;
#ifdef SO_REUSEPORT
n = 1;
if (setsockopt(ctx->dhcp6_fd, SOL_SOCKET, SO_REUSEPORT,
&n, sizeof(n)) == -1)
logerr("SO_REUSEPORT");
#endif
if (!(ctx->options & DHCPCD_MASTER)) {
/* Bind to the link-local address to allow more than one
* DHCPv6 client to work. */
@ -3260,8 +3298,11 @@ dhcp6_open(struct dhcpcd_ctx *ctx)
return 0;
errexit:
close(ctx->dhcp6_fd);
ctx->dhcp6_fd = -1;
logerr(__func__);
if (ctx->dhcp6_fd != -1) {
close(ctx->dhcp6_fd);
ctx->dhcp6_fd = -1;
}
return -1;
}
@ -3428,40 +3469,20 @@ dhcp6_freedrop(struct interface *ifp, int drop, const char *reason)
struct dhcp6_state *state;
struct dhcpcd_ctx *ctx;
unsigned long long options;
#ifndef SMALL
int dropdele;
#endif
/*
* As the interface is going away from dhcpcd we need to
* remove the delegated addresses, otherwise we lose track
* of which interface is delegating as we remeber it by pointer.
* So if we need to change this behaviour, we need to change
* how we remember which interface delegated.
*
* XXX The below is no longer true due to the change of the
* default IAID, but do PPP links have stable ethernet
* addresses?
*
* To make it more interesting, on some OS's with PPP links
* there is no guarantee the delegating interface will have
* the same name or index so think very hard before changing
* this.
*/
if (ifp->options)
options = ifp->options->options;
else
options = ifp->ctx->options;
#ifndef SMALL
dropdele = (options & (DHCPCD_STOPPING | DHCPCD_RELEASE) &&
(options & DHCPCD_NODROP) != DHCPCD_NODROP);
#endif
if (ifp->ctx->eloop)
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
#ifndef SMALL
if (dropdele)
/* If we're dropping the lease, drop delegated addresses.
* If, for whatever reason, we don't drop them in the future
* then they should at least be marked as deprecated (pltime 0). */
if (drop && (options & DHCPCD_NODROP) != DHCPCD_NODROP)
dhcp6_delete_delegates(ifp);
#endif
@ -3573,9 +3594,11 @@ dhcp6_env(char **env, const char *prefix, const struct interface *ifp,
char *pfx;
uint32_t en;
const struct dhcpcd_ctx *ctx;
#ifndef SMALL
const struct dhcp6_state *state;
const struct ipv6_addr *ap;
char *v, *val;
#endif
n = 0;
if (m == NULL)
@ -3676,6 +3699,7 @@ dhcp6_env(char **env, const char *prefix, const struct interface *ifp,
free(pfx);
delegated:
#ifndef SMALL
/* Needed for Delegated Prefixes */
state = D6_CSTATE(ifp);
i = 0;
@ -3707,6 +3731,7 @@ delegated:
}
if (i)
n++;
#endif
return (ssize_t)n;
}

View File

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd April 11, 2017
.Dd May 9, 2017
.Dt DHCPCD 8
.Os
.Sh NAME
@ -610,6 +610,8 @@ So to stop
.Nm
from touching your DNS settings you would do:-
.D1 dhcpcd -C resolv.conf eth0
.It Fl G , Fl Fl nogateway
Don't set any default routes.
.It Fl H , Fl Fl xidhwaddr
Use the last four bytes of the hardware address as the DHCP xid instead
of a randomly generated number.

View File

@ -477,6 +477,10 @@ configure_interface1(struct interface *ifp)
* between reboots without persitent storage,
* generating the IAID from the MAC address is the only
* logical default.
* Saying that, if a VLANID has been specified then we
* can use that. It's possible that different interfaces
* can have the same VLANID, but this is no worse than
* generating the IAID from the duplicate MAC address.
*
* dhclient uses the last 4 bytes of the MAC address.
* dibbler uses an increamenting counter.
@ -487,11 +491,18 @@ configure_interface1(struct interface *ifp)
* dhcpcd-6.1.0 and earlier used the interface name,
* falling back to interface index if name > 4.
*/
if (ifp->hwlen >= sizeof(ifo->iaid))
if (ifp->vlanid != 0) {
uint32_t vlanid;
/* Maximal VLANID is 4095, so prefix with 0xff
* so we don't conflict with an interface index. */
vlanid = htonl(ifp->vlanid | 0xff000000);
memcpy(ifo->iaid, &vlanid, sizeof(vlanid));
} else if (ifp->hwlen >= sizeof(ifo->iaid)) {
memcpy(ifo->iaid,
ifp->hwaddr + ifp->hwlen - sizeof(ifo->iaid),
sizeof(ifo->iaid));
else {
} else {
uint32_t len;
len = (uint32_t)strlen(ifp->name);
@ -503,7 +514,7 @@ configure_interface1(struct interface *ifp)
} else {
/* IAID is the same size as a uint32_t */
len = htonl(ifp->index);
memcpy(ifo->iaid, &len, sizeof(len));
memcpy(ifo->iaid, &len, sizeof(ifo->iaid));
}
}
ifo->options |= DHCPCD_IAID;
@ -775,7 +786,7 @@ warn_iaid_conflict(struct interface *ifp, uint8_t *iaid)
/* This is only a problem if the interfaces are on the same network. */
if (ifn)
logerr("%s: IAID conflicts with one assigned to %s",
logerrx("%s: IAID conflicts with one assigned to %s",
ifp->name, ifn->name);
}
@ -1510,6 +1521,7 @@ main(int argc, char **argv)
#endif
case 'P':
ctx.options |= DHCPCD_PRINT_PIDFILE;
logopts &= ~(LOGERR_LOG | LOGERR_ERR);
break;
case 'T':
i = 1;
@ -1603,10 +1615,12 @@ printpidfile:
* instance for that interface. */
if (optind == argc - 1 && !(ctx.options & DHCPCD_MASTER)) {
const char *per;
const char *ifname;
if (strlen(argv[optind]) > IF_NAMESIZE) {
logerrx("%s: interface name too long",
argv[optind]);
ifname = *ctx.ifv;
if (ifname == NULL || strlen(ifname) > IF_NAMESIZE) {
errno = ifname == NULL ? EINVAL : E2BIG;
logerr("%s: ", ifname);
goto exit_failure;
}
/* Allow a dhcpcd interface per address family */
@ -1621,7 +1635,7 @@ printpidfile:
per = "";
}
snprintf(ctx.pidfile, sizeof(ctx.pidfile),
PIDFILE, "-", argv[optind], per);
PIDFILE, "-", ifname, per);
} else {
snprintf(ctx.pidfile, sizeof(ctx.pidfile),
PIDFILE, "", "", "");
@ -1643,20 +1657,13 @@ printpidfile:
goto exit_failure;
}
/* Open our persistent sockets.
* This is needed early for dumping leases on valid interfaces. */
#ifdef USE_SIGNALS
if (sig == 0) {
#endif
if (ctx.options & DHCPCD_DUMPLEASE) {
/* Open sockets so we can dump something about
* valid interfaces. */
if (if_opensockets(&ctx) == -1) {
logerr("%s: if_opensockets", __func__);
goto exit_failure;
}
#ifdef USE_SIGNALS
}
#endif
if (ctx.options & DHCPCD_DUMPLEASE) {
if (optind != argc) {
/* We need to try and find the interface so we can load
* the hardware address to compare automated IAID */
@ -1803,6 +1810,12 @@ printpidfile:
logdebugx(PACKAGE "-" VERSION " starting");
ctx.options |= DHCPCD_STARTED;
if (if_opensockets(&ctx) == -1) {
logerr("%s: if_opensockets", __func__);
goto exit_failure;
}
#ifdef USE_SIGNALS
if (eloop_signal_set_cb(ctx.eloop,
dhcpcd_signals, dhcpcd_signals_len,

View File

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd April 11, 2017
.Dd May 9, 2017
.Dt DHCPCD.CONF 5
.Os
.Sh NAME
@ -199,7 +199,8 @@ Set the Interface Association Identifier to
This option must be used in an
.Ic interface
block.
This defaults to the last 4 bytes of the hardware address assigned to the
This defaults to the VLANID (prefixed with 0xff) for the interface if set,
otherwise the last 4 bytes of the hardware address assigned to the
interface.
Each instance of this should be unique within the scope of the client and
.Nm dhcpcd
@ -457,6 +458,10 @@ This is only useful when allowing IPv4LL.
.It Ic nodhcp6
Don't start DHCPv6 or listen to DHCPv6 messages.
Normally DHCPv6 is started by a RA instruction or configuration.
.It Ic nogateway
Don't install any default routes.
.It Ic gateway
Install a default route if available (default).
.It Ic nohook Ar script
Don't run this hook script.
Matches full name, or prefixed with 2 numbers optionally ending with

View File

@ -81,6 +81,7 @@ struct interface {
sa_family_t family;
unsigned char hwaddr[HWADDR_LEN];
uint8_t hwlen;
unsigned short vlanid;
unsigned int metric;
int carrier;
int wireless;

View File

@ -48,6 +48,11 @@
#include <netinet/in_var.h>
#include <netinet6/in6_var.h>
#include <netinet6/nd6.h>
#ifdef __NetBSD__
#include <net/if_vlanvar.h> /* Needs netinet/if_ether.h */
#else
#include <net/if_vlan_var.h>
#endif
#ifdef __DragonFly__
# include <netproto/802_11/ieee80211_ioctl.h>
#elif __APPLE__
@ -153,6 +158,8 @@ if_opensockets_os(struct dhcpcd_ctx *ctx)
#define SOCK_FLAGS (SOCK_CLOEXEC | SOCK_NONBLOCK)
ctx->link_fd = xsocket(PF_ROUTE, SOCK_RAW | SOCK_FLAGS, AF_UNSPEC);
#undef SOCK_FLAGS
if (ctx->link_fd == -1)
return -1;
#if defined(RO_MSGFILTER)
if (setsockopt(ctx->link_fd, PF_ROUTE, RO_MSGFILTER,
@ -168,7 +175,7 @@ if_opensockets_os(struct dhcpcd_ctx *ctx)
logerr(__func__);
#endif
return ctx->link_fd == -1 ? -1 : 0;
return 0;
}
void
@ -194,12 +201,31 @@ if_linkaddr(struct sockaddr_dl *sdl, const struct interface *ifp)
}
#endif
#if defined(SIOCG80211NWID) || defined(SIOCGETVLAN)
static int if_direct_ioctl(int s, const char *ifname,
unsigned long cmd, void *data)
{
strlcpy(data, ifname, IFNAMSIZ);
return ioctl(s, cmd, data);
}
static int if_indirect_ioctl(int s, const char *ifname,
unsigned long cmd, void *data)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_data = data;
return if_direct_ioctl(s, ifname, cmd, &ifr);
}
#endif
static int
if_getssid1(int s, const char *ifname, void *ssid)
{
int retval = -1;
#if defined(SIOCG80211NWID)
struct ifreq ifr;
struct ieee80211_nwid nwid;
#elif defined(IEEE80211_IOC_SSID)
struct ieee80211req ireq;
@ -207,11 +233,8 @@ if_getssid1(int s, const char *ifname, void *ssid)
#endif
#if defined(SIOCG80211NWID) /* NetBSD */
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
memset(&nwid, 0, sizeof(nwid));
ifr.ifr_data = (void *)&nwid;
if (ioctl(s, SIOCG80211NWID, &ifr) == 0) {
if (if_indirect_ioctl(s, ifname, SIOCG80211NWID, &nwid) == 0) {
if (ssid == NULL)
retval = nwid.i_len;
else if (nwid.i_len > IF_SSIDLEN)
@ -286,6 +309,31 @@ if_vimaster(const struct dhcpcd_ctx *ctx, const char *ifname)
return 0;
}
unsigned short
if_vlanid(const struct interface *ifp)
{
#ifdef SIOCGETVLAN
struct vlanreq vlr;
memset(&vlr, 0, sizeof(vlr));
if (if_indirect_ioctl(ifp->ctx->pf_inet_fd,
ifp->name, SIOCGETVLAN, &vlr) != 0)
return 0; /* 0 means no VLANID */
return vlr.vlr_tag;
#elif defined(SIOCGVNETID)
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
if (ioctl(ifp->ctx->pf_inet_fd, SIOCGVNETID, &ifr) != 0)
return 0; /* 0 means no VLANID */
return ifr.ifr_vnetid;
#else
UNUSED(ifp);
return 0; /* 0 means no VLANID */
#endif
}
static void
get_addrs(int type, const void *data, const struct sockaddr **sa)
{
@ -413,6 +461,9 @@ if_route(unsigned char cmd, const struct rt *rt)
char *bp = rtmsg.buffer;
struct sockaddr_dl sdl;
bool gateway_unspec;
#ifdef RTA_LABEL
struct sockaddr_rtlabel label;
#endif
assert(rt != NULL);
ctx = rt->rt_ifp->ctx;
@ -448,6 +499,9 @@ if_route(unsigned char cmd, const struct rt *rt)
rtm->rtm_flags |= RTF_UP;
rtm->rtm_addrs |= RTA_GATEWAY;
#ifdef RTA_LABEL
rtm->rtm_addrs |= RTA_LABEL;
#endif
if (!(rtm->rtm_flags & RTF_REJECT) &&
!sa_is_loopback(&rt->rt_gateway))
{
@ -532,6 +586,23 @@ if_route(unsigned char cmd, const struct rt *rt)
if (rtm->rtm_addrs & RTA_IFA)
ADDSA(&rt->rt_ifa);
#ifdef RTA_LABEL
if (rtm->rtm_addrs & RTA_LABEL) {
int len;
memset(&label, 0, sizeof(label));
label.sr_family = AF_UNSPEC;
label.sr_len = sizeof(label);
len = snprintf(label.sr_label, sizeof(label.sr_label),
PACKAGE " %d", getpid());
/* Don't add the label if we failed to create it. */
if (len == -1 || (size_t)len > sizeof(label.sr_label))
rtm->rtm_addrs &= ~RTA_LABEL;
else
ADDSA((struct sockaddr *)&label);
}
#endif
#undef ADDSA
rtm->rtm_msglen = (unsigned short)(bp - (char *)rtm);
@ -785,7 +856,7 @@ if_address6(unsigned char cmd, const struct ipv6_addr *ia)
*/
#if !((defined(__NetBSD_Version__) && __NetBSD_Version__ >= 799003600) || \
(defined(__OpenBSD__)))
(defined(__OpenBSD__) && OpenBSD >= 201605))
if (cmd == RTM_NEWADDR && !(ia->flags & IPV6_AF_ADDED)) {
ifa.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
ifa.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
@ -793,8 +864,8 @@ if_address6(unsigned char cmd, const struct ipv6_addr *ia)
}
#endif
#if defined(__OpenBSD__)
/* BUT OpenBSD does not reset the address lifetime
#if defined(__OpenBSD__) && OpenBSD <= 201705
/* BUT OpenBSD older than 6.2 does not reset the address lifetime
* for subsequent calls...
* Luckily dhcpcd will remove the lease when it expires so
* just set an infinite lifetime, unless a temporary address. */

View File

@ -93,7 +93,7 @@
#define O_IPV6 O_BASE + 33
#define O_CONTROLGRP O_BASE + 34
#define O_SLAAC O_BASE + 35
// unused O_BASE + 36
#define O_GATEWAY O_BASE + 36
#define O_NOUP O_BASE + 37
#define O_IPV6RA_AUTOCONF O_BASE + 38
#define O_IPV6RA_NOAUTOCONF O_BASE + 39
@ -196,6 +196,7 @@ const struct option cf_options[] = {
{"nodhcp6", no_argument, NULL, O_NODHCP6},
{"controlgroup", required_argument, NULL, O_CONTROLGRP},
{"slaac", required_argument, NULL, O_SLAAC},
{"gateway", no_argument, NULL, O_GATEWAY},
{"reject", required_argument, NULL, O_REJECT},
{"bootp", no_argument, NULL, O_BOOTP},
{"nodelay", no_argument, NULL, O_NODELAY},
@ -978,6 +979,9 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
return -1;
}
break;
case 'G':
ifo->options &= ~DHCPCD_GATEWAY;
break;
case 'H':
ifo->options |= DHCPCD_XID_HWADDR;
break;
@ -1062,8 +1066,14 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
strncmp(arg, "ms_classless_static_routes=",
strlen("ms_classless_static_routes=")) == 0)
{
struct interface *ifp;
struct in_addr addr3;
ifp = if_find(ctx->ifaces, ifname);
if (ifp == NULL) {
logerrx("static routes require an interface");
return -1;
}
fp = np = strwhite(p);
if (np == NULL) {
logerrx("all routes need a gateway");
@ -1077,7 +1087,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
*fp = ' ';
return -1;
}
if ((rt = rt_new(if_find(ctx->ifaces, ifname))) == NULL) {
if ((rt = rt_new(ifp)) == NULL) {
*fp = ' ';
return -1;
}
@ -1087,9 +1097,16 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
TAILQ_INSERT_TAIL(&ifo->routes, rt, rt_next);
*fp = ' ';
} else if (strncmp(arg, "routers=", strlen("routers=")) == 0) {
struct interface *ifp;
ifp = if_find(ctx->ifaces, ifname);
if (ifp == NULL) {
logerrx("static routes require an interface");
return -1;
}
if (parse_addr(&addr, NULL, p) == -1)
return -1;
if ((rt = rt_new(if_find(ctx->ifaces, ifname))) == NULL)
if ((rt = rt_new(ifp)) == NULL)
return -1;
addr2.s_addr = INADDR_ANY;
sa_in_init(&rt->rt_dest, &addr2);
@ -2078,6 +2095,9 @@ err_sla:
ctx->control_group = grp->gr_gid;
#endif
break;
case O_GATEWAY:
ifo->options |= DHCPCD_GATEWAY;
break;
case O_NOUP:
ifo->options &= ~DHCPCD_IF_UP;
break;
@ -2257,7 +2277,7 @@ read_config(struct dhcpcd_ctx *ctx,
/* Seed our default options */
if ((ifo = default_config(ctx)) == NULL)
return NULL;
ifo->options |= DHCPCD_DAEMONISE;
ifo->options |= DHCPCD_DAEMONISE | DHCPCD_GATEWAY;
#ifdef PLUGIN_DEV
ifo->options |= DHCPCD_DEV;
#endif

View File

@ -43,7 +43,7 @@
/* Don't set any optional arguments here so we retain POSIX
* compatibility with getopt */
#define IF_OPTS "146bc:de:f:gh:i:j:kl:m:no:pqr:s:t:u:v:wxy:z:" \
"ABC:DEF:HI:JKLMNO:PQ:S:TUVW:X:Z:"
"ABC:DEF:GHI:JKLMNO:PQ:S:TUVW:X:Z:"
#define NOERR_IF_OPTS ":" IF_OPTS
#define DEFAULT_TIMEOUT 30
@ -61,7 +61,7 @@
#define DHCPCD_ARP (1ULL << 0)
#define DHCPCD_RELEASE (1ULL << 1)
// unused (1ULL << 2)
// unused (1ULL << 3)
#define DHCPCD_GATEWAY (1ULL << 3)
#define DHCPCD_STATIC (1ULL << 4)
#define DHCPCD_DEBUG (1ULL << 5)
#define DHCPCD_LASTLEASE (1ULL << 7)

View File

@ -516,6 +516,8 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
}
}
ifp->vlanid = if_vlanid(ifp);
#ifdef SIOCGIFPRIORITY
/* Respect the interface priority */
memset(&ifr, 0, sizeof(ifr));

View File

@ -141,6 +141,7 @@ int if_conf(struct interface *);
int if_init(struct interface *);
int if_getssid(struct interface *);
int if_vimaster(const struct dhcpcd_ctx *ctx, const char *);
unsigned short if_vlanid(const struct interface *);
int if_opensockets(struct dhcpcd_ctx *);
int if_opensockets_os(struct dhcpcd_ctx *);
void if_closesockets(struct dhcpcd_ctx *);

View File

@ -229,9 +229,9 @@ ipv4_ifcmp(const struct interface *si, const struct interface *ti)
if (!sis->new && tis->new)
return 1;
/* Always prefer proper leases */
if (!(sis->added & STATE_FAKE) && (sis->added & STATE_FAKE))
if (!(sis->added & STATE_FAKE) && (tis->added & STATE_FAKE))
return -1;
if ((sis->added & STATE_FAKE) && !(sis->added & STATE_FAKE))
if ((sis->added & STATE_FAKE) && !(tis->added & STATE_FAKE))
return 1;
/* If we are either, they neither have a lease, or they both have.
* We need to check for IPv4LL and make it non-preferred. */

View File

@ -578,6 +578,22 @@ ipv6_checkaddrflags(void *arg)
}
#endif
static void
ipv6_deletedaddr(struct ipv6_addr *ia)
{
#ifdef SMALL
UNUSED(ia);
#else
/* NOREJECT is set if we delegated exactly the prefix to another
* address.
* This can only be one address, so just clear the flag.
* This should ensure the reject route will be restored. */
if (ia->delegating_prefix != NULL)
ia->delegating_prefix->flags &= ~IPV6_AF_NOREJECT;
#endif
}
static void
ipv6_deleteaddr(struct ipv6_addr *ia)
{
@ -590,12 +606,7 @@ ipv6_deleteaddr(struct ipv6_addr *ia)
errno != ENXIO && errno != ENODEV)
logerr(__func__);
/* NOREJECT is set if we delegated exactly the prefix to another
* address.
* This can only be one address, so just clear the flag.
* This should ensure the reject route will be restored. */
if (ia->delegating_prefix != NULL)
ia->delegating_prefix->flags &= ~IPV6_AF_NOREJECT;
ipv6_deletedaddr(ia);
state = IPV6_STATE(ia->iface);
TAILQ_FOREACH(ap, &state->addrs, next) {
@ -635,6 +646,38 @@ ipv6_addaddr1(struct ipv6_addr *ap, const struct timespec *now)
ipv6_iffindaddr(ap->iface, &ap->addr, IN6_IFF_NOTUSEABLE))
ap->flags |= IPV6_AF_DADCOMPLETED;
/* Adjust plftime and vltime based on acquired time */
pltime = ap->prefix_pltime;
vltime = ap->prefix_vltime;
if (timespecisset(&ap->acquired) &&
(ap->prefix_pltime != ND6_INFINITE_LIFETIME ||
ap->prefix_vltime != ND6_INFINITE_LIFETIME))
{
struct timespec n;
if (now == NULL) {
clock_gettime(CLOCK_MONOTONIC, &n);
now = &n;
}
timespecsub(now, &ap->acquired, &n);
if (ap->prefix_pltime != ND6_INFINITE_LIFETIME) {
ap->prefix_pltime -= (uint32_t)n.tv_sec;
/* This can happen when confirming a
* deprecated but still valid lease. */
if (ap->prefix_pltime > pltime)
ap->prefix_pltime = 0;
}
if (ap->prefix_vltime != ND6_INFINITE_LIFETIME) {
ap->prefix_vltime -= (uint32_t)n.tv_sec;
/* This should never happen. */
if (ap->prefix_vltime > vltime) {
logerrx("%s: %s: lifetime overflow",
ifp->name, ap->saddr);
ap->prefix_vltime = ap->prefix_pltime = 0;
}
}
}
logfunc = ap->flags & IPV6_AF_NEW ? loginfox : logdebugx;
logfunc("%s: adding %saddress %s", ap->iface->name,
#ifdef IPV6_AF_TEMPORARY
@ -658,41 +701,6 @@ ipv6_addaddr1(struct ipv6_addr *ap, const struct timespec *now)
" seconds",
ap->iface->name, ap->prefix_pltime, ap->prefix_vltime);
/* Adjust plftime and vltime based on acquired time */
pltime = ap->prefix_pltime;
vltime = ap->prefix_vltime;
if (timespecisset(&ap->acquired) &&
(ap->prefix_pltime != ND6_INFINITE_LIFETIME ||
ap->prefix_vltime != ND6_INFINITE_LIFETIME))
{
struct timespec n;
if (now == NULL) {
clock_gettime(CLOCK_MONOTONIC, &n);
now = &n;
}
timespecsub(now, &ap->acquired, &n);
if (ap->prefix_pltime != ND6_INFINITE_LIFETIME) {
ap->prefix_pltime -= (uint32_t)n.tv_sec;
/* This can happen when confirming a
* deprecated but still valid lease. */
if (ap->prefix_pltime > pltime)
ap->prefix_pltime = 0;
}
if (ap->prefix_vltime != ND6_INFINITE_LIFETIME)
ap->prefix_vltime -= (uint32_t)n.tv_sec;
#if 0
logdebugx("%s: acquired %lld.%.9ld, now %lld.%.9ld, diff %lld.%.9ld",
ap->iface->name,
(long long)ap->acquired.tv_sec, ap->acquired.tv_nsec,
(long long)now->tv_sec, now->tv_nsec,
(long long)n.tv_sec, n.tv_nsec);
logdebugx("%s: adj pltime %"PRIu32" seconds, "
"vltime %"PRIu32" seconds",
ap->iface->name, ap->prefix_pltime, ap->prefix_vltime);
#endif
}
if (if_address6(RTM_NEWADDR, ap) == -1) {
logerr(__func__);
@ -719,8 +727,10 @@ ipv6_addaddr1(struct ipv6_addr *ap, const struct timespec *now)
ap->flags &= ~IPV6_AF_NEW;
ap->flags |= IPV6_AF_ADDED;
#ifndef SMALL
if (ap->delegating_prefix != NULL)
ap->flags |= IPV6_AF_DELEGATED;
#endif
#ifdef IPV6_POLLADDRFLAG
eloop_timeout_delete(ap->iface->ctx->eloop,
@ -944,6 +954,7 @@ ipv6_addaddrs(struct ipv6_addrhead *addrs)
void
ipv6_freeaddr(struct ipv6_addr *ap)
{
#ifndef SMALL
struct ipv6_addr *ia;
/* Forget the reference */
@ -954,6 +965,7 @@ ipv6_freeaddr(struct ipv6_addr *ap)
} else if (ap->delegating_prefix != NULL) {
TAILQ_REMOVE(&ap->delegating_prefix->pd_pfxs, ap, pd_next);
}
#endif
eloop_q_timeout_delete(ap->iface->ctx->eloop, 0, NULL, ap);
free(ap);
@ -966,12 +978,17 @@ ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop,
struct ipv6_addr *ap, *apn, *apf;
struct timespec now;
#ifdef SMALL
UNUSED(ifd);
#endif
timespecclear(&now);
TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
#ifndef SMALL
if (ifd != NULL &&
(ap->delegating_prefix == NULL ||
ap->delegating_prefix->iface != ifd))
continue;
#endif
if (drop != 2)
TAILQ_REMOVE(addrs, ap, next);
if (drop && ap->flags & IPV6_AF_ADDED &&
@ -1676,6 +1693,11 @@ ipv6_handleifa_addrs(int cmd,
ia->iface->name, ia->saddr);
ia->flags &= ~IPV6_AF_ADDED;
}
if (ia->flags & IPV6_AF_DELEGATED) {
TAILQ_REMOVE(addrs, ia, next);
ipv6_deletedaddr(ia);
ipv6_freeaddr(ia);
}
break;
case RTM_NEWADDR:
/* Safety - ignore tentative announcements */

View File

@ -166,12 +166,14 @@ struct ipv6_addr {
uint8_t iaid[4];
uint16_t ia_type;
#ifndef SMALL
struct ipv6_addr *delegating_prefix;
struct ipv6_addrhead pd_pfxs;
TAILQ_ENTRY(ipv6_addr) pd_next;
uint8_t prefix_exclude_len;
struct in6_addr prefix_exclude;
#endif
void (*dadcallback)(void *);
int dadcounter;

View File

@ -281,6 +281,21 @@ rt_add(struct rt *nrt, struct rt *ort)
assert(nrt != NULL);
ctx = nrt->rt_ifp->ctx;
/*
* Don't install a gateway if not asked to.
* This option is mainly for VPN users who want their VPN to be the
* default route.
* Because VPN's generally don't care about route management
* beyond their own, a longer term solution would be to remove this
* and get the VPN to inject the default route into dhcpcd somehow.
*/
if (((nrt->rt_ifp->active &&
!(nrt->rt_ifp->options->options & DHCPCD_GATEWAY)) ||
(!nrt->rt_ifp->active && !(ctx->options & DHCPCD_GATEWAY))) &&
sa_is_unspecified(&nrt->rt_dest) &&
sa_is_unspecified(&nrt->rt_netmask))
return false;
rt_desc(ort == NULL ? "adding" : "changing", nrt);
change = false;