Index: etc/defaults/rc.conf =================================================================== --- etc/defaults/rc.conf +++ etc/defaults/rc.conf @@ -113,6 +113,9 @@ #background_dhclient_fxp0="YES" # Start dhcp client on fxp0 in the background. synchronous_dhclient="NO" # Start dhclient directly on configured # interfaces during startup. +#dhclient6_program="/sbin/dhclient" # Path to DHCPv6 client program. +dhclient6_flags="" # Extra flags to pass to DHCPv6 client. +background_dhclient6="NO" # Start DHCPv6 client in the background. defaultroute_delay="30" # Time to wait for a default route on a DHCP interface. defaultroute_carrier_delay="5" # Time to wait for carrier while waiting for a default route. netif_enable="YES" # Set to YES to initialize network interfaces Index: etc/network.subr =================================================================== --- etc/network.subr +++ etc/network.subr @@ -234,6 +234,16 @@ _cfg=0 fi + if dhcp6if $1; then + if [ $_cfg -ne 0 ] ; then + ${IFCONFIG_CMD} $1 up + fi + if syncdhcp6if $1; then + /etc/rc.d/dhclient6 start $1 + fi + _cfg=0 + fi + return $_cfg } @@ -259,6 +269,11 @@ _cfg=0 fi + if dhcp6if $1; then + /etc/rc.d/dhclient6 stop $1 + _cfg=0 + fi + if ifexists $1; then ${IFCONFIG_CMD} $1 down _cfg=0 @@ -325,9 +340,12 @@ for _arg in $_tmpargs; do case $_arg:$_vnet in [Dd][Hh][Cc][Pp]:0) ;; + [Dd][Hh][Cc][Pp]6:0) ;; [Nn][Oo][Aa][Uu][Tt][Oo]:0) ;; [Nn][Oo][Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]:0) ;; + [Nn][Oo][Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]6:0) ;; [Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]:0) ;; + [Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]6:0) ;; [Ww][Pp][Aa]:0) ;; [Hh][Oo][Ss][Tt][Aa][Pp]:0) ;; vnet:0) _vnet=1 ;; @@ -396,6 +414,43 @@ return 1 } +# dhcp6if if +# Returns 0 if the interface is a DHCP6 interface and 1 otherwise. +dhcp6if() +{ + local _tmpargs _arg + _tmpargs=`_ifconfig_getargs $1 ipv6` + + case $1 in + lo[0-9]*|\ + stf[0-9]*|\ + faith[0-9]*|\ + lp[0-9]*|\ + sl[0-9]*) + return 1 + ;; + esac + if noafif $1; then + return 1 + fi + + for _arg in $_tmpargs; do + case $_arg in + [Dd][Hh][Cc][Pp]6) + return 0 + ;; + [Nn][Oo][Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]6) + return 0 + ;; + [Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]6) + return 0 + ;; + esac + done + + return 1 +} + # syncdhcpif # Returns 0 if the interface should be configured synchronously and # 1 otherwise. @@ -422,6 +477,32 @@ checkyesno synchronous_dhclient } +# syncdhcp6if +# Returns 0 if the interface should be configured synchronously and +# 1 otherwise. +syncdhcp6if() +{ + local _tmpargs _arg + _tmpargs=`_ifconfig_getargs $1 ipv6` + + if noafif $1; then + return 1 + fi + + for _arg in $_tmpargs; do + case $_arg in + [Nn][Oo][Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]6) + return 1 + ;; + [Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]6) + return 0 + ;; + esac + done + + checkyesno synchronous_dhclient6 +} + # wpaif if # Returns 0 if the interface is a WPA interface and 1 otherwise. wpaif() @@ -1620,8 +1701,9 @@ # List all network interfaces. The type of interface returned # can be controlled by the type argument. The type # argument can be any of the following: -# nodhcp - all interfaces, excluding DHCP configured interfaces +# nodhcp - all interfaces, excluding DHCP/DHCP6 configured interfaces # dhcp - list only DHCP configured interfaces +# dhcp6 - list only DHCP6 configured interfaces # noautoconf - all interfaces, excluding IPv6 Stateless # Address Autoconf configured interfaces # autoconf - list only IPv6 Stateless Address Autoconf @@ -1687,7 +1769,9 @@ nodhcp) for _if in ${_tmplist} ; do if ! dhcpif $_if && \ - [ -n "`_ifconfig_getargs $_if`" ]; then + ! dhcp6if $_if && \ + ( [ -n "`_ifconfig_getargs $_if`" ] || \ + [ -n "`_ifconfig_getargs $_if ipv6`" ] ); then _list="${_list# } ${_if}" fi done @@ -1699,6 +1783,13 @@ fi done ;; + dhcp6) + for _if in ${_tmplist} ; do + if dhcp6if $_if; then + _list="${_list# } ${_if}" + fi + done + ;; noautoconf) for _if in ${_tmplist} ; do if ! ipv6_autoconfif $_if && \ Index: etc/rc.d/dhclient6 =================================================================== --- /dev/null +++ etc/rc.d/dhclient6 @@ -0,0 +1,75 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# PROVIDE: dhclient6 +# KEYWORD: nojail nostart + +. /etc/rc.subr +. /etc/network.subr + +ifn="$2" + +name="dhclient6" +rcvar= +# ISC dhcp-client from ports (the only dhcp-client tested with this script so +# far) doesn't use a per-interface pidfile. +#pidfile="/var/run/${name}.${ifn}.pid" +pidfile="/var/run/${name}.pid" +start_precmd="dhclient6_prestart" +stop_precmd="dhclient6_pre_check" + +# rc_force check can only be done at the run_rc_command +# time, so we're testing it in the pre* hooks. +dhclient6_pre_check() +{ + if [ -z "${rc_force}" ] && ! dhcp6if $ifn; then + local msg + msg="'$ifn' is not a DHCP6-enabled interface" + if [ -z "${rc_quiet}" ]; then + echo "$msg" + else + debug "$msg" + fi + exit 1 + fi +} + +dhclient6_prestart() +{ + dhclient6_pre_check + + # Interface-specific flags (see rc.subr for $flags setting) + specific=$(get_if_var $ifn dhclient6_flags_IF) + if [ -z "$flags" -a -n "$specific" ]; then + rc_flags=$specific + fi + + background_dhclient6=$(get_if_var $ifn background_dhclient6_IF $background_dhclient6) + if checkyesno background_dhclient6; then + rc_flags="${rc_flags} -b" + fi + + rc_flags="${rc_flags} ${ifn}" + + # Wait for DAD to complete on the link local address. If DAD isn't + # complete, then dhclient won't be able to bind and will exit. + while ifconfig ${ifn} | grep "inet6.*%${ifn}" | grep -q tentative + do + sleep 1 + done + +} + +load_rc_config $name +load_rc_config network + +if [ -z $ifn ] ; then + # only complain if a command was specified but no interface + if [ -n "$1" ] ; then + err 1 "$0: no interface specified" + fi +fi + +run_rc_command "$1" Index: sbin/dhclient/dhclient-script =================================================================== --- sbin/dhclient/dhclient-script +++ sbin/dhclient/dhclient-script @@ -22,6 +22,7 @@ ARP=/usr/sbin/arp HOSTNAME=/bin/hostname IFCONFIG='/sbin/ifconfig -n' +RESOLVCONF='/sbin/resolvconf' LOCALHOST=127.0.0.1 @@ -35,6 +36,19 @@ # Helper functions that implement common actions. # +resolvconf_enabled() { + case "$resolvconf_enable" in + # "no", "false", "off", or "0" + [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) + return 1 + ;; + + *) + return 0 + ;; + esac +} + check_hostname() { current_hostname=`$HOSTNAME` if [ -z "$current_hostname" ]; then @@ -57,6 +71,10 @@ eval "$IFCONFIG $interface inet -alias $old_ip_address $medium" } +delete_old_address6() { + eval "$IFCONFIG $interface inet6 ${old_ip6_address}/${old_ip6_prefixlen} -alias" +} + add_new_address() { eval "$IFCONFIG $interface \ inet $new_ip_address \ @@ -70,6 +88,18 @@ $LOGGER "New Routers ($interface): $new_routers" } +add_new_address6() { + if [ -z ${new_ip6_address} ] || [ -z ${new_ip6_prefixlen} ] ; then + exit_with_hooks 2; + fi + eval "$IFCONFIG $interface \ + inet6 ${new_ip6_address}/${new_ip6_prefixlen} alias \ + $medium" + + $LOGGER "New IP Address ($interface): ${new_ip6_address}/${new_ip6_prefixlen}" + #$LOGGER "New Routers ($interface): $new_routers" +} + delete_old_alias() { if [ -n "$alias_ip_address" ]; then $IFCONFIG $interface inet -alias $alias_ip_address > /dev/null 2>&1 @@ -198,7 +228,7 @@ # thus broke the script. This code creates the resolv.conf if either # are provided. - local tmpres=/var/run/resolv.conf.${interface} + local tmpres=/var/run/resolv.conf.${interface}.dhcp rm -f $tmpres if [ -n "$new_domain_search" ]; then @@ -218,9 +248,9 @@ cat /etc/resolv.conf.tail >>$tmpres fi - case $resolvconf_enable in - # "no", "false", "off", or "0" - [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) + if resolvconf_enabled; then + $RESOLVCONF -a ${interface}.dhcp < $tmpres + else # When resolv.conf is not changed actually, we don't # need to update it. # If /usr is not mounted yet, we cannot use cmp, then @@ -244,12 +274,71 @@ # Try to ensure correct ownership and permissions. chown -RL root:wheel /etc/resolv.conf chmod -RL 644 /etc/resolv.conf - ;; + fi - *) - /sbin/resolvconf -a ${interface} < $tmpres - ;; - esac + rm -f $tmpres + + return 0 + fi + + return 1 +} + +add_new_resolv_conf6() { + local tmpres=/var/run/resolv.conf.${interface}.dhcp6 + rm -f $tmpres + + if [ -n "$new_dhcp6_domain_search" ]; then + echo "search $new_dhcp6_domain_search" >>$tmpres + elif [ -n "$new_domain_name" ]; then + echo "search $new_domain_name" >>$tmpres + fi + + if [ -n "$new_dhcp6_name_servers" ]; then + for nameserver in $new_dhcp6_name_servers; do + # If the nameserver has a link-local address + # add a (interface name) to it. + case $nameserver in + fe80:*) zone_id="%$interface";; + FE80:*) zone_id="%$interface";; + *) zone_id="";; + esac + echo "nameserver ${nameserver}${zone_id}" >>$tmpres + done + fi + + if [ -f $tmpres ]; then + if [ -f /etc/resolv.conf.tail ]; then + cat /etc/resolv.conf.tail >>$tmpres + fi + + if resolvconf_enabled; then + $RESOLVCONF -a ${interface}.dhcp6 < $tmpres + else + # When resolv.conf is not changed actually, we don't + # need to update it. + # If /usr is not mounted yet, we cannot use cmp, then + # the following test fails. In such case, we simply + # ignore an error and do update resolv.conf. + if cmp -s $tmpres /etc/resolv.conf; then + rm -f $tmpres + return 0 + fi 2>/dev/null + + # In case (e.g. during OpenBSD installs) + # /etc/resolv.conf is a symbolic link, take + # care to preserve the link and write the new + # data in the correct location. + + if [ -f /etc/resolv.conf ]; then + cat /etc/resolv.conf > /etc/resolv.conf.save + fi + cat $tmpres > /etc/resolv.conf + + # Try to ensure correct ownership and permissions. + chown -RL root:wheel /etc/resolv.conf + chmod -RL 644 /etc/resolv.conf + fi rm -f $tmpres @@ -321,6 +410,20 @@ PREINIT) delete_old_alias $IFCONFIG $interface inet alias 0.0.0.0 netmask 255.0.0.0 broadcast 255.255.255.255 up + if resolvconf_enabled; then + $RESOLVCONF -d ${interface}.dhcp + fi + ;; + +PREINIT6) + # Ensure interface is up. + ifconfig ${interface} up + + # XXX: Remove any stale addresses from aborted clients. + + if resolvconf_enabled; then + $RESOLVCONF -d ${interface}.dhcp6 + fi ;; ARPCHECK|ARPSEND) @@ -352,6 +455,41 @@ fi ;; +BOUND6|RENEW6|REBIND6|REBOOT6) + check_hostname + if [ -n "$old_ip6_address" ]; then + if [ "$old_ip6_address" != "$new_ip6_address" ]; then + delete_old_address6 + delete_old_routes6 + fi + fi + if [ "$reason" = BOUND6 ] || \ + [ "$reason" = REBOOT6 ] || \ + [ -z "$old_ip6_address" ] || \ + [ "$old_ip6_address" != "$new_ip6_address" ]; then + add_new_address6 + fi + if is_default_interface; then + add_new_resolv_conf6 + fi + ;; + +DEPREF6) + if [ -z ${new_ip6_address} ] ; then + exit_with_hooks 2; + fi + + ifconfig ${interface} inet6 ${new_ip6_address} deprecated + ;; + +EXPIRE6|RELEASE6|STOP6) + if [ -z ${old_ip6_address} ] || [ -z ${old_ip6_prefixlen} ] ; then + exit_with_hooks 2; + fi + + delete_old_alias6 + ;; + EXPIRE|FAIL) delete_old_alias if [ -n "$old_ip_address" ]; then @@ -364,17 +502,13 @@ # XXX Why add alias we just deleted above? add_new_alias if is_default_interface; then - case $resolvconf_enable in - # "no", "false", "off", or "0" - [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) + if resolvconf_enabled; then + $RESOLVCONF -d ${interface}.dhcp + else if [ -f /etc/resolv.conf.save ]; then cat /etc/resolv.conf.save > /etc/resolv.conf fi - ;; - *) - /sbin/resolvconf -d ${interface} - ;; - esac + fi fi ;; @@ -402,6 +536,11 @@ delete_old_routes exit_with_hooks 1 ;; + +*) + $LOGGER "Unhandled DHCP event: $reason" + exit_with_hooks 1 + ;; esac exit_with_hooks 0 Index: share/man/man5/rc.conf.5 =================================================================== --- share/man/man5/rc.conf.5 +++ share/man/man5/rc.conf.5 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 8, 2016 +.Dd July 14, 2016 .Dt RC.CONF 5 .Os .Sh NAME @@ -478,6 +478,47 @@ .Dq Li SYNCDHCP or .Dq Li NOSYNCDHCP . +.It Va dhclient6_program +.Pq Vt str +Path to the DHCP6 client program. +There is currently no default DHCP6 client program. +.It Va dhclient6_flags +.Pq Vt str +Additional flags to pass to the DHCP6 client program. +.It Va dhclient6_flags_ Ns Aq Ar iface +Additional flags to pass to the DHCP6 client program running on +.Ar iface +only. +When specified, this variable overrides +.Va dhclient6_flags . +.It Va background_dhclient6 +.Pq Vt bool +Set to +.Dq Li YES +to start the DHCP6 client in background. +This can cause trouble with applications depending on +a working network, but it will provide a faster startup +in many cases. +.It Va background_dhclient6_ Ns Aq Ar iface +When specified, this variable overrides the +.Va background_dhclient6 +variable for interface +.Ar iface +only. +.It Va synchronous_dhclient6 +.Pq Vt bool +Set to +.Dq Li YES +to start the DHCP6 client synchronously at startup. +This behavior can be overridden on a per-interface basis by replacing +the +.Dq Li DHCP6 +keyword in the +.Va ipv6_ Ns Aq Ar interface +variable with +.Dq Li SYNCDHCP6 +or +.Dq Li NOSYNCDHCP6 . .It Va defaultroute_delay .Pq Vt int When set to a positive value, wait up to this long after configuring @@ -948,7 +989,7 @@ instances that should be started at system boot time. If .Va pflog_instances -is set, for each whitespace-seperated +is set, for each whitespace-separated .Ar element in the list, .Ao Ar element Ac Ns Va _dev @@ -990,7 +1031,7 @@ .Xr ftp-proxy 8 are desired at boot time, .Va ftpproxy_instances -should contain a whitespace-seperated list of instance names. +should contain a whitespace-separated list of instance names. For each .Ar element in the list, a variable named @@ -1389,6 +1430,19 @@ ifconfig_ed0="DHCP" .Ed .Pp +It is possible to bring up an interface with DHCPv6 by adding +.Dq Li DHCP6 +to the +.Va ipv6_ Ns Aq Ar interface +variable. +For instance, to initialize the +.Li ed0 +device via DHCPv6, +it is possible to use something like: +.Bd -literal +ipv6_ed0="DHCP6" +.Ed +.Pp If you want to configure your wireless interface with .Xr wpa_supplicant 8 for use with WPA, EAP/LEAP or WEP, you need to add @@ -2267,7 +2321,7 @@ is set to .Dq Li YES , run the nfsuserd daemon, which is needed for NFSv4 in order -to map between user/group names vs uid/gid numbers. +to map between user/group names versus uid/gid numbers. If .Va nfsv4_server_enable is set to @@ -2770,7 +2824,7 @@ .Pq Vt bool If set to .Dq Li YES , -configure host to act as an IP router, e.g.\& to forward packets +configure host to act as an IP router, e.g.,\& to forward packets between interfaces. .It Va ipv6_gateway_enable .Pq Vt bool