#!/bin/bash
# Copyright (C) 2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
. /lib/lsb/init-functions
: ${vyatta_env:=/etc/default/vyatta}
source $vyatta_env
declare progname=${0##*/}
declare action=$1; shift
declare -x BOOTFILE=$vyatta_sysconfdir/config/config.boot
# If vyos-config= boot option is present, use that file instead
for x in $(cat /proc/cmdline); do
[[ $x = vyos-config=* ]] || continue
VYOS_CONFIG="${x#vyos-config=}"
done
if [ ! -z "$VYOS_CONFIG" ]; then
if [ -r "$VYOS_CONFIG" ]; then
echo "Config selected manually: $VYOS_CONFIG"
declare -x BOOTFILE="$VYOS_CONFIG"
else
echo "WARNING: Could not read selected config file, using default!"
fi
fi
declare -a subinit
declare -a all_subinits=( firewall )
if [ $# -gt 0 ] ; then
for s in $@ ; do
[ -x ${vyatta_sbindir}/${s}.init ] && subinit[${#subinit}]=$s
done
else
for s in ${all_subinits[@]} ; do
[ -x ${vyatta_sbindir}/${s}.init ] && subinit[${#subinit}]=$s
done
fi
GROUP=vyattacfg
# easy way to make empty file without any command
empty()
{
>$1
}
# check if bootup of this portion is disabled
disabled () {
grep -q -w no-vyos-$1 /proc/cmdline
}
# if necessary, provide initial config
init_bootfile () {
if [ ! -r $BOOTFILE ] ; then
if [ -f $vyatta_sysconfdir/config.boot.default ]; then
cp $vyatta_sysconfdir/config.boot.default $BOOTFILE
else
$vyos_libexec_dir/system-versions-foot.py > $BOOTFILE
fi
chgrp ${GROUP} $BOOTFILE
chmod 660 $BOOTFILE
fi
}
# if necessary, migrate initial config
migrate_bootfile ()
{
if [ -x $vyos_libexec_dir/run-config-migration.py ]; then
log_progress_msg migrate
sg ${GROUP} -c "$vyos_libexec_dir/run-config-migration.py $BOOTFILE"
fi
}
# load the initial config
load_bootfile ()
{
log_progress_msg configure
(
if [ -f /etc/default/vyatta-load-boot ]; then
# build-specific environment for boot-time config loading
source /etc/default/vyatta-load-boot
fi
if [ -x $vyos_libexec_dir/vyos-boot-config-loader.py ]; then
sg ${GROUP} -c "$vyos_libexec_dir/vyos-boot-config-loader.py $BOOTFILE"
fi
)
}
# restore if missing pre-config script
restore_if_missing_preconfig_script ()
{
if [ ! -x ${vyatta_sysconfdir}/config/scripts/vyos-preconfig-bootup.script ]; then
mkdir -p ${vyatta_sysconfdir}/config/scripts
chgrp ${GROUP} ${vyatta_sysconfdir}/config/scripts
chmod 775 ${vyatta_sysconfdir}/config/scripts
cp ${vyos_rootfs_dir}/opt/vyatta/etc/config/scripts/vyos-preconfig-bootup.script ${vyatta_sysconfdir}/config/scripts/
chgrp ${GROUP} ${vyatta_sysconfdir}/config/scripts/vyos-preconfig-bootup.script
chmod 750 ${vyatta_sysconfdir}/config/scripts/vyos-preconfig-bootup.script
fi
}
# execute the pre-config script
run_preconfig_script ()
{
if [ -x $vyatta_sysconfdir/config/scripts/vyos-preconfig-bootup.script ]; then
$vyatta_sysconfdir/config/scripts/vyos-preconfig-bootup.script
fi
}
# restore if missing post-config script
restore_if_missing_postconfig_script ()
{
if [ ! -x ${vyatta_sysconfdir}/config/scripts/vyos-postconfig-bootup.script ]; then
mkdir -p ${vyatta_sysconfdir}/config/scripts
chgrp ${GROUP} ${vyatta_sysconfdir}/config/scripts
chmod 775 ${vyatta_sysconfdir}/config/scripts
cp ${vyos_rootfs_dir}/opt/vyatta/etc/config/scripts/vyos-postconfig-bootup.script ${vyatta_sysconfdir}/config/scripts/
chgrp ${GROUP} ${vyatta_sysconfdir}/config/scripts/vyos-postconfig-bootup.script
chmod 750 ${vyatta_sysconfdir}/config/scripts/vyos-postconfig-bootup.script
fi
}
# execute the post-config scripts
run_postconfig_scripts ()
{
if [ -x $vyatta_sysconfdir/config/scripts/vyatta-postconfig-bootup.script ]; then
$vyatta_sysconfdir/config/scripts/vyatta-postconfig-bootup.script
fi
if [ -x $vyatta_sysconfdir/config/scripts/vyos-postconfig-bootup.script ]; then
$vyatta_sysconfdir/config/scripts/vyos-postconfig-bootup.script
fi
}
run_postupgrade_script ()
{
if [ -f $vyatta_sysconfdir/config/.upgraded ]; then
# Run the system script
/usr/libexec/vyos/system/post-upgrade
# Run user scripts
if [ -d $vyatta_sysconfdir/config/scripts/post-upgrade.d ]; then
run-parts $vyatta_sysconfdir/config/scripts/post-upgrade.d
fi
rm -f $vyatta_sysconfdir/config/.upgraded
fi
}
#
# On image booted machines, we need to mount /boot from the image-specific
# boot directory so that kernel package installation will put the
# files in the right place. We also have to mount /boot/grub from the
# system-wide grub directory so that tools that edit the grub.cfg
# file will find it in the expected location.
#
bind_mount_boot ()
{
persist_path=$(/opt/vyatta/sbin/vyos-persistpath)
if [ $? == 0 ]; then
if [ -e $persist_path/boot ]; then
image_name=$(cat /proc/cmdline | sed -e s+^.*vyos-union=/boot/++ | sed -e 's/ .*$//')
if [ -n "$image_name" ]; then
mount --bind $persist_path/boot/$image_name /boot
if [ $? -ne 0 ]; then
echo "Couldn't bind mount /boot"
fi
if [ ! -d /boot/grub ]; then
mkdir /boot/grub
fi
mount --bind $persist_path/boot/grub /boot/grub
if [ $? -ne 0 ]; then
echo "Couldn't bind mount /boot/grub"
fi
fi
fi
fi
}
clear_or_override_config_files ()
{
for conf in snmp/snmpd.conf snmp/snmptrapd.conf snmp/snmp.conf \
keepalived/keepalived.conf cron.d/vyos-crontab \
ipvsadm.rules default/ipvsadm resolv.conf
do
if [ -s /etc/$conf ] ; then
empty /etc/$conf
chmod 0644 /etc/$conf
fi
done
}
update_interface_config ()
{
if [ -d /run/udev/vyos ]; then
$vyos_libexec_dir/vyos-interface-rescan.py $BOOTFILE
fi
}
cleanup_post_commit_hooks () {
# Remove links from the post-commit hooks directory.
# note that this approach only supports hooks that are "configured",
# i.e., it does not support hooks that need to always be present.
cpostdir=$(cli-shell-api getPostCommitHookDir)
# exclude commits hooks from vyatta-cfg
excluded="10vyatta-log-commit.pl 99vyos-user-postcommit-hooks"
if [ -d "$cpostdir" ]; then
for f in $cpostdir/*; do
if [[ ! $excluded =~ $(basename $f) ]]; then
rm -f $cpostdir/$(basename $f)
fi
done
fi
}
# These are all the default security setting which are later
# overridden when configuration is read. These are the values the
# system defaults.
security_reset ()
{
# restore NSS cofniguration back to sane system defaults
# will be overwritten later when configuration is loaded
cat </etc/nsswitch.conf
passwd: files
group: files
shadow: files
gshadow: files
# Per T2678, commenting out myhostname
hosts: files dns #myhostname
networks: files
protocols: db files
services: db files
ethers: db files
rpc: db files
netgroup: nis
EOF
# restore PAM back to virgin state (no radius/tacacs services)
pam-auth-update --package --remove radius
rm -f /etc/pam_radius_auth.conf
pam-auth-update --package --remove tacplus
rm -f /etc/tacplus_nss.conf /etc/tacplus_servers
# Certain configuration files are re-generated by the configuration
# subsystem and must reside under /etc and can not easily be moved to /run.
# So on every boot we simply delete any remaining files and let the CLI
# regenearte them.
# PPPoE
rm -f /etc/ppp/peers/pppoe* /etc/ppp/peers/wlm*
# IPSec
rm -rf /etc/ipsec.conf /etc/ipsec.secrets
find /etc/swanctl -type f | xargs rm -f
# limit cleanup
rm -f /etc/security/limits.d/10-vyos.conf
# iproute2 cleanup
rm -f /etc/iproute2/rt_tables.d/vyos-*.conf
# Container
rm -f /etc/containers/storage.conf /etc/containers/registries.conf /etc/containers/containers.conf
# Clean all networks and re-create them from our CLI
rm -f /etc/containers/networks/*
# System Options (SSH/cURL)
rm -f /etc/ssh/ssh_config.d/*vyos*.conf
rm -f /etc/curlrc
}
# XXX: T3885 - generate persistend DHCPv6 DUID (Type4 - UUID based)
gen_duid ()
{
DUID_FILE="/var/lib/dhcpv6/dhcp6c_duid"
UUID_FILE="/sys/class/dmi/id/product_uuid"
UUID_FILE_ALT="/sys/class/dmi/id/product_serial"
if [ ! -f ${UUID_FILE} ] && [ ! -f ${UUID_FILE_ALT} ]; then
return 1
fi
# DUID is based on the BIOS/EFI UUID. We omit additional - characters
if [ -f ${UUID_FILE} ]; then
UUID=$(cat ${UUID_FILE} | tr -d -)
fi
if [ -z ${UUID} ]; then
UUID=$(uuidgen --sha1 --namespace @dns --name $(cat ${UUID_FILE_ALT}) | tr -d -)
fi
# Add DUID type4 (UUID) information
DUID_TYPE="0004"
# The length-information (as per RFC6355 UUID is 128 bits long) is in big-endian
# format - beware when porting to ARM64. The length field consists out of the
# UUID (128 bit + 16 bits DUID type) resulting in hex 12.
DUID_LEN="0012"
if [ "$(echo -n I | od -to2 | head -n1 | cut -f2 -d" " | cut -c6 )" -eq 1 ]; then
# true on little-endian (x86) systems
DUID_LEN="1200"
fi
for i in $(echo -n ${DUID_LEN}${DUID_TYPE}${UUID} | sed 's/../& /g'); do
echo -ne "\x$i"
done > ${DUID_FILE}
}
start ()
{
# reset and clean config files
security_reset || log_failure_msg "security reset failed"
# some legacy directories migrated over from old rl-system.init
mkdir -p /var/run/vyatta /var/log/vyatta
chgrp vyattacfg /var/run/vyatta /var/log/vyatta
chmod 775 /var/run/vyatta /var/log/vyatta
log_daemon_msg "Waiting for NICs to settle down"
# On boot time udev migth take a long time to reorder nic's, this will ensure that
# all udev activity is completed and all nics presented at boot-time will have their
# final name before continuing with vyos-router initialization.
SECONDS=0
udevadm settle
STATUS=$?
log_progress_msg "settled in ${SECONDS}sec."
log_end_msg ${STATUS}
# mountpoint for bpf maps required by xdp
mount -t bpf none /sys/fs/bpf
# Clear out Debian APT source config file
empty /etc/apt/sources.list
# Generate DHCPv6 DUID
gen_duid || log_failure_msg "could not generate DUID"
# Mount a temporary filesystem for container networks.
# Configuration should be loaded from VyOS cli.
cni_dir="/etc/cni/net.d"
[ ! -d ${cni_dir} ] && mkdir -p ${cni_dir}
mount -t tmpfs none ${cni_dir}
# Init firewall
nfct helper add rpc inet tcp
nfct helper add rpc inet udp
nfct helper add tns inet tcp
nft -f /usr/share/vyos/vyos-firewall-init.conf || log_failure_msg "could not initiate firewall rules"
# As VyOS does not execute commands that are not present in the CLI we call
# the script by hand to have a single source for the login banner and MOTD
${vyos_conf_scripts_dir}/system_console.py || log_failure_msg "could not reset serial console"
${vyos_conf_scripts_dir}/system-login-banner.py || log_failure_msg "could not reset motd and issue files"
${vyos_conf_scripts_dir}/system-option.py || log_failure_msg "could not reset system option files"
${vyos_conf_scripts_dir}/system-ip.py || log_failure_msg "could not reset system IPv4 options"
${vyos_conf_scripts_dir}/system-ipv6.py || log_failure_msg "could not reset system IPv6 options"
${vyos_conf_scripts_dir}/conntrack.py || log_failure_msg "could not reset conntrack subsystem"
${vyos_conf_scripts_dir}/container.py || log_failure_msg "could not reset container subsystem"
clear_or_override_config_files || log_failure_msg "could not reset config files"
# enable some debugging before loading the configuration
if grep -q vyos-debug /proc/cmdline; then
log_action_begin_msg "Enable runtime debugging options"
touch /tmp/vyos.container.debug
touch /tmp/vyos.ifconfig.debug
touch /tmp/vyos.frr.debug
touch /tmp/vyos.container.debug
fi
log_action_begin_msg "Mounting VyOS Config"
# ensure the vyatta_configdir supports a large number of inodes since
# the config hierarchy is often inode-bound (instead of size).
# impose a minimum and then scale up dynamically with the actual size
# of the system memory.
local tmem=$(sed -n 's/^MemTotal: \+\([0-9]\+\) kB$/\1/p' /proc/meminfo)
local tpages
local tmpfs_opts="nosuid,nodev,mode=775,nr_inodes=0" #automatically allocate inodes
mount -o $tmpfs_opts -t tmpfs none ${vyatta_configdir} \
&& chgrp ${GROUP} ${vyatta_configdir}
log_action_end_msg $?
# T5239: early read of system hostname as this value is read-only once during
# FRR initialisation
tmp=$(${vyos_libexec_dir}/read-saved-value.py --path "system host-name")
hostnamectl set-hostname --static "$tmp"
${vyos_conf_scripts_dir}/system_frr.py || log_failure_msg "could not reset FRR config"
# If for any reason FRR was not started by system_frr.py - start it anyways.
# This is a safety net!
systemctl start frr.service
disabled bootfile || init_bootfile
cleanup_post_commit_hooks
log_daemon_msg "Starting VyOS router"
disabled migrate || migrate_bootfile
restore_if_missing_preconfig_script
run_preconfig_script
run_postupgrade_script
update_interface_config
for s in ${subinit[@]} ; do
if ! disabled $s; then
log_progress_msg $s
if ! ${vyatta_sbindir}/${s}.init start
then log_failure_msg
exit 1
fi
fi
done
bind_mount_boot
disabled configure || load_bootfile
log_end_msg $?
telinit q
chmod g-w,o-w /
restore_if_missing_postconfig_script
run_postconfig_scripts
}
stop()
{
local -i status=0
log_daemon_msg "Stopping VyOS router"
for ((i=${#sub_inits[@]} - 1; i >= 0; i--)) ; do
s=${subinit[$i]}
log_progress_msg $s
${vyatta_sbindir}/${s}.init stop
let status\|=$?
done
log_end_msg $status
log_action_begin_msg "Un-mounting VyOS Config"
umount ${vyatta_configdir}
log_action_end_msg $?
systemctl stop frr.service
}
case "$action" in
start) start ;;
stop) stop ;;
restart|force-reload) stop && start ;;
*) log_failure_msg "usage: $progname [ start|stop|restart ] [ subinit ... ]" ;
false ;;
esac
exit $?
# Local Variables:
# mode: shell-script
# sh-indentation: 4
# End: