The configure program attempts to find hooks for systems you have installed.
To add more simply
`./configure -with-hook=ntp.conf`
+
+If using resolvconf, the `20-resolv.conf` hook now requires a version with the
+`-C` and `-c` options to deprecate and activate interfaces to support wireless
+roaming (Linux) or carrier just drops (NetBSD).
+If your resolvconf does not support this then you will see a warning
+about an illegal option when the carrier changes, but things should still work.
+In this instance the DNS information cannot be Deprecated and may not
+be optimal for multi-homed hosts.
NL="
"
: ${resolvconf:=resolvconf}
+if type "$resolvconf" >/dev/null 2>&1; then
+ have_resolvconf=true
+else
+ have_resolvconf=false
+fi
build_resolv_conf()
{
for x in ${new_domain_name_servers}; do
conf="${conf}nameserver $x$NL"
done
- if type "$resolvconf" >/dev/null 2>&1; then
+ if $have_resolvconf; then
[ -n "$ifmetric" ] && export IF_METRIC="$ifmetric"
printf %s "$conf" | "$resolvconf" -a "$ifname"
return $?
remove_resolv_conf()
{
- if type "$resolvconf" >/dev/null 2>&1; then
+ if $have_resolvconf; then
"$resolvconf" -d "$ifname" -f
else
if [ -e "$resolv_conf_dir/$ifname" ]; then
esac
if $if_configured; then
- if $if_up || [ "$reason" = ROUTERADVERT ]; then
+ if $have_resolvconf && [ "$reason" = NOCARRIER_ROAMING ]; then
+ "$resolvconf" -C "$interface.*"
+ elif $have_resolvconf && [ "$reason" = CARRIER ]; then
+ "$resolvconf" -c "$interface.*"
+ elif $if_up || [ "$reason" = ROUTERADVERT ]; then
add_resolv_conf
elif $if_down; then
remove_resolv_conf
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd May 24, 2020
+.Dd December 27, 2020
.Dt DHCPCD-RUN-HOOKS 8
.Os
.Sh NAME
.It Dv NOCARRIER
dhcpcd lost the carrier.
The cable may have been unplugged or association to the wireless point lost.
+.It Dv NOCARRIER_ROAMING
+dhcpcd lost the carrier but the interface configuration is persisted.
+The OS has to support wireless roaming or IP Persistance for this to happen.
.It Dv INFORM | Dv INFORM6
dhcpcd informed a DHCP server about its address and obtained other
configuration details.
The following variables will then be set, along with any protocol supplied
ones.
.Bl -tag -width xnew_delegated_dhcp6_prefix
-.It Ev $chroot
-the directory where
-.Nm dhcpcd
-is chrooted.
.It Ev $interface
the name of the interface.
.It Ev $protocol
.Ev interface
is up, otherwise
.Dv false .
+This is more than IFF_UP and may not be equal.
.It Ev $if_down
.Dv true
if the
.Ev interface
is down, otherwise
.Dv false .
+This is more than IFF_UP and may not be equal.
.It Ev $af_waiting
Address family waiting for, as defined in
.Xr dhcpcd.conf 5 .
{
loginfox("%s: carrier lost - roaming", ifp->name);
-
- /*
- * XXX We should pass something like NOCARRIER_ROAMING
- * and set if_up=true; ifdown=false; so that the hook scripts
- * can make a decision to keep or discard the interface information.
- *
- * Currently they discard it (no carrier after all) which is
- * generally fine as new connections won't work and current
- * connections try to chug along as best as.
- * dhcpcd has been doing this since NetBSD-7 at least.
- *
- * However, for slow roaming this is poor for say web browsing
- * as new lookups will fail quickly giving a poor user experience.
- * We should improve this, but the hooks will require some work first
- * as we need to introduce a mechanism to sort interfaces by
- * carrier > roaming > nocarrier. Then the hooks know in which
- * order to apply their data, if at all.
- * This probably should be a user toggle.
- */
- script_runreason(ifp, "NOCARRIER");
+ script_runreason(ifp, "NOCARRIER_ROAMING");
#ifdef ARP
arp_drop(ifp);
ifp->metric = (unsigned int)ifr.ifr_metric;
if_getssid(ifp);
#else
- /* We reserve the 100 range for virtual interfaces, if and when
- * we can work them out. */
- ifp->metric = 200 + ifp->index;
+ /* Leave a low portion for user config */
+ ifp->metric = RTMETRIC_BASE + ifp->index;
if (if_getssid(ifp) != -1) {
ifp->wireless = true;
- ifp->metric += 100;
+ ifp->metric += RTMETRIC_WIRELESS;
}
#endif
sa_in_init(&rt->rt_ifa, &state->addr->addr);
rt->rt_dflags |= RTDF_IPV4LL;
#ifdef HAVE_ROUTE_METRIC
- rt->rt_metric += 10000;
+ rt->rt_metric += RTMETRIC_IPV4LL;
#endif
return rt_proto_add(routes, rt) ? 1 : 0;
}
if (c != 0)
return -c;
+ /* Prefer roaming over non roaming if both carriers are down. */
+ if (ifp1->carrier == LINK_DOWN && ifp2->carrier == LINK_DOWN) {
+ bool roam1 = if_roaming(ifp1);
+ bool roam2 = if_roaming(ifp2);
+
+ if (roam1 != roam2)
+ return roam1 ? 1 : -1;
+ }
+
#ifdef INET
/* IPv4LL routes always come last */
if (rt1->rt_dflags & RTDF_IPV4LL && !(rt2->rt_dflags & RTDF_IPV4LL))
rt->rt_ifp = ifp;
#ifdef HAVE_ROUTE_METRIC
rt->rt_metric = ifp->metric;
+ if (if_roaming(ifp))
+ rt->rt_metric += RTMETRIC_ROAM;
#endif
}
#ifdef HAVE_ROUTE_METRIC
unsigned int rt_metric;
#endif
+/* Maximum interface index is generally USHORT_MAX or 65535.
+ * Add some padding for other stuff and we get offsets for the
+ * below that should work automatically.
+ * This is only an issue if the user defines higher metrics in
+ * their configuration, but then they might wish to override also. */
+#define RTMETRIC_BASE 1000U
+#define RTMETRIC_WIRELESS 2000U
+#define RTMETRIC_IPV4LL 1000000U
+#define RTMETRIC_ROAM 2000000U
#ifdef HAVE_ROUTE_PREF
int rt_pref;
#endif
NULL
};
+static const char * true_str = "true";
+static const char * false_str = "false";
+
void
if_printoptions(void)
{
const struct if_options *ifo;
const struct interface *ifp2;
int af;
+ bool is_stdin = ifp->name[0] == '\0';
+ const char *if_up, *if_down;
+ rb_tree_t ifaces;
+ struct rt *rt;
#ifdef INET
const struct dhcp_state *state;
#ifdef IPV4LL
#ifdef DHCP6
const struct dhcp6_state *d6_state;
#endif
- bool is_stdin = ifp->name[0] == '\0';
#ifdef HAVE_OPEN_MEMSTREAM
if (ctx->script_fp == NULL) {
if (efprintf(fp, "pid=%d", getpid()) == -1)
goto eexit;
}
+
if (!is_stdin) {
if (efprintf(fp, "reason=%s", reason) == -1)
goto eexit;
else if (strcmp(reason, "PREINIT") == 0 ||
strcmp(reason, "CARRIER") == 0 ||
strcmp(reason, "NOCARRIER") == 0 ||
+ strcmp(reason, "NOCARRIER_ROAMING") == 0 ||
strcmp(reason, "UNKNOWN") == 0 ||
strcmp(reason, "DEPARTED") == 0 ||
strcmp(reason, "STOPPED") == 0)
if (ifp->ctx->options & DHCPCD_DUMPLEASE)
goto dumplease;
+ rb_tree_init(&ifaces, &rt_compare_proto_ops);
+ TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
+ rt = rt_new(UNCONST(ifp2));
+ if (rt == NULL)
+ goto eexit;
+ if (rb_tree_insert_node(&ifaces, rt) != rt)
+ goto eexit;
+ }
if (fprintf(fp, "interface_order=") == -1)
goto eexit;
- TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
- if (ifp2 != TAILQ_FIRST(ifp->ctx->ifaces)) {
- if (fputc(' ', fp) == EOF)
- return -1;
- }
- if (fprintf(fp, "%s", ifp2->name) == -1)
- return -1;
+ RB_TREE_FOREACH(rt, &ifaces) {
+ if (rt != RB_TREE_MIN(&ifaces) &&
+ fprintf(fp, "%s", " ") == -1)
+ goto eexit;
+ if (fprintf(fp, "%s", rt->rt_ifp->name) == -1)
+ goto eexit;
}
+ rt_headclear(&ifaces, AF_UNSPEC);
if (fputc('\0', fp) == EOF)
- return -1;
+ goto eexit;
if (strcmp(reason, "STOPPED") == 0) {
- if (efprintf(fp, "if_up=false") == -1)
- goto eexit;
- if (efprintf(fp, "if_down=%s",
- ifo->options & DHCPCD_RELEASE ? "true" : "false") == -1)
- goto eexit;
+ if_up = false_str;
+ if_down = ifo->options & DHCPCD_RELEASE ? true_str : false_str;
} else if (strcmp(reason, "TEST") == 0 ||
strcmp(reason, "PREINIT") == 0 ||
strcmp(reason, "CARRIER") == 0 ||
strcmp(reason, "UNKNOWN") == 0)
{
- if (efprintf(fp, "if_up=false") == -1)
- goto eexit;
- if (efprintf(fp, "if_down=false") == -1)
- goto eexit;
+ if_up = false_str;
+ if_down = false_str;
+ } else if (strcmp(reason, "NOCARRIER") == 0) {
+ if_up = false_str;
+ if_down = true_str;
+ } else if (strcmp(reason, "NOCARRIER_ROAMING") == 0) {
+ if_up = true_str;
+ if_down = false_str;
} else if (1 == 2 /* appease ifdefs */
#ifdef INET
|| (protocol == PROTO_DHCP && state && state->new)
#endif
)
{
- if (efprintf(fp, "if_up=true") == -1)
- goto eexit;
- if (efprintf(fp, "if_down=false") == -1)
- goto eexit;
+ if_up = true_str;
+ if_down = false_str;
} else {
- if (efprintf(fp, "if_up=false") == -1)
- goto eexit;
- if (efprintf(fp, "if_down=true") == -1)
- goto eexit;
+ if_up = false_str;
+ if_down = true_str;
}
+ if (efprintf(fp, "if_up=%s", if_up) == -1)
+ goto eexit;
+ if (efprintf(fp, "if_down=%s", if_down) == -1)
+ goto eexit;
+
if ((af = dhcpcd_ifafwaiting(ifp)) != AF_MAX) {
if (efprintf(fp, "if_afwaiting=%d", af) == -1)
goto eexit;