dhcpcd-discuss

Re: Prefix delegation for /60

Neal P. Murphy

Tue Sep 05 18:36:34 2017

On Tue, 5 Sep 2017 21:09:15 +1000
Scott Leggett <scott@xxxxxxxx> wrote:

> Hi,
> 
> My ISP provides a /60 and I'm having trouble delegating it correctly to
> the other interfaces on my router using dhcpcd.
> 
> This is on current master/HEAD (dhcpcd-7.0.0-rc1-55-g5da607b5).
> 
> /etc/dhcpcd.conf:
> 
>   noipv6rs
>   allowinterfaces enp1s0
>   interface enp1s0
>       ipv6rs
>       ia_pd 1 enp2s0/1 wlxc412f52e39d2/2 wlxc412f52ebb7b/3 enp3s0/4
> 
> log snippet:
> 
>   systemd[1]: Started DHCP Client Daemon.
>   dhcpcd[248]: enp1s0: soliciting a DHCPv6 lease
>   dhcpcd[248]: enp1s0: ADV 2401:a400:2704:1750::/60 from fe80::d6ca:6dff:fe74:72f8
>   dhcpcd[248]: enp1s0: REPLY6 received from fe80::d6ca:6dff:fe74:72f8
>   dhcpcd[248]: 2401:a400:2704:1750::/60 262
>   dhcpcd[248]: 2401:a400:2704:1750::/60 258
>   dhcpcd[248]: enp1s0: adding address 2401:a400:2704:1750::/60
>   dhcpcd[248]: enp1s0: renew in 302400, rebind in 483840, expire in 604800 seconds
>   dhcpcd[248]: lo: adding reject route to 2401:a400:2704:1700::/60
>   dhcpcd[248]: enp2s0: adding address 2401:a400:2704:1701::1/64
>   dhcpcd[248]: enp3s0: adding address 2401:a400:2704:1704::1/64
>   dhcpcd[248]: wlxc412f52ebb7b: adding address 2401:a400:2704:1703::1/64
>   dhcpcd[248]: wlxc412f52e39d2: adding address 2401:a400:2704:1702::1/64
>   dhcpcd[248]: enp2s0: adding route to 2401:a400:2704:1701::/64
>   dhcpcd[248]: enp3s0: adding route to 2401:a400:2704:1704::/64
>   dhcpcd[248]: wlxc412f52ebb7b: adding route to 2401:a400:2704:1703::/64
>   dhcpcd[248]: wlxc412f52e39d2: adding route to 2401:a400:2704:1702::/64
> 
> Notice that the prefix received from the upstream router
> (2401:a400:2704:1750::/60), appears to be incorrectly interpreted later
> as a /56 (2401:a400:2704:1700::/60), which is then delegated incorrectly
> to the interfaces. E.g. the delegation to enp2s0 should be
> 2401:a400:2704:1751::1/64, but instead it is 2401:a400:2704:1701::1/64.
> 
> Have I misconfigured dhcpcd, misunderstood prefix delegation, or hit a
> bug?
> 

The following works for me. It gets a /60 from Comcrash and assigns a /64 to each of the four interfaces. It does only IPv6 to keep it from interfering with IPv4 (which is handled automatically on the Smoothie; I haven't finished IPv6 work for Express). I last tested on 6.10 or 6.11.


This is the .conf I use on my Smoothwall Express v3.1 system (for testing).
-------------------------------------------------------------------------
#
# A sample configuration for dhcpcd.
# See dhcpcd.conf(5) for details.

# Allow users of this group to interact with dhcpcd via the control socket.
#controlgroup wheel

# Inform the DHCP server of our hostname for DDNS.

# Use the hardware address of the interface for the Client ID.
#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

# Persist interface configuration when dhcpcd exits.
persistent

# Rapid commit support.
# Safe to enable by default because it requires the equivalent option set
# on the server to actually work.
option rapid_commit

# A list of options to request from the DHCP server.
option domain_name_servers, domain_name, domain_search, host_name
option classless_static_routes
# Most distributions have NTP support.
option ntp_servers
# Respect the network MTU.
# Some interface drivers reset when changing the MTU so disabled by default.
#option interface_mtu

# A ServerID is required by RFC2131.
require dhcp_server_identifier

# Generate Stable Private IPv6 Addresses instead of hardware based ones
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, hostname, resolv.conf, ntp.conf, timezone, wpa_supplicant

# Use smoothie's script
script /etc/rc.d/rc.update6red

allowinterfaces eth0 eth1 eth2 eth3
denyinterfaces lo ipsec0 ipsec1
debug
ipv6only
ipv6ra_own
ipv6ra_own_default
leasetime 31622400
nodhcp
nodhcp6
noipv6rs
#logfile /var/log/dhcpcd6.log

interface eth0
iaid 4b:17:f2:7a

interface eth1
iaid 4b:17:f2:7b

interface eth2
iaid 4b:17:f2:7c

interface eth3
dhcp6
ipv6rs
iaid 4b:17:f2:7d
ia_na 4b:17:f2:7d
ia_pd 4b:17:f2:7a/::/60 eth0/1/64 eth1/2/64 eth2/3/64
-------------------------------------------------------------------------




This is the rc.update6red script. There are more than several Express-specific things in here; but it should yield at least a few clues.
-------------------------------------------------------------------------
#!/bin/bash

# Like nearly everything in SWE, the file is covered by the project's
#   umbrella GPL license.

# Tweaks to handle DHCP changes by Neal Murphy and Stan Prescott, 4/2013
# Re-arranged a little and ip-up merged in; Neal Murphy, 7/2013
# Console output expanded to dump to console, syslog (smoothwall) and/or
#   syslog (dhcpcd debugging); Murphy/Jones, 2015

# In addition to execution trace debugging, it is possible to dump this script's
#   environment as passed from dhcpcd.
#
# To enable dhcpcd environment logging, create the debug_dhcpcdenv flag file:
#   touch "/var/run/debug-dhcpcdenv"
# To disable this logging, delete the file:
#   rm -f "/var/run/debug-dhcpcdenv"


# A bit of shorthand
ethDIR="/var/smoothwall/ethernet"
pppDIR="/var/smoothwall/ppp"
redDIR="/var/smoothwall/red"

. /etc/rc.d/inc.rc-functions

dns1ENV=$DNS1
dns2ENV=$DNS2
. ${ethDIR}/settings


# readRED6: read the data files in .../red/*
function readRED6 {
        case $RED_TYPE in
          DHCP)
            RED6_INTERFACE=`cat $redDIR/iface6`
            RED6_ADDRESS=`cat $redDIR/local6-ipaddress`
            RED6_GATEWAY=`cat $redDIR/remote6-ipaddress`
            RED6_NETMASK=`cat $redDIR/dhcp6-netmask`
            RED6_DNS1=`cat $redDIR/dns61`
            RED6_DNS2=`cat $redDIR/dns62`

            RED_DNS1=`cat $redDIR/dns1`
            RED_DNS2=`cat $redDIR/dns2`
            ;;
          *)
            echolog "" "s" "$DEBUG_DHCPCD" "..readRED6 called for invalid red type '$RED_TYPE'"
            exit 0
            ;;
        esac
}

# writeRED: write the data files in .../red/*
function writeRED6 {
        echo -n $1 >$redDIR/iface6
        echo -n $2 >$redDIR/local6-ipaddress
        echo -n $3 >$redDIR/remote6-ipaddress
        echo -n $4 >$redDIR/dhcp6-netmask
        echo -n $5 >$redDIR/dns61
        echo -n $6 >$redDIR/dns62
        > $redDIR/active6
        chown nobody:nobody $redDIR/*
}


if [ "$reason" != "ROUTERADVERT" ]; then
  echolog "$crDEBUG" "" "$DEBUG_DHCPCD" "..enter rc.update6red ($reason) [`date`]"

  # Drop a trace
  echolog "$crDEBUG" "s" "$crDEBUG_DHCPCD" "..Update6 RED"
fi


if [ "$RED_TYPE" == "DHCP" ]; then
        # First up; when RED is DHCP

        # We only care about BOUND, REBOOT, RENEW, STOPPED and STOP; we ignore the rest:
        #   EXPIRE*|EXPIRE6*|NAK*|FAIL*|CARRIER*|NOCARRIER*|PREINIT*|DEPARTED*|TIMEOUT*
        # If new reasons appear, we'll see them in the log.

        if [ "$reason" != "ROUTERADVERT" ]; then
                echolog "$crDEBUG" "s" "$DEBUG_DHCPCD" "..RED6 is DHCP"
        fi

        # Special dhcpcd debug: maybe dump the environment to syslog (debug.log)
        if [ -e "/var/run/debug-dhcpcd6env" ]; then
                (
                echo -e "\n======\nAs of `date`"
                echo "Second Param: " $2
                echo "env reason: " $reason
                echo
                echo "Positional params"
                for i in "$@"; do echo "  '$i'";done

                echo "environment"
                set
                ) |& logger -t dhcpcd6env -p local6.debug
        fi
        # end dhcpcd environment debug logging block


        # Why did you call me?
        case $reason in
          STOPPED)
            # Nothing to do; either the system is going down or networking is
            #   being stopped for restart. *Technically*, it might be more correct
            #   to stop the various services; but since they are re-started soon
            #   enough or the system halts, it might not matter.

            echolog "" "s" "" "..DHCP6 stopped on $interface"
            echolog "$crDEBUG" "" \
                    "$DEBUG_DHCPCD" "..DHCP6 stopped on $interface; rc.update6red RED_TYPE [$RED_TYPE] ($reason) [`date`]"
            #echo -e "\n$reason" >> /var/log/dhcpcdtmp.log
            #set | egrep "^[a-z]" >> /var/log/dhcpcdtmp.log
            for i in $old_dhcp6_name_servers; do
                    sed -i -e "/$i/d" /etc/resolv.conf
            done

            # This might could get annoying if the lease changes often
            [ "$interface" == "$RED_DEV" ] && /usr/bin/sounds/offlinesound
            echolog "$crDEBUG" "" "$DEBUG_DHCPCD" \
                    "..DHCP6 stopped; exit rc.update6red RED_TYPE [$RED_TYPE] ($reason) [`date`]"
            echolog "" "s" "" "..DHCP6 stopped, reason: ($reason)"

            # Clear the v6 files and mark IPv6 not active on RED
            writeRED6
            rm /var/smoothwall/red/active6

            echolog "$crDEBUG" "" "$DEBUG_DHCPCD" \
                    "..exit rc.update6red RED_TYPE [$RED_TYPE] ($reason) [`date`]"
            exit 0
            ;;

          BOUND6|REBOOT6)
            # New lease bound; all new.

            # Log some stuff
            #echo -e "\n$reason" >> /var/log/dhcpcdtmp.log
            #set | egrep "^[a-z]" >> /var/log/dhcpcdtmp.log

            # Clear the old DNS server addresses in resolv.conf, if any
            for i in $old_dhcp6_name_servers; do
              sed -i -e '/$i/d' /etc/resolv.conf
            done >> /etc/resolv.conf

            # Put the new IPv6 DNS addresses in resolv.conf
            for i in $new_dhcp6_name_servers; do
                    sed -i -e '/$i/d' /etc/resolv.conf
                    echo "nameserver $i" >> /etc/resolv.conf
            done

            # Log lease received and address bound
            echolog "E" "s" "" "..DHCP6 lease bound ($reason) and prefix delegated; update RED6 info"
            echolog "$crDEBUG" "" "$DEBUG_DHCPCD" "..DHCP6 new lease bound ($reason) and prefix delegated; update RED6 info. rc.update6red RED_TYPE [$RED_TYPE] ($reason) [`date`]"

            # Log some environment
            #echo $reason >> /var/log/dhcpcdtmp.log
            #set | egrep "^[a-z]" >> /var/log/dhcpcdtmp.log

            # Save the address
            sed -i -e '/^IP6_ADDRESS/d' /var/lib/dhcpcd/dhcpcd6-$interface.info
            echo "IP6_ADDRESS=$new_dhcp6_ia_na1_ia_addr1/128" >> /var/lib/dhcpcd/dhcpcd6-$interface.info
            echolog "$crDEBUG" "" "$DEBUG_DHCPCD" "..DHCP6 new address: $new_dhcp6_ia_na1_ia_addr1/128 [$RED_TYPE] ($reason) [`date`]"

            # Did we get a prefix?
            if [ ! -z "$new_dhcp6_ia_pd1_prefix1" ]; then

              # Save the delegated net
              echo "IP6_NET=$new_dhcp6_ia_pd1_prefix1/$new_dhcp6_ia_pd1_prefix1_length" > /var/lib/dhcpcd/dhcpcd6-delegated.info
              echolog "$crDEBUG" "" "$DEBUG_DHCPCD" "..DHCP6 delegated prefix: $new_dhcp6_ia_pd1_prefix1/$new_dhcp6_ia_pd1_prefix1_length [$RED_TYPE] ($reason) [`date`]"

              # Clear the old prefix address, if any, from RED
              if [ ! -z "$old_dhcp6_ia_pd1_prefix1" ]; then
                ip -6 addr del ${old_dhcp6_ia_pd1_prefix1}1/64 dev $RED_DEV #>/dev/null 2>&1
              fi

              # And assign 'subnet 0'::1 to RED
              RED6_IP="${new_dhcp6_ia_pd1_prefix1}1"
              ip -6 addr add ${new_dhcp6_ia_pd1_prefix1}1/64 dev $RED_DEV

              # dhcpcd assigns 'subnet 1', 'subnet 2' and 'subnet 3' to GREEN, ORANGE and PURPLE, respectively.
            fi

            # Save the available RED info
            readRED6
            writeRED6 "$interface" "$new_dhcp6_ia_na1_ia_addr1" "$RED6_GATEWAY" \
                     "/128" $new_dhcp6_name_servers

            # We may want to restart daemons &cet, so don't exit.
            ;;

          RELEASE6)
            # Log some stuff
            #echo -e "\n$reason" >> /var/log/dhcpcdtmp.log
            #set | egrep "^[a-z]" >> /var/log/dhcpcdtmp.log

            # Remove IPv6 from resolv.conf
            for i in $old_dhcp6_name_servers; do
                    sed -i -e "/$i/d" /etc/resolv.conf
            done

            # Clear the RED6 files
            writeRED6
            rm -f $redDIR/active6

            echolog "$crDEBUG" "" "$DEBUG_DHCPCD" \
                    "..exit rc.update6red RED_TYPE [$RED_TYPE] ($reason) [`date`]"
            exit 0
            ;;

          EXPIRE6)
            # Lease expired; clean up.
            #echo -e "\n$reason" >> /var/log/dhcpcdtmp.log
            #set | egrep "^[a-z]" >> /var/log/dhcpcdtmp.log

            writeRED6
            rm -f $redDIR/active6

            echolog "$crDEBUG" "" "$DEBUG_DHCPCD" \
                    "..DHCP6 lease expired ($old_dhcp6_ia_na1_ia_addr1; old_dhcp6_ia_pd1_prefix1) $interface [$RED_TYPE] ($reason) [`date`]"

            echolog "$crDEBUG" "" "$DEBUG_DHCPCD" \
                    "..exit rc.update6red RED_TYPE [$RED_TYPE] ($reason) [`date`]"
            exit 0
            ;;

          DELEGATED6)
            # IP addrs have been fetched and delegated to internal IFs. Record them.
            # Eventually, rewrite dhcp.conf and/or restart dhcpd (the server daemon)
            #   so that correct addresses will be fed to internal hosts.
            #echo -e "\n$reason" >> /var/log/dhcpcdtmp.log
            #set | egrep "^[a-z]" >> /var/log/dhcpcdtmp.log
            sed -i -e '/^IP6_ADDRESS/d' /var/lib/dhcpcd/dhcpcd6-$interface.info
            echo "IP6_ADDRESS=$new_delegated_dhcp6_prefix" >> /var/lib/dhcpcd/dhcpcd6-$interface.info
            echolog "$crDEBUG" "" "$DEBUG_DHCPCD" \
                    "..DHCP6 $new_delegated_dhcp6_prefix delegated to $interface [$RED_TYPE] ($reason) [`date`]"

            echolog "$crDEBUG" "" "$DEBUG_DHCPCD" \
                    "..exit rc.update6red RED_TYPE [$RED_TYPE] ($reason) [`date`]"
            exit 0
            ;;

          ROUTERADVERT)
            # Our default gateway. These arrive 'forever', so minimize logging.

            # Log some stuff
            #echo -e "\n$reason" >> /var/log/dhcpcdtmp.log
            #set | egrep "^[a-z]" >> /var/log/dhcpcdtmp.log

            # Get current RED params, store and log if changed.
            readRED6
            if [ "$RED6_GATEWAY" != "$nd1_from" ]; then
              echolog "$crDEBUG" "" "$DEBUG_DHCPCD" "..enter rc.update6red ($reason) [`date`]"
              echolog "$crDEBUG" "s" "$crDEBUG_DHCPCD" "..Update6 RED"

              writeRED6 "$interface" "$RED6_ADDRESS" "$nd1_from" \
                        "$RED6_NETMASK" "$RED6_DNS1" "$RED6_DNS2"

              echolog "$crDEBUG" "" "$DEBUG_DHCPCD" \
                      "..DHCP6 $nd1_from assigned as default gateway [$RED_TYPE] ($reason) [`date`]"
              echolog "$crDEBUG" "" "$DEBUG_DHCPCD" \
                      "..exit rc.updatered RED_TYPE [$RED_TYPE] ($reason) [`date`]"
            fi
            exit 0
            ;;

          *)
            # Ignore all other reasons, known or not. If important, we'll code it up.
            echolog "$crDEBUG" "s" "$DEBUG_DHCPCD" \
                    "..Ignore DHCPCD6 unknown callback reason '$reason'"
            echolog "$crDEBUG" "" "$DEBUG_DHCPCD" \
                    "..exit rc.update6red RED_TYPE [$RED_TYPE] ($reason) [`date`]"
            #echo -e "\nUNKNOWN $reason" >> /var/log/dhcpcdtmp.log
            #set | egrep "^[a-z]" >> /var/log/dhcpcdtmp.log
            exit 0
            ;;
        esac


fi

#####################
# For now, do nothing when IPv6 changes
#####################

exit 0


# Restart/reset everything that depends on RED
#
echolog "E" "s" "" "..DNSMasq (DNS1: $DNSMASQ_DNS1; DNS2: $DNSMASQ_DNS2)"

#echolog "E" "s" "" "..RED6 filtering"
# For now, there is minimal filtering; until IPv6 is fully integrated, the IPv6
#   firewall is static: NEW-to-RED is allowed, REL/EST-from-RED is allowed,
#   and all traffic among internal LANs is allowed. Not ideal, but good enough
#   for testing and development.

#/usr/bin/smoothcom setincoming
#/usr/bin/smoothcom setoutgoing

# Part of Roadster's integrated TOFC
#if [ -f /var/smoothwall/outgoing/configErrors.log ]; then
#  tput smso;
#  sed -e 's/^/..  /' /var/smoothwall/outgoing/configErrors.log
#  tput rmso
#fi

#echolog "E" "s" "" "..external access rules"
#/usr/bin/smoothcom setxtaccess

echolog "E" "s" "$DEBUG_DHCPCD" "..snort, squid, upnpd, TC, DDNS, VPN (as enabled)"
/usr/bin/smoothcom snortrestart
echolog "$crDEBUG" "" "$DEBUG_DHCPCD" "....smoothcom: squidrestart  [`date`]"
/usr/bin/smoothcom squidrestart
echolog "$crDEBUG" "" "$DEBUG_DHCPCD" "....smoothcom: upnpdrestart [`date`]"
/usr/bin/smoothcom upnpdrestart
echolog "$crDEBUG" "" "$DEBUG_DHCPCD" "....smoothcom: trafficrestart [`date`]"
/usr/bin/smoothcom trafficrestart

/usr/bin/smoothwall/setddns.pl

/etc/rc.d/rc.vpn.up

# Adapted from Steve McNeill's ModInstall
echolog "E" "s" "" "..run mods' 'on RED6 up' scripts"
# if any; limited to .../mods/*/etc/rc.d
shopt -s nullglob
for i in /var/smoothwall/mods/*/etc/rc.d/00rc.update6red; do
  $i
done
shopt -u nullglob

# exit rc.updatered:
echolog "$crDEBUG" "" "$DEBUG_DHCPCD" "..exit rc.updatered RED_TYPE [$RED_TYPE] ($reason) [`date`]"

-------------------------------------------------------------------------

Follow-Ups:
Re: Prefix delegation for /60Scott Leggett
References:
Prefix delegation for /60Scott Leggett
Archive administrator: postmaster@marples.name