Import dhcpcd-8.0.0 with the following changes:
* ARP now supports many requests * Routing tables now use Red-Black Trees * Script variables are no longer allocated manually
This commit is contained in:
parent
6964063b9b
commit
141ff30ff1
|
@ -93,7 +93,7 @@ wpa_supplicant_stop()
|
|||
err=$(wpa_cli -i"$interface" terminate 2>&1)
|
||||
errn=$?
|
||||
if [ $errn != 0 ]; then
|
||||
syslog err "failed to start wpa_supplicant"
|
||||
syslog err "failed to stop wpa_supplicant"
|
||||
syslog err "$err"
|
||||
fi
|
||||
return $errn
|
||||
|
|
|
@ -19,6 +19,7 @@ build_resolv_conf()
|
|||
interfaces=$(list_interfaces "$resolv_conf_dir")
|
||||
|
||||
# Build the resolv.conf
|
||||
header=
|
||||
if [ -n "$interfaces" ]; then
|
||||
# Build the header
|
||||
for x in ${interfaces}; do
|
||||
|
@ -69,30 +70,26 @@ build_resolv_conf()
|
|||
}
|
||||
|
||||
# Extract any ND DNS options from the RA
|
||||
# For now, we ignore the lifetime of the DNS options unless they
|
||||
# are absent or zero.
|
||||
# In this case they are removed from consideration.
|
||||
# See draft-gont-6man-slaac-dns-config-issues-01 for issues
|
||||
# regarding DNS option lifetime in ND messages.
|
||||
# Obey the lifetimes
|
||||
eval_nd_dns()
|
||||
{
|
||||
eval ltime=\$nd${i}_rdnss${j}_lifetime
|
||||
if [ -z "$ltime" ] || [ "$ltime" = 0 ]; then
|
||||
rdnss=
|
||||
else
|
||||
|
||||
eval rdnsstime=\$nd${i}_rdnss${j}_lifetime
|
||||
[ -z "$rdnsstime" ] && return 1
|
||||
ltime=$(($rdnsstime - $offset))
|
||||
if [ "$ltime" -gt 0 ]; then
|
||||
eval rdnss=\$nd${i}_rdnss${j}_servers
|
||||
[ -n "$rdnss" ] && new_rdnss="$new_rdnss${new_rdnss:+ }$rdnss"
|
||||
fi
|
||||
eval ltime=\$nd${i}_dnssl${j}_lifetime
|
||||
if [ -z "$ltime" ] || [ "$ltime" = 0 ]; then
|
||||
dnssl=
|
||||
else
|
||||
|
||||
eval dnssltime=\$nd${i}_dnssl${j}_lifetime
|
||||
[ -z "$dnssltime" ] && return 1
|
||||
ltime=$(($dnssltime - $offset))
|
||||
if [ "$ltime" -gt 0 ]; then
|
||||
eval dnssl=\$nd${i}_dnssl${j}_search
|
||||
[ -n "$dnssl" ] && new_dnssl="$new_dnssl${new_dnssl:+ }$dnssl"
|
||||
fi
|
||||
|
||||
[ -z "${rdnss}${dnssl}" ] && return 1
|
||||
|
||||
[ -n "$rdnss" ] && new_rdnss="$new_rdnss${new_rdnss:+ }$rdnss"
|
||||
[ -n "$dnssl" ] && new_dnssl="$new_dnssl${new_dnssl:+ }$dnssl"
|
||||
j=$(($j + 1))
|
||||
return 0
|
||||
}
|
||||
|
@ -106,12 +103,16 @@ add_resolv_conf()
|
|||
i=1
|
||||
j=1
|
||||
while true; do
|
||||
eval acquired=\$nd${i}_acquired
|
||||
[ -z "$acquired" ] && break
|
||||
eval now=\$nd${i}_now
|
||||
[ -z "$now" ] && break
|
||||
offset=$(($now - $acquired))
|
||||
while true; do
|
||||
eval_nd_dns || break
|
||||
done
|
||||
i=$(($i + 1))
|
||||
j=1
|
||||
eval_nd_dns || break
|
||||
done
|
||||
[ -n "$new_rdnss" ] && \
|
||||
new_domain_name_servers="$new_domain_name_servers${new_domain_name_servers:+ }$new_rdnss"
|
||||
|
|
|
@ -62,6 +62,7 @@ build_ntp_conf()
|
|||
# Build a list of interfaces
|
||||
interfaces=$(list_interfaces "$ntp_conf_dir")
|
||||
|
||||
header=
|
||||
servers=
|
||||
if [ -n "$interfaces" ]; then
|
||||
# Build the header
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - ARP handler
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -36,6 +37,7 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
@ -62,8 +64,9 @@
|
|||
/* Assert the correct structure size for on wire */
|
||||
__CTASSERT(sizeof(struct arphdr) == 8);
|
||||
|
||||
ssize_t
|
||||
arp_request(const struct interface *ifp, in_addr_t sip, in_addr_t tip)
|
||||
static ssize_t
|
||||
arp_request(const struct interface *ifp,
|
||||
const struct in_addr *sip, const struct in_addr *tip)
|
||||
{
|
||||
uint8_t arp_buffer[ARP_LEN];
|
||||
struct arphdr ar;
|
||||
|
@ -74,7 +77,7 @@ arp_request(const struct interface *ifp, in_addr_t sip, in_addr_t tip)
|
|||
ar.ar_hrd = htons(ifp->family);
|
||||
ar.ar_pro = htons(ETHERTYPE_IP);
|
||||
ar.ar_hln = ifp->hwlen;
|
||||
ar.ar_pln = sizeof(sip);
|
||||
ar.ar_pln = sizeof(tip->s_addr);
|
||||
ar.ar_op = htons(ARPOP_REQUEST);
|
||||
|
||||
p = arp_buffer;
|
||||
|
@ -93,9 +96,12 @@ arp_request(const struct interface *ifp, in_addr_t sip, in_addr_t tip)
|
|||
|
||||
APPEND(&ar, sizeof(ar));
|
||||
APPEND(ifp->hwaddr, ifp->hwlen);
|
||||
APPEND(&sip, sizeof(sip));
|
||||
if (sip != NULL)
|
||||
APPEND(&sip->s_addr, sizeof(sip->s_addr));
|
||||
else
|
||||
ZERO(sizeof(tip->s_addr));
|
||||
ZERO(ifp->hwlen);
|
||||
APPEND(&tip, sizeof(tip));
|
||||
APPEND(&tip->s_addr, sizeof(tip->s_addr));
|
||||
|
||||
state = ARP_CSTATE(ifp);
|
||||
return bpf_send(ifp, state->bpf_fd, ETHERTYPE_ARP, arp_buffer, len);
|
||||
|
@ -105,6 +111,77 @@ eexit:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
arp_report_conflicted(const struct arp_state *astate,
|
||||
const struct arp_msg *amsg)
|
||||
{
|
||||
char buf[HWADDR_LEN * 3];
|
||||
|
||||
if (amsg == NULL) {
|
||||
logerrx("%s: DAD detected %s",
|
||||
astate->iface->name, inet_ntoa(astate->addr));
|
||||
return;
|
||||
}
|
||||
|
||||
logerrx("%s: hardware address %s claims %s",
|
||||
astate->iface->name,
|
||||
hwaddr_ntoa(amsg->sha, astate->iface->hwlen, buf, sizeof(buf)),
|
||||
inet_ntoa(astate->addr));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
arp_found(struct arp_state *astate, const struct arp_msg *amsg)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct ivp4_addr *ia;
|
||||
#ifndef KERNEL_RFC5227
|
||||
struct timespec now, defend;
|
||||
#endif
|
||||
|
||||
arp_report_conflicted(astate, amsg);
|
||||
ifp = astate->iface;
|
||||
|
||||
#pragma GCC diagnostic push /* GCC is clearly wrong about this warning. */
|
||||
#pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
|
||||
/* If we haven't added the address we're doing a probe. */
|
||||
ia = ipv4_iffindaddr(ifp, &astate->addr, NULL);
|
||||
#pragma GCC diagnostic pop
|
||||
if (ia == NULL) {
|
||||
if (astate->found_cb != NULL)
|
||||
astate->found_cb(astate, amsg);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef KERNEL_RFC5227
|
||||
/* RFC 3927 Section 2.5 says a defence should
|
||||
* broadcast an ARP announcement.
|
||||
* Because the kernel will also unicast a reply to the
|
||||
* hardware address which requested the IP address
|
||||
* the other IPv4LL client will receieve two ARP
|
||||
* messages.
|
||||
* If another conflict happens within DEFEND_INTERVAL
|
||||
* then we must drop our address and negotiate a new one. */
|
||||
defend.tv_sec = astate->defend.tv_sec + DEFEND_INTERVAL;
|
||||
defend.tv_nsec = astate->defend.tv_nsec;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
if (timespeccmp(&defend, &now, >))
|
||||
logwarnx("%s: %d second defence failed for %s",
|
||||
ifp->name, DEFEND_INTERVAL, inet_ntoa(astate->addr));
|
||||
else if (arp_request(ifp, &astate->addr, &astate->addr) == -1)
|
||||
logerr(__func__);
|
||||
else {
|
||||
logdebugx("%s: defended address %s",
|
||||
ifp->name, inet_ntoa(astate->addr));
|
||||
astate->defend = now;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (astate->defend_failed_cb != NULL)
|
||||
astate->defend_failed_cb(astate);
|
||||
}
|
||||
|
||||
static void
|
||||
arp_packet(struct interface *ifp, uint8_t *data, size_t len)
|
||||
{
|
||||
|
@ -164,14 +241,15 @@ arp_packet(struct interface *ifp, uint8_t *data, size_t len)
|
|||
memcpy(&arm.tha, hw_t, ar.ar_hln);
|
||||
memcpy(&arm.tip.s_addr, hw_t + ar.ar_hln, ar.ar_pln);
|
||||
|
||||
/* Run the conflicts */
|
||||
/* Match the ARP probe to our states.
|
||||
* Ignore Unicast Poll, RFC1122. */
|
||||
state = ARP_CSTATE(ifp);
|
||||
TAILQ_FOREACH_SAFE(astate, &state->arp_states, next, astaten) {
|
||||
if (arm.sip.s_addr != astate->addr.s_addr &&
|
||||
arm.tip.s_addr != astate->addr.s_addr)
|
||||
continue;
|
||||
if (astate->conflicted_cb)
|
||||
astate->conflicted_cb(astate, &arm);
|
||||
if (IN_ARE_ADDR_EQUAL(&arm.sip, &astate->addr) ||
|
||||
(IN_IS_ADDR_UNSPECIFIED(&arm.sip) &&
|
||||
IN_ARE_ADDR_EQUAL(&arm.tip, &astate->addr) &&
|
||||
state->bpf_flags & BPF_BCAST))
|
||||
arp_found(astate, &arm);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,7 +321,7 @@ arp_read(void *arg)
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
arp_open(struct interface *ifp)
|
||||
{
|
||||
struct iarp_state *state;
|
||||
|
@ -265,7 +343,8 @@ arp_probed(void *arg)
|
|||
{
|
||||
struct arp_state *astate = arg;
|
||||
|
||||
astate->probed_cb(astate);
|
||||
timespecclear(&astate->defend);
|
||||
astate->not_found_cb(astate);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -290,7 +369,7 @@ arp_probe1(void *arg)
|
|||
ifp->name, inet_ntoa(astate->addr),
|
||||
astate->probes ? astate->probes : PROBE_NUM, PROBE_NUM,
|
||||
timespec_to_double(&tv));
|
||||
if (arp_request(ifp, 0, astate->addr.s_addr) == -1)
|
||||
if (arp_request(ifp, NULL, &astate->addr) == -1)
|
||||
logerr(__func__);
|
||||
}
|
||||
|
||||
|
@ -314,6 +393,23 @@ arp_probe(struct arp_state *astate)
|
|||
}
|
||||
#endif /* ARP */
|
||||
|
||||
static struct arp_state *
|
||||
arp_find(struct interface *ifp, const struct in_addr *addr)
|
||||
{
|
||||
struct iarp_state *state;
|
||||
struct arp_state *astate;
|
||||
|
||||
if ((state = ARP_STATE(ifp)) == NULL)
|
||||
goto out;
|
||||
TAILQ_FOREACH(astate, &state->arp_states, next) {
|
||||
if (astate->addr.s_addr == addr->s_addr && astate->iface == ifp)
|
||||
return astate;
|
||||
}
|
||||
out:
|
||||
errno = ESRCH;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
arp_announced(void *arg)
|
||||
{
|
||||
|
@ -342,7 +438,7 @@ arp_announce1(void *arg)
|
|||
logdebugx("%s: ARP announcing %s (%d of %d)",
|
||||
ifp->name, inet_ntoa(astate->addr),
|
||||
astate->claims, ANNOUNCE_NUM);
|
||||
if (arp_request(ifp, astate->addr.s_addr, astate->addr.s_addr) == -1)
|
||||
if (arp_request(ifp, &astate->addr, &astate->addr) == -1)
|
||||
logerr(__func__);
|
||||
eloop_timeout_add_sec(ifp->ctx->eloop, ANNOUNCE_WAIT,
|
||||
astate->claims < ANNOUNCE_NUM ? arp_announce1 : arp_announced,
|
||||
|
@ -400,73 +496,45 @@ arp_announce(struct arp_state *astate)
|
|||
arp_announce1(astate);
|
||||
}
|
||||
|
||||
void
|
||||
arp_announceaddr(struct dhcpcd_ctx *ctx, const struct in_addr *ia)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct ipv4_addr *iaf;
|
||||
struct arp_state *astate;
|
||||
|
||||
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
|
||||
iaf = ipv4_iffindaddr(ifp, ia, NULL);
|
||||
#ifdef IN_IFF_NOTUSEABLE
|
||||
if (iaf && !(iaf->addr_flags & IN_IFF_NOTUSEABLE))
|
||||
#else
|
||||
if (iaf)
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (ifp == NULL)
|
||||
return;
|
||||
|
||||
astate = arp_find(ifp, ia);
|
||||
if (astate != NULL)
|
||||
arp_announce(astate);
|
||||
}
|
||||
|
||||
void
|
||||
arp_ifannounceaddr(struct interface *ifp, const struct in_addr *ia)
|
||||
{
|
||||
struct arp_state *astate;
|
||||
|
||||
astate = arp_new(ifp, ia);
|
||||
if (astate != NULL)
|
||||
arp_announce(astate);
|
||||
astate = arp_find(ifp, ia);
|
||||
if (astate == NULL) {
|
||||
astate = arp_new(ifp, ia);
|
||||
if (astate == NULL)
|
||||
return;
|
||||
astate->announced_cb = arp_free;
|
||||
}
|
||||
arp_announce(astate);
|
||||
}
|
||||
|
||||
void
|
||||
arp_report_conflicted(const struct arp_state *astate,
|
||||
const struct arp_msg *amsg)
|
||||
arp_announceaddr(struct dhcpcd_ctx *ctx, const struct in_addr *ia)
|
||||
{
|
||||
struct interface *ifp, *iff = NULL;
|
||||
struct ipv4_addr *iap;
|
||||
|
||||
if (amsg != NULL) {
|
||||
char buf[HWADDR_LEN * 3];
|
||||
|
||||
logerrx("%s: hardware address %s claims %s",
|
||||
astate->iface->name,
|
||||
hwaddr_ntoa(amsg->sha, astate->iface->hwlen,
|
||||
buf, sizeof(buf)),
|
||||
inet_ntoa(astate->failed));
|
||||
} else
|
||||
logerrx("%s: DAD detected %s",
|
||||
astate->iface->name, inet_ntoa(astate->failed));
|
||||
}
|
||||
|
||||
struct arp_state *
|
||||
arp_find(struct interface *ifp, const struct in_addr *addr)
|
||||
{
|
||||
struct iarp_state *state;
|
||||
struct arp_state *astate;
|
||||
|
||||
if ((state = ARP_STATE(ifp)) == NULL)
|
||||
goto out;
|
||||
TAILQ_FOREACH(astate, &state->arp_states, next) {
|
||||
if (astate->addr.s_addr == addr->s_addr && astate->iface == ifp)
|
||||
return astate;
|
||||
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
|
||||
if (!ifp->active || ifp->carrier <= LINK_DOWN)
|
||||
continue;
|
||||
iap = ipv4_iffindaddr(ifp, ia, NULL);
|
||||
if (iap == NULL)
|
||||
continue;
|
||||
#ifdef IN_IFF_NOTUSEABLE
|
||||
if (!(iap->addr_flags & IN_IFF_NOTUSEABLE))
|
||||
continue;
|
||||
#endif
|
||||
if (iff != NULL && iff->metric < ifp->metric)
|
||||
continue;
|
||||
iff = ifp;
|
||||
}
|
||||
out:
|
||||
errno = ESRCH;
|
||||
return NULL;
|
||||
if (iff == NULL)
|
||||
return;
|
||||
|
||||
arp_ifannounceaddr(iff, ia);
|
||||
}
|
||||
|
||||
struct arp_state *
|
||||
|
@ -532,61 +600,24 @@ arp_free(struct arp_state *astate)
|
|||
arp_tryfree(ifp);
|
||||
}
|
||||
|
||||
static void
|
||||
arp_free_but1(struct interface *ifp, struct arp_state *astate)
|
||||
{
|
||||
struct iarp_state *state;
|
||||
|
||||
if ((state = ARP_STATE(ifp)) != NULL) {
|
||||
struct arp_state *p, *n;
|
||||
|
||||
TAILQ_FOREACH_SAFE(p, &state->arp_states, next, n) {
|
||||
if (p != astate)
|
||||
arp_free(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
arp_free_but(struct arp_state *astate)
|
||||
arp_freeaddr(struct interface *ifp, const struct in_addr *ia)
|
||||
{
|
||||
struct arp_state *astate;
|
||||
|
||||
arp_free_but1(astate->iface, astate);
|
||||
astate = arp_find(ifp, ia);
|
||||
arp_free(astate);
|
||||
}
|
||||
|
||||
void
|
||||
arp_drop(struct interface *ifp)
|
||||
{
|
||||
|
||||
arp_free_but1(ifp, NULL);
|
||||
arp_close(ifp);
|
||||
}
|
||||
|
||||
void
|
||||
arp_handleifa(int cmd, struct ipv4_addr *addr)
|
||||
{
|
||||
struct iarp_state *state;
|
||||
struct arp_state *astate, *asn;
|
||||
struct arp_state *astate;
|
||||
|
||||
state = ARP_STATE(addr->iface);
|
||||
if (state == NULL)
|
||||
return;
|
||||
while ((state = ARP_STATE(ifp)) != NULL &&
|
||||
(astate = TAILQ_FIRST(&state->arp_states)) != NULL)
|
||||
arp_free(astate);
|
||||
|
||||
TAILQ_FOREACH_SAFE(astate, &state->arp_states, next, asn) {
|
||||
if (astate->addr.s_addr != addr->addr.s_addr)
|
||||
continue;
|
||||
if (cmd == RTM_DELADDR)
|
||||
arp_free(astate);
|
||||
#ifdef IN_IFF_DUPLICATED
|
||||
if (cmd != RTM_NEWADDR)
|
||||
continue;
|
||||
if (addr->addr_flags & IN_IFF_DUPLICATED) {
|
||||
if (astate->conflicted_cb)
|
||||
astate->conflicted_cb(astate, NULL);
|
||||
} else if (!(addr->addr_flags & IN_IFF_NOTUSEABLE)) {
|
||||
if (astate->probed_cb)
|
||||
astate->probed_cb(astate);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/* No need to close because the last free will close */
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -63,15 +64,16 @@ struct arp_state {
|
|||
TAILQ_ENTRY(arp_state) next;
|
||||
struct interface *iface;
|
||||
|
||||
void (*probed_cb)(struct arp_state *);
|
||||
void (*found_cb)(struct arp_state *, const struct arp_msg *);
|
||||
void (*not_found_cb)(struct arp_state *);
|
||||
void (*announced_cb)(struct arp_state *);
|
||||
void (*conflicted_cb)(struct arp_state *, const struct arp_msg *);
|
||||
void (*defend_failed_cb)(struct arp_state *);
|
||||
void (*free_cb)(struct arp_state *);
|
||||
|
||||
struct in_addr addr;
|
||||
int probes;
|
||||
int claims;
|
||||
struct in_addr failed;
|
||||
struct timespec defend;
|
||||
};
|
||||
TAILQ_HEAD(arp_statehead, arp_state);
|
||||
|
||||
|
@ -87,20 +89,14 @@ struct iarp_state {
|
|||
((const struct iarp_state *)(ifp)->if_data[IF_DATA_ARP])
|
||||
|
||||
#ifdef ARP
|
||||
int arp_open(struct interface *);
|
||||
ssize_t arp_request(const struct interface *, in_addr_t, in_addr_t);
|
||||
void arp_probe(struct arp_state *);
|
||||
void arp_report_conflicted(const struct arp_state *, const struct arp_msg *);
|
||||
struct arp_state *arp_new(struct interface *, const struct in_addr *);
|
||||
struct arp_state *arp_find(struct interface *, const struct in_addr *);
|
||||
void arp_probe(struct arp_state *);
|
||||
void arp_announce(struct arp_state *);
|
||||
void arp_announceaddr(struct dhcpcd_ctx *, const struct in_addr *);
|
||||
void arp_ifannounceaddr(struct interface *, const struct in_addr *);
|
||||
void arp_cancel(struct arp_state *);
|
||||
void arp_free(struct arp_state *);
|
||||
void arp_free_but(struct arp_state *);
|
||||
void arp_freeaddr(struct interface *, const struct in_addr *);
|
||||
void arp_drop(struct interface *);
|
||||
|
||||
void arp_handleifa(int, struct ipv4_addr *);
|
||||
#endif /* ARP */
|
||||
#endif /* ARP_H */
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -30,6 +31,7 @@
|
|||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd: BPF arp and bootp filtering
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -84,7 +85,7 @@ size_t
|
|||
bpf_frame_header_len(const struct interface *ifp)
|
||||
{
|
||||
|
||||
switch(ifp->family) {
|
||||
switch (ifp->family) {
|
||||
case ARPHRD_ETHER:
|
||||
return sizeof(struct ether_header);
|
||||
default:
|
||||
|
@ -92,6 +93,23 @@ bpf_frame_header_len(const struct interface *ifp)
|
|||
}
|
||||
}
|
||||
|
||||
static const uint8_t etherbroadcastaddr[] =
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
int
|
||||
bpf_frame_bcast(const struct interface *ifp, const char *frame)
|
||||
{
|
||||
|
||||
switch (ifp->family) {
|
||||
case ARPHRD_ETHER:
|
||||
return memcmp(frame +
|
||||
offsetof(struct ether_header, ether_dhost),
|
||||
etherbroadcastaddr, sizeof(etherbroadcastaddr));
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __linux__
|
||||
/* Linux is a special snowflake for opening, attaching and reading BPF.
|
||||
* See if-linux.c for the Linux specific BPF functions. */
|
||||
|
@ -227,8 +245,12 @@ bpf_read(struct interface *ifp, int fd, void *data, size_t len,
|
|||
if (state->buffer_pos + packet.bh_caplen + packet.bh_hdrlen >
|
||||
state->buffer_len)
|
||||
goto next; /* Packet beyond buffer, drop. */
|
||||
payload = state->buffer + state->buffer_pos +
|
||||
packet.bh_hdrlen + fl;
|
||||
payload = state->buffer + state->buffer_pos + packet.bh_hdrlen;
|
||||
if (bpf_frame_bcast(ifp, payload) == 0)
|
||||
*flags |= BPF_BCAST;
|
||||
else
|
||||
*flags &= ~BPF_BCAST;
|
||||
payload += fl;
|
||||
bytes = (ssize_t)packet.bh_caplen - fl;
|
||||
if ((size_t)bytes > len)
|
||||
bytes = (ssize_t)len;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd: BPF arp and bootp filtering
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -31,11 +32,13 @@
|
|||
#define BPF_READING (1U << 0)
|
||||
#define BPF_EOF (1U << 1)
|
||||
#define BPF_PARTIALCSUM (1U << 2)
|
||||
#define BPF_BCAST (1U << 3)
|
||||
|
||||
#include "dhcpcd.h"
|
||||
|
||||
extern const char *bpf_name;
|
||||
size_t bpf_frame_header_len(const struct interface *);
|
||||
int bpf_frame_bcast(const struct interface *, const char *frame);
|
||||
int bpf_open(struct interface *, int (*)(struct interface *, int));
|
||||
int bpf_close(struct interface *, int);
|
||||
int bpf_attach(int, void *, unsigned int);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -56,54 +57,6 @@
|
|||
/* Most route(4) messages are less than 256 bytes. */
|
||||
#define IOVEC_BUFSIZ 256
|
||||
|
||||
ssize_t
|
||||
setvar(char **e, const char *prefix, const char *var, const char *value)
|
||||
{
|
||||
size_t len = strlen(var) + strlen(value) + 3;
|
||||
|
||||
if (prefix)
|
||||
len += strlen(prefix) + 1;
|
||||
if ((*e = malloc(len)) == NULL) {
|
||||
logerr(__func__);
|
||||
return -1;
|
||||
}
|
||||
if (prefix)
|
||||
snprintf(*e, len, "%s_%s=%s", prefix, var, value);
|
||||
else
|
||||
snprintf(*e, len, "%s=%s", var, value);
|
||||
return (ssize_t)len;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
setvard(char **e, const char *prefix, const char *var, size_t value)
|
||||
{
|
||||
|
||||
char buffer[32];
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "%zu", value);
|
||||
return setvar(e, prefix, var, buffer);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
addvar(char ***e, const char *prefix, const char *var, const char *value)
|
||||
{
|
||||
ssize_t len;
|
||||
|
||||
len = setvar(*e, prefix, var, value);
|
||||
if (len != -1)
|
||||
(*e)++;
|
||||
return (ssize_t)len;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
addvard(char ***e, const char *prefix, const char *var, size_t value)
|
||||
{
|
||||
char buffer[32];
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "%zu", value);
|
||||
return addvar(e, prefix, var, buffer);
|
||||
}
|
||||
|
||||
const char *
|
||||
hwaddr_ntoa(const void *hwaddr, size_t hwlen, char *buf, size_t buflen)
|
||||
{
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -30,12 +31,9 @@
|
|||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "defs.h"
|
||||
#include "dhcpcd.h"
|
||||
|
||||
#ifndef HOSTNAME_MAX_LEN
|
||||
#define HOSTNAME_MAX_LEN 250 /* 255 - 3 (FQDN) - 2 (DNS enc) */
|
||||
#endif
|
||||
|
@ -130,6 +128,29 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
/* Needed for rbtree(3) compat */
|
||||
#ifndef __RCSID
|
||||
#define __RCSID(a)
|
||||
#endif
|
||||
#ifndef __predict_false
|
||||
# if __GNUC__ > 2
|
||||
# define __predict_true(exp) __builtin_expect((exp) != 0, 1)
|
||||
# define __predict_false(exp) __builtin_expect((exp) != 0, 0)
|
||||
#else
|
||||
# define __predict_true(exp) (exp)
|
||||
# define __predict_false(exp) (exp)
|
||||
# endif
|
||||
#endif
|
||||
#ifndef __BEGIN_DECLS
|
||||
# if defined(__cplusplus)
|
||||
# define __BEGIN_DECLS extern "C" {
|
||||
# define __END_DECLS };
|
||||
# else /* __BEGIN_DECLS */
|
||||
# define __BEGIN_DECLS
|
||||
# define __END_DECLS
|
||||
# endif /* __BEGIN_DECLS */
|
||||
#endif /* __BEGIN_DECLS */
|
||||
|
||||
#ifndef __fallthrough
|
||||
# if __GNUC__ >= 7
|
||||
# define __fallthrough __attribute__((fallthrough))
|
||||
|
@ -173,11 +194,6 @@ void get_line_free(void);
|
|||
extern int clock_monotonic;
|
||||
int get_monotonic(struct timespec *);
|
||||
|
||||
ssize_t setvar(char **, const char *, const char *, const char *);
|
||||
ssize_t setvard(char **, const char *, const char *, size_t);
|
||||
ssize_t addvar(char ***, const char *, const char *, const char *);
|
||||
ssize_t addvard(char ***, const char *, const char *, size_t);
|
||||
|
||||
const char *hwaddr_ntoa(const void *, size_t, char *, size_t);
|
||||
size_t hwaddr_aton(uint8_t *, const char *);
|
||||
size_t read_hwaddr_aton(uint8_t **, const char *);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -28,7 +29,7 @@
|
|||
#define CONFIG_H
|
||||
|
||||
#define PACKAGE "dhcpcd"
|
||||
#define VERSION "7.2.3"
|
||||
#define VERSION "8.0.0"
|
||||
|
||||
#ifndef CONFIG
|
||||
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -36,8 +37,6 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <arpa/nameser.h> /* after normal includes for sunos */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "common.h"
|
||||
|
@ -46,13 +45,7 @@
|
|||
#include "if.h"
|
||||
#include "ipv6.h"
|
||||
#include "logerr.h"
|
||||
|
||||
/* Support very old arpa/nameser.h as found in OpenBSD */
|
||||
#ifndef NS_MAXDNAME
|
||||
#define NS_MAXCDNAME MAXCDNAME
|
||||
#define NS_MAXDNAME MAXDNAME
|
||||
#define NS_MAXLABEL MAXLABEL
|
||||
#endif
|
||||
#include "script.h"
|
||||
|
||||
const char *
|
||||
dhcp_get_hostname(char *buf, size_t buf_len, const struct if_options *ifo)
|
||||
|
@ -624,41 +617,9 @@ dhcp_optlen(const struct dhcp_opt *opt, size_t dl)
|
|||
return (ssize_t)sz;
|
||||
}
|
||||
|
||||
/* It's possible for DHCPv4 to contain an IPv6 address */
|
||||
static ssize_t
|
||||
ipv6_printaddr(char *s, size_t sl, const uint8_t *d, const char *ifname)
|
||||
{
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
const char *p;
|
||||
size_t l;
|
||||
|
||||
p = inet_ntop(AF_INET6, d, buf, sizeof(buf));
|
||||
if (p == NULL)
|
||||
return -1;
|
||||
|
||||
l = strlen(p);
|
||||
if (d[0] == 0xfe && (d[1] & 0xc0) == 0x80)
|
||||
l += 1 + strlen(ifname);
|
||||
|
||||
if (s == NULL)
|
||||
return (ssize_t)l;
|
||||
|
||||
if (sl < l) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
s += strlcpy(s, p, sl);
|
||||
if (d[0] == 0xfe && (d[1] & 0xc0) == 0x80) {
|
||||
*s++ = '%';
|
||||
s += strlcpy(s, ifname, sl);
|
||||
}
|
||||
*s = '\0';
|
||||
return (ssize_t)l;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
print_option(char *s, size_t len, const struct dhcp_opt *opt,
|
||||
print_option(FILE *fp, const char *prefix, const struct dhcp_opt *opt,
|
||||
int vname,
|
||||
const uint8_t *data, size_t dl, const char *ifname)
|
||||
{
|
||||
const uint8_t *e, *t;
|
||||
|
@ -667,52 +628,58 @@ print_option(char *s, size_t len, const struct dhcp_opt *opt,
|
|||
uint32_t u32;
|
||||
int32_t s32;
|
||||
struct in_addr addr;
|
||||
ssize_t bytes = 0, sl;
|
||||
ssize_t sl;
|
||||
size_t l;
|
||||
#ifdef INET
|
||||
char *tmp;
|
||||
#endif
|
||||
|
||||
/* Ensure a valid length */
|
||||
dl = (size_t)dhcp_optlen(opt, dl);
|
||||
if ((ssize_t)dl == -1)
|
||||
return 0;
|
||||
|
||||
if (fprintf(fp, "%s", prefix) == -1)
|
||||
return -1;
|
||||
if (vname) {
|
||||
if (fprintf(fp, "_%s", opt->var) == -1)
|
||||
return -1;
|
||||
}
|
||||
if (fputc('=', fp) == EOF)
|
||||
return -1;
|
||||
if (dl == 0)
|
||||
return 1;
|
||||
|
||||
if (opt->type & OT_RFC1035) {
|
||||
sl = decode_rfc1035(s, len, data, dl);
|
||||
char domain[NS_MAXDNAME];
|
||||
|
||||
sl = decode_rfc1035(domain, sizeof(domain), data, dl);
|
||||
if (sl == 0 || sl == -1)
|
||||
return sl;
|
||||
if (s != NULL) {
|
||||
if (valid_domainname(s, opt->type) == -1)
|
||||
return -1;
|
||||
}
|
||||
return sl;
|
||||
if (valid_domainname(domain, opt->type) == -1)
|
||||
return -1;
|
||||
return efprintf(fp, "%s", domain);
|
||||
}
|
||||
|
||||
#ifdef INET
|
||||
if (opt->type & OT_RFC3361) {
|
||||
if ((tmp = decode_rfc3361(data, dl)) == NULL)
|
||||
return -1;
|
||||
l = strlen(tmp);
|
||||
sl = print_string(s, len, opt->type, (uint8_t *)tmp, l);
|
||||
free(tmp);
|
||||
return sl;
|
||||
}
|
||||
if (opt->type & OT_RFC3361)
|
||||
return print_rfc3361(fp, data, dl);
|
||||
|
||||
if (opt->type & OT_RFC3442)
|
||||
return decode_rfc3442(s, len, data, dl);
|
||||
return print_rfc3442(fp, data, dl);
|
||||
#endif
|
||||
|
||||
if (opt->type & OT_STRING)
|
||||
return print_string(s, len, opt->type, data, dl);
|
||||
if (opt->type & OT_STRING) {
|
||||
char buf[1024];
|
||||
|
||||
if (opt->type & OT_FLAG) {
|
||||
if (s) {
|
||||
*s++ = '1';
|
||||
*s = '\0';
|
||||
}
|
||||
return 1;
|
||||
if (print_string(buf, sizeof(buf), opt->type, data, dl) == -1)
|
||||
return -1;
|
||||
return efprintf(fp, "%s", buf);
|
||||
}
|
||||
|
||||
if (opt->type & OT_FLAG)
|
||||
return efprintf(fp, "1");
|
||||
|
||||
if (opt->type & OT_BITFLAG) {
|
||||
/* bitflags are a string, MSB first, such as ABCDEFGH
|
||||
* where A is 10000000, B is 01000000, etc. */
|
||||
bytes = 0;
|
||||
for (l = 0, sl = sizeof(opt->bitflags) - 1;
|
||||
l < sizeof(opt->bitflags);
|
||||
l++, sl--)
|
||||
|
@ -722,109 +689,80 @@ print_option(char *s, size_t len, const struct dhcp_opt *opt,
|
|||
opt->bitflags[l] != '0' &&
|
||||
*data & (1 << sl))
|
||||
{
|
||||
if (s)
|
||||
*s++ = opt->bitflags[l];
|
||||
bytes++;
|
||||
if (fputc(opt->bitflags[l], fp) == EOF)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (s)
|
||||
*s = '\0';
|
||||
return bytes;
|
||||
}
|
||||
|
||||
if (!s) {
|
||||
if (opt->type & OT_UINT8)
|
||||
l = 3;
|
||||
else if (opt->type & OT_INT8)
|
||||
l = 4;
|
||||
else if (opt->type & OT_UINT16) {
|
||||
l = 5;
|
||||
dl /= 2;
|
||||
} else if (opt->type & OT_INT16) {
|
||||
l = 6;
|
||||
dl /= 2;
|
||||
} else if (opt->type & OT_UINT32) {
|
||||
l = 10;
|
||||
dl /= 4;
|
||||
} else if (opt->type & OT_INT32) {
|
||||
l = 11;
|
||||
dl /= 4;
|
||||
} else if (opt->type & OT_ADDRIPV4) {
|
||||
l = 16;
|
||||
dl /= 4;
|
||||
} else if (opt->type & OT_ADDRIPV6) {
|
||||
e = data + dl;
|
||||
l = 0;
|
||||
while (data < e) {
|
||||
if (l)
|
||||
l++; /* space */
|
||||
sl = ipv6_printaddr(NULL, 0, data, ifname);
|
||||
if (sl == -1)
|
||||
return l == 0 ? -1 : (ssize_t)l;
|
||||
l += (size_t)sl;
|
||||
data += 16;
|
||||
}
|
||||
return (ssize_t)l;
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
if (fputc('\0', fp) == EOF)
|
||||
return -1;
|
||||
}
|
||||
return (ssize_t)(l * dl);
|
||||
return 1;
|
||||
}
|
||||
|
||||
t = data;
|
||||
e = data + dl;
|
||||
while (data < e) {
|
||||
if (data != t) {
|
||||
*s++ = ' ';
|
||||
bytes++;
|
||||
len--;
|
||||
if (fputc(' ', fp) == EOF)
|
||||
return -1;
|
||||
}
|
||||
if (opt->type & OT_UINT8) {
|
||||
sl = snprintf(s, len, "%u", *data);
|
||||
if (fprintf(fp, "%u", *data) == -1)
|
||||
return -1;
|
||||
data++;
|
||||
} else if (opt->type & OT_INT8) {
|
||||
sl = snprintf(s, len, "%d", *data);
|
||||
if (fprintf(fp, "%d", *data) == -1)
|
||||
return -1;
|
||||
data++;
|
||||
} else if (opt->type & OT_UINT16) {
|
||||
memcpy(&u16, data, sizeof(u16));
|
||||
u16 = ntohs(u16);
|
||||
sl = snprintf(s, len, "%u", u16);
|
||||
if (fprintf(fp, "%u", u16) == -1)
|
||||
return -1;
|
||||
data += sizeof(u16);
|
||||
} else if (opt->type & OT_INT16) {
|
||||
memcpy(&u16, data, sizeof(u16));
|
||||
s16 = (int16_t)ntohs(u16);
|
||||
sl = snprintf(s, len, "%d", s16);
|
||||
if (fprintf(fp, "%d", s16) == -1)
|
||||
return -1;
|
||||
data += sizeof(u16);
|
||||
} else if (opt->type & OT_UINT32) {
|
||||
memcpy(&u32, data, sizeof(u32));
|
||||
u32 = ntohl(u32);
|
||||
sl = snprintf(s, len, "%u", u32);
|
||||
if (fprintf(fp, "%u", u32) == -1)
|
||||
return -1;
|
||||
data += sizeof(u32);
|
||||
} else if (opt->type & OT_INT32) {
|
||||
memcpy(&u32, data, sizeof(u32));
|
||||
s32 = (int32_t)ntohl(u32);
|
||||
sl = snprintf(s, len, "%d", s32);
|
||||
if (fprintf(fp, "%d", s32) == -1)
|
||||
return -1;
|
||||
data += sizeof(u32);
|
||||
} else if (opt->type & OT_ADDRIPV4) {
|
||||
memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
|
||||
sl = snprintf(s, len, "%s", inet_ntoa(addr));
|
||||
if (fprintf(fp, "%s", inet_ntoa(addr)) == -1)
|
||||
return -1;
|
||||
data += sizeof(addr.s_addr);
|
||||
} else if (opt->type & OT_ADDRIPV6) {
|
||||
sl = ipv6_printaddr(s, len, data, ifname);
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
|
||||
if (inet_ntop(AF_INET6, data, buf, sizeof(buf)) == NULL)
|
||||
return -1;
|
||||
if (fprintf(fp, "%s", buf) == -1)
|
||||
return -1;
|
||||
if (data[0] == 0xfe && (data[1] & 0xc0) == 0x80) {
|
||||
if (fprintf(fp,"%%%s", ifname) == -1)
|
||||
return -1;
|
||||
}
|
||||
data += 16;
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (sl == -1)
|
||||
return bytes == 0 ? -1 : bytes;
|
||||
len -= (size_t)sl;
|
||||
bytes += sl;
|
||||
s += sl;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
if (fputc('\0', fp) == EOF)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -859,61 +797,15 @@ dhcp_set_leasefile(char *leasefile, size_t len, int family,
|
|||
ifp->name, ssid);
|
||||
}
|
||||
|
||||
static size_t
|
||||
dhcp_envoption1(char **env, const char *prefix,
|
||||
const struct dhcp_opt *opt, int vname, const uint8_t *od, size_t ol,
|
||||
const char *ifname)
|
||||
{
|
||||
ssize_t len;
|
||||
size_t e;
|
||||
char *v, *val;
|
||||
int r;
|
||||
|
||||
/* Ensure a valid length */
|
||||
ol = (size_t)dhcp_optlen(opt, ol);
|
||||
if ((ssize_t)ol == -1)
|
||||
return 0;
|
||||
|
||||
len = print_option(NULL, 0, opt, od, ol, ifname);
|
||||
if (len < 0)
|
||||
return 0;
|
||||
if (vname)
|
||||
e = strlen(opt->var) + 1;
|
||||
else
|
||||
e = 0;
|
||||
if (prefix)
|
||||
e += strlen(prefix);
|
||||
e += (size_t)len + 2;
|
||||
if (env == NULL)
|
||||
return e;
|
||||
v = val = *env = malloc(e);
|
||||
if (v == NULL)
|
||||
return 0;
|
||||
if (vname)
|
||||
r = snprintf(val, e, "%s_%s=", prefix, opt->var);
|
||||
else
|
||||
r = snprintf(val, e, "%s=", prefix);
|
||||
if (r != -1 && len != 0) {
|
||||
v += r;
|
||||
if (print_option(v, (size_t)len + 1, opt, od, ol, ifname) == -1)
|
||||
r = -1;
|
||||
}
|
||||
if (r == -1) {
|
||||
free(val);
|
||||
return 0;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
size_t
|
||||
dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
|
||||
void
|
||||
dhcp_envoption(struct dhcpcd_ctx *ctx, FILE *fp, const char *prefix,
|
||||
const char *ifname, struct dhcp_opt *opt,
|
||||
const uint8_t *(*dgetopt)(struct dhcpcd_ctx *,
|
||||
size_t *, unsigned int *, size_t *,
|
||||
const uint8_t *, size_t, struct dhcp_opt **),
|
||||
const uint8_t *od, size_t ol)
|
||||
{
|
||||
size_t e, i, n, eos, eol;
|
||||
size_t i, eos, eol;
|
||||
ssize_t eo;
|
||||
unsigned int eoc;
|
||||
const uint8_t *eod;
|
||||
|
@ -923,52 +815,36 @@ dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
|
|||
|
||||
/* If no embedded or encapsulated options, it's easy */
|
||||
if (opt->embopts_len == 0 && opt->encopts_len == 0) {
|
||||
if (!(opt->type & OT_RESERVED)) {
|
||||
if (dhcp_envoption1(env == NULL ? NULL : &env[0],
|
||||
prefix, opt, 1, od, ol, ifname))
|
||||
return 1;
|
||||
else
|
||||
logerr("%s: %s %d",
|
||||
ifname, __func__, opt->option);
|
||||
}
|
||||
return 0;
|
||||
if (opt->type & OT_RESERVED)
|
||||
return;
|
||||
if (print_option(fp, prefix, opt, 1, od, ol, ifname) == -1)
|
||||
logerr("%s: %s %d", ifname, __func__, opt->option);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create a new prefix based on the option */
|
||||
if (env) {
|
||||
if (opt->type & OT_INDEX) {
|
||||
if (opt->index > 999) {
|
||||
errno = ENOBUFS;
|
||||
logerr(__func__);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
e = strlen(prefix) + strlen(opt->var) + 2 +
|
||||
(opt->type & OT_INDEX ? 3 : 0);
|
||||
pfx = malloc(e);
|
||||
if (pfx == NULL) {
|
||||
logerr(__func__);
|
||||
return 0;
|
||||
}
|
||||
if (opt->type & OT_INDEX)
|
||||
snprintf(pfx, e, "%s_%s%d", prefix,
|
||||
opt->var, ++opt->index);
|
||||
else
|
||||
snprintf(pfx, e, "%s_%s", prefix, opt->var);
|
||||
} else
|
||||
pfx = NULL;
|
||||
if (opt->type & OT_INDEX) {
|
||||
if (asprintf(&pfx, "%s_%s%d",
|
||||
prefix, opt->var, ++opt->index) == -1)
|
||||
pfx = NULL;
|
||||
} else {
|
||||
if (asprintf(&pfx, "%s_%s", prefix, opt->var) == -1)
|
||||
pfx = NULL;
|
||||
}
|
||||
if (pfx == NULL) {
|
||||
logerr(__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Embedded options are always processed first as that
|
||||
* is a fixed layout */
|
||||
n = 0;
|
||||
for (i = 0, eopt = opt->embopts; i < opt->embopts_len; i++, eopt++) {
|
||||
eo = dhcp_optlen(eopt, ol);
|
||||
if (eo == -1) {
|
||||
if (env == NULL)
|
||||
logerrx("%s: %s %d.%d/%zu: "
|
||||
"malformed embedded option",
|
||||
ifname, __func__, opt->option,
|
||||
eopt->option, i);
|
||||
logerrx("%s: %s %d.%d/%zu: "
|
||||
"malformed embedded option",
|
||||
ifname, __func__, opt->option,
|
||||
eopt->option, i);
|
||||
goto out;
|
||||
}
|
||||
if (eo == 0) {
|
||||
|
@ -977,9 +853,9 @@ dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
|
|||
* This may not be an error as some options like
|
||||
* DHCP FQDN in RFC4702 have a string as the last
|
||||
* option which is optional. */
|
||||
if (env == NULL &&
|
||||
(ol != 0 || !(eopt->type & OT_OPTIONAL)))
|
||||
logerrx("%s: %s %d.%d/%zu: missing embedded option",
|
||||
if (ol != 0 || !(eopt->type & OT_OPTIONAL))
|
||||
logerrx("%s: %s %d.%d/%zu: "
|
||||
"missing embedded option",
|
||||
ifname, __func__, opt->option,
|
||||
eopt->option, i);
|
||||
goto out;
|
||||
|
@ -989,10 +865,8 @@ dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
|
|||
* This avoids new_fqdn_fqdn which would be silly. */
|
||||
if (!(eopt->type & OT_RESERVED)) {
|
||||
ov = strcmp(opt->var, eopt->var);
|
||||
if (dhcp_envoption1(env == NULL ? NULL : &env[n],
|
||||
pfx, eopt, ov, od, (size_t)eo, ifname))
|
||||
n++;
|
||||
else if (env == NULL)
|
||||
if (print_option(fp, pfx, eopt, ov, od, (size_t)eo,
|
||||
ifname) == -1)
|
||||
logerr("%s: %s %d.%d/%zu",
|
||||
ifname, __func__,
|
||||
opt->option, eopt->option, i);
|
||||
|
@ -1023,19 +897,16 @@ dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
|
|||
i < opt->encopts_len;
|
||||
i++, eopt++)
|
||||
{
|
||||
if (eopt->option == eoc) {
|
||||
if (eopt->type & OT_OPTION) {
|
||||
if (oopt == NULL)
|
||||
/* Report error? */
|
||||
continue;
|
||||
}
|
||||
n += dhcp_envoption(ctx,
|
||||
env == NULL ? NULL : &env[n], pfx,
|
||||
ifname,
|
||||
eopt->type & OT_OPTION ? oopt:eopt,
|
||||
dgetopt, eod, eol);
|
||||
break;
|
||||
if (eopt->option != eoc)
|
||||
continue;
|
||||
if (eopt->type & OT_OPTION) {
|
||||
if (oopt == NULL)
|
||||
/* Report error? */
|
||||
continue;
|
||||
}
|
||||
dhcp_envoption(ctx, fp, pfx, ifname,
|
||||
eopt->type & OT_OPTION ? oopt:eopt,
|
||||
dgetopt, eod, eol);
|
||||
}
|
||||
od += eos + eol;
|
||||
ol -= eos + eol;
|
||||
|
@ -1043,11 +914,7 @@ dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
|
|||
}
|
||||
|
||||
out:
|
||||
if (env)
|
||||
free(pfx);
|
||||
|
||||
/* Return number of options found */
|
||||
return n;
|
||||
free(pfx);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1070,7 +937,7 @@ dhcp_read_lease_fd(int fd, void **lease)
|
|||
size_t sz;
|
||||
void *buf;
|
||||
ssize_t len;
|
||||
|
||||
|
||||
if (fstat(fd, &st) != 0)
|
||||
goto out;
|
||||
if (!S_ISREG(st.st_mode)) {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -33,9 +34,18 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <arpa/nameser.h> /* after normal includes for sunos */
|
||||
|
||||
#include "common.h"
|
||||
#include "dhcpcd.h"
|
||||
|
||||
/* Support very old arpa/nameser.h as found in OpenBSD */
|
||||
#ifndef NS_MAXDNAME
|
||||
#define NS_MAXCDNAME MAXCDNAME
|
||||
#define NS_MAXDNAME MAXDNAME
|
||||
#define NS_MAXLABEL MAXLABEL
|
||||
#endif
|
||||
|
||||
/* Max MTU - defines dhcp option length */
|
||||
#define IP_UDP_SIZE 28
|
||||
#define MTU_MAX 1500 - IP_UDP_SIZE
|
||||
|
@ -111,8 +121,8 @@ ssize_t decode_rfc1035(char *, size_t, const uint8_t *, size_t);
|
|||
ssize_t print_string(char *, size_t, int, const uint8_t *, size_t);
|
||||
int dhcp_set_leasefile(char *, size_t, int, const struct interface *);
|
||||
|
||||
size_t dhcp_envoption(struct dhcpcd_ctx *,
|
||||
char **, const char *, const char *, struct dhcp_opt *,
|
||||
void dhcp_envoption(struct dhcpcd_ctx *,
|
||||
FILE *, const char *, const char *, struct dhcp_opt *,
|
||||
const uint8_t *(*dgetopt)(struct dhcpcd_ctx *,
|
||||
size_t *, unsigned int *, size_t *,
|
||||
const uint8_t *, size_t, struct dhcp_opt **),
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -47,6 +48,7 @@
|
|||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
@ -124,8 +126,9 @@ static const char * const dhcp_params[] = {
|
|||
};
|
||||
|
||||
static int dhcp_openbpf(struct interface *);
|
||||
static void dhcp_start1(void *);
|
||||
#ifdef ARP
|
||||
static void dhcp_arp_conflicted(struct arp_state *, const struct arp_msg *);
|
||||
static void dhcp_arp_found(struct arp_state *, const struct arp_msg *);
|
||||
#endif
|
||||
static void dhcp_handledhcp(struct interface *, struct bootp *, size_t,
|
||||
const struct in_addr *);
|
||||
|
@ -339,23 +342,25 @@ get_option_uint8(struct dhcpcd_ctx *ctx,
|
|||
}
|
||||
|
||||
ssize_t
|
||||
decode_rfc3442(char *out, size_t len, const uint8_t *p, size_t pl)
|
||||
print_rfc3442(FILE *fp, const uint8_t *data, size_t data_len)
|
||||
{
|
||||
const uint8_t *e;
|
||||
size_t bytes = 0, ocets;
|
||||
int b;
|
||||
const uint8_t *p = data, *e;
|
||||
size_t ocets;
|
||||
uint8_t cidr;
|
||||
struct in_addr addr;
|
||||
char *o = out;
|
||||
|
||||
/* Minimum is 5 -first is CIDR and a router length of 4 */
|
||||
if (pl < 5) {
|
||||
if (data_len < 5) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
e = p + pl;
|
||||
e = p + data_len;
|
||||
while (p < e) {
|
||||
if (p != data) {
|
||||
if (fputc(' ', fp) == EOF)
|
||||
return -1;
|
||||
}
|
||||
cidr = *p++;
|
||||
if (cidr > 32) {
|
||||
errno = EINVAL;
|
||||
|
@ -366,45 +371,29 @@ decode_rfc3442(char *out, size_t len, const uint8_t *p, size_t pl)
|
|||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
if (!out) {
|
||||
p += 4 + ocets;
|
||||
bytes += ((4 * 4) * 2) + 4;
|
||||
continue;
|
||||
}
|
||||
if ((((4 * 4) * 2) + 4) > len) {
|
||||
errno = ENOBUFS;
|
||||
return -1;
|
||||
}
|
||||
if (o != out) {
|
||||
*o++ = ' ';
|
||||
len--;
|
||||
}
|
||||
/* If we have ocets then we have a destination and netmask */
|
||||
addr.s_addr = 0;
|
||||
if (ocets > 0) {
|
||||
addr.s_addr = 0;
|
||||
memcpy(&addr.s_addr, p, ocets);
|
||||
b = snprintf(o, len, "%s/%d", inet_ntoa(addr), cidr);
|
||||
p += ocets;
|
||||
} else
|
||||
b = snprintf(o, len, "0.0.0.0/0");
|
||||
o += b;
|
||||
len -= (size_t)b;
|
||||
}
|
||||
if (fprintf(fp, "%s/%d", inet_ntoa(addr), cidr) == -1)
|
||||
return -1;
|
||||
|
||||
/* Finally, snag the router */
|
||||
memcpy(&addr.s_addr, p, 4);
|
||||
p += 4;
|
||||
b = snprintf(o, len, " %s", inet_ntoa(addr));
|
||||
o += b;
|
||||
len -= (size_t)b;
|
||||
if (fprintf(fp, " %s", inet_ntoa(addr)) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (out)
|
||||
return o - out;
|
||||
return (ssize_t)bytes;
|
||||
if (fputc('\0', fp) == EOF)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
decode_rfc3442_rt(struct rt_head *routes, struct interface *ifp,
|
||||
decode_rfc3442_rt(rb_tree_t *routes, struct interface *ifp,
|
||||
const uint8_t *data, size_t dl, const struct bootp *bootp)
|
||||
{
|
||||
const uint8_t *p = data;
|
||||
|
@ -467,22 +456,18 @@ decode_rfc3442_rt(struct rt_head *routes, struct interface *ifp,
|
|||
sa_in_init(&rt->rt_dest, &dest);
|
||||
sa_in_init(&rt->rt_netmask, &netmask);
|
||||
sa_in_init(&rt->rt_gateway, &gateway);
|
||||
|
||||
TAILQ_INSERT_TAIL(routes, rt, rt_next);
|
||||
n++;
|
||||
if (rt_proto_add(routes, rt))
|
||||
n = 1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
char *
|
||||
decode_rfc3361(const uint8_t *data, size_t dl)
|
||||
ssize_t
|
||||
print_rfc3361(FILE *fp, const uint8_t *data, size_t dl)
|
||||
{
|
||||
uint8_t enc;
|
||||
size_t l;
|
||||
ssize_t r;
|
||||
char *sip = NULL;
|
||||
char sip[NS_MAXDNAME];
|
||||
struct in_addr addr;
|
||||
char *p;
|
||||
|
||||
if (dl < 2) {
|
||||
errno = EINVAL;
|
||||
|
@ -493,13 +478,10 @@ decode_rfc3361(const uint8_t *data, size_t dl)
|
|||
dl--;
|
||||
switch (enc) {
|
||||
case 0:
|
||||
if ((r = decode_rfc1035(NULL, 0, data, dl)) > 0) {
|
||||
l = (size_t)r + 1;
|
||||
sip = malloc(l);
|
||||
if (sip == NULL)
|
||||
return 0;
|
||||
decode_rfc1035(sip, l, data, dl);
|
||||
}
|
||||
if (decode_rfc1035(sip, sizeof(sip), data, dl) == -1)
|
||||
return -1;
|
||||
if (efprintf(fp, "%s", sip) == -1)
|
||||
return -1;
|
||||
break;
|
||||
case 1:
|
||||
if (dl == 0 || dl % 4 != 0) {
|
||||
|
@ -507,25 +489,27 @@ decode_rfc3361(const uint8_t *data, size_t dl)
|
|||
break;
|
||||
}
|
||||
addr.s_addr = INADDR_BROADCAST;
|
||||
l = ((dl / sizeof(addr.s_addr)) * ((4 * 4) + 1)) + 1;
|
||||
sip = p = malloc(l);
|
||||
if (sip == NULL)
|
||||
return 0;
|
||||
while (dl != 0) {
|
||||
for (;
|
||||
dl != 0;
|
||||
data += sizeof(addr.s_addr), dl -= sizeof(addr.s_addr))
|
||||
{
|
||||
memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
|
||||
data += sizeof(addr.s_addr);
|
||||
p += snprintf(p, l - (size_t)(p - sip),
|
||||
"%s ", inet_ntoa(addr));
|
||||
dl -= sizeof(addr.s_addr);
|
||||
if (fprintf(fp, "%s", inet_ntoa(addr)) == -1)
|
||||
return -1;
|
||||
if (dl != 0) {
|
||||
if (fputc(' ', fp) == EOF)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
*--p = '\0';
|
||||
if (fputc('\0', fp) == EOF)
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sip;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char *
|
||||
|
@ -581,7 +565,7 @@ route_netmask(uint32_t ip_in)
|
|||
* If we have a CSR then we only use that.
|
||||
* Otherwise we add static routes and then routers. */
|
||||
static int
|
||||
get_option_routes(struct rt_head *routes, struct interface *ifp,
|
||||
get_option_routes(rb_tree_t *routes, struct interface *ifp,
|
||||
const struct bootp *bootp, size_t bootp_len)
|
||||
{
|
||||
struct if_options *ifo = ifp->options;
|
||||
|
@ -656,9 +640,8 @@ get_option_routes(struct rt_head *routes, struct interface *ifp,
|
|||
sa_in_init(&rt->rt_dest, &dest);
|
||||
sa_in_init(&rt->rt_netmask, &netmask);
|
||||
sa_in_init(&rt->rt_gateway, &gateway);
|
||||
|
||||
TAILQ_INSERT_TAIL(routes, rt, rt_next);
|
||||
n++;
|
||||
if (rt_proto_add(routes, rt))
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -667,7 +650,7 @@ get_option_routes(struct rt_head *routes, struct interface *ifp,
|
|||
p = get_option(ifp->ctx, bootp, bootp_len, DHO_ROUTER, &len);
|
||||
else
|
||||
p = NULL;
|
||||
if (p) {
|
||||
if (p && len % 4 == 0) {
|
||||
e = p + len;
|
||||
dest.s_addr = INADDR_ANY;
|
||||
netmask.s_addr = INADDR_ANY;
|
||||
|
@ -679,8 +662,8 @@ get_option_routes(struct rt_head *routes, struct interface *ifp,
|
|||
sa_in_init(&rt->rt_dest, &dest);
|
||||
sa_in_init(&rt->rt_netmask, &netmask);
|
||||
sa_in_init(&rt->rt_gateway, &gateway);
|
||||
TAILQ_INSERT_TAIL(routes, rt, rt_next);
|
||||
n++;
|
||||
if (rt_proto_add(routes, rt))
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -707,7 +690,7 @@ dhcp_get_mtu(const struct interface *ifp)
|
|||
/* Grab our routers from the DHCP message and apply any MTU value
|
||||
* the message contains */
|
||||
int
|
||||
dhcp_get_routes(struct rt_head *routes, struct interface *ifp)
|
||||
dhcp_get_routes(rb_tree_t *routes, struct interface *ifp)
|
||||
{
|
||||
const struct dhcp_state *state;
|
||||
|
||||
|
@ -1299,9 +1282,8 @@ dhcp_getoption(struct dhcpcd_ctx *ctx,
|
|||
}
|
||||
|
||||
ssize_t
|
||||
dhcp_env(char **env, const char *prefix,
|
||||
const struct bootp *bootp, size_t bootp_len,
|
||||
const struct interface *ifp)
|
||||
dhcp_env(FILE *fenv, const char *prefix, const struct interface *ifp,
|
||||
const struct bootp *bootp, size_t bootp_len)
|
||||
{
|
||||
const struct if_options *ifo;
|
||||
const uint8_t *p;
|
||||
|
@ -1309,109 +1291,73 @@ dhcp_env(char **env, const char *prefix,
|
|||
struct in_addr net;
|
||||
struct in_addr brd;
|
||||
struct dhcp_opt *opt, *vo;
|
||||
size_t e, i, pl;
|
||||
char **ep;
|
||||
char cidr[4], safe[(BOOTP_FILE_LEN * 4) + 1];
|
||||
size_t i, pl;
|
||||
char safe[(BOOTP_FILE_LEN * 4) + 1];
|
||||
uint8_t overl = 0;
|
||||
uint32_t en;
|
||||
|
||||
e = 0;
|
||||
ifo = ifp->options;
|
||||
if (get_option_uint8(ifp->ctx, &overl, bootp, bootp_len,
|
||||
DHO_OPTSOVERLOADED) == -1)
|
||||
overl = 0;
|
||||
|
||||
if (env == NULL) {
|
||||
if (bootp->yiaddr || bootp->ciaddr)
|
||||
e += 5;
|
||||
if (*bootp->file && !(overl & 1))
|
||||
e++;
|
||||
if (*bootp->sname && !(overl & 2))
|
||||
e++;
|
||||
for (i = 0, opt = ifp->ctx->dhcp_opts;
|
||||
i < ifp->ctx->dhcp_opts_len;
|
||||
i++, opt++)
|
||||
{
|
||||
if (has_option_mask(ifo->nomask, opt->option))
|
||||
continue;
|
||||
if (dhcp_getoverride(ifo, opt->option))
|
||||
continue;
|
||||
p = get_option(ifp->ctx, bootp, bootp_len,
|
||||
opt->option, &pl);
|
||||
if (!p)
|
||||
continue;
|
||||
e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name,
|
||||
opt, dhcp_getoption, p, pl);
|
||||
}
|
||||
for (i = 0, opt = ifo->dhcp_override;
|
||||
i < ifo->dhcp_override_len;
|
||||
i++, opt++)
|
||||
{
|
||||
if (has_option_mask(ifo->nomask, opt->option))
|
||||
continue;
|
||||
p = get_option(ifp->ctx, bootp, bootp_len,
|
||||
opt->option, &pl);
|
||||
if (!p)
|
||||
continue;
|
||||
e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name,
|
||||
opt, dhcp_getoption, p, pl);
|
||||
}
|
||||
return (ssize_t)e;
|
||||
}
|
||||
|
||||
ep = env;
|
||||
if (bootp->yiaddr || bootp->ciaddr) {
|
||||
/* Set some useful variables that we derive from the DHCP
|
||||
* message but are not necessarily in the options */
|
||||
addr.s_addr = bootp->yiaddr ? bootp->yiaddr : bootp->ciaddr;
|
||||
addvar(&ep, prefix, "ip_address", inet_ntoa(addr));
|
||||
if (efprintf(fenv, "%s_ip_address=%s",
|
||||
prefix, inet_ntoa(addr)) == -1)
|
||||
return -1;
|
||||
if (get_option_addr(ifp->ctx, &net,
|
||||
bootp, bootp_len, DHO_SUBNETMASK) == -1)
|
||||
{
|
||||
bootp, bootp_len, DHO_SUBNETMASK) == -1) {
|
||||
net.s_addr = ipv4_getnetmask(addr.s_addr);
|
||||
addvar(&ep, prefix,
|
||||
"subnet_mask", inet_ntoa(net));
|
||||
if (efprintf(fenv, "%s_subnet_mask=%s",
|
||||
prefix, inet_ntoa(net)) == -1)
|
||||
return -1;
|
||||
}
|
||||
snprintf(cidr, sizeof(cidr), "%d", inet_ntocidr(net));
|
||||
addvar(&ep, prefix, "subnet_cidr", cidr);
|
||||
if (efprintf(fenv, "%s_subnet_cidr=%d",
|
||||
prefix, inet_ntocidr(net))== -1)
|
||||
return -1;
|
||||
if (get_option_addr(ifp->ctx, &brd,
|
||||
bootp, bootp_len, DHO_BROADCAST) == -1)
|
||||
{
|
||||
brd.s_addr = addr.s_addr | ~net.s_addr;
|
||||
addvar(&ep, prefix,
|
||||
"broadcast_address", inet_ntoa(brd));
|
||||
if (efprintf(fenv, "%s_broadcast_address=%s",
|
||||
prefix, inet_ntoa(brd)) == -1)
|
||||
return -1;
|
||||
}
|
||||
addr.s_addr = bootp->yiaddr & net.s_addr;
|
||||
addvar(&ep, prefix,
|
||||
"network_number", inet_ntoa(addr));
|
||||
if (efprintf(fenv, "%s_network_number=%s",
|
||||
prefix, inet_ntoa(addr)) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*bootp->file && !(overl & 1)) {
|
||||
print_string(safe, sizeof(safe), OT_STRING,
|
||||
bootp->file, sizeof(bootp->file));
|
||||
addvar(&ep, prefix, "filename", safe);
|
||||
if (efprintf(fenv, "%s_filename=%s", prefix, safe) == -1)
|
||||
return -1;
|
||||
}
|
||||
if (*bootp->sname && !(overl & 2)) {
|
||||
print_string(safe, sizeof(safe), OT_STRING | OT_DOMAIN,
|
||||
bootp->sname, sizeof(bootp->sname));
|
||||
addvar(&ep, prefix, "server_name", safe);
|
||||
if (efprintf(fenv, "%s_server_name=%s", prefix, safe) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Zero our indexes */
|
||||
if (env) {
|
||||
for (i = 0, opt = ifp->ctx->dhcp_opts;
|
||||
i < ifp->ctx->dhcp_opts_len;
|
||||
i++, opt++)
|
||||
dhcp_zero_index(opt);
|
||||
for (i = 0, opt = ifp->options->dhcp_override;
|
||||
i < ifp->options->dhcp_override_len;
|
||||
i++, opt++)
|
||||
dhcp_zero_index(opt);
|
||||
for (i = 0, opt = ifp->ctx->vivso;
|
||||
i < ifp->ctx->vivso_len;
|
||||
i++, opt++)
|
||||
dhcp_zero_index(opt);
|
||||
}
|
||||
for (i = 0, opt = ifp->ctx->dhcp_opts;
|
||||
i < ifp->ctx->dhcp_opts_len;
|
||||
i++, opt++)
|
||||
dhcp_zero_index(opt);
|
||||
for (i = 0, opt = ifp->options->dhcp_override;
|
||||
i < ifp->options->dhcp_override_len;
|
||||
i++, opt++)
|
||||
dhcp_zero_index(opt);
|
||||
for (i = 0, opt = ifp->ctx->vivso;
|
||||
i < ifp->ctx->vivso_len;
|
||||
i++, opt++)
|
||||
dhcp_zero_index(opt);
|
||||
|
||||
for (i = 0, opt = ifp->ctx->dhcp_opts;
|
||||
i < ifp->ctx->dhcp_opts_len;
|
||||
|
@ -1424,7 +1370,7 @@ dhcp_env(char **env, const char *prefix,
|
|||
p = get_option(ifp->ctx, bootp, bootp_len, opt->option, &pl);
|
||||
if (p == NULL)
|
||||
continue;
|
||||
ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name,
|
||||
dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name,
|
||||
opt, dhcp_getoption, p, pl);
|
||||
|
||||
if (opt->option != DHO_VIVSO || pl <= (int)sizeof(uint32_t))
|
||||
|
@ -1437,7 +1383,7 @@ dhcp_env(char **env, const char *prefix,
|
|||
/* Skip over en + total size */
|
||||
p += sizeof(en) + 1;
|
||||
pl -= sizeof(en) + 1;
|
||||
ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name,
|
||||
dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name,
|
||||
vo, dhcp_getoption, p, pl);
|
||||
}
|
||||
|
||||
|
@ -1450,11 +1396,11 @@ dhcp_env(char **env, const char *prefix,
|
|||
p = get_option(ifp->ctx, bootp, bootp_len, opt->option, &pl);
|
||||
if (p == NULL)
|
||||
continue;
|
||||
ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name,
|
||||
dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name,
|
||||
opt, dhcp_getoption, p, pl);
|
||||
}
|
||||
|
||||
return ep - env;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1497,7 +1443,7 @@ get_lease(struct interface *ifp,
|
|||
}
|
||||
if (get_option_uint32(ctx, &lease->leasetime,
|
||||
bootp, len, DHO_LEASETIME) != 0)
|
||||
lease->leasetime = ~0U; /* Default to infinite lease */
|
||||
lease->leasetime = DHCP_INFINITE_LIFETIME;
|
||||
if (get_option_uint32(ctx, &lease->renewaltime,
|
||||
bootp, len, DHO_RENEWALTIME) != 0)
|
||||
lease->renewaltime = 0;
|
||||
|
@ -1923,35 +1869,6 @@ dhcp_request(void *arg)
|
|||
send_request(ifp);
|
||||
}
|
||||
|
||||
static int
|
||||
dhcp_leaseextend(struct interface *ifp)
|
||||
{
|
||||
|
||||
#ifdef ARP
|
||||
if (ifp->options->options & DHCPCD_ARP) {
|
||||
const struct dhcp_state *state;
|
||||
struct arp_state *astate;
|
||||
|
||||
state = D_CSTATE(ifp);
|
||||
if ((astate = arp_new(ifp, &state->lease.addr)) == NULL)
|
||||
return -1;
|
||||
astate->conflicted_cb = dhcp_arp_conflicted;
|
||||
|
||||
#ifndef KERNEL_RFC5227
|
||||
if (arp_open(ifp) == -1)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
logwarnx("%s: extending lease until DaD failure or DHCP",
|
||||
ifp->name);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
logwarnx("%s: extending lease", ifp->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp_expire1(struct interface *ifp)
|
||||
{
|
||||
|
@ -1970,12 +1887,12 @@ dhcp_expire(void *arg)
|
|||
{
|
||||
struct interface *ifp = arg;
|
||||
|
||||
logerrx("%s: DHCP lease expired", ifp->name);
|
||||
if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND) {
|
||||
if (dhcp_leaseextend(ifp) == 0)
|
||||
return;
|
||||
logerr(__func__);
|
||||
logwarnx("%s: DHCP lease expired, extending lease", ifp->name);
|
||||
return;
|
||||
}
|
||||
|
||||
logerrx("%s: DHCP lease expired", ifp->name);
|
||||
dhcp_expire1(ifp);
|
||||
}
|
||||
|
||||
|
@ -2041,9 +1958,78 @@ dhcp_rebind(void *arg)
|
|||
send_rebind(ifp);
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp_finish_dad(struct interface *ifp, struct in_addr *ia)
|
||||
{
|
||||
struct dhcp_state *state = D_STATE(ifp);
|
||||
|
||||
if (state->state != DHS_PROBE)
|
||||
return;
|
||||
if (state->offer == NULL || state->offer->yiaddr != ia->s_addr)
|
||||
return;
|
||||
|
||||
logdebugx("%s: DAD completed for %s", ifp->name, inet_ntoa(*ia));
|
||||
if (!(ifp->options->options & DHCPCD_INFORM))
|
||||
dhcp_bind(ifp);
|
||||
#ifndef IN_IFF_DUPLICATED
|
||||
else {
|
||||
struct bootp *bootp;
|
||||
size_t len;
|
||||
|
||||
bootp = state->new;
|
||||
len = state->new_len;
|
||||
state->new = state->offer;
|
||||
state->new_len = state->offer_len;
|
||||
get_lease(ifp, &state->lease, state->new, state->new_len);
|
||||
ipv4_applyaddr(ifp);
|
||||
state->new = bootp;
|
||||
state->new_len = len;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If we forked, stop here. */
|
||||
if (ifp->ctx->options & DHCPCD_FORKED)
|
||||
return;
|
||||
|
||||
#ifdef IPV4LL
|
||||
/* Stop IPv4LL now we have a working DHCP address */
|
||||
ipv4ll_drop(ifp);
|
||||
#endif
|
||||
|
||||
if (ifp->options->options & DHCPCD_INFORM)
|
||||
dhcp_inform(ifp);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dhcp_addr_duplicated(struct interface *ifp, struct in_addr *ia)
|
||||
{
|
||||
struct dhcp_state *state = D_STATE(ifp);
|
||||
#ifdef IN_IFF_DUPLICATED
|
||||
struct ipv4_addr *iap;
|
||||
#endif
|
||||
|
||||
if ((state->offer == NULL || state->offer->yiaddr != ia->s_addr) &&
|
||||
!IN_ARE_ADDR_EQUAL(ia, &state->lease.addr))
|
||||
return;
|
||||
|
||||
/* RFC 2131 3.1.5, Client-server interaction */
|
||||
logerrx("%s: DAD detected %s", ifp->name, inet_ntoa(*ia));
|
||||
unlink(state->leasefile);
|
||||
if (!(ifp->options->options & DHCPCD_STATIC) && !state->lease.frominfo)
|
||||
dhcp_decline(ifp);
|
||||
#ifdef IN_IFF_DUPLICATED
|
||||
if ((iap = ipv4_iffindaddr(ifp, ia, NULL)) != NULL)
|
||||
ipv4_deladdr(iap, 0);
|
||||
#endif
|
||||
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
|
||||
eloop_timeout_add_sec(ifp->ctx->eloop,
|
||||
DHCP_RAND_MAX, dhcp_discover, ifp);
|
||||
}
|
||||
|
||||
#ifdef ARP
|
||||
static void
|
||||
dhcp_arp_probed(struct arp_state *astate)
|
||||
dhcp_arp_not_found(struct arp_state *astate)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct dhcp_state *state;
|
||||
|
@ -2069,56 +2055,21 @@ dhcp_arp_probed(struct arp_state *astate)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Already bound so DAD has worked */
|
||||
if (state->state == DHS_BOUND)
|
||||
return;
|
||||
|
||||
logdebugx("%s: DAD completed for %s",
|
||||
ifp->name, inet_ntoa(astate->addr));
|
||||
if (!(ifo->options & DHCPCD_INFORM))
|
||||
dhcp_bind(ifp);
|
||||
#ifndef IN_IFF_DUPLICATED
|
||||
else {
|
||||
struct bootp *bootp;
|
||||
size_t len;
|
||||
|
||||
bootp = state->new;
|
||||
len = state->new_len;
|
||||
state->new = state->offer;
|
||||
state->new_len = state->offer_len;
|
||||
get_lease(ifp, &state->lease, state->new, state->new_len);
|
||||
ipv4_applyaddr(astate->iface);
|
||||
state->new = bootp;
|
||||
state->new_len = len;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If we forked, stop here. */
|
||||
if (ifp->ctx->options & DHCPCD_FORKED)
|
||||
return;
|
||||
|
||||
#ifdef IPV4LL
|
||||
/* Stop IPv4LL now we have a working DHCP address */
|
||||
ipv4ll_drop(ifp);
|
||||
#endif
|
||||
|
||||
if (ifo->options & DHCPCD_INFORM)
|
||||
dhcp_inform(ifp);
|
||||
dhcp_finish_dad(ifp, &astate->addr);
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
|
||||
dhcp_arp_found(struct arp_state *astate, const struct arp_msg *amsg)
|
||||
{
|
||||
struct in_addr addr;
|
||||
#ifdef ARPING
|
||||
struct interface *ifp;
|
||||
struct dhcp_state *state;
|
||||
#ifdef ARPING
|
||||
struct if_options *ifo;
|
||||
#endif
|
||||
|
||||
ifp = astate->iface;
|
||||
state = D_STATE(ifp);
|
||||
|
||||
#ifdef ARPING
|
||||
ifo = ifp->options;
|
||||
if (state->arping_index != -1 &&
|
||||
state->arping_index < ifo->arping_len &&
|
||||
|
@ -2127,17 +2078,14 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
|
|||
{
|
||||
char buf[HWADDR_LEN * 3];
|
||||
|
||||
astate->failed.s_addr = ifo->arping[state->arping_index];
|
||||
arp_report_conflicted(astate, amsg);
|
||||
hwaddr_ntoa(amsg->sha, ifp->hwlen, buf, sizeof(buf));
|
||||
if (dhcpcd_selectprofile(ifp, buf) == -1 &&
|
||||
dhcpcd_selectprofile(ifp,
|
||||
inet_ntoa(astate->failed)) == -1)
|
||||
dhcpcd_selectprofile(ifp, inet_ntoa(amsg->sip)) == -1)
|
||||
{
|
||||
/* We didn't find a profile for this
|
||||
* address or hwaddr, so move to the next
|
||||
* arping profile */
|
||||
dhcp_arp_probed(astate);
|
||||
dhcp_arp_not_found(astate);
|
||||
return;
|
||||
}
|
||||
arp_free(astate);
|
||||
|
@ -2147,65 +2095,20 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* RFC 2131 3.1.5, Client-server interaction
|
||||
* NULL amsg means IN_IFF_DUPLICATED */
|
||||
if (amsg == NULL || (state->offer &&
|
||||
(amsg->sip.s_addr == state->offer->yiaddr ||
|
||||
(amsg->sip.s_addr == 0 &&
|
||||
amsg->tip.s_addr == state->offer->yiaddr))))
|
||||
{
|
||||
#ifdef IN_IFF_DUPLICATED
|
||||
struct ipv4_addr *ia;
|
||||
#endif
|
||||
|
||||
if (amsg)
|
||||
astate->failed.s_addr = state->offer->yiaddr;
|
||||
else
|
||||
astate->failed = astate->addr;
|
||||
arp_report_conflicted(astate, amsg);
|
||||
unlink(state->leasefile);
|
||||
#ifdef ARP
|
||||
if (!(ifp->options->options & DHCPCD_STATIC) &&
|
||||
!state->lease.frominfo)
|
||||
dhcp_decline(ifp);
|
||||
#endif
|
||||
#ifdef IN_IFF_DUPLICATED
|
||||
if ((ia = ipv4_iffindaddr(ifp, &astate->addr, NULL)) != NULL)
|
||||
ipv4_deladdr(ia, 1);
|
||||
#endif
|
||||
arp_free(astate);
|
||||
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
|
||||
eloop_timeout_add_sec(ifp->ctx->eloop,
|
||||
DHCP_RAND_MAX, dhcp_discover, ifp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Bound address */
|
||||
if (amsg && state->addr &&
|
||||
amsg->sip.s_addr == state->addr->addr.s_addr)
|
||||
{
|
||||
astate->failed = state->addr->addr;
|
||||
arp_report_conflicted(astate, amsg);
|
||||
if (state->state == DHS_BOUND) {
|
||||
/* For now, just report the duplicated address */
|
||||
} else {
|
||||
arp_free(astate);
|
||||
dhcp_expire1(ifp);
|
||||
}
|
||||
return;
|
||||
}
|
||||
addr = astate->addr;
|
||||
arp_free(astate);
|
||||
dhcp_addr_duplicated(ifp, &addr);
|
||||
}
|
||||
|
||||
#ifdef KERNEL_RFC5227
|
||||
static void
|
||||
dhcp_arp_announced(struct arp_state *state)
|
||||
{
|
||||
|
||||
// TODO: DHCP addresses handle ACD?
|
||||
//#ifdef KERNEL_RFC5227
|
||||
arp_free(state);
|
||||
//#endif
|
||||
}
|
||||
#endif
|
||||
#endif /* KERNEL_RFC5227 */
|
||||
#endif /* ARP */
|
||||
|
||||
void
|
||||
dhcp_bind(struct interface *ifp)
|
||||
|
@ -2232,17 +2135,17 @@ dhcp_bind(struct interface *ifp)
|
|||
loginfox("%s: using static address %s/%d",
|
||||
ifp->name, inet_ntoa(lease->addr),
|
||||
inet_ntocidr(lease->mask));
|
||||
lease->leasetime = ~0U;
|
||||
lease->leasetime = DHCP_INFINITE_LIFETIME;
|
||||
state->reason = "STATIC";
|
||||
} else if (ifo->options & DHCPCD_INFORM) {
|
||||
loginfox("%s: received approval for %s",
|
||||
ifp->name, inet_ntoa(lease->addr));
|
||||
lease->leasetime = ~0U;
|
||||
lease->leasetime = DHCP_INFINITE_LIFETIME;
|
||||
state->reason = "INFORM";
|
||||
} else {
|
||||
if (lease->frominfo)
|
||||
state->reason = "TIMEOUT";
|
||||
if (lease->leasetime == ~0U) {
|
||||
if (lease->leasetime == DHCP_INFINITE_LIFETIME) {
|
||||
lease->renewaltime =
|
||||
lease->rebindtime =
|
||||
lease->leasetime;
|
||||
|
@ -2305,7 +2208,7 @@ dhcp_bind(struct interface *ifp)
|
|||
else
|
||||
state->reason = "BOUND";
|
||||
}
|
||||
if (lease->leasetime == ~0U)
|
||||
if (lease->leasetime == DHCP_INFINITE_LIFETIME)
|
||||
lease->renewaltime = lease->rebindtime = lease->leasetime;
|
||||
else {
|
||||
eloop_timeout_add_sec(ctx->eloop,
|
||||
|
@ -2359,12 +2262,6 @@ dhcp_lastlease(void *arg)
|
|||
if (ifp->ctx->options & DHCPCD_FORKED)
|
||||
return;
|
||||
state->interval = 0;
|
||||
if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND &&
|
||||
dhcp_leaseextend(ifp) == -1)
|
||||
{
|
||||
logerr("%s: %s", ifp->name, __func__);
|
||||
dhcp_expire(ifp);
|
||||
}
|
||||
dhcp_discover(ifp);
|
||||
}
|
||||
|
||||
|
@ -2397,17 +2294,32 @@ dhcp_message_new(struct bootp **bootp,
|
|||
}
|
||||
|
||||
#ifdef ARP
|
||||
#ifndef KERNEL_RFC5227
|
||||
static void
|
||||
dhcp_arp_defend_failed(struct arp_state *astate)
|
||||
{
|
||||
|
||||
dhcp_drop(astate->iface, "EXPIRED");
|
||||
dhcp_start1(astate->iface);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct arp_state *
|
||||
dhcp_arp_new(struct interface *ifp, struct in_addr *addr)
|
||||
{
|
||||
struct arp_state *astate;
|
||||
|
||||
astate = arp_new(ifp, addr);
|
||||
if (astate == NULL)
|
||||
return NULL;
|
||||
|
||||
astate->probed_cb = dhcp_arp_probed;
|
||||
astate->conflicted_cb = dhcp_arp_conflicted;
|
||||
astate->found_cb = dhcp_arp_found;
|
||||
astate->not_found_cb = dhcp_arp_not_found;
|
||||
#ifdef KERNEL_RFC5227
|
||||
astate->announced_cb = dhcp_arp_announced;
|
||||
#else
|
||||
astate->defend_failed_cb = dhcp_arp_defend_failed;
|
||||
#endif
|
||||
return astate;
|
||||
}
|
||||
|
||||
|
@ -2417,7 +2329,6 @@ dhcp_arp_address(struct interface *ifp)
|
|||
struct dhcp_state *state;
|
||||
struct in_addr addr;
|
||||
struct ipv4_addr *ia;
|
||||
struct arp_state *astate;
|
||||
|
||||
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
|
||||
|
||||
|
@ -2427,10 +2338,6 @@ dhcp_arp_address(struct interface *ifp)
|
|||
/* If the interface already has the address configured
|
||||
* then we can't ARP for duplicate detection. */
|
||||
ia = ipv4_iffindaddr(ifp, &addr, NULL);
|
||||
astate = dhcp_arp_new(ifp, &addr);
|
||||
if (astate == NULL)
|
||||
return -1;
|
||||
|
||||
#ifdef IN_IFF_NOTUSEABLE
|
||||
if (ia == NULL || ia->addr_flags & IN_IFF_NOTUSEABLE) {
|
||||
state->state = DHS_PROBE;
|
||||
|
@ -2439,7 +2346,8 @@ dhcp_arp_address(struct interface *ifp)
|
|||
|
||||
get_lease(ifp, &l, state->offer, state->offer_len);
|
||||
/* Add the address now, let the kernel handle DAD. */
|
||||
ipv4_addaddr(ifp, &l.addr, &l.mask, &l.brd);
|
||||
ipv4_addaddr(ifp, &l.addr, &l.mask, &l.brd,
|
||||
l.leasetime, l.rebindtime);
|
||||
} else
|
||||
loginfox("%s: waiting for DAD on %s",
|
||||
ifp->name, inet_ntoa(addr));
|
||||
|
@ -2447,8 +2355,13 @@ dhcp_arp_address(struct interface *ifp)
|
|||
}
|
||||
#else
|
||||
if (ifp->options->options & DHCPCD_ARP && ia == NULL) {
|
||||
struct arp_state *astate;
|
||||
struct dhcp_lease l;
|
||||
|
||||
astate = dhcp_arp_new(ifp, &addr);
|
||||
if (astate == NULL)
|
||||
return -1;
|
||||
|
||||
state->state = DHS_PROBE;
|
||||
get_lease(ifp, &l, state->offer, state->offer_len);
|
||||
loginfox("%s: probing address %s/%d",
|
||||
|
@ -2705,9 +2618,14 @@ dhcp_drop(struct interface *ifp, const char *reason)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef ARP
|
||||
if (state->addr != NULL)
|
||||
arp_freeaddr(ifp, &state->addr->addr);
|
||||
#endif
|
||||
#ifdef ARPING
|
||||
state->arping_index = -1;
|
||||
#endif
|
||||
|
||||
if (ifp->options->options & DHCPCD_RELEASE &&
|
||||
!(ifp->options->options & DHCPCD_INFORM))
|
||||
{
|
||||
|
@ -3653,15 +3571,9 @@ dhcp_init(struct interface *ifp)
|
|||
const struct if_options *ifo;
|
||||
uint8_t len;
|
||||
char buf[(sizeof(ifo->clientid) - 1) * 3];
|
||||
int r;
|
||||
|
||||
r = dhcp_initstate(ifp);
|
||||
if (r == -1)
|
||||
if (dhcp_initstate(ifp) == -1)
|
||||
return -1;
|
||||
else if (r == 1) {
|
||||
/* Now is a good time to find IPv4 routes */
|
||||
if_initrt(ifp->ctx, AF_INET);
|
||||
}
|
||||
|
||||
state = D_STATE(ifp);
|
||||
state->state = DHS_INIT;
|
||||
|
@ -3771,7 +3683,7 @@ dhcp_start1(void *arg)
|
|||
|
||||
astate = dhcp_arp_new(ifp, NULL);
|
||||
if (astate)
|
||||
dhcp_arp_probed(astate);
|
||||
dhcp_arp_not_found(astate);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
@ -3848,7 +3760,7 @@ dhcp_start1(void *arg)
|
|||
state->offer = NULL;
|
||||
state->offer_len = 0;
|
||||
} else if (!(ifo->options & DHCPCD_LASTLEASE_EXTEND) &&
|
||||
state->lease.leasetime != ~0U &&
|
||||
state->lease.leasetime != DHCP_INFINITE_LIFETIME &&
|
||||
stat(state->leasefile, &st) == 0)
|
||||
{
|
||||
time_t now;
|
||||
|
@ -4023,8 +3935,10 @@ dhcp_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid)
|
|||
return;
|
||||
|
||||
#ifdef IN_IFF_NOTUSEABLE
|
||||
if (ia->addr_flags & IN_IFF_NOTUSEABLE)
|
||||
return;
|
||||
if (!(ia->addr_flags & IN_IFF_NOTUSEABLE))
|
||||
dhcp_finish_dad(ifp, &ia->addr);
|
||||
else if (ia->addr_flags & IN_IFF_DUPLICATED)
|
||||
dhcp_addr_duplicated(ifp, &ia->addr);
|
||||
#endif
|
||||
|
||||
ifo = ifp->options;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -182,6 +183,10 @@ struct dhcp_lease {
|
|||
uint32_t cookie;
|
||||
};
|
||||
|
||||
#ifndef DHCP_INFINITE_LIFETIME
|
||||
# define DHCP_INFINITE_LIFETIME (~0U)
|
||||
#endif
|
||||
|
||||
enum DHS {
|
||||
DHS_NONE,
|
||||
DHS_INIT,
|
||||
|
@ -245,15 +250,15 @@ struct dhcp_state {
|
|||
#include "dhcpcd.h"
|
||||
#include "if-options.h"
|
||||
|
||||
char *decode_rfc3361(const uint8_t *, size_t);
|
||||
ssize_t decode_rfc3442(char *, size_t, const uint8_t *p, size_t);
|
||||
ssize_t print_rfc3361(FILE *, const uint8_t *, size_t);
|
||||
ssize_t print_rfc3442(FILE *, const uint8_t *, size_t);
|
||||
|
||||
void dhcp_printoptions(const struct dhcpcd_ctx *,
|
||||
const struct dhcp_opt *, size_t);
|
||||
uint16_t dhcp_get_mtu(const struct interface *);
|
||||
int dhcp_get_routes(struct rt_head *, struct interface *);
|
||||
ssize_t dhcp_env(char **, const char *, const struct bootp *, size_t,
|
||||
const struct interface *);
|
||||
int dhcp_get_routes(rb_tree_t *, struct interface *);
|
||||
ssize_t dhcp_env(FILE *, const char *, const struct interface *,
|
||||
const struct bootp *, size_t);
|
||||
|
||||
void dhcp_handleifa(int, struct ipv4_addr *, pid_t pid);
|
||||
void dhcp_drop(struct interface *, const char *);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -582,10 +583,14 @@ dhcp6_delegateaddr(struct in6_addr *addr, struct interface *ifp,
|
|||
|
||||
#define BIT(n) (1UL << (n))
|
||||
#define BIT_MASK(len) (BIT(len) - 1)
|
||||
if (ia->sla_max == 0)
|
||||
if (ia->sla_max == 0) {
|
||||
/* Work out the real sla_max from our bits used */
|
||||
ia->sla_max = (uint32_t)BIT_MASK(asla.prefix_len -
|
||||
prefix->prefix_len);
|
||||
bits = asla.prefix_len - prefix->prefix_len;
|
||||
/* Make static analysis happy.
|
||||
* Bits cannot be bigger than 32 thanks to fls32. */
|
||||
assert(bits <= 32);
|
||||
ia->sla_max = (uint32_t)BIT_MASK(bits);
|
||||
}
|
||||
}
|
||||
|
||||
if (ipv6_userprefix(&prefix->prefix, prefix->prefix_len,
|
||||
|
@ -2845,26 +2850,11 @@ dhcp6_delegate_prefix(struct interface *ifp)
|
|||
struct dhcp6_state *s = D6_STATE(ifd);
|
||||
|
||||
ipv6_addaddrs(&s->addrs);
|
||||
|
||||
/*
|
||||
* Can't add routes here because that will trigger
|
||||
* interface sorting which may break the current
|
||||
* enumeration.
|
||||
* This doesn't really matter thanks to DaD because
|
||||
* calling the script will be delayed and routes
|
||||
* will get re-built if needed first.
|
||||
* This only cause minor confusion when dhcpcd is
|
||||
* restarted and confirms a lease where prior delegation
|
||||
* has already been assigned, because it will log it
|
||||
* added routes after the script has run.
|
||||
* The routes should still be there and fine though.
|
||||
*/
|
||||
dhcp6_script_try_run(ifd, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now all addresses have been added, rebuild the routing table. */
|
||||
if_initrt(ifp->ctx, AF_INET6);
|
||||
rt_build(ifp->ctx, AF_INET6);
|
||||
}
|
||||
|
||||
|
@ -2929,7 +2919,6 @@ dhcp6_find_delegates(struct interface *ifp)
|
|||
state = D6_STATE(ifp);
|
||||
state->state = DH6S_DELEGATED;
|
||||
ipv6_addaddrs(&state->addrs);
|
||||
if_initrt(ifp->ctx, AF_INET6);
|
||||
rt_build(ifp->ctx, AF_INET6);
|
||||
dhcp6_script_try_run(ifp, 1);
|
||||
}
|
||||
|
@ -3167,7 +3156,6 @@ dhcp6_bind(struct interface *ifp, const char *op, const char *sfrom)
|
|||
else
|
||||
lognewinfo("%s: expire in %"PRIu32" seconds",
|
||||
ifp->name, state->expire);
|
||||
if_initrt(ifp->ctx, AF_INET6);
|
||||
rt_build(ifp->ctx, AF_INET6);
|
||||
if (!timed_out)
|
||||
dhcp6_writelease(ifp);
|
||||
|
@ -3971,24 +3959,22 @@ dhcp6_handleifa(int cmd, struct ipv6_addr *ia, pid_t pid)
|
|||
}
|
||||
|
||||
ssize_t
|
||||
dhcp6_env(char **env, const char *prefix, const struct interface *ifp,
|
||||
dhcp6_env(FILE *fp, const char *prefix, const struct interface *ifp,
|
||||
const struct dhcp6_message *m, size_t len)
|
||||
{
|
||||
const struct if_options *ifo;
|
||||
struct dhcp_opt *opt, *vo;
|
||||
const uint8_t *p;
|
||||
struct dhcp6_option o;
|
||||
size_t i, n;
|
||||
size_t i;
|
||||
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)
|
||||
goto delegated;
|
||||
|
||||
|
@ -4003,28 +3989,20 @@ dhcp6_env(char **env, const char *prefix, const struct interface *ifp,
|
|||
ctx = ifp->ctx;
|
||||
|
||||
/* Zero our indexes */
|
||||
if (env) {
|
||||
for (i = 0, opt = ctx->dhcp6_opts;
|
||||
i < ctx->dhcp6_opts_len;
|
||||
i++, opt++)
|
||||
dhcp_zero_index(opt);
|
||||
for (i = 0, opt = ifp->options->dhcp6_override;
|
||||
i < ifp->options->dhcp6_override_len;
|
||||
i++, opt++)
|
||||
dhcp_zero_index(opt);
|
||||
for (i = 0, opt = ctx->vivso;
|
||||
i < ctx->vivso_len;
|
||||
i++, opt++)
|
||||
dhcp_zero_index(opt);
|
||||
i = strlen(prefix) + strlen("_dhcp6") + 1;
|
||||
pfx = malloc(i);
|
||||
if (pfx == NULL) {
|
||||
logerr(__func__);
|
||||
return -1;
|
||||
}
|
||||
snprintf(pfx, i, "%s_dhcp6", prefix);
|
||||
} else
|
||||
pfx = NULL;
|
||||
for (i = 0, opt = ctx->dhcp6_opts;
|
||||
i < ctx->dhcp6_opts_len;
|
||||
i++, opt++)
|
||||
dhcp_zero_index(opt);
|
||||
for (i = 0, opt = ifp->options->dhcp6_override;
|
||||
i < ifp->options->dhcp6_override_len;
|
||||
i++, opt++)
|
||||
dhcp_zero_index(opt);
|
||||
for (i = 0, opt = ctx->vivso;
|
||||
i < ctx->vivso_len;
|
||||
i++, opt++)
|
||||
dhcp_zero_index(opt);
|
||||
if (asprintf(&pfx, "%s_dhcp6", prefix) == -1)
|
||||
return -1;
|
||||
|
||||
/* Unlike DHCP, DHCPv6 options *may* occur more than once.
|
||||
* There is also no provision for option concatenation unlike DHCP. */
|
||||
|
@ -4070,15 +4048,13 @@ dhcp6_env(char **env, const char *prefix, const struct interface *ifp,
|
|||
opt = NULL;
|
||||
}
|
||||
if (opt) {
|
||||
n += dhcp_envoption(ifp->ctx,
|
||||
env == NULL ? NULL : &env[n],
|
||||
pfx, ifp->name,
|
||||
dhcp_envoption(ifp->ctx,
|
||||
fp, pfx, ifp->name,
|
||||
opt, dhcp6_getoption, p, o.len);
|
||||
}
|
||||
if (vo) {
|
||||
n += dhcp_envoption(ifp->ctx,
|
||||
env == NULL ? NULL : &env[n],
|
||||
pfx, ifp->name,
|
||||
dhcp_envoption(ifp->ctx,
|
||||
fp, pfx, ifp->name,
|
||||
vo, dhcp6_getoption,
|
||||
p + sizeof(en),
|
||||
o.len - sizeof(en));
|
||||
|
@ -4090,38 +4066,29 @@ delegated:
|
|||
#ifndef SMALL
|
||||
/* Needed for Delegated Prefixes */
|
||||
state = D6_CSTATE(ifp);
|
||||
i = 0;
|
||||
TAILQ_FOREACH(ap, &state->addrs, next) {
|
||||
if (ap->delegating_prefix) {
|
||||
i += strlen(ap->saddr) + 1;
|
||||
}
|
||||
if (ap->delegating_prefix)
|
||||
break;
|
||||
}
|
||||
if (env && i) {
|
||||
i += strlen(prefix) + strlen("_delegated_dhcp6_prefix=");
|
||||
v = val = env[n] = malloc(i);
|
||||
if (v == NULL) {
|
||||
logerr(__func__);
|
||||
if (ap == NULL)
|
||||
return 1;
|
||||
if (fprintf(fp, "%s_delegated_dhcp6_prefix=", prefix) == -1)
|
||||
return -1;
|
||||
TAILQ_FOREACH(ap, &state->addrs, next) {
|
||||
if (ap->delegating_prefix == NULL)
|
||||
continue;
|
||||
if (ap != TAILQ_FIRST(&state->addrs)) {
|
||||
if (fputc(' ', fp) == EOF)
|
||||
return -1;
|
||||
}
|
||||
if (fprintf(fp, "%s", ap->saddr) == -1)
|
||||
return -1;
|
||||
}
|
||||
v += snprintf(val, i, "%s_delegated_dhcp6_prefix=", prefix);
|
||||
TAILQ_FOREACH(ap, &state->addrs, next) {
|
||||
if (ap->delegating_prefix) {
|
||||
/* Can't use stpcpy(3) due to "security" */
|
||||
const char *sap = ap->saddr;
|
||||
|
||||
do
|
||||
*v++ = *sap;
|
||||
while (*++sap != '\0');
|
||||
*v++ = ' ';
|
||||
}
|
||||
}
|
||||
*--v = '\0';
|
||||
}
|
||||
if (i)
|
||||
n++;
|
||||
if (fputc('\0', fp) == EOF)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
return (ssize_t)n;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -228,7 +229,7 @@ size_t dhcp6_find_delegates(struct interface *);
|
|||
int dhcp6_start(struct interface *, enum DH6S);
|
||||
void dhcp6_reboot(struct interface *);
|
||||
void dhcp6_renew(struct interface *);
|
||||
ssize_t dhcp6_env(char **, const char *, const struct interface *,
|
||||
ssize_t dhcp6_env(FILE *, const char *, const struct interface *,
|
||||
const struct dhcp6_message *, size_t);
|
||||
void dhcp6_free(struct interface *);
|
||||
void dhcp6_handleifa(int, struct ipv6_addr *, pid_t);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
.\" SPDX-License-Identifier: BSD-2-Clause
|
||||
.\"
|
||||
.\" Copyright (c) 2006-2019 Roy Marples
|
||||
.\" All rights reserved
|
||||
.\"
|
||||
|
@ -22,7 +24,7 @@
|
|||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd January 2, 2019
|
||||
.Dd July 23, 2019
|
||||
.Dt DHCPCD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -352,7 +354,7 @@ rather than
|
|||
.Xr syslog 3 .
|
||||
The
|
||||
.Ar logfile
|
||||
is s reopened when
|
||||
is reopened when
|
||||
.Nm
|
||||
receives the
|
||||
.Dv SIGUSR2
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -738,9 +739,6 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags,
|
|||
#ifdef INET
|
||||
dhcp_abort(ifp);
|
||||
#endif
|
||||
#ifdef INET6
|
||||
ipv6nd_expire(ifp, 0);
|
||||
#endif
|
||||
#ifdef DHCP6
|
||||
dhcp6_abort(ifp);
|
||||
#endif
|
||||
|
@ -785,7 +783,7 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags,
|
|||
/* Set any IPv6 Routers we remembered to expire
|
||||
* faster than they would normally as we
|
||||
* maybe on a new network. */
|
||||
ipv6nd_expire(ifp, RTR_CARRIER_EXPIRE);
|
||||
ipv6nd_startexpire(ifp);
|
||||
#endif
|
||||
/* RFC4941 Section 3.5 */
|
||||
ipv6_gentempifid(ifp);
|
||||
|
@ -1003,6 +1001,7 @@ dhcpcd_handleinterface(void *arg, int action, const char *ifname)
|
|||
struct if_head *ifs;
|
||||
struct interface *ifp, *iff;
|
||||
const char * const argv[] = { ifname };
|
||||
int e;
|
||||
|
||||
ctx = arg;
|
||||
if (action == -1) {
|
||||
|
@ -1026,13 +1025,17 @@ dhcpcd_handleinterface(void *arg, int action, const char *ifname)
|
|||
logerr(__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ifp = if_find(ifs, ifname);
|
||||
if (ifp == NULL) {
|
||||
/* This can happen if an interface is quickly added
|
||||
* and then removed. */
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
e = -1;
|
||||
goto out;
|
||||
}
|
||||
e = 1;
|
||||
|
||||
/* Check if we already have the interface */
|
||||
iff = if_find(ctx->ifaces, ifp->name);
|
||||
|
||||
|
@ -1061,6 +1064,7 @@ dhcpcd_handleinterface(void *arg, int action, const char *ifname)
|
|||
dhcpcd_prestartinterface(iff);
|
||||
}
|
||||
|
||||
out:
|
||||
/* Free our discovered list */
|
||||
while ((ifp = TAILQ_FIRST(ifs))) {
|
||||
TAILQ_REMOVE(ifs, ifp, next);
|
||||
|
@ -1068,7 +1072,7 @@ dhcpcd_handleinterface(void *arg, int action, const char *ifname)
|
|||
}
|
||||
free(ifs);
|
||||
|
||||
return 1;
|
||||
return e;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1081,7 +1085,8 @@ dhcpcd_handlelink(void *arg)
|
|||
dhcpcd_linkoverflow(ctx);
|
||||
return;
|
||||
}
|
||||
logerr(__func__);
|
||||
if (errno != ENOTSUP)
|
||||
logerr(__func__);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1093,6 +1098,22 @@ dhcpcd_checkcarrier(void *arg)
|
|||
dhcpcd_handlecarrier(ifp->ctx, LINK_UNKNOWN, ifp->flags, ifp->name);
|
||||
}
|
||||
|
||||
#ifndef SMALL
|
||||
static void
|
||||
dhcpcd_setlinkrcvbuf(struct dhcpcd_ctx *ctx)
|
||||
{
|
||||
socklen_t socklen;
|
||||
|
||||
if (ctx->link_rcvbuf == 0)
|
||||
return;
|
||||
|
||||
socklen = sizeof(ctx->link_rcvbuf);
|
||||
if (setsockopt(ctx->link_fd, SOL_SOCKET,
|
||||
SO_RCVBUF, &ctx->link_rcvbuf, socklen) == -1)
|
||||
logerr(__func__);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
dhcpcd_linkoverflow(struct dhcpcd_ctx *ctx)
|
||||
{
|
||||
|
@ -1113,10 +1134,17 @@ dhcpcd_linkoverflow(struct dhcpcd_ctx *ctx)
|
|||
eloop_exit(ctx->eloop, EXIT_FAILURE);
|
||||
return;
|
||||
}
|
||||
#ifndef SMALL
|
||||
dhcpcd_setlinkrcvbuf(ctx);
|
||||
#endif
|
||||
eloop_event_add(ctx->eloop, ctx->link_fd, dhcpcd_handlelink, ctx);
|
||||
|
||||
/* Work out the current interfaces. */
|
||||
ifaces = if_discover(ctx, &ifaddrs, ctx->ifc, ctx->ifv);
|
||||
if (ifaces == NULL) {
|
||||
logerr(__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Punt departed interfaces */
|
||||
TAILQ_FOREACH_SAFE(ifp, ctx->ifaces, next, ifn) {
|
||||
|
@ -1126,21 +1154,23 @@ dhcpcd_linkoverflow(struct dhcpcd_ctx *ctx)
|
|||
}
|
||||
|
||||
/* Add new interfaces */
|
||||
TAILQ_FOREACH_SAFE(ifp, ifaces, next, ifn) {
|
||||
while ((ifp = TAILQ_FIRST(ifaces)) != NULL ) {
|
||||
TAILQ_REMOVE(ifaces, ifp, next);
|
||||
ifp1 = if_find(ctx->ifaces, ifp->name);
|
||||
if (ifp1 != NULL) {
|
||||
/* If the interface already exists,
|
||||
* check carrier state. */
|
||||
eloop_timeout_add_sec(ctx->eloop, 0,
|
||||
dhcpcd_checkcarrier, ifp1);
|
||||
if_free(ifp);
|
||||
continue;
|
||||
}
|
||||
TAILQ_REMOVE(ifaces, ifp, next);
|
||||
TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next);
|
||||
if (ifp->active)
|
||||
eloop_timeout_add_sec(ctx->eloop, 0,
|
||||
dhcpcd_prestartinterface, ifp);
|
||||
}
|
||||
free(ifaces);
|
||||
|
||||
/* Update address state. */
|
||||
if_markaddrsstale(ctx->ifaces);
|
||||
|
@ -1958,6 +1988,9 @@ printpidfile:
|
|||
logerr("%s: if_opensockets", __func__);
|
||||
goto exit_failure;
|
||||
}
|
||||
#ifndef SMALL
|
||||
dhcpcd_setlinkrcvbuf(&ctx);
|
||||
#endif
|
||||
|
||||
/* When running dhcpcd against a single interface, we need to retain
|
||||
* the old behaviour of waiting for an IP address */
|
||||
|
@ -2057,7 +2090,6 @@ printpidfile:
|
|||
free_options(&ctx, ifo);
|
||||
ifo = NULL;
|
||||
|
||||
if_sortinterfaces(&ctx);
|
||||
TAILQ_FOREACH(ifp, ctx.ifaces, next) {
|
||||
if (ifp->active)
|
||||
eloop_timeout_add_sec(ctx.eloop, 0,
|
||||
|
@ -2114,5 +2146,11 @@ exit1:
|
|||
if (ctx.options & DHCPCD_FORKED)
|
||||
_exit(i); /* so atexit won't remove our pidfile */
|
||||
#endif
|
||||
#ifdef HAVE_OPEN_MEMSTREAM
|
||||
if (ctx.script_fp)
|
||||
fclose(ctx.script_fp);
|
||||
#endif
|
||||
free(ctx.script_buf);
|
||||
free(ctx.script_env);
|
||||
return i;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
.\" SPDX-License-Identifier: BSD-2-Clause
|
||||
.\"
|
||||
.\" Copyright (c) 2006-2019 Roy Marples
|
||||
.\" All rights reserved
|
||||
.\"
|
||||
|
@ -428,6 +430,12 @@ globally but needs to be enabled for one interface.
|
|||
.It Ic leasetime Ar seconds
|
||||
Request a leasetime of
|
||||
.Ar seconds .
|
||||
.It Ic link_rcvbuf Ar size
|
||||
Override the size of the link receive buffer from the kernel default.
|
||||
While
|
||||
.Nm dhcpcd
|
||||
will recover from link buffer overflows,
|
||||
this may not be desirable on heavily loaded systems.
|
||||
.It Ic logfile Ar logfile
|
||||
Writes to the specified
|
||||
.Ar logfile
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -136,13 +137,18 @@ struct dhcpcd_ctx {
|
|||
size_t duid_len;
|
||||
struct if_head *ifaces;
|
||||
|
||||
struct rt_head routes; /* our routes */
|
||||
struct rt_head kroutes; /* all kernel routes */
|
||||
struct rt_head froutes; /* free routes for re-use */
|
||||
rb_tree_t routes; /* our routes */
|
||||
#ifdef RT_FREE_ROUTE_TABLE
|
||||
rb_tree_t froutes; /* free routes for re-use */
|
||||
#endif
|
||||
size_t rt_order; /* route order storage */
|
||||
|
||||
int pf_inet_fd;
|
||||
void *priv;
|
||||
int link_fd;
|
||||
#ifndef SMALL
|
||||
int link_rcvbuf;
|
||||
#endif
|
||||
int seq; /* route message sequence no */
|
||||
int sseq; /* successful seq no sent */
|
||||
|
||||
|
@ -151,6 +157,14 @@ struct dhcpcd_ctx {
|
|||
#endif
|
||||
struct eloop *eloop;
|
||||
|
||||
#ifdef HAVE_OPEN_MEMSTREAM
|
||||
FILE *script_fp;
|
||||
#endif
|
||||
char *script_buf;
|
||||
size_t script_buflen;
|
||||
char **script_env;
|
||||
size_t script_envlen;
|
||||
|
||||
int control_fd;
|
||||
int control_unpriv_fd;
|
||||
struct fd_list_head control_fds;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* eloop - portable event based main loop.
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* BSD interface driver for dhcpcd
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -496,6 +497,8 @@ if_route(unsigned char cmd, const struct rt *rt)
|
|||
bool gateway_unspec;
|
||||
|
||||
assert(rt != NULL);
|
||||
assert(rt->rt_ifp != NULL);
|
||||
assert(rt->rt_ifp->ctx != NULL);
|
||||
ctx = rt->rt_ifp->ctx;
|
||||
|
||||
#define ADDSA(sa) do { \
|
||||
|
@ -695,15 +698,13 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, const struct rt_msghdr *rtm)
|
|||
}
|
||||
|
||||
int
|
||||
if_initrt(struct dhcpcd_ctx *ctx, int af)
|
||||
if_initrt(struct dhcpcd_ctx *ctx, rb_tree_t *kroutes, int af)
|
||||
{
|
||||
struct rt_msghdr *rtm;
|
||||
int mib[6];
|
||||
size_t needed;
|
||||
char *buf, *p, *end;
|
||||
struct rt rt;
|
||||
|
||||
rt_headclear(&ctx->kroutes, af);
|
||||
struct rt rt, *rtn;
|
||||
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = PF_ROUTE;
|
||||
|
@ -730,10 +731,15 @@ if_initrt(struct dhcpcd_ctx *ctx, int af)
|
|||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
if (if_copyrt(ctx, &rt, rtm) == 0) {
|
||||
rt.rt_dflags |= RTDF_INIT;
|
||||
rt_recvrt(RTM_ADD, &rt, rtm->rtm_pid);
|
||||
if (if_copyrt(ctx, &rt, rtm) != 0)
|
||||
continue;
|
||||
if ((rtn = rt_new(rt.rt_ifp)) == NULL) {
|
||||
logerr(__func__);
|
||||
break;
|
||||
}
|
||||
memcpy(rtn, &rt, sizeof(*rtn));
|
||||
if (rb_tree_insert_node(kroutes, rtn) != rtn)
|
||||
rt_free(rtn);
|
||||
}
|
||||
free(buf);
|
||||
return p == end ? 0 : -1;
|
||||
|
@ -1063,7 +1069,7 @@ if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
|
|||
return 0;
|
||||
|
||||
if (if_copyrt(ctx, &rt, rtm) == -1)
|
||||
return errno == ENOTSUP ? 0 : -1;
|
||||
return -1;
|
||||
|
||||
#ifdef INET6
|
||||
/*
|
||||
|
@ -1306,7 +1312,6 @@ if_dispatch(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
|
|||
#ifdef RTM_DESYNC
|
||||
case RTM_DESYNC:
|
||||
dhcpcd_linkoverflow(ctx);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1326,12 +1331,13 @@ if_handlelink(struct dhcpcd_ctx *ctx)
|
|||
return -1;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
if ((size_t)len < offsetof(struct rt_msghdr, rtm_index) ||
|
||||
len < rtm.hdr.rtm_msglen)
|
||||
{
|
||||
if (len < rtm.hdr.rtm_msglen) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/* We generally treat rtm.hdr has an array so we can easily
|
||||
* access the following data. */
|
||||
/* coverity[callee_ptr_arith] */
|
||||
return if_dispatch(ctx, &rtm.hdr);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -64,7 +65,7 @@
|
|||
#define O_IPV6RS O_BASE + 4
|
||||
#define O_NOIPV6RS O_BASE + 5
|
||||
#define O_IPV6RA_FORK O_BASE + 6
|
||||
// unused O_BASE + 7
|
||||
#define O_LINK_RCVBUF O_BASE + 7
|
||||
// unused O_BASE + 8
|
||||
#define O_NOALIAS O_BASE + 9
|
||||
#define O_IA_NA O_BASE + 10
|
||||
|
@ -204,6 +205,7 @@ const struct option cf_options[] = {
|
|||
{"lastleaseextend", no_argument, NULL, O_LASTLEASE_EXTEND},
|
||||
{"inactive", no_argument, NULL, O_INACTIVE},
|
||||
{"mudurl", required_argument, NULL, O_MUDURL},
|
||||
{"link_rcvbuf", required_argument, NULL, O_LINK_RCVBUF},
|
||||
{NULL, 0, NULL, '\0'}
|
||||
};
|
||||
|
||||
|
@ -724,8 +726,9 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
|
|||
logerr(__func__);
|
||||
return -1;
|
||||
}
|
||||
parse_str(ifo->script, dl, arg, PARSE_STRING_NULL);
|
||||
if (ifo->script[0] == '\0' ||
|
||||
s = parse_str(ifo->script, dl, arg, PARSE_STRING_NULL);
|
||||
if (s == -1 ||
|
||||
ifo->script[0] == '\0' ||
|
||||
strcmp(ifo->script, "/dev/null") == 0)
|
||||
{
|
||||
free(ifo->script);
|
||||
|
@ -1122,16 +1125,14 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
|
|||
*fp = ' ';
|
||||
return -1;
|
||||
}
|
||||
if ((rt = rt_new0(ctx)) == NULL) {
|
||||
*fp = ' ';
|
||||
*fp = ' ';
|
||||
if ((rt = rt_new0(ctx)) == NULL)
|
||||
return -1;
|
||||
}
|
||||
sa_in_init(&rt->rt_dest, &addr);
|
||||
sa_in_init(&rt->rt_netmask, &addr2);
|
||||
sa_in_init(&rt->rt_gateway, &addr3);
|
||||
TAILQ_INSERT_TAIL(&ifo->routes, rt, rt_next);
|
||||
*fp = ' ';
|
||||
add_environ(&ifo->config, arg, 0);
|
||||
if (rt_proto_add_ctx(&ifo->routes, rt, ctx))
|
||||
add_environ(&ifo->config, arg, 0);
|
||||
} else if (strncmp(arg, "routers=", strlen("routers=")) == 0) {
|
||||
if (parse_addr(&addr, NULL, p) == -1)
|
||||
return -1;
|
||||
|
@ -1141,8 +1142,8 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
|
|||
sa_in_init(&rt->rt_dest, &addr2);
|
||||
sa_in_init(&rt->rt_netmask, &addr2);
|
||||
sa_in_init(&rt->rt_gateway, &addr);
|
||||
TAILQ_INSERT_TAIL(&ifo->routes, rt, rt_next);
|
||||
add_environ(&ifo->config, arg, 0);
|
||||
if (rt_proto_add_ctx(&ifo->routes, rt, ctx))
|
||||
add_environ(&ifo->config, arg, 0);
|
||||
} else if (strncmp(arg, "interface_mtu=",
|
||||
strlen("interface_mtu=")) == 0 ||
|
||||
strncmp(arg, "mtu=", strlen("mtu=")) == 0)
|
||||
|
@ -1868,6 +1869,7 @@ err_sla:
|
|||
ifo->vivco_len + 1, sizeof(*ifo->vivco));
|
||||
if (vivco == NULL) {
|
||||
logerr( __func__);
|
||||
free(np);
|
||||
return -1;
|
||||
}
|
||||
ifo->vivco = vivco;
|
||||
|
@ -2160,6 +2162,16 @@ err_sla:
|
|||
}
|
||||
*ifo->mudurl = (uint8_t)s;
|
||||
break;
|
||||
case O_LINK_RCVBUF:
|
||||
#ifndef SMALL
|
||||
ARG_REQUIRED;
|
||||
ctx->link_rcvbuf = (int)strtoi(arg, NULL, 0, 0, INT32_MAX, &e);
|
||||
if (e) {
|
||||
logerrx("failed to convert link_rcvbuf %s", arg);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -2269,7 +2281,7 @@ default_config(struct dhcpcd_ctx *ctx)
|
|||
ifo->script = UNCONST(default_script);
|
||||
ifo->metric = -1;
|
||||
ifo->auth.options |= DHCPCD_AUTH_REQUIRE;
|
||||
TAILQ_INIT(&ifo->routes);
|
||||
rb_tree_init(&ifo->routes, &rt_compare_proto_ops);
|
||||
#ifdef AUTH
|
||||
TAILQ_INIT(&ifo->auth.tokens);
|
||||
#endif
|
||||
|
@ -2327,6 +2339,9 @@ read_config(struct dhcpcd_ctx *ctx,
|
|||
buf = NULL;
|
||||
buflen = 0;
|
||||
|
||||
/* Reset route order */
|
||||
ctx->rt_order = 0;
|
||||
|
||||
/* Parse our embedded options file */
|
||||
if (ifname == NULL && !(ctx->options & DHCPCD_PRINT_PIDFILE)) {
|
||||
/* Space for initial estimates */
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -181,7 +182,7 @@ struct if_options {
|
|||
struct in_addr req_addr;
|
||||
struct in_addr req_mask;
|
||||
struct in_addr req_brd;
|
||||
struct rt_head routes;
|
||||
rb_tree_t routes;
|
||||
struct in6_addr req_addr6;
|
||||
uint8_t req_prefix_len;
|
||||
unsigned int mtu;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -59,7 +60,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "dev.h"
|
||||
|
@ -704,58 +704,6 @@ if_domtu(const struct interface *ifp, short int mtu)
|
|||
return ifr.ifr_mtu;
|
||||
}
|
||||
|
||||
/* Interface comparer for working out ordering. */
|
||||
static int
|
||||
if_cmp(const struct interface *si, const struct interface *ti)
|
||||
{
|
||||
#ifdef INET
|
||||
int r;
|
||||
#endif
|
||||
|
||||
/* Check active first */
|
||||
if (si->active > ti->active)
|
||||
return -1;
|
||||
if (si->active < ti->active)
|
||||
return 1;
|
||||
|
||||
/* Check carrier status next */
|
||||
if (si->carrier > ti->carrier)
|
||||
return -1;
|
||||
if (si->carrier < ti->carrier)
|
||||
return 1;
|
||||
#ifdef INET
|
||||
if (D_STATE_RUNNING(si) && !D_STATE_RUNNING(ti))
|
||||
return -1;
|
||||
if (!D_STATE_RUNNING(si) && D_STATE_RUNNING(ti))
|
||||
return 1;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
if (RS_STATE_RUNNING(si) && !RS_STATE_RUNNING(ti))
|
||||
return -1;
|
||||
if (!RS_STATE_RUNNING(si) && RS_STATE_RUNNING(ti))
|
||||
return 1;
|
||||
#endif
|
||||
#ifdef DHCP6
|
||||
if (D6_STATE_RUNNING(si) && !D6_STATE_RUNNING(ti))
|
||||
return -1;
|
||||
if (!D6_STATE_RUNNING(si) && D6_STATE_RUNNING(ti))
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
#ifdef INET
|
||||
/* Special attention needed here due to states and IPv4LL. */
|
||||
if ((r = ipv4_ifcmp(si, ti)) != 0)
|
||||
return r;
|
||||
#endif
|
||||
|
||||
/* Finally, metric */
|
||||
if (si->metric < ti->metric)
|
||||
return -1;
|
||||
if (si->metric > ti->metric)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ALIAS_ADDR
|
||||
int
|
||||
if_makealias(char *alias, size_t alias_len, const char *ifname, int lun)
|
||||
|
@ -767,35 +715,6 @@ if_makealias(char *alias, size_t alias_len, const char *ifname, int lun)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Sort the interfaces into a preferred order - best first, worst last. */
|
||||
void
|
||||
if_sortinterfaces(struct dhcpcd_ctx *ctx)
|
||||
{
|
||||
struct if_head sorted;
|
||||
struct interface *ifp, *ift;
|
||||
|
||||
if (ctx->ifaces == NULL ||
|
||||
(ifp = TAILQ_FIRST(ctx->ifaces)) == NULL ||
|
||||
TAILQ_NEXT(ifp, next) == NULL)
|
||||
return;
|
||||
|
||||
TAILQ_INIT(&sorted);
|
||||
TAILQ_REMOVE(ctx->ifaces, ifp, next);
|
||||
TAILQ_INSERT_HEAD(&sorted, ifp, next);
|
||||
while ((ifp = TAILQ_FIRST(ctx->ifaces))) {
|
||||
TAILQ_REMOVE(ctx->ifaces, ifp, next);
|
||||
TAILQ_FOREACH(ift, &sorted, next) {
|
||||
if (if_cmp(ifp, ift) == -1) {
|
||||
TAILQ_INSERT_BEFORE(ift, ifp, next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ift == NULL)
|
||||
TAILQ_INSERT_TAIL(&sorted, ifp, next);
|
||||
}
|
||||
TAILQ_CONCAT(ctx->ifaces, &sorted, next);
|
||||
}
|
||||
|
||||
struct interface *
|
||||
if_findifpfromcmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg, int *hoplimit)
|
||||
{
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -123,7 +124,6 @@ void if_deletestaleaddrs(struct if_head *);
|
|||
struct interface *if_find(struct if_head *, const char *);
|
||||
struct interface *if_findindex(struct if_head *, unsigned int);
|
||||
struct interface *if_loopback(struct dhcpcd_ctx *);
|
||||
void if_sortinterfaces(struct dhcpcd_ctx *);
|
||||
void if_free(struct interface *);
|
||||
int if_domtu(const struct interface *, short int);
|
||||
#define if_getmtu(ifp) if_domtu((ifp), 0)
|
||||
|
@ -186,7 +186,7 @@ int if_handlelink(struct dhcpcd_ctx *);
|
|||
#endif
|
||||
|
||||
int if_route(unsigned char, const struct rt *rt);
|
||||
int if_initrt(struct dhcpcd_ctx *, int);
|
||||
int if_initrt(struct dhcpcd_ctx *, rb_tree_t *, int);
|
||||
|
||||
#ifdef INET
|
||||
int if_address(unsigned char, const struct ipv4_addr *);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -38,6 +39,7 @@
|
|||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
@ -247,10 +249,10 @@ ipv4_ifcmp(const struct interface *si, const struct interface *ti)
|
|||
}
|
||||
|
||||
static int
|
||||
inet_dhcproutes(struct rt_head *routes, struct interface *ifp)
|
||||
inet_dhcproutes(rb_tree_t *routes, struct interface *ifp, bool *have_default)
|
||||
{
|
||||
const struct dhcp_state *state;
|
||||
struct rt_head nroutes;
|
||||
rb_tree_t nroutes;
|
||||
struct rt *rt, *r = NULL;
|
||||
struct in_addr in;
|
||||
uint16_t mtu;
|
||||
|
@ -263,7 +265,7 @@ inet_dhcproutes(struct rt_head *routes, struct interface *ifp)
|
|||
/* An address does have to exist. */
|
||||
assert(state->addr);
|
||||
|
||||
TAILQ_INIT(&nroutes);
|
||||
rb_tree_init(&nroutes, &rt_compare_proto_ops);
|
||||
|
||||
/* First, add a subnet route. */
|
||||
if (!(ifp->flags & IFF_POINTOPOINT) &&
|
||||
|
@ -283,12 +285,12 @@ inet_dhcproutes(struct rt_head *routes, struct interface *ifp)
|
|||
//in.s_addr = INADDR_ANY;
|
||||
//sa_in_init(&rt->rt_gateway, &in);
|
||||
rt->rt_gateway.sa_family = AF_UNSPEC;
|
||||
TAILQ_INSERT_HEAD(&nroutes, rt, rt_next);
|
||||
rt_proto_add(&nroutes, rt);
|
||||
}
|
||||
|
||||
/* If any set routes, grab them, otherwise DHCP routes. */
|
||||
if (TAILQ_FIRST(&ifp->options->routes)) {
|
||||
TAILQ_FOREACH(r, &ifp->options->routes, rt_next) {
|
||||
if (RB_TREE_MIN(&ifp->options->routes)) {
|
||||
RB_TREE_FOREACH(r, &ifp->options->routes) {
|
||||
if (sa_is_unspecified(&r->rt_gateway))
|
||||
break;
|
||||
if ((rt = rt_new0(ifp->ctx)) == NULL)
|
||||
|
@ -296,14 +298,14 @@ inet_dhcproutes(struct rt_head *routes, struct interface *ifp)
|
|||
memcpy(rt, r, sizeof(*rt));
|
||||
rt_setif(rt, ifp);
|
||||
rt->rt_dflags = RTDF_STATIC;
|
||||
TAILQ_INSERT_TAIL(&nroutes, rt, rt_next);
|
||||
rt_proto_add(&nroutes, rt);
|
||||
}
|
||||
} else {
|
||||
if (dhcp_get_routes(&nroutes, ifp) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If configured, Install a gateway to the desintion
|
||||
/* If configured, install a gateway to the desintion
|
||||
* for P2P interfaces. */
|
||||
if (ifp->flags & IFF_POINTOPOINT &&
|
||||
has_option_mask(ifp->options->dstmask, DHO_ROUTER))
|
||||
|
@ -315,20 +317,26 @@ inet_dhcproutes(struct rt_head *routes, struct interface *ifp)
|
|||
sa_in_init(&rt->rt_netmask, &in);
|
||||
sa_in_init(&rt->rt_gateway, &state->addr->brd);
|
||||
sa_in_init(&rt->rt_ifa, &state->addr->addr);
|
||||
TAILQ_INSERT_HEAD(routes, rt, rt_next);
|
||||
rt_proto_add(&nroutes, rt);
|
||||
}
|
||||
|
||||
/* Copy our address as the source address and set mtu */
|
||||
mtu = dhcp_get_mtu(ifp);
|
||||
n = 0;
|
||||
TAILQ_FOREACH(rt, &nroutes, rt_next) {
|
||||
while ((rt = RB_TREE_MIN(&nroutes)) != NULL) {
|
||||
rb_tree_remove_node(&nroutes, rt);
|
||||
rt->rt_mtu = mtu;
|
||||
if (!(rt->rt_dflags & RTDF_STATIC))
|
||||
rt->rt_dflags |= RTDF_DHCP;
|
||||
sa_in_init(&rt->rt_ifa, &state->addr->addr);
|
||||
n++;
|
||||
if (rb_tree_insert_node(routes, rt) != rt) {
|
||||
rt_free(rt);
|
||||
continue;
|
||||
}
|
||||
if (rt_is_default(rt))
|
||||
*have_default = true;
|
||||
n = 1;
|
||||
}
|
||||
TAILQ_CONCAT(routes, &nroutes, rt_next);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
@ -336,20 +344,23 @@ inet_dhcproutes(struct rt_head *routes, struct interface *ifp)
|
|||
/* We should check to ensure the routers are on the same subnet
|
||||
* OR supply a host route. If not, warn and add a host route. */
|
||||
static int
|
||||
inet_routerhostroute(struct rt_head *routes, struct interface *ifp)
|
||||
inet_routerhostroute(rb_tree_t *routes, struct interface *ifp)
|
||||
{
|
||||
struct rt *rt, *rth;
|
||||
struct rt *rt, *rth, *rtp;
|
||||
struct sockaddr_in *dest, *netmask, *gateway;
|
||||
const char *cp, *cp2, *cp3, *cplim;
|
||||
struct if_options *ifo;
|
||||
const struct dhcp_state *state;
|
||||
struct in_addr in;
|
||||
rb_tree_t troutes;
|
||||
|
||||
/* Don't add a host route for these interfaces. */
|
||||
if (ifp->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
|
||||
return 0;
|
||||
|
||||
TAILQ_FOREACH(rt, routes, rt_next) {
|
||||
rb_tree_init(&troutes, &rt_compare_proto_ops);
|
||||
|
||||
RB_TREE_FOREACH(rt, routes) {
|
||||
if (rt->rt_dest.sa_family != AF_INET)
|
||||
continue;
|
||||
if (!sa_is_unspecified(&rt->rt_dest) ||
|
||||
|
@ -357,13 +368,14 @@ inet_routerhostroute(struct rt_head *routes, struct interface *ifp)
|
|||
continue;
|
||||
gateway = satosin(&rt->rt_gateway);
|
||||
/* Scan for a route to match */
|
||||
TAILQ_FOREACH(rth, routes, rt_next) {
|
||||
RB_TREE_FOREACH(rth, routes) {
|
||||
if (rth == rt)
|
||||
break;
|
||||
/* match host */
|
||||
if (sa_cmp(&rth->rt_dest, &rt->rt_gateway) == 0)
|
||||
break;
|
||||
/* match subnet */
|
||||
/* XXX ADD TO RT_COMARE? XXX */
|
||||
cp = (const char *)&gateway->sin_addr.s_addr;
|
||||
dest = satosin(&rth->rt_dest);
|
||||
cp2 = (const char *)&dest->sin_addr.s_addr;
|
||||
|
@ -408,6 +420,7 @@ inet_routerhostroute(struct rt_head *routes, struct interface *ifp)
|
|||
ifp->name,
|
||||
sa_addrtop(&rt->rt_gateway, buf, sizeof(buf)));
|
||||
}
|
||||
|
||||
if ((rth = rt_new(ifp)) == NULL)
|
||||
return -1;
|
||||
rth->rt_flags |= RTF_HOST;
|
||||
|
@ -418,24 +431,36 @@ inet_routerhostroute(struct rt_head *routes, struct interface *ifp)
|
|||
sa_in_init(&rth->rt_gateway, &in);
|
||||
rth->rt_mtu = dhcp_get_mtu(ifp);
|
||||
sa_in_init(&rth->rt_ifa, &state->addr->addr);
|
||||
TAILQ_INSERT_BEFORE(rt, rth, rt_next);
|
||||
|
||||
/* We need to insert the host route just before the router. */
|
||||
while ((rtp = RB_TREE_MAX(routes)) != NULL) {
|
||||
rb_tree_remove_node(routes, rtp);
|
||||
rt_proto_add(&troutes, rtp);
|
||||
if (rtp == rt)
|
||||
break;
|
||||
}
|
||||
rt_proto_add(routes, rth);
|
||||
/* troutes is now reversed, so add backwards again. */
|
||||
while ((rtp = RB_TREE_MAX(&troutes)) != NULL) {
|
||||
rb_tree_remove_node(&troutes, rtp);
|
||||
rt_proto_add(routes, rtp);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
inet_getroutes(struct dhcpcd_ctx *ctx, struct rt_head *routes)
|
||||
inet_getroutes(struct dhcpcd_ctx *ctx, rb_tree_t *routes)
|
||||
{
|
||||
struct interface *ifp;
|
||||
#ifdef IPV4LL
|
||||
struct rt def;
|
||||
bool have_default;
|
||||
bool have_default = false;
|
||||
#endif
|
||||
|
||||
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
|
||||
if (!ifp->active)
|
||||
continue;
|
||||
if (inet_dhcproutes(routes, ifp) == -1)
|
||||
if (inet_dhcproutes(routes, ifp, &have_default) == -1)
|
||||
return false;
|
||||
#ifdef IPV4LL
|
||||
if (ipv4ll_subnetroute(routes, ifp) == -1)
|
||||
|
@ -447,15 +472,13 @@ inet_getroutes(struct dhcpcd_ctx *ctx, struct rt_head *routes)
|
|||
|
||||
#ifdef IPV4LL
|
||||
/* If there is no default route, see if we can use an IPv4LL one. */
|
||||
memset(&def, 0, sizeof(def));
|
||||
def.rt_dest.sa_family = AF_INET;
|
||||
have_default = (rt_find(routes, &def) != NULL);
|
||||
if (!have_default) {
|
||||
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
|
||||
if (ifp->active &&
|
||||
ipv4ll_defaultroute(routes, ifp) == 1)
|
||||
break;
|
||||
}
|
||||
if (have_default)
|
||||
return true;
|
||||
|
||||
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
|
||||
if (ifp->active &&
|
||||
ipv4ll_defaultroute(routes, ifp) == 1)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -468,11 +491,6 @@ ipv4_deladdr(struct ipv4_addr *addr, int keeparp)
|
|||
int r;
|
||||
struct ipv4_state *state;
|
||||
struct ipv4_addr *ap;
|
||||
#ifdef ARP
|
||||
struct arp_state *astate;
|
||||
#else
|
||||
UNUSED(keeparp);
|
||||
#endif
|
||||
|
||||
logdebugx("%s: deleting IP address %s",
|
||||
addr->iface->name, addr->saddr);
|
||||
|
@ -484,8 +502,8 @@ ipv4_deladdr(struct ipv4_addr *addr, int keeparp)
|
|||
logerr("%s: %s", addr->iface->name, __func__);
|
||||
|
||||
#ifdef ARP
|
||||
if (!keeparp && (astate = arp_find(addr->iface, &addr->addr)) != NULL)
|
||||
arp_free(astate);
|
||||
if (!keeparp)
|
||||
arp_freeaddr(addr->iface, &addr->addr);
|
||||
#endif
|
||||
|
||||
state = IPV4_STATE(addr->iface);
|
||||
|
@ -523,6 +541,7 @@ delete_address(struct interface *ifp)
|
|||
ifo->options & DHCPCD_INFORM ||
|
||||
(ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0))
|
||||
return 0;
|
||||
arp_freeaddr(ifp, &state->addr->addr);
|
||||
r = ipv4_deladdr(state->addr, 0);
|
||||
return r;
|
||||
}
|
||||
|
@ -597,7 +616,8 @@ find_lun:
|
|||
|
||||
struct ipv4_addr *
|
||||
ipv4_addaddr(struct interface *ifp, const struct in_addr *addr,
|
||||
const struct in_addr *mask, const struct in_addr *bcast)
|
||||
const struct in_addr *mask, const struct in_addr *bcast,
|
||||
uint32_t vltime, uint32_t pltime)
|
||||
{
|
||||
struct ipv4_state *state;
|
||||
struct ipv4_addr *ia;
|
||||
|
@ -637,6 +657,8 @@ ipv4_addaddr(struct interface *ifp, const struct in_addr *addr,
|
|||
|
||||
ia->mask = *mask;
|
||||
ia->brd = *bcast;
|
||||
ia->vltime = vltime;
|
||||
ia->pltime = pltime;
|
||||
snprintf(ia->saddr, sizeof(ia->saddr), "%s/%d",
|
||||
inet_ntoa(*addr), inet_ntocidr(*mask));
|
||||
|
||||
|
@ -679,7 +701,8 @@ ipv4_daddaddr(struct interface *ifp, const struct dhcp_lease *lease)
|
|||
struct dhcp_state *state;
|
||||
struct ipv4_addr *ia;
|
||||
|
||||
ia = ipv4_addaddr(ifp, &lease->addr, &lease->mask, &lease->brd);
|
||||
ia = ipv4_addaddr(ifp, &lease->addr, &lease->mask, &lease->brd,
|
||||
lease->leasetime, lease->rebindtime);
|
||||
if (ia == NULL)
|
||||
return -1;
|
||||
|
||||
|
@ -697,7 +720,6 @@ ipv4_applyaddr(void *arg)
|
|||
struct dhcp_lease *lease;
|
||||
struct if_options *ifo = ifp->options;
|
||||
struct ipv4_addr *ia;
|
||||
int r;
|
||||
|
||||
if (state == NULL)
|
||||
return;
|
||||
|
@ -722,25 +744,16 @@ ipv4_applyaddr(void *arg)
|
|||
return;
|
||||
}
|
||||
|
||||
#if __linux__
|
||||
/* If the netmask or broadcast is different, re-add the addresss */
|
||||
ia = ipv4_iffindaddr(ifp, &lease->addr, NULL);
|
||||
if (ia &&
|
||||
ia->mask.s_addr == lease->mask.s_addr &&
|
||||
ia->brd.s_addr == lease->brd.s_addr)
|
||||
logdebugx("%s: IP address %s already exists",
|
||||
ifp->name, ia->saddr);
|
||||
else {
|
||||
#if __linux__
|
||||
/* Linux does not change netmask/broadcast address
|
||||
* for re-added addresses, so we need to delete the old one
|
||||
* first. */
|
||||
if (ia != NULL)
|
||||
ipv4_deladdr(ia, 0);
|
||||
if (ia != NULL &&
|
||||
(ia->mask.s_addr != lease->mask.s_addr ||
|
||||
ia->brd.s_addr != lease->brd.s_addr))
|
||||
ipv4_deladdr(ia, 0);
|
||||
#endif
|
||||
r = ipv4_daddaddr(ifp, lease);
|
||||
if (r == -1 && errno != EEXIST)
|
||||
return;
|
||||
}
|
||||
if (ipv4_daddaddr(ifp, lease) == -1 && errno != EEXIST)
|
||||
return;
|
||||
|
||||
ia = ipv4_iffindaddr(ifp, &lease->addr, NULL);
|
||||
if (ia == NULL) {
|
||||
|
@ -761,10 +774,6 @@ ipv4_applyaddr(void *arg)
|
|||
state->addr = ia;
|
||||
state->added = STATE_ADDED;
|
||||
|
||||
/* Find any freshly added routes, such as the subnet route.
|
||||
* We do this because we cannot rely on recieving the kernel
|
||||
* notification right now via our link socket. */
|
||||
if_initrt(ifp->ctx, AF_INET);
|
||||
rt_build(ifp->ctx, AF_INET);
|
||||
|
||||
#ifdef ARP
|
||||
|
@ -897,10 +906,10 @@ ipv4_handleifa(struct dhcpcd_ctx *ctx,
|
|||
}
|
||||
|
||||
if (addr->s_addr != INADDR_ANY && addr->s_addr != INADDR_BROADCAST) {
|
||||
#ifdef ARP
|
||||
arp_handleifa(cmd, ia);
|
||||
#endif
|
||||
dhcp_handleifa(cmd, ia, pid);
|
||||
#ifdef IPV4LL
|
||||
ipv4ll_handleifa(cmd, ia, pid);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (cmd == RTM_DELADDR)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -71,6 +72,9 @@
|
|||
(IN_IFF_TENTATIVE | IN_IFF_DUPLICATED | IN_IFF_DETACHED)
|
||||
#endif
|
||||
|
||||
#define IN_ARE_ADDR_EQUAL(a, b) ((a)->s_addr == (b)->s_addr)
|
||||
#define IN_IS_ADDR_UNSPECIFIED(a) ((a)->s_addr == INADDR_ANY)
|
||||
|
||||
struct ipv4_addr {
|
||||
TAILQ_ENTRY(ipv4_addr) next;
|
||||
struct in_addr addr;
|
||||
|
@ -79,6 +83,8 @@ struct ipv4_addr {
|
|||
struct interface *iface;
|
||||
int addr_flags;
|
||||
unsigned int flags;
|
||||
uint32_t vltime;
|
||||
uint32_t pltime;
|
||||
char saddr[INET_ADDRSTRLEN + 3];
|
||||
#ifdef ALIAS_ADDR
|
||||
char alias[IF_NAMESIZE];
|
||||
|
@ -115,14 +121,15 @@ int inet_cidrtoaddr(int, struct in_addr *);
|
|||
uint32_t ipv4_getnetmask(uint32_t);
|
||||
int ipv4_hasaddr(const struct interface *);
|
||||
|
||||
bool inet_getroutes(struct dhcpcd_ctx *, struct rt_head *);
|
||||
bool inet_getroutes(struct dhcpcd_ctx *, rb_tree_t *);
|
||||
|
||||
#define STATE_ADDED 0x01
|
||||
#define STATE_FAKE 0x02
|
||||
|
||||
int ipv4_deladdr(struct ipv4_addr *, int);
|
||||
struct ipv4_addr *ipv4_addaddr(struct interface *,
|
||||
const struct in_addr *, const struct in_addr *, const struct in_addr *);
|
||||
const struct in_addr *, const struct in_addr *, const struct in_addr *,
|
||||
uint32_t, uint32_t);
|
||||
void ipv4_applyaddr(void *);
|
||||
|
||||
struct ipv4_addr *ipv4_iffindaddr(struct interface *,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -30,6 +31,7 @@
|
|||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
@ -38,6 +40,7 @@
|
|||
#include "config.h"
|
||||
#include "arp.h"
|
||||
#include "common.h"
|
||||
#include "dhcp.h"
|
||||
#include "eloop.h"
|
||||
#include "if.h"
|
||||
#include "if-options.h"
|
||||
|
@ -47,7 +50,6 @@
|
|||
#include "sa.h"
|
||||
#include "script.h"
|
||||
|
||||
#ifdef IPV4LL
|
||||
static const struct in_addr inaddr_llmask = {
|
||||
.s_addr = HTONL(LINKLOCAL_MASK)
|
||||
};
|
||||
|
@ -55,18 +57,21 @@ static const struct in_addr inaddr_llbcast = {
|
|||
.s_addr = HTONL(LINKLOCAL_BCAST)
|
||||
};
|
||||
|
||||
static void ipv4ll_start1(struct interface *, struct arp_state *);
|
||||
|
||||
static in_addr_t
|
||||
ipv4ll_pickaddr(struct arp_state *astate)
|
||||
ipv4ll_pickaddr(struct interface *ifp)
|
||||
{
|
||||
struct in_addr addr;
|
||||
struct ipv4ll_state *istate;
|
||||
struct ipv4ll_state *state;
|
||||
|
||||
istate = IPV4LL_STATE(astate->iface);
|
||||
setstate(istate->randomstate);
|
||||
state = IPV4LL_STATE(ifp);
|
||||
setstate(state->randomstate);
|
||||
|
||||
do {
|
||||
long r;
|
||||
|
||||
again:
|
||||
/* RFC 3927 Section 2.1 states that the first 256 and
|
||||
* last 256 addresses are reserved for future use.
|
||||
* See ipv4ll_start for why we don't use arc4random. */
|
||||
|
@ -76,18 +81,18 @@ ipv4ll_pickaddr(struct arp_state *astate)
|
|||
((uint32_t)(r % 0xFD00) + 0x0100));
|
||||
|
||||
/* No point using a failed address */
|
||||
if (addr.s_addr == astate->failed.s_addr)
|
||||
continue;
|
||||
if (IN_ARE_ADDR_EQUAL(&addr, &state->pickedaddr))
|
||||
goto again;
|
||||
/* Ensure we don't have the address on another interface */
|
||||
} while (ipv4_findaddr(astate->iface->ctx, &addr) != NULL);
|
||||
} while (ipv4_findaddr(ifp->ctx, &addr) != NULL);
|
||||
|
||||
/* Restore the original random state */
|
||||
setstate(istate->arp->iface->ctx->randomstate);
|
||||
setstate(ifp->ctx->randomstate);
|
||||
return addr.s_addr;
|
||||
}
|
||||
|
||||
int
|
||||
ipv4ll_subnetroute(struct rt_head *routes, struct interface *ifp)
|
||||
ipv4ll_subnetroute(rb_tree_t *routes, struct interface *ifp)
|
||||
{
|
||||
struct ipv4ll_state *state;
|
||||
struct rt *rt;
|
||||
|
@ -108,12 +113,11 @@ ipv4ll_subnetroute(struct rt_head *routes, struct interface *ifp)
|
|||
in.s_addr = INADDR_ANY;
|
||||
sa_in_init(&rt->rt_gateway, &in);
|
||||
sa_in_init(&rt->rt_ifa, &state->addr->addr);
|
||||
TAILQ_INSERT_TAIL(routes, rt, rt_next);
|
||||
return 1;
|
||||
return rt_proto_add(routes, rt) ? 1 : 0;
|
||||
}
|
||||
|
||||
int
|
||||
ipv4ll_defaultroute(struct rt_head *routes, struct interface *ifp)
|
||||
ipv4ll_defaultroute(rb_tree_t *routes, struct interface *ifp)
|
||||
{
|
||||
struct ipv4ll_state *state;
|
||||
struct rt *rt;
|
||||
|
@ -132,12 +136,11 @@ ipv4ll_defaultroute(struct rt_head *routes, struct interface *ifp)
|
|||
sa_in_init(&rt->rt_netmask, &in);
|
||||
sa_in_init(&rt->rt_gateway, &in);
|
||||
sa_in_init(&rt->rt_ifa, &state->addr->addr);
|
||||
TAILQ_INSERT_TAIL(routes, rt, rt_next);
|
||||
return 1;
|
||||
return rt_proto_add(routes, rt) ? 1 : 0;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
ipv4ll_env(char **env, const char *prefix, const struct interface *ifp)
|
||||
ipv4ll_env(FILE *fp, const char *prefix, const struct interface *ifp)
|
||||
{
|
||||
const struct ipv4ll_state *state;
|
||||
const char *pf = prefix == NULL ? "" : "_";
|
||||
|
@ -147,185 +150,35 @@ ipv4ll_env(char **env, const char *prefix, const struct interface *ifp)
|
|||
if ((state = IPV4LL_CSTATE(ifp)) == NULL || state->addr == NULL)
|
||||
return 0;
|
||||
|
||||
if (env == NULL)
|
||||
return 5;
|
||||
|
||||
/* Emulate a DHCP environment */
|
||||
if (asprintf(&env[0], "%s%sip_address=%s",
|
||||
if (efprintf(fp, "%s%sip_address=%s",
|
||||
prefix, pf, inet_ntoa(state->addr->addr)) == -1)
|
||||
return -1;
|
||||
if (asprintf(&env[1], "%s%ssubnet_mask=%s",
|
||||
if (efprintf(fp, "%s%ssubnet_mask=%s",
|
||||
prefix, pf, inet_ntoa(state->addr->mask)) == -1)
|
||||
return -1;
|
||||
if (asprintf(&env[2], "%s%ssubnet_cidr=%d",
|
||||
if (efprintf(fp, "%s%ssubnet_cidr=%d",
|
||||
prefix, pf, inet_ntocidr(state->addr->mask)) == -1)
|
||||
return -1;
|
||||
if (asprintf(&env[3], "%s%sbroadcast_address=%s",
|
||||
if (efprintf(fp, "%s%sbroadcast_address=%s",
|
||||
prefix, pf, inet_ntoa(state->addr->brd)) == -1)
|
||||
return -1;
|
||||
netnum.s_addr = state->addr->addr.s_addr & state->addr->mask.s_addr;
|
||||
if (asprintf(&env[4], "%s%snetwork_number=%s",
|
||||
if (efprintf(fp, "%s%snetwork_number=%s",
|
||||
prefix, pf, inet_ntoa(netnum)) == -1)
|
||||
return -1;
|
||||
return 5;
|
||||
}
|
||||
|
||||
static void
|
||||
ipv4ll_probed(struct arp_state *astate)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct ipv4ll_state *state;
|
||||
struct ipv4_addr *ia;
|
||||
|
||||
assert(astate != NULL);
|
||||
assert(astate->iface != NULL);
|
||||
|
||||
ifp = astate->iface;
|
||||
state = IPV4LL_STATE(ifp);
|
||||
assert(state != NULL);
|
||||
|
||||
ia = ipv4_iffindaddr(ifp, &astate->addr, &inaddr_llmask);
|
||||
#ifdef IN_IFF_NOTREADY
|
||||
if (ia == NULL || ia->addr_flags & IN_IFF_NOTREADY)
|
||||
#endif
|
||||
loginfox("%s: using IPv4LL address %s",
|
||||
ifp->name, inet_ntoa(astate->addr));
|
||||
if (ia == NULL) {
|
||||
if (ifp->ctx->options & DHCPCD_TEST)
|
||||
goto test;
|
||||
ia = ipv4_addaddr(ifp, &astate->addr,
|
||||
&inaddr_llmask, &inaddr_llbcast);
|
||||
}
|
||||
if (ia == NULL)
|
||||
return;
|
||||
#ifdef IN_IFF_NOTREADY
|
||||
if (ia->addr_flags & IN_IFF_NOTREADY)
|
||||
return;
|
||||
logdebugx("%s: DAD completed for %s",
|
||||
ifp->name, inet_ntoa(astate->addr));
|
||||
#endif
|
||||
test:
|
||||
state->addr = ia;
|
||||
if (ifp->ctx->options & DHCPCD_TEST) {
|
||||
script_runreason(ifp, "TEST");
|
||||
eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
|
||||
return;
|
||||
}
|
||||
timespecclear(&state->defend);
|
||||
if_initrt(ifp->ctx, AF_INET);
|
||||
rt_build(ifp->ctx, AF_INET);
|
||||
arp_announce(astate);
|
||||
script_runreason(ifp, "IPV4LL");
|
||||
dhcpcd_daemonise(ifp->ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
ipv4ll_announced(struct arp_state *astate)
|
||||
ipv4ll_announced_arp(struct arp_state *astate)
|
||||
{
|
||||
struct ipv4ll_state *state = IPV4LL_STATE(astate->iface);
|
||||
|
||||
state->conflicts = 0;
|
||||
/* Need to keep the arp state so we can defend our IP. */
|
||||
}
|
||||
|
||||
static void
|
||||
ipv4ll_probe(void *arg)
|
||||
{
|
||||
|
||||
#ifdef IN_IFF_DUPLICATED
|
||||
ipv4ll_probed(arg);
|
||||
#else
|
||||
arp_probe(arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct ipv4ll_state *state;
|
||||
#ifdef IN_IFF_DUPLICATED
|
||||
struct ipv4_addr *ia;
|
||||
#endif
|
||||
|
||||
assert(astate != NULL);
|
||||
assert(astate->iface != NULL);
|
||||
ifp = astate->iface;
|
||||
state = IPV4LL_STATE(ifp);
|
||||
assert(state != NULL);
|
||||
|
||||
/*
|
||||
* NULL amsg means kernel detected DAD.
|
||||
* We always fail on matching sip.
|
||||
* We only fail on matching tip and we haven't added that address yet.
|
||||
*/
|
||||
if (amsg == NULL ||
|
||||
amsg->sip.s_addr == astate->addr.s_addr ||
|
||||
(amsg->sip.s_addr == 0 && amsg->tip.s_addr == astate->addr.s_addr
|
||||
&& ipv4_iffindaddr(ifp, &amsg->tip, NULL) == NULL))
|
||||
astate->failed = astate->addr;
|
||||
else
|
||||
return;
|
||||
|
||||
arp_report_conflicted(astate, amsg);
|
||||
|
||||
if (state->addr != NULL &&
|
||||
astate->failed.s_addr == state->addr->addr.s_addr)
|
||||
{
|
||||
#ifdef KERNEL_RFC5227
|
||||
logwarnx("%s: IPv4LL defence failed for %s",
|
||||
ifp->name, state->addr->saddr);
|
||||
#else
|
||||
struct timespec now, defend;
|
||||
|
||||
/* RFC 3927 Section 2.5 says a defence should
|
||||
* broadcast an ARP announcement.
|
||||
* Because the kernel will also unicast a reply to the
|
||||
* hardware address which requested the IP address
|
||||
* the other IPv4LL client will receieve two ARP
|
||||
* messages.
|
||||
* If another conflict happens within DEFEND_INTERVAL
|
||||
* then we must drop our address and negotiate a new one. */
|
||||
defend.tv_sec = state->defend.tv_sec + DEFEND_INTERVAL;
|
||||
defend.tv_nsec = state->defend.tv_nsec;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
if (timespeccmp(&defend, &now, >))
|
||||
logwarnx("%s: IPv4LL %d second defence failed for %s",
|
||||
ifp->name, DEFEND_INTERVAL, state->addr->saddr);
|
||||
else if (arp_request(ifp,
|
||||
state->addr->addr.s_addr, state->addr->addr.s_addr) == -1)
|
||||
logerr(__func__);
|
||||
else {
|
||||
logdebugx("%s: defended IPv4LL address %s",
|
||||
ifp->name, state->addr->saddr);
|
||||
state->defend = now;
|
||||
return;
|
||||
}
|
||||
arp_free(astate);
|
||||
#endif
|
||||
ipv4_deladdr(state->addr, 1);
|
||||
state->down = 1;
|
||||
state->addr = NULL;
|
||||
if_initrt(ifp->ctx, AF_INET);
|
||||
rt_build(ifp->ctx, AF_INET);
|
||||
script_runreason(ifp, "IPV4LL");
|
||||
}
|
||||
|
||||
#ifdef IN_IFF_DUPLICATED
|
||||
ia = ipv4_iffindaddr(ifp, &astate->addr, NULL);
|
||||
if (ia != NULL && ia->addr_flags & IN_IFF_DUPLICATED)
|
||||
ipv4_deladdr(ia, 1);
|
||||
#endif
|
||||
|
||||
arp_cancel(astate);
|
||||
if (++state->conflicts == MAX_CONFLICTS)
|
||||
logerr("%s: failed to acquire an IPv4LL address",
|
||||
ifp->name);
|
||||
state->pickedaddr.s_addr = ipv4ll_pickaddr(astate);
|
||||
astate->addr = state->pickedaddr;
|
||||
eloop_timeout_add_sec(ifp->ctx->eloop,
|
||||
state->conflicts >= MAX_CONFLICTS ?
|
||||
RATE_LIMIT_INTERVAL : PROBE_WAIT,
|
||||
ipv4ll_probe, astate);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -338,16 +191,144 @@ ipv4ll_arpfree(struct arp_state *astate)
|
|||
state->arp = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ipv4ll_start(void *arg)
|
||||
static void
|
||||
ipv4ll_not_found(struct interface *ifp)
|
||||
{
|
||||
struct ipv4ll_state *state;
|
||||
struct ipv4_addr *ia;
|
||||
#ifdef KERNEL_RFC5227
|
||||
struct arp_state *astate;
|
||||
#endif
|
||||
|
||||
state = IPV4LL_STATE(ifp);
|
||||
assert(state != NULL);
|
||||
|
||||
ia = ipv4_iffindaddr(ifp, &state->pickedaddr, &inaddr_llmask);
|
||||
#ifdef IN_IFF_NOTREADY
|
||||
if (ia == NULL || ia->addr_flags & IN_IFF_NOTREADY)
|
||||
#endif
|
||||
loginfox("%s: using IPv4LL address %s",
|
||||
ifp->name, inet_ntoa(state->pickedaddr));
|
||||
if (ia == NULL) {
|
||||
if (ifp->ctx->options & DHCPCD_TEST)
|
||||
goto test;
|
||||
ia = ipv4_addaddr(ifp, &state->pickedaddr,
|
||||
&inaddr_llmask, &inaddr_llbcast,
|
||||
DHCP_INFINITE_LIFETIME, DHCP_INFINITE_LIFETIME);
|
||||
}
|
||||
if (ia == NULL)
|
||||
return;
|
||||
#ifdef IN_IFF_NOTREADY
|
||||
if (ia->addr_flags & IN_IFF_NOTREADY)
|
||||
return;
|
||||
logdebugx("%s: DAD completed for %s", ifp->name, ia->saddr);
|
||||
#endif
|
||||
test:
|
||||
state->addr = ia;
|
||||
state->down = false;
|
||||
if (ifp->ctx->options & DHCPCD_TEST) {
|
||||
script_runreason(ifp, "TEST");
|
||||
eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
|
||||
return;
|
||||
}
|
||||
rt_build(ifp->ctx, AF_INET);
|
||||
#ifdef KERNEL_RFC5227
|
||||
astate = arp_new(ifp, &ia->addr);
|
||||
if (astate != NULL) {
|
||||
astate->announced_cb = ipv4ll_announced_arp;
|
||||
astate->free_cb = ipv4ll_arpfree;
|
||||
arp_announce(astate);
|
||||
}
|
||||
#else
|
||||
arp_announce(state->arp);
|
||||
#endif
|
||||
script_runreason(ifp, "IPV4LL");
|
||||
dhcpcd_daemonise(ifp->ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
ipv4ll_startifp(void *arg)
|
||||
{
|
||||
struct interface *ifp = arg;
|
||||
struct ipv4ll_state *state;
|
||||
|
||||
state = IPV4LL_STATE(ifp);
|
||||
ipv4ll_start1(ifp, state->arp);
|
||||
}
|
||||
|
||||
static void
|
||||
ipv4ll_found(struct interface *ifp)
|
||||
{
|
||||
struct ipv4ll_state *state = IPV4LL_STATE(ifp);
|
||||
|
||||
arp_cancel(state->arp);
|
||||
if (++state->conflicts == MAX_CONFLICTS)
|
||||
logerr("%s: failed to acquire an IPv4LL address",
|
||||
ifp->name);
|
||||
eloop_timeout_add_sec(ifp->ctx->eloop,
|
||||
state->conflicts >= MAX_CONFLICTS ?
|
||||
RATE_LIMIT_INTERVAL : PROBE_WAIT,
|
||||
ipv4ll_startifp, ifp);
|
||||
}
|
||||
|
||||
static void
|
||||
ipv4ll_defend_failed(struct interface *ifp)
|
||||
{
|
||||
struct ipv4ll_state *state = IPV4LL_STATE(ifp);
|
||||
|
||||
ipv4_deladdr(state->addr, 1);
|
||||
state->down = true;
|
||||
state->addr = NULL;
|
||||
rt_build(ifp->ctx, AF_INET);
|
||||
script_runreason(ifp, "IPV4LL");
|
||||
ipv4ll_start1(ifp, state->arp);
|
||||
}
|
||||
|
||||
#ifndef KERNEL_RFC5227
|
||||
static void
|
||||
ipv4ll_not_found_arp(struct arp_state *astate)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct ipv4ll_state *state;
|
||||
struct arp_state *astate;
|
||||
struct ipv4_addr *ia;
|
||||
|
||||
assert(arg != NULL);
|
||||
ifp = arg;
|
||||
assert(astate != NULL);
|
||||
assert(astate->iface != NULL);
|
||||
|
||||
ifp = astate->iface;
|
||||
state = IPV4LL_STATE(ifp);
|
||||
assert(state != NULL);
|
||||
assert(state->arp == astate);
|
||||
ipv4ll_not_found_arp(astate);
|
||||
}
|
||||
|
||||
static void
|
||||
ipv4ll_found_arp(struct arp_state *astate, __unused const struct arp_msg *amsg)
|
||||
{
|
||||
struct interface *ifp = astate->iface;
|
||||
struct ipv4ll_state *state = IPV4LL_STATE(ifp);
|
||||
|
||||
assert(state->arp == astate);
|
||||
ipv4ll_found(ifp);
|
||||
}
|
||||
|
||||
static void
|
||||
ipv4ll_defend_failed_arp(struct arp_state *astate)
|
||||
{
|
||||
struct ipv4ll_state *state = IPV4LL_STATE(astate->iface);
|
||||
|
||||
assert(state->arp == astate);
|
||||
ipv4ll_defend_failed(astate->iface);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
ipv4ll_start1(struct interface *ifp, struct arp_state *astate)
|
||||
{
|
||||
struct ipv4ll_state *state;
|
||||
struct ipv4_addr *ia;
|
||||
bool repick;
|
||||
|
||||
assert(ifp != NULL);
|
||||
if ((state = IPV4LL_STATE(ifp)) == NULL) {
|
||||
ifp->if_data[IF_DATA_IPV4LL] = calloc(1, sizeof(*state));
|
||||
if ((state = IPV4LL_STATE(ifp)) == NULL) {
|
||||
|
@ -383,16 +364,25 @@ ipv4ll_start(void *arg)
|
|||
state->seeded = true;
|
||||
}
|
||||
|
||||
if (state->arp != NULL)
|
||||
return;
|
||||
if ((astate = arp_new(ifp, NULL)) == NULL)
|
||||
return;
|
||||
#ifndef KERNEL_RFC5227
|
||||
if (astate == NULL) {
|
||||
if (state->arp != NULL)
|
||||
return;
|
||||
if ((astate = arp_new(ifp, NULL)) == NULL)
|
||||
return;
|
||||
astate->found_cb = ipv4ll_found_arp;
|
||||
astate->not_found_cb = ipv4ll_not_found_arp;
|
||||
astate->announced_cb = ipv4ll_announced_arp;
|
||||
astate->defend_failed_cb = ipv4ll_defend_failed_arp;
|
||||
astate->free_cb = ipv4ll_arpfree;
|
||||
state->arp = astate;
|
||||
} else
|
||||
assert(state->arp == astate);
|
||||
#else
|
||||
UNUSED(astate);
|
||||
#endif
|
||||
|
||||
state->arp = astate;
|
||||
astate->probed_cb = ipv4ll_probed;
|
||||
astate->announced_cb = ipv4ll_announced;
|
||||
astate->conflicted_cb = ipv4ll_conflicted;
|
||||
astate->free_cb = ipv4ll_arpfree;
|
||||
state->down = true;
|
||||
|
||||
/* Find the previosuly used address. */
|
||||
if (state->pickedaddr.s_addr != INADDR_ANY)
|
||||
|
@ -404,15 +394,22 @@ ipv4ll_start(void *arg)
|
|||
if (ia == NULL)
|
||||
ia = ipv4_iffindlladdr(ifp);
|
||||
|
||||
repick = false;
|
||||
#ifdef IN_IFF_DUPLICATED
|
||||
if (ia != NULL && ia->addr_flags & IN_IFF_DUPLICATED) {
|
||||
state->pickedaddr = ia->addr; /* So it's not picked again. */
|
||||
repick = true;
|
||||
ipv4_deladdr(ia, 0);
|
||||
ia = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
state->addr = ia;
|
||||
if (ia != NULL) {
|
||||
state->pickedaddr = astate->addr = ia->addr;
|
||||
state->pickedaddr = ia->addr;
|
||||
#ifndef KERNEL_RFC5227
|
||||
astate->addr = ia->addr;
|
||||
#endif
|
||||
#ifdef IN_IFF_TENTATIVE
|
||||
if (ia->addr_flags & (IN_IFF_TENTATIVE | IN_IFF_DETACHED)) {
|
||||
loginfox("%s: waiting for DAD to complete on %s",
|
||||
|
@ -423,21 +420,30 @@ ipv4ll_start(void *arg)
|
|||
#ifdef IN_IFF_DUPLICATED
|
||||
loginfox("%s: using IPv4LL address %s", ifp->name, ia->saddr);
|
||||
#endif
|
||||
ipv4ll_probed(astate);
|
||||
ipv4ll_not_found(ifp);
|
||||
return;
|
||||
}
|
||||
|
||||
loginfox("%s: probing for an IPv4LL address", ifp->name);
|
||||
if (state->pickedaddr.s_addr == INADDR_ANY)
|
||||
state->pickedaddr.s_addr = ipv4ll_pickaddr(astate);
|
||||
if (repick || state->pickedaddr.s_addr == INADDR_ANY)
|
||||
state->pickedaddr.s_addr = ipv4ll_pickaddr(ifp);
|
||||
#ifndef KERNEL_RFC5227
|
||||
astate->addr = state->pickedaddr;
|
||||
#endif
|
||||
#ifdef IN_IFF_DUPLICATED
|
||||
ipv4ll_probed(astate);
|
||||
ipv4ll_not_found(ifp);
|
||||
#else
|
||||
arp_probe(astate);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ipv4ll_start(void *arg)
|
||||
{
|
||||
|
||||
ipv4ll_start1(arg, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
ipv4ll_freearp(struct interface *ifp)
|
||||
{
|
||||
|
@ -449,7 +455,6 @@ ipv4ll_freearp(struct interface *ifp)
|
|||
|
||||
eloop_timeout_delete(ifp->ctx->eloop, NULL, state->arp);
|
||||
arp_free(state->arp);
|
||||
state->arp = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -463,9 +468,7 @@ ipv4ll_drop(struct interface *ifp)
|
|||
|
||||
ipv4ll_freearp(ifp);
|
||||
|
||||
#ifndef IN_IFF_TENATIVE
|
||||
if ((ifp->options->options & DHCPCD_NODROP) == DHCPCD_NODROP)
|
||||
#endif
|
||||
return;
|
||||
|
||||
state = IPV4LL_STATE(ifp);
|
||||
|
@ -524,10 +527,6 @@ ipv4ll_recvrt(__unused int cmd, const struct rt *rt)
|
|||
struct dhcpcd_ctx *ctx;
|
||||
struct interface *ifp;
|
||||
|
||||
/* Ignore route init. */
|
||||
if (rt->rt_dflags & RTDF_INIT)
|
||||
return 0;
|
||||
|
||||
/* Only interested in default route changes. */
|
||||
if (sa_is_unspecified(&rt->rt_dest))
|
||||
return 0;
|
||||
|
@ -536,7 +535,6 @@ ipv4ll_recvrt(__unused int cmd, const struct rt *rt)
|
|||
ctx = rt->rt_ifp->ctx;
|
||||
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
|
||||
if (IPV4LL_STATE_RUNNING(ifp)) {
|
||||
if_initrt(ctx, AF_INET);
|
||||
rt_build(ctx, AF_INET);
|
||||
break;
|
||||
}
|
||||
|
@ -545,4 +543,34 @@ ipv4ll_recvrt(__unused int cmd, const struct rt *rt)
|
|||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
ipv4ll_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct ipv4ll_state *state;
|
||||
|
||||
ifp = ia->iface;
|
||||
state = IPV4LL_STATE(ifp);
|
||||
if (state == NULL || state->addr == NULL ||
|
||||
!IN_ARE_ADDR_EQUAL(&state->addr->addr, &ia->addr))
|
||||
return;
|
||||
|
||||
if (cmd == RTM_DELADDR) {
|
||||
loginfox("%s: pid %d deleted IP address %s",
|
||||
ifp->name, pid, ia->saddr);
|
||||
ipv4ll_defend_failed(ifp);
|
||||
}
|
||||
|
||||
#ifdef IN_IFF_DUPLICATED
|
||||
if (cmd != RTM_NEWADDR)
|
||||
return;
|
||||
if (!(ia->addr_flags & IN_IFF_NOTUSEABLE))
|
||||
ipv4ll_not_found(ifp);
|
||||
else if (ia->addr_flags & IN_IFF_DUPLICATED) {
|
||||
logerrx("%s: DAD detected %s", ifp->name, ia->saddr);
|
||||
ipv4_deladdr(state->addr, 1);
|
||||
ipv4ll_found(ifp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -43,11 +44,10 @@ struct ipv4ll_state {
|
|||
struct in_addr pickedaddr;
|
||||
struct ipv4_addr *addr;
|
||||
struct arp_state *arp;
|
||||
unsigned int conflicts;
|
||||
struct timespec defend;
|
||||
char randomstate[128];
|
||||
bool seeded;
|
||||
uint8_t down;
|
||||
bool down;
|
||||
size_t conflicts;
|
||||
};
|
||||
|
||||
#define IPV4LL_STATE(ifp) \
|
||||
|
@ -58,12 +58,13 @@ struct ipv4ll_state {
|
|||
(IPV4LL_CSTATE((ifp)) && !IPV4LL_CSTATE((ifp))->down && \
|
||||
(IPV4LL_CSTATE((ifp))->addr != NULL))
|
||||
|
||||
int ipv4ll_subnetroute(struct rt_head *, struct interface *);
|
||||
int ipv4ll_defaultroute(struct rt_head *,struct interface *);
|
||||
ssize_t ipv4ll_env(char **, const char *, const struct interface *);
|
||||
int ipv4ll_subnetroute(rb_tree_t *, struct interface *);
|
||||
int ipv4ll_defaultroute(rb_tree_t *,struct interface *);
|
||||
ssize_t ipv4ll_env(FILE *, const char *, const struct interface *);
|
||||
void ipv4ll_start(void *);
|
||||
void ipv4ll_claimed(void *);
|
||||
void ipv4ll_handle_failure(void *);
|
||||
void ipv4ll_handleifa(int, struct ipv4_addr *, pid_t pid);
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
int ipv4ll_recvrt(int, const struct rt *);
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -1540,23 +1541,17 @@ ipv6_staticdadcallback(void *arg)
|
|||
}
|
||||
|
||||
ssize_t
|
||||
ipv6_env(char **env, const char *prefix, const struct interface *ifp)
|
||||
ipv6_env(FILE *fp, const char *prefix, const struct interface *ifp)
|
||||
{
|
||||
char **ep;
|
||||
ssize_t n;
|
||||
struct ipv6_addr *ia;
|
||||
|
||||
ep = env;
|
||||
n = 0;
|
||||
ia = ipv6_iffindaddr(UNCONST(ifp), &ifp->options->req_addr6,
|
||||
IN6_IFF_NOTUSEABLE);
|
||||
if (ia) {
|
||||
if (env)
|
||||
addvar(&ep, prefix, "ip6_address", ia->saddr);
|
||||
n++;
|
||||
}
|
||||
|
||||
return n;
|
||||
if (ia == NULL)
|
||||
return 0;
|
||||
if (efprintf(fp, "%s_ip6_address=%s", prefix, ia->saddr) == -1)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1612,7 +1607,6 @@ ipv6_startstatic(struct interface *ifp)
|
|||
ia->prefix_pltime = ND6_INFINITE_LIFETIME;
|
||||
ia->dadcallback = ipv6_staticdadcallback;
|
||||
ipv6_addaddr(ia, NULL);
|
||||
if_initrt(ifp->ctx, AF_INET6);
|
||||
rt_build(ifp->ctx, AF_INET6);
|
||||
if (run_script)
|
||||
script_runreason(ifp, "STATIC6");
|
||||
|
@ -1654,8 +1648,6 @@ ipv6_start(struct interface *ifp)
|
|||
ipv6_regentempifid(ifp);
|
||||
}
|
||||
|
||||
/* Load existing routes */
|
||||
if_initrt(ifp->ctx, AF_INET6);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1679,10 +1671,8 @@ ipv6_freedrop(struct interface *ifp, int drop)
|
|||
|
||||
ipv6_freedrop_addrs(&state->addrs, drop ? 2 : 0, NULL);
|
||||
if (drop) {
|
||||
if (ifp->ctx->ra_routers != NULL) {
|
||||
if_initrt(ifp->ctx, AF_INET6);
|
||||
if (ifp->ctx->ra_routers != NULL)
|
||||
rt_build(ifp->ctx, AF_INET6);
|
||||
}
|
||||
} else {
|
||||
/* Because we need to cache the addresses we don't control,
|
||||
* we only free the state on when NOT dropping addresses. */
|
||||
|
@ -2216,7 +2206,7 @@ inet6_makerouter(struct ra *rap)
|
|||
IN6_ARE_ADDR_EQUAL(&((rtp)->mask), &in6addr_any))
|
||||
|
||||
static int
|
||||
inet6_staticroutes(struct rt_head *routes, struct dhcpcd_ctx *ctx)
|
||||
inet6_staticroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct ipv6_state *state;
|
||||
|
@ -2232,7 +2222,7 @@ inet6_staticroutes(struct rt_head *routes, struct dhcpcd_ctx *ctx)
|
|||
{
|
||||
rt = inet6_makeprefix(ifp, NULL, ia);
|
||||
if (rt)
|
||||
TAILQ_INSERT_TAIL(routes, rt, rt_next);
|
||||
rt_proto_add(routes, rt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2240,15 +2230,14 @@ inet6_staticroutes(struct rt_head *routes, struct dhcpcd_ctx *ctx)
|
|||
}
|
||||
|
||||
static int
|
||||
inet6_raroutes(struct rt_head *routes, struct dhcpcd_ctx *ctx, int expired,
|
||||
bool *have_default)
|
||||
inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
|
||||
{
|
||||
struct rt *rt;
|
||||
struct ra *rap;
|
||||
const struct ipv6_addr *addr;
|
||||
|
||||
TAILQ_FOREACH(rap, ctx->ra_routers, next) {
|
||||
if (rap->expired != expired)
|
||||
if (rap->expired)
|
||||
continue;
|
||||
TAILQ_FOREACH(addr, &rap->addrs, next) {
|
||||
if (addr->prefix_vltime == 0)
|
||||
|
@ -2256,25 +2245,23 @@ inet6_raroutes(struct rt_head *routes, struct dhcpcd_ctx *ctx, int expired,
|
|||
rt = inet6_makeprefix(rap->iface, rap, addr);
|
||||
if (rt) {
|
||||
rt->rt_dflags |= RTDF_RA;
|
||||
TAILQ_INSERT_TAIL(routes, rt, rt_next);
|
||||
}
|
||||
}
|
||||
if (rap->lifetime) {
|
||||
rt = inet6_makerouter(rap);
|
||||
if (rt) {
|
||||
rt->rt_dflags |= RTDF_RA;
|
||||
TAILQ_INSERT_TAIL(routes, rt, rt_next);
|
||||
if (have_default)
|
||||
*have_default = true;
|
||||
rt_proto_add(routes, rt);
|
||||
}
|
||||
}
|
||||
if (rap->lifetime == 0)
|
||||
continue;
|
||||
rt = inet6_makerouter(rap);
|
||||
if (rt == NULL)
|
||||
continue;
|
||||
rt->rt_dflags |= RTDF_RA;
|
||||
rt_proto_add(routes, rt);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DHCP6
|
||||
static int
|
||||
inet6_dhcproutes(struct rt_head *routes, struct dhcpcd_ctx *ctx,
|
||||
inet6_dhcproutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx,
|
||||
enum DH6S dstate)
|
||||
{
|
||||
struct interface *ifp;
|
||||
|
@ -2287,10 +2274,10 @@ inet6_dhcproutes(struct rt_head *routes, struct dhcpcd_ctx *ctx,
|
|||
if (d6_state && d6_state->state == dstate) {
|
||||
TAILQ_FOREACH(addr, &d6_state->addrs, next) {
|
||||
rt = inet6_makeprefix(ifp, NULL, addr);
|
||||
if (rt) {
|
||||
rt->rt_dflags |= RTDF_DHCP;
|
||||
TAILQ_INSERT_TAIL(routes, rt, rt_next);
|
||||
}
|
||||
if (rt == NULL)
|
||||
continue;
|
||||
rt->rt_dflags |= RTDF_DHCP;
|
||||
rt_proto_add(routes, rt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2299,44 +2286,26 @@ inet6_dhcproutes(struct rt_head *routes, struct dhcpcd_ctx *ctx,
|
|||
#endif
|
||||
|
||||
bool
|
||||
inet6_getroutes(struct dhcpcd_ctx *ctx, struct rt_head *routes)
|
||||
inet6_getroutes(struct dhcpcd_ctx *ctx, rb_tree_t *routes)
|
||||
{
|
||||
bool have_default;
|
||||
|
||||
/* Should static take priority? */
|
||||
if (inet6_staticroutes(routes, ctx) == -1)
|
||||
return false;
|
||||
|
||||
/* First add reachable routers and their prefixes */
|
||||
have_default = false;
|
||||
if (inet6_raroutes(routes, ctx, 0, &have_default) == -1)
|
||||
if (inet6_raroutes(routes, ctx) == -1)
|
||||
return false;
|
||||
|
||||
#ifdef DHCP6
|
||||
/* We have no way of knowing if prefixes added by DHCP are reachable
|
||||
* or not, so we have to assume they are.
|
||||
* Add bound before delegated so we can prefer interfaces better */
|
||||
* Add bound before delegated so we can prefer interfaces better. */
|
||||
if (inet6_dhcproutes(routes, ctx, DH6S_BOUND) == -1)
|
||||
return false;
|
||||
if (inet6_dhcproutes(routes, ctx, DH6S_DELEGATED) == -1)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
/* If we have an unreachable router, we really do need to remove the
|
||||
* route to it beause it could be a lower metric than a reachable
|
||||
* router. Of course, we should at least have some routers if all
|
||||
* are unreachable. */
|
||||
if (!have_default) {
|
||||
#endif
|
||||
/* Add our non-reachable routers and prefixes
|
||||
* Unsure if this is needed, but it's a close match to kernel
|
||||
* behaviour */
|
||||
if (inet6_raroutes(routes, ctx, 1, NULL) == -1)
|
||||
return false;
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -287,9 +288,9 @@ void ipv6_addtempaddrs(struct interface *, const struct timespec *);
|
|||
int ipv6_start(struct interface *);
|
||||
int ipv6_staticdadcompleted(const struct interface *);
|
||||
int ipv6_startstatic(struct interface *);
|
||||
ssize_t ipv6_env(char **, const char *, const struct interface *);
|
||||
ssize_t ipv6_env(FILE *, const char *, const struct interface *);
|
||||
void ipv6_ctxfree(struct dhcpcd_ctx *);
|
||||
bool inet6_getroutes(struct dhcpcd_ctx *, struct rt_head *);
|
||||
bool inet6_getroutes(struct dhcpcd_ctx *, rb_tree_t *);
|
||||
#endif /* INET6 */
|
||||
|
||||
#endif /* INET6_H */
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - IPv6 ND handling
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -105,6 +106,9 @@ __CTASSERT(sizeof(struct nd_opt_rdnss) == 8);
|
|||
#define RTPREF_RESERVED (-2)
|
||||
#define RTPREF_INVALID (-3) /* internal */
|
||||
|
||||
#define EXPIRED_MAX 5 /* Remember 5 expired routers to avoid
|
||||
logspam. */
|
||||
|
||||
#define MIN_RANDOM_FACTOR 500 /* millisecs */
|
||||
#define MAX_RANDOM_FACTOR 1500 /* millisecs */
|
||||
#define MIN_RANDOM_FACTOR_U MIN_RANDOM_FACTOR * 1000 /* usecs */
|
||||
|
@ -462,7 +466,6 @@ ipv6nd_advertise(struct ipv6_addr *ia)
|
|||
return;
|
||||
|
||||
ctx = ia->iface->ctx;
|
||||
if_sortinterfaces(ctx);
|
||||
/* Find the most preferred address to advertise. */
|
||||
iaf = NULL;
|
||||
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
|
||||
|
@ -483,7 +486,8 @@ ipv6nd_advertise(struct ipv6_addr *ia)
|
|||
iap->addr_flags & IN6_IFF_NOTUSEABLE)
|
||||
continue;
|
||||
|
||||
if (iaf == NULL)
|
||||
if (iaf == NULL ||
|
||||
iaf->iface->metric > iap->iface->metric)
|
||||
iaf = iap;
|
||||
}
|
||||
}
|
||||
|
@ -523,46 +527,34 @@ ipv6nd_advertise(struct ipv6_addr *ia)
|
|||
ipv6nd_sendadvertisement(iaf);
|
||||
}
|
||||
|
||||
void
|
||||
ipv6nd_expire(struct interface *ifp, uint32_t seconds)
|
||||
static void
|
||||
ipv6nd_expire(void *arg)
|
||||
{
|
||||
struct interface *ifp = arg;
|
||||
struct ra *rap;
|
||||
struct timespec now;
|
||||
uint32_t vltime = seconds;
|
||||
uint32_t pltime = seconds / 2;
|
||||
struct ipv6_addr *ia;
|
||||
struct timespec now = { .tv_sec = 1 };
|
||||
|
||||
if (ifp->ctx->ra_routers == NULL)
|
||||
return;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
|
||||
if (rap->iface == ifp) {
|
||||
rap->acquired = now;
|
||||
rap->expired = seconds ? 0 : 1;
|
||||
if (seconds) {
|
||||
struct ipv6_addr *ia;
|
||||
|
||||
rap->lifetime = seconds;
|
||||
TAILQ_FOREACH(ia, &rap->addrs, next) {
|
||||
if (ia->prefix_pltime > pltime ||
|
||||
ia->prefix_vltime > vltime)
|
||||
{
|
||||
ia->acquired = now;
|
||||
if (ia->prefix_pltime != 0)
|
||||
ia->prefix_pltime =
|
||||
pltime;
|
||||
ia->prefix_vltime = vltime;
|
||||
}
|
||||
}
|
||||
ipv6_addaddrs(&rap->addrs);
|
||||
}
|
||||
if (rap->iface == ifp)
|
||||
continue;
|
||||
rap->acquired = now;
|
||||
TAILQ_FOREACH(ia, &rap->addrs, next) {
|
||||
ia->acquired = now;
|
||||
}
|
||||
}
|
||||
if (seconds)
|
||||
ipv6nd_expirera(ifp);
|
||||
else
|
||||
rt_build(ifp->ctx, AF_INET6);
|
||||
ipv6nd_expirera(ifp);
|
||||
}
|
||||
|
||||
void
|
||||
ipv6nd_startexpire(struct interface *ifp)
|
||||
{
|
||||
|
||||
eloop_timeout_add_sec(ifp->ctx->eloop, RTR_CARRIER_EXPIRE,
|
||||
ipv6nd_expire, ifp);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1228,6 +1220,10 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
|
|||
break;
|
||||
|
||||
case ND_OPT_MTU:
|
||||
if (len < sizeof(mtu)) {
|
||||
logerrx("%s: short MTU option", ifp->name);
|
||||
break;
|
||||
}
|
||||
memcpy(&mtu, p, sizeof(mtu));
|
||||
mtu.nd_opt_mtu_mtu = ntohl(mtu.nd_opt_mtu_mtu);
|
||||
if (mtu.nd_opt_mtu_mtu < IPV6_MMTU) {
|
||||
|
@ -1239,6 +1235,10 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
|
|||
break;
|
||||
|
||||
case ND_OPT_RDNSS:
|
||||
if (len < sizeof(rdnss)) {
|
||||
logerrx("%s: short RDNSS option", ifp->name);
|
||||
break;
|
||||
}
|
||||
memcpy(&rdnss, p, sizeof(rdnss));
|
||||
if (rdnss.nd_opt_rdnss_lifetime &&
|
||||
rdnss.nd_opt_rdnss_len > 1)
|
||||
|
@ -1278,11 +1278,6 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
|
|||
ipv6_addtempaddrs(ifp, &rap->acquired);
|
||||
#endif
|
||||
|
||||
/* Find any freshly added routes, such as the subnet route.
|
||||
* We do this because we cannot rely on recieving the kernel
|
||||
* notification right now via our link socket. */
|
||||
if_initrt(ifp->ctx, AF_INET6);
|
||||
|
||||
rt_build(ifp->ctx, AF_INET6);
|
||||
if (ipv6nd_scriptrun(rap))
|
||||
return;
|
||||
|
@ -1390,11 +1385,11 @@ ipv6nd_getoption(struct dhcpcd_ctx *ctx,
|
|||
}
|
||||
|
||||
ssize_t
|
||||
ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
|
||||
ipv6nd_env(FILE *fp, const struct interface *ifp)
|
||||
{
|
||||
size_t i, j, n, len, olen;
|
||||
struct ra *rap;
|
||||
char ndprefix[32], abuf[24];
|
||||
char ndprefix[32];
|
||||
struct dhcp_opt *opt;
|
||||
uint8_t *p;
|
||||
struct nd_opt_hdr ndo;
|
||||
|
@ -1407,34 +1402,25 @@ ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
|
|||
if (rap->iface != ifp)
|
||||
continue;
|
||||
i++;
|
||||
if (prefix != NULL)
|
||||
snprintf(ndprefix, sizeof(ndprefix),
|
||||
"%s_nd%zu", prefix, i);
|
||||
else
|
||||
snprintf(ndprefix, sizeof(ndprefix),
|
||||
"nd%zu", i);
|
||||
if (env)
|
||||
setvar(&env[n], ndprefix, "from", rap->sfrom);
|
||||
n++;
|
||||
if (env)
|
||||
setvard(&env[n], ndprefix, "acquired",
|
||||
(size_t)rap->acquired.tv_sec);
|
||||
n++;
|
||||
if (env)
|
||||
setvard(&env[n], ndprefix, "now", (size_t)now.tv_sec);
|
||||
n++;
|
||||
snprintf(ndprefix, sizeof(ndprefix), "nd%zu", i);
|
||||
if (efprintf(fp, "%s_from=%s", ndprefix, rap->sfrom) == -1)
|
||||
return -1;
|
||||
if (efprintf(fp, "%s_acquired=%lld", ndprefix,
|
||||
(long long)rap->acquired.tv_sec) == -1)
|
||||
return -1;
|
||||
if (efprintf(fp, "%s_now=%lld", ndprefix,
|
||||
(long long)now.tv_sec) == -1)
|
||||
return -1;
|
||||
|
||||
/* Zero our indexes */
|
||||
if (env) {
|
||||
for (j = 0, opt = rap->iface->ctx->nd_opts;
|
||||
j < rap->iface->ctx->nd_opts_len;
|
||||
j++, opt++)
|
||||
dhcp_zero_index(opt);
|
||||
for (j = 0, opt = rap->iface->options->nd_override;
|
||||
j < rap->iface->options->nd_override_len;
|
||||
j++, opt++)
|
||||
dhcp_zero_index(opt);
|
||||
}
|
||||
for (j = 0, opt = rap->iface->ctx->nd_opts;
|
||||
j < rap->iface->ctx->nd_opts_len;
|
||||
j++, opt++)
|
||||
dhcp_zero_index(opt);
|
||||
for (j = 0, opt = rap->iface->options->nd_override;
|
||||
j < rap->iface->options->nd_override_len;
|
||||
j++, opt++)
|
||||
dhcp_zero_index(opt);
|
||||
|
||||
/* Unlike DHCP, ND6 options *may* occur more than once.
|
||||
* There is also no provision for option concatenation
|
||||
|
@ -1467,34 +1453,31 @@ ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
|
|||
if (j == rap->iface->ctx->nd_opts_len)
|
||||
opt = NULL;
|
||||
}
|
||||
if (opt) {
|
||||
n += dhcp_envoption(rap->iface->ctx,
|
||||
env == NULL ? NULL : &env[n],
|
||||
ndprefix, rap->iface->name,
|
||||
opt, ipv6nd_getoption,
|
||||
p + sizeof(ndo), olen - sizeof(ndo));
|
||||
}
|
||||
if (opt == NULL)
|
||||
continue;
|
||||
dhcp_envoption(rap->iface->ctx, fp,
|
||||
ndprefix, rap->iface->name,
|
||||
opt, ipv6nd_getoption,
|
||||
p + sizeof(ndo), olen - sizeof(ndo));
|
||||
}
|
||||
|
||||
/* We need to output the addresses we actually made
|
||||
* from the prefix information options as well. */
|
||||
j = 0;
|
||||
TAILQ_FOREACH(ia, &rap->addrs, next) {
|
||||
if (!(ia->flags & IPV6_AF_AUTOCONF)
|
||||
if (!(ia->flags & IPV6_AF_AUTOCONF) ||
|
||||
#ifdef IPV6_AF_TEMPORARY
|
||||
|| ia->flags & IPV6_AF_TEMPORARY
|
||||
ia->flags & IPV6_AF_TEMPORARY ||
|
||||
#endif
|
||||
)
|
||||
!(ia->flags & IPV6_AF_ADDED) ||
|
||||
ia->prefix_vltime == 0)
|
||||
continue;
|
||||
j++;
|
||||
if (env) {
|
||||
snprintf(abuf, sizeof(abuf), "addr%zu", j);
|
||||
setvar(&env[n], ndprefix, abuf, ia->saddr);
|
||||
}
|
||||
n++;
|
||||
if (efprintf(fp, "%s_addr%zu=%s",
|
||||
ndprefix, j++, ia->saddr) == -1)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return (ssize_t)n;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1522,6 +1505,16 @@ ipv6nd_expirera(void *arg)
|
|||
struct timespec now, lt, expire, next;
|
||||
bool expired, valid, validone;
|
||||
struct ipv6_addr *ia;
|
||||
size_t len, olen;
|
||||
uint8_t *p;
|
||||
struct nd_opt_hdr ndo;
|
||||
#if 0
|
||||
struct nd_opt_prefix_info pi;
|
||||
#endif
|
||||
struct nd_opt_dnssl dnssl;
|
||||
struct nd_opt_rdnss rdnss;
|
||||
uint32_t ltime;
|
||||
size_t nexpired = 0;
|
||||
|
||||
ifp = arg;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
@ -1536,8 +1529,7 @@ ipv6nd_expirera(void *arg)
|
|||
lt.tv_sec = (time_t)rap->lifetime;
|
||||
lt.tv_nsec = 0;
|
||||
timespecadd(&rap->acquired, <, &expire);
|
||||
if (rap->lifetime == 0 || timespeccmp(&now, &expire, >))
|
||||
{
|
||||
if (timespeccmp(&now, &expire, >)) {
|
||||
if (!rap->expired) {
|
||||
logwarnx("%s: %s: router expired",
|
||||
ifp->name, rap->sfrom);
|
||||
|
@ -1588,14 +1580,79 @@ ipv6nd_expirera(void *arg)
|
|||
}
|
||||
}
|
||||
|
||||
/* XXX FixMe!
|
||||
* We need to extract the lifetime from each option and check
|
||||
* if that has expired or not.
|
||||
* If it has, zero the option out in the returned data. */
|
||||
/* Work out expiry for ND options */
|
||||
len = rap->data_len - sizeof(struct nd_router_advert);
|
||||
for (p = rap->data + sizeof(struct nd_router_advert);
|
||||
len >= sizeof(ndo);
|
||||
p += olen, len -= olen)
|
||||
{
|
||||
memcpy(&ndo, p, sizeof(ndo));
|
||||
olen = (size_t)(ndo.nd_opt_len * 8);
|
||||
if (olen > len) {
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* No valid lifetimes are left on the RA, so we might
|
||||
* as well punt it. */
|
||||
if (!valid && !validone)
|
||||
if (has_option_mask(rap->iface->options->nomasknd,
|
||||
ndo.nd_opt_type))
|
||||
continue;
|
||||
|
||||
switch (ndo.nd_opt_type) {
|
||||
/* Prefix info is already checked in the above loop. */
|
||||
#if 0
|
||||
case ND_OPT_PREFIX_INFORMATION:
|
||||
if (len < sizeof(pi))
|
||||
break;
|
||||
memcpy(&pi, p, sizeof(pi));
|
||||
ltime = pi.nd_opt_pi_valid_time;
|
||||
break;
|
||||
#endif
|
||||
case ND_OPT_DNSSL:
|
||||
if (len < sizeof(dnssl))
|
||||
continue;
|
||||
memcpy(&dnssl, p, sizeof(dnssl));
|
||||
ltime = dnssl.nd_opt_dnssl_lifetime;
|
||||
break;
|
||||
case ND_OPT_RDNSS:
|
||||
if (len < sizeof(rdnss))
|
||||
continue;
|
||||
memcpy(&rdnss, p, sizeof(rdnss));
|
||||
ltime = rdnss.nd_opt_rdnss_lifetime;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ltime == 0)
|
||||
continue;
|
||||
if (ltime == ND6_INFINITE_LIFETIME) {
|
||||
validone = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
lt.tv_sec = (time_t)ntohl(ltime);
|
||||
lt.tv_nsec = 0;
|
||||
timespecadd(&rap->acquired, <, &expire);
|
||||
if (timespeccmp(&now, &expire, >)) {
|
||||
expired = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
timespecsub(&expire, &now, <);
|
||||
if (!timespecisset(&next) ||
|
||||
timespeccmp(&next, <, >))
|
||||
{
|
||||
next = lt;
|
||||
validone = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid || validone)
|
||||
continue;
|
||||
|
||||
/* Router has expired. Let's not keep a lot of them.
|
||||
* We should work out if all the options have expired .... */
|
||||
if (++nexpired > EXPIRED_MAX)
|
||||
ipv6nd_free_ra(rap);
|
||||
}
|
||||
|
||||
|
@ -1603,6 +1660,7 @@ ipv6nd_expirera(void *arg)
|
|||
eloop_timeout_add_tv(ifp->ctx->eloop,
|
||||
&next, ipv6nd_expirera, ifp);
|
||||
if (expired) {
|
||||
logwarnx("%s: part of Router Advertisement expired", ifp->name);
|
||||
rt_build(ifp->ctx, AF_INET6);
|
||||
script_runreason(ifp, "ROUTERADVERT");
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - IPv6 ND handling
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -95,7 +96,7 @@ struct rs_state {
|
|||
void ipv6nd_printoptions(const struct dhcpcd_ctx *,
|
||||
const struct dhcp_opt *, size_t);
|
||||
void ipv6nd_startrs(struct interface *);
|
||||
ssize_t ipv6nd_env(char **, const char *, const struct interface *);
|
||||
ssize_t ipv6nd_env(FILE *, const struct interface *);
|
||||
const struct ipv6_addr *ipv6nd_iffindaddr(const struct interface *ifp,
|
||||
const struct in6_addr *addr, unsigned int flags);
|
||||
struct ipv6_addr *ipv6nd_findaddr(struct dhcpcd_ctx *,
|
||||
|
@ -107,7 +108,7 @@ int ipv6nd_hasradhcp(const struct interface *);
|
|||
void ipv6nd_handleifa(int, struct ipv6_addr *, pid_t);
|
||||
int ipv6nd_dadcompleted(const struct interface *);
|
||||
void ipv6nd_advertise(struct ipv6_addr *);
|
||||
void ipv6nd_expire(struct interface *, uint32_t);
|
||||
void ipv6nd_startexpire(struct interface *);
|
||||
void ipv6nd_drop(struct interface *);
|
||||
void ipv6nd_neighbour(struct dhcpcd_ctx *, struct in6_addr *, int);
|
||||
#endif /* INET6 */
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* logerr: errx with logging
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -91,7 +92,7 @@ getprogname(void)
|
|||
|
||||
#ifndef SMALL
|
||||
/* Write the time, syslog style. month day time - */
|
||||
static void
|
||||
static int
|
||||
logprintdate(FILE *stream)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
@ -100,19 +101,22 @@ logprintdate(FILE *stream)
|
|||
char buf[32];
|
||||
|
||||
if (gettimeofday(&tv, NULL) == -1)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
now = tv.tv_sec;
|
||||
tzset();
|
||||
localtime_r(&now, &tmnow);
|
||||
strftime(buf, sizeof(buf), "%b %d %T ", &tmnow);
|
||||
fprintf(stream, "%s", buf);
|
||||
if (localtime_r(&now, &tmnow) == NULL)
|
||||
return -1;
|
||||
if (strftime(buf, sizeof(buf), "%b %d %T ", &tmnow) == 0)
|
||||
return -1;
|
||||
return fprintf(stream, "%s", buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
__printflike(3, 0) static void
|
||||
__printflike(3, 0) static int
|
||||
vlogprintf_r(struct logctx *ctx, FILE *stream, const char *fmt, va_list args)
|
||||
{
|
||||
int len = 0, e;
|
||||
va_list a;
|
||||
#ifndef SMALL
|
||||
bool log_pid;
|
||||
|
@ -122,7 +126,11 @@ vlogprintf_r(struct logctx *ctx, FILE *stream, const char *fmt, va_list args)
|
|||
|
||||
if ((stream == stderr && ctx->log_opts & LOGERR_ERR_DATE) ||
|
||||
(stream != stderr && ctx->log_opts & LOGERR_LOG_DATE))
|
||||
logprintdate(stream);
|
||||
{
|
||||
if ((e = logprintdate(stream)) == -1)
|
||||
return -1;
|
||||
len += e;
|
||||
}
|
||||
|
||||
#ifdef LOGERR_TAG
|
||||
log_tag = ((stream == stderr && ctx->log_opts & LOGERR_ERR_TAG) ||
|
||||
|
@ -130,29 +138,43 @@ vlogprintf_r(struct logctx *ctx, FILE *stream, const char *fmt, va_list args)
|
|||
if (log_tag) {
|
||||
if (ctx->log_tag == NULL)
|
||||
ctx->log_tag = getprogname();
|
||||
fprintf(stream, "%s", ctx->log_tag);
|
||||
if ((e = fprintf(stream, "%s", ctx->log_tag)) == -1)
|
||||
return -1;
|
||||
len += e;
|
||||
}
|
||||
#endif
|
||||
|
||||
log_pid = ((stream == stderr && ctx->log_opts & LOGERR_ERR_PID) ||
|
||||
(stream != stderr && ctx->log_opts & LOGERR_LOG_PID));
|
||||
if (log_pid)
|
||||
fprintf(stream, "[%d]", getpid());
|
||||
if (log_pid) {
|
||||
if ((e = fprintf(stream, "[%d]", getpid())) == -1)
|
||||
return -1;
|
||||
len += e;
|
||||
}
|
||||
|
||||
#ifdef LOGERR_TAG
|
||||
if (log_tag || log_pid)
|
||||
#else
|
||||
if (log_pid)
|
||||
#endif
|
||||
fprintf(stream, ": ");
|
||||
{
|
||||
if ((e = fprintf(stream, ": ")) == -1)
|
||||
return -1;
|
||||
len += e;
|
||||
}
|
||||
#else
|
||||
UNUSED(ctx);
|
||||
#endif
|
||||
|
||||
va_copy(a, args);
|
||||
vfprintf(stream, fmt, a);
|
||||
fputc('\n', stream);
|
||||
e = vfprintf(stream, fmt, a);
|
||||
if (fputc('\n', stream) == EOF)
|
||||
e = -1;
|
||||
else if (e != -1)
|
||||
e++;
|
||||
va_end(a);
|
||||
|
||||
return e == -1 ? -1 : len + e;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -170,30 +192,31 @@ vlogprintf_r(struct logctx *ctx, FILE *stream, const char *fmt, va_list args)
|
|||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmissing-format-attribute"
|
||||
#endif
|
||||
__printflike(2, 0) static void
|
||||
__printflike(2, 0) static int
|
||||
vlogmessage(int pri, const char *fmt, va_list args)
|
||||
{
|
||||
struct logctx *ctx = &_logctx;
|
||||
int len = 0;
|
||||
|
||||
if (ctx->log_opts & LOGERR_ERR &&
|
||||
(pri <= LOG_ERR ||
|
||||
(!(ctx->log_opts & LOGERR_QUIET) && pri <= LOG_INFO) ||
|
||||
(ctx->log_opts & LOGERR_DEBUG && pri <= LOG_DEBUG)))
|
||||
vlogprintf_r(ctx, stderr, fmt, args);
|
||||
len = vlogprintf_r(ctx, stderr, fmt, args);
|
||||
|
||||
if (!(ctx->log_opts & LOGERR_LOG))
|
||||
return;
|
||||
return len;
|
||||
|
||||
#ifdef SMALL
|
||||
vsyslog(pri, fmt, args);
|
||||
#else
|
||||
if (ctx->log_file == NULL) {
|
||||
vsyslog(pri, fmt, args);
|
||||
return;
|
||||
return len;
|
||||
}
|
||||
if (pri == LOG_DEBUG && !(ctx->log_opts & LOGERR_DEBUG))
|
||||
return;
|
||||
vlogprintf_r(ctx, ctx->log_file, fmt, args);
|
||||
return len;
|
||||
return vlogprintf_r(ctx, ctx->log_file, fmt, args);
|
||||
#endif
|
||||
}
|
||||
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5))
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* logerr: errx with logging
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - route management
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -29,6 +30,7 @@
|
|||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
@ -44,6 +46,66 @@
|
|||
#include "route.h"
|
||||
#include "sa.h"
|
||||
|
||||
/* Needed for NetBSD-6, 7 and 8. */
|
||||
#ifndef RB_TREE_FOREACH_SAFE
|
||||
#ifndef RB_TREE_PREV
|
||||
#define RB_TREE_NEXT(T, N) rb_tree_iterate((T), (N), RB_DIR_RIGHT)
|
||||
#define RB_TREE_PREV(T, N) rb_tree_iterate((T), (N), RB_DIR_LEFT)
|
||||
#endif
|
||||
#define RB_TREE_FOREACH_SAFE(N, T, S) \
|
||||
for ((N) = RB_TREE_MIN(T); \
|
||||
(N) && ((S) = RB_TREE_NEXT((T), (N)), 1); \
|
||||
(N) = (S))
|
||||
#define RB_TREE_FOREACH_REVERSE_SAFE(N, T, S) \
|
||||
for ((N) = RB_TREE_MAX(T); \
|
||||
(N) && ((S) = RB_TREE_PREV((T), (N)), 1); \
|
||||
(N) = (S))
|
||||
#endif
|
||||
|
||||
#ifdef RT_FREE_ROUTE_TABLE_STATS
|
||||
static size_t croutes;
|
||||
static size_t nroutes;
|
||||
static size_t froutes;
|
||||
static size_t mroutes;
|
||||
#endif
|
||||
|
||||
static void
|
||||
rt_maskedaddr(struct sockaddr *dst,
|
||||
const struct sockaddr *addr, const struct sockaddr *netmask)
|
||||
{
|
||||
const char *addrp = addr->sa_data, *netmaskp = netmask->sa_data;
|
||||
char *dstp = dst->sa_data;
|
||||
const char *addre = (char *)dst + sa_len(addr);
|
||||
const char *netmaske = (char *)dst + MIN(sa_len(addr), sa_len(netmask));
|
||||
|
||||
dst->sa_family = addr->sa_family;
|
||||
#ifdef HAVE_SA_LEN
|
||||
dst->sa_len = addr->sa_len;
|
||||
#endif
|
||||
|
||||
if (sa_is_unspecified(netmask)) {
|
||||
if (addre > dstp)
|
||||
memcpy(dstp, addrp, (size_t)(addre - dstp));
|
||||
return;
|
||||
}
|
||||
|
||||
while (dstp < netmaske)
|
||||
*dstp++ = *addrp++ & *netmaskp++;
|
||||
if (dstp < addre)
|
||||
memset(dstp, 0, (size_t)(addre - dstp));
|
||||
}
|
||||
|
||||
int
|
||||
rt_cmp_dest(const struct rt *rt1, const struct rt *rt2)
|
||||
{
|
||||
union sa_ss ma1 = { .sa.sa_family = AF_UNSPEC };
|
||||
union sa_ss ma2 = { .sa.sa_family = AF_UNSPEC };
|
||||
|
||||
rt_maskedaddr(&ma1.sa, &rt1->rt_dest, &rt1->rt_netmask);
|
||||
rt_maskedaddr(&ma2.sa, &rt2->rt_dest, &rt2->rt_netmask);
|
||||
return sa_cmp(&ma1.sa, &ma2.sa);
|
||||
}
|
||||
|
||||
/*
|
||||
* On some systems, host routes have no need for a netmask.
|
||||
* However DHCP specifies host routes using an all-ones netmask.
|
||||
|
@ -59,13 +121,99 @@ rt_cmp_netmask(const struct rt *rt1, const struct rt *rt2)
|
|||
return sa_cmp(&rt1->rt_netmask, &rt2->rt_netmask);
|
||||
}
|
||||
|
||||
static int
|
||||
rt_compare_os(__unused void *context, const void *node1, const void *node2)
|
||||
{
|
||||
const struct rt *rt1 = node1, *rt2 = node2;
|
||||
int c;
|
||||
|
||||
/* Sort by masked destination. */
|
||||
c = rt_cmp_dest(rt1, rt2);
|
||||
if (c != 0)
|
||||
return c;
|
||||
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
c = (int)(rt1->rt_ifp->metric - rt2->rt_ifp->metric);
|
||||
#endif
|
||||
return c;
|
||||
}
|
||||
|
||||
static int
|
||||
rt_compare_proto(__unused void *context, const void *node1, const void *node2)
|
||||
{
|
||||
const struct rt *rt1 = node1, *rt2 = node2;
|
||||
int c;
|
||||
struct interface *ifp1, *ifp2;
|
||||
|
||||
assert(rt1->rt_ifp != NULL);
|
||||
assert(rt2->rt_ifp != NULL);
|
||||
ifp1 = rt1->rt_ifp;
|
||||
ifp2 = rt2->rt_ifp;
|
||||
|
||||
/* Prefer interfaces with a carrier. */
|
||||
c = ifp1->carrier - ifp2->carrier;
|
||||
if (c != 0)
|
||||
return -c;
|
||||
|
||||
/* Lower metric interfaces come first. */
|
||||
c = (int)(ifp1->metric - ifp2->metric);
|
||||
if (c != 0)
|
||||
return c;
|
||||
|
||||
/* Finally the order in which the route was given to us. */
|
||||
if (rt1->rt_order > rt2->rt_order)
|
||||
return 1;
|
||||
if (rt1->rt_order < rt2->rt_order)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const rb_tree_ops_t rt_compare_os_ops = {
|
||||
.rbto_compare_nodes = rt_compare_os,
|
||||
.rbto_compare_key = rt_compare_os,
|
||||
.rbto_node_offset = offsetof(struct rt, rt_tree),
|
||||
.rbto_context = NULL
|
||||
};
|
||||
|
||||
const rb_tree_ops_t rt_compare_proto_ops = {
|
||||
.rbto_compare_nodes = rt_compare_proto,
|
||||
.rbto_compare_key = rt_compare_proto,
|
||||
.rbto_node_offset = offsetof(struct rt, rt_tree),
|
||||
.rbto_context = NULL
|
||||
};
|
||||
|
||||
#ifdef RT_FREE_ROUTE_TABLE
|
||||
static int
|
||||
rt_compare_free(__unused void *context, const void *node1, const void *node2)
|
||||
{
|
||||
|
||||
return node1 == node2 ? 0 : node1 < node2 ? -1 : 1;
|
||||
}
|
||||
|
||||
static const rb_tree_ops_t rt_compare_free_ops = {
|
||||
.rbto_compare_nodes = rt_compare_free,
|
||||
.rbto_compare_key = rt_compare_free,
|
||||
.rbto_node_offset = offsetof(struct rt, rt_tree),
|
||||
.rbto_context = NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
void
|
||||
rt_init(struct dhcpcd_ctx *ctx)
|
||||
{
|
||||
|
||||
TAILQ_INIT(&ctx->routes);
|
||||
TAILQ_INIT(&ctx->kroutes);
|
||||
TAILQ_INIT(&ctx->froutes);
|
||||
rb_tree_init(&ctx->routes, &rt_compare_os_ops);
|
||||
#ifdef RT_FREE_ROUTE_TABLE
|
||||
rb_tree_init(&ctx->froutes, &rt_compare_free_ops);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
rt_is_default(const struct rt *rt)
|
||||
{
|
||||
|
||||
return sa_is_unspecified(&rt->rt_dest) &&
|
||||
sa_is_unspecified(&rt->rt_netmask);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -92,9 +240,7 @@ rt_desc(const char *cmd, const struct rt *rt)
|
|||
else
|
||||
loginfox("%s: %s host route to %s via %s",
|
||||
ifname, cmd, dest, gateway);
|
||||
} else if (sa_is_unspecified(&rt->rt_dest) &&
|
||||
sa_is_unspecified(&rt->rt_netmask))
|
||||
{
|
||||
} else if (rt_is_default(rt)) {
|
||||
if (gateway_unspec)
|
||||
loginfox("%s: %s default route",
|
||||
ifname, cmd);
|
||||
|
@ -114,42 +260,44 @@ rt_desc(const char *cmd, const struct rt *rt)
|
|||
}
|
||||
|
||||
void
|
||||
rt_headclear0(struct dhcpcd_ctx *ctx, struct rt_head *rts, int af)
|
||||
rt_headclear0(struct dhcpcd_ctx *ctx, rb_tree_t *rts, int af)
|
||||
{
|
||||
struct rt *rt, *rtn;
|
||||
|
||||
if (rts == NULL)
|
||||
return;
|
||||
assert(ctx != NULL);
|
||||
#ifdef RT_FREE_ROUTE_TABLE
|
||||
assert(&ctx->froutes != rts);
|
||||
#endif
|
||||
|
||||
TAILQ_FOREACH_SAFE(rt, rts, rt_next, rtn) {
|
||||
RB_TREE_FOREACH_SAFE(rt, rts, rtn) {
|
||||
if (af != AF_UNSPEC &&
|
||||
rt->rt_dest.sa_family != af &&
|
||||
rt->rt_gateway.sa_family != af)
|
||||
continue;
|
||||
TAILQ_REMOVE(rts, rt, rt_next);
|
||||
TAILQ_INSERT_TAIL(&ctx->froutes, rt, rt_next);
|
||||
rb_tree_remove_node(rts, rt);
|
||||
rt_free(rt);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rt_headclear(struct rt_head *rts, int af)
|
||||
rt_headclear(rb_tree_t *rts, int af)
|
||||
{
|
||||
struct rt *rt;
|
||||
|
||||
if (rts == NULL || (rt = TAILQ_FIRST(rts)) == NULL)
|
||||
if (rts == NULL || (rt = RB_TREE_MIN(rts)) == NULL)
|
||||
return;
|
||||
rt_headclear0(rt->rt_ifp->ctx, rts, af);
|
||||
}
|
||||
|
||||
static void
|
||||
rt_headfree(struct rt_head *rts)
|
||||
rt_headfree(rb_tree_t *rts)
|
||||
{
|
||||
struct rt *rt;
|
||||
|
||||
while ((rt = TAILQ_FIRST(rts))) {
|
||||
TAILQ_REMOVE(rts, rt, rt_next);
|
||||
while ((rt = RB_TREE_MIN(rts)) != NULL) {
|
||||
rb_tree_remove_node(rts, rt);
|
||||
free(rt);
|
||||
}
|
||||
}
|
||||
|
@ -160,8 +308,14 @@ rt_dispose(struct dhcpcd_ctx *ctx)
|
|||
|
||||
assert(ctx != NULL);
|
||||
rt_headfree(&ctx->routes);
|
||||
rt_headfree(&ctx->kroutes);
|
||||
#ifdef RT_FREE_ROUTE_TABLE
|
||||
rt_headfree(&ctx->froutes);
|
||||
#ifdef RT_FREE_ROUTE_TABLE_STATS
|
||||
logdebugx("free route list used %zu times", froutes);
|
||||
logdebugx("new routes from route free list %zu", nroutes);
|
||||
logdebugx("maximum route free list size %zu", mroutes);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
struct rt *
|
||||
|
@ -170,9 +324,16 @@ rt_new0(struct dhcpcd_ctx *ctx)
|
|||
struct rt *rt;
|
||||
|
||||
assert(ctx != NULL);
|
||||
if ((rt = TAILQ_FIRST(&ctx->froutes)) != NULL)
|
||||
TAILQ_REMOVE(&ctx->froutes, rt, rt_next);
|
||||
else if ((rt = malloc(sizeof(*rt))) == NULL) {
|
||||
#ifdef RT_FREE_ROUTE_TABLE
|
||||
if ((rt = RB_TREE_MIN(&ctx->froutes)) != NULL) {
|
||||
rb_tree_remove_node(&ctx->froutes, rt);
|
||||
#ifdef RT_FREE_ROUTE_TABLE_STATS
|
||||
croutes--;
|
||||
nroutes++;
|
||||
#endif
|
||||
} else
|
||||
#endif
|
||||
if ((rt = malloc(sizeof(*rt))) == NULL) {
|
||||
logerr(__func__);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -204,13 +365,47 @@ rt_new(struct interface *ifp)
|
|||
return rt;
|
||||
}
|
||||
|
||||
struct rt *
|
||||
rt_proto_add_ctx(rb_tree_t *tree, struct rt *rt, struct dhcpcd_ctx *ctx)
|
||||
{
|
||||
|
||||
rt->rt_order = ctx->rt_order++;
|
||||
if (rb_tree_insert_node(tree, rt) == rt)
|
||||
return rt;
|
||||
|
||||
rt_free(rt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct rt *
|
||||
rt_proto_add(rb_tree_t *tree, struct rt *rt)
|
||||
{
|
||||
|
||||
assert (rt->rt_ifp != NULL);
|
||||
return rt_proto_add_ctx(tree, rt, rt->rt_ifp->ctx);
|
||||
}
|
||||
|
||||
void
|
||||
rt_free(struct rt *rt)
|
||||
{
|
||||
#ifdef RT_FREE_ROUTE_TABLE
|
||||
struct dhcpcd_ctx *ctx;
|
||||
|
||||
assert(rt != NULL);
|
||||
assert(rt->rt_ifp != NULL);
|
||||
assert(rt->rt_ifp->ctx != NULL);
|
||||
TAILQ_INSERT_TAIL(&rt->rt_ifp->ctx->froutes, rt, rt_next);
|
||||
|
||||
ctx = rt->rt_ifp->ctx;
|
||||
rb_tree_insert_node(&ctx->froutes, rt);
|
||||
#ifdef RT_FREE_ROUTE_TABLE_STATS
|
||||
croutes++;
|
||||
froutes++;
|
||||
if (croutes > mroutes)
|
||||
mroutes = croutes;
|
||||
#endif
|
||||
#else
|
||||
free(rt);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -222,51 +417,12 @@ rt_freeif(struct interface *ifp)
|
|||
if (ifp == NULL)
|
||||
return;
|
||||
ctx = ifp->ctx;
|
||||
TAILQ_FOREACH_SAFE(rt, &ctx->routes, rt_next, rtn) {
|
||||
RB_TREE_FOREACH_SAFE(rt, &ctx->routes, rtn) {
|
||||
if (rt->rt_ifp == ifp) {
|
||||
TAILQ_REMOVE(&ctx->routes, rt, rt_next);
|
||||
rb_tree_remove_node(&ctx->routes, rt);
|
||||
rt_free(rt);
|
||||
}
|
||||
}
|
||||
TAILQ_FOREACH_SAFE(rt, &ctx->kroutes, rt_next, rtn) {
|
||||
if (rt->rt_ifp == ifp) {
|
||||
TAILQ_REMOVE(&ctx->kroutes, rt, rt_next);
|
||||
rt_free(rt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct rt *
|
||||
rt_find(struct rt_head *rts, const struct rt *f)
|
||||
{
|
||||
struct rt *rt;
|
||||
|
||||
assert(rts != NULL);
|
||||
assert(f != NULL);
|
||||
TAILQ_FOREACH(rt, rts, rt_next) {
|
||||
if (sa_cmp(&rt->rt_dest, &f->rt_dest) == 0 &&
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
(f->rt_ifp == NULL ||
|
||||
rt->rt_ifp->metric == f->rt_ifp->metric) &&
|
||||
#endif
|
||||
rt_cmp_netmask(f, rt) == 0)
|
||||
return rt;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
rt_kfree(struct rt *rt)
|
||||
{
|
||||
struct dhcpcd_ctx *ctx;
|
||||
struct rt *f;
|
||||
|
||||
assert(rt != NULL);
|
||||
ctx = rt->rt_ifp->ctx;
|
||||
if ((f = rt_find(&ctx->kroutes, rt)) != NULL) {
|
||||
TAILQ_REMOVE(&ctx->kroutes, f, rt_next);
|
||||
rt_free(f);
|
||||
}
|
||||
}
|
||||
|
||||
/* If something other than dhcpcd removes a route,
|
||||
|
@ -278,32 +434,23 @@ rt_recvrt(int cmd, const struct rt *rt, pid_t pid)
|
|||
struct rt *f;
|
||||
|
||||
assert(rt != NULL);
|
||||
assert(rt->rt_ifp != NULL);
|
||||
assert(rt->rt_ifp->ctx != NULL);
|
||||
|
||||
ctx = rt->rt_ifp->ctx;
|
||||
f = rt_find(&ctx->kroutes, rt);
|
||||
|
||||
switch(cmd) {
|
||||
case RTM_DELETE:
|
||||
f = rb_tree_find_node(&ctx->routes, rt);
|
||||
if (f != NULL) {
|
||||
TAILQ_REMOVE(&ctx->kroutes, f, rt_next);
|
||||
rt_free(f);
|
||||
}
|
||||
if ((f = rt_find(&ctx->routes, rt)) != NULL) {
|
||||
char buf[32];
|
||||
|
||||
TAILQ_REMOVE(&ctx->routes, f, rt_next);
|
||||
rb_tree_remove_node(&ctx->routes, f);
|
||||
snprintf(buf, sizeof(buf), "pid %d deleted", pid);
|
||||
rt_desc(buf, f);
|
||||
rt_free(f);
|
||||
}
|
||||
break;
|
||||
case RTM_ADD:
|
||||
if (f != NULL)
|
||||
break;
|
||||
if ((f = rt_new(rt->rt_ifp)) == NULL)
|
||||
break;
|
||||
memcpy(f, rt, sizeof(*f));
|
||||
TAILQ_INSERT_TAIL(&ctx->kroutes, f, rt_next);
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(IPV4LL) && defined(HAVE_ROUTE_METRIC)
|
||||
|
@ -313,10 +460,10 @@ rt_recvrt(int cmd, const struct rt *rt, pid_t pid)
|
|||
}
|
||||
|
||||
static bool
|
||||
rt_add(struct rt *nrt, struct rt *ort)
|
||||
rt_add(rb_tree_t *kroutes, struct rt *nrt, struct rt *ort)
|
||||
{
|
||||
struct dhcpcd_ctx *ctx;
|
||||
bool change;
|
||||
bool change, kroute, result;
|
||||
|
||||
assert(nrt != NULL);
|
||||
ctx = nrt->rt_ifp->ctx;
|
||||
|
@ -338,9 +485,9 @@ rt_add(struct rt *nrt, struct rt *ort)
|
|||
|
||||
rt_desc(ort == NULL ? "adding" : "changing", nrt);
|
||||
|
||||
change = false;
|
||||
change = kroute = result = false;
|
||||
if (ort == NULL) {
|
||||
ort = rt_find(&ctx->kroutes, nrt);
|
||||
ort = rb_tree_find_node(kroutes, nrt);
|
||||
if (ort != NULL &&
|
||||
((ort->rt_flags & RTF_REJECT &&
|
||||
nrt->rt_flags & RTF_REJECT) ||
|
||||
|
@ -353,6 +500,7 @@ rt_add(struct rt *nrt, struct rt *ort)
|
|||
if (ort->rt_mtu == nrt->rt_mtu)
|
||||
return true;
|
||||
change = true;
|
||||
kroute = true;
|
||||
}
|
||||
} else if (ort->rt_dflags & RTDF_FAKE &&
|
||||
!(nrt->rt_dflags & RTDF_FAKE) &&
|
||||
|
@ -379,8 +527,10 @@ rt_add(struct rt *nrt, struct rt *ort)
|
|||
#endif
|
||||
|
||||
if (change) {
|
||||
if (if_route(RTM_CHANGE, nrt) != -1)
|
||||
return true;
|
||||
if (if_route(RTM_CHANGE, nrt) != -1) {
|
||||
result = true;
|
||||
goto out;
|
||||
}
|
||||
if (errno != ESRCH)
|
||||
logerr("if_route (CHG)");
|
||||
}
|
||||
|
@ -392,9 +542,9 @@ rt_add(struct rt *nrt, struct rt *ort)
|
|||
if (ort != NULL) {
|
||||
if (if_route(RTM_DELETE, ort) == -1 && errno != ESRCH)
|
||||
logerr("if_route (DEL)");
|
||||
rt_kfree(ort);
|
||||
}
|
||||
return true;
|
||||
result = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If the kernel claims the route exists we need to rip out the
|
||||
|
@ -412,7 +562,7 @@ rt_add(struct rt *nrt, struct rt *ort)
|
|||
if (if_route(RTM_DELETE, ort) == -1 && errno != ESRCH)
|
||||
logerr("if_route (DEL)");
|
||||
else
|
||||
rt_kfree(ort);
|
||||
kroute = false;
|
||||
}
|
||||
#ifdef ROUTE_PER_GATEWAY
|
||||
/* The OS allows many routes to the same dest with different gateways.
|
||||
|
@ -425,13 +575,23 @@ rt_add(struct rt *nrt, struct rt *ort)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
if (if_route(RTM_ADD, nrt) != -1)
|
||||
return true;
|
||||
|
||||
if (if_route(RTM_ADD, nrt) != -1) {
|
||||
result = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
logerr:
|
||||
#endif
|
||||
logerr("if_route (ADD)");
|
||||
return false;
|
||||
|
||||
out:
|
||||
if (kroute) {
|
||||
rb_tree_remove_node(kroutes, ort);
|
||||
rt_free(ort);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -443,10 +603,6 @@ rt_delete(struct rt *rt)
|
|||
retval = if_route(RTM_DELETE, rt) == -1 ? false : true;
|
||||
if (!retval && errno != ENOENT && errno != ESRCH)
|
||||
logerr(__func__);
|
||||
/* Remove the route from our kernel table so we can add a
|
||||
* IPv4LL default route if possible. */
|
||||
else
|
||||
rt_kfree(rt);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -462,14 +618,15 @@ rt_cmp(const struct rt *r1, const struct rt *r2)
|
|||
}
|
||||
|
||||
static bool
|
||||
rt_doroute(struct rt *rt)
|
||||
rt_doroute(rb_tree_t *kroutes, struct rt *rt)
|
||||
{
|
||||
struct dhcpcd_ctx *ctx;
|
||||
struct rt *or;
|
||||
|
||||
ctx = rt->rt_ifp->ctx;
|
||||
/* Do we already manage it? */
|
||||
if ((or = rt_find(&ctx->routes, rt))) {
|
||||
or = rb_tree_find_node(&ctx->routes, rt);
|
||||
if (or != NULL) {
|
||||
if (rt->rt_dflags & RTDF_FAKE)
|
||||
return true;
|
||||
if (or->rt_dflags & RTDF_FAKE ||
|
||||
|
@ -478,19 +635,20 @@ rt_doroute(struct rt *rt)
|
|||
sa_cmp(&or->rt_ifa, &rt->rt_ifa) != 0) ||
|
||||
or->rt_mtu != rt->rt_mtu)
|
||||
{
|
||||
if (!rt_add(rt, or))
|
||||
if (!rt_add(kroutes, rt, or))
|
||||
return false;
|
||||
}
|
||||
TAILQ_REMOVE(&ctx->routes, or, rt_next);
|
||||
rb_tree_remove_node(&ctx->routes, or);
|
||||
rt_free(or);
|
||||
} else {
|
||||
if (rt->rt_dflags & RTDF_FAKE) {
|
||||
if ((or = rt_find(&ctx->kroutes, rt)) == NULL)
|
||||
or = rb_tree_find_node(kroutes, rt);
|
||||
if (or == NULL)
|
||||
return false;
|
||||
if (!rt_cmp(rt, or))
|
||||
return false;
|
||||
} else {
|
||||
if (!rt_add(rt, NULL))
|
||||
if (!rt_add(kroutes, rt, NULL))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -501,16 +659,15 @@ rt_doroute(struct rt *rt)
|
|||
void
|
||||
rt_build(struct dhcpcd_ctx *ctx, int af)
|
||||
{
|
||||
struct rt_head routes, added;
|
||||
rb_tree_t routes, added, kroutes;
|
||||
struct rt *rt, *rtn;
|
||||
unsigned long long o;
|
||||
|
||||
/* We need to have the interfaces in the correct order to ensure
|
||||
* our routes are managed correctly. */
|
||||
if_sortinterfaces(ctx);
|
||||
|
||||
TAILQ_INIT(&routes);
|
||||
TAILQ_INIT(&added);
|
||||
rb_tree_init(&routes, &rt_compare_proto_ops);
|
||||
rb_tree_init(&added, &rt_compare_os_ops);
|
||||
rb_tree_init(&kroutes, &rt_compare_os_ops);
|
||||
if_initrt(ctx, &kroutes, af);
|
||||
ctx->rt_order = 0;
|
||||
|
||||
switch (af) {
|
||||
#ifdef INET
|
||||
|
@ -527,26 +684,34 @@ rt_build(struct dhcpcd_ctx *ctx, int af)
|
|||
#endif
|
||||
}
|
||||
|
||||
TAILQ_FOREACH_SAFE(rt, &routes, rt_next, rtn) {
|
||||
if (rt->rt_dest.sa_family != af &&
|
||||
rt->rt_gateway.sa_family != af)
|
||||
RB_TREE_FOREACH_SAFE(rt, &routes, rtn) {
|
||||
if ((rt->rt_dest.sa_family != af &&
|
||||
rt->rt_dest.sa_family != AF_UNSPEC) ||
|
||||
(rt->rt_gateway.sa_family != af &&
|
||||
rt->rt_gateway.sa_family != AF_UNSPEC))
|
||||
continue;
|
||||
/* Is this route already in our table? */
|
||||
if ((rt_find(&added, rt)) != NULL)
|
||||
if (rb_tree_find_node(&added, rt) != NULL)
|
||||
continue;
|
||||
if (rt_doroute(rt)) {
|
||||
TAILQ_REMOVE(&routes, rt, rt_next);
|
||||
TAILQ_INSERT_TAIL(&added, rt, rt_next);
|
||||
if (rt_doroute(&kroutes, rt)) {
|
||||
rb_tree_remove_node(&routes, rt);
|
||||
if (rb_tree_insert_node(&added, rt) != rt) {
|
||||
errno = EEXIST;
|
||||
logerr(__func__);
|
||||
rt_free(rt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove old routes we used to manage. */
|
||||
TAILQ_FOREACH_SAFE(rt, &ctx->routes, rt_next, rtn) {
|
||||
if (rt->rt_dest.sa_family != af &&
|
||||
rt->rt_gateway.sa_family != af)
|
||||
RB_TREE_FOREACH_REVERSE_SAFE(rt, &ctx->routes, rtn) {
|
||||
if ((rt->rt_dest.sa_family != af &&
|
||||
rt->rt_dest.sa_family != AF_UNSPEC) ||
|
||||
(rt->rt_gateway.sa_family != af &&
|
||||
rt->rt_gateway.sa_family != AF_UNSPEC))
|
||||
continue;
|
||||
TAILQ_REMOVE(&ctx->routes, rt, rt_next);
|
||||
if (rt_find(&added, rt) == NULL) {
|
||||
rb_tree_remove_node(&ctx->routes, rt);
|
||||
if (rb_tree_find_node(&added, rt) == NULL) {
|
||||
o = rt->rt_ifp->options ?
|
||||
rt->rt_ifp->options->options :
|
||||
ctx->options;
|
||||
|
@ -555,12 +720,21 @@ rt_build(struct dhcpcd_ctx *ctx, int af)
|
|||
(DHCPCD_EXITING | DHCPCD_PERSISTENT))
|
||||
rt_delete(rt);
|
||||
}
|
||||
TAILQ_INSERT_TAIL(&ctx->froutes, rt, rt_next);
|
||||
rt_free(rt);
|
||||
}
|
||||
|
||||
/* XXX This needs to be optimised. */
|
||||
while ((rt = RB_TREE_MIN(&added)) != NULL) {
|
||||
rb_tree_remove_node(&added, rt);
|
||||
if (rb_tree_insert_node(&ctx->routes, rt) != rt) {
|
||||
errno = EEXIST;
|
||||
logerr(__func__);
|
||||
rt_free(rt);
|
||||
}
|
||||
}
|
||||
|
||||
rt_headclear(&ctx->routes, af);
|
||||
TAILQ_CONCAT(&ctx->routes, &added, rt_next);
|
||||
|
||||
getfail:
|
||||
rt_headclear(&routes, AF_UNSPEC);
|
||||
rt_headclear(&kroutes, AF_UNSPEC);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - route management
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -28,6 +29,10 @@
|
|||
#ifndef ROUTE_H
|
||||
#define ROUTE_H
|
||||
|
||||
#ifdef HAVE_SYS_RBTREE_H
|
||||
#include <sys/rbtree.h>
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <net/route.h>
|
||||
|
||||
|
@ -36,6 +41,17 @@
|
|||
#include "dhcpcd.h"
|
||||
#include "sa.h"
|
||||
|
||||
/*
|
||||
* Enable the route free list by default as
|
||||
* memory usage is still reported as low/unchanged even
|
||||
* when dealing with millions of routes.
|
||||
*/
|
||||
#if !defined(RT_FREE_ROUTE_TABLE)
|
||||
#define RT_FREE_ROUTE_TABLE 1
|
||||
#elif RT_FREE_ROUTE_TABLE == 0
|
||||
#undef RT_FREE_ROUTE_TABLE
|
||||
#endif
|
||||
|
||||
/* Some systems have route metrics.
|
||||
* OpenBSD route priority is not this. */
|
||||
#ifndef HAVE_ROUTE_METRIC
|
||||
|
@ -56,7 +72,6 @@
|
|||
#endif
|
||||
|
||||
struct rt {
|
||||
TAILQ_ENTRY(rt) rt_next;
|
||||
union sa_ss rt_ss_dest;
|
||||
#define rt_dest rt_ss_dest.sa
|
||||
union sa_ss rt_ss_netmask;
|
||||
|
@ -72,26 +87,31 @@ struct rt {
|
|||
unsigned int rt_metric;
|
||||
#endif
|
||||
unsigned int rt_dflags;
|
||||
#define RTDF_INIT 0x01 /* Generated by if_initrt() */
|
||||
#define RTDF_IFA_ROUTE 0x02 /* Address generated route */
|
||||
#define RTDF_FAKE 0x04 /* Maybe us on lease reboot */
|
||||
#define RTDF_RA 0x08 /* Router Advertisement */
|
||||
#define RTDF_DHCP 0x10 /* DHCP route */
|
||||
#define RTDF_STATIC 0x20 /* Configured in dhcpcd */
|
||||
size_t rt_order;
|
||||
rb_node_t rt_tree;
|
||||
};
|
||||
TAILQ_HEAD(rt_head, rt);
|
||||
|
||||
extern const rb_tree_ops_t rt_compare_proto_ops;
|
||||
|
||||
void rt_init(struct dhcpcd_ctx *);
|
||||
void rt_dispose(struct dhcpcd_ctx *);
|
||||
struct rt * rt_find(struct rt_head *, const struct rt *);
|
||||
void rt_free(struct rt *);
|
||||
void rt_freeif(struct interface *);
|
||||
void rt_headclear0(struct dhcpcd_ctx *, struct rt_head *, int);
|
||||
void rt_headclear(struct rt_head *, int);
|
||||
void rt_headfreeif(struct rt_head *);
|
||||
bool rt_is_default(const struct rt *);
|
||||
void rt_headclear0(struct dhcpcd_ctx *, rb_tree_t *, int);
|
||||
void rt_headclear(rb_tree_t *, int);
|
||||
void rt_headfreeif(rb_tree_t *);
|
||||
struct rt * rt_new0(struct dhcpcd_ctx *);
|
||||
void rt_setif(struct rt *, struct interface *);
|
||||
struct rt * rt_new(struct interface *);
|
||||
struct rt * rt_proto_add_ctx(rb_tree_t *, struct rt *, struct dhcpcd_ctx *);
|
||||
struct rt * rt_proto_add(rb_tree_t *, struct rt *);
|
||||
int rt_cmp_dest(const struct rt *, const struct rt *);
|
||||
void rt_recvrt(int, const struct rt *, pid_t);
|
||||
void rt_build(struct dhcpcd_ctx *, int);
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* Socket Address handling for dhcpcd
|
||||
* Copyright (c) 2015-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -37,6 +38,7 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
@ -92,6 +94,30 @@ sa_addrlen(const struct sockaddr *sa)
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef HAVE_SA_LEN
|
||||
socklen_t
|
||||
sa_len(const struct sockaddr *sa)
|
||||
{
|
||||
|
||||
switch (sa->sa_family) {
|
||||
#ifdef AF_LINK
|
||||
case AF_LINK:
|
||||
return sizeof(struct sockaddr_dl);
|
||||
#endif
|
||||
#ifdef AF_PACKET
|
||||
case AF_PACKET:
|
||||
return sizeof(struct sockaddr_ll);
|
||||
#endif
|
||||
case AF_INET:
|
||||
return sizeof(struct sockaddr_in);
|
||||
case AF_INET6:
|
||||
return sizeof(struct sockaddr_in6);
|
||||
default:
|
||||
return sizeof(struct sockaddr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
sa_is_unspecified(const struct sockaddr *sa)
|
||||
{
|
||||
|
@ -339,6 +365,13 @@ sa_addrtop(const struct sockaddr *sa, char *buf, socklen_t len)
|
|||
const void *addr;
|
||||
|
||||
assert(buf != NULL);
|
||||
assert(len > 0);
|
||||
|
||||
if (sa->sa_family == 0) {
|
||||
*buf = '\0';
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef AF_LINK
|
||||
#ifndef CLLADDR
|
||||
#define CLLADDR(sdl) (const void *)((sdl)->sdl_data + (sdl)->sdl_nlen)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* Socket Address handling for dhcpcd
|
||||
* Copyright (c) 2015-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -29,6 +30,7 @@
|
|||
#define SA_H
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
union sa_ss {
|
||||
struct sockaddr sa;
|
||||
|
@ -54,6 +56,11 @@ union sa_ss {
|
|||
|
||||
socklen_t sa_addroffset(const struct sockaddr *sa);
|
||||
socklen_t sa_addrlen(const struct sockaddr *sa);
|
||||
#ifdef HAVE_SA_LEN
|
||||
#define sa_len(sa) ((sa)->sa_len)
|
||||
#else
|
||||
socklen_t sa_len(const struct sockaddr *sa);
|
||||
#endif
|
||||
bool sa_is_unspecified(const struct sockaddr *);
|
||||
bool sa_is_allones(const struct sockaddr *);
|
||||
bool sa_is_loopback(const struct sockaddr *);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -36,6 +37,7 @@
|
|||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <spawn.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
@ -56,7 +58,7 @@
|
|||
#define RC_SVCNAME "RC_SVCNAME"
|
||||
#endif
|
||||
|
||||
#define DEFAULT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin"
|
||||
#define DEFAULT_PATH "/usr/bin:/usr/sbin:/bin:/sbin"
|
||||
|
||||
static const char * const if_params[] = {
|
||||
"interface",
|
||||
|
@ -120,104 +122,24 @@ exec_script(const struct dhcpcd_ctx *ctx, char *const *argv, char *const *env)
|
|||
}
|
||||
|
||||
#ifdef INET
|
||||
static char *
|
||||
make_var(const char *prefix, const char *var)
|
||||
{
|
||||
size_t len;
|
||||
char *v;
|
||||
|
||||
len = strlen(prefix) + strlen(var) + 2;
|
||||
if ((v = malloc(len)) == NULL) {
|
||||
logerr(__func__);
|
||||
return NULL;
|
||||
}
|
||||
snprintf(v, len, "%s_%s", prefix, var);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
append_config(char ***env, size_t *len,
|
||||
const char *prefix, const char *const *config)
|
||||
append_config(FILE *fp, const char *prefix, const char *const *config)
|
||||
{
|
||||
size_t i, j, e1;
|
||||
char **ne, *eq, **nep, *p;
|
||||
int ret;
|
||||
size_t i;
|
||||
|
||||
if (config == NULL)
|
||||
return 0;
|
||||
|
||||
ne = *env;
|
||||
ret = 0;
|
||||
/* Do we need to replace existing config rather than append? */
|
||||
for (i = 0; config[i] != NULL; i++) {
|
||||
eq = strchr(config[i], '=');
|
||||
e1 = (size_t)(eq - config[i] + 1);
|
||||
for (j = 0; j < *len; j++) {
|
||||
if (strncmp(ne[j], prefix, strlen(prefix)) == 0 &&
|
||||
ne[j][strlen(prefix)] == '_' &&
|
||||
strncmp(ne[j] + strlen(prefix) + 1,
|
||||
config[i], e1) == 0)
|
||||
{
|
||||
p = make_var(prefix, config[i]);
|
||||
if (p == NULL) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
free(ne[j]);
|
||||
ne[j] = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == *len) {
|
||||
j++;
|
||||
p = make_var(prefix, config[i]);
|
||||
if (p == NULL) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
nep = realloc(ne, sizeof(char *) * (j + 1));
|
||||
if (nep == NULL) {
|
||||
logerr(__func__);
|
||||
free(p);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
ne = nep;
|
||||
ne[j - 1] = p;
|
||||
*len = j;
|
||||
}
|
||||
if (efprintf(fp, "%s_%s", prefix, config[i]) == -1)
|
||||
return -1;
|
||||
}
|
||||
*env = ne;
|
||||
return ret;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static ssize_t
|
||||
arraytostr(const char *const *argv, char **s)
|
||||
{
|
||||
const char *const *ap;
|
||||
char *p;
|
||||
size_t len, l;
|
||||
|
||||
if (*argv == NULL)
|
||||
return 0;
|
||||
len = 0;
|
||||
ap = argv;
|
||||
while (*ap)
|
||||
len += strlen(*ap++) + 1;
|
||||
*s = p = malloc(len);
|
||||
if (p == NULL)
|
||||
return -1;
|
||||
ap = argv;
|
||||
while (*ap) {
|
||||
l = strlen(*ap) + 1;
|
||||
memcpy(p, *ap, l);
|
||||
p += l;
|
||||
ap++;
|
||||
}
|
||||
return (ssize_t)len;
|
||||
}
|
||||
|
||||
#define PROTO_LINK 0
|
||||
#define PROTO_DHCP 1
|
||||
#define PROTO_IPV4LL 2
|
||||
|
@ -233,15 +155,32 @@ static const char *protocols[] = {
|
|||
"static6"
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
make_env(const struct interface *ifp, const char *reason, char ***argv)
|
||||
int
|
||||
efprintf(FILE *fp, const char *fmt, ...)
|
||||
{
|
||||
int protocol, r;
|
||||
char **env, **nenv, *p;
|
||||
size_t e, elen, l;
|
||||
#if defined(INET) || defined(INET6)
|
||||
ssize_t n;
|
||||
#endif
|
||||
va_list args;
|
||||
int r;
|
||||
|
||||
va_start(args, fmt);
|
||||
r = vfprintf(fp, fmt, args);
|
||||
va_end(args);
|
||||
if (r == -1)
|
||||
return -1;
|
||||
/* Write a trailing NULL so we can easily create env strings. */
|
||||
if (fputc('\0', fp) == EOF)
|
||||
return -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
make_env(const struct interface *ifp, const char *reason)
|
||||
{
|
||||
struct dhcpcd_ctx *ctx = ifp->ctx;
|
||||
FILE *fp;
|
||||
char **env, **envp, *buf, *bufp, *endp, *path;
|
||||
size_t nenv;
|
||||
long buf_pos, i;
|
||||
int protocol;
|
||||
const struct if_options *ifo = ifp->options;
|
||||
const struct interface *ifp2;
|
||||
int af;
|
||||
|
@ -255,6 +194,31 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
|
|||
const struct dhcp6_state *d6_state;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPEN_MEMSTREAM
|
||||
if (ctx->script_fp == NULL) {
|
||||
fp = open_memstream(&ctx->script_buf, &ctx->script_buflen);
|
||||
if (fp == NULL)
|
||||
goto eexit;
|
||||
ctx->script_fp = fp;
|
||||
} else {
|
||||
fp = ctx->script_fp;
|
||||
rewind(fp);
|
||||
}
|
||||
#else
|
||||
char tmpfile[] = "/tmp/dhcpcd-script-env-XXXXXX";
|
||||
int tmpfd;
|
||||
|
||||
fp = NULL;
|
||||
tmpfd = mkstemp(tmpfile);
|
||||
if (tmpfd == -1)
|
||||
goto eexit;
|
||||
unlink(tmpfile);
|
||||
fp = fopen(tmpfile, "w+");
|
||||
close(tmpfd);
|
||||
if (fp == NULL)
|
||||
goto eexit;
|
||||
#endif
|
||||
|
||||
#ifdef INET
|
||||
state = D_STATE(ifp);
|
||||
#ifdef IPV4LL
|
||||
|
@ -309,71 +273,60 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
|
|||
protocol = PROTO_DHCP;
|
||||
#endif
|
||||
|
||||
/* When dumping the lease, we only want to report interface and
|
||||
reason - the other interface variables are meaningless */
|
||||
if (ifp->ctx->options & DHCPCD_DUMPLEASE)
|
||||
elen = 2;
|
||||
else
|
||||
elen = 11;
|
||||
|
||||
#define EMALLOC(i, l) if ((env[(i)] = malloc((l))) == NULL) goto eexit;
|
||||
/* Make our env + space for profile, wireless and debug */
|
||||
env = calloc(1, sizeof(char *) * (elen + 5 + 1));
|
||||
if (env == NULL)
|
||||
/* Needed for scripts */
|
||||
path = getenv("PATH");
|
||||
if (efprintf(fp, "PATH=%s", path == NULL ? DEFAULT_PATH:path) == -1)
|
||||
goto eexit;
|
||||
|
||||
if (efprintf(fp, "interface=%s", ifp->name) == -1)
|
||||
goto eexit;
|
||||
if (efprintf(fp, "reason=%s", reason) == -1)
|
||||
goto eexit;
|
||||
e = strlen("interface") + strlen(ifp->name) + 2;
|
||||
EMALLOC(0, e);
|
||||
snprintf(env[0], e, "interface=%s", ifp->name);
|
||||
e = strlen("reason") + strlen(reason) + 2;
|
||||
EMALLOC(1, e);
|
||||
snprintf(env[1], e, "reason=%s", reason);
|
||||
if (ifp->ctx->options & DHCPCD_DUMPLEASE)
|
||||
goto dumplease;
|
||||
e = 20;
|
||||
EMALLOC(2, e);
|
||||
snprintf(env[2], e, "pid=%d", getpid());
|
||||
EMALLOC(3, e);
|
||||
snprintf(env[3], e, "ifcarrier=%s",
|
||||
if (efprintf(fp, "pid=%d", getpid()) == -1)
|
||||
goto eexit;
|
||||
if (efprintf(fp, "ifcarrier=%s",
|
||||
ifp->carrier == LINK_UNKNOWN ? "unknown" :
|
||||
ifp->carrier == LINK_UP ? "up" : "down");
|
||||
EMALLOC(4, e);
|
||||
snprintf(env[4], e, "ifmetric=%d", ifp->metric);
|
||||
EMALLOC(5, e);
|
||||
snprintf(env[5], e, "ifwireless=%d", ifp->wireless);
|
||||
EMALLOC(6, e);
|
||||
snprintf(env[6], e, "ifflags=%u", ifp->flags);
|
||||
EMALLOC(7, e);
|
||||
snprintf(env[7], e, "ifmtu=%d", if_getmtu(ifp));
|
||||
l = e = strlen("interface_order=");
|
||||
ifp->carrier == LINK_UP ? "up" : "down") == -1)
|
||||
goto eexit;
|
||||
if (efprintf(fp, "ifmetric=%d", ifp->metric) == -1)
|
||||
goto eexit;
|
||||
if (efprintf(fp, "ifwireless=%d", ifp->wireless) == -1)
|
||||
goto eexit;
|
||||
if (efprintf(fp, "ifflags=%u", ifp->flags) == -1)
|
||||
goto eexit;
|
||||
if (efprintf(fp, "ifmtu=%d", if_getmtu(ifp)) == -1)
|
||||
goto eexit;
|
||||
|
||||
if (fprintf(fp, "interface_order=") == -1)
|
||||
goto eexit;
|
||||
TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
|
||||
e += strlen(ifp2->name) + 1;
|
||||
if (ifp2 != TAILQ_FIRST(ifp->ctx->ifaces)) {
|
||||
if (fputc(' ', fp) == EOF)
|
||||
return -1;
|
||||
}
|
||||
if (fprintf(fp, "%s", ifp2->name) == -1)
|
||||
return -1;
|
||||
}
|
||||
EMALLOC(8, e);
|
||||
p = env[8];
|
||||
strlcpy(p, "interface_order=", e);
|
||||
e -= l;
|
||||
p += l;
|
||||
TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
|
||||
l = strlcpy(p, ifp2->name, e);
|
||||
p += l;
|
||||
e -= l;
|
||||
*p++ = ' ';
|
||||
e--;
|
||||
}
|
||||
*--p = '\0';
|
||||
if (fputc('\0', fp) == EOF)
|
||||
return -1;
|
||||
|
||||
if (strcmp(reason, "STOPPED") == 0) {
|
||||
env[9] = strdup("if_up=false");
|
||||
if (ifo->options & DHCPCD_RELEASE)
|
||||
env[10] = strdup("if_down=true");
|
||||
else
|
||||
env[10] = strdup("if_down=false");
|
||||
if (efprintf(fp, "if_up=false") == -1)
|
||||
goto eexit;
|
||||
if (efprintf(fp, "if_down=%s",
|
||||
ifo->options & DHCPCD_RELEASE ? "true" : "false") == -1)
|
||||
goto eexit;
|
||||
} else if (strcmp(reason, "TEST") == 0 ||
|
||||
strcmp(reason, "PREINIT") == 0 ||
|
||||
strcmp(reason, "CARRIER") == 0 ||
|
||||
strcmp(reason, "UNKNOWN") == 0)
|
||||
{
|
||||
env[9] = strdup("if_up=false");
|
||||
env[10] = strdup("if_down=false");
|
||||
if (efprintf(fp, "if_up=false") == -1)
|
||||
goto eexit;
|
||||
if (efprintf(fp, "if_down=false") == -1)
|
||||
goto eexit;
|
||||
} else if (1 == 2 /* appease ifdefs */
|
||||
#ifdef INET
|
||||
|| (protocol == PROTO_DHCP && state && state->new)
|
||||
|
@ -390,24 +343,23 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
|
|||
#endif
|
||||
)
|
||||
{
|
||||
env[9] = strdup("if_up=true");
|
||||
env[10] = strdup("if_down=false");
|
||||
} else {
|
||||
env[9] = strdup("if_up=false");
|
||||
env[10] = strdup("if_down=true");
|
||||
}
|
||||
if (env[9] == NULL || env[10] == NULL)
|
||||
goto eexit;
|
||||
if (protocols[protocol] != NULL) {
|
||||
r = asprintf(&env[elen], "protocol=%s", protocols[protocol]);
|
||||
if (r == -1)
|
||||
if (efprintf(fp, "if_up=true") == -1)
|
||||
goto eexit;
|
||||
if (efprintf(fp, "if_down=false") == -1)
|
||||
goto eexit;
|
||||
} else {
|
||||
if (efprintf(fp, "if_up=false") == -1)
|
||||
goto eexit;
|
||||
if (efprintf(fp, "if_down=true") == -1)
|
||||
goto eexit;
|
||||
}
|
||||
if (protocols[protocol] != NULL) {
|
||||
if (efprintf(fp, "protocol=%s", protocols[protocol]) == -1)
|
||||
goto eexit;
|
||||
elen++;
|
||||
}
|
||||
if ((af = dhcpcd_ifafwaiting(ifp)) != AF_MAX) {
|
||||
e = 20;
|
||||
EMALLOC(elen, e);
|
||||
snprintf(env[elen++], e, "if_afwaiting=%d", af);
|
||||
if (efprintf(fp, "if_afwaiting=%d", af) == -1)
|
||||
goto eexit;
|
||||
}
|
||||
if ((af = dhcpcd_afwaiting(ifp->ctx)) != AF_MAX) {
|
||||
TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
|
||||
|
@ -416,75 +368,42 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
|
|||
}
|
||||
}
|
||||
if (af != AF_MAX) {
|
||||
e = 20;
|
||||
EMALLOC(elen, e);
|
||||
snprintf(env[elen++], e, "af_waiting=%d", af);
|
||||
if (efprintf(fp, "af_waiting=%d", af) == -1)
|
||||
goto eexit;
|
||||
}
|
||||
if (ifo->options & DHCPCD_DEBUG) {
|
||||
e = strlen("syslog_debug=true") + 1;
|
||||
EMALLOC(elen, e);
|
||||
snprintf(env[elen++], e, "syslog_debug=true");
|
||||
if (efprintf(fp, "syslog_debug=true") == -1)
|
||||
goto eexit;
|
||||
}
|
||||
if (*ifp->profile) {
|
||||
e = strlen("profile=") + strlen(ifp->profile) + 1;
|
||||
EMALLOC(elen, e);
|
||||
snprintf(env[elen++], e, "profile=%s", ifp->profile);
|
||||
if (efprintf(fp, "profile=%s", ifp->profile) == -1)
|
||||
goto eexit;
|
||||
}
|
||||
if (ifp->wireless) {
|
||||
static const char *pfx = "ifssid=";
|
||||
size_t pfx_len;
|
||||
ssize_t psl;
|
||||
char pssid[IF_SSIDLEN * 4];
|
||||
|
||||
pfx_len = strlen(pfx);
|
||||
psl = print_string(NULL, 0, OT_ESCSTRING,
|
||||
(const uint8_t *)ifp->ssid, ifp->ssid_len);
|
||||
if (psl != -1) {
|
||||
EMALLOC(elen, pfx_len + (size_t)psl + 1);
|
||||
memcpy(env[elen], pfx, pfx_len);
|
||||
print_string(env[elen] + pfx_len, (size_t)psl + 1,
|
||||
OT_ESCSTRING,
|
||||
(const uint8_t *)ifp->ssid, ifp->ssid_len);
|
||||
elen++;
|
||||
if (print_string(pssid, sizeof(pssid), OT_ESCSTRING,
|
||||
ifp->ssid, ifp->ssid_len) != -1)
|
||||
{
|
||||
if (efprintf(fp, "ifssid=%s", pssid) == -1)
|
||||
goto eexit;
|
||||
}
|
||||
}
|
||||
#ifdef INET
|
||||
if (protocol == PROTO_DHCP && state && state->old) {
|
||||
n = dhcp_env(NULL, NULL, state->old, state->old_len, ifp);
|
||||
if (n == -1)
|
||||
if (dhcp_env(fp, "old", ifp,
|
||||
state->old, state->old_len) == -1)
|
||||
goto eexit;
|
||||
if (n > 0) {
|
||||
nenv = realloc(env, sizeof(char *) *
|
||||
(elen + (size_t)n + 1));
|
||||
if (nenv == NULL)
|
||||
goto eexit;
|
||||
env = nenv;
|
||||
n = dhcp_env(env + elen, "old",
|
||||
state->old, state->old_len, ifp);
|
||||
if (n == -1)
|
||||
goto eexit;
|
||||
elen += (size_t)n;
|
||||
}
|
||||
if (append_config(&env, &elen, "old",
|
||||
if (append_config(fp, "old",
|
||||
(const char *const *)ifo->config) == -1)
|
||||
goto eexit;
|
||||
}
|
||||
#endif
|
||||
#ifdef DHCP6
|
||||
if (protocol == PROTO_DHCP6 && d6_state && d6_state->old) {
|
||||
n = dhcp6_env(NULL, NULL, ifp,
|
||||
d6_state->old, d6_state->old_len);
|
||||
if (n > 0) {
|
||||
nenv = realloc(env, sizeof(char *) *
|
||||
(elen + (size_t)n + 1));
|
||||
if (nenv == NULL)
|
||||
goto eexit;
|
||||
env = nenv;
|
||||
n = dhcp6_env(env + elen, "old", ifp,
|
||||
d6_state->old, d6_state->old_len);
|
||||
if (n == -1)
|
||||
goto eexit;
|
||||
elen += (size_t)n;
|
||||
}
|
||||
if (dhcp6_env(fp, "old", ifp,
|
||||
d6_state->old, d6_state->old_len) == -1)
|
||||
goto eexit;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -492,144 +411,114 @@ dumplease:
|
|||
#ifdef INET
|
||||
#ifdef IPV4LL
|
||||
if (protocol == PROTO_IPV4LL) {
|
||||
n = ipv4ll_env(NULL, NULL, ifp);
|
||||
if (n > 0) {
|
||||
nenv = realloc(env, sizeof(char *) *
|
||||
(elen + (size_t)n + 1));
|
||||
if (nenv == NULL)
|
||||
goto eexit;
|
||||
env = nenv;
|
||||
if ((n = ipv4ll_env(env + elen,
|
||||
istate->down ? "old" : "new", ifp)) == -1)
|
||||
goto eexit;
|
||||
elen += (size_t)n;
|
||||
}
|
||||
if (ipv4ll_env(fp, istate->down ? "old" : "new", ifp) == -1)
|
||||
goto eexit;
|
||||
}
|
||||
#endif
|
||||
if (protocol == PROTO_DHCP && state && state->new) {
|
||||
n = dhcp_env(NULL, NULL, state->new, state->new_len, ifp);
|
||||
if (n > 0) {
|
||||
nenv = realloc(env, sizeof(char *) *
|
||||
(elen + (size_t)n + 1));
|
||||
if (nenv == NULL)
|
||||
goto eexit;
|
||||
env = nenv;
|
||||
n = dhcp_env(env + elen, "new",
|
||||
state->new, state->new_len, ifp);
|
||||
if (n == -1)
|
||||
goto eexit;
|
||||
elen += (size_t)n;
|
||||
}
|
||||
if (append_config(&env, &elen, "new",
|
||||
if (dhcp_env(fp, "new", ifp,
|
||||
state->new, state->new_len) == -1)
|
||||
goto eexit;
|
||||
if (append_config(fp, "new",
|
||||
(const char *const *)ifo->config) == -1)
|
||||
goto eexit;
|
||||
}
|
||||
#endif
|
||||
#ifdef INET6
|
||||
if (protocol == PROTO_STATIC6) {
|
||||
n = ipv6_env(NULL, NULL, ifp);
|
||||
if (n > 0) {
|
||||
nenv = realloc(env, sizeof(char *) *
|
||||
(elen + (size_t)n + 1));
|
||||
if (nenv == NULL)
|
||||
goto eexit;
|
||||
env = nenv;
|
||||
n = ipv6_env(env + elen, "new", ifp);
|
||||
if (n == -1)
|
||||
goto eexit;
|
||||
elen += (size_t)n;
|
||||
}
|
||||
if (ipv6_env(fp, "new", ifp) == -1)
|
||||
goto eexit;
|
||||
}
|
||||
#ifdef DHCP6
|
||||
if (protocol == PROTO_DHCP6 && D6_STATE_RUNNING(ifp)) {
|
||||
n = dhcp6_env(NULL, NULL, ifp,
|
||||
d6_state->new, d6_state->new_len);
|
||||
if (n > 0) {
|
||||
nenv = realloc(env, sizeof(char *) *
|
||||
(elen + (size_t)n + 1));
|
||||
if (nenv == NULL)
|
||||
goto eexit;
|
||||
env = nenv;
|
||||
n = dhcp6_env(env + elen, "new", ifp,
|
||||
d6_state->new, d6_state->new_len);
|
||||
if (n == -1)
|
||||
goto eexit;
|
||||
elen += (size_t)n;
|
||||
}
|
||||
if (dhcp6_env(fp, "new", ifp,
|
||||
d6_state->new, d6_state->new_len) == -1)
|
||||
goto eexit;
|
||||
}
|
||||
#endif
|
||||
if (protocol == PROTO_RA) {
|
||||
n = ipv6nd_env(NULL, NULL, ifp);
|
||||
if (n > 0) {
|
||||
nenv = realloc(env, sizeof(char *) *
|
||||
(elen + (size_t)n + 1));
|
||||
if (nenv == NULL)
|
||||
goto eexit;
|
||||
env = nenv;
|
||||
n = ipv6nd_env(env + elen, NULL, ifp);
|
||||
if (n == -1)
|
||||
goto eexit;
|
||||
elen += (size_t)n;
|
||||
}
|
||||
if (ipv6nd_env(fp, ifp) == -1)
|
||||
goto eexit;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Add our base environment */
|
||||
if (ifo->environ) {
|
||||
e = 0;
|
||||
while (ifo->environ[e++])
|
||||
;
|
||||
nenv = realloc(env, sizeof(char *) * (elen + e + 1));
|
||||
if (nenv == NULL)
|
||||
goto eexit;
|
||||
env = nenv;
|
||||
e = 0;
|
||||
while (ifo->environ[e]) {
|
||||
env[elen + e] = strdup(ifo->environ[e]);
|
||||
if (env[elen + e] == NULL)
|
||||
for (i = 0; ifo->environ[i] != NULL; i++)
|
||||
if (efprintf(fp, "%s", ifo->environ[i]) == -1)
|
||||
goto eexit;
|
||||
e++;
|
||||
}
|
||||
elen += e;
|
||||
}
|
||||
env[elen] = NULL;
|
||||
|
||||
*argv = env;
|
||||
return (ssize_t)elen;
|
||||
/* Convert buffer to argv */
|
||||
fflush(fp);
|
||||
|
||||
buf_pos = ftell(fp);
|
||||
if (buf_pos == -1) {
|
||||
logerr(__func__);
|
||||
goto eexit;
|
||||
}
|
||||
#ifdef HAVE_OPEN_MEMSTREAM
|
||||
buf = ctx->script_buf;
|
||||
#else
|
||||
size_t buf_len = (size_t)buf_pos;
|
||||
if (ctx->script_buflen < buf_len) {
|
||||
buf = realloc(ctx->script_buf, buf_len);
|
||||
if (buf == NULL)
|
||||
goto eexit;
|
||||
ctx->script_buf = buf;
|
||||
ctx->script_buflen = buf_len;
|
||||
}
|
||||
buf = ctx->script_buf;
|
||||
rewind(fp);
|
||||
if (fread(buf, sizeof(char), buf_len, fp) != buf_len)
|
||||
goto eexit;
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
#endif
|
||||
|
||||
nenv = 0;
|
||||
endp = buf + buf_pos;
|
||||
for (bufp = buf; bufp < endp; bufp++) {
|
||||
if (*bufp == '\0')
|
||||
nenv++;
|
||||
}
|
||||
if (ctx->script_envlen < nenv) {
|
||||
env = reallocarray(ctx->script_env, nenv + 1, sizeof(*env));
|
||||
if (env == NULL)
|
||||
goto eexit;
|
||||
ctx->script_env = env;
|
||||
ctx->script_envlen = nenv;
|
||||
}
|
||||
bufp = buf;
|
||||
envp = ctx->script_env;
|
||||
*envp++ = bufp++;
|
||||
endp--; /* Avoid setting the last \0 to an invalid pointer */
|
||||
for (; bufp < endp; bufp++) {
|
||||
if (*bufp == '\0')
|
||||
*envp++ = bufp + 1;
|
||||
}
|
||||
*envp = NULL;
|
||||
|
||||
return (ssize_t)nenv;
|
||||
|
||||
eexit:
|
||||
logerr(__func__);
|
||||
if (env) {
|
||||
nenv = env;
|
||||
while (*nenv)
|
||||
free(*nenv++);
|
||||
free(env);
|
||||
}
|
||||
#ifndef HAVE_OPEN_MEMSTREAM
|
||||
if (fp != NULL)
|
||||
fclose(fp);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
send_interface1(struct fd_list *fd, const struct interface *iface,
|
||||
send_interface1(struct fd_list *fd, const struct interface *ifp,
|
||||
const char *reason)
|
||||
{
|
||||
char **env, **ep, *s;
|
||||
size_t elen;
|
||||
int retval;
|
||||
struct dhcpcd_ctx *ctx = ifp->ctx;
|
||||
|
||||
if (make_env(iface, reason, &env) == -1)
|
||||
if (make_env(ifp, reason) == -1)
|
||||
return -1;
|
||||
s = NULL;
|
||||
elen = (size_t)arraytostr((const char *const *)env, &s);
|
||||
if ((ssize_t)elen == -1) {
|
||||
free(s);
|
||||
retval = -1;
|
||||
} else
|
||||
retval = control_queue(fd, s, elen, 1);
|
||||
ep = env;
|
||||
while (*ep)
|
||||
free(*ep++);
|
||||
free(env);
|
||||
return retval;
|
||||
return control_queue(fd, ctx->script_buf, ctx->script_buflen, 1);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -696,10 +585,8 @@ send_interface(struct fd_list *fd, const struct interface *ifp)
|
|||
int
|
||||
script_runreason(const struct interface *ifp, const char *reason)
|
||||
{
|
||||
struct dhcpcd_ctx *ctx = ifp->ctx;
|
||||
char *argv[2];
|
||||
char **env = NULL, **ep;
|
||||
char *svcname, *path, *bigenv;
|
||||
size_t e, elen = 0;
|
||||
pid_t pid;
|
||||
int status = 0;
|
||||
struct fd_list *fd;
|
||||
|
@ -709,8 +596,7 @@ script_runreason(const struct interface *ifp, const char *reason)
|
|||
return 0;
|
||||
|
||||
/* Make our env */
|
||||
elen = (size_t)make_env(ifp, reason, &env);
|
||||
if (elen == (size_t)-1) {
|
||||
if (make_env(ifp, reason) == -1) {
|
||||
logerr(__func__);
|
||||
return -1;
|
||||
}
|
||||
|
@ -722,43 +608,7 @@ script_runreason(const struct interface *ifp, const char *reason)
|
|||
argv[1] = NULL;
|
||||
logdebugx("%s: executing `%s' %s", ifp->name, argv[0], reason);
|
||||
|
||||
/* Resize for PATH and RC_SVCNAME */
|
||||
svcname = getenv(RC_SVCNAME);
|
||||
ep = reallocarray(env, elen + 2 + (svcname ? 1 : 0), sizeof(char *));
|
||||
if (ep == NULL) {
|
||||
elen = 0;
|
||||
goto out;
|
||||
}
|
||||
env = ep;
|
||||
/* Add path to it */
|
||||
path = getenv("PATH");
|
||||
if (path) {
|
||||
e = strlen("PATH") + strlen(path) + 2;
|
||||
env[elen] = malloc(e);
|
||||
if (env[elen] == NULL) {
|
||||
elen = 0;
|
||||
goto out;
|
||||
}
|
||||
snprintf(env[elen], e, "PATH=%s", path);
|
||||
} else {
|
||||
env[elen] = strdup(DEFAULT_PATH);
|
||||
if (env[elen] == NULL) {
|
||||
elen = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (svcname) {
|
||||
e = strlen(RC_SVCNAME) + strlen(svcname) + 2;
|
||||
env[++elen] = malloc(e);
|
||||
if (env[elen] == NULL) {
|
||||
elen = 0;
|
||||
goto out;
|
||||
}
|
||||
snprintf(env[elen], e, "%s=%s", RC_SVCNAME, svcname);
|
||||
}
|
||||
env[++elen] = NULL;
|
||||
|
||||
pid = exec_script(ifp->ctx, argv, env);
|
||||
pid = exec_script(ctx, argv, ctx->script_env);
|
||||
if (pid == -1)
|
||||
logerr("%s: %s", __func__, argv[0]);
|
||||
else if (pid != 0) {
|
||||
|
@ -781,36 +631,16 @@ script_runreason(const struct interface *ifp, const char *reason)
|
|||
|
||||
send_listeners:
|
||||
/* Send to our listeners */
|
||||
bigenv = NULL;
|
||||
status = 0;
|
||||
TAILQ_FOREACH(fd, &ifp->ctx->control_fds, next) {
|
||||
TAILQ_FOREACH(fd, &ctx->control_fds, next) {
|
||||
if (!(fd->flags & FD_LISTEN))
|
||||
continue;
|
||||
if (bigenv == NULL) {
|
||||
elen = (size_t)arraytostr((const char *const *)env,
|
||||
&bigenv);
|
||||
if ((ssize_t)elen == -1) {
|
||||
logerr("%s: arraytostr", ifp->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (control_queue(fd, bigenv, elen, 1) == -1)
|
||||
if (control_queue(fd, ctx->script_buf, ctx->script_buflen, 1)
|
||||
== -1)
|
||||
logerr("%s: control_queue", __func__);
|
||||
else
|
||||
status = 1;
|
||||
}
|
||||
if (!status)
|
||||
free(bigenv);
|
||||
|
||||
out:
|
||||
/* Cleanup */
|
||||
ep = env;
|
||||
while (*ep)
|
||||
free(*ep++);
|
||||
free(env);
|
||||
if (elen == 0) {
|
||||
logerr(__func__);
|
||||
return -1;
|
||||
}
|
||||
return WEXITSTATUS(status);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
|
||||
|
@ -30,6 +31,7 @@
|
|||
|
||||
#include "control.h"
|
||||
|
||||
__printflike(2, 3) int efprintf(FILE *, const char *, ...);
|
||||
void if_printoptions(void);
|
||||
int send_interface(struct fd_list *, const struct interface *);
|
||||
int script_runreason(const struct interface *, const char *);
|
||||
|
|
Loading…
Reference in New Issue