Import dhcpcd-5.2.8 with the following changes from 5.2.4
* Use dynamically sized buffers for reading kernel link events * Use the active link address * Added option to dump a lease to stdout * TEST mode now works correctly if an old lease is NAKed * routes with the gateway = leased ip are now treated as host routes
This commit is contained in:
parent
b5a696dfa9
commit
ada0026e42
|
@ -551,6 +551,21 @@ get_routes(const struct interface *iface)
|
|||
iface->name, &iface->state->options->options);
|
||||
}
|
||||
|
||||
/* Some DHCP servers add set host routes by setting the gateway
|
||||
* to the assinged IP address. This differs from our notion of a host route
|
||||
* where the gateway is the destination address, so we fix it. */
|
||||
static struct rt *
|
||||
massage_host_routes(struct rt *rt, const struct interface *iface)
|
||||
{
|
||||
struct rt *r;
|
||||
|
||||
for (r = rt; r; r = r->next)
|
||||
if (r->gate.s_addr == iface->addr.s_addr &&
|
||||
r->net.s_addr == INADDR_BROADCAST)
|
||||
r->gate.s_addr = r->dest.s_addr;
|
||||
return rt;
|
||||
}
|
||||
|
||||
static struct rt *
|
||||
add_destination_route(struct rt *rt, const struct interface *iface)
|
||||
{
|
||||
|
@ -629,6 +644,7 @@ build_routes(void)
|
|||
if (ifp->state->new == NULL)
|
||||
continue;
|
||||
dnr = get_routes(ifp);
|
||||
dnr = massage_host_routes(dnr, ifp);
|
||||
dnr = add_subnet_route(dnr, ifp);
|
||||
dnr = add_router_host_route(dnr, ifp);
|
||||
dnr = add_destination_route(dnr, ifp);
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#define CONFIG_H
|
||||
|
||||
#define PACKAGE "dhcpcd"
|
||||
#define VERSION "5.2.4"
|
||||
#define VERSION "5.2.8"
|
||||
|
||||
#ifndef CONFIG
|
||||
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"
|
||||
|
|
|
@ -1052,7 +1052,7 @@ write_lease(const struct interface *iface, const struct dhcp_message *dhcp)
|
|||
syslog(LOG_DEBUG, "%s: writing lease `%s'",
|
||||
iface->name, iface->leasefile);
|
||||
|
||||
fd = open(iface->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0400);
|
||||
fd = open(iface->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0444);
|
||||
if (fd == -1) {
|
||||
syslog(LOG_ERR, "%s: open: %m", iface->name);
|
||||
return -1;
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# Just echo our DHCP options we have
|
||||
|
||||
if [ "$reason" = "DUMP" ]; then
|
||||
set | sed -ne 's/^new_//p' | sort
|
||||
fi
|
|
@ -4,7 +4,7 @@ mtu_dir="$state_dir/mtu"
|
|||
|
||||
if [ "$reason" = PREINIT -a -e "$mtu_dir/$interface" ]; then
|
||||
rm "$mtu_dir/$interface"
|
||||
elif [ "$reason" != TEST -a -n "$new_interface_mtu" ]; then
|
||||
elif [ -n "$new_interface_mtu" ] && $if_up; then
|
||||
# The smalled MTU dhcpcd can work with is 576
|
||||
if [ "$new_interface_mtu" -ge 576 ]; then
|
||||
if ifconfig "$interface" mtu "$new_interface_mtu"; then
|
||||
|
@ -16,10 +16,12 @@ elif [ "$reason" != TEST -a -n "$new_interface_mtu" ]; then
|
|||
fi
|
||||
fi
|
||||
fi
|
||||
elif [ "$reason" != TEST -a -e "$mtu_dir/$interface" ]; then
|
||||
# No MTU in this state, so restore the prior MTU
|
||||
mtu=$(cat "$mtu_dir/$interface")
|
||||
syslog info "$interface: MTU restored to $mtu"
|
||||
ifconfig "$interface" mtu "$mtu"
|
||||
rm "$mtu_dir/$interface"
|
||||
elif [ -e "$mtu_dir/$interface" ]; then
|
||||
if $if_up || $if_down; then
|
||||
# No MTU in this state, so restore the prior MTU
|
||||
mtu=$(cat "$mtu_dir/$interface")
|
||||
syslog info "$interface: MTU restored to $mtu"
|
||||
ifconfig "$interface" mtu "$mtu"
|
||||
rm "$mtu_dir/$interface"
|
||||
fi
|
||||
fi
|
||||
|
|
|
@ -119,7 +119,8 @@ remove_resolv_conf()
|
|||
fi
|
||||
}
|
||||
|
||||
case "$reason" in
|
||||
BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT|STATIC) add_resolv_conf;;
|
||||
PREINIT|EXPIRE|FAIL|IPV4LL|NAK|NOCARRIER|RELEASE|STOP) remove_resolv_conf;;
|
||||
esac
|
||||
if $if_up; then
|
||||
add_resolv_conf
|
||||
elif $if_down; then
|
||||
remove_resolv_conf
|
||||
fi
|
||||
|
|
|
@ -29,6 +29,6 @@ set_hostname()
|
|||
fi
|
||||
}
|
||||
|
||||
case "$reason" in
|
||||
BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT|STATIC) set_hostname;;
|
||||
esac
|
||||
if $if_up; then
|
||||
set_hostname
|
||||
fi
|
||||
|
|
|
@ -29,6 +29,6 @@ set_hostname()
|
|||
fi
|
||||
}
|
||||
|
||||
case "$reason" in
|
||||
BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT|STATIC) set_hostname;;
|
||||
esac
|
||||
if $if_up; then
|
||||
set_hostname
|
||||
fi
|
||||
|
|
|
@ -8,14 +8,12 @@
|
|||
# NTP_CONF=/usr/pkg/etc/ntpd.conf
|
||||
# to use openntpd from pkgsrc instead of the system provided ntp.
|
||||
|
||||
# Detect OpenRC or BSD rc
|
||||
# Distributions may want to just have their command here instead of this
|
||||
if type rc-service >/dev/null 2>&1 && rc-service --exists ntpd; then
|
||||
ntpd_restart_cmd="rc-service ntpd -- -Ds restart"
|
||||
elif [ -x /etc/rc.d/ntpd ]; then
|
||||
ntpd_restart_cmd="/etc/rc.d/ntpd status >/dev/null 2>&1 && /etc/rc.d/ntpd restart"
|
||||
elif [ -x /usr/local/etc/rc.d/ntpd ]; then
|
||||
ntpd_restart_cmd="/usr/local/etc/rc.d/ntpd status >/dev/null 2>&1 && /usr/local/etc/rc.d/ntpd restart"
|
||||
: ${ntpd_restart_cmd:="service_condcommand ntpd restart || service_condcommand ntp restart"}
|
||||
if type invoke-rc.d >/dev/null 2>&1; then
|
||||
# Debian has a seperate file for DHCP config to avoid stamping on
|
||||
# the master.
|
||||
[ -e /var/lib/ntp ] || mkdir /var/lib/ntp
|
||||
: ${NTP_DHCP_CONF:=/var/lib/ntp/ntp.conf.dhcp}
|
||||
fi
|
||||
|
||||
ntp_conf_dir="$state_dir/ntp.conf"
|
||||
|
@ -48,14 +46,21 @@ build_ntp_conf()
|
|||
# Merge our config into ntp.conf
|
||||
[ -e "$cf" ] && rm -f "$cf"
|
||||
[ -d "$ntp_conf_dir" ] || mkdir -p "$ntp_conf_dir"
|
||||
if [ -e "$ntp_conf" ]; then
|
||||
|
||||
if [ -n "$NTP_DHCP_CONF" ]; then
|
||||
cp "$ntp_conf" "$cf"
|
||||
ntp_conf="$NTP_DHCP_CONF"
|
||||
elif [ -e "$ntp_conf" ]; then
|
||||
remove_markers "$signature_base" "$signature_base_end" \
|
||||
"$ntp_conf" > "$cf"
|
||||
fi
|
||||
|
||||
if [ -n "$servers" ]; then
|
||||
echo "$signature_base${header:+ $from }$header" >> "$cf"
|
||||
printf "$search$servers" >> "$cf"
|
||||
echo "$signature_base_end${header:+ $from }$header" >> "$cf"
|
||||
else
|
||||
[ -e "$ntp_conf" ] || return
|
||||
fi
|
||||
|
||||
# If we changed anything, restart ntpd
|
||||
|
@ -86,7 +91,8 @@ remove_ntp_conf()
|
|||
build_ntp_conf
|
||||
}
|
||||
|
||||
case "$reason" in
|
||||
BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT|STATIC) add_ntp_conf add;;
|
||||
PREINIT|EXPIRE|FAIL|IPV4LL|NAK|NOCARRIER|RELEASE|STOP) remove_ntp_conf del;;
|
||||
esac
|
||||
if $if_up; then
|
||||
add_ntp_conf add
|
||||
elif $if_down; then
|
||||
remove_ntp_conf del
|
||||
fi
|
||||
|
|
|
@ -1,15 +1,8 @@
|
|||
# Sample dhcpcd hook for ypbind
|
||||
# This script is only suitable for the Linux version.
|
||||
|
||||
# Distributions may want to just have their command here instead of this
|
||||
if [ -x /etc/rc.d/ypbind ]; then
|
||||
ypbind_restart_cmd="/etc/rc.d/ypbind restart"
|
||||
ypbind_stop_cmd="/etc/rc.d/ypbind stop"
|
||||
elif [ -x /usr/local/etc/rc.d/ypbind ]; then
|
||||
ypbind_restart_cmd="/usr/local/etc/rc.d/ypbind restart"
|
||||
ypbind_stop_cmd="/usr/local/etc/rc.d/ypbind stop"
|
||||
fi
|
||||
|
||||
: ${ypbind_restart_cmd:="service_command ypbind restart"}
|
||||
: ${ypbind_stop_cmd:="service_condcommand ypbind stop"}
|
||||
ypbind_dir="$state_dir/ypbind"
|
||||
|
||||
best_domain()
|
||||
|
@ -70,17 +63,12 @@ restore_yp_binding()
|
|||
fi
|
||||
}
|
||||
|
||||
case "$reason" in
|
||||
PREINIT)
|
||||
if [ "$reason" = PREINIT ]; then
|
||||
rm -f "$ypbind_dir/$interface"
|
||||
;;
|
||||
TEST)
|
||||
;;
|
||||
*)
|
||||
else if $if_up || $if_down; then
|
||||
if [ -n "$new_nis_domain" ]; then
|
||||
make_yp_binding
|
||||
elif [ -n "$old_nis_domain" ]; then
|
||||
restore_yp_binding
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.\" Copyright (c) 2006-2009 Roy Marples
|
||||
.\" Copyright (c) 2006-2010 Roy Marples
|
||||
.\" All rights reserved
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
|
@ -22,7 +22,7 @@
|
|||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd March 23, 2009
|
||||
.Dd August 24, 2010
|
||||
.Dt DHCPCD-RUN-HOOKS 8 SMM
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -110,11 +110,14 @@ means it cannot work as a DHCP or ZeroConf client.
|
|||
Static configuration and DHCP INFORM is still allowed.
|
||||
.It Dv STOP
|
||||
dhcpcd stopped running on the interface.
|
||||
.iT Dv DUMP
|
||||
dhcpcd has been asked to dump the last lease for the interface.
|
||||
.It Dv TEST
|
||||
dhcpcd received an OFFER from a DHCP server but will not configure the
|
||||
interface.
|
||||
This is primarily used to test the variables are filled correctly for the
|
||||
script to process them.
|
||||
|
||||
.El
|
||||
.Sh FILES
|
||||
When
|
||||
|
|
|
@ -9,6 +9,13 @@ signature_base_end="# End of dhcpcd"
|
|||
signature_end="$signature_base_end $from $interface"
|
||||
state_dir=/var/run/dhcpcd
|
||||
|
||||
if_up=false
|
||||
if_down=false
|
||||
case "$reason" in
|
||||
BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT|STATIC) if_up=true;;
|
||||
PREINIT|EXPIRE|FAIL|IPV4LL|NAK|NOCARRIER|RELEASE|STOP) if_down=true;;
|
||||
esac
|
||||
|
||||
# Ensure that all arguments are unique
|
||||
uniqify()
|
||||
{
|
||||
|
@ -91,17 +98,19 @@ remove_markers()
|
|||
# If different, replace first with second otherwise remove second
|
||||
change_file()
|
||||
{
|
||||
if type cmp >/dev/null 2>&1; then
|
||||
cmp -s "$1" "$2"
|
||||
elif type diff >/dev/null 2>&1; then
|
||||
diff -q "$1" "$2" >/dev/null
|
||||
else
|
||||
# Hopefully we're only working on small text files ...
|
||||
[ "$(cat "$1")" = "$(cat "$2")" ]
|
||||
fi
|
||||
if [ $? -eq 0 ]; then
|
||||
rm -f "$2"
|
||||
return 1
|
||||
if [ -e "$1" ]; then
|
||||
if type cmp >/dev/null 2>&1; then
|
||||
cmp -s "$1" "$2"
|
||||
elif type diff >/dev/null 2>&1; then
|
||||
diff -q "$1" "$2" >/dev/null
|
||||
else
|
||||
# Hopefully we're only working on small text files ...
|
||||
[ "$(cat "$1")" = "$(cat "$2")" ]
|
||||
fi
|
||||
if [ $? -eq 0 ]; then
|
||||
rm -f "$2"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
cat "$2" > "$1"
|
||||
rm -f "$2"
|
||||
|
@ -131,13 +140,40 @@ syslog()
|
|||
local lvl="$1"
|
||||
|
||||
[ -n "$lvl" ] && shift
|
||||
if [ -n "$@" ]; then
|
||||
if [ -n "$*" ]; then
|
||||
if type logger >/dev/null 2>&1; then
|
||||
logger -t dhcpcd -p daemon."$lvl" -s "$@"
|
||||
logger -t dhcpcd -p daemon."$lvl" -s "$*"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Check a system service exists
|
||||
service_exists()
|
||||
{
|
||||
@SERVICEEXISTS@
|
||||
}
|
||||
|
||||
# Send a command to a system service
|
||||
service_cmd()
|
||||
{
|
||||
@SERVICECMD@
|
||||
}
|
||||
|
||||
# Send a command to a system service if it is running
|
||||
service_status()
|
||||
{
|
||||
@SERVICESTATUS@
|
||||
}
|
||||
|
||||
# Handy macros for our hooks
|
||||
service_command()
|
||||
{
|
||||
service_exists $1 && service_cmd $1 $2
|
||||
}
|
||||
service_condcommand()
|
||||
{
|
||||
service_exists $1 && service_status $1 && service_cmd $1 $2
|
||||
}
|
||||
|
||||
# We source each script into this one so that scripts run earlier can
|
||||
# remove variables from the environment so later scripts don't see them.
|
||||
|
|
|
@ -88,6 +88,7 @@ char **ifdv = NULL;
|
|||
|
||||
static char **margv;
|
||||
static int margc;
|
||||
static struct if_options *if_options;
|
||||
static char **ifv;
|
||||
static int ifc;
|
||||
static char *cffile;
|
||||
|
@ -161,6 +162,8 @@ cleanup(void)
|
|||
struct interface *iface;
|
||||
int i;
|
||||
|
||||
free_options(if_options);
|
||||
|
||||
while (ifaces) {
|
||||
iface = ifaces;
|
||||
ifaces = iface->next;
|
||||
|
@ -197,8 +200,13 @@ handle_exit_timeout(_unused void *arg)
|
|||
int timeout;
|
||||
|
||||
syslog(LOG_ERR, "timed out");
|
||||
if (!(options & DHCPCD_TIMEOUT_IPV4LL))
|
||||
exit(EXIT_FAILURE);
|
||||
if (!(options & DHCPCD_TIMEOUT_IPV4LL)) {
|
||||
if (options & DHCPCD_MASTER) {
|
||||
daemonise();
|
||||
return;
|
||||
} else
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
options &= ~DHCPCD_TIMEOUT_IPV4LL;
|
||||
timeout = (PROBE_NUM * PROBE_MAX) + PROBE_WAIT + 1;
|
||||
syslog(LOG_WARNING, "allowing %d seconds for IPv4LL timeout", timeout);
|
||||
|
@ -1083,6 +1091,7 @@ start_interface(void *arg)
|
|||
struct stat st;
|
||||
struct timeval now;
|
||||
uint32_t l;
|
||||
int nolease;
|
||||
|
||||
handle_carrier(iface->name);
|
||||
if (iface->carrier == LINK_DOWN) {
|
||||
|
@ -1090,6 +1099,9 @@ start_interface(void *arg)
|
|||
return;
|
||||
}
|
||||
|
||||
/* We don't want to read the old lease if we NAK an old test */
|
||||
nolease = iface->state->offer && options & DHCPCD_TEST;
|
||||
|
||||
iface->start_uptime = uptime();
|
||||
free(iface->state->offer);
|
||||
iface->state->offer = NULL;
|
||||
|
@ -1128,7 +1140,7 @@ start_interface(void *arg)
|
|||
start_inform(iface);
|
||||
return;
|
||||
}
|
||||
} else
|
||||
} else if (!nolease)
|
||||
iface->state->offer = read_lease(iface);
|
||||
if (iface->state->offer) {
|
||||
get_lease(&iface->state->lease, iface->state->offer);
|
||||
|
@ -1324,71 +1336,8 @@ handle_link(_unused void *arg)
|
|||
syslog(LOG_ERR, "manage_link: %m");
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
handle_signal(_unused void *arg)
|
||||
{
|
||||
struct interface *iface, *ifl;
|
||||
int sig = signal_read();
|
||||
int do_release = 0;
|
||||
|
||||
switch (sig) {
|
||||
case SIGINT:
|
||||
syslog(LOG_INFO, "received SIGINT, stopping");
|
||||
break;
|
||||
case SIGTERM:
|
||||
syslog(LOG_INFO, "received SIGTERM, stopping");
|
||||
break;
|
||||
case SIGALRM:
|
||||
syslog(LOG_INFO, "received SIGALRM, rebinding lease");
|
||||
for (iface = ifaces; iface; iface = iface->next)
|
||||
start_interface(iface);
|
||||
return;
|
||||
case SIGHUP:
|
||||
syslog(LOG_INFO, "received SIGHUP, releasing lease");
|
||||
do_release = 1;
|
||||
break;
|
||||
case SIGUSR1:
|
||||
syslog(LOG_INFO, "received SIGUSR, reconfiguring");
|
||||
for (iface = ifaces; iface; iface = iface->next)
|
||||
if (iface->state->new)
|
||||
configure(iface);
|
||||
return;
|
||||
case SIGPIPE:
|
||||
syslog(LOG_WARNING, "received SIGPIPE");
|
||||
return;
|
||||
default:
|
||||
syslog(LOG_ERR,
|
||||
"received signal %d, but don't know what to do with it",
|
||||
sig);
|
||||
return;
|
||||
}
|
||||
|
||||
if (options & DHCPCD_TEST)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
/* As drop_config could re-arrange the order, we do it like this. */
|
||||
for (;;) {
|
||||
/* Be sane and drop the last config first */
|
||||
ifl = NULL;
|
||||
for (iface = ifaces; iface; iface = iface->next) {
|
||||
if (iface->next == NULL)
|
||||
break;
|
||||
ifl = iface;
|
||||
}
|
||||
if (iface == NULL)
|
||||
break;
|
||||
if (iface->carrier != LINK_DOWN &&
|
||||
(do_release ||
|
||||
iface->state->options->options & DHCPCD_RELEASE))
|
||||
send_release(iface);
|
||||
stop_interface(iface);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void
|
||||
reconf_reboot(struct interface *iface, int argc, char **argv)
|
||||
if_reboot(struct interface *iface, int argc, char **argv)
|
||||
{
|
||||
const struct if_options *ifo;
|
||||
int opt;
|
||||
|
@ -1411,10 +1360,148 @@ reconf_reboot(struct interface *iface, int argc, char **argv)
|
|||
start_interface(iface);
|
||||
}
|
||||
|
||||
static void
|
||||
reconf_reboot(int action, int argc, char **argv, int oi)
|
||||
{
|
||||
struct interface *ifl, *ifn, *ifp, *ifs, *ift;
|
||||
|
||||
ifs = discover_interfaces(argc - oi, argv + oi);
|
||||
if (ifs == NULL)
|
||||
return;
|
||||
|
||||
/* Remove any old interfaces */
|
||||
if (ifaces) {
|
||||
for (ifl = NULL; ifl != ifaces;) {
|
||||
/* Work our way backwards */
|
||||
for (ifp = ifaces; ifp; ifp = ifp->next)
|
||||
if (ifp->next == ifl) {
|
||||
ifl = ifp;
|
||||
break;
|
||||
}
|
||||
for (ifn = ifs; ifn; ifn = ifn->next)
|
||||
if (strcmp(ifn->name, ifp->name) == 0)
|
||||
break;
|
||||
if (ifn == NULL) {
|
||||
ifl = ifp->next;
|
||||
stop_interface(ifp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ifp = ifs; ifp && (ift = ifp->next, 1); ifp = ift) {
|
||||
ifl = NULL;
|
||||
for (ifn = ifaces; ifn; ifn = ifn->next) {
|
||||
if (strcmp(ifn->name, ifp->name) == 0)
|
||||
break;
|
||||
ifl = ifn;
|
||||
}
|
||||
if (ifn) {
|
||||
if (action)
|
||||
if_reboot(ifn, argc, argv);
|
||||
else if (ifn->state->new)
|
||||
configure(ifn);
|
||||
free_interface(ifp);
|
||||
} else {
|
||||
ifp->next = NULL;
|
||||
init_state(ifp, argc, argv);
|
||||
start_interface(ifp);
|
||||
if (ifl)
|
||||
ifl->next = ifp;
|
||||
else
|
||||
ifaces = ifp;
|
||||
}
|
||||
}
|
||||
|
||||
sort_interfaces();
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
handle_signal(_unused void *arg)
|
||||
{
|
||||
struct interface *ifp, *ifl;
|
||||
struct if_options *ifo;
|
||||
int sig = signal_read();
|
||||
int do_release, do_rebind, i;
|
||||
|
||||
do_rebind = do_release = 0;
|
||||
switch (sig) {
|
||||
case SIGINT:
|
||||
syslog(LOG_INFO, "received SIGINT, stopping");
|
||||
break;
|
||||
case SIGTERM:
|
||||
syslog(LOG_INFO, "received SIGTERM, stopping");
|
||||
break;
|
||||
case SIGALRM:
|
||||
syslog(LOG_INFO, "received SIGALRM, rebinding");
|
||||
for (i = 0; i < ifac; i++)
|
||||
free(ifav[i]);
|
||||
free(ifav);
|
||||
ifav = NULL;
|
||||
ifac = 0;
|
||||
for (i = 0; i < ifdc; i++)
|
||||
free(ifdv[i]);
|
||||
free(ifdv);
|
||||
ifdc = 0;
|
||||
ifdv = NULL;
|
||||
ifo = read_config(cffile, NULL, NULL, NULL);
|
||||
add_options(ifo, margc, margv);
|
||||
/* We need to preserve these two options. */
|
||||
if (options & DHCPCD_MASTER)
|
||||
ifo->options |= DHCPCD_MASTER;
|
||||
if (options & DHCPCD_DAEMONISED)
|
||||
ifo->options |= DHCPCD_DAEMONISED;
|
||||
options = ifo->options;
|
||||
free_options(ifo);
|
||||
reconf_reboot(1, 0, NULL, 0);
|
||||
return;
|
||||
case SIGHUP:
|
||||
syslog(LOG_INFO, "received SIGHUP, releasing");
|
||||
do_release = 1;
|
||||
break;
|
||||
case SIGUSR1:
|
||||
syslog(LOG_INFO, "received SIGUSR, reconfiguring");
|
||||
for (ifp = ifaces; ifp; ifp = ifp->next)
|
||||
if (ifp->state->new)
|
||||
configure(ifp);
|
||||
return;
|
||||
case SIGPIPE:
|
||||
syslog(LOG_WARNING, "received SIGPIPE");
|
||||
return;
|
||||
default:
|
||||
syslog(LOG_ERR,
|
||||
"received signal %d, but don't know what to do with it",
|
||||
sig);
|
||||
return;
|
||||
}
|
||||
|
||||
if (options & DHCPCD_TEST)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
/* As drop_config could re-arrange the order, we do it like this. */
|
||||
for (;;) {
|
||||
/* Be sane and drop the last config first */
|
||||
ifl = NULL;
|
||||
for (ifp = ifaces; ifp; ifp = ifp->next) {
|
||||
if (ifp->next == NULL)
|
||||
break;
|
||||
ifl = ifp;
|
||||
}
|
||||
if (ifp == NULL)
|
||||
break;
|
||||
if (ifp->carrier != LINK_DOWN &&
|
||||
(do_release ||
|
||||
ifp->state->options->options & DHCPCD_RELEASE))
|
||||
send_release(ifp);
|
||||
stop_interface(ifp);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int
|
||||
handle_args(struct fd_list *fd, int argc, char **argv)
|
||||
{
|
||||
struct interface *ifs, *ifp, *ifl, *ifn, *ift;
|
||||
struct interface *ifp;
|
||||
int do_exit = 0, do_release = 0, do_reboot = 0, do_reconf = 0;
|
||||
int opt, oi = 0;
|
||||
ssize_t len;
|
||||
|
@ -1537,32 +1624,7 @@ handle_args(struct fd_list *fd, int argc, char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if ((ifs = discover_interfaces(argc - optind, argv + optind))) {
|
||||
for (ifp = ifs; ifp && (ift = ifp->next, 1); ifp = ift) {
|
||||
ifl = NULL;
|
||||
for (ifn = ifaces; ifn; ifn = ifn->next) {
|
||||
if (strcmp(ifn->name, ifp->name) == 0)
|
||||
break;
|
||||
ifl = ifn;
|
||||
}
|
||||
if (ifn) {
|
||||
if (do_reboot)
|
||||
reconf_reboot(ifn, argc, argv);
|
||||
else if (do_reconf && ifn->state->new)
|
||||
configure(ifn);
|
||||
free_interface(ifp);
|
||||
} else {
|
||||
ifp->next = NULL;
|
||||
init_state(ifp, argc, argv);
|
||||
start_interface(ifp);
|
||||
if (ifl)
|
||||
ifl->next = ifp;
|
||||
else
|
||||
ifaces = ifp;
|
||||
}
|
||||
}
|
||||
sort_interfaces();
|
||||
}
|
||||
reconf_reboot(do_reboot, argc, argv, optind);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1608,7 +1670,6 @@ close_sockets(struct interface *iface)
|
|||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct if_options *ifo;
|
||||
struct interface *iface;
|
||||
int opt, oi = 0, signal_fd, sig = 0, i, control_fd;
|
||||
size_t len;
|
||||
|
@ -1652,6 +1713,9 @@ main(int argc, char **argv)
|
|||
case 'T':
|
||||
i = 1;
|
||||
break;
|
||||
case 'U':
|
||||
i = 2;
|
||||
break;
|
||||
case 'V':
|
||||
print_options();
|
||||
exit(EXIT_SUCCESS);
|
||||
|
@ -1663,16 +1727,20 @@ main(int argc, char **argv)
|
|||
|
||||
margv = argv;
|
||||
margc = argc;
|
||||
ifo = read_config(cffile, NULL, NULL, NULL);
|
||||
opt = add_options(ifo, argc, argv);
|
||||
if_options = read_config(cffile, NULL, NULL, NULL);
|
||||
opt = add_options(if_options, argc, argv);
|
||||
if (opt != 1) {
|
||||
if (opt == 0)
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
options = ifo->options;
|
||||
options = if_options->options;
|
||||
if (i != 0) {
|
||||
options |= DHCPCD_TEST | DHCPCD_PERSISTENT;
|
||||
if (i == 1)
|
||||
options |= DHCPCD_TEST;
|
||||
else
|
||||
options |= DHCPCD_DUMPLEASE;
|
||||
options |= DHCPCD_PERSISTENT;
|
||||
options &= ~DHCPCD_DAEMONISE;
|
||||
}
|
||||
|
||||
|
@ -1685,7 +1753,7 @@ main(int argc, char **argv)
|
|||
if (options & DHCPCD_QUIET)
|
||||
close(STDERR_FILENO);
|
||||
|
||||
if (!(options & DHCPCD_TEST)) {
|
||||
if (!(options & (DHCPCD_TEST | DHCPCD_DUMPLEASE))) {
|
||||
/* If we have any other args, we should run as a single dhcpcd
|
||||
* instance for that interface. */
|
||||
len = strlen(PIDFILE) + IF_NAMESIZE + 2;
|
||||
|
@ -1702,6 +1770,36 @@ main(int argc, char **argv)
|
|||
syslog(LOG_ERR, "chdir `/': %m");
|
||||
atexit(cleanup);
|
||||
|
||||
if (options & DHCPCD_DUMPLEASE) {
|
||||
if (optind != argc - 1) {
|
||||
syslog(LOG_ERR, "dumplease requires an interface");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
ifaces = iface = xzalloc(sizeof(*iface));
|
||||
strlcpy(iface->name, argv[optind], sizeof(iface->name));
|
||||
snprintf(iface->leasefile, sizeof(iface->leasefile),
|
||||
LEASEFILE, iface->name);
|
||||
iface->state = xzalloc(sizeof(*iface->state));
|
||||
iface->state->options = xzalloc(sizeof(*iface->state->options));
|
||||
strlcpy(iface->state->options->script, if_options->script,
|
||||
sizeof(iface->state->options->script));
|
||||
iface->state->new = read_lease(iface);
|
||||
if (iface->state->new == NULL && errno == ENOENT) {
|
||||
strlcpy(iface->leasefile, argv[optind],
|
||||
sizeof(iface->leasefile));
|
||||
iface->state->new = read_lease(iface);
|
||||
}
|
||||
if (iface->state->new == NULL) {
|
||||
if (errno == ENOENT)
|
||||
syslog(LOG_ERR, "%s: no lease to dump",
|
||||
iface->name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
iface->state->reason = "DUMP";
|
||||
run_script(iface);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (!(options & (DHCPCD_MASTER | DHCPCD_TEST))) {
|
||||
control_fd = open_control();
|
||||
if (control_fd != -1) {
|
||||
|
@ -1812,7 +1910,7 @@ main(int argc, char **argv)
|
|||
syslog(LOG_ERR, "init_socket: %m");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (ifo->options & DHCPCD_LINK) {
|
||||
if (if_options->options & DHCPCD_LINK) {
|
||||
linkfd = open_link_socket();
|
||||
if (linkfd == -1)
|
||||
syslog(LOG_ERR, "open_link_socket: %m");
|
||||
|
@ -1884,14 +1982,15 @@ main(int argc, char **argv)
|
|||
{
|
||||
syslog(LOG_WARNING, "no interfaces have a carrier");
|
||||
daemonise();
|
||||
} else if (ifo->timeout > 0) {
|
||||
} else if (if_options->timeout > 0) {
|
||||
if (options & DHCPCD_IPV4LL)
|
||||
options |= DHCPCD_TIMEOUT_IPV4LL;
|
||||
add_timeout_sec(ifo->timeout, handle_exit_timeout,
|
||||
NULL);
|
||||
add_timeout_sec(if_options->timeout,
|
||||
handle_exit_timeout, NULL);
|
||||
}
|
||||
}
|
||||
free_options(ifo);
|
||||
free_options(if_options);
|
||||
if_options = NULL;
|
||||
|
||||
sort_interfaces();
|
||||
for (iface = ifaces; iface; iface = iface->next)
|
||||
|
|
|
@ -51,6 +51,7 @@ static struct timeout {
|
|||
struct timeval when;
|
||||
void (*callback)(void *);
|
||||
void *arg;
|
||||
int queue;
|
||||
struct timeout *next;
|
||||
} *timeouts;
|
||||
static struct timeout *free_timeouts;
|
||||
|
@ -109,7 +110,8 @@ delete_event(int fd)
|
|||
}
|
||||
|
||||
void
|
||||
add_timeout_tv(const struct timeval *when, void (*callback)(void *), void *arg)
|
||||
add_q_timeout_tv(int queue,
|
||||
const struct timeval *when, void (*callback)(void *), void *arg)
|
||||
{
|
||||
struct timeval w;
|
||||
struct timeout *t, *tt = NULL;
|
||||
|
@ -147,6 +149,7 @@ add_timeout_tv(const struct timeval *when, void (*callback)(void *), void *arg)
|
|||
t->when.tv_usec = w.tv_usec;
|
||||
t->callback = callback;
|
||||
t->arg = arg;
|
||||
t->queue = queue;
|
||||
|
||||
/* The timeout list should be in chronological order,
|
||||
* soonest first.
|
||||
|
@ -168,28 +171,30 @@ add_timeout_tv(const struct timeval *when, void (*callback)(void *), void *arg)
|
|||
}
|
||||
|
||||
void
|
||||
add_timeout_sec(time_t when, void (*callback)(void *), void *arg)
|
||||
add_q_timeout_sec(int queue, time_t when, void (*callback)(void *), void *arg)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = when;
|
||||
tv.tv_usec = 0;
|
||||
add_timeout_tv(&tv, callback, arg);
|
||||
add_q_timeout_tv(queue, &tv, callback, arg);
|
||||
}
|
||||
|
||||
/* This deletes all timeouts for the interface EXCEPT for ones with the
|
||||
* callbacks given. Handy for deleting everything apart from the expire
|
||||
* timeout. */
|
||||
void
|
||||
delete_timeouts(void *arg, void (*callback)(void *), ...)
|
||||
static void
|
||||
v_delete_q_timeouts(int queue, void *arg, void (*callback)(void *), va_list v)
|
||||
{
|
||||
struct timeout *t, *tt, *last = NULL;
|
||||
va_list va;
|
||||
void (*f)(void *);
|
||||
|
||||
for (t = timeouts; t && (tt = t->next, 1); t = tt) {
|
||||
if (t->arg == arg && t->callback != callback) {
|
||||
va_start(va, callback);
|
||||
if (t->queue == queue && t->arg == arg &&
|
||||
t->callback != callback)
|
||||
{
|
||||
va_copy(va, v);
|
||||
while ((f = va_arg(va, void (*)(void *))))
|
||||
if (f == t->callback)
|
||||
break;
|
||||
|
@ -209,12 +214,32 @@ delete_timeouts(void *arg, void (*callback)(void *), ...)
|
|||
}
|
||||
|
||||
void
|
||||
delete_timeout(void (*callback)(void *), void *arg)
|
||||
delete_q_timeouts(int queue, void *arg, void (*callback)(void *), ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, callback);
|
||||
v_delete_q_timeouts(queue, arg, callback, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void
|
||||
delete_timeouts( void *arg, void (*callback)(void *), ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, callback);
|
||||
v_delete_q_timeouts(0, arg, callback, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void
|
||||
delete_q_timeout(int queue, void (*callback)(void *), void *arg)
|
||||
{
|
||||
struct timeout *t, *tt, *last = NULL;
|
||||
|
||||
for (t = timeouts; t && (tt = t->next, 1); t = tt) {
|
||||
if (t->arg == arg &&
|
||||
if (t->queue == queue && t->arg == arg &&
|
||||
(!callback || t->callback == callback))
|
||||
{
|
||||
if (last)
|
||||
|
|
|
@ -30,11 +30,17 @@
|
|||
|
||||
#include <time.h>
|
||||
|
||||
#define add_timeout_tv(a, b, c) add_q_timeout_tv(0, a, b, c)
|
||||
#define add_timeout_sec(a, b, c) add_q_timeout_sec(0, a, b, c)
|
||||
#define delete_timeout(a, b) delete_q_timeout(0, a, b)
|
||||
|
||||
void add_event(int fd, void (*)(void *), void *);
|
||||
void delete_event(int fd);
|
||||
void add_timeout_sec(time_t, void (*)(void *), void *);
|
||||
void add_timeout_tv(const struct timeval *, void (*)(void *), void *);
|
||||
void delete_timeout(void (*)(void *), void *);
|
||||
void add_q_timeout_sec(int queue, time_t, void (*)(void *), void *);
|
||||
void add_q_timeout_tv(int queue, const struct timeval *, void (*)(void *),
|
||||
void *);
|
||||
void delete_q_timeout(int, void (*)(void *), void *);
|
||||
void delete_q_timeouts(int, void *, void (*)(void *), ...);
|
||||
void delete_timeouts(void *, void (*)(void *), ...);
|
||||
void start_eloop(void);
|
||||
|
||||
|
|
|
@ -71,6 +71,8 @@
|
|||
(((struct sockaddr_in *)(void *)sa)->sin_addr).s_addr : 0
|
||||
|
||||
static int r_fd = -1;
|
||||
static char *link_buf;
|
||||
static ssize_t link_buflen;
|
||||
|
||||
int
|
||||
if_init(_unused struct interface *iface)
|
||||
|
@ -302,11 +304,10 @@ get_addrs(int type, char *cp, struct sockaddr **sa)
|
|||
}
|
||||
}
|
||||
|
||||
#define BUFFER_LEN 2048
|
||||
int
|
||||
manage_link(int fd)
|
||||
{
|
||||
char buffer[2048], *p, *e, *cp;
|
||||
char *p, *e, *cp;
|
||||
char ifname[IF_NAMESIZE];
|
||||
ssize_t bytes;
|
||||
struct rt_msghdr *rtm;
|
||||
|
@ -315,9 +316,19 @@ manage_link(int fd)
|
|||
struct ifa_msghdr *ifam;
|
||||
struct rt rt;
|
||||
struct sockaddr *sa, *rti_info[RTAX_MAX];
|
||||
int len;
|
||||
|
||||
for (;;) {
|
||||
bytes = read(fd, buffer, BUFFER_LEN);
|
||||
if (ioctl(fd, FIONREAD, &len) == -1)
|
||||
return -1;
|
||||
if (link_buflen < len) {
|
||||
p = realloc(link_buf, len);
|
||||
if (p == NULL)
|
||||
return -1;
|
||||
link_buf = p;
|
||||
link_buflen = len;
|
||||
}
|
||||
bytes = read(fd, link_buf, link_buflen);
|
||||
if (bytes == -1) {
|
||||
if (errno == EAGAIN)
|
||||
return 0;
|
||||
|
@ -325,8 +336,8 @@ manage_link(int fd)
|
|||
continue;
|
||||
return -1;
|
||||
}
|
||||
e = buffer + bytes;
|
||||
for (p = buffer; p < e; p += rtm->rtm_msglen) {
|
||||
e = link_buf + bytes;
|
||||
for (p = link_buf; p < e; p += rtm->rtm_msglen) {
|
||||
rtm = (struct rt_msghdr *)(void *)p;
|
||||
switch(rtm->rtm_type) {
|
||||
case RTM_IFANNOUNCE:
|
||||
|
|
|
@ -95,6 +95,7 @@ const struct option cf_options[] = {
|
|||
{"require", required_argument, NULL, 'Q'},
|
||||
{"static", required_argument, NULL, 'S'},
|
||||
{"test", no_argument, NULL, 'T'},
|
||||
{"dumplease", no_argument, NULL, 'U'},
|
||||
{"variables", no_argument, NULL, 'V'},
|
||||
{"whitelist", required_argument, NULL, 'W'},
|
||||
{"blacklist", required_argument, NULL, 'X'},
|
||||
|
@ -336,7 +337,8 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
|
|||
case 'g': /* FALLTHROUGH */
|
||||
case 'n': /* FALLTHROUGH */
|
||||
case 'x': /* FALLTHROUGH */
|
||||
case 'T': /* We need to handle non interface options */
|
||||
case 'T': /* FALLTHROUGH */
|
||||
case 'U': /* We need to handle non interface options */
|
||||
break;
|
||||
case 'b':
|
||||
ifo->options |= DHCPCD_BACKGROUND;
|
||||
|
@ -524,9 +526,7 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
|
|||
}
|
||||
break;
|
||||
case 'z':
|
||||
/* We only set this if we haven't got any interfaces */
|
||||
if (!ifaces)
|
||||
ifav = splitv(&ifac, ifav, arg);
|
||||
ifav = splitv(&ifac, ifav, arg);
|
||||
break;
|
||||
case 'A':
|
||||
ifo->options &= ~DHCPCD_ARP;
|
||||
|
@ -712,9 +712,7 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
|
|||
ifo->blacklist[ifo->blacklist_len++] = addr2.s_addr;
|
||||
break;
|
||||
case 'Z':
|
||||
/* We only set this if we haven't got any interfaces */
|
||||
if (!ifaces)
|
||||
ifdv = splitv(&ifdc, ifdv, arg);
|
||||
ifdv = splitv(&ifdc, ifdv, arg);
|
||||
break;
|
||||
case O_ARPING:
|
||||
if (parse_addr(&addr, NULL, arg) != 0)
|
||||
|
@ -849,8 +847,7 @@ read_config(const char *file,
|
|||
}
|
||||
if (skip)
|
||||
continue;
|
||||
if (parse_config_line(ifo, option, line) != 1)
|
||||
break;
|
||||
parse_config_line(ifo, option, line);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
/* Don't set any optional arguments here so we retain POSIX
|
||||
* compatibility with getopt */
|
||||
#define IF_OPTS "bc:de:f:gh:i:kl:m:no:pqr:s:t:u:v:wxy:z:ABC:DEF:GHI:JKLO:Q:S:TVW:X:Z:"
|
||||
#define IF_OPTS "bc:de:f:gh:i:kl:m:no:pqr:s:t:u:v:wxy:z:ABC:DEF:GHI:JKLO:Q:S:TUVW:X:Z:"
|
||||
|
||||
#define DEFAULT_TIMEOUT 30
|
||||
#define DEFAULT_REBOOT 10
|
||||
|
@ -76,6 +76,7 @@
|
|||
#define DHCPCD_CSR_WARNED (1 << 27)
|
||||
#define DHCPCD_XID_HWADDR (1 << 28)
|
||||
#define DHCPCD_BROADCAST (1 << 29)
|
||||
#define DHCPCD_DUMPLEASE (1 << 30)
|
||||
|
||||
extern const struct option cf_options[];
|
||||
|
||||
|
|
|
@ -322,6 +322,15 @@ discover_interfaces(int argc, char * const *argv)
|
|||
#endif
|
||||
#ifdef AF_LINK
|
||||
const struct sockaddr_dl *sdl;
|
||||
#ifdef IFLR_ACTIVE
|
||||
struct if_laddrreq iflr;
|
||||
int socket_aflink;
|
||||
|
||||
socket_aflink = socket(AF_LINK, SOCK_DGRAM, 0);
|
||||
if (socket_aflink == -1)
|
||||
return NULL;
|
||||
memset(&iflr, 0, sizeof(iflr));
|
||||
#endif
|
||||
#elif AF_PACKET
|
||||
const struct sockaddr_ll *sll;
|
||||
#endif
|
||||
|
@ -409,6 +418,23 @@ discover_interfaces(int argc, char * const *argv)
|
|||
} else if (ifa->ifa_addr != NULL) {
|
||||
#ifdef AF_LINK
|
||||
sdl = (const struct sockaddr_dl *)(void *)ifa->ifa_addr;
|
||||
|
||||
#ifdef IFLR_ACTIVE
|
||||
/* We need to check for active address */
|
||||
strlcpy(iflr.iflr_name, ifp->name,
|
||||
sizeof(iflr.iflr_name));
|
||||
memcpy(&iflr.addr, ifa->ifa_addr,
|
||||
MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr)));
|
||||
iflr.flags = IFLR_PREFIX;
|
||||
iflr.prefixlen = sdl->sdl_alen * NBBY;
|
||||
if (ioctl(socket_aflink, SIOCGLIFADDR, &iflr) == -1 ||
|
||||
!(iflr.flags & IFLR_ACTIVE))
|
||||
{
|
||||
free_interface(ifp);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch(sdl->sdl_type) {
|
||||
case IFT_ETHER:
|
||||
ifp->family = ARPHRD_ETHER;
|
||||
|
@ -464,6 +490,11 @@ discover_interfaces(int argc, char * const *argv)
|
|||
ifl = ifp;
|
||||
}
|
||||
freeifaddrs(ifaddrs);
|
||||
|
||||
#ifdef IFLR_ACTIVE
|
||||
close(socket_aflink);
|
||||
#endif
|
||||
|
||||
return ifs;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue