From 753c537e52fa30287c9fd09a7fd3c8bc50622a55 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 11 Jan 2025 12:06:30 -0700 Subject: [PATCH 01/59] mount: allow [ro|rw|rq|sw|xx] as available mount options --- usr/local/share/bastille/mount.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index ba66ae8b..73d5d5e7 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -89,8 +89,8 @@ elif [ ! -e "${_hostpath}" ] || [ "${_type}" != "nullfs" ]; then usage fi -# Mount permissions,options need to start with "ro" or "rw" -if ! echo "${_perms}" | grep -Eq 'r[w|o],.*$'; then +# Mount permissions,options need to include at least on of "ro, rw, rq, sw, xx" +if ! echo "${_perms}" | grep -Eq '[ro|rw|rq|sw|xx]'; then error_notify "Detected invalid mount permissions in FSTAB." warn "Format: /host/path /jail/path nullfs ro 0 0" warn "Read: ${_fstab}" From fa4466eb7f479c79737760a282601cd0325faa0e Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 11 Jan 2025 12:07:59 -0700 Subject: [PATCH 02/59] mount: docs, allow all fs type options --- docs/chapters/subcommands/mount.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/chapters/subcommands/mount.rst b/docs/chapters/subcommands/mount.rst index cabe779c..dfbbd526 100644 --- a/docs/chapters/subcommands/mount.rst +++ b/docs/chapters/subcommands/mount.rst @@ -10,7 +10,7 @@ Syntax follows standard `/etc/fstab` format: Usage: bastille mount TARGET HOST_PATH JAIL_PATH [filesystem_type options dump pass_number] -The 'options' string can include a comma-separated list of mount options, but must start with 'ro' or 'rw'. +The 'options' string can include a comma-separated list of mount options, but must include at least one of (rw,ro,rq.sw,xx) according to fstab documentation. Example: Mount a tmpfs filesystem with options. .. code-block:: shell From f3123bf08de1a6982b3479c2bdae96e2e28d83dd Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 11 Jan 2025 12:08:24 -0700 Subject: [PATCH 03/59] mount: Docs, typo . > , --- docs/chapters/subcommands/mount.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/chapters/subcommands/mount.rst b/docs/chapters/subcommands/mount.rst index dfbbd526..a5fbc930 100644 --- a/docs/chapters/subcommands/mount.rst +++ b/docs/chapters/subcommands/mount.rst @@ -10,7 +10,7 @@ Syntax follows standard `/etc/fstab` format: Usage: bastille mount TARGET HOST_PATH JAIL_PATH [filesystem_type options dump pass_number] -The 'options' string can include a comma-separated list of mount options, but must include at least one of (rw,ro,rq.sw,xx) according to fstab documentation. +The 'options' string can include a comma-separated list of mount options, but must include at least one of (rw,ro,rq,sw,xx) according to fstab documentation. Example: Mount a tmpfs filesystem with options. .. code-block:: shell From e33dd04ad1c0f9d16b391361d4583177131679b2 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 11 Jan 2025 12:10:27 -0700 Subject: [PATCH 04/59] mount: Docs, one more typo "on > one" --- usr/local/share/bastille/mount.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index 73d5d5e7..c6bf5bf8 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -89,7 +89,7 @@ elif [ ! -e "${_hostpath}" ] || [ "${_type}" != "nullfs" ]; then usage fi -# Mount permissions,options need to include at least on of "ro, rw, rq, sw, xx" +# Mount permissions,options need to include at least one of "ro, rw, rq, sw, xx" if ! echo "${_perms}" | grep -Eq '[ro|rw|rq|sw|xx]'; then error_notify "Detected invalid mount permissions in FSTAB." warn "Format: /host/path /jail/path nullfs ro 0 0" From 10822931bbbe97afa3dab9939b1e136beae0356e Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 13 Jan 2025 13:19:26 -0700 Subject: [PATCH 05/59] create: Static MAC optional --- usr/local/share/bastille/create.sh | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/usr/local/share/bastille/create.sh b/usr/local/share/bastille/create.sh index 77169e8f..0f47f17c 100644 --- a/usr/local/share/bastille/create.sh +++ b/usr/local/share/bastille/create.sh @@ -41,12 +41,13 @@ usage() { cat << EOF Options: - -E | --empty -- Creates an empty container, intended for custom jail builds (thin/thick/linux or unsupported). - -L | --linux -- This option is intended for testing with Linux jails, this is considered experimental. - -T | --thick -- Creates a thick container, they consume more space as they are self contained and independent. - -V | --vnet -- Enables VNET, VNET containers are attached to a virtual bridge interface for connectivity. - -C | --clone -- Creates a clone container, they are duplicates of the base release, consume low space and preserves changing data. - -B | --bridge -- Enables VNET, VNET containers are attached to a specified, already existing external bridge. + -M | --static-mac -- Generate a static MAC address for jail (VNET only). + -E | --empty -- Creates an empty container, intended for custom jail builds (thin/thick/linux or unsupported). + -L | --linux -- This option is intended for testing with Linux jails, this is considered experimental. + -T | --thick -- Creates a thick container, they consume more space as they are self contained and independent. + -V | --vnet -- Enables VNET, VNET containers are attached to a virtual bridge interface for connectivity. + -C | --clone -- Creates a clone container, they are duplicates of the base release, consume low space and preserves changing data. + -B | --bridge -- Enables VNET, VNET containers are attached to a specified, already existing external bridge. EOF exit 1 @@ -229,7 +230,7 @@ generate_vnet_jail_conf() { else devfs_ruleset_value=13 fi - NETBLOCK=$(generate_vnet_jail_netblock "$NAME" "${VNET_JAIL_BRIDGE}" "${bastille_jail_conf_interface}") + NETBLOCK=$(generate_vnet_jail_netblock "$NAME" "${VNET_JAIL_BRIDGE}" "${bastille_jail_conf_interface}" "${STATIC_MAC}") cat << EOF > "${bastille_jail_conf}" ${NAME} { enforce_statfs = 2; @@ -630,10 +631,15 @@ THICK_JAIL="" CLONE_JAIL="" VNET_JAIL="" LINUX_JAIL="" +STATIC_MAC="" # Handle and parse options while [ $# -gt 0 ]; do case "${1}" in + -M|--static-mac) + STATIC_MAC="1" + shift + ;; -E|--empty) EMPTY_JAIL="1" shift From cd8461691f812dc20a95d4b115aad76bc37e2945 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 13 Jan 2025 13:23:08 -0700 Subject: [PATCH 06/59] common: Static MAC optional --- usr/local/share/bastille/common.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/usr/local/share/bastille/common.sh b/usr/local/share/bastille/common.sh index 4189f07b..2a737185 100644 --- a/usr/local/share/bastille/common.sh +++ b/usr/local/share/bastille/common.sh @@ -126,6 +126,7 @@ generate_vnet_jail_netblock() { local jail_name="$1" local use_unique_bridge="$2" local external_interface="$3" + local static_mac="${4}" generate_static_mac "${jail_name}" "${external_interface}" ## determine number of containers + 1 ## iterate num and grep all jail configs @@ -148,6 +149,7 @@ generate_vnet_jail_netblock() { local uniq_epair_bridge="0" fi if [ -n "${use_unique_bridge}" ]; then + if [ -n "${static_mac}" ]; then ## generate bridge config cat <<-EOF vnet; @@ -161,7 +163,20 @@ generate_vnet_jail_netblock() { exec.poststop += "ifconfig ${external_interface} deletem e${uniq_epair_bridge}a_${jail_name}"; exec.poststop += "ifconfig e${uniq_epair_bridge}a_${jail_name} destroy"; EOF + else + cat <<-EOF + vnet; + vnet.interface = e${uniq_epair_bridge}b_${jail_name}; + exec.prestart += "ifconfig epair${uniq_epair_bridge} create"; + exec.prestart += "ifconfig ${external_interface} addm epair${uniq_epair_bridge}a"; + exec.prestart += "ifconfig epair${uniq_epair_bridge}a up name e${uniq_epair_bridge}a_${jail_name}"; + exec.prestart += "ifconfig epair${uniq_epair_bridge}b up name e${uniq_epair_bridge}b_${jail_name}"; + exec.poststop += "ifconfig ${external_interface} deletem e${uniq_epair_bridge}a_${jail_name}"; + exec.poststop += "ifconfig e${uniq_epair_bridge}a_${jail_name} destroy"; +EOF + fi else + if [ -n "${static_mac}" ]; then ## generate config cat <<-EOF vnet; @@ -172,6 +187,15 @@ EOF exec.prestart += "ifconfig e0a_${uniq_epair} description \"vnet host interface for Bastille jail ${jail_name}\""; exec.poststop += "jib destroy ${uniq_epair}"; EOF + else + cat <<-EOF + vnet; + vnet.interface = e0b_${uniq_epair}; + exec.prestart += "jib addm ${uniq_epair} ${external_interface}"; + exec.prestart += "ifconfig e0a_${uniq_epair} description \"vnet host interface for Bastille jail ${jail_name}\""; + exec.poststop += "jib destroy ${uniq_epair}"; +EOF + fi fi } From 131c89c6f83c928c486fc1c2df90fb31d5127fdc Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 13 Jan 2025 13:25:54 -0700 Subject: [PATCH 07/59] clone: Static MAC optional --- usr/local/share/bastille/clone.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/usr/local/share/bastille/clone.sh b/usr/local/share/bastille/clone.sh index 9dae7f44..c913db56 100644 --- a/usr/local/share/bastille/clone.sh +++ b/usr/local/share/bastille/clone.sh @@ -118,9 +118,13 @@ update_jailconf_vnet() { local uniq_epair_bridge="${_num}" # since we don't have access to the external_interface variable, we cat the jail.conf file to retrieve the mac prefix # we also do not use the main generate_static_mac function here - local macaddr_prefix="$(cat ${JAIL_CONFIG} | grep -m 1 ether | grep -oE '([0-9a-f]{2}(:[0-9a-f]{2}){5})' | awk -F: '{print $1":"$2":"$3}')" - local macaddr_suffix="$(echo -n ${NEWNAME} | sha256 | cut -b -5 | sed 's/\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F]\)/\1:\2:\3/')" - local macaddr="${macaddr_prefix}:${macaddr_suffix}" + if grep -oq ether ${JAIL_CONFIG}; then + local macaddr_prefix="$(cat ${JAIL_CONFIG} | grep -m 1 ether | grep -oE '([0-9a-f]{2}(:[0-9a-f]{2}){5})' | awk -F: '{print $1":"$2":"$3}')" + local macaddr_suffix="$(echo -n ${NEWNAME} | sha256 | cut -b -5 | sed 's/\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F]\)/\1:\2:\3/')" + local macaddr="${macaddr_prefix}:${macaddr_suffix}" + sed -i '' "s|ether.*:.*:.*:.*:.*:.*a\";|ether ${macaddr}a\";|" "${JAIL_CONFIG}" + sed -i '' "s|ether.*:.*:.*:.*:.*:.*b\";|ether ${macaddr}b\";|" "${JAIL_CONFIG}" + fi # Update the exec.* with uniq_epair when cloning jails. # for VNET jails sed -i '' "s|bastille\([0-9]\{1,\}\)|${uniq_epair}|g" "${JAIL_CONFIG}" @@ -128,8 +132,6 @@ update_jailconf_vnet() { sed -i '' "s|e\([0-9]\{1,\}\)b_${NEWNAME}|e${uniq_epair_bridge}b_${NEWNAME}|g" "${JAIL_CONFIG}" sed -i '' "s|epair\([0-9]\{1,\}\)|epair${uniq_epair_bridge}|g" "${JAIL_CONFIG}" sed -i '' "s|exec.prestart += \"ifconfig e0a_bastille\([0-9]\{1,\}\).*description.*|exec.prestart += \"ifconfig e0a_${uniq_epair} description \\\\\"vnet host interface for Bastille jail ${NEWNAME}\\\\\"\";|" "${JAIL_CONFIG}" - sed -i '' "s|ether.*:.*:.*:.*:.*:.*a\";|ether ${macaddr}a\";|" "${JAIL_CONFIG}" - sed -i '' "s|ether.*:.*:.*:.*:.*:.*b\";|ether ${macaddr}b\";|" "${JAIL_CONFIG}" break fi fi From 5345c2a59985e9650404827995533686465f9b98 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 13 Jan 2025 13:59:55 -0700 Subject: [PATCH 08/59] common: MAC now follows host prefix, and hashes jail+hostMAC for suffix --- usr/local/share/bastille/common.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usr/local/share/bastille/common.sh b/usr/local/share/bastille/common.sh index 2a737185..afe07a5f 100644 --- a/usr/local/share/bastille/common.sh +++ b/usr/local/share/bastille/common.sh @@ -113,8 +113,8 @@ generate_static_mac() { local jail_name="${1}" local external_interface="${2}" local external_interface_mac="$(ifconfig ${external_interface} | grep ether | awk '{print $2}' | sed 's#:##g')" - local macaddr_prefix="$(echo -n "${external_interface_mac}" | sha256 | cut -b -6 | sed 's/\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F]\)/\1:\2:\3/')" - local macaddr_suffix="$(echo -n "${jail_name}" | sha256 | cut -b -5 | sed 's/\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F]\)/\1:\2:\3/')" + local macaddr_prefix="$(echo ${external_interface_mac} | cut -d':' -f1-3)" + local macaddr_suffix="$(echo -n "${external_interface_mac}${jail_name}" | sed 's#:##g' | sha256 | cut -b -5 | sed 's/\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F]\)/\1:\2:\3/')" if [ -z "${macaddr_prefix}" ] || [ -z "${macaddr_suffix}" ]; then error_notify "Failed to generate MAC address." fi From c9bb5132c03cea38bc58f70b7a1dc8d3a232a70c Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 13 Jan 2025 15:58:56 -0700 Subject: [PATCH 09/59] common: do not trim : from MAC too early --- usr/local/share/bastille/common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/local/share/bastille/common.sh b/usr/local/share/bastille/common.sh index afe07a5f..2b7ea6af 100644 --- a/usr/local/share/bastille/common.sh +++ b/usr/local/share/bastille/common.sh @@ -112,7 +112,7 @@ check_target_is_stopped() { generate_static_mac() { local jail_name="${1}" local external_interface="${2}" - local external_interface_mac="$(ifconfig ${external_interface} | grep ether | awk '{print $2}' | sed 's#:##g')" + local external_interface_mac="$(ifconfig ${external_interface} | grep ether | awk '{print $2}')" local macaddr_prefix="$(echo ${external_interface_mac} | cut -d':' -f1-3)" local macaddr_suffix="$(echo -n "${external_interface_mac}${jail_name}" | sed 's#:##g' | sha256 | cut -b -5 | sed 's/\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F]\)/\1:\2:\3/')" if [ -z "${macaddr_prefix}" ] || [ -z "${macaddr_suffix}" ]; then From d9ef63bc60e8fd4a4be4d77a0cf2ddfaac4a98d0 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 13 Jan 2025 16:03:30 -0700 Subject: [PATCH 10/59] clone: update "update_jail_conf_vnet" function for optional static MAC --- usr/local/share/bastille/clone.sh | 101 +++++++++++++++++++----------- 1 file changed, 65 insertions(+), 36 deletions(-) diff --git a/usr/local/share/bastille/clone.sh b/usr/local/share/bastille/clone.sh index c913db56..4b01ec10 100644 --- a/usr/local/share/bastille/clone.sh +++ b/usr/local/share/bastille/clone.sh @@ -105,51 +105,80 @@ update_jailconf() { update_jailconf_vnet() { bastille_jail_rc_conf="${bastille_jailsdir}/${NEWNAME}/root/etc/rc.conf" - - # Determine number of containers and define an uniq_epair - local list_jails_num="$(bastille list jails | wc -l | awk '{print $1}')" - local num_range="$(expr "${list_jails_num}" + 1)" - jail_list=$(bastille list jail) - for _num in $(seq 0 "${num_range}"); do - if [ -n "${jail_list}" ]; then - if ! grep -q "e0b_bastille${_num}" "${bastille_jailsdir}"/*/jail.conf; then - if ! grep -q "epair${_num}" "${bastille_jailsdir}"/*/jail.conf; then - local uniq_epair="bastille${_num}" + # Determine number of interfaces and define a uniq_epair + local _if_list="$(grep -Eo 'epair[0-9]+|bastille[0-9]+' ${JAIL_CONFIG} | sort -u)" + for _if in ${_if_list}; do + local _epair_if_count="$(grep -Eo 'epair[0-9]+' ${bastille_jailsdir}/*/jail.conf | sort -u | wc -l | awk '{print $1}')" + local _bastille_if_count="$(grep -Eo 'bastille[0-9]+' ${bastille_jailsdir}/*/jail.conf | sort -u | wc -l | awk '{print $1}')" + local epair_num_range=$((_epair_if_count + 1)) + local bastille_num_range=$((_bastille_if_count + 1)) + if echo ${_if} | grep -Eoq 'epair[0-9]+'; then + # Update bridged VNET config + for _num in $(seq 0 "${epair_num_range}"); do + if ! grep -oq "epair${_num}" ${bastille_jailsdir}/*/jail.conf; then + # Update jail.conf epair name local uniq_epair_bridge="${_num}" - # since we don't have access to the external_interface variable, we cat the jail.conf file to retrieve the mac prefix - # we also do not use the main generate_static_mac function here + local _if_epaira="${_if}a" + local _if_epairb="${_if}b" + local _if_vnet="$(grep ${_if_epairb} "${bastille_jail_rc_conf}" | grep -Eo -m 1 "vnet[0-9]+")" + sed -i '' "s|${_if}|epair${uniq_epair_bridge}|g" "${JAIL_CONFIG}" + # If jail had a static MAC, generate one for clone if grep -oq ether ${JAIL_CONFIG}; then - local macaddr_prefix="$(cat ${JAIL_CONFIG} | grep -m 1 ether | grep -oE '([0-9a-f]{2}(:[0-9a-f]{2}){5})' | awk -F: '{print $1":"$2":"$3}')" - local macaddr_suffix="$(echo -n ${NEWNAME} | sha256 | cut -b -5 | sed 's/\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F]\)/\1:\2:\3/')" - local macaddr="${macaddr_prefix}:${macaddr_suffix}" - sed -i '' "s|ether.*:.*:.*:.*:.*:.*a\";|ether ${macaddr}a\";|" "${JAIL_CONFIG}" - sed -i '' "s|ether.*:.*:.*:.*:.*:.*b\";|ether ${macaddr}b\";|" "${JAIL_CONFIG}" + local external_interface="$(grep "epair${uniq_epair_bridge}" ${JAIL_CONFIG} | grep -o '[^ ]* addm' | awk '{print $1}')" + generate_static_mac "${NEWNAME}" "${external_interface}" + sed -i '' "s|epair${uniq_epair_bridge}a ether.*:.*:.*:.*:.*:.*a\";|epair${uniq_epair}a ether ${macaddr}a\";|" "${JAIL_CONFIG}" + sed -i '' "s|epair${uniq_epair_bridge}b ether.*:.*:.*:.*:.*:.*b\";|epair${uniq_epair}b ether ${macaddr}b\";|" "${JAIL_CONFIG}" + fi + sed -i '' "s|vnet host interface for Bastille jail ${TARGET}|vnet host interface for Bastille jail ${NEWNAME}|g" "${JAIL_CONFIG}" + # Update /etc/rc.conf + sed -i '' "s|${_if_epairb}_name|epair${uniq_epair_bridge}b_name|" "${bastille_jail_rc_conf}" + if grep "vnet0" "${bastille_jail_rc_conf}" | grep -q "epair${uniq_epair_bridge}b_name"; then + if [ "${IP}" = "0.0.0.0" ]; then + sysrc -f "${bastille_jail_rc_conf}" ifconfig_vnet0="SYNCDHCP" + else + sysrc -f "${bastille_jail_rc_conf}" ifconfig_vnet0="inet ${IP}" + fi + else + sysrc -f "${bastille_jail_rc_conf}" ifconfig_${_if_vnet}="SYNCDHCP" fi - # Update the exec.* with uniq_epair when cloning jails. - # for VNET jails - sed -i '' "s|bastille\([0-9]\{1,\}\)|${uniq_epair}|g" "${JAIL_CONFIG}" - sed -i '' "s|e\([0-9]\{1,\}\)a_${NEWNAME}|e${uniq_epair_bridge}a_${NEWNAME}|g" "${JAIL_CONFIG}" - sed -i '' "s|e\([0-9]\{1,\}\)b_${NEWNAME}|e${uniq_epair_bridge}b_${NEWNAME}|g" "${JAIL_CONFIG}" - sed -i '' "s|epair\([0-9]\{1,\}\)|epair${uniq_epair_bridge}|g" "${JAIL_CONFIG}" - sed -i '' "s|exec.prestart += \"ifconfig e0a_bastille\([0-9]\{1,\}\).*description.*|exec.prestart += \"ifconfig e0a_${uniq_epair} description \\\\\"vnet host interface for Bastille jail ${NEWNAME}\\\\\"\";|" "${JAIL_CONFIG}" break fi - fi + done + elif echo ${_if} | grep -Eoq 'bastille[0-9]+'; then + # Update VNET config + for _num in $(seq 0 "${bastille_num_range}"); do + if ! grep -oq "bastille${_num}" ${bastille_jailsdir}/*/jail.conf; then + # Update jail.conf epair name + local uniq_epair="bastille${_num}" + local _if_vnet="$(grep ${_if} "${bastille_jail_rc_conf}" | grep -Eo -m 1 "vnet[0-9]+")" + sed -i '' "s|${_if}|${uniq_epair}|g" "${JAIL_CONFIG}" + # If jail had a static MAC, generate one for clone + if grep -oq ether ${JAIL_CONFIG}; then + local external_interface="$(grep ${uniq_epair} ${JAIL_CONFIG} | grep -o 'addm.*' | awk '{print $3}' | sed 's/["|;]//g')" + generate_static_mac "${NEWNAME}" "${external_interface}" + sed -i '' "s|${uniq_epair} ether.*:.*:.*:.*:.*:.*a\";|${uniq_epair} ether ${macaddr}a\";|" "${JAIL_CONFIG}" + sed -i '' "s|${uniq_epair} ether.*:.*:.*:.*:.*:.*b\";|${uniq_epair} ether ${macaddr}b\";|" "${JAIL_CONFIG}" + fi + sed -i '' "s|vnet host interface for Bastille jail ${TARGET}|vnet host interface for Bastille jail ${NEWNAME}|g" "${JAIL_CONFIG}" + # Update /etc/rc.conf + sed -i '' "s|ifconfig_e0b_${_if}_name|ifconfig_e0b_${uniq_epair}_name|" "${bastille_jail_rc_conf}" + if grep "vnet0" "${bastille_jail_rc_conf}" | grep -q ${uniq_epair}; then + if [ "${IP}" = "0.0.0.0" ]; then + sysrc -f "${bastille_jail_rc_conf}" ifconfig_vnet0="SYNCDHCP" + else + sysrc -f "${bastille_jail_rc_conf}" ifconfig_vnet0=" inet ${IP} " + fi + else + sysrc -f "${bastille_jail_rc_conf}" ifconfig_${_if_vnet}="SYNCDHCP" + fi + break + fi + done fi done - - # Rename interface to new uniq_epair - sed -i '' "s|ifconfig_e0b_bastille.*_name|ifconfig_e0b_${uniq_epair}_name|" "${bastille_jail_rc_conf}" - sed -i '' "s|ifconfig_e.*b_${TARGET}_name|ifconfig_e${uniq_epair_bridge}b_${NEWNAME}_name|" "${bastille_jail_rc_conf}" - - # If 0.0.0.0 set DHCP, else set static IP address - if [ "${IP}" = "0.0.0.0" ]; then - sysrc -f "${bastille_jail_rc_conf}" ifconfig_vnet0="SYNCDHCP" - else - sysrc -f "${bastille_jail_rc_conf}" ifconfig_vnet0="inet ${IP}" - fi } + update_fstab() { # Update fstab to use the new name FSTAB_CONFIG="${bastille_jailsdir}/${NEWNAME}/fstab" From e36d1c2881d0ccc608e9c0092da214124c0966e3 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 13 Jan 2025 17:19:03 -0700 Subject: [PATCH 11/59] clone: fix mac not applying on bridge --- usr/local/share/bastille/clone.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/usr/local/share/bastille/clone.sh b/usr/local/share/bastille/clone.sh index 4b01ec10..428bf9c8 100644 --- a/usr/local/share/bastille/clone.sh +++ b/usr/local/share/bastille/clone.sh @@ -123,11 +123,11 @@ update_jailconf_vnet() { local _if_vnet="$(grep ${_if_epairb} "${bastille_jail_rc_conf}" | grep -Eo -m 1 "vnet[0-9]+")" sed -i '' "s|${_if}|epair${uniq_epair_bridge}|g" "${JAIL_CONFIG}" # If jail had a static MAC, generate one for clone - if grep -oq ether ${JAIL_CONFIG}; then + if grep ether ${JAIL_CONFIG} | grep -qoc epair${uniq_epair_bridge}; then local external_interface="$(grep "epair${uniq_epair_bridge}" ${JAIL_CONFIG} | grep -o '[^ ]* addm' | awk '{print $1}')" generate_static_mac "${NEWNAME}" "${external_interface}" - sed -i '' "s|epair${uniq_epair_bridge}a ether.*:.*:.*:.*:.*:.*a\";|epair${uniq_epair}a ether ${macaddr}a\";|" "${JAIL_CONFIG}" - sed -i '' "s|epair${uniq_epair_bridge}b ether.*:.*:.*:.*:.*:.*b\";|epair${uniq_epair}b ether ${macaddr}b\";|" "${JAIL_CONFIG}" + sed -i '' "s|epair${uniq_epair_bridge}a ether.*:.*:.*:.*:.*:.*a\";|epair${uniq_epair_bridge}a ether ${macaddr}a\";|" "${JAIL_CONFIG}" + sed -i '' "s|epair${uniq_epair_bridge}b ether.*:.*:.*:.*:.*:.*b\";|epair${uniq_epair_bridge}b ether ${macaddr}b\";|" "${JAIL_CONFIG}" fi sed -i '' "s|vnet host interface for Bastille jail ${TARGET}|vnet host interface for Bastille jail ${NEWNAME}|g" "${JAIL_CONFIG}" # Update /etc/rc.conf @@ -153,7 +153,7 @@ update_jailconf_vnet() { local _if_vnet="$(grep ${_if} "${bastille_jail_rc_conf}" | grep -Eo -m 1 "vnet[0-9]+")" sed -i '' "s|${_if}|${uniq_epair}|g" "${JAIL_CONFIG}" # If jail had a static MAC, generate one for clone - if grep -oq ether ${JAIL_CONFIG}; then + if grep ether ${JAIL_CONFIG} | grep -qoc ${uniq_epair}; then local external_interface="$(grep ${uniq_epair} ${JAIL_CONFIG} | grep -o 'addm.*' | awk '{print $3}' | sed 's/["|;]//g')" generate_static_mac "${NEWNAME}" "${external_interface}" sed -i '' "s|${uniq_epair} ether.*:.*:.*:.*:.*:.*a\";|${uniq_epair} ether ${macaddr}a\";|" "${JAIL_CONFIG}" @@ -178,7 +178,6 @@ update_jailconf_vnet() { done } - update_fstab() { # Update fstab to use the new name FSTAB_CONFIG="${bastille_jailsdir}/${NEWNAME}/fstab" From 57a652cc70338bd0c2ecca03812154e94d9605da Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 13 Jan 2025 17:44:30 -0700 Subject: [PATCH 12/59] common: update function to use "epairx" because of name limit in FreeBSD --- usr/local/share/bastille/common.sh | 82 +++++++++++++++++------------- 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/usr/local/share/bastille/common.sh b/usr/local/share/bastille/common.sh index 2b7ea6af..a7b5ed0a 100644 --- a/usr/local/share/bastille/common.sh +++ b/usr/local/share/bastille/common.sh @@ -123,62 +123,73 @@ generate_static_mac() { } generate_vnet_jail_netblock() { - local jail_name="$1" - local use_unique_bridge="$2" - local external_interface="$3" + local jail_name="${1}" + local use_unique_bridge="${2}" + local external_interface="${3}" local static_mac="${4}" - generate_static_mac "${jail_name}" "${external_interface}" - ## determine number of containers + 1 + ## determine number of interfaces + 1 ## iterate num and grep all jail configs ## define uniq_epair - local jail_list="$(bastille list jails)" - if [ -n "${jail_list}" ]; then - local list_jails_num="$(echo "${jail_list}" | wc -l | awk '{print $1}')" - local num_range=$((list_jails_num + 1)) - for _num in $(seq 0 "${num_range}"); do - if ! grep -q "e[0-9]b_bastille${_num}" "${bastille_jailsdir}"/*/jail.conf; then - if ! grep -q "epair${_num}" "${bastille_jailsdir}"/*/jail.conf; then - local uniq_epair="bastille${_num}" + local _epair_if_count="$(grep -Eos 'epair[0-9]+' ${bastille_jailsdir}/*/jail.conf | sort -u | wc -l | awk '{print $1}')" + local _bastille_if_count="$(grep -Eos 'bastille[0-9]+' ${bastille_jailsdir}/*/jail.conf | sort -u | wc -l | awk '{print $1}')" + local epair_num_range=$((_epair_if_count + 1)) + local bastille_num_range=$((_bastille_if_count + 1)) + if [ -n "${use_unique_bridge}" ]; then + if [ "${_epair_if_count}" -gt 0 ]; then + for _num in $(seq 0 "${epair_num_range}"); do + if ! grep -Eosq "epair${_num}" ${bastille_jailsdir}/*/jail.conf; then local uniq_epair_bridge="${_num}" break fi - fi - done + done + else + local uniq_epair_bridge="0" + fi else - local uniq_epair="bastille0" - local uniq_epair_bridge="0" + if [ "${_bastille_if_count}" -gt 0 ]; then + for _num in $(seq 0 "${bastille_num_range}"); do + if ! grep -Eosq "bastille${_num}" ${bastille_jailsdir}/*/jail.conf; then + local uniq_epair="bastille${_num}" + break + fi + done + else + local uniq_epair="bastille0" + fi fi + ## If BRIDGE is enabled, generate bridge config, else generate VNET config if [ -n "${use_unique_bridge}" ]; then if [ -n "${static_mac}" ]; then - ## generate bridge config - cat <<-EOF + ## Generate bridged VNET config with static MAC address + generate_static_mac "${jail_name}" "${external_interface}" + cat <<-EOF vnet; - vnet.interface = e${uniq_epair_bridge}b_${jail_name}; + vnet.interface = epair${uniq_epair_bridge}b; exec.prestart += "ifconfig epair${uniq_epair_bridge} create"; exec.prestart += "ifconfig ${external_interface} addm epair${uniq_epair_bridge}a"; - exec.prestart += "ifconfig epair${uniq_epair_bridge}a up name e${uniq_epair_bridge}a_${jail_name}"; - exec.prestart += "ifconfig epair${uniq_epair_bridge}b up name e${uniq_epair_bridge}b_${jail_name}"; - exec.prestart += "ifconfig e${uniq_epair_bridge}a_${jail_name} ether ${macaddr}a"; - exec.prestart += "ifconfig e${uniq_epair_bridge}b_${jail_name} ether ${macaddr}b"; - exec.poststop += "ifconfig ${external_interface} deletem e${uniq_epair_bridge}a_${jail_name}"; - exec.poststop += "ifconfig e${uniq_epair_bridge}a_${jail_name} destroy"; + exec.prestart += "ifconfig epair${uniq_epair_bridge}a ether ${macaddr}a"; + exec.prestart += "ifconfig epair${uniq_epair_bridge}b ether ${macaddr}b"; + exec.prestart += "ifconfig epair${uniq_epair_bridge}a description \"vnet host interface for Bastille jail ${jail_name}\""; + exec.poststop += "ifconfig ${external_interface} deletem epair${uniq_epair_bridge}a"; + exec.poststop += "ifconfig epair${uniq_epair_bridge}a destroy"; EOF else - cat <<-EOF + ## Generate bridged VNET config without static MAC address + cat <<-EOF vnet; - vnet.interface = e${uniq_epair_bridge}b_${jail_name}; + vnet.interface = epair${uniq_epair_bridge}b; exec.prestart += "ifconfig epair${uniq_epair_bridge} create"; exec.prestart += "ifconfig ${external_interface} addm epair${uniq_epair_bridge}a"; - exec.prestart += "ifconfig epair${uniq_epair_bridge}a up name e${uniq_epair_bridge}a_${jail_name}"; - exec.prestart += "ifconfig epair${uniq_epair_bridge}b up name e${uniq_epair_bridge}b_${jail_name}"; - exec.poststop += "ifconfig ${external_interface} deletem e${uniq_epair_bridge}a_${jail_name}"; - exec.poststop += "ifconfig e${uniq_epair_bridge}a_${jail_name} destroy"; + exec.prestart += "ifconfig epair${uniq_epair_bridge}a description \"vnet host interface for Bastille jail ${jail_name}\""; + exec.poststop += "ifconfig ${external_interface} deletem epair${uniq_epair_bridge}a"; + exec.poststop += "ifconfig epair${uniq_epair_bridge}a destroy"; EOF fi else if [ -n "${static_mac}" ]; then - ## generate config - cat <<-EOF + ## Generate VNET config with static MAC address + generate_static_mac "${jail_name}" "${external_interface}" + cat <<-EOF vnet; vnet.interface = e0b_${uniq_epair}; exec.prestart += "jib addm ${uniq_epair} ${external_interface}"; @@ -188,7 +199,8 @@ EOF exec.poststop += "jib destroy ${uniq_epair}"; EOF else - cat <<-EOF + ## Generate VNET config without static MAC address + cat <<-EOF vnet; vnet.interface = e0b_${uniq_epair}; exec.prestart += "jib addm ${uniq_epair} ${external_interface}"; From b1a3306cef06eb32f785be7ef1d057f4909e2804 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Tue, 14 Jan 2025 07:33:43 -0700 Subject: [PATCH 13/59] common: use FreeBSD prefix for static MAC --- usr/local/share/bastille/common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/local/share/bastille/common.sh b/usr/local/share/bastille/common.sh index a7b5ed0a..a71b4182 100644 --- a/usr/local/share/bastille/common.sh +++ b/usr/local/share/bastille/common.sh @@ -113,7 +113,7 @@ generate_static_mac() { local jail_name="${1}" local external_interface="${2}" local external_interface_mac="$(ifconfig ${external_interface} | grep ether | awk '{print $2}')" - local macaddr_prefix="$(echo ${external_interface_mac} | cut -d':' -f1-3)" + local macaddr_prefix="58:9c:fc" local macaddr_suffix="$(echo -n "${external_interface_mac}${jail_name}" | sed 's#:##g' | sha256 | cut -b -5 | sed 's/\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F]\)/\1:\2:\3/')" if [ -z "${macaddr_prefix}" ] || [ -z "${macaddr_suffix}" ]; then error_notify "Failed to generate MAC address." From 9420441a566dd480aac3f80ca5c461017c378e2a Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Tue, 14 Jan 2025 10:54:28 -0700 Subject: [PATCH 14/59] common: Add comments about static MAC --- usr/local/share/bastille/common.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/usr/local/share/bastille/common.sh b/usr/local/share/bastille/common.sh index a71b4182..973a37ca 100644 --- a/usr/local/share/bastille/common.sh +++ b/usr/local/share/bastille/common.sh @@ -113,7 +113,9 @@ generate_static_mac() { local jail_name="${1}" local external_interface="${2}" local external_interface_mac="$(ifconfig ${external_interface} | grep ether | awk '{print $2}')" + # Use the FreeBSD vendor MAC prefix for jail MAC prefix "58:9c:fc" local macaddr_prefix="58:9c:fc" + # Hash interface+jailname for jail MAC suffix local macaddr_suffix="$(echo -n "${external_interface_mac}${jail_name}" | sed 's#:##g' | sha256 | cut -b -5 | sed 's/\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F]\)/\1:\2:\3/')" if [ -z "${macaddr_prefix}" ] || [ -z "${macaddr_suffix}" ]; then error_notify "Failed to generate MAC address." From b22d68db13eb4653dd01228ecda0ae5b70a439c2 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Tue, 14 Jan 2025 11:24:10 -0700 Subject: [PATCH 15/59] update: set -d and -f for release updates and think jail updates --- usr/local/share/bastille/update.sh | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/usr/local/share/bastille/update.sh b/usr/local/share/bastille/update.sh index 85d632c0..8ee766fc 100644 --- a/usr/local/share/bastille/update.sh +++ b/usr/local/share/bastille/update.sh @@ -96,6 +96,9 @@ jail_check() { } jail_update() { + local _freebsd_update_conf="${bastille_jailsdir}/${TARGET}/root/etc/freebsd-update.conf" + local _jail_dir="${bastille_jailsdir}/${TARGET}/root" + local _workdir="${bastille_releasesdir}/${TARGET}/root/var/db/freebsd-update" # Update a thick container if [ -d "${bastille_jailsdir}/${TARGET}" ]; then jail_check @@ -103,7 +106,9 @@ jail_update() { if [ -z "${CURRENT_VERSION}" ]; then error_exit "Can't determine '${TARGET}' version." else - env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_jailsdir}/${TARGET}/root" \ + env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${_jail_dir}" \ + -d "${_workdir}" \ + -f "${_freebsd_update_conf}" \ fetch install --currently-running "${CURRENT_VERSION}" fi else @@ -112,6 +117,9 @@ jail_update() { } release_update() { + local _freebsd_update_conf="${bastille_releasesdir}/${TARGET}/etc/freebsd-update.conf" + local _release_dir="${bastille_releasesdir}/${TARGET}" + local _workdir="${bastille_releasesdir}/${TARGET}/var/db/freebsd-update" # Update a release base(affects child containers) if [ -d "${bastille_releasesdir}/${TARGET}" ]; then TARGET_TRIM="${TARGET}" @@ -120,8 +128,12 @@ release_update() { fi env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_releasesdir}/${TARGET}" \ + -d "${_workdir}" \ + -f "${_freebsd_update_conf}" \ fetch --currently-running "${TARGET_TRIM}" env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_releasesdir}/${TARGET}" \ + -d "${_workdir}" \ + -f "${_freebsd_update_conf}" \ install --currently-running "${TARGET_TRIM}" else error_exit "${TARGET} not found. See 'bastille bootstrap'." From 2f7120a176355045e37e76784c5f8789c33dd0b4 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Tue, 14 Jan 2025 13:02:02 -0700 Subject: [PATCH 16/59] update: add debug, code cleanup --- usr/local/share/bastille/update.sh | 113 +++++++++++++++++------------ 1 file changed, 68 insertions(+), 45 deletions(-) diff --git a/usr/local/share/bastille/update.sh b/usr/local/share/bastille/update.sh index 8ee766fc..f2ab3c61 100644 --- a/usr/local/share/bastille/update.sh +++ b/usr/local/share/bastille/update.sh @@ -34,39 +34,62 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille update [release|container|template] | [force]" -} + error_notify "Usage: bastille update [option(s)] TARGET" + cat << EOF + Options: -# Handle special-case commands first. -case "$1" in -help|-h|--help) - usage - ;; -esac + -a | --auto Auto mode. Start/stop jail(s) if required. + -f | --force Force update a release. + -x | --debug Enable debug mode. + +EOF + exit 1 +} if [ $# -gt 2 ] || [ $# -lt 1 ]; then usage fi -bastille_root_check +# Handle options. +OPTION="" +AUTO=0 +while [ "$#" -gt 0 ]; do + case "${1}" in + -h|--help|help) + usage + ;; + -a|--auto) + AUTO=1 + shift + ;; + -f|--force) + OPTION="-F" + shift + ;; + -x|--debug) + enable_debug + shift + ;; + -*) + for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do + case ${_opt} in + a) AUTO=1 ;; + f) OPTION="-F" ;; + x) enable_debug ;; + *) error_exit "Unknown Option: \"${1}\"" ;; + esac + done + shift + ;; + *) + break + ;; + esac +done TARGET="${1}" -OPTION="${2}" -# Handle options -case "${OPTION}" in - -f|--force) - OPTION="-F" - ;; - *) - OPTION= - ;; -esac - -# Check for unsupported actions -if [ "${TARGET}" = "ALL" ]; then - error_exit "Batch upgrade is unsupported." -fi +bastille_root_check if [ -f "/bin/midnightbsd-version" ]; then echo -e "${COLOR_RED}Not yet supported on MidnightBSD.${COLOR_RESET}" @@ -86,22 +109,25 @@ arch_check() { jail_check() { # Check if the jail is thick and is running - if [ ! "$(/usr/sbin/jls name | awk "/^${TARGET}$/")" ]; then - error_exit "[${TARGET}]: Not started. See 'bastille start ${TARGET}'." - else - if grep -qw "${bastille_jailsdir}/${TARGET}/root/.bastille" "${bastille_jailsdir}/${TARGET}/fstab"; then - error_exit "${TARGET} is not a thick container." - fi + set_target_single "${TARGET}" + check_target_is_running "${TARGET}" || if [ "${AUTO}" -eq 1 ]; then + bastille start "${TARGET}" + else + error_notify "Jail is not running." + error_continue "Use [-a|--auto] to auto-start the jail." + fi + if grep -qw "${bastille_jailsdir}/${TARGET}/root/.bastille" "${bastille_jailsdir}/${TARGET}/fstab"; then + error_notify "${TARGET} is not a thick container." + error_exit "See 'bastille update RELEASE' to update thin jails." fi } jail_update() { local _freebsd_update_conf="${bastille_jailsdir}/${TARGET}/root/etc/freebsd-update.conf" local _jail_dir="${bastille_jailsdir}/${TARGET}/root" - local _workdir="${bastille_releasesdir}/${TARGET}/root/var/db/freebsd-update" + local _workdir="${bastille_jailsdir}/${TARGET}/root/var/db/freebsd-update" # Update a thick container - if [ -d "${bastille_jailsdir}/${TARGET}" ]; then - jail_check + if [ -d "${bastille_jailsdir}/${TARGET}" ]; then CURRENT_VERSION=$(/usr/sbin/jexec -l "${TARGET}" freebsd-version 2>/dev/null) if [ -z "${CURRENT_VERSION}" ]; then error_exit "Can't determine '${TARGET}' version." @@ -111,32 +137,28 @@ jail_update() { -f "${_freebsd_update_conf}" \ fetch install --currently-running "${CURRENT_VERSION}" fi - else - error_exit "${TARGET} not found. See 'bastille bootstrap'." fi } release_update() { local _freebsd_update_conf="${bastille_releasesdir}/${TARGET}/etc/freebsd-update.conf" local _release_dir="${bastille_releasesdir}/${TARGET}" - local _workdir="${bastille_releasesdir}/${TARGET}/var/db/freebsd-update" # Update a release base(affects child containers) - if [ -d "${bastille_releasesdir}/${TARGET}" ]; then + if [ -d "${_release_dir}" ]; then TARGET_TRIM="${TARGET}" if [ -n "${ARCH_I386}" ]; then TARGET_TRIM=$(echo "${TARGET}" | sed 's/-i386//') fi - env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_releasesdir}/${TARGET}" \ - -d "${_workdir}" \ + -d "${bastille_releasesdir}/${TARGET}/var/db/freebsd-update" \ -f "${_freebsd_update_conf}" \ fetch --currently-running "${TARGET_TRIM}" env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_releasesdir}/${TARGET}" \ - -d "${_workdir}" \ + -d "${bastille_releasesdir}/${TARGET}/var/db/freebsd-update" \ -f "${_freebsd_update_conf}" \ install --currently-running "${TARGET_TRIM}" else - error_exit "${TARGET} not found. See 'bastille bootstrap'." + error_exit "${TARGET} not found. See 'bastille bootstrap RELEASE'." fi } @@ -157,10 +179,10 @@ template_update() { templates_update() { # Update all templates _updated_templates=0 - if [ -d "${bastille_templatesdir}" ]; then - # shellcheck disable=SC2045 - for _template_path in $(ls -d "${bastille_templatesdir}"/*/*); do - if [ -d "$_template_path"/.git ]; then + if [ -d ${bastille_templatesdir} ]; then + # shellcheck disable=SC2045 + for _template_path in $(ls -d ${bastille_templatesdir}/*/*); do + if [ -d $_template_path/.git ]; then BASTILLE_TEMPLATE=$(echo "$_template_path" | awk -F / '{ print $(NF-1) "/" $NF }') template_update @@ -186,5 +208,6 @@ elif echo "${TARGET}" | grep -q "[0-9]\{2\}.[0-9]-RELEASE"; then arch_check release_update else + jail_check jail_update fi From 6bddbaab2c72b336ff1f98a6ef5ab7872ec36f12 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Tue, 14 Jan 2025 13:03:36 -0700 Subject: [PATCH 17/59] upgrade: deprecate RELEASE upgrade, fix thick/thin jail upgrades --- usr/local/share/bastille/upgrade.sh | 167 ++++++++++++++++------------ 1 file changed, 95 insertions(+), 72 deletions(-) diff --git a/usr/local/share/bastille/upgrade.sh b/usr/local/share/bastille/upgrade.sh index 5aa06905..a1092948 100644 --- a/usr/local/share/bastille/upgrade.sh +++ b/usr/local/share/bastille/upgrade.sh @@ -34,31 +34,64 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille upgrade release newrelease | target newrelease | target install | [force]" + error_notify "Usage: bastille upgrade [option(s)] TARGET [NEWRELEASE|install]" + cat << EOF + Options: + + -a | --auto Auto mode. Start/stop jail(s) if required. + -f | --force Force upgrade a release. + -x | --debug Enable debug mode. + +EOF + exit 1 } -# Handle special-case commands first. -case "$1" in -help|-h|--help) - usage - ;; -esac +# Handle options. +OPTION="" +while [ "$#" -gt 0 ]; do + case "${1}" in + -h|--help|help) + usage + ;; + -a|--auto) + AUTO=1 + shift + ;; + -f|--force) + OPTION="-F" + shift + ;; + -x|--debug) + enable_debug + shift + ;; + -*) + for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do + case ${_opt} in + a) AUTO=1 ;; + f) OPTION="-F" ;; + x) enable_debug ;; + *) error_exit "Unknown Option: \"${1}\"" ;; + esac + done + shift + ;; + *) + break + ;; + esac +done -if [ $# -gt 3 ] || [ $# -lt 2 ]; then +if [ $# -lt 2 ] || [ $# -gt 3 ]; then usage fi +TARGET="${1}" +NEWRELEASE="${2}" + bastille_root_check -TARGET="$1" -NEWRELEASE="$2" -OPTION="$3" - -# Check for unsupported actions -if [ "${TARGET}" = "ALL" ]; then - error_exit "Batch upgrade is unsupported." -fi - +# Check for unsupported actions if [ -f "/bin/midnightbsd-version" ]; then echo -e "${COLOR_RED}Not yet supported on MidnightBSD.${COLOR_RESET}" exit 1 @@ -68,24 +101,14 @@ if freebsd-version | grep -qi HBSD; then error_exit "Not yet supported on HardenedBSD." fi -# Handle options -case "${OPTION}" in - -f|--force) - OPTION="-F" - ;; - *) - OPTION= - ;; -esac - jail_check() { # Check if the jail is thick and is running - if [ ! "$(/usr/sbin/jls name | awk "/^${TARGET}$/")" ]; then - error_exit "[${TARGET}]: Not started. See 'bastille start ${TARGET}'." - else - if grep -qw "${bastille_jailsdir}/${TARGET}/root/.bastille" "${bastille_jailsdir}/${TARGET}/fstab"; then - error_exit "${TARGET} is not a thick container." - fi + set_target_single "${TARGET}" + check_target_is_running "${TARGET}" || if [ "${AUTO}" -eq 1 ]; then + bastille start "${TARGET}" + else + error_notify "Jail is not running." + error_continue "Use [-a|--auto] to auto-start the jail." fi } @@ -96,60 +119,60 @@ release_check() { fi } -release_upgrade() { - # Upgrade a release - if [ -d "${bastille_releasesdir}/${TARGET}" ]; then - release_check - env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_releasesdir}/${TARGET}" --currently-running "${TARGET}" -r "${NEWRELEASE}" upgrade - echo - echo -e "${COLOR_YELLOW}Please run 'bastille upgrade ${TARGET} install' to finish installing updates.${COLOR_RESET}" - else - error_exit "${TARGET} not found. See 'bastille bootstrap'." - fi -} - jail_upgrade() { - # Upgrade a thick container - if [ -d "${bastille_jailsdir}/${TARGET}" ]; then - jail_check - release_check - CURRENT_VERSION=$(jexec -l ${TARGET} freebsd-version) - env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_jailsdir}/${TARGET}/root" --currently-running "${CURRENT_VERSION}" -r ${NEWRELEASE} upgrade + local _jailname="${1}" + local _oldrelease="$(jexec -l ${TARGET} freebsd-version)" + local _newrelease="${2}" + local _jailpath="${bastille_jailsdir}/${TARGET}/root" + local _workdir="${bastille_jailsdir}/${TARGET}/root/var/db/freebsd-update" + local _freebsd_update_conf="${bastille_jailsdir}/${TARGET}/root/etc/freebsd-update.conf" + + jail_check + release_check + + # Upgrade a thin jail + if grep -qw "${bastille_jailsdir}/${TARGET}/root/.bastille" "${bastille_jailsdir}/${TARGET}/fstab"; then + local _oldrelease="$(grep osrelease ${bastille_jailsdir}/${TARGET}/jail.conf | awk -F"= " '{print $2}' | sed 's/;//g')" + local _newrelease="${NEWRELEASE}" + sed -i '' "/.bastille/ s|${_oldrelease}|${_newrelease}|g" "${bastille_jailsdir}/${TARGET}/fstab" + sed -i '' "/osrelease/ s|${_oldrelease}|${_newrelease}|g" "${bastille_jailsdir}/${TARGET}/jail.conf" + info "Upgraded ${TARGET}: ${_oldrelease} -> ${_newrelease}" + info "See 'bastille etcupdate TARGET' to update /etc/rc.conf" + else + # Upgrade a thick jail + env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron \ + --currently-running "${_oldrelease}" \ + -b "${_jailpath}" \ + -d "${_workdir}" \ + -f "${_freebsd_update_conf}" \ + -r "${_newrelease}" \ + upgrade + echo echo -e "${COLOR_YELLOW}Please run 'bastille upgrade ${TARGET} install' to finish installing updates.${COLOR_RESET}" - else - error_exit "${TARGET} not found. See 'bastille bootstrap'." fi } jail_updates_install() { + local _jailpath="${bastille_jailsdir}/${TARGET}/root" + local _workdir="${bastille_jailsdir}/${TARGET}/root/var/db/freebsd-update" + local _freebsd_update_conf="${bastille_jailsdir}/${TARGET}/root/etc/freebsd-update.conf" # Finish installing upgrade on a thick container if [ -d "${bastille_jailsdir}/${TARGET}" ]; then jail_check - env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_jailsdir}/${TARGET}/root" install + env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron \ + -b "${_jailpath}" \ + -d "${_workdir}" \ + -f "${_freebsd_update_conf}" \ + install else - error_exit "${TARGET} not found. See 'bastille bootstrap'." - fi -} - -release_updates_install() { - # Finish installing upgrade on a release - if [ -d "${bastille_releasesdir}/${TARGET}" ]; then - env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_releasesdir}/${TARGET}" install - else - error_exit "${TARGET} not found. See 'bastille bootstrap'." + error_exit "${TARGET} not found. See 'bastille bootstrap RELEASE'." fi } # Check what we should upgrade -if echo "${TARGET}" | grep -q "[0-9]\{2\}.[0-9]-RELEASE"; then - if [ "${NEWRELEASE}" = "install" ]; then - release_updates_install - else - release_upgrade - fi -elif [ "${NEWRELEASE}" = "install" ]; then +if [ "${NEWRELEASE}" = "install" ]; then jail_updates_install else - jail_upgrade + jail_upgrade "${TARGET}" "${NEWRELEASE}" fi From 5394ad8979214786aa2b1579499b517994032187 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Tue, 14 Jan 2025 13:22:30 -0700 Subject: [PATCH 18/59] upgrade: Update "osrelease" entry --- usr/local/share/bastille/upgrade.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/usr/local/share/bastille/upgrade.sh b/usr/local/share/bastille/upgrade.sh index a1092948..74822da3 100644 --- a/usr/local/share/bastille/upgrade.sh +++ b/usr/local/share/bastille/upgrade.sh @@ -134,7 +134,9 @@ jail_upgrade() { if grep -qw "${bastille_jailsdir}/${TARGET}/root/.bastille" "${bastille_jailsdir}/${TARGET}/fstab"; then local _oldrelease="$(grep osrelease ${bastille_jailsdir}/${TARGET}/jail.conf | awk -F"= " '{print $2}' | sed 's/;//g')" local _newrelease="${NEWRELEASE}" + # Update "osrelease" entry inside jail.conf sed -i '' "/.bastille/ s|${_oldrelease}|${_newrelease}|g" "${bastille_jailsdir}/${TARGET}/fstab" + # Update "fstab" entry sed -i '' "/osrelease/ s|${_oldrelease}|${_newrelease}|g" "${bastille_jailsdir}/${TARGET}/jail.conf" info "Upgraded ${TARGET}: ${_oldrelease} -> ${_newrelease}" info "See 'bastille etcupdate TARGET' to update /etc/rc.conf" @@ -145,9 +147,10 @@ jail_upgrade() { -b "${_jailpath}" \ -d "${_workdir}" \ -f "${_freebsd_update_conf}" \ - -r "${_newrelease}" \ - upgrade - + -r "${_newrelease}" upgrade + + # Update "osrelease" entry inside jail.conf + sed -i '' "/osrelease/ s|${_oldrelease}|${_newrelease}|g" "${bastille_jailsdir}/${TARGET}/jail.conf" echo echo -e "${COLOR_YELLOW}Please run 'bastille upgrade ${TARGET} install' to finish installing updates.${COLOR_RESET}" fi From 35f698bc960d97d0c598c6f38e4316772f3d3359 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Thu, 16 Jan 2025 07:25:49 -0700 Subject: [PATCH 19/59] upgrade: use $jailpath for vars --- usr/local/share/bastille/upgrade.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/usr/local/share/bastille/upgrade.sh b/usr/local/share/bastille/upgrade.sh index 74822da3..0b9d2365 100644 --- a/usr/local/share/bastille/upgrade.sh +++ b/usr/local/share/bastille/upgrade.sh @@ -124,8 +124,8 @@ jail_upgrade() { local _oldrelease="$(jexec -l ${TARGET} freebsd-version)" local _newrelease="${2}" local _jailpath="${bastille_jailsdir}/${TARGET}/root" - local _workdir="${bastille_jailsdir}/${TARGET}/root/var/db/freebsd-update" - local _freebsd_update_conf="${bastille_jailsdir}/${TARGET}/root/etc/freebsd-update.conf" + local _workdir="${_jailpath}/var/db/freebsd-update" + local _freebsd_update_conf="${_jailpath}/etc/freebsd-update.conf" jail_check release_check @@ -158,8 +158,8 @@ jail_upgrade() { jail_updates_install() { local _jailpath="${bastille_jailsdir}/${TARGET}/root" - local _workdir="${bastille_jailsdir}/${TARGET}/root/var/db/freebsd-update" - local _freebsd_update_conf="${bastille_jailsdir}/${TARGET}/root/etc/freebsd-update.conf" + local _workdir="${_jailpath}/var/db/freebsd-update" + local _freebsd_update_conf="${_jailpath}/etc/freebsd-update.conf" # Finish installing upgrade on a thick container if [ -d "${bastille_jailsdir}/${TARGET}" ]; then jail_check From e4f58af7707eb18211416c613623763eac1b4377 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Thu, 16 Jan 2025 07:27:48 -0700 Subject: [PATCH 20/59] upgrade: Use -j jailname instead of -b --- usr/local/share/bastille/upgrade.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usr/local/share/bastille/upgrade.sh b/usr/local/share/bastille/upgrade.sh index 0b9d2365..70db6071 100644 --- a/usr/local/share/bastille/upgrade.sh +++ b/usr/local/share/bastille/upgrade.sh @@ -144,7 +144,7 @@ jail_upgrade() { # Upgrade a thick jail env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron \ --currently-running "${_oldrelease}" \ - -b "${_jailpath}" \ + -j "${_jailname}" \ -d "${_workdir}" \ -f "${_freebsd_update_conf}" \ -r "${_newrelease}" upgrade @@ -164,7 +164,7 @@ jail_updates_install() { if [ -d "${bastille_jailsdir}/${TARGET}" ]; then jail_check env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron \ - -b "${_jailpath}" \ + -j "${_jailname}" \ -d "${_workdir}" \ -f "${_freebsd_update_conf}" \ install From a74f87162ae27b7e417d2df99f347df28a2e390f Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Thu, 16 Jan 2025 07:36:25 -0700 Subject: [PATCH 21/59] update: Use -j jailpath and _release path as vars --- usr/local/share/bastille/update.sh | 33 ++++++++++++++++++------------ 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/usr/local/share/bastille/update.sh b/usr/local/share/bastille/update.sh index f2ab3c61..f1ee3ef7 100644 --- a/usr/local/share/bastille/update.sh +++ b/usr/local/share/bastille/update.sh @@ -123,38 +123,45 @@ jail_check() { } jail_update() { - local _freebsd_update_conf="${bastille_jailsdir}/${TARGET}/root/etc/freebsd-update.conf" - local _jail_dir="${bastille_jailsdir}/${TARGET}/root" - local _workdir="${bastille_jailsdir}/${TARGET}/root/var/db/freebsd-update" + local _jailname="${1}" + local _jailpath="${bastille_jailsdir}/${TARGET}/root" + local _freebsd_update_conf="${_jailpath}/etc/freebsd-update.conf" + local _workdir="${_jailpath}/var/db/freebsd-update" # Update a thick container if [ -d "${bastille_jailsdir}/${TARGET}" ]; then CURRENT_VERSION=$(/usr/sbin/jexec -l "${TARGET}" freebsd-version 2>/dev/null) if [ -z "${CURRENT_VERSION}" ]; then error_exit "Can't determine '${TARGET}' version." else - env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${_jail_dir}" \ + env PAGER="/bin/cat" freebsd-update ${OPTION} \ + --not-running-from-cron \ + -j "${_jailname}" \ -d "${_workdir}" \ -f "${_freebsd_update_conf}" \ - fetch install --currently-running "${CURRENT_VERSION}" + fetch install fi fi } release_update() { - local _freebsd_update_conf="${bastille_releasesdir}/${TARGET}/etc/freebsd-update.conf" - local _release_dir="${bastille_releasesdir}/${TARGET}" + local _releasepath="${bastille_releasesdir}/${TARGET}" + local _freebsd_update_conf="${_releasepath}/etc/freebsd-update.conf" # Update a release base(affects child containers) - if [ -d "${_release_dir}" ]; then + if [ -d "${_releasepath}" ]; then TARGET_TRIM="${TARGET}" if [ -n "${ARCH_I386}" ]; then TARGET_TRIM=$(echo "${TARGET}" | sed 's/-i386//') fi - env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_releasesdir}/${TARGET}" \ - -d "${bastille_releasesdir}/${TARGET}/var/db/freebsd-update" \ + env PAGER="/bin/cat" freebsd-update ${OPTION} \ + --not-running-from-cron \ + -b "${_releasepath}" \ + -d "${_releasepath}/var/db/freebsd-update" \ -f "${_freebsd_update_conf}" \ fetch --currently-running "${TARGET_TRIM}" - env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_releasesdir}/${TARGET}" \ - -d "${bastille_releasesdir}/${TARGET}/var/db/freebsd-update" \ + env PAGER="/bin/cat" freebsd-update ${OPTION} \ + --not-running-from-cron \ + -b "${_releasepath}" \ + -d "${_releasepath}/var/db/freebsd-update" \ -f "${_freebsd_update_conf}" \ install --currently-running "${TARGET_TRIM}" else @@ -209,5 +216,5 @@ elif echo "${TARGET}" | grep -q "[0-9]\{2\}.[0-9]-RELEASE"; then release_update else jail_check - jail_update + jail_update "${TARGET}" fi From ce0ab9d3642e8513a60f62ef0e3664d8a5e88d2f Mon Sep 17 00:00:00 2001 From: Matthias Petermann Date: Fri, 17 Jan 2025 09:58:23 +0100 Subject: [PATCH 22/59] Commit fb71f0d introduced to possibility to add options behind permissions in fstab. Unfortunately it breaks scenarios where no options are provided as the current regex expects the comma with the options always to be present. This patch fixes the regex to handle the options as group. --- usr/local/share/bastille/mount.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index b2aeb438..8aa3cb78 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -92,7 +92,7 @@ elif [ ! -e "${_hostpath}" ] || [ "${_type}" != "nullfs" ]; then fi # Mount permissions,options need to start with "ro" or "rw" -if ! echo "${_perms}" | grep -Eq 'r[w|o],.*$'; then +if ! echo "${_perms}" | grep -Eq 'r[w|o](,.*)?$'; then error_notify "Detected invalid mount permissions in FSTAB." warn "Format: /host/path /jail/path nullfs ro 0 0" warn "Read: ${_fstab}" From 6eaa16e2998d77456ee41c60717fb5576778f515 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Fri, 17 Jan 2025 07:34:13 -0700 Subject: [PATCH 23/59] =?UTF-8?q?update:=20use=20=E2=80=9Cworkdir=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- usr/local/share/bastille/update.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/usr/local/share/bastille/update.sh b/usr/local/share/bastille/update.sh index f1ee3ef7..1a387b36 100644 --- a/usr/local/share/bastille/update.sh +++ b/usr/local/share/bastille/update.sh @@ -146,6 +146,7 @@ jail_update() { release_update() { local _releasepath="${bastille_releasesdir}/${TARGET}" local _freebsd_update_conf="${_releasepath}/etc/freebsd-update.conf" + local _workdir="${_releasepath}/var/db/freebsd-update" # Update a release base(affects child containers) if [ -d "${_releasepath}" ]; then TARGET_TRIM="${TARGET}" @@ -155,13 +156,13 @@ release_update() { env PAGER="/bin/cat" freebsd-update ${OPTION} \ --not-running-from-cron \ -b "${_releasepath}" \ - -d "${_releasepath}/var/db/freebsd-update" \ + -d "${_workdir}" \ -f "${_freebsd_update_conf}" \ fetch --currently-running "${TARGET_TRIM}" env PAGER="/bin/cat" freebsd-update ${OPTION} \ --not-running-from-cron \ -b "${_releasepath}" \ - -d "${_releasepath}/var/db/freebsd-update" \ + -d "${_workdir}" \ -f "${_freebsd_update_conf}" \ install --currently-running "${TARGET_TRIM}" else From ee0b8b8f962bd44ca4f8ae3554cef53665b56928 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Fri, 17 Jan 2025 08:11:58 -0700 Subject: [PATCH 24/59] mount: fix perms check --- usr/local/share/bastille/mount.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index c6bf5bf8..604a70d7 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -89,8 +89,8 @@ elif [ ! -e "${_hostpath}" ] || [ "${_type}" != "nullfs" ]; then usage fi -# Mount permissions,options need to include at least one of "ro, rw, rq, sw, xx" -if ! echo "${_perms}" | grep -Eq '[ro|rw|rq|sw|xx]'; then +# Mount permissions,options must start with one of "ro, rw, rq, sw, xx" +if ! echo "${_perms}" | grep -Eq '(ro|rw|rq|sw|xx)(,.*)?$'; then error_notify "Detected invalid mount permissions in FSTAB." warn "Format: /host/path /jail/path nullfs ro 0 0" warn "Read: ${_fstab}" From d9106b5b3ebd2ebb690ec8898ab1eb8c30c0f8c3 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Fri, 17 Jan 2025 08:13:29 -0700 Subject: [PATCH 25/59] docs: Fix mount perms check docs --- docs/chapters/subcommands/mount.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/chapters/subcommands/mount.rst b/docs/chapters/subcommands/mount.rst index a5fbc930..172799ad 100644 --- a/docs/chapters/subcommands/mount.rst +++ b/docs/chapters/subcommands/mount.rst @@ -10,7 +10,7 @@ Syntax follows standard `/etc/fstab` format: Usage: bastille mount TARGET HOST_PATH JAIL_PATH [filesystem_type options dump pass_number] -The 'options' string can include a comma-separated list of mount options, but must include at least one of (rw,ro,rq,sw,xx) according to fstab documentation. +The 'options' string can include a comma-separated list of mount options, but must start with one of (rw,ro,rq,sw,xx) according to fstab documentation. Example: Mount a tmpfs filesystem with options. .. code-block:: shell From 5cfbe222adff6789d4d1ae1c43d8ec3daeafa22d Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Fri, 17 Jan 2025 12:27:11 -0700 Subject: [PATCH 26/59] upgrade: Fix jail update var --- usr/local/share/bastille/upgrade.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/usr/local/share/bastille/upgrade.sh b/usr/local/share/bastille/upgrade.sh index 70db6071..2be09435 100644 --- a/usr/local/share/bastille/upgrade.sh +++ b/usr/local/share/bastille/upgrade.sh @@ -157,6 +157,7 @@ jail_upgrade() { } jail_updates_install() { + local _jailname="${1}" local _jailpath="${bastille_jailsdir}/${TARGET}/root" local _workdir="${_jailpath}/var/db/freebsd-update" local _freebsd_update_conf="${_jailpath}/etc/freebsd-update.conf" @@ -175,7 +176,7 @@ jail_updates_install() { # Check what we should upgrade if [ "${NEWRELEASE}" = "install" ]; then - jail_updates_install + jail_updates_install "${TARGET}" else jail_upgrade "${TARGET}" "${NEWRELEASE}" fi From bbb1555eccc148e8353e347ce418d9254cb1b2c0 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 18 Jan 2025 07:33:00 -0700 Subject: [PATCH 27/59] mount: Fix similar path mount grep --- usr/local/share/bastille/mount.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index 1c2a8efb..5895823a 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -117,7 +117,7 @@ for _jail in ${JAILS}; do # Check if mount point has already been added _existing_mount="$(echo ${_fullpath_fstab} 2>/dev/null | sed 's#\\#\\\\#g')" - if grep -Eq "[[:blank:]]${_existing_mount}.*[[:blank:]]" "${bastille_jailsdir}/${_jail}/fstab"; then + if grep -Eq "[[:blank:]]${_existing_mount}[[:blank:]]" "${bastille_jailsdir}/${_jail}/fstab"; then warn "Mountpoint already present in ${bastille_jailsdir}/${_jail}/fstab" grep -E "[[:blank:]]${_existing_mount}" "${bastille_jailsdir}/${_jail}/fstab" continue From e1a2ed1b6bf9ea5d849d219fefa7acb73da92c3a Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 18 Jan 2025 07:39:42 -0700 Subject: [PATCH 28/59] mount: Fix () > [] --- usr/local/share/bastille/mount.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index 5895823a..398d1bf8 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -92,7 +92,7 @@ elif [ ! -e "${_hostpath}" ] || [ "${_type}" != "nullfs" ]; then fi # Mount permissions,options must start with one of "ro, rw, rq, sw, xx" -if ! echo "${_perms}" | grep -Eq '(ro|rw|rq|sw|xx)(,.*)?$'; then +if ! echo "${_perms}" | grep -Eq '[ro|rw|rq|sw|xx](,.*)?$'; then error_notify "Detected invalid mount permissions in FSTAB." warn "Format: /host/path /jail/path nullfs ro 0 0" warn "Read: ${_fstab}" From f994df3baddae8a4c68ad9464a750facfa2b62cc Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 18 Jan 2025 07:51:00 -0700 Subject: [PATCH 29/59] mount: Revert [] > () --- usr/local/share/bastille/mount.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index 398d1bf8..5895823a 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -92,7 +92,7 @@ elif [ ! -e "${_hostpath}" ] || [ "${_type}" != "nullfs" ]; then fi # Mount permissions,options must start with one of "ro, rw, rq, sw, xx" -if ! echo "${_perms}" | grep -Eq '[ro|rw|rq|sw|xx](,.*)?$'; then +if ! echo "${_perms}" | grep -Eq '(ro|rw|rq|sw|xx)(,.*)?$'; then error_notify "Detected invalid mount permissions in FSTAB." warn "Format: /host/path /jail/path nullfs ro 0 0" warn "Read: ${_fstab}" From 589f19032ae246c941c60a0452498746c7d571df Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 18 Jan 2025 16:32:40 -0700 Subject: [PATCH 30/59] common: Allow name=if for bridge --- usr/local/share/bastille/common.sh | 240 +++++++++++++++++++---------- 1 file changed, 159 insertions(+), 81 deletions(-) diff --git a/usr/local/share/bastille/common.sh b/usr/local/share/bastille/common.sh index 654ff026..1f4e2fa0 100644 --- a/usr/local/share/bastille/common.sh +++ b/usr/local/share/bastille/common.sh @@ -31,7 +31,9 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # Source config file -. /usr/local/etc/bastille/bastille.conf +if [ -f /usr/local/etc/bastille/bastille.conf ]; then + . /usr/local/etc/bastille/bastille.conf +fi COLOR_RED= COLOR_GREEN= @@ -50,24 +52,30 @@ enable_color() { . /usr/local/share/bastille/colors.pre.sh } +enable_debug() { + # Enable debug mode. + warn "***DEBUG MODE***" + set -x +} + # If "NO_COLOR" environment variable is present, or we aren't speaking to a # tty, disable output colors. if [ -z "${NO_COLOR}" ] && [ -t 1 ]; then enable_color fi -# Error/Info functions -error_notify() { - echo -e "${COLOR_RED}$*${COLOR_RESET}" 1>&2 -} - +# Notify message on error, and continue to next jail error_continue() { error_notify "$@" - # Disabling this shellcheck as we only ever call it inside of a loop # shellcheck disable=SC2104 continue } +# Notify message on error, but do not exit +error_notify() { + echo -e "${COLOR_RED}$*${COLOR_RESET}" 1>&2 +} + # Notify message on error and exit error_exit() { error_notify "$@" @@ -84,7 +92,8 @@ warn() { check_target_exists() { local _TARGET="${1}" - if [ ! -d "${bastille_jailsdir}"/"${_TARGET}" ]; then + local _jaillist="$(bastille list jails)" + if ! echo "${_jaillist}" | grep -Eq "^${_TARGET}$"; then return 1 else return 0 @@ -93,7 +102,7 @@ check_target_exists() { check_target_is_running() { local _TARGET="${1}" - if [ ! "$(/usr/sbin/jls name | awk "/^${_TARGET}$/")" ]; then + if ! jls name | grep -Eq "^${_TARGET}$"; then return 1 else return 0 @@ -102,20 +111,124 @@ check_target_is_running() { check_target_is_stopped() { local _TARGET="${1}" - if [ "$(/usr/sbin/jls name | awk "/^${_TARGET}$/")" ]; then + if jls name | grep -Eq "^${_TARGET}$"; then return 1 else return 0 fi } +get_jail_name() { + local _JID="${1}" + local _jailname="$(jls -j ${_JID} name 2>/dev/null)" + if [ -z "${_jailname}" ]; then + return 1 + else + echo "${_jailname}" + fi +} + +jail_autocomplete() { + local _TARGET="${1}" + local _jaillist="$(bastille list jails)" + local _AUTOTARGET="$(echo "${_jaillist}" | grep -E "^${_TARGET}")" + if [ -n "${_AUTOTARGET}" ]; then + if [ "$(echo "${_AUTOTARGET}" | wc -l)" -eq 1 ]; then + echo "${_AUTOTARGET}" + else + error_continue "Multiple jails found for ${_TARGET}:\n${_AUTOTARGET}" + return 1 + fi + else + return 2 + fi +} + +set_target() { + local _TARGET=${1} + JAILS="" + TARGET="" + if [ "${_TARGET}" = ALL ] || [ "${_TARGET}" = all ]; then + target_all_jails + else + for _jail in ${_TARGET}; do + if [ ! -d "${bastille_jailsdir}/${_TARGET}" ] && echo "${_jail}" | grep -Eq '^[0-9]+$'; then + if get_jail_name "${_jail}" > /dev/null; then + _jail="$(get_jail_name ${_jail})" + else + error_continue "Error: JID \"${_jail}\" not found. Is jail running?" + fi + elif ! check_target_exists "${_jail}"; then + if jail_autocomplete "${_jail}" > /dev/null; then + _jail="$(jail_autocomplete ${_jail})" + elif [ $? -eq 2 ]; then + error_continue "Jail not found \"${_jail}\"" + else + exit 1 + fi + fi + TARGET="${TARGET} ${_jail}" + JAILS="${JAILS} ${_jail}" + done + export TARGET + export JAILS + fi +} + +set_target_single() { + local _TARGET="${1}" + if [ "${_TARGET}" = ALL ] || [ "${_TARGET}" = all ]; then + error_exit "[all|ALL] not supported with this command." + elif [ "$(echo ${_TARGET} | wc -w)" -gt 1 ]; then + error_exit "Error: Command only supports a single TARGET." + elif [ ! -d "${bastille_jailsdir}/${_TARGET}" ] && echo "${_TARGET}" | grep -Eq '^[0-9]+$'; then + if get_jail_name "${_TARGET}" > /dev/null; then + _TARGET="$(get_jail_name ${_TARGET})" + else + error_exit "Error: JID \"${_TARGET}\" not found. Is jail running?" + fi + elif ! check_target_exists "${_TARGET}"; then + if jail_autocomplete "${_TARGET}" > /dev/null; then + _TARGET="$(jail_autocomplete ${_TARGET})" + elif [ $? -eq 2 ]; then + error_exit "Jail not found \"${_TARGET}\"" + else + exit 1 + fi + fi + TARGET="${_TARGET}" + JAILS="${_TARGET}" + export TARGET + export JAILS +} + +target_all_jails() { + local _JAILS="$(bastille list jails)" + JAILS="" + for _jail in ${_JAILS}; do + if [ -d "${bastille_jailsdir}/${_jail}" ]; then + JAILS="${JAILS} ${_jail}" + fi + done + export JAILS +} + +update_fstab() { + local _oldname="${1}" + local _newname="${2}" + local _fstab="${bastille_jailsdir}/${_newname}/fstab" + if [ -f "${_fstab}" ]; then + sed -i '' "s|${bastille_jailsdir}/${_oldname}/root/|${bastille_jailsdir}/${_newname}/root/|" "${_fstab}" + else + error_notify "Error: Failed to update fstab: ${_newmane}" + fi +} + generate_static_mac() { local jail_name="${1}" local external_interface="${2}" local external_interface_mac="$(ifconfig ${external_interface} | grep ether | awk '{print $2}')" - # Use the FreeBSD vendor MAC prefix for jail MAC prefix "58:9c:fc" local macaddr_prefix="58:9c:fc" - # Hash interface+jailname for jail MAC suffix local macaddr_suffix="$(echo -n "${external_interface_mac}${jail_name}" | sed 's#:##g' | sha256 | cut -b -5 | sed 's/\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F]\)/\1:\2:\3/')" if [ -z "${macaddr_prefix}" ] || [ -z "${macaddr_suffix}" ]; then error_notify "Failed to generate MAC address." @@ -140,12 +253,26 @@ generate_vnet_jail_netblock() { if [ "${_epair_if_count}" -gt 0 ]; then for _num in $(seq 0 "${epair_num_range}"); do if ! grep -Eosq "epair${_num}" ${bastille_jailsdir}/*/jail.conf; then - local uniq_epair_bridge="${_num}" + if [ "$(echo -n "e${_num}a_${jail_name}" | awk '{print length}')" -lt 16 ]; then + local host_epair=e${_num}a_${jail_name} + local jail_epair=e${_num}b_${jail_name} + else + local host_epair=epair${_num}a + local jail_epair=epair${_num}b + fi break fi done else - local uniq_epair_bridge="0" + if [ "$(echo -n "e0a_${jail_name}" | awk '{print length}')" -lt 16 ]; then + local _num=0 + local host_epair=e${_num}a_${jail_name} + local jail_epair=e${_num}b_${jail_name} + else + local _num=0 + local host_epair=epair${_num}a + local jail_epair=epair${_num}b + fi fi else if [ "${_bastille_if_count}" -gt 0 ]; then @@ -166,25 +293,29 @@ generate_vnet_jail_netblock() { generate_static_mac "${jail_name}" "${external_interface}" cat <<-EOF vnet; - vnet.interface = epair${uniq_epair_bridge}b; - exec.prestart += "ifconfig epair${uniq_epair_bridge} create"; - exec.prestart += "ifconfig ${external_interface} addm epair${uniq_epair_bridge}a"; - exec.prestart += "ifconfig epair${uniq_epair_bridge}a ether ${macaddr}a"; - exec.prestart += "ifconfig epair${uniq_epair_bridge}b ether ${macaddr}b"; - exec.prestart += "ifconfig epair${uniq_epair_bridge}a description \"vnet host interface for Bastille jail ${jail_name}\""; - exec.poststop += "ifconfig ${external_interface} deletem epair${uniq_epair_bridge}a"; - exec.poststop += "ifconfig epair${uniq_epair_bridge}a destroy"; + vnet.interface = ${jail_epair}; + exec.prestart += "ifconfig epair${_num} create"; + exec.prestart += "ifconfig ${external_interface} addm epair${_num}a"; + exec.prestart += "ifconfig epair${_num}a up name ${host_epair}"; + exec.prestart += "ifconfig epair${_num}b up name ${jail_epair}"; + exec.prestart += "ifconfig ${host_epair} ether ${macaddr}a"; + exec.prestart += "ifconfig ${jail_epair} ether ${macaddr}b"; + exec.prestart += "ifconfig ${host_epair} description \"vnet host interface for Bastille jail ${jail_name}\""; + exec.poststop += "ifconfig ${external_interface} deletem ${host_epair}"; + exec.poststop += "ifconfig ${host_epair} destroy"; EOF else ## Generate bridged VNET config without static MAC address cat <<-EOF vnet; - vnet.interface = epair${uniq_epair_bridge}b; - exec.prestart += "ifconfig epair${uniq_epair_bridge} create"; - exec.prestart += "ifconfig ${external_interface} addm epair${uniq_epair_bridge}a"; - exec.prestart += "ifconfig epair${uniq_epair_bridge}a description \"vnet host interface for Bastille jail ${jail_name}\""; - exec.poststop += "ifconfig ${external_interface} deletem epair${uniq_epair_bridge}a"; - exec.poststop += "ifconfig epair${uniq_epair_bridge}a destroy"; + vnet.interface = ${jail_epair}; + exec.prestart += "ifconfig epair${_num} create"; + exec.prestart += "ifconfig ${external_interface} addm epair${_num}a"; + exec.prestart += "ifconfig epair${_num}a up name ${host_epair}"; + exec.prestart += "ifconfig epair${_num}b up name ${jail_epair}"; + exec.prestart += "ifconfig ${host_epair} description \"vnet host interface for Bastille jail ${jail_name}\""; + exec.poststop += "ifconfig ${external_interface} deletem ${host_epair}"; + exec.poststop += "ifconfig ${host_epair} destroy"; EOF fi else @@ -213,58 +344,6 @@ EOF fi } -set_target() { - local _TARGET="${1}" - if [ "${_TARGET}" = ALL ] || [ "${_TARGET}" = all ]; then - target_all_jails - else - check_target_exists "${_TARGET}" || error_exit "Jail not found \"${_TARGET}\"" - JAILS="${_TARGET}" - TARGET="${_TARGET}" - export JAILS - export TARGET - fi -} - -set_target_single() { - local _TARGET="${1}" - if [ "${_TARGET}" = ALL ] || [ "${_TARGET}" = all ]; then - error_exit "[all|ALL] not supported with this command." - elif [ "$(echo ${_TARGET} | wc -w)" -gt 1 ]; then - error_exit "Error: Command only supports a single TARGET." - elif echo "${_TARGET}" | grep -Eq '^[0-9]+$'; then - if get_jail_name "${_TARGET}" > /dev/null; then - _TARGET="$(get_jail_name ${_TARGET})" - else - error_exit "Error: JID \"${_TARGET}\" not found. Is jail running?" - fi - elif - ! check_target_exists "${_TARGET}"; then - if jail_autocomplete "${_TARGET}" > /dev/null; then - _TARGET="$(jail_autocomplete ${_TARGET})" - elif [ $? -eq 2 ]; then - error_exit "Jail not found \"${_TARGET}\"" - else - exit 1 - fi - fi - TARGET="${_TARGET}" - JAILS="${_TARGET}" - export TARGET - export JAILS -} - -target_all_jails() { - local _JAILS="$(bastille list jails)" - JAILS="" - for _jail in ${_JAILS}; do - if [ -d "${bastille_jailsdir}/${_jail}" ]; then - JAILS="${JAILS} ${_jail}" - fi - done - export JAILS -} - checkyesno() { ## copied from /etc/rc.subr -- cedwards (20231125) ## issue #368 (lowercase values should be parsed) @@ -285,4 +364,3 @@ checkyesno() { ;; esac } - From 04f86c3f5badfb89b3b688726348871ed2827743 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 18 Jan 2025 16:38:29 -0700 Subject: [PATCH 31/59] clone: Allow name=if clone --- usr/local/share/bastille/clone.sh | 236 +++++++++++++++++++++--------- 1 file changed, 167 insertions(+), 69 deletions(-) diff --git a/usr/local/share/bastille/clone.sh b/usr/local/share/bastille/clone.sh index 428bf9c8..290db01b 100644 --- a/usr/local/share/bastille/clone.sh +++ b/usr/local/share/bastille/clone.sh @@ -34,24 +34,78 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille clone TARGET NEW_NAME IPADDRESS" + error_notify "Usage: bastille clone [option(s)] TARGET NEW_NAME IP_ADDRESS" + cat << EOF + Options: + + -a | --auto Auto mode. Start/stop jail(s) if required. Cannot be used with [-l|--live]. + -l | --live Clone a running jail. ZFS only. Jail must be running. Cannot be used with [-f|--force]. + -x | --debug Enable debug mode. + +EOF + exit 1 } -# Handle special-case commands first -case "$1" in -help|-h|--help) - usage - ;; -esac +# Handle options. +AUTO=0 +LIVE=0 +while [ "$#" -gt 0 ]; do + case "${1}" in + -h|--help|help) + usage + ;; + -a|--auto) + AUTO=1 + shift + ;; + -l|--live) + if ! checkyesno bastille_zfs_enable; then + error_exit "[-l|--live] can only be used with ZFS." + else + LIVE=1 + shift + fi + ;; + -x|--debug) + enable_debug + shift + ;; + -*) + for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do + case ${_opt} in + a) AUTO=1 ;; + l) LIVE=1 ;; + x) enable_debug ;; + *) error_exit "Unknown Option: \"${1}\"" + esac + done + shift + ;; + *) + break + ;; + esac +done -if [ $# -ne 2 ]; then +if [ "${AUTO}" -eq 1 ] && [ "${LIVE}" -eq 1 ]; then + error_exit "[-a|--auto] cannot be used with [-l|--live]" +fi + +if [ $# -ne 3 ]; then usage fi -bastille_root_check +TARGET="${1}" +NEWNAME="${2}" +IP="${3}" -NEWNAME="${1}" -IP="${2}" +bastille_root_check +set_target_single "${TARGET}" + +## don't allow for dots(.) in container names +if echo "${NEWNAME}" | grep -q "[.]"; then + error_exit "Container names may not contain a dot(.)!" +fi validate_ip() { IPX_ADDR="ip4.addr" @@ -89,24 +143,43 @@ update_jailconf() { JAIL_CONFIG="${bastille_jailsdir}/${NEWNAME}/jail.conf" if [ -f "${JAIL_CONFIG}" ]; then if ! grep -qw "path = ${bastille_jailsdir}/${NEWNAME}/root;" "${JAIL_CONFIG}"; then - sed -i '' "s|host.hostname = ${TARGET};|host.hostname = ${NEWNAME};|" "${JAIL_CONFIG}" + sed -i '' "s|host.hostname = ${TARGET};|host.hostname = ${NEWNAME};|" "${JAIL_CONFIG}" sed -i '' "s|exec.consolelog = .*;|exec.consolelog = ${bastille_logsdir}/${NEWNAME}_console.log;|" "${JAIL_CONFIG}" sed -i '' "s|path = .*;|path = ${bastille_jailsdir}/${NEWNAME}/root;|" "${JAIL_CONFIG}" sed -i '' "s|mount.fstab = .*;|mount.fstab = ${bastille_jailsdir}/${NEWNAME}/fstab;|" "${JAIL_CONFIG}" sed -i '' "s|${TARGET} {|${NEWNAME} {|" "${JAIL_CONFIG}" - sed -i '' "s|${IPX_ADDR} = .*;|${IPX_ADDR} = ${IP};|" "${JAIL_CONFIG}" fi fi if grep -qw "vnet;" "${JAIL_CONFIG}"; then update_jailconf_vnet + else + _ip4="$(bastille config ${TARGET} get ip4.addr | sed 's/,/ /g')" + _ip6="$(bastille config ${TARGET} get ip6.addr | sed 's/,/ /g')" + # IP4 + if [ "${_ip4}" != "not set" ]; then + for _ip in ${_ip4}; do + _ip="$(echo ${_ip} | awk -F"|" '{print $2}')" + sed -i '' "/${IPX_ADDR} = .*/ s/${_ip}/${IP}/" "${JAIL_CONFIG}" + sed -i '' "/${IPX_ADDR} += .*/ s/${_ip}/127.0.0.1/" "${JAIL_CONFIG}" + done + fi + # IP6 + if [ "${_ip6}" != "not set" ]; then + for _ip in ${_ip6}; do + _ip="$(echo ${_ip} | awk -F"|" '{print $2}')" + sed -i '' "/${IPX_ADDR} = .*/ s/${_ip}/${IP}/" "${JAIL_CONFIG}" + sed -i '' "/${IPX_ADDR} += .*/ s/${_ip}/127.0.0.1/" "${JAIL_CONFIG}" + done + fi fi } update_jailconf_vnet() { - bastille_jail_rc_conf="${bastille_jailsdir}/${NEWNAME}/root/etc/rc.conf" + local _jail_conf="${bastille_jailsdir}/${NEWNAME}/jail.conf" + local _rc_conf="${bastille_jailsdir}/${NEWNAME}/root/etc/rc.conf" # Determine number of interfaces and define a uniq_epair - local _if_list="$(grep -Eo 'epair[0-9]+|bastille[0-9]+' ${JAIL_CONFIG} | sort -u)" + local _if_list="$(grep -Eo 'epair[0-9]+|bastille[0-9]+' ${_jail_conf} | sort -u)" for _if in ${_if_list}; do local _epair_if_count="$(grep -Eo 'epair[0-9]+' ${bastille_jailsdir}/*/jail.conf | sort -u | wc -l | awk '{print $1}')" local _bastille_if_count="$(grep -Eo 'bastille[0-9]+' ${bastille_jailsdir}/*/jail.conf | sort -u | wc -l | awk '{print $1}')" @@ -116,30 +189,53 @@ update_jailconf_vnet() { # Update bridged VNET config for _num in $(seq 0 "${epair_num_range}"); do if ! grep -oq "epair${_num}" ${bastille_jailsdir}/*/jail.conf; then - # Update jail.conf epair name - local uniq_epair_bridge="${_num}" - local _if_epaira="${_if}a" - local _if_epairb="${_if}b" - local _if_vnet="$(grep ${_if_epairb} "${bastille_jail_rc_conf}" | grep -Eo -m 1 "vnet[0-9]+")" - sed -i '' "s|${_if}|epair${uniq_epair_bridge}|g" "${JAIL_CONFIG}" - # If jail had a static MAC, generate one for clone - if grep ether ${JAIL_CONFIG} | grep -qoc epair${uniq_epair_bridge}; then - local external_interface="$(grep "epair${uniq_epair_bridge}" ${JAIL_CONFIG} | grep -o '[^ ]* addm' | awk '{print $1}')" - generate_static_mac "${NEWNAME}" "${external_interface}" - sed -i '' "s|epair${uniq_epair_bridge}a ether.*:.*:.*:.*:.*:.*a\";|epair${uniq_epair_bridge}a ether ${macaddr}a\";|" "${JAIL_CONFIG}" - sed -i '' "s|epair${uniq_epair_bridge}b ether.*:.*:.*:.*:.*:.*b\";|epair${uniq_epair_bridge}b ether ${macaddr}b\";|" "${JAIL_CONFIG}" + # Generate new epair name + if [ "$(echo -n "e${_num}a_${NEWNAME}" | awk '{print length}')" -lt 16 ]; then + local _new_host_epair="e${_num}a_${NEWNAME}" + local _new_jail_epair="e${_num}b_${NEWNAME}" + else + local _new_host_epair="epair${_num}a" + local _new_jail_epair="epair${_num}b" fi - sed -i '' "s|vnet host interface for Bastille jail ${TARGET}|vnet host interface for Bastille jail ${NEWNAME}|g" "${JAIL_CONFIG}" + # Get epair name from TARGET + if grep -Eoq "e[0-9]+a_${TARGET}" "${_jail_conf}"; then + _target_host_epair="$(grep -Eo -m 1 "e[0-9]+a_${TARGET}" "${_jail_conf}")" + _target_jail_epair="$(grep -Eo -m 1 "e[0-9]+b_${TARGET}" "${_jail_conf}")" + else + _target_host_epair="${_if}a" + _target_jail_epair="${_if}b" + fi + # Replace epair name in jail.conf + sed -i '' "s|${_if}|epair${_num}|g" "${_jail_conf}" + # Replace host epair name in jail.conf + sed -i '' "s|up name ${_target_host_epair}|up name ${_new_host_epair}|g" "${_jail_conf}" + sed -i '' "s|${_target_host_epair} ether|${_new_host_epair} ether|g" "${_jail_conf}" + sed -i '' "s|deletem ${_target_host_epair}|deletem ${_new_host_epair}|g" "${_jail_conf}" + sed -i '' "s|${_target_host_epair} destroy|${_new_host_epair} destroy|g" "${_jail_conf}" + sed -i '' "s|${_target_host_epair} description|${_new_host_epair} description|g" "${_jail_conf}" + # Replace jail epair name in jail.conf + sed -i '' "s|= ${_target_jail_epair};|= ${_new_jail_epair};|g" "${_jail_conf}" + sed -i '' "s|up name ${_target_jail_epair}|up name ${_new_jail_epair}|g" "${_jail_conf}" + sed -i '' "s|${_target_jail_epair} ether|${_new_jail_epair} ether|g" "${_jail_conf}" + # If jail had a static MAC, generate one for clone + if grep -q ether ${_jail_conf}; then + local external_interface="$(grep "${_new_host_epair}" ${_jail_conf} | grep -o '[^ ]* addm' | awk '{print $1}')" + generate_static_mac "${NEWNAME}" "${external_interface}" + sed -i '' "s|${_new_host_epair} ether.*:.*:.*:.*:.*:.*a\";|${_new_host_epair} ether ${macaddr}a\";|" "${_jail_conf}" + sed -i '' "s|${_new_jail_epair} ether.*:.*:.*:.*:.*:.*b\";|${_new_jail_epair} ether ${macaddr}b\";|" "${_jail_conf}" + fi + sed -i '' "s|vnet host interface for Bastille jail ${TARGET}|vnet host interface for Bastille jail ${NEWNAME}|g" "${_jail_conf}" # Update /etc/rc.conf - sed -i '' "s|${_if_epairb}_name|epair${uniq_epair_bridge}b_name|" "${bastille_jail_rc_conf}" - if grep "vnet0" "${bastille_jail_rc_conf}" | grep -q "epair${uniq_epair_bridge}b_name"; then + local _jail_vnet="$(grep ${_target_jail_epair} "${_rc_conf}" | grep -Eo -m 1 "vnet[0-9]+")" + sed -i '' "s|${_target_jail_epair}_name|${_new_jail_epair}_name|" "${_rc_conf}" + if grep "vnet0" "${_rc_conf}" | grep -q "${_new_jail_epair}_name"; then if [ "${IP}" = "0.0.0.0" ]; then - sysrc -f "${bastille_jail_rc_conf}" ifconfig_vnet0="SYNCDHCP" + sysrc -f "${_rc_conf}" ifconfig_vnet0="SYNCDHCP" else - sysrc -f "${bastille_jail_rc_conf}" ifconfig_vnet0="inet ${IP}" + sysrc -f "${_rc_conf}" ifconfig_vnet0="inet ${IP}" fi else - sysrc -f "${bastille_jail_rc_conf}" ifconfig_${_if_vnet}="SYNCDHCP" + sysrc -f "${_rc_conf}" ifconfig_${_jail_vnet}="SYNCDHCP" fi break fi @@ -150,26 +246,26 @@ update_jailconf_vnet() { if ! grep -oq "bastille${_num}" ${bastille_jailsdir}/*/jail.conf; then # Update jail.conf epair name local uniq_epair="bastille${_num}" - local _if_vnet="$(grep ${_if} "${bastille_jail_rc_conf}" | grep -Eo -m 1 "vnet[0-9]+")" - sed -i '' "s|${_if}|${uniq_epair}|g" "${JAIL_CONFIG}" + local _if_vnet="$(grep ${_if} "${_rc_conf}" | grep -Eo -m 1 "vnet[0-9]+")" + sed -i '' "s|${_if}|${uniq_epair}|g" "${_jail_conf}" # If jail had a static MAC, generate one for clone - if grep ether ${JAIL_CONFIG} | grep -qoc ${uniq_epair}; then - local external_interface="$(grep ${uniq_epair} ${JAIL_CONFIG} | grep -o 'addm.*' | awk '{print $3}' | sed 's/["|;]//g')" + if grep ether ${_jail_conf} | grep -qoc ${uniq_epair}; then + local external_interface="$(grep ${uniq_epair} ${_jail_conf} | grep -o 'addm.*' | awk '{print $3}' | sed 's/["|;]//g')" generate_static_mac "${NEWNAME}" "${external_interface}" - sed -i '' "s|${uniq_epair} ether.*:.*:.*:.*:.*:.*a\";|${uniq_epair} ether ${macaddr}a\";|" "${JAIL_CONFIG}" - sed -i '' "s|${uniq_epair} ether.*:.*:.*:.*:.*:.*b\";|${uniq_epair} ether ${macaddr}b\";|" "${JAIL_CONFIG}" + sed -i '' "s|${uniq_epair} ether.*:.*:.*:.*:.*:.*a\";|${uniq_epair} ether ${macaddr}a\";|" "${_jail_conf}" + sed -i '' "s|${uniq_epair} ether.*:.*:.*:.*:.*:.*b\";|${uniq_epair} ether ${macaddr}b\";|" "${_jail_conf}" fi - sed -i '' "s|vnet host interface for Bastille jail ${TARGET}|vnet host interface for Bastille jail ${NEWNAME}|g" "${JAIL_CONFIG}" + sed -i '' "s|vnet host interface for Bastille jail ${TARGET}|vnet host interface for Bastille jail ${NEWNAME}|g" "${_jail_conf}" # Update /etc/rc.conf - sed -i '' "s|ifconfig_e0b_${_if}_name|ifconfig_e0b_${uniq_epair}_name|" "${bastille_jail_rc_conf}" - if grep "vnet0" "${bastille_jail_rc_conf}" | grep -q ${uniq_epair}; then + sed -i '' "s|ifconfig_e0b_${_if}_name|ifconfig_e0b_${uniq_epair}_name|" "${_rc_conf}" + if grep "vnet0" "${_rc_conf}" | grep -q ${uniq_epair}; then if [ "${IP}" = "0.0.0.0" ]; then - sysrc -f "${bastille_jail_rc_conf}" ifconfig_vnet0="SYNCDHCP" + sysrc -f "${_rc_conf}" ifconfig_vnet0="SYNCDHCP" else - sysrc -f "${bastille_jail_rc_conf}" ifconfig_vnet0=" inet ${IP} " + sysrc -f "${_rc_conf}" ifconfig_vnet0=" inet ${IP} " fi else - sysrc -f "${bastille_jail_rc_conf}" ifconfig_${_if_vnet}="SYNCDHCP" + sysrc -f "${_rc_conf}" ifconfig_${_if_vnet}="SYNCDHCP" fi break fi @@ -178,20 +274,21 @@ update_jailconf_vnet() { done } -update_fstab() { - # Update fstab to use the new name - FSTAB_CONFIG="${bastille_jailsdir}/${NEWNAME}/fstab" - if [ -f "${FSTAB_CONFIG}" ]; then - # Update additional fstab paths with new jail path - sed -i '' "s|${bastille_jailsdir}/${TARGET}/root/|${bastille_jailsdir}/${NEWNAME}/root/|" "${FSTAB_CONFIG}" - fi -} - clone_jail() { - # Attempt container clone - info "Attempting to clone '${TARGET}' to ${NEWNAME}..." + + info "Attempting to clone ${TARGET} to ${NEWNAME}..." + if ! [ -d "${bastille_jailsdir}/${NEWNAME}" ]; then if checkyesno bastille_zfs_enable; then + if [ "${LIVE}" -eq 1 ]; then + check_target_is_running "${TARGET}" || error_exit "[-l|--live] can only be used with a running jail." + else check_target_is_stopped "${TARGET}" || if [ "${FORCE}" -eq 1 ]; then + bastille stop "${TARGET}" + else + error_notify "Jail is running." + error_exit "Use [-f|--force] to force stop the jail, or [-l|--live] (ZFS only) to clone a running jail." + fi + fi if [ -n "${bastille_zfs_zpool}" ]; then # Replicate the existing container DATE=$(date +%F-%H%M%S) @@ -207,13 +304,13 @@ clone_jail() { zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${NEWNAME}@bastille_clone_${DATE}" fi else - # Just clone the jail directory - # Check if container is running - if [ -n "$(/usr/sbin/jls name | awk "/^${TARGET}$/")" ]; then - error_exit "${TARGET} is running. See 'bastille stop ${TARGET}'." + # Perform container file copy (archive mode) + check_target_is_stopped "${TARGET}" || if [ "${FORCE}" -eq 1 ]; then + bastille stop "${TARGET}" + else + error_notify "Jail is running." + error_exit "Use [-f|--force] to force stop the jail." fi - - # Perform container file copy(archive mode) cp -a "${bastille_jailsdir}/${TARGET}" "${bastille_jailsdir}/${NEWNAME}" fi else @@ -222,7 +319,7 @@ clone_jail() { # Generate jail configuration files update_jailconf - update_fstab + update_fstab "${TARGET}" "${NEWNAME}" # Display the exist status if [ "$?" -ne 0 ]; then @@ -230,14 +327,15 @@ clone_jail() { else info "Cloned '${TARGET}' to '${NEWNAME}' successfully." fi + if [ "${AUTO}" -eq 1 ]; then + if [ "${LIVE}" -eq 0 ]; then + bastille start "${TARGET}" + fi + bastille start "${NEWNAME}" + fi } -## don't allow for dots(.) in container names -if echo "${NEWNAME}" | grep -q "[.]"; then - error_exit "Container names may not contain a dot(.)!" -fi - -## check if ip address is valid +# Check if IP address is valid. if [ -n "${IP}" ]; then validate_ip else From c26d470a7d681b8fe3074868949133547db88dce Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 18 Jan 2025 17:02:19 -0700 Subject: [PATCH 32/59] rename: Allow if=name --- usr/local/share/bastille/rename.sh | 154 +++++++++++++++++++++-------- 1 file changed, 113 insertions(+), 41 deletions(-) diff --git a/usr/local/share/bastille/rename.sh b/usr/local/share/bastille/rename.sh index 20fb8021..52e206f7 100644 --- a/usr/local/share/bastille/rename.sh +++ b/usr/local/share/bastille/rename.sh @@ -1,8 +1,6 @@ #!/bin/sh # -# SPDX-License-Identifier: BSD-3-Clause -# -# Copyright (c) 2018-2025, Christer Edwards +# Copyright (c) 2018-2024, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -34,11 +32,62 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille rename TARGET NEW_NAME" + error_notify "Usage: bastille rename [option(s)] TARGET NEW_NAME" + cat << EOF + Options: + + -a | --auto Auto mode. Start/stop jail(s) if required. + -x | --debug Enable debug mode. + +EOF + exit 1 } +# Handle options. +AUTO=0 +while [ "$#" -gt 0 ]; do + case "${1}" in + -h|--help|help) + usage + ;; + -a|--auto) + AUTO=1 + shift + ;; + -*) + for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do + case ${_opt} in + a) AUTO=1 ;; + x) enable_debug ;; + *) error_exit "Unknown Option: \"${1}\"" + esac + done + shift + ;; + *) + break + ;; + esac +done + +if [ "$#" -ne 2 ]; then + usage +fi + +TARGET="${1}" +NEWNAME="${2}" + +bastille_root_check +set_target_single "${TARGET}" +check_target_is_stopped "${TARGET}" || if [ "${AUTO}" -eq 1 ]; then + bastille stop "${TARGET}" +else + error_notify "Jail is running." + error_exit "Use [-a|--auto] to auto-stop the jail." +fi + validate_name() { - local NAME_VERIFY=${NEWNAME} + local NAME_VERIFY="${NEWNAME}" local NAME_SANITY="$(echo "${NAME_VERIFY}" | tr -c -d 'a-zA-Z0-9-_')" if [ -n "$(echo "${NAME_SANITY}" | awk "/^[-_].*$/" )" ]; then error_exit "Container names may not begin with (-|_) characters!" @@ -47,44 +96,64 @@ validate_name() { fi } -# Handle special-case commands first -case "$1" in -help|-h|--help) - usage - ;; -esac - -if [ $# -ne 1 ]; then - usage -fi - -bastille_root_check - -NEWNAME="${1}" - update_jailconf() { # Update jail.conf - JAIL_CONFIG="${bastille_jailsdir}/${NEWNAME}/jail.conf" - if [ -f "${JAIL_CONFIG}" ]; then - if ! grep -qw "path = ${bastille_jailsdir}/${NEWNAME}/root;" "${JAIL_CONFIG}"; then - sed -i '' "s|host.hostname.*=.*${TARGET};|host.hostname = ${NEWNAME};|" "${JAIL_CONFIG}" - sed -i '' "s|exec.consolelog.*=.*;|exec.consolelog = ${bastille_logsdir}/${NEWNAME}_console.log;|" "${JAIL_CONFIG}" - sed -i '' "s|path.*=.*;|path = ${bastille_jailsdir}/${NEWNAME}/root;|" "${JAIL_CONFIG}" - sed -i '' "s|mount.fstab.*=.*;|mount.fstab = ${bastille_jailsdir}/${NEWNAME}/fstab;|" "${JAIL_CONFIG}" - sed -i '' "s|${TARGET}.*{|${NEWNAME} {|" "${JAIL_CONFIG}" - # Rename vnet interface - sed -i '' "/vnet.interface/s|_${TARGET}\";|_${NEWNAME}\";|" "${JAIL_CONFIG}" - sed -i '' "/ifconfig/s|_${TARGET}|_${NEWNAME}|" "${JAIL_CONFIG}" + local _jail_conf="${bastille_jailsdir}/${NEWNAME}/jail.conf" + local _rc_conf="${bastille_jailsdir}/${NEWNAME}/root/etc/rc.conf" + if [ -f "${_jail_conf}" ]; then + if ! grep -qw "path = ${bastille_jailsdir}/${NEWNAME}/root;" "${_jail_conf}"; then + sed -i '' "s|host.hostname.*=.*${TARGET};|host.hostname = ${NEWNAME};|" "${_jail_conf}" + sed -i '' "s|exec.consolelog.*=.*;|exec.consolelog = ${bastille_logsdir}/${NEWNAME}_console.log;|" "${_jail_conf}" + sed -i '' "s|path.*=.*;|path = ${bastille_jailsdir}/${NEWNAME}/root;|" "${_jail_conf}" + sed -i '' "s|mount.fstab.*=.*;|mount.fstab = ${bastille_jailsdir}/${NEWNAME}/fstab;|" "${_jail_conf}" + sed -i '' "s|${TARGET}.*{|${NEWNAME} {|" "${_jail_conf}" + fi + if grep -qo "vnet;" "${_jail_conf}"; then + update_jailconf_vnet fi fi } -update_fstab() { - # Update fstab to use the new name - FSTAB_CONFIG="${bastille_jailsdir}/${NEWNAME}/fstab" - if [ -f "${FSTAB_CONFIG}" ]; then - sed -i '' "s|${bastille_jailsdir}/${TARGET}|${bastille_jailsdir}/${NEWNAME}|g" "${FSTAB_CONFIG}" - fi +update_jailconf_vnet() { + local _jail_conf="${bastille_jailsdir}/${NEWNAME}/jail.conf" + local _rc_conf="${bastille_jailsdir}/${NEWNAME}/root/etc/rc.conf" + # Change epair name (if needed) + local _if_list="$(grep -Eo 'epair[0-9]+|bastille[0-9]+' ${_jail_conf} | sort -u)" + for _if in ${_if_list}; do + if echo ${_if} | grep -Eoq 'epair[0-9]+'; then + # Check if epair name = jail name + local _epair_num="$(grep -Eo -m 1 "epair[0-9]+" "${_jail_conf}" | grep -Eo "[0-9]+")" + if grep -E "epair[0-9]+a" "${_jail_conf}" | grep -Eo "e[0-9]+a_${TARGET}"; then + local _target_host_epair="$(grep -Eo -m 1 "e[0-9]+a_${TARGET}" "${_jail_conf}")" + local _target_jail_epair="$(grep -Eo -m 1 "e[0-9]+b_${TARGET}" "${_jail_conf}")" + else + local _target_host_epair="$(grep -Eo -m 1 "epair[0-9]+a" "${_jail_conf}")" + local _target_jail_epair="$(grep -Eo -m 1 "epair[0-9]+b" "${_jail_conf}")" + fi + if [ "$(echo -n "e${_epair_num}a_${NEWNAME}" | awk '{print length}')" -lt 16 ]; then + # Generate new epair name + local _new_host_epair="e${_epair_num}a_${NEWNAME}" + local _new_jail_epair="e${_epair_num}b_${NEWNAME}" + else + local _new_host_epair="epair${_epair_num}a" + local _new_jail_epair="epair${_epair_num}b" + fi + # Replace host epair name in jail.conf + sed -i '' "s|up name ${_target_host_epair}|up name ${_new_host_epair}|g" "${_jail_conf}" + sed -i '' "s|${_target_host_epair} ether|${_new_host_epair} ether|g" "${_jail_conf}" + sed -i '' "s|deletem ${_target_host_epair}|deletem ${_new_host_epair}|g" "${_jail_conf}" + sed -i '' "s|${_target_host_epair} destroy|${_new_host_epair} destroy|g" "${_jail_conf}" + sed -i '' "s|${_target_host_epair} description|${_new_host_epair} description|g" "${_jail_conf}" + # Replace jail epair name in jail.conf + sed -i '' "s|= ${_target_jail_epair};|= ${_new_jail_epair};|g" "${_jail_conf}" + sed -i '' "s|up name ${_target_jail_epair}|up name ${_new_jail_epair}|g" "${_jail_conf}" + sed -i '' "s|${_target_jail_epair} ether|${_new_jail_epair} ether|g" "${_jail_conf}" + # Replace epair description + sed -i '' "s|vnet host interface for Bastille jail ${TARGET}|vnet host interface for Bastille jail ${NEWNAME}|g" "${_jail_conf}" + # Replace epair name in /etc/rc.conf + sed -i '' "/ifconfig/ s|${_target_jail_epair}|${_new_jail_epair}|g" "${_rc_conf}" + fi + done } change_name() { @@ -124,24 +193,27 @@ change_name() { fi fi - # Update jail configuration files accordingly + # Update jail conf files update_jailconf - update_fstab + update_fstab "${TARGET}" "${NEWNAME}" # Check exit status and notify if [ "$?" -ne 0 ]; then error_exit "An error has occurred while attempting to rename '${TARGET}'." else info "Renamed '${TARGET}' to '${NEWNAME}' successfully." + if [ "${AUTO}" -eq 1 ]; then + bastille start "${NEWNAME}" + fi fi } -## validate jail name +# Validate NEW_NAME if [ -n "${NEWNAME}" ]; then validate_name fi -## check if a jail already exists with the new name +# Check if a jail already exists with NEW_NAME if [ -d "${bastille_jailsdir}/${NEWNAME}" ]; then error_exit "Jail: ${NEWNAME} already exists." fi From 3f9d903f10656d2f8add96132a4026b7e67321f7 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 18 Jan 2025 17:44:38 -0700 Subject: [PATCH 33/59] bastille: rename+clone > no options command --- usr/local/bin/bastille | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usr/local/bin/bastille b/usr/local/bin/bastille index ba831d07..04f28e8c 100755 --- a/usr/local/bin/bastille +++ b/usr/local/bin/bastille @@ -164,10 +164,10 @@ version|-v|--version) help|-h|--help) usage ;; -bootstrap|create|destroy|etcupdate|export|htop|import|list|mount|rdr|restart|setup|start|top|umount|update|upgrade|verify) +bootstrap|clone|create|destroy|etcupdate|export|htop|import|list|mount|rdr|rename|restart|setup|start|top|umount|update|upgrade|verify) # Nothing "extra" to do for these commands. -- cwells ;; -clone|config|cmd|console|convert|cp|edit|limits|pkg|rcp|rename|service|stop|sysrc|tags|template|zfs) +config|cmd|console|convert|cp|edit|limits|pkg|rcp|service|stop|sysrc|tags|template|zfs) # Parse the target and ensure it exists. -- cwells if [ $# -eq 0 ]; then # No target was given, so show the command's help. -- cwells PARAMS='help' From abdf885c3a738c357772b416a51f146ea1cc631b Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 18 Jan 2025 17:47:13 -0700 Subject: [PATCH 34/59] common: Comment about MAC prefix --- usr/local/share/bastille/common.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/usr/local/share/bastille/common.sh b/usr/local/share/bastille/common.sh index 1f4e2fa0..8c7e57e9 100644 --- a/usr/local/share/bastille/common.sh +++ b/usr/local/share/bastille/common.sh @@ -228,6 +228,7 @@ generate_static_mac() { local jail_name="${1}" local external_interface="${2}" local external_interface_mac="$(ifconfig ${external_interface} | grep ether | awk '{print $2}')" + # Use FreeBSD vendor prefix for jail MAC prefix local macaddr_prefix="58:9c:fc" local macaddr_suffix="$(echo -n "${external_interface_mac}${jail_name}" | sed 's#:##g' | sha256 | cut -b -5 | sed 's/\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F]\)/\1:\2:\3/')" if [ -z "${macaddr_prefix}" ] || [ -z "${macaddr_suffix}" ]; then @@ -363,4 +364,4 @@ checkyesno() { return 1 ;; esac -} +} \ No newline at end of file From 73b9b149319d1614bee646377f1d6b79a5b4f5a7 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 18 Jan 2025 22:10:23 -0700 Subject: [PATCH 35/59] clone: typos --- usr/local/share/bastille/clone.sh | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/usr/local/share/bastille/clone.sh b/usr/local/share/bastille/clone.sh index 290db01b..edb6c9f0 100644 --- a/usr/local/share/bastille/clone.sh +++ b/usr/local/share/bastille/clone.sh @@ -38,7 +38,7 @@ usage() { cat << EOF Options: - -a | --auto Auto mode. Start/stop jail(s) if required. Cannot be used with [-l|--live]. + -a | --auto Auto mode. Start/stop jail(s) if required. Cannot be used with [-l|--live]. -l | --live Clone a running jail. ZFS only. Jail must be running. Cannot be used with [-f|--force]. -x | --debug Enable debug mode. @@ -282,11 +282,11 @@ clone_jail() { if checkyesno bastille_zfs_enable; then if [ "${LIVE}" -eq 1 ]; then check_target_is_running "${TARGET}" || error_exit "[-l|--live] can only be used with a running jail." - else check_target_is_stopped "${TARGET}" || if [ "${FORCE}" -eq 1 ]; then + else check_target_is_stopped "${TARGET}" || if [ "${AUTO}" -eq 1 ]; then bastille stop "${TARGET}" else error_notify "Jail is running." - error_exit "Use [-f|--force] to force stop the jail, or [-l|--live] (ZFS only) to clone a running jail." + error_exit "Use [-a|--auto] to force stop the jail, or [-l|--live] (ZFS only) to clone a running jail." fi fi if [ -n "${bastille_zfs_zpool}" ]; then @@ -327,10 +327,7 @@ clone_jail() { else info "Cloned '${TARGET}' to '${NEWNAME}' successfully." fi - if [ "${AUTO}" -eq 1 ]; then - if [ "${LIVE}" -eq 0 ]; then - bastille start "${TARGET}" - fi + if [ "${AUTO}" -eq 1 ] || [ "${LIVE}" -eq 1 ]; then bastille start "${NEWNAME}" fi } From ef8a4e209fceb4d885ddd1d171427de8821a1d40 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 18 Jan 2025 22:14:13 -0700 Subject: [PATCH 36/59] clone: more typos --- usr/local/share/bastille/clone.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usr/local/share/bastille/clone.sh b/usr/local/share/bastille/clone.sh index edb6c9f0..6d2db6f8 100644 --- a/usr/local/share/bastille/clone.sh +++ b/usr/local/share/bastille/clone.sh @@ -305,11 +305,11 @@ clone_jail() { fi else # Perform container file copy (archive mode) - check_target_is_stopped "${TARGET}" || if [ "${FORCE}" -eq 1 ]; then + check_target_is_stopped "${TARGET}" || if [ "${AUTO}" -eq 1 ]; then bastille stop "${TARGET}" else error_notify "Jail is running." - error_exit "Use [-f|--force] to force stop the jail." + error_exit "Use [-a|--auto] to force stop the jail." fi cp -a "${bastille_jailsdir}/${TARGET}" "${bastille_jailsdir}/${NEWNAME}" fi From b2ba31984e4fbac05ea56f61c6b78c45090d5514 Mon Sep 17 00:00:00 2001 From: ejherlig Date: Sun, 19 Jan 2025 12:25:02 +0000 Subject: [PATCH 37/59] Create config.rst The "config" subcommand exists but is not documented. This file documents the subcommand with a few examples. --- docs/chapters/subcommands/config.rst | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docs/chapters/subcommands/config.rst diff --git a/docs/chapters/subcommands/config.rst b/docs/chapters/subcommands/config.rst new file mode 100644 index 00000000..aa583ca4 --- /dev/null +++ b/docs/chapters/subcommands/config.rst @@ -0,0 +1,32 @@ +======= +config +======= + +Gets or sets properties for a target container. + +.. code-block:: shell + + Usage: bastille config TARGET get|set propertyName [newValue] + +Getting a property that *is* defined in jail.conf: + +.. code-block:: shell + + ishmael ~ # bastille config azkaban get ip4.addr + 192.168.2.23 + +Getting a property that *is not* defined in jail.conf + +.. code-block:: shell + + ishmael ~ # bastille config azkaban get notaproperty + not set + +Setting a property: + +.. code-block:: shell + + ishmael ~ # bastille config azkaban set ip4.addr 192.168.2.24 + A restart is required for the changes to be applied. See 'bastille restart azkaban'. + +The restart message will appear every time a property is set. From 1fc84bc16876116aa08df5848fbd03e4c6d54837 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sun, 19 Jan 2025 08:14:24 -0700 Subject: [PATCH 38/59] clone: Fix retrieving ext if MAC on bridge --- usr/local/share/bastille/clone.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/usr/local/share/bastille/clone.sh b/usr/local/share/bastille/clone.sh index 6d2db6f8..c967cd85 100644 --- a/usr/local/share/bastille/clone.sh +++ b/usr/local/share/bastille/clone.sh @@ -205,8 +205,6 @@ update_jailconf_vnet() { _target_host_epair="${_if}a" _target_jail_epair="${_if}b" fi - # Replace epair name in jail.conf - sed -i '' "s|${_if}|epair${_num}|g" "${_jail_conf}" # Replace host epair name in jail.conf sed -i '' "s|up name ${_target_host_epair}|up name ${_new_host_epair}|g" "${_jail_conf}" sed -i '' "s|${_target_host_epair} ether|${_new_host_epair} ether|g" "${_jail_conf}" @@ -219,11 +217,14 @@ update_jailconf_vnet() { sed -i '' "s|${_target_jail_epair} ether|${_new_jail_epair} ether|g" "${_jail_conf}" # If jail had a static MAC, generate one for clone if grep -q ether ${_jail_conf}; then - local external_interface="$(grep "${_new_host_epair}" ${_jail_conf} | grep -o '[^ ]* addm' | awk '{print $1}')" + local external_interface="$(grep "epair${_num}a" ${_jail_conf} | grep -o '[^ ]* addm' | awk '{print $1}')" generate_static_mac "${NEWNAME}" "${external_interface}" sed -i '' "s|${_new_host_epair} ether.*:.*:.*:.*:.*:.*a\";|${_new_host_epair} ether ${macaddr}a\";|" "${_jail_conf}" sed -i '' "s|${_new_jail_epair} ether.*:.*:.*:.*:.*:.*b\";|${_new_jail_epair} ether ${macaddr}b\";|" "${_jail_conf}" fi + # Replace epair name in jail.conf + sed -i '' "s|${_if}|epair${_num}|g" "${_jail_conf}" + # Replace epair description sed -i '' "s|vnet host interface for Bastille jail ${TARGET}|vnet host interface for Bastille jail ${NEWNAME}|g" "${_jail_conf}" # Update /etc/rc.conf local _jail_vnet="$(grep ${_target_jail_epair} "${_rc_conf}" | grep -Eo -m 1 "vnet[0-9]+")" From c1537e2a206cdf1c7afcaafe00c1a538a72a2242 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sun, 19 Jan 2025 08:22:12 -0700 Subject: [PATCH 39/59] clone: Spacing -1 --- usr/local/share/bastille/clone.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/usr/local/share/bastille/clone.sh b/usr/local/share/bastille/clone.sh index c967cd85..283def73 100644 --- a/usr/local/share/bastille/clone.sh +++ b/usr/local/share/bastille/clone.sh @@ -222,9 +222,9 @@ update_jailconf_vnet() { sed -i '' "s|${_new_host_epair} ether.*:.*:.*:.*:.*:.*a\";|${_new_host_epair} ether ${macaddr}a\";|" "${_jail_conf}" sed -i '' "s|${_new_jail_epair} ether.*:.*:.*:.*:.*:.*b\";|${_new_jail_epair} ether ${macaddr}b\";|" "${_jail_conf}" fi - # Replace epair name in jail.conf - sed -i '' "s|${_if}|epair${_num}|g" "${_jail_conf}" - # Replace epair description + # Replace epair name in jail.conf + sed -i '' "s|${_if}|epair${_num}|g" "${_jail_conf}" + # Replace epair description sed -i '' "s|vnet host interface for Bastille jail ${TARGET}|vnet host interface for Bastille jail ${NEWNAME}|g" "${_jail_conf}" # Update /etc/rc.conf local _jail_vnet="$(grep ${_target_jail_epair} "${_rc_conf}" | grep -Eo -m 1 "vnet[0-9]+")" From 10c82964e3b75dc34a30f4aec9f9cbfc22678495 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sun, 19 Jan 2025 08:27:41 -0700 Subject: [PATCH 40/59] clone: Change MAC after IF --- usr/local/share/bastille/clone.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usr/local/share/bastille/clone.sh b/usr/local/share/bastille/clone.sh index 283def73..9c945f94 100644 --- a/usr/local/share/bastille/clone.sh +++ b/usr/local/share/bastille/clone.sh @@ -215,6 +215,8 @@ update_jailconf_vnet() { sed -i '' "s|= ${_target_jail_epair};|= ${_new_jail_epair};|g" "${_jail_conf}" sed -i '' "s|up name ${_target_jail_epair}|up name ${_new_jail_epair}|g" "${_jail_conf}" sed -i '' "s|${_target_jail_epair} ether|${_new_jail_epair} ether|g" "${_jail_conf}" + # Replace epair name in jail.conf + sed -i '' "s|${_if}|epair${_num}|g" "${_jail_conf}" # If jail had a static MAC, generate one for clone if grep -q ether ${_jail_conf}; then local external_interface="$(grep "epair${_num}a" ${_jail_conf} | grep -o '[^ ]* addm' | awk '{print $1}')" @@ -222,8 +224,6 @@ update_jailconf_vnet() { sed -i '' "s|${_new_host_epair} ether.*:.*:.*:.*:.*:.*a\";|${_new_host_epair} ether ${macaddr}a\";|" "${_jail_conf}" sed -i '' "s|${_new_jail_epair} ether.*:.*:.*:.*:.*:.*b\";|${_new_jail_epair} ether ${macaddr}b\";|" "${_jail_conf}" fi - # Replace epair name in jail.conf - sed -i '' "s|${_if}|epair${_num}|g" "${_jail_conf}" # Replace epair description sed -i '' "s|vnet host interface for Bastille jail ${TARGET}|vnet host interface for Bastille jail ${NEWNAME}|g" "${_jail_conf}" # Update /etc/rc.conf From 4fc9426bc129ac069b89b0e59adc93fc787fd380 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 20 Jan 2025 12:36:27 -0700 Subject: [PATCH 41/59] upgrade: let users know to restart and run install command again --- usr/local/share/bastille/upgrade.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/local/share/bastille/upgrade.sh b/usr/local/share/bastille/upgrade.sh index 2be09435..7df54354 100644 --- a/usr/local/share/bastille/upgrade.sh +++ b/usr/local/share/bastille/upgrade.sh @@ -152,7 +152,7 @@ jail_upgrade() { # Update "osrelease" entry inside jail.conf sed -i '' "/osrelease/ s|${_oldrelease}|${_newrelease}|g" "${bastille_jailsdir}/${TARGET}/jail.conf" echo - echo -e "${COLOR_YELLOW}Please run 'bastille upgrade ${TARGET} install' to finish installing updates.${COLOR_RESET}" + echo -e "${COLOR_YELLOW}Please run 'bastille upgrade ${TARGET} install', restart the jail, then run 'bastille upgrade ${TARGET} install' again to finish installing updates.${COLOR_RESET}" fi } From 0bf87b1980b7e2626036543077748d9b06829533 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 20 Jan 2025 18:28:33 -0700 Subject: [PATCH 42/59] mount: Add debug mode --- usr/local/share/bastille/mount.sh | 33 ++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index 5895823a..9c7a450e 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -34,15 +34,34 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille mount TARGET HOST_PATH JAIL_PATH [filesystem_type options dump pass_number]" + error_notify "Usage: bastille mount TARGET HOST_PATH JAIL_PATH [filesystem_type options dump pass_number]" + cat << EOF + Options: + + -x | --debug Enable debug mode. + +EOF + exit 1 } -# Handle special-case commands first. -case "${1}" in - help|-h|--help) - usage - ;; -esac +# Handle options. +while [ "$#" -gt 0 ]; do + case "${1}" in + -h|--help|help) + usage + ;; + -x|--debug) + enable_debug + shift + ;; + -*) + error_exit "Unknown Option: \"${1}\"" + ;; + *) + break + ;; + esac +done if [ "$#" -lt 3 ] || [ "$#" -gt 7 ]; then usage From caee31a62118244776d4e20b89363ff4dd4db58e Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 20 Jan 2025 18:30:23 -0700 Subject: [PATCH 43/59] mount: Spacing --- usr/local/share/bastille/mount.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index 9c7a450e..5aa624f6 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -47,9 +47,9 @@ EOF # Handle options. while [ "$#" -gt 0 ]; do case "${1}" in - -h|--help|help) - usage - ;; + -h|--help|help) + usage + ;; -x|--debug) enable_debug shift From 391abe2335c35158d8f53eeff5df689e05383b31 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 20 Jan 2025 18:32:35 -0700 Subject: [PATCH 44/59] mount: just change "must start with" to "must include" for documentation --- usr/local/share/bastille/mount.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index 5aa624f6..4ff5d88c 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -110,7 +110,7 @@ elif [ ! -e "${_hostpath}" ] || [ "${_type}" != "nullfs" ]; then usage fi -# Mount permissions,options must start with one of "ro, rw, rq, sw, xx" +# Mount permissions,options must include one of "ro, rw, rq, sw, xx" if ! echo "${_perms}" | grep -Eq '(ro|rw|rq|sw|xx)(,.*)?$'; then error_notify "Detected invalid mount permissions in FSTAB." warn "Format: /host/path /jail/path nullfs ro 0 0" From a49d58124d4da40a6e3cd48caddbdf65a2c6215a Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 20 Jan 2025 18:33:20 -0700 Subject: [PATCH 45/59] docs: Mount fix --- docs/chapters/subcommands/mount.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/chapters/subcommands/mount.rst b/docs/chapters/subcommands/mount.rst index 172799ad..2f37f47b 100644 --- a/docs/chapters/subcommands/mount.rst +++ b/docs/chapters/subcommands/mount.rst @@ -10,7 +10,7 @@ Syntax follows standard `/etc/fstab` format: Usage: bastille mount TARGET HOST_PATH JAIL_PATH [filesystem_type options dump pass_number] -The 'options' string can include a comma-separated list of mount options, but must start with one of (rw,ro,rq,sw,xx) according to fstab documentation. +The 'options' string can include a comma-separated list of mount options, but must include one of (rw,ro,rq,sw,xx) according to fstab documentation. Example: Mount a tmpfs filesystem with options. .. code-block:: shell From c27f0a7408374f5c66fcf7a7e61ea2582819a515 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 20 Jan 2025 18:36:54 -0700 Subject: [PATCH 46/59] mount: Add options block to notify message --- usr/local/share/bastille/mount.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index 4ff5d88c..db69638d 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -34,7 +34,7 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_notify "Usage: bastille mount TARGET HOST_PATH JAIL_PATH [filesystem_type options dump pass_number]" + error_notify "Usage: bastille mount [option(s)] TARGET HOST_PATH JAIL_PATH [filesystem_type options dump pass_number]" cat << EOF Options: From 90777ca37e52517c3dfa53a9935cbd2b111c0601 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 20 Jan 2025 18:38:47 -0700 Subject: [PATCH 47/59] mount: Stay consistent with "Unknown Option." --- usr/local/share/bastille/mount.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index db69638d..d9281696 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -55,7 +55,7 @@ while [ "$#" -gt 0 ]; do shift ;; -*) - error_exit "Unknown Option: \"${1}\"" + error_exit "Unknown Option." ;; *) break From c790e65f13fb9c61fb95a993dce651a987f1a2c2 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 20 Jan 2025 18:42:39 -0700 Subject: [PATCH 48/59] mount: Call usage on unknown option --- usr/local/share/bastille/mount.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index d9281696..7903eedb 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -54,8 +54,9 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) - error_exit "Unknown Option." + --*|-*) + error_notify "Unknown Option." + usage ;; *) break From dee9ab08652a3af6ec3ab57bbe825a7f0bb58813 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 20 Jan 2025 18:52:16 -0700 Subject: [PATCH 49/59] mount: Remove debug option for later addition --- usr/local/share/bastille/mount.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index 7903eedb..b9b2da2c 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -50,10 +50,6 @@ while [ "$#" -gt 0 ]; do -h|--help|help) usage ;; - -x|--debug) - enable_debug - shift - ;; --*|-*) error_notify "Unknown Option." usage From f0072cebbd1324dcee819931df85074bedba168c Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Mon, 20 Jan 2025 18:53:04 -0700 Subject: [PATCH 50/59] mount: Do not show debug as an option --- usr/local/share/bastille/mount.sh | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index b9b2da2c..e2c060e6 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -34,14 +34,7 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_notify "Usage: bastille mount [option(s)] TARGET HOST_PATH JAIL_PATH [filesystem_type options dump pass_number]" - cat << EOF - Options: - - -x | --debug Enable debug mode. - -EOF - exit 1 + error_exit "Usage: bastille mount [option(s)] TARGET HOST_PATH JAIL_PATH [filesystem_type options dump pass_number]" } # Handle options. From af78f2b74d1ff9696ff59c22dfb82b4372f6b633 Mon Sep 17 00:00:00 2001 From: JRGTH Date: Tue, 21 Jan 2025 05:55:37 -0400 Subject: [PATCH 51/59] Initial 'bastille setup' cmd rewrite/enhancements This PR will add the Initial 'bastille setup' command rewrite and enhancements, includes the ZFS activation helper, also further enhancements will be added accordingly. Further testing/bug reporting welcome. --- usr/local/share/bastille/setup.sh | 879 +++++++++++++++++++++++++++--- 1 file changed, 806 insertions(+), 73 deletions(-) diff --git a/usr/local/share/bastille/setup.sh b/usr/local/share/bastille/setup.sh index 020d2cf4..bd22d4fa 100644 --- a/usr/local/share/bastille/setup.sh +++ b/usr/local/share/bastille/setup.sh @@ -1,7 +1,5 @@ #!/bin/sh # -# SPDX-License-Identifier: BSD-3-Clause -# # Copyright (c) 2018-2025, Christer Edwards # All rights reserved. # @@ -30,41 +28,410 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -bastille_config="/usr/local/etc/bastille/bastille.conf" +# Let's set some predefined/fallback variables. +bastille_config_path="/usr/local/etc/bastille" +bastille_config="${bastille_config_path}/bastille.conf" +bastille_prefix_default="/usr/local/bastille" +bastille_zfsprefix_default="bastille" +bastille_ifbridge_name="bastille1" + . /usr/local/share/bastille/common.sh # shellcheck source=/usr/local/etc/bastille/bastille.conf . ${bastille_config} usage() { - error_exit "Usage: bastille setup [pf|network|zfs|vnet]" + # Build an independent usage for the `setup` command. + # No short options here for the special purpose --long-options, + # so we can reserve short options for future adds, also the user + # must genuinely agreed on configuration reset/restore so let them type for it. + error_notify "Usage: bastille setup [option]" + + cat << EOF + Options: + + -p | --firewall -- Attempt to configure bastille PF firewall. + -n | --network -- Attempt to configure network loopback interface. + -v | --vnet -- Attempt to configure VNET bridge interface [bastille1]. + -z | --zfs -- Activates ZFS storage features and benefits for bastille. + --conf-network-reset -- Restore bastille default Network options on the config file. + --conf-storage-reset -- Restore bastille default ZFS storage options on the config file. + --conf-restore-clean -- Restore bastille default config file from bastille.conf.sample file. + +EOF + exit 1 } -# Check for too many args +input_error() { + error_exit "Invalid user input, aborting!" +} + +config_runtime() { + # Run here variables considered to be required by bastille by default silently. + if ! sysrc -qn bastille_enable | grep -qi "yes"; then + sysrc bastille_enable="YES" >/dev/null 2>&1 + fi +} + +# Check for too many args. if [ $# -gt 1 ]; then usage fi -# Configure bastille loopback network interface -configure_network() { - info "Configuring ${bastille_network_loopback} loopback interface" - sysrc cloned_interfaces+=lo1 - sysrc ifconfig_lo1_name="${bastille_network_loopback}" +# Handle special-case commands first. +case "${1}" in + help|--help|-h) + usage + ;; +esac - info "Bringing up new interface: ${bastille_network_loopback}" +user_canceled() { + # Don't use 'error_exit' here as this only should inform the user, not panic them. + info "Cancelled by user, exiting!" + exit 1 +} + +config_backup() { + # Create bastille configuration backup with system time appended. + # This should be called each time `bastille setup` attempts to + # write to bastille configuration file. + BACKUP_DATE=$(date +%Y%m%d-%H%M%S) + cp "${bastille_config}" "${bastille_config}.${BACKUP_DATE}" + BACKUP_NAME="${bastille_config}.${BACKUP_DATE}" + info "Config backup created in: [${BACKUP_NAME}]" +} + +config_network_reset() { + # Restore bastille default network options. + warn "Performing Network configuration reset, requested by the user..." + read -p "$(warn "Do you really want to reset 'bastille' network configuration? [y/N]: ")" _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + local VAR_ITEMS="bastille_network_loopback=bastille0 bastille_network_pf_ext_if=ext_if + bastille_network_pf_table=jails bastille_network_shared= bastille_network_gateway= bastille_network_gateway6=" + for _item in ${VAR_ITEMS}; do + sysrc -f "${bastille_config}" ${_item} + done + info "Network configuration has been reset successfully!" + exit 0 + ;; + [Nn]|[Nn][Oo]) + user_canceled + ;; + *) + input_error + ;; + esac +} + +config_storage_reset() { + # Restore bastille default ZFS storage options. + warn "Performing ZFS configuration reset, requested by the user..." + read -p "$(warn "Do you really want to reset 'bastille' ZFS configuration? [y/N]: ")" _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + local VAR_ITEMS="bastille_zfs_enable= bastille_zfs_zpool= bastille_zfs_prefix=bastille" + for _item in ${VAR_ITEMS}; do + sysrc -f "${bastille_config}" ${_item} + done + + # Let's configure variables with complex values individually to keep it simple/readable for everyone. + sysrc -f "${bastille_config}" bastille_zfs_options="-o compress=lz4 -o atime=off" + sysrc -f "${bastille_config}" bastille_prefix="${bastille_prefix_default}" + info "ZFS configuration has been reset successfully!" + exit 0 + ;; + [Nn]|[Nn][Oo]) + user_canceled + ;; + *) + input_error + ;; + esac +} + +config_restore_global() { + local _response + # This will restore bastille default configuration file from the sample config file. + # Be aware that if the sample configuration file is missing, we can generate a new one, + # but that's highly unlikely to happen so will keep the code smaller here. + warn "Performing Bastille default configuration restore, requested by the user..." + read -p "$(warn "Do you really want to restore 'bastille' default configuration file and start over? [y/N]: ")" _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + config_backup + if [ -f "${bastille_config}.sample" ]; then + mv "${bastille_config}" "${bastille_config}.${BACKUP_DATE}" + cp "${bastille_config}.sample" "${bastille_config}" + else + error_exit "Bastille sample configuration file is missing, exiting." + fi + info "Bastille configuration file restored successfully!" + exit 0 + ;; + [Nn]|[Nn][Oo]) + user_canceled + ;; + *) + input_error + ;; + esac +} + +get_zfs_params() { + info "Reading on-disk and bastille ZFS config parameters..." + # Always try to detect and recover on-disk ZFS bastille configuration first. + # Bastille ZFS prefix is always set to "bastille" in the config file by default, + # so will keep things simple here, or considered custom setup if this variable is changed. + BARTILLE_ROOTFS=$(mount | awk '/ \/ / {print $1}') + BASTILLE_UFSBOOT= + BASTILLE_ZFSPOOL= + BASTILLE_PREFIXDEF= + BASTILLE_ZFSENABLE= + BASTILLE_PREFIX_MATCH= + + # Check if the system boots from ZFS. + if echo "${BARTILLE_ROOTFS}" | grep -q -m 1 -E "^/dev/"; then + # Assume the host is running from UFS. + info "This system doesn't boot from ZFS, looking for alternate configuration." + BASTILLE_UFSBOOT="1" + fi + + BASTILLE_PREFIXCONF=$(sysrc -qn -f "${bastille_config}" bastille_prefix) + BASTILLE_PREFIXZFS=$(sysrc -qn -f "${bastille_config}" bastille_zfs_prefix) + + if [ -z "${BASTILLE_PREFIXZFS}" ]; then + BASTILLE_PREFIXZFS="${bastille_zfsprefix_default}" + fi + + if [ -z "${BASTILLE_UFSBOOT}" ]; then + if [ "${BASTILLE_PREFIXZFS}" != "${bastille_zfsprefix_default}" ]; then + BASTILLE_CUSTOM_CONFIG="1" + fi + fi + + # Try to determine "zroot" pool name as it may happens that the user + # customized the "zroot" pool name during the initial FreeBSD installation. + if [ -z "${BASTILLE_UFSBOOT}" ]; then + #BASTILLE_ZFSPOOL=$(df ${bastille_config_path} 2>/dev/null | sed 1d | awk -F '/' '{print $1}') + BASTILLE_ZFSPOOL=$(zfs list -H ${bastille_config_path} 2>/dev/null | awk -F '/' '{print $1}') + fi + + if [ -z "${BASTILLE_UFSBOOT}" ]; then + BASTILLE_PREFIXDEF=$(zfs list -H "${BASTILLE_ZFSPOOL}/${BASTILLE_PREFIXZFS}" 2>/dev/null | awk '{print $5}') + fi + + if [ -n "${BASTILLE_UFSBOOT}" ]; then + # Make sure bastille_prefix is listed by ZFS then try to get bastille_zfs_pool from it. + # Make some additional checks for non ZFS boot systems, also rely on some 'bastille.conf' ZFS parameters. + BASTILLE_PREFIXLOOK=$(zfs list -H "${BASTILLE_PREFIXCONF}" 2>/dev/null | awk '{print $1}') + BASTILLE_ZFSPOOL=$(zfs list -H "${BASTILLE_PREFIXLOOK}" 2>/dev/null | awk -F '/' '{print $1}') + BASTILLE_PREFIXDEF=$(zfs list -H "${BASTILLE_PREFIXCONF}" 2>/dev/null | awk '{print $5}') + + else + # Fallback to default config. + if [ -z "${BASTILLE_PREFIXDEF}" ]; then + BASTILLE_PREFIXDEF="${bastille_prefix_default}" + fi + fi + + if [ "${BASTILLE_PREFIXDEF}" = "${BASTILLE_PREFIXCONF}" ]; then + BASTILLE_PREFIX_MATCH="1" + fi + + # Update 'bastille_prefix' if a custom dataset is detected while reading on-disk configuration. + if [ ! -d "${bastille_prefix}" ] || [ -n "${ZFS_DATASET_DETECT}" ] || [ -n "${BASTILLE_PREFIXDEF}" ]; then + BASTILLE_ZFSENABLE="YES" + bastille_prefix="${BASTILLE_PREFIXDEF}" + else + BASTILLE_ZFSENABLE="NO" + if [ -z "${BASTILLE_UFSBOOT}" ]; then + BASTILLE_PREFIXZFS="" + fi + fi +} + +config_validation(){ + # Perform a basic bastille ZFS configuration check, + if [ -d "${bastille_prefix}" ] && [ -n "${BASTILLE_PREFIX_MATCH}" ] && echo "${bastille_zfs_enable}" | grep -qi "yes" \ + && zfs list "${bastille_zfs_zpool}/${bastille_zfs_prefix}" >/dev/null 2>&1; then + info "Looks like Bastille ZFS storage features has been activated successfully!." + exit 0 + else + if [ ! -d "${bastille_prefix}" ] && [ -z "${BASTILLE_ZFSPOOL}" ]; then + zfs_initial_activation + else + if ! echo "${bastille_zfs_enable}" | grep -qi "no"; then + + # Inform the user bastille ZFS configuration has been tampered and/or on-disk ZFS config has changed. + error_exit "Bastille ZFS misconfiguration detected, please refer to 'bastille.conf' or see 'bastille setup --config-reset'." + fi + fi + fi +} + +show_zfs_params() { + # Show a brief info of the detected and/or pending bastille ZFS configuration parameters. + # Don't need to show bastille zfs enable as this will be enabled by default. + info "*************************************" + info "Bastille Storage Prefix: [${BASTILLE_PREFIXDEF}]" + info "Bastille ZFS Pool: [${BASTILLE_ZFSPOOL}]" + info "Bastille ZFS Prefix: [${BASTILLE_PREFIXZFS}]" + info "*************************************" +} + +write_zfs_opts() { + # Write/update to bastille config file the required and/or misssing parameters. + if [ -z "${bastille_prefix}" ] || [ "${BASTILLE_PREFIXDEF}" != "${bastille_prefix_default}" ]; then + if [ -z "${BASTILLE_PREFIX_MATCH}" ]; then + sysrc -f "${bastille_config}" bastille_prefix="${BASTILLE_PREFIXDEF}" + fi + else + if [ -z "${BASTILLE_PREFIXCONF}" ] && [ -n "${BASTILLE_PREFIXDEF}" ]; then + sysrc -f "${bastille_config}" bastille_prefix="${BASTILLE_PREFIXDEF}" + fi + fi + + if [ -z "${bastille_zfs_enable}" ]; then + sysrc -f "${bastille_config}" bastille_zfs_enable="${BASTILLE_ZFSENABLE}" + fi + if [ -z "${bastille_zfs_zpool}" ]; then + sysrc -f "${bastille_config}" bastille_zfs_zpool="${BASTILLE_ZFSPOOL}" + fi + if [ -z "${bastille_zfs_prefix}" ] || [ "${BASTILLE_PREFIXDEF}" != "${bastille_zfs_prefix}" ]; then + sysrc -f "${bastille_config}" bastille_zfs_prefix="${BASTILLE_PREFIXZFS}" + fi + info "ZFS has been enabled in bastille configuration successfully!" +} + +create_zfs_dataset(){ + info "Creating ZFS dataset [${BASTILLE_ZFSPOOL}/${BASTILLE_PREFIXZFS}] for bastille..." + + if [ -n "${BASTILLE_CONFIG_USER}" ]; then + bastille_prefix="${BASTILLE_PREFIXDEF}" + fi + + # shellcheck disable=SC1073 + if zfs list "${BASTILLE_ZFSPOOL}/${BASTILLE_PREFIXZFS}" >/dev/null 2>&1; then + info "Dataset ${BASTILLE_ZFSPOOL}/${BASTILLE_PREFIXZFS} already exist, skipping." + else + if ! zfs create -p "${bastille_zfs_options}" -o mountpoint="${bastille_prefix}" "${BASTILLE_ZFSPOOL}/${BASTILLE_PREFIXZFS}"; then + error_exit "Failed to create 'bastille_prefix' dataset, exiting." + fi + fi + chmod 0750 "${bastille_prefix}" + info "Bastille ZFS storage features has been activated successfully!" + exit 0 +} + +write_zfs_disable() { + # Explicitly disable ZFS in 'bastille_zfs_enable' + sysrc -f "${bastille_config}" bastille_zfs_enable="NO" + info "ZFS has been disabled in bastille configuration successfully!" +} + +write_zfs_enable() { + # Explicitly enable ZFS in 'bastille_zfs_enable' + # Just empty the 'bastille_zfs_enable' variable so the user can re-run the ZFS activation helper. + # Don't put "YES" here as it will trigger the ZFS validation and failing due missing and/or invalid configuration. + sysrc -f "${bastille_config}" bastille_zfs_enable="" + info "ZFS activation helper enabled!" +} + +zfs_initial_activation() { + local _response= + + # Just let the user interactively select the ZFS items manually from a list for the initial activation. + # This should be performed before `bastille bootstrap` as we already know. + info "Initial bastille ZFS activation helper invoked." + #read -p "$(info "Would you like bastille attempt to auto-detect/activate ZFS for you?, (assuming a standard install was performed) [y/N]: ")" _response + read -p "$(info "Would you like to configure the bastille ZFS options interactively? [y/N]: ")" _response + + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + # Assume the user knows what hes/she doing and want to configure ZFS parameters interactively. + configure_zfs_manually + ;; + [Nn]|[Nn][Oo]) + # Assume the user will manually edit the ZFS parameters in the config file. + user_canceled + ;; + *) + input_error + ;; + esac +} + +configure_network() { + local _response + + # Configure bastille loopback network interface. + # This is an initial attempt to make this function interactive, + # however this may be enhanced in the future by advanced contributors in this topic. + info "This will attempt to configure the loopback network interface [${bastille_network_loopback}]." + read -p "$(warn "Would you like to configure the loopback network interface now? [y/N]: ")" _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + # shellcheck disable=SC2104 + break + ;; + [Nn]|[Nn][Oo]) + user_canceled + ;; + *) + input_error + ;; + esac + + info "Configuring ${bastille_network_loopback} loopback interface..." + if ! sysrc -qn cloned_interfaces | grep -qi "lo1"; then + sysrc cloned_interfaces+="lo1" + fi + if ! sysrc -qn ifconfig_lo1_name | grep -qi "${bastille_network_loopback}"; then + sysrc ifconfig_lo1_name="${bastille_network_loopback}" + fi + + info "Bringing up new interface: ${bastille_network_loopback}..." service netif cloneup } configure_vnet() { - info "Configuring bridge interface" - sysrc cloned_interfaces+=bridge1 - sysrc ifconfig_bridge1_name=bastille1 + local _response - info "Bringing up new interface: bastille1" + # This is an initial attempt to make this function interactive, + # however this may be enhanced in the future by advanced contributors in this topic. + info "This will attempt to configure the VNET bridge interface [${bastille_ifbridge_name}]." + read -p "$(warn "Would you like to configure the VNET bridge interface now? [y/N]: ")" _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + # shellcheck disable=SC2104 + break + ;; + [Nn]|[Nn][Oo]) + user_canceled + ;; + *) + input_error + ;; + esac + + info "Configuring bridge interface [${bastille_ifbridge_name}]..." + + if ! sysrc -qn cloned_interfaces | grep -qi "${bastille_ifbridge_name}"; then + sysrc cloned_interfaces+="${bastille_ifbridge_name}" + fi + if ! sysrc -qn ifconfig_bridge1_name | grep -qi "${bastille_ifbridge_name}"; then + sysrc ifconfig_bridge1_name="${bastille_ifbridge_name}" + fi + + info "Bringing up new interface: ${bastille_ifbridge_name}..." service netif cloneup - if [ ! -f /etc/devfs.rules ]; then - info "Creating bastille_vnet devfs.rules" + if [ ! -f "/etc/devfs.rules" ]; then + info "Creating bastille_vnet devfs.rules..." cat << EOF > /etc/devfs.rules +# Auto-generated file from `bastille setup` +# devfs configuration information + [bastille_vnet=13] add include \$devfsrules_hide_all add include \$devfsrules_unhide_basic @@ -73,22 +440,47 @@ add include \$devfsrules_jail add include \$devfsrules_jail_vnet add path 'bpf*' unhide EOF + else + warn "File [/etc/devfs.rules] already exist, skipping." + exit 1 fi + exit 0 } -# Configure pf firewall configure_pf() { -# shellcheck disable=SC2154 -if [ ! -f "${bastille_pf_conf}" ]; then - # shellcheck disable=SC3043 - local ext_if - ext_if=$(netstat -rn | awk '/default/ {print $4}' | head -n1) - info "Determined default network interface: ($ext_if)" - info "${bastille_pf_conf} does not exist: creating..." + local _response + + # Configure the PF firewall. + # This is an initial attempt to make this function interactive, + # however this may be enhanced in the future by advanced contributors in this topic. + info "This will attempt to configure the PF firewall parameters in [${bastille_pf_conf}]." + read -p "$(warn "Would you like to configure the PF firewall parameters now? [y/N]: ")" _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + # shellcheck disable=SC2104 + break + ;; + [Nn]|[Nn][Oo]) + user_canceled + ;; + *) + input_error + ;; + esac + + # shellcheck disable=SC2154 + if [ ! -f "${bastille_pf_conf}" ]; then + # shellcheck disable=SC3043 + local ext_if + ext_if=$(netstat -rn | awk '/default/ {print $4}' | head -n1) + info "Determined default network interface: ($ext_if)" + info "${bastille_pf_conf} does not exist: creating..." + + # Creating pf.conf file. + cat << EOF > "${bastille_pf_conf}" +# Auto-generated file from `bastille setup` +# packet filter configuration file - ## creating pf.conf - cat << EOF > "${bastille_pf_conf}" -## generated by bastille setup ext_if="$ext_if" set block-policy return @@ -104,58 +496,399 @@ pass out quick keep state antispoof for \$ext_if inet pass in inet proto tcp from any to any port ssh flags S/SA keep state EOF - sysrc pf_enable=YES - warn "pf ruleset created, please review ${bastille_pf_conf} and enable it using 'service pf start'." -else - error_exit "${bastille_pf_conf} already exists. Exiting." -fi + + if ! sysrc -qn pf_enable | grep -qi "yes"; then + sysrc pf_enable="YES" + fi + warn "The pf ruleset file has been created, please review '${bastille_pf_conf}' and enable it using 'service pf start'." + else + warn "${bastille_pf_conf} already exists, skipping." + exit 1 + fi + exit 0 } -# Configure ZFS configure_zfs() { - if [ ! "$(kldstat -m zfs)" ]; then - info "ZFS module not loaded; skipping..." + # Attempt to detect and setup either new or an existing bastille ZFS on-disk configuration. + # This is useful for new users to easily activate the bastille ZFS parameters on a standard installation, + # or to recover an existing on-disk ZFS bastille configuration in case the config file has been borked/reset by the user, + # also a config backup will be created each time the config needs to be modified in the following format: bastille.conf.YYYYMMDD-HHMMSS + # Be aware that the users now need to explicitly enable ZFS in the config file due later config file changes, failing to do so + # before initial `bastille bootstrap` will private the user from activating ZFS storage features without manual intervention. + + ZFS_DATASET_DETECT= + BASTILLE_CUSTOM_CONFIG= + BASTILLE_INITIAL_CONFIG= + local _response= + + if ! kldstat -qm zfs; then + warn "Looks like the ZFS module is not loaded." + warn "If this is not a dedicated ZFS system you can ignore this warning." + exit 1 else - ## attempt to determine bastille_zroot from `zpool list` - bastille_zroot=$(zpool list | grep -v NAME | awk '{print $1}') - if [ "$(echo "${bastille_zroot}" | wc -l)" -gt 1 ]; then - error_notify "Error: Multiple ZFS pools available:\n${bastille_zroot}" - error_notify "Set desired pool using \"sysrc -f ${bastille_config} bastille_zfs_zpool=ZPOOL_NAME\"" - error_exit "Don't forget to also enable ZFS using \"sysrc -f ${bastille_config} bastille_zfs_enable=YES\"" + # If the below statement becomes true, will assume that the user do not want ZFS activation at all regardless of the + # host filesystem, or the default configuration file has been changed officially and set to "NO" by default. + if echo "${bastille_zfs_enable}" | grep -qi "no"; then + info "Looks like Bastille ZFS has been disabled in 'bastille.conf', ZFS activation helper disabled." + read -p "$(warn "Would you like to enable the ZFS activation helper now? [y/N]: ")" _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + # Assume the user wants to configure the ZFS parameters. + if config_backup; then + write_zfs_enable + warn "Please run 'bastille setup' again or consult bastille.conf for further configuration." + exit 0 + else + error_exit "Config backup creation failed, exiting." + fi + ;; + [Nn]|[Nn][Oo]) + # Assume the user will manually configure the ZFS parameters, or skip ZFS configuration. + user_canceled + ;; + esac + else + # Attempt to detect if bastille was installed with sane defaults(ports/pkg) and hasn't been bootstrapped yet, + # then offer the user initial ZFS activation option to gain all of the ZFS storage features and benefits. + # This should be performed before `bastille` initial bootstrap because several ZFS datasets will be + # created/configured during the bootstrap process by default. + get_zfs_params + if [ ! -d "${bastille_prefix}" ] && [ -n "${BASTILLE_ZFSPOOL}" ]; then + if [ "${bastille_prefix}" = "${bastille_prefix_default}" ] && [ -z "${BASTILLE_CUSTOM_CONFIG}" ]; then + show_zfs_params + info "Looks like bastille has been installed and hasn't been bootstrapped yet." + read -p "$(warn "Would you like to activate ZFS now to get the features and benefits? [y/N]"): " _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + if [ -n "${BASTILLE_ZFSPOOL}" ]; then + info "Attempting to create a backup file of the current bastille.conf file..." + if config_backup; then + write_zfs_opts + create_zfs_dataset + else + error_exit "Config backup creation failed, exiting." + fi + else + error_exit "Unable to determine the [zroot] pool name, exiting" + fi + ;; + [Nn]|[Nn][Oo]) + info "Looks like you cancelled the ZFS activation." + # Offer the user option to disable ZFS in the configuration file. + # Maybe the user wants to use UFS or ZFS with legacy directories instead. + read -p "$(warn "Would you like to explicitly disable ZFS in the configuration file? [y/N]: ")" _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + if config_backup; then + # Assume the user want to skip ZFS configuration regardless. + write_zfs_disable + exit 0 + else + error_exit "Config backup creation failed, exiting." + fi + ;; + [Nn]|[Nn][Oo]) + # Assume the user will manually configure the ZFS parameters by itself. + user_canceled + ;; + *) + input_error + ;; + esac + ;; + *) + input_error + ;; + esac + else + config_validation + fi + else + if [ -d "${bastille_prefix}" ] && [ -z "${bastille_zfs_enable}" ] && [ -z "${bastille_zfs_zpool}" ] && [ -z "${BASTILLE_CUSTOM_CONFIG}" ] && [ -z "${BASTILLE_UFSBOOT}" ]; then + show_zfs_params + # This section is handy if the user has reset the bastille configuration file after a successful ZFS activation. + info "Looks like bastille has been bootstrapped already, but ZFS options are not configured." + info "Attempting to configure default ZFS options for you..." + if zfs list | grep -qw "${bastille_prefix}"; then + ZFS_DATASET_DETECT="1" + read -p "$(warn "Would you like to auto-configure the detected ZFS parameters now? [y/N]: ")" _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + if config_backup; then + write_zfs_opts + exit 0 + else + error_exit "Config backup creation failed, exiting." + fi + ;; + [Nn]|[Nn][Oo]) + # Assume the user will manually configure the ZFS parameters by itself. + user_canceled + ;; + *) + input_error + ;; + esac + else + if [ -d "${bastille_prefix}" ]; then + if [ ! "$(ls -A ${bastille_prefix})" ]; then + if ! zfs list | grep -qw "${bastille_prefix}"; then + # If the user want to use ZFS he/she need to remove/rename the existing 'bastille_prefix' directory manually. + # We do not want to cause existing data lost at all due end-user errors. + warn "Looks like bastille prefix is not a ZFS dataset, thus ZFS storage options are not required." + warn "Please refer to 'bastille.conf' and/or verify for alreay existing 'bastille_prefix' directory." + read -p "$(warn "Would you like to explicitly disable ZFS in the configuration file so we don't ask again? [y/N]: ")" _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + if config_backup; then + write_zfs_disable + exit 0 + else + error_exit "Config backup creation failed, exiting." + fi + ;; + [Nn]|[Nn][Oo]) + # Assume the user will manually configure the ZFS parameters by itself. + user_canceled + ;; + *) + input_error + ;; + esac + fi + else + error_exit "Looks like 'bastille_prefix' is not a ZFS dataset and is not empty, aborting." + fi + fi + fi + fi + if [ -n "${BASTILLE_CUSTOM_CONFIG}" ]; then + # Attempt to detect an existing on-disk bastille ZFS configuration and let the user interactively select the items manually from a list. + # This should be performed if the user has borked/reset the config file or in the event the setup detected an unusual/customized bastille install. + warn "A custom bastille ZFS configuration has been detected and/or unable to read ZFS configuration properly." + warn "Please refer to 'bastille.conf' config file and/or 'bastille setup -help' for additional info." + zfs_initial_activation + else + config_validation + fi + fi fi - sysrc -f "${bastille_config}" bastille_zfs_enable=YES - sysrc -f "${bastille_config}" bastille_zfs_zpool="${bastille_zroot}" fi } -# Run all base functions (w/o vnet) if no args -if [ $# -eq 0 ]; then - sysrc bastille_enable=YES - configure_network - configure_pf - configure_zfs -fi +configure_zfs_manually() { + BASTILLE_CONFIG_USER= + local ZFSPOOL_COUNT="0" + local ZFSDATA_COUNT="0" + local MPREFIX_COUNT="0" + local _zfsprefix_trim= + local _zfspool_choice= + local _zfspool_select= + local _zfsprefix_choice= + local _zfsprefix_select= + local _zfsmount_choice= + local _zfsmount_select= + local _response= -# Handle special-case commands first. -case "$1" in -help|-h|--help) - usage - ;; -pf|firewall) - configure_pf - ;; -bastille0) - # TODO remove in future release 0.13 - warn "'bastille setup bastille0' will be deprecated in the next 0.13 version." - configure_network - ;; -network|loopback) - configure_network - ;; -zfs|storage) - configure_zfs - ;; -bastille1|vnet|bridge) - configure_vnet - ;; + read -p "$(info "Would you like to configure the ZFS parameters entirely by hand? [y/N]: ")" _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + # We will assume the user knows what hes/she doing and want to configure ZFS parameters entirely by hand. + read -p "$(warn "Please enter the desired ZFS pool for bastille: ")" _zfspool_select + read -p "$(warn "Please enter the ZFS dataset for bastille: ")" _zfsprefix_select + read -p "$(warn "Please enter the ZFS mountpoint for bastille: ")" _zfsmount_select + + # Set the parameters and show the user a preview. + BASTILLE_PREFIXDEF="${_zfsmount_select}" + BASTILLE_ZFSPOOL="${_zfspool_select}" + BASTILLE_PREFIXZFS="${_zfsprefix_select}" + show_zfs_params + + # Ask again to make sure the user is confident with the entered parameters. + warn "Are you sure the above bastille ZFS configuration is correct?" + read -p "$(warn "Once bastille is activated it can't be easily undone, do you really want to activate ZFS now? [y/N]: ")" _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + BASTILLE_CONFIG_USER="1" + write_zfs_opts + create_zfs_dataset + ;; + [Nn]|[Nn][Oo]) + user_canceled + ;; + *) + input_error + ;; + esac + ;; + [Nn]|[Nn][Oo]) + # shellcheck disable=SC2104 + break + ;; + *) + input_error + ;; + esac + + # Ask here several times as we want the user to be really sure of what they doing, + # We do not want to cause existing data lost at all due end-user errors. + info "Listing available ZFS pools..." + bastille_zpool=$(zpool list -H | awk '{print $1}') + for _zpool in ${bastille_zpool}; do + echo "[${ZFSPOOL_COUNT}] ${_zpool}" + ZFSPOOL_NUM="${ZFSPOOL_NUM} [${ZFSPOOL_COUNT}]${_zpool}" + ZFSPOOL_COUNT=$(expr ${ZFSPOOL_COUNT} + 1) + done + + read -p "$(info "Please select the ZFS pool [NUM] for bastille: ")" _zfspool_choice + if ! echo "${_zfspool_choice}" | grep -Eq "^[0-9]{1,3}$"; then + error_exit "Invalid input number, aborting!" + else + _zfspool_select=$(echo "${ZFSPOOL_NUM}" | grep -wo "\[${_zfspool_choice}\][^ ]*" | sed 's/\[.*\]//g') + # If the user is unsure here, just abort as no input validation will be performed after. + if [ -z "${_zfspool_select}" ]; then + error_exit "No ZFS pool selected, aborting!" + else + info "Selected ZFS pool: [${_zfspool_select}]" + # Ask again to make sure the user is confident in his election. + read -p "$(warn "Are you sure '${_zfspool_select}' is the correct ZFS pool [y/N]: ")" _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + # shellcheck disable=SC2104 + continue + ;; + [Nn]|[Nn][Oo]) + user_canceled + ;; + *) + input_error + ;; + esac + fi + fi + + # Ask on what zfs dataset `bastille` is installed. + info "Listing available ZFS datasets from the selected ZFS pool..." + bastille_zprefix=$(zfs list -H -r "${_zfspool_select}" | awk '{print $1}') + for _zprefix in ${bastille_zprefix}; do + echo "[${ZFSDATA_COUNT}] ${_zprefix}" + ZFSDATA_NUM="${ZFSDATA_NUM} [${ZFSDATA_COUNT}]${_zprefix}" + ZFSDATA_COUNT=$(expr ${ZFSDATA_COUNT} + 1) + done + read -p "$(info "Please select the ZFS dataset [NUM] for bastille: ")" _zfsprefix_choice + if ! echo "${_zfsprefix_choice}" | grep -Eq "^[0-9]{1,3}$"; then + error_exit "Invalid input number, aborting!" + else + _zfsprefix_select=$(echo "${ZFSDATA_NUM}" | grep -wo "\[${_zfsprefix_choice}\][^ ]*" | sed 's/\[.*\]//g') + if [ -z "${_zfsprefix_select}" ]; then + # If the user is unsure here, just abort as no input validation will be performed after. + error_exit "No ZFS dataset selected, aborting!" + else + _zfsprefix_select=$(echo ${ZFSDATA_NUM} | grep -wo "\[${_zfsprefix_choice}\][^ ]*" | sed 's/\[.*\]//g') + _zfsprefix_trim=$(echo ${ZFSDATA_NUM} | grep -wo "\[${_zfsprefix_choice}\][^ ]*" | awk -F "${_zfspool_select}/" 'NR==1{print $2}') + info "Selected ZFS prefix: [${_zfsprefix_select}]" + # Ask again to make sure the user is confident in his election. + read -p "$(warn "Are you sure '${_zfsprefix_select}' is the correct ZFS dataset [y/N]: ")" _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + # shellcheck disable=SC2104 + continue + ;; + [Nn]|[Nn][Oo]) + user_canceled + ;; + *) + input_error + ;; + esac + fi + fi + + _zfsmount_select="${_zfsprefix_select}" + # Ask what zfs mountpoint `bastille` will use. + info "Listing ZFS mountpoints from the selected ZFS dataset: [${_zfsmount_select}]..." + bastille_prefix=$(zfs list -H "${_zfsmount_select}" | awk '{print $5}') + for _zfsmount_choice in ${bastille_prefix}; do + echo "[${MPREFIX_COUNT}] ${_zfsmount_choice}" + MPREFIX_NUM="${MPREFIX_NUM} [${MPREFIX_COUNT}]${_zfsmount_choice}" + MPREFIX_COUNT=$(expr ${MPREFIX_COUNT} + 1) + done + read -p "$(info "Please select the ZFS mountpoint [NUM] for bastille: ")" _zfsmount_choice + if ! echo "${_zfsmount_choice}" | grep -Eq "^[0-9]{1,3}$"; then + error_exit "Invalid input number, aborting!" + else + _zfsmount_select=$(echo ${MPREFIX_NUM} | grep -wo "\[${_zfsmount_choice}\][^ ]*" | sed 's/\[.*\]//g') + if [ -z "${_zfsmount_select}" ]; then + # If the user is unsure here, just abort as no input validation will be performed after. + error_exit "No ZFS mountpoint selected, aborting!" + else + info "Selected bastille storage mountpoint: [${_zfsmount_select}]" + # Ask again to make sure the user is confident in his election. + read -p "$(warn "Are you sure '${_zfsmount_select}' is the correct bastille prefix [y/N]: ")" _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + # Set the parameters and show the user a preview. + BASTILLE_PREFIXDEF="${_zfsmount_select}" + BASTILLE_ZFSPOOL="${_zfspool_select}" + BASTILLE_PREFIXZFS="${_zfsprefix_trim}" + show_zfs_params + warn "Are you sure the above bastille ZFS configuration is correct?" + read -p "$(warn "Once bastille is activated it can't be easily undone, do you really want to activate ZFS now? [y/N]: ")" _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + write_zfs_opts + create_zfs_dataset + ;; + [Nn]|[Nn][Oo]) + user_canceled + ;; + *) + input_error + ;; + esac + ;; + [Nn]|[Nn][Oo]) + user_canceled + ;; + *) + input_error + ;; + esac + fi + fi + +} + +# Runtime required variables. +config_runtime + +# Handle options one at a time per topic, we don't want users to select/process +# multiple options at once just to end with a broked and/or unwanted configuration. +case "${1}" in + --firewall|-p) + configure_pf + ;; + --network|-n|bastille0) + # TODO remove in future release 0.13 + warn "Notice: 'bastille setup bastille0' will be deprecated in the next 0.13 version." + configure_network + ;; + --vnet|-v|bridge) + configure_vnet + ;; + --zfs|-z) + configure_zfs + ;; + --conf-network-reset) + config_network_reset + ;; + --conf-storage-reset) + config_storage_reset + ;; + --conf-restore-clean) + config_restore_global + ;; + *) + usage + ;; esac From 6327d3654b6e3821d5f7e5b319052e30b3232567 Mon Sep 17 00:00:00 2001 From: JRGTH Date: Tue, 21 Jan 2025 06:25:44 -0400 Subject: [PATCH 52/59] Local shellcheck pass using shellcheck version: 0.8.0 --- usr/local/share/bastille/setup.sh | 75 ++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/usr/local/share/bastille/setup.sh b/usr/local/share/bastille/setup.sh index bd22d4fa..f4993a15 100644 --- a/usr/local/share/bastille/setup.sh +++ b/usr/local/share/bastille/setup.sh @@ -103,7 +103,8 @@ config_backup() { config_network_reset() { # Restore bastille default network options. warn "Performing Network configuration reset, requested by the user..." - read -p "$(warn "Do you really want to reset 'bastille' network configuration? [y/N]: ")" _response + warn "Do you really want to reset 'bastille' network configuration? [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) local VAR_ITEMS="bastille_network_loopback=bastille0 bastille_network_pf_ext_if=ext_if @@ -126,7 +127,8 @@ config_network_reset() { config_storage_reset() { # Restore bastille default ZFS storage options. warn "Performing ZFS configuration reset, requested by the user..." - read -p "$(warn "Do you really want to reset 'bastille' ZFS configuration? [y/N]: ")" _response + warn "Do you really want to reset 'bastille' ZFS configuration? [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) local VAR_ITEMS="bastille_zfs_enable= bastille_zfs_zpool= bastille_zfs_prefix=bastille" @@ -155,7 +157,8 @@ config_restore_global() { # Be aware that if the sample configuration file is missing, we can generate a new one, # but that's highly unlikely to happen so will keep the code smaller here. warn "Performing Bastille default configuration restore, requested by the user..." - read -p "$(warn "Do you really want to restore 'bastille' default configuration file and start over? [y/N]: ")" _response + warn "Do you really want to restore 'bastille' default configuration file and start over? [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) config_backup @@ -343,9 +346,8 @@ zfs_initial_activation() { # Just let the user interactively select the ZFS items manually from a list for the initial activation. # This should be performed before `bastille bootstrap` as we already know. info "Initial bastille ZFS activation helper invoked." - #read -p "$(info "Would you like bastille attempt to auto-detect/activate ZFS for you?, (assuming a standard install was performed) [y/N]: ")" _response - read -p "$(info "Would you like to configure the bastille ZFS options interactively? [y/N]: ")" _response - + info "Would you like to configure the bastille ZFS options interactively? [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) # Assume the user knows what hes/she doing and want to configure ZFS parameters interactively. @@ -368,7 +370,8 @@ configure_network() { # This is an initial attempt to make this function interactive, # however this may be enhanced in the future by advanced contributors in this topic. info "This will attempt to configure the loopback network interface [${bastille_network_loopback}]." - read -p "$(warn "Would you like to configure the loopback network interface now? [y/N]: ")" _response + warn "Would you like to configure the loopback network interface now? [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) # shellcheck disable=SC2104 @@ -400,7 +403,8 @@ configure_vnet() { # This is an initial attempt to make this function interactive, # however this may be enhanced in the future by advanced contributors in this topic. info "This will attempt to configure the VNET bridge interface [${bastille_ifbridge_name}]." - read -p "$(warn "Would you like to configure the VNET bridge interface now? [y/N]: ")" _response + warn "Would you like to configure the VNET bridge interface now? [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) # shellcheck disable=SC2104 @@ -454,7 +458,8 @@ configure_pf() { # This is an initial attempt to make this function interactive, # however this may be enhanced in the future by advanced contributors in this topic. info "This will attempt to configure the PF firewall parameters in [${bastille_pf_conf}]." - read -p "$(warn "Would you like to configure the PF firewall parameters now? [y/N]: ")" _response + warn "Would you like to configure the PF firewall parameters now? [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) # shellcheck disable=SC2104 @@ -518,7 +523,6 @@ configure_zfs() { ZFS_DATASET_DETECT= BASTILLE_CUSTOM_CONFIG= - BASTILLE_INITIAL_CONFIG= local _response= if ! kldstat -qm zfs; then @@ -530,7 +534,8 @@ configure_zfs() { # host filesystem, or the default configuration file has been changed officially and set to "NO" by default. if echo "${bastille_zfs_enable}" | grep -qi "no"; then info "Looks like Bastille ZFS has been disabled in 'bastille.conf', ZFS activation helper disabled." - read -p "$(warn "Would you like to enable the ZFS activation helper now? [y/N]: ")" _response + warn "Would you like to enable the ZFS activation helper now? [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) # Assume the user wants to configure the ZFS parameters. @@ -557,7 +562,8 @@ configure_zfs() { if [ "${bastille_prefix}" = "${bastille_prefix_default}" ] && [ -z "${BASTILLE_CUSTOM_CONFIG}" ]; then show_zfs_params info "Looks like bastille has been installed and hasn't been bootstrapped yet." - read -p "$(warn "Would you like to activate ZFS now to get the features and benefits? [y/N]"): " _response + warn "Would you like to activate ZFS now to get the features and benefits? [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) if [ -n "${BASTILLE_ZFSPOOL}" ]; then @@ -576,7 +582,8 @@ configure_zfs() { info "Looks like you cancelled the ZFS activation." # Offer the user option to disable ZFS in the configuration file. # Maybe the user wants to use UFS or ZFS with legacy directories instead. - read -p "$(warn "Would you like to explicitly disable ZFS in the configuration file? [y/N]: ")" _response + warn "Would you like to explicitly disable ZFS in the configuration file? [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) if config_backup; then @@ -611,7 +618,8 @@ configure_zfs() { info "Attempting to configure default ZFS options for you..." if zfs list | grep -qw "${bastille_prefix}"; then ZFS_DATASET_DETECT="1" - read -p "$(warn "Would you like to auto-configure the detected ZFS parameters now? [y/N]: ")" _response + warn "Would you like to auto-configure the detected ZFS parameters now? [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) if config_backup; then @@ -637,7 +645,8 @@ configure_zfs() { # We do not want to cause existing data lost at all due end-user errors. warn "Looks like bastille prefix is not a ZFS dataset, thus ZFS storage options are not required." warn "Please refer to 'bastille.conf' and/or verify for alreay existing 'bastille_prefix' directory." - read -p "$(warn "Would you like to explicitly disable ZFS in the configuration file so we don't ask again? [y/N]: ")" _response + warn "Would you like to explicitly disable ZFS in the configuration file so we don't ask again? [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) if config_backup; then @@ -690,13 +699,17 @@ configure_zfs_manually() { local _zfsmount_select= local _response= - read -p "$(info "Would you like to configure the ZFS parameters entirely by hand? [y/N]: ")" _response + info "Would you like to configure the ZFS parameters entirely by hand? [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) # We will assume the user knows what hes/she doing and want to configure ZFS parameters entirely by hand. - read -p "$(warn "Please enter the desired ZFS pool for bastille: ")" _zfspool_select - read -p "$(warn "Please enter the ZFS dataset for bastille: ")" _zfsprefix_select - read -p "$(warn "Please enter the ZFS mountpoint for bastille: ")" _zfsmount_select + warn "Please enter the desired ZFS pool for bastille: " + read _zfspool_select + warn "Please enter the ZFS dataset for bastille: " + read _zfsprefix_select + warn "Please enter the ZFS mountpoint for bastille: " + read _zfsmount_select # Set the parameters and show the user a preview. BASTILLE_PREFIXDEF="${_zfsmount_select}" @@ -706,7 +719,8 @@ configure_zfs_manually() { # Ask again to make sure the user is confident with the entered parameters. warn "Are you sure the above bastille ZFS configuration is correct?" - read -p "$(warn "Once bastille is activated it can't be easily undone, do you really want to activate ZFS now? [y/N]: ")" _response + warn "Once bastille is activated it can't be easily undone, do you really want to activate ZFS now? [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) BASTILLE_CONFIG_USER="1" @@ -740,7 +754,8 @@ configure_zfs_manually() { ZFSPOOL_COUNT=$(expr ${ZFSPOOL_COUNT} + 1) done - read -p "$(info "Please select the ZFS pool [NUM] for bastille: ")" _zfspool_choice + info "Please select the ZFS pool [NUM] for bastille: " + read _zfspool_choice if ! echo "${_zfspool_choice}" | grep -Eq "^[0-9]{1,3}$"; then error_exit "Invalid input number, aborting!" else @@ -751,7 +766,8 @@ configure_zfs_manually() { else info "Selected ZFS pool: [${_zfspool_select}]" # Ask again to make sure the user is confident in his election. - read -p "$(warn "Are you sure '${_zfspool_select}' is the correct ZFS pool [y/N]: ")" _response + warn "Are you sure '${_zfspool_select}' is the correct ZFS pool [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) # shellcheck disable=SC2104 @@ -775,7 +791,8 @@ configure_zfs_manually() { ZFSDATA_NUM="${ZFSDATA_NUM} [${ZFSDATA_COUNT}]${_zprefix}" ZFSDATA_COUNT=$(expr ${ZFSDATA_COUNT} + 1) done - read -p "$(info "Please select the ZFS dataset [NUM] for bastille: ")" _zfsprefix_choice + info "Please select the ZFS dataset [NUM] for bastille: " + read _zfsprefix_choice if ! echo "${_zfsprefix_choice}" | grep -Eq "^[0-9]{1,3}$"; then error_exit "Invalid input number, aborting!" else @@ -788,7 +805,8 @@ configure_zfs_manually() { _zfsprefix_trim=$(echo ${ZFSDATA_NUM} | grep -wo "\[${_zfsprefix_choice}\][^ ]*" | awk -F "${_zfspool_select}/" 'NR==1{print $2}') info "Selected ZFS prefix: [${_zfsprefix_select}]" # Ask again to make sure the user is confident in his election. - read -p "$(warn "Are you sure '${_zfsprefix_select}' is the correct ZFS dataset [y/N]: ")" _response + warn "Are you sure '${_zfsprefix_select}' is the correct ZFS dataset [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) # shellcheck disable=SC2104 @@ -813,7 +831,8 @@ configure_zfs_manually() { MPREFIX_NUM="${MPREFIX_NUM} [${MPREFIX_COUNT}]${_zfsmount_choice}" MPREFIX_COUNT=$(expr ${MPREFIX_COUNT} + 1) done - read -p "$(info "Please select the ZFS mountpoint [NUM] for bastille: ")" _zfsmount_choice + info "Please select the ZFS mountpoint [NUM] for bastille: " + read _zfsmount_choice if ! echo "${_zfsmount_choice}" | grep -Eq "^[0-9]{1,3}$"; then error_exit "Invalid input number, aborting!" else @@ -824,7 +843,8 @@ configure_zfs_manually() { else info "Selected bastille storage mountpoint: [${_zfsmount_select}]" # Ask again to make sure the user is confident in his election. - read -p "$(warn "Are you sure '${_zfsmount_select}' is the correct bastille prefix [y/N]: ")" _response + warn "Are you sure '${_zfsmount_select}' is the correct bastille prefix [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) # Set the parameters and show the user a preview. @@ -833,7 +853,8 @@ configure_zfs_manually() { BASTILLE_PREFIXZFS="${_zfsprefix_trim}" show_zfs_params warn "Are you sure the above bastille ZFS configuration is correct?" - read -p "$(warn "Once bastille is activated it can't be easily undone, do you really want to activate ZFS now? [y/N]: ")" _response + warn "Once bastille is activated it can't be easily undone, do you really want to activate ZFS now? [y/N]: " + read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) write_zfs_opts From 848bec5fae898dcc6c77cf6a93b29ba22d82ae21 Mon Sep 17 00:00:00 2001 From: JRGTH Date: Tue, 21 Jan 2025 18:17:12 -0400 Subject: [PATCH 53/59] Add --ethernet option for bastille_network_shared Add '-e|--ethernet' option to configure `bastille_network_shared` physical interface, also add config backups to select partial variable resets as well. --- usr/local/share/bastille/setup.sh | 82 +++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/usr/local/share/bastille/setup.sh b/usr/local/share/bastille/setup.sh index f4993a15..6069f4c0 100644 --- a/usr/local/share/bastille/setup.sh +++ b/usr/local/share/bastille/setup.sh @@ -51,6 +51,7 @@ usage() { -p | --firewall -- Attempt to configure bastille PF firewall. -n | --network -- Attempt to configure network loopback interface. + -e | --ethernet -- Attempt to configure the network shared interface. -v | --vnet -- Attempt to configure VNET bridge interface [bastille1]. -z | --zfs -- Activates ZFS storage features and benefits for bastille. --conf-network-reset -- Restore bastille default Network options on the config file. @@ -107,6 +108,7 @@ config_network_reset() { read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) + config_backup local VAR_ITEMS="bastille_network_loopback=bastille0 bastille_network_pf_ext_if=ext_if bastille_network_pf_table=jails bastille_network_shared= bastille_network_gateway= bastille_network_gateway6=" for _item in ${VAR_ITEMS}; do @@ -131,6 +133,7 @@ config_storage_reset() { read _response case "${_response}" in [Yy]|[Yy][Ee][Ss]) + config_backup local VAR_ITEMS="bastille_zfs_enable= bastille_zfs_zpool= bastille_zfs_prefix=bastille" for _item in ${VAR_ITEMS}; do sysrc -f "${bastille_config}" ${_item} @@ -363,6 +366,76 @@ zfs_initial_activation() { esac } +configure_ethernet() { + # This will attempt to configure the physical ethernet interface for 'bastille_network_shared', + # commonly used with shared IP jails and/or simple jail network configurations. + + local ETHIF_COUNT="0" + local _ethernet_choice= + local _response= + + # Try to get a list of the available physical network/ethernet interfaces. + local ETHERNET_PHY_ADAPTERS=$(pciconf -lv | grep 'ethernet' -B4 | grep 'class=0x020000' | awk -F '@' '{print $1}') + if [ -z "${ETHERNET_PHY_ADAPTERS}" ]; then + error_exit "Unable to detect for any physical ethernet interfaces, exiting." + fi + + info "This will attempt to configure the physical ethernet interface for [bastille_network_shared]." + warn "Would you like to configure the physical ethernet interface now? [y/N]: " + read _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + # shellcheck disable=SC2104 + break + ;; + [Nn]|[Nn][Oo]) + user_canceled + ;; + *) + input_error + ;; + esac + + info "Listing available physical ethernet interfaces..." + for _ethernetif in ${ETHERNET_PHY_ADAPTERS}; do + echo "[${ETHIF_COUNT}] ${_ethernetif}" + ETHIF_NUM="${ETHIF_NUM} [${ETHIF_COUNT}]${_ethernetif}" + ETHIF_COUNT=$(expr ${ETHIF_COUNT} + 1) + done + + info "Please select the wanted physical ethernet adapter [NUM] to be used as 'bastille_network_shared': " + read _ethernet_choice + if ! echo "${_ethernet_choice}" | grep -Eq "^[0-9]{1,3}$"; then + error_exit "Invalid input number, aborting!" + else + _ethernet_select=$(echo "${ETHIF_NUM}" | grep -wo "\[${_ethernet_choice}\][^ ]*" | sed 's/\[.*\]//g') + # If the user is unsure here, just abort as no input validation will be performed after. + if [ -z "${_ethernet_select}" ]; then + error_exit "No physical ethernet interface selected, aborting!" + else + info "Selected physical ethernet interface: [${_ethernet_select}]" + # Ask again to make sure the user is confident with the election. + warn "Are you sure '${_ethernet_select}' is the correct physical ethernet interface [y/N]: " + read _response + case "${_response}" in + [Yy]|[Yy][Ee][Ss]) + if ! sysrc -f "${bastille_config}" bastille_network_shared | grep -qi "${_ethernet_select}"; then + config_backup + sysrc -f "${bastille_config}" bastille_network_shared="${_ethernet_select}" + fi + exit 0 + ;; + [Nn]|[Nn][Oo]) + user_canceled + ;; + *) + input_error + ;; + esac + fi + fi +} + configure_network() { local _response @@ -765,7 +838,7 @@ configure_zfs_manually() { error_exit "No ZFS pool selected, aborting!" else info "Selected ZFS pool: [${_zfspool_select}]" - # Ask again to make sure the user is confident in his election. + # Ask again to make sure the user is confident with the election. warn "Are you sure '${_zfspool_select}' is the correct ZFS pool [y/N]: " read _response case "${_response}" in @@ -804,7 +877,7 @@ configure_zfs_manually() { _zfsprefix_select=$(echo ${ZFSDATA_NUM} | grep -wo "\[${_zfsprefix_choice}\][^ ]*" | sed 's/\[.*\]//g') _zfsprefix_trim=$(echo ${ZFSDATA_NUM} | grep -wo "\[${_zfsprefix_choice}\][^ ]*" | awk -F "${_zfspool_select}/" 'NR==1{print $2}') info "Selected ZFS prefix: [${_zfsprefix_select}]" - # Ask again to make sure the user is confident in his election. + # Ask again to make sure the user is confident with the election. warn "Are you sure '${_zfsprefix_select}' is the correct ZFS dataset [y/N]: " read _response case "${_response}" in @@ -842,7 +915,7 @@ configure_zfs_manually() { error_exit "No ZFS mountpoint selected, aborting!" else info "Selected bastille storage mountpoint: [${_zfsmount_select}]" - # Ask again to make sure the user is confident in his election. + # Ask again to make sure the user is confident with the election. warn "Are you sure '${_zfsmount_select}' is the correct bastille prefix [y/N]: " read _response case "${_response}" in @@ -889,6 +962,9 @@ case "${1}" in --firewall|-p) configure_pf ;; + --ethernet|-e) + configure_ethernet + ;; --network|-n|bastille0) # TODO remove in future release 0.13 warn "Notice: 'bastille setup bastille0' will be deprecated in the next 0.13 version." From f45fb739134b416c80ddff72ac782873d3ba79a8 Mon Sep 17 00:00:00 2001 From: JRGTH Date: Tue, 21 Jan 2025 18:23:52 -0400 Subject: [PATCH 54/59] Quick shellcheck fix as per suggestion --- usr/local/share/bastille/setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/local/share/bastille/setup.sh b/usr/local/share/bastille/setup.sh index 6069f4c0..518ec976 100644 --- a/usr/local/share/bastille/setup.sh +++ b/usr/local/share/bastille/setup.sh @@ -375,7 +375,7 @@ configure_ethernet() { local _response= # Try to get a list of the available physical network/ethernet interfaces. - local ETHERNET_PHY_ADAPTERS=$(pciconf -lv | grep 'ethernet' -B4 | grep 'class=0x020000' | awk -F '@' '{print $1}') + local ETHERNET_PHY_ADAPTERS="$(pciconf -lv | grep 'ethernet' -B4 | grep 'class=0x020000' | awk -F '@' '{print $1}')" if [ -z "${ETHERNET_PHY_ADAPTERS}" ]; then error_exit "Unable to detect for any physical ethernet interfaces, exiting." fi From 050d2008322ea7a3a97bee35e5bcfc47680fd02c Mon Sep 17 00:00:00 2001 From: JRGTH Date: Tue, 21 Jan 2025 18:45:38 -0400 Subject: [PATCH 55/59] Quick cleanup revision --- usr/local/share/bastille/setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/local/share/bastille/setup.sh b/usr/local/share/bastille/setup.sh index 518ec976..8e609d95 100644 --- a/usr/local/share/bastille/setup.sh +++ b/usr/local/share/bastille/setup.sh @@ -372,6 +372,7 @@ configure_ethernet() { local ETHIF_COUNT="0" local _ethernet_choice= + local _ethernet_select= local _response= # Try to get a list of the available physical network/ethernet interfaces. @@ -950,7 +951,6 @@ configure_zfs_manually() { esac fi fi - } # Runtime required variables. From 2c45c51e8412b9ed1e97a07454a8093caf4c5c5e Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Fri, 24 Jan 2025 07:33:19 -0700 Subject: [PATCH 56/59] common: Add notes about how MAC is generated --- usr/local/share/bastille/common.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/usr/local/share/bastille/common.sh b/usr/local/share/bastille/common.sh index 8c7e57e9..6837d76d 100644 --- a/usr/local/share/bastille/common.sh +++ b/usr/local/share/bastille/common.sh @@ -228,8 +228,9 @@ generate_static_mac() { local jail_name="${1}" local external_interface="${2}" local external_interface_mac="$(ifconfig ${external_interface} | grep ether | awk '{print $2}')" - # Use FreeBSD vendor prefix for jail MAC prefix + # Use FreeBSD vendor MAC prefix (58:9c:fc) for jail MAC prefix local macaddr_prefix="58:9c:fc" + # Use hash of interface+jailname for jail MAC suffix local macaddr_suffix="$(echo -n "${external_interface_mac}${jail_name}" | sed 's#:##g' | sha256 | cut -b -5 | sed 's/\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F][0-9a-fA-F]\)\([0-9a-fA-F]\)/\1:\2:\3/')" if [ -z "${macaddr_prefix}" ] || [ -z "${macaddr_suffix}" ]; then error_notify "Failed to generate MAC address." @@ -364,4 +365,4 @@ checkyesno() { return 1 ;; esac -} \ No newline at end of file +} From 2f594e4e65c8728141220998f8deb1668eaa5e59 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 25 Jan 2025 10:22:23 -0700 Subject: [PATCH 57/59] common: Also check ifconfig for epairs --- usr/local/share/bastille/common.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usr/local/share/bastille/common.sh b/usr/local/share/bastille/common.sh index 6837d76d..3f861fab 100644 --- a/usr/local/share/bastille/common.sh +++ b/usr/local/share/bastille/common.sh @@ -247,14 +247,14 @@ generate_vnet_jail_netblock() { ## determine number of interfaces + 1 ## iterate num and grep all jail configs ## define uniq_epair - local _epair_if_count="$(grep -Eos 'epair[0-9]+' ${bastille_jailsdir}/*/jail.conf | sort -u | wc -l | awk '{print $1}')" + local _epair_if_count="$( (grep -Eos 'epair[0-9]+' ${bastille_jailsdir}/*/jail.conf; ifconfig | grep -Eo '(e[0-9]+a|epair[0-9]+a)' ) | sort -u | wc -l | awk '{print $1}')" local _bastille_if_count="$(grep -Eos 'bastille[0-9]+' ${bastille_jailsdir}/*/jail.conf | sort -u | wc -l | awk '{print $1}')" local epair_num_range=$((_epair_if_count + 1)) local bastille_num_range=$((_bastille_if_count + 1)) if [ -n "${use_unique_bridge}" ]; then if [ "${_epair_if_count}" -gt 0 ]; then for _num in $(seq 0 "${epair_num_range}"); do - if ! grep -Eosq "epair${_num}" ${bastille_jailsdir}/*/jail.conf; then + if ! grep -Eosq "epair${_num}" ${bastille_jailsdir}/*/jail.conf && ! ifconfig | grep -Eosq "(e${_num}a|epair${_num}a)"; then if [ "$(echo -n "e${_num}a_${jail_name}" | awk '{print length}')" -lt 16 ]; then local host_epair=e${_num}a_${jail_name} local jail_epair=e${_num}b_${jail_name} From 1a77041e8e88bc0d9c8b6329645e6b08341ab860 Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sat, 25 Jan 2025 10:24:33 -0700 Subject: [PATCH 58/59] clone: Also check ifconfig for epairs --- usr/local/share/bastille/clone.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usr/local/share/bastille/clone.sh b/usr/local/share/bastille/clone.sh index 9c945f94..998f4674 100644 --- a/usr/local/share/bastille/clone.sh +++ b/usr/local/share/bastille/clone.sh @@ -181,14 +181,14 @@ update_jailconf_vnet() { # Determine number of interfaces and define a uniq_epair local _if_list="$(grep -Eo 'epair[0-9]+|bastille[0-9]+' ${_jail_conf} | sort -u)" for _if in ${_if_list}; do - local _epair_if_count="$(grep -Eo 'epair[0-9]+' ${bastille_jailsdir}/*/jail.conf | sort -u | wc -l | awk '{print $1}')" + local _epair_if_count="$( (grep -Eo 'epair[0-9]+' ${bastille_jailsdir}/*/jail.conf; ifconfig | grep -Eo '(e[0-9]+a|epair[0-9]+a)' ) | sort -u | wc -l | awk '{print $1}')" local _bastille_if_count="$(grep -Eo 'bastille[0-9]+' ${bastille_jailsdir}/*/jail.conf | sort -u | wc -l | awk '{print $1}')" local epair_num_range=$((_epair_if_count + 1)) local bastille_num_range=$((_bastille_if_count + 1)) if echo ${_if} | grep -Eoq 'epair[0-9]+'; then # Update bridged VNET config for _num in $(seq 0 "${epair_num_range}"); do - if ! grep -oq "epair${_num}" ${bastille_jailsdir}/*/jail.conf; then + if ! grep -Eoq "epair${_num}" ${bastille_jailsdir}/*/jail.conf && ! ifconfig | grep -Eoq "(e${_num}a|epair${_num}a)"; then # Generate new epair name if [ "$(echo -n "e${_num}a_${NEWNAME}" | awk '{print length}')" -lt 16 ]; then local _new_host_epair="e${_num}a_${NEWNAME}" From b1d6b49141b5bec828e092dd36065b9ead4c4bbf Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Sun, 26 Jan 2025 11:11:00 -0700 Subject: [PATCH 59/59] clone: Typo in usage block --- usr/local/share/bastille/clone.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/local/share/bastille/clone.sh b/usr/local/share/bastille/clone.sh index 998f4674..2d2dee9e 100644 --- a/usr/local/share/bastille/clone.sh +++ b/usr/local/share/bastille/clone.sh @@ -39,7 +39,7 @@ usage() { Options: -a | --auto Auto mode. Start/stop jail(s) if required. Cannot be used with [-l|--live]. - -l | --live Clone a running jail. ZFS only. Jail must be running. Cannot be used with [-f|--force]. + -l | --live Clone a running jail. ZFS only. Jail must be running. Cannot be used with [-a|--auto]. -x | --debug Enable debug mode. EOF