########################################################################## ## ## The rc.router Project ## Copyright (C) 2026 ADAM David Alan Martin ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU Affero General Public License as ## published by the Free Software Foundation, either version 3 of the ## License, or (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU Affero General Public License for more details. ## ## You should have received a copy of the ## GNU Affero General Public License along with this program. If not, ## see . ## ########################################################################## ########################################################### # Print debugging info, if `debug_conf` is set. _echo() { if [ "${debug_conf}" = "YES" ] then echo 1>&2 $* fi } ########################################################### # Log warning info. _warn() { if [ -x /usr/bin/logger ]; then logger "$0: WARNING: $*" fi echo 1>&2 "$0: WARNING: $*" } ########################################################### # Repeat a command for multiple arguments # # - First param is the name of the function or binary to repeat. # - Remaining arguments are each passed to the function. # # Example: __repeat touch Hello World __repeat() { __func=$1;shift 1 while [ "$1" != "" ] do ${__func} $1 shift 1 done } ########################################################### # Create the specified single interface # # This adds the interface to the `cloned_interfaces` # rc.conf variable __clone_interface() { _echo Adding $1 to cloned interfaces cloned_interfaces="${cloned_interfaces} $1" _echo "Cloned interfaces are now \"${cloned_interfaces}\"" } ########################################################### # Create the specified list of interfaces. clone_interfaces() { __repeat __clone_interface $* } ########################################################### # Create the specified interface # (optionally create more interfaces) clone_interface() { clone_interfaces $* } __add_wireguard_interface() { _echo "Adding $1 to ${wireguard_interfaces}" wireguard_enable="YES" wireguard_interfaces="${wireguard_interfaces} $1" } add_wireguard_interfaces() { __repeat __add_wireguard_interface $* } add_wireguard_interface() { add_wireguard_interfaces $* } add_wireguard_route() { add_route_policy $1 $2 add_wireguard_interface wg$2 } add_wireguard_route_v4() { add_route_policy_v4 $1 $2 # Assuming v6 did this, for now... #add_wireguard_interface wg$2 } compute_56_net() { _echo Running 56 > /dev/fd/2 _echo 'Computing for `'$1'`' > /dev/fd/2 echo $1 | sha1 | cut -c 1-12 | sed -e 's/\([0-9a-f][0-9a-f]\)/\1:/g' | awk -F: '{print "fd"$1":"$2$3":"$4$5":"$6}' } compute_48_net() { _echo Running 48 > /dev/fd/2 _echo 'Computing for `'$1'`' > /dev/fd/2 echo $1 | sha1 | cut -c 1-10 | sed -e 's/\([0-9a-f][0-9a-f]\)/\1:/g' | awk -F: '{print "fd"$1":"$2$3":"$4$5":}' } ########################################################### # Compute the ULA prefix for the specified subnet size # using the second argument (string) as a seed. # # Note: Only `/56` and `/48` ULA prefixes are supported at # this time. compute_net() { _echo 'Computing for `'$2'`' > /dev/fd/2 case $1 in 56) compute_56_net "$2" ;; 48) compute_48_net "$2" ;; esac } compute_v4_net() { _prefix_name=v4_net_${1} _prefix=\${${_prefix_name}} _subnet=$2 echo "${_prefix}.${_subnet}.1/24" } compute_v6_net() { _subnet=$2 _prefix=$1 echo "${_prefix}${_subnet}::1" } _compute_nets() { _card=$1 shift 1 _vlan=$1 shift 1 _base=$((${_vlan}%10)) _net=$((${_vlan}/100)) _subnet=${_net}${_base} _extra_address="" if [ -z "${1}" ] then #echo "Error in configuration: No network class given" #exit 1 sleep 0 fi _class=$1 shift 1 _priv="YES" while true do case ${1} in "no_ula") _priv="NO" ;; "no_isp") _isp="" ;; isp=*) _isp=`echo ${1} | sed -e 's/isp=//'` ;; *) break ;; esac shift 1 done while [ -n "${1}" ] do _extra_address="${_extra_address} $1" shift 1 done } _add_vlan() { _card=$1 _vlan=$2 _vlans_var=vlans_${_card} eval _vlans="\${${_vlans_var}}" _echo "XXX ${_vlans} XXX" _echo "QQQ ${_vlans} QQQ" | grep ${_vlan} _qres=$? _echo $_qres echo "${_vlans}" | grep ${_vlan} > /dev/null _res=$? _echo $_res if [ 0 -ne $_res ] then _echo vlans_${_card}="\${vlans_${_card}} ${_vlan}" eval vlans_${_card}=\"\${vlans_${_card}} ${_vlan}\" else _echo "Not adding vlan ${_vlan} to card ${_card}" fi } _add_rtadv() { _card=$1 _vlan=$2 _subcard="${_card}.${_vlan}" _echo "XXX ${rtadvd_interfaces} XXX" _echo "QQQ ${rtadvd_interfaces} QQQ" | grep ${_subcard} _qres=$? _echo $_qres echo "${rtadvd_interfaces}" | grep ${_subcard} > /dev/null _res=$? _echo $_res if [ 0 -ne $_res ] then _echo rtadvd_interfaces="${rtadvd_interfaces} ${_subcard}" rtadvd_interfaces="${rtadvd_interfaces} ${_subcard}" else _echo "Not adding subcard ${_subcard} to ipv6 rtadvd list: ${rtadvd_interfaces}" fi } _add_dhcpv6() { _iface=${1} _isp=${2} if [ -z "${_isp}" ] then _isp=${default_isp} fi eval dhcpv6_${_isp}_list=\"\${dhcpv6_${_isp}_list} ${_iface}\" } add_dhcpv6() { _iface=${1} _sla=${2} _isp=${3} if [ -z "${_isp}" ] then _isp=${default_isp} fi eval dhcpv6_${_isp}_supplement_list=\"\${dhcpv6_${_isp}_supplement_list} ${_iface}/${_sla}\" } _emit_dhcpv6_for_iface() { _iface=${1} _sla=${2} echo " prefix-interface ${_iface}" >> ${_dhcp_file} echo " {" >> ${_dhcp_file} echo " sla-id ${_sla};" >> ${_dhcp_file} echo " sla-len $((64 - ${_prefix_len}));" >> ${_dhcp_file} echo " };" >> ${_dhcp_file} echo "" >> ${_dhcp_file} } _emit_dhcpv6_for_isp() { _isp=${1} eval _interface=\"\${dhcp_interface_${_isp}}\" _n=${2} eval _prefix_len=\"\${dhcp_prefix_${_isp}}\" mkdir -p ${router_conf_dir}/gen _dhcp_file=${router_conf_dir}/gen/dhcp6c.${_isp}.conf eval _isp_list=\${dhcpv6_${_isp}_list} eval _isp_supplement_list=\${dhcpv6_${_isp}_supplement_list} _echo "Building DHCP info for ${_isp} (interfaces: ${_isp_list})" echo "" > ${_dhcp_file} echo "id-assoc pd $_n" >> ${_dhcp_file} echo "{" >> ${_dhcp_file} echo " prefix ::/${_prefix_len} infinity;" >> ${_dhcp_file} for _iface_desc in ${_isp_supplement_list} do _iface=`echo ${_iface_desc} | sed -e 's;/.*$;;'` _sla=`echo ${_iface_desc} | sed -e 's;^.*/;;'` _emit_dhcpv6_for_iface ${_iface} ${_sla} done for _iface in ${_isp_list} do _vlan=`echo ${_iface} | sed -e 's/^.*\.//'` _num=`echo ${_vlan} | sed -e 's/\([0-9]\)0\([0-9]\)/\1\2/'` _vlan_sla=`printf "%d" 0x${_num}` _emit_dhcpv6_for_iface ${_iface} ${_vlan_sla} done echo "};" >> ${_dhcp_file} echo "" >> ${_dhcp_file} echo "interface ${_interface} {" >> ${_dhcp_file} echo " send ia-pd ${_n};" >> ${_dhcp_file} echo "};" >> ${_dhcp_file} } _emit_dhcpv6() { _n=0 for _isp in ${dhcp_isps} do _emit_dhcpv6_for_isp $_isp ${_n} _n=$((${_n}+1)) done } add_v4_net() { _compute_nets $* _add_vlan $_card $_vlan _class_group="" if [ ! -z "${_class}" ] then _class_group="group ${_class}" fi eval ifconfig_${_card}_${_vlan}=\"$(compute_v4_net $_card $_subnet) group internal ${_class_group}\" eval dhcpd_ifaces=\"${dhcpd_ifaces} ${_card}.${_vlan}\" } _add_v6_prefixes() { _next_alias=$1 shift 1 while [ -n "${1}" ] do eval ifconfig_${_card}_${_vlan}_alias${_next_alias}=\"inet6 $1/64\" shift 1 _next_alias=`expr $_next_alias + 1` done } ########################################################### # Create a VLAN on the specified network interface with # the specififed VLAN-ID, interface group, and optional # address parameters. # # @1 - The underlying network interface to use. # @2 - The VLAN-ID of the VLAN to create. # @3 - The network interface group to put this new # VLAN into. (Uses: `ifconfig @dev group @3`) # @* - Additional networks to join (or adjustments # to make). # - `no_ula` Make this VLAN not use a ULA. # - `no_isp` Make this VLAN not use any ISP prefixes # (from DHCPv6) # - `isp:${isp}` Put this VLAN under the specified ISP # - `2001:db8:42::` Make this VLAN have `2001:db8:42::/64` # as a prefix. # add_v6_net() { _isp=${default_isp} _compute_nets $* _add_vlan $_card $_vlan _add_rtadv $_card $_vlan _class_group="" if [ ! -z "${_class}" ] then _class_group="group ${_class}" fi eval ifconfig_${_card}_${_vlan}_ipv6=\"inet6 fe80::1/64 group internal ${_class_group}\" _next_alias=0 if [ "${_priv}" = "YES" ] then eval ifconfig_${_card}_${_vlan}_alias${_next_alias}=\"inet6 $(compute_v6_net ${secret_ip6_net} ${_subnet})/64\" _next_alias=1 # UGLY HACK!!! Does BASH increment work in BSD's sh? fi if [ -n "${_isp}" ] then _add_dhcpv6 $_card.$_vlan ${_isp} fi _add_v6_prefixes ${_next_alias} ${_extra_address} } add_net() { add_v4_net $* add_v6_net $* } option_selected() { eval _value=\$${1} _echo "option_selected: $1 is set to $_value." case $_value in # "yes", "true", "on", or "1" [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) echo "YES" ;; # "no", "false", "off", or "0" [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) echo "NO" ;; *) _warn "\$${1} is not set properly - see rc.conf(5)." echo "FAILED" ;; esac } build_zoneinfo_for_host() { _ISP_PREFIX=${1};shift 1 _MAIN_SUBNET=${1};shift 1 _host=$( echo ${1} | sed -e 's/=.*$//' ) # Not really the MAC, but maybe that's the right way? # For now it's host=SUFFIX _MAC=$( echo ${1} | sed -e 's/^.*=//' ) #echo "Host: ${_host} --- MAC: ${_MAC}" echo "${_host}" IN AAAA ${_ISP_PREFIX}${_MAIN_SUBNET}:${_MAC} } build_zoneinfo() { _prefix=${1} ; shift 1 _subnet=${1} ; shift 1 echo '$TTL 1h30m' echo '@ IN SOA '"${localnet_zoneinfo_master_nameserver}"'. '"${localnet_zoneinfo_email}"'. (' date +'%s' echo 7200 echo 1200 echo 7200 echo 5400 echo ')' echo '$ORIGIN '"${localnet_zoneinfo_domain}"'.' for nameserver in ${localnet_zoneinfo_nameservers} do echo '@ IN NS '"${nameserver}"'.' done for _hostline in $(cat ${1}) do #echo ${_prefix} ${_subnet} ${_hostline} case "${_hostline}" in "#"*) continue ;; esac build_zoneinfo_for_host ${_prefix} ${_subnet} ${_hostline} done } # Now we compute a prefix from the hash of the network name. # This lets us be deterministic, yet still know what our # net name is. # #compute_net 56 "${ip6_net_name}" secret_ip6_net=$(compute_net ${ip6_net_size} "${ip6_net_name}") . ${router_conf_dir}/pf-framework.subr # vim: ft=bash