hooks/10-wpa_supplicant | 9 ++++++ hooks/15-timezone | 3 +- hooks/20-resolv.conf | 16 +++++++---- hooks/29-lookup-hostname | 3 +- hooks/30-hostname.in | 15 ++++++++-- hooks/50-ntp.conf | 60 +++++++++++++++++++++------------------- hooks/50-yp.conf | 5 ++-- hooks/50-ypbind.in | 11 +++++--- hooks/dhcpcd-run-hooks.in | 32 ++++++++++++++-------- src/dhcpcd.conf | 29 +++++++++++++++++--- src/if-linux.c | 70 +++++++++++++++++++++++++++++++++++++++++++---- src/privsep-linux.c | 6 ++++ 12 files changed, 194 insertions(+), 65 deletions(-) diff --git a/hooks/10-wpa_supplicant b/hooks/10-wpa_supplicant index 04acce0..c8353c4 100644 --- a/hooks/10-wpa_supplicant +++ b/hooks/10-wpa_supplicant @@ -7,6 +7,7 @@ if [ -z "$wpa_supplicant_conf" ]; then for x in \ + /etc/net/ifaces/"$interface"/wpa_supplicant.conf \ /etc/wpa_supplicant/wpa_supplicant-"$interface".conf \ /etc/wpa_supplicant/wpa_supplicant.conf \ /etc/wpa_supplicant-"$interface".conf \ @@ -22,6 +23,8 @@ fi wpa_supplicant_ctrldir() { + local dir + dir=$(key_get_value "[[:space:]]*ctrl_interface=" \ "$wpa_supplicant_conf") dir=$(trim "$dir") @@ -37,6 +40,8 @@ wpa_supplicant_ctrldir() wpa_supplicant_start() { + local dir err errn + # If the carrier is up, don't bother checking anything [ "$ifcarrier" = "up" ] && return 0 @@ -70,6 +75,8 @@ wpa_supplicant_start() wpa_supplicant_reconfigure() { + local dir err errn + dir=$(wpa_supplicant_ctrldir) [ -z "$dir" ] && return 1 if ! wpa_cli -p "$dir" -i "$interface" status >/dev/null 2>&1; then @@ -88,6 +95,8 @@ wpa_supplicant_reconfigure() wpa_supplicant_stop() { + local dir err errn + dir=$(wpa_supplicant_ctrldir) [ -z "$dir" ] && return 1 wpa_cli -p "$dir" -i "$interface" status >/dev/null 2>&1 || return 0 diff --git a/hooks/15-timezone b/hooks/15-timezone index 3d51732..504fef5 100644 --- a/hooks/15-timezone +++ b/hooks/15-timezone @@ -4,9 +4,10 @@ set_zoneinfo() { + local zoneinfo_dir= zone_file= + [ -z "$new_tzdb_timezone" ] && return 0 - zoneinfo_dir= for d in \ /usr/share/zoneinfo \ /usr/lib/zoneinfo \ diff --git a/hooks/20-resolv.conf b/hooks/20-resolv.conf index 73d3338..783e62a 100644 --- a/hooks/20-resolv.conf +++ b/hooks/20-resolv.conf @@ -7,13 +7,16 @@ # or dnsmasq. This is important as the libc resolver isn't that powerful. resolv_conf_dir="$state_dir/resolv.conf" +uchrooted=/sbin/update_chrooted + NL=" " : ${resolvconf:=resolvconf} build_resolv_conf() { - cf="$state_dir/resolv.conf.$ifname" + local cf="$state_dir/resolv.conf.$ifname" + local interfaces= header= domain= search= srvs= servers= x= # Build a list of interfaces interfaces=$(list_interfaces "$resolv_conf_dir") @@ -67,13 +70,13 @@ build_resolv_conf() chmod 644 /etc/resolv.conf fi rm -f "$cf" + [ ! -x "$uchrooted" ] || "$uchrooted" conf } # Extract any ND DNS options from the RA # Obey the lifetimes eval_nd_dns() { - eval rdnsstime=\$nd${i}_rdnss${j}_lifetime [ -z "$rdnsstime" ] && return 1 ltime=$(($rdnsstime - $offset)) @@ -96,8 +99,8 @@ eval_nd_dns() add_resolv_conf() { - conf="$signature$NL" - warn=true + local x= conf="$signature$NL" warn=true + local i j ltime= rdnss= dnssl= new_rdnss= new_dnssl= # Loop to extract the ND DNS options using our indexed shell values i=1 @@ -165,7 +168,10 @@ add_resolv_conf() conf="${conf}nameserver $x$NL" done if type "$resolvconf" >/dev/null 2>&1; then - [ -n "$ifmetric" ] && export IF_METRIC="$ifmetric" + # Don't use metric for resolvconf: + # at the time metric is not used in all cases + # of network interfaces configuration. +# [ -n "$ifmetric" ] && export IF_METRIC="$ifmetric" printf %s "$conf" | "$resolvconf" -a "$ifname" return $? fi diff --git a/hooks/29-lookup-hostname b/hooks/29-lookup-hostname index 811c7a9..129dc0d 100644 --- a/hooks/29-lookup-hostname +++ b/hooks/29-lookup-hostname @@ -3,11 +3,12 @@ lookup_hostname() { [ -z "$new_ip_address" ] && return 1 + local h= # Silly ISC programs love to send error text to stdout if type dig >/dev/null 2>&1; then h=$(dig +short -x $new_ip_address) if [ $? = 0 ]; then - echo "$h" | sed 's/\.$//' + echo "${h%.}" return 0 fi elif type host >/dev/null 2>&1; then diff --git a/hooks/30-hostname.in b/hooks/30-hostname.in index abeb369..b6c388e 100644 --- a/hooks/30-hostname.in +++ b/hooks/30-hostname.in @@ -22,6 +22,8 @@ # Some systems don't have hostname(1) _hostname() { + local name= + if [ -z "${1+x}" ]; then if [ -r /proc/sys/kernel/hostname ]; then read name /dev/null 2>&1; then - [ -e /var/lib/ntp ] || mkdir /var/lib/ntp - : ${ntp_service:=ntp} - : ${NTP_DHCP_CONF:=/var/lib/ntp/ntp.conf.dhcp} +if [ -n "$NTP_CONF" ]; then + ntp_restart_cmd="/sbin/service $ntp_service condrestart" fi -: ${ntp_restart_cmd:=service_condcommand $ntp_service restart} - -ntp_conf=${NTP_CONF} NL=" " build_ntp_conf() { - cf="$state_dir/ntp.conf.$ifname" + local ntp_conf="$1" + local server_keyword=${2:-server} + local cf="$state_dir/ntp.conf.$ifname" + local interfaces= header= srvs= servers= x= + + [ -n "$ntp_conf" -a -w "$ntp_conf" ] || return 0 # Build a list of interfaces interfaces=$(list_interfaces "$ntp_conf_dir") - header= - servers= if [ -n "$interfaces" ]; then # Build the header for x in ${interfaces}; do @@ -75,7 +79,7 @@ build_ntp_conf() key_get_value "server " $interfaces) if [ -n "$srvs" ]; then for x in $(uniqify $srvs); do - servers="${servers}server $x$NL" + servers="${servers}${server_keyword} $x$NL" done fi fi @@ -108,7 +112,7 @@ build_ntp_conf() add_ntp_conf() { - cf="$ntp_conf_dir/$ifname" + local cf="$ntp_conf_dir/$ifname" x= [ -e "$cf" ] && rm "$cf" [ -d "$ntp_conf_dir" ] || mkdir -p "$ntp_conf_dir" @@ -117,7 +121,7 @@ add_ntp_conf() echo "server $x" >> "$cf" done fi - build_ntp_conf + build_ntp_conf "$NTP_CONF" $ntp_conf_server_word } remove_ntp_conf() @@ -125,7 +129,7 @@ remove_ntp_conf() if [ -e "$ntp_conf_dir/$ifname" ]; then rm "$ntp_conf_dir/$ifname" fi - build_ntp_conf + build_ntp_conf "$NTP_CONF" $ntp_conf_server_word } # For ease of use, map DHCP6 names onto our DHCP4 names diff --git a/hooks/50-yp.conf b/hooks/50-yp.conf index c5cdad9..07858b5 100644 --- a/hooks/50-yp.conf +++ b/hooks/50-yp.conf @@ -9,10 +9,9 @@ ypbind_pid() make_yp_conf() { [ -z "${new_nis_domain}${new_nis_servers}" ] && return 0 - cf=/etc/yp.conf."$ifname" + local cf=/etc/yp.conf."$ifname" prefix= x= pid= rm -f "$cf" echo "$signature" > "$cf" - prefix= if [ -n "$new_nis_domain" ]; then if ! valid_domainname "$new_nis_domain"; then syslog err "Invalid NIS domain name: $new_nis_domain" @@ -44,7 +43,7 @@ restore_yp_conf() { [ -n "$old_nis_domain" ] && domainname "" restore_conf /etc/yp.conf || return 0 - pid="$(ypbind_pid)" + local pid="$(ypbind_pid)" if [ -n "$pid" ]; then kill -HUP "$pid" fi diff --git a/hooks/50-ypbind.in b/hooks/50-ypbind.in index 09a12b9..9812142 100644 --- a/hooks/50-ypbind.in +++ b/hooks/50-ypbind.in @@ -10,6 +10,8 @@ ypbind_dir="$state_dir/ypbind" best_domain() { + local i= + for i in "$ypbind_dir/$interface_order".*; do if [ -f "$i" ]; then cat "$i" @@ -27,9 +29,9 @@ make_yp_binding() if [ -z "$ypdomain_dir" ]; then false else - cf="$ypdomain_dir/$new_nis_domain$ypdomain_suffix" + local cf="$ypdomain_dir/$new_nis_domain$ypdomain_suffix" if [ -n "$new_nis_servers" ]; then - ncf="$cf.$ifname" + local ncf="$cf.$ifname" x= rm -f "$ncf" for x in $new_nis_servers; do echo "$x" >>"$ncf" @@ -40,7 +42,7 @@ make_yp_binding() fi fi - nd="$(best_domain)" + local nd="$(best_domain)" if [ $? = 0 ] && [ "$nd" != "$(domainname)" ]; then domainname "$nd" if [ -n "$ypbind_restart_cmd" ]; then @@ -51,8 +53,9 @@ make_yp_binding() restore_yp_binding() { + rm -f "$ypbind_dir/$ifname" - nd="$(best_domain)" + local nd="$(best_domain)" # We need to stop ypbind if there is no best domain # otherwise it will just stall as we cannot set domainname # to blank :/ diff --git a/hooks/dhcpcd-run-hooks.in b/hooks/dhcpcd-run-hooks.in index a237f6a..46c72ae 100644 --- a/hooks/dhcpcd-run-hooks.in +++ b/hooks/dhcpcd-run-hooks.in @@ -10,6 +10,7 @@ signature_base_end="# End of dhcpcd" signature_end="$signature_base_end $from $ifname" state_dir=@RUNDIR@/hook-state _detected_init=false +logger_util=logger : ${if_up:=false} : ${if_down:=false} @@ -18,7 +19,7 @@ _detected_init=false # Ensure that all arguments are unique uniqify() { - result= + local result= i= for i do case " $result " in *" $i "*);; @@ -34,7 +35,7 @@ uniqify() # Otherwise we just use what we have. list_interfaces() { - ifaces= + local i= x= ifaces= for i in $interface_order; do for x in "$1"/$i.*; do [ -f "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}" @@ -49,7 +50,8 @@ list_interfaces() # Trim function trim() { - var="$*" + local var="$*" + var=${var#"${var%%[![:space:]]*}"} var=${var%"${var##*[![:space:]]}"} if [ -z "$var" ]; then @@ -64,9 +66,9 @@ trim() # but sed may not always be available at the time. key_get_value() { - key="$1" - shift + local key="$1" value= x= line= + shift if type sed >/dev/null 2>&1; then sed -n "s/^$key//p" $@ else @@ -84,9 +86,7 @@ key_get_value() # but sed may not always be available at the time. remove_markers() { - m1="$1" - m2="$2" - in_marker=0 + local m1="$1" m2="$2" x= line= in_marker=0 shift; shift if type sed >/dev/null 2>&1; then @@ -167,7 +167,7 @@ restore_conf() # Write a syslog entry syslog() { - lvl="$1" + local lvl="$1" if [ "$lvl" = debug ]; then ${syslog_debug} || return 0 @@ -186,7 +186,8 @@ syslog() # Check for a valid name as per RFC952 and RFC1123 section 2.1 valid_domainname() { - name="$1" + local name="$1" label + [ -z "$name" ] || [ ${#name} -gt 255 ] && return 1 while [ -n "$name" ]; do @@ -204,6 +205,8 @@ valid_domainname() valid_domainname_list() { + local name + for name do valid_domainname "$name" || return $? done @@ -229,7 +232,7 @@ detect_init() # Detect the running init system. # As systemd and OpenRC can be installed on top of legacy init # systems we try to detect them first. - status="@STATUSARG@" + local status="@STATUSARG@" : ${status:=status} if [ -x /bin/systemctl ] && [ -S /run/systemd/private ]; then _service_exists="/bin/systemctl --quiet is-enabled \$1.service" @@ -338,6 +341,9 @@ for hook in \ @HOOKDIR@/* \ @SYSCONFDIR@/dhcpcd.exit-hook do + # Don't run *.rpm* and *~ scripts. + [ "${hook%.rpm*}" = "$hook" -a "${hook%\~}" = "$hook" ] || continue + for skip in $skip_hooks; do case "$hook" in */*~) continue 2;; @@ -348,5 +354,9 @@ do done if [ -f "$hook" ]; then . "$hook" + exit_status="$?" + if [ "$exit_status" -ne 0 ] && type $logger_util >/dev/null 2>&1; then + $logger_util -p daemon.err "dhcpcd-run-hooks($reason): ${hook##*/} returned non-zero exit status $exit_status" + fi fi done diff --git a/src/dhcpcd.conf b/src/dhcpcd.conf index 916e82d..4c5d710 100644 --- a/src/dhcpcd.conf +++ b/src/dhcpcd.conf @@ -7,16 +7,19 @@ # Inform the DHCP server of our hostname for DDNS. #hostname -# Use the hardware address of the interface for the Client ID. +# To share the DHCP lease across OSX and Windows a ClientID is needed. +# Enabling this may get a different lease than the kernel DHCP client. +# Some upstream DHCP servers may also require a ClientID, such as FRITZ!Box. +# Use the hardware address of the interface for the Client ID (default). #clientid # or # Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as per RFC4361. # Some non-RFC compliant DHCP servers do not reply with this set. # In this case, comment out duid and enable clientid above. -duid +#duid # Persist interface configuration when dhcpcd exits. -persistent +#persistent # vendorclassid is set to blank to avoid sending the default of # dhcpcd-::: @@ -32,7 +35,7 @@ option interface_mtu option host_name # Most distributions have NTP support. -#option ntp_servers +option ntp_servers # Rapid commit support. # Safe to enable by default because it requires the equivalent option set @@ -46,3 +49,21 @@ require dhcp_server_identifier #slaac hwaddr # OR generate Stable Private IPv6 Addresses based from the DUID slaac private + +# A hook script is provided to lookup the hostname if not set by the DHCP +# server, but it should not be run by default. +nohook lookup-hostname + +# Don't attempt to obtain an IPv4LL address if we failed to get one via DHCP. +noipv4ll + +# Don't send any ARP requests. +noarp + +# Don't attmept to configure an IPv6 address. +noipv6 + +# Force the sending of the short hostname. +# So DDNS will always work, even if the hostname domain is different +# from the DHCP servers. +hostname_short diff --git a/src/if-linux.c b/src/if-linux.c index eaa5a4d..e2fd6a6 100644 --- a/src/if-linux.c +++ b/src/if-linux.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -515,6 +516,61 @@ if_carrier(struct interface *ifp, __unused const void *ifadata) return ifp->flags & IFF_RUNNING ? LINK_UP : LINK_DOWN; } +#if defined(IFA_F_NOPREFIXROUTE) || defined(IFA_F_MANAGETEMPADDR) +/* + * This function from glibc_preinstall originally. + * Permission to use under 2-clause BSD license is granted by ldv@. + */ +static int +parse_release(const char *p) +{ + unsigned int i, osversion = 0; + + for (i = 0; i < 3 && *p; i++, ++p) + { + unsigned int d = 0; + const char *p0 = p; + + for (;*p >= '0' && *p <= '9'; ++p) + d = d * 10 + (*p - '0'); + + if ((d == 0 && p == p0) || d >= 255 || (i < 2 && *p && *p != '.')) { + osversion = 0; + break; + } + osversion |= d << (16 - 8 * i); + + if (!*p) + break; + } + return osversion; +} + +static bool +can_ifa_flags(void) +{ + static int can = -1; + struct utsname name; + + if (can >= 0) + return can > 0; + + can = 0; + + if (uname(&name) < 0) { + logwarn("Can't get kernel version, netlink's IFA_FLAGS are disabled"); + return false; + } + + if (parse_release(name.release) < parse_release("3.14.0")) + logdebugx("This kernel is too old, netlink's IFA_FLAGS are disabled"); + else + can = 1; + + return can > 0; +} +#endif /*IFA_F_NOPREFIXROUTE || IFA_F_MANAGETEMPADDR */ + int if_getnetlink(struct dhcpcd_ctx *ctx, struct iovec *iov, int fd, int flags, int (*cb)(struct dhcpcd_ctx *, void *, struct nlmsghdr *), void *cbarg) @@ -1855,7 +1911,7 @@ if_address(unsigned char cmd, const struct ipv4_addr *ia) if (cmd == RTM_NEWADDR) { #ifdef IFA_F_NOPREFIXROUTE - if (nlm.ifa.ifa_prefixlen < 32) + if (nlm.ifa.ifa_prefixlen < 32 && can_ifa_flags()) flags |= IFA_F_NOPREFIXROUTE; add_attr_32(&nlm.hdr, sizeof(nlm), IFA_FLAGS, flags); #endif @@ -1921,17 +1977,19 @@ if_address6(unsigned char cmd, const struct ipv6_addr *ia) if (ia->flags & IPV6_AF_TEMPORARY) { /* Currently the kernel filters out these flags */ #ifdef IFA_F_NOPREFIXROUTE - flags |= IFA_F_TEMPORARY; -#else - nlm.ifa.ifa_flags |= IFA_F_TEMPORARY; + if (can_ifa_flags()) + flags |= IFA_F_TEMPORARY; + else #endif + nlm.ifa.ifa_flags |= IFA_F_TEMPORARY; } #elif IFA_F_MANAGETEMPADDR - if (ia->flags & IPV6_AF_AUTOCONF && IA6_CANAUTOCONF(ia)) + if (ia->flags & IPV6_AF_AUTOCONF && IA6_CANAUTOCONF(ia) && + can_ifa_flags()) flags |= IFA_F_MANAGETEMPADDR; #endif #ifdef IFA_F_NOPREFIXROUTE - if (!IN6_IS_ADDR_LINKLOCAL(&ia->addr)) + if (!IN6_IS_ADDR_LINKLOCAL(&ia->addr) && can_ifa_flags()) flags |= IFA_F_NOPREFIXROUTE; #endif #if defined(IFA_F_MANAGETEMPADDR) || defined(IFA_F_NOPREFIXROUTE) diff --git a/src/privsep-linux.c b/src/privsep-linux.c index e588ecd..fb63010 100644 --- a/src/privsep-linux.c +++ b/src/privsep-linux.c @@ -29,6 +29,10 @@ #include #include #include +/* For TCGETS on powerpc */ +#if defined(__powerpc64__) || defined(__powerpc__) +#include +#endif #include #include @@ -199,6 +203,8 @@ ps_root_sendnetlink(struct dhcpcd_ctx *ctx, int protocol, struct msghdr *msg) # else # define AUDIT_ARCH_SPARC # endif +#elif defined(__e2k__) +# define SECCOMP_AUDIT_ARCH AUDIT_ARCH_E2K #else # error "Platform does not support seccomp filter yet" #endif