#!/bin/sh # bump version when a change in this file effects provision scripts mt6_version() { echo "20260204"; } dec_to_hex() { printf '%04x\n' "$1"; } get_random_ip6net() { # shellcheck disable=2039 local RAND16 RAND16=$(od -t uI -N 2 /dev/urandom | awk '{print $2}') echo "fd7a:e5cd:1fc1:$(dec_to_hex "$RAND16"):dead:beef:cafe" } tell_status() { echo; echo " *** $1 ***"; echo if [ -t 0 ]; then sleep 1; fi } store_config() { # $1 - path to config file, $2 - overwrite, STDIN is file contents local _overwrite=${2:-""} if [ ! -d "$(dirname $1)" ]; then tell_status "creating $(dirname $1)" mkdir -p "$(dirname $1)" fi cat - > "$1.mt6" if [ ! -f "$1" ] || [ "$_overwrite" = "overwrite" ]; then tell_status "installing $1" cp "$1.mt6" "$1" else tell_status "preserving $1" fi } create_default_config() { local _HOSTNAME local _EMAIL_DOMAIN local _ORGNAME if [ -t 0 ] && [ "$(uname)" = 'FreeBSD' ]; then echo "editing prefs" _HOSTNAME=$(bsddialog --nocancel --backtitle "mail-toaster.sh" --title TOASTER_HOSTNAME --inputbox "the hostname of this [virtual] machine" 8 70 "mail.example.com" 3>&1 1>&2 2>&3) _EMAIL_DOMAIN=$(bsddialog --nocancel --backtitle "mail-toaster.sh" --title TOASTER_MAIL_DOMAIN --inputbox "the primary email domain" 8 70 "example.com" 3>&1 1>&2 2>&3) _ORGNAME=$(bsddialog --nocancel --backtitle "mail-toaster.sh" --title TOASTER_ORG_NAME --inputbox "the name of your organization" 8 70 "Email Inc" 3>&1 1>&2 2>&3) fi # for dev/test environs where bsddialog doesn't exist if [ -z "$_HOSTNAME" ]; then _HOSTNAME=$(hostname); fi if [ -z "$_EMAIL_DOMAIN" ]; then _EMAIL_DOMAIN=$(hostname); fi if [ -z "$_ORGNAME" ]; then _ORGNAME="Sparky the Toaster"; fi echo "creating mail-toaster.conf with defaults" store_config mail-toaster.conf <" return else echo "v: $_github" fi local _this _this="$(mt6_version)"; if [ -n "$_this" ] && [ "$_this" -lt "$_github" ]; then echo "NOTICE: updating mail-toaster.sh" mt6-update fi } export TOASTER_SRC_URL=${TOASTER_SRC_URL:="https://raw.githubusercontent.com/msimerson/Mail-Toaster-6/master"} mt6_version_check # load the local config file config # Required settings export TOASTER_HOSTNAME=${TOASTER_HOSTNAME:="mail.example.com"} || exit 1 export TOASTER_MAIL_DOMAIN=${TOASTER_MAIL_DOMAIN:="example.com"} export TOASTER_ADMIN_EMAIL=${TOASTER_ADMIN_EMAIL:="postmaster@$TOASTER_MAIL_DOMAIN"} # export these in your environment to customize export BOURNE_SHELL=${BOURNE_SHELL:="bash"} export JAIL_NET_PREFIX=${JAIL_NET_PREFIX:="172.16.15"} export JAIL_NET_MASK=${JAIL_NET_MASK:="/19"} export JAIL_NET_INTERFACE=${JAIL_NET_INTERFACE:="lo1"} export JAIL_ORDERED_LIST="syslog base dns mysql clamav spamassassin foundationdb vpopmail haraka webmail munin haproxy rspamd stalwart dovecot redis geoip nginx mailtest apache postgres minecraft joomla php7 memcached sphinxsearch elasticsearch nictool sqwebmail dhcp letsencrypt tinydns roundcube squirrelmail rainloop rsnapshot mediawiki smf wordpress whmcs squirrelcart horde grafana unifi mongodb gitlab gitlab_runner dcc prometheus influxdb telegraf statsd mail_dmarc ghost jekyll borg nagios postfix puppeteer snappymail knot nsd bsd_cache wildduck zonemta centos ubuntu bhyve-ubuntu mailman" export ZFS_VOL=${ZFS_VOL:="zroot"} export ZFS_BHYVE_VOL="${ZFS_BHYVE_VOL:=$ZFS_VOL}" export ZFS_JAIL_MNT=${ZFS_JAIL_MNT:="/jails"} export ZFS_DATA_MNT=${ZFS_DATA_MNT:="/data"} export FBSD_MIRROR=${FBSD_MIRROR:="ftp://ftp.freebsd.org"} export TLS_LIBRARY=${TLS_LIBRARY:=""} export TOASTER_BASE_MTA=${TOASTER_BASE_MTA:=""} export TOASTER_BASE_PKGS=${TOASTER_BASE_PKGS:="pkg ca_root_nss"} export TOASTER_BUILD_DEBUG=${TOASTER_BUILD_DEBUG:="0"} export TOASTER_EDITOR=${TOASTER_EDITOR:="vim"} export TOASTER_EDITOR_PORT=${TOASTER_EDITOR_PORT:="vim-tiny"} # See https://github.com/msimerson/Mail-Toaster-6/wiki/MySQL export TOASTER_MYSQL=${TOASTER_MYSQL:="1"} export TOASTER_MARIADB=${TOASTER_MARIADB:="0"} export TOASTER_NTP=${TOASTER_NTP:="openntpd"} export TOASTER_MSA=${TOASTER_MSA:="haraka"} export TOASTER_PKG_AUDIT=${TOASTER_PKG_AUDIT:="0"} export TOASTER_PKG_BRANCH=${TOASTER_PKG_BRANCH:="latest"} export TOASTER_USE_TMPFS=${TOASTER_USE_TMPFS:="0"} export TOASTER_VPOPMAIL_CLEAR=${TOASTER_VPOPMAIL_CLEAR:="1"} export TOASTER_VPOPMAIL_EXT=${TOASTER_VPOPMAIL_EXT:="0"} export TOASTER_VQADMIN=${TOASTER_VQADMIN:="0"} export TOASTER_WEBMAIL_PROXY=${TOASTER_WEBMAIL_PROXY:="haproxy"} export CLAMAV_FANGFRISCH=${CLAMAV_FANGFRISCH:="0"} export CLAMAV_UNOFFICIAL=${CLAMAV_UNOFFICIAL:="0"} export ROUNDCUBE_SQL=${ROUNDCUBE_SQL:="$TOASTER_MYSQL"} export ROUNDCUBE_PRODUCT_NAME=${ROUNDCUBE_PRODUCT_NAME:="Roundcube Webmail"} export ROUNDCUBE_ATTACHMENT_SIZE_MB=${ROUNDCUBE_ATTACHMENT_SIZE_MB:="25"} export SQUIRREL_SQL=${SQUIRREL_SQL:="$TOASTER_MYSQL"} export WILDDUCK_MAIL_DOMAIN=${WILDDUCK_MAIL_DOMAIN:="$TOASTER_MAIL_DOMAIN"} export WILDDUCK_HOSTNAME=${WILDDUCK_HOSTNAME:="$TOASTER_HOSTNAME"} # shellcheck disable=2009,2317 if ps -o args= -p "$$" | grep csh; then echo; echo "ERROR: switch to sh or bash"; return 1; exit 1; fi echo "shell: $SHELL" if [ "$TOASTER_MYSQL" = "1" ]; then echo "mysql enabled" fi usage() { if [ -n "$1" ]; then echo; echo "ERROR: invalid $1"; echo; fi echo; echo "Next step, edit mail-toaster.conf!"; echo echo "See: https://github.com/msimerson/Mail-Toaster-6/wiki/FreeBSD"; echo } # shellcheck disable=2317 if [ "$TOASTER_HOSTNAME" = "mail.example.com" ]; then usage TOASTER_HOSTNAME; return 1; exit 1 fi echo "toaster host: $TOASTER_HOSTNAME" # shellcheck disable=2317 if [ "$TOASTER_MAIL_DOMAIN" = "example.com" ]; then usage TOASTER_MAIL_DOMAIN; return 1; exit 1 fi echo "email domain: $TOASTER_MAIL_DOMAIN" if [ -z "$JAIL_NET6" ]; then JAIL_NET6=$(get_random_ip6net) echo "export JAIL_NET6=\"$JAIL_NET6\"" >> mail-toaster.conf export JAIL_NET6 fi # little below here should need customizing. If so, consider opening # an issue or PR at https://github.com/msimerson/Mail-Toaster-6 export ZFS_JAIL_VOL="${ZFS_VOL}${ZFS_JAIL_MNT}" export ZFS_DATA_VOL="${ZFS_VOL}${ZFS_DATA_MNT}" export FBSD_REL_VER FBSD_PATCH_VER if [ "$(uname)" = 'FreeBSD' ]; then FBSD_REL_VER=$(/bin/freebsd-version | /usr/bin/cut -f1-2 -d'-') FBSD_PATCH_VER=$(/bin/freebsd-version | /usr/bin/cut -f3 -d'-') FBSD_PATCH_VER=${FBSD_PATCH_VER:="p0"} fi # the 'base' jail that other jails are cloned from. This will be named as the # host OS version, eg: base-13.2-RELEASE and the snapshot name will be the OS # patch level, eg: base-13.2-RELEASE@p3 export BASE_NAME="base-$FBSD_REL_VER" export BASE_VOL="$ZFS_JAIL_VOL/$BASE_NAME" export BASE_SNAP="${BASE_VOL}@${FBSD_PATCH_VER}" export BASE_MNT="$ZFS_JAIL_MNT/$BASE_NAME" export STAGE_MNT="$ZFS_JAIL_MNT/stage" fatal_err() { echo; echo "FATAL: $1"; echo; exit 1; } safe_jailname() { # constrain jail name chars to alpha-numeric and _ # shellcheck disable=SC2001 echo "$1" | sed -e 's/[^a-zA-Z0-9]/_/g' } export SAFE_NAME; SAFE_NAME=$(safe_jailname stage) if [ -z "$SAFE_NAME" ]; then echo "unset SAFE_NAME"; exit; fi zfs_filesystem_exists() { zfs list -t filesystem "$1" 2>/dev/null | grep -q "^$1" || return 1 tell_status "$1 filesystem exists" return 0 } zfs_snapshot_exists() { if zfs list -t snapshot "$1" 2>/dev/null | grep -q "$1"; then echo "$1 snapshot exists" return fi false } zfs_mountpoint_exists() { zfs list -t filesystem "$1" 2>/dev/null | grep -q "$1\$" || return 1 echo "$1 mountpoint exists" return 0 } zfs_create_fs() { if zfs_filesystem_exists "$1"; then return; fi if zfs_mountpoint_exists "$2"; then return; fi if echo "$1" | grep "$ZFS_DATA_VOL"; then if ! zfs_filesystem_exists "$ZFS_DATA_VOL"; then tell_status "zfs create -o mountpoint=$ZFS_DATA_MNT $ZFS_DATA_VOL" zfs create -o mountpoint="$ZFS_DATA_MNT" "$ZFS_DATA_VOL" || exit fi fi if echo "$1" | grep "$ZFS_JAIL_VOL"; then if ! zfs_filesystem_exists "$ZFS_JAIL_VOL"; then tell_status "zfs create -o mountpoint=$ZFS_JAIL_MNT $ZFS_JAIL_VOL" zfs create -o mountpoint="$ZFS_JAIL_MNT" "$ZFS_JAIL_VOL" || exit fi fi if [ -z "$2" ]; then tell_status "zfs create $1" zfs create "$1" || exit echo "done" return fi tell_status "zfs create -o mountpoint=$2 $1" zfs create -o mountpoint="$2" "$1" || exit echo "done" } zfs_destroy_fs() { local _fs="$1" local _flags=${2-} if ! zfs_filesystem_exists "$_fs"; then return; fi if [ -n "$_flags" ]; then echo "zfs destroy $2 $1" zfs destroy "$2" "$1" || exit 1 else echo "zfs destroy $1" zfs destroy "$1" || exit 1 fi } base_snapshot_exists() { if zfs_snapshot_exists "$BASE_SNAP"; then return 0 fi echo "$BASE_SNAP does not exist, use 'provision base' to create it" return 1 } jail_conf_header() { local _path="$ZFS_JAIL_MNT/$1" if [ "$1" = "base" ]; then _path="$BASE_MNT"; fi cat <" /etc/jail.conf; then tell_status "preserving $1 config in /etc/jail.conf" return fi tell_status "adding $1 to /etc/jail.conf" echo "$1 {$(get_safe_jail_path $1) mount.fstab = \"$ZFS_DATA_MNT/$1/etc/fstab\"; ip4.addr = $JAIL_NET_INTERFACE|${_jail_ip}; ip6.addr = $JAIL_NET_INTERFACE|$(get_jail_ip6 $1);${JAIL_CONF_EXTRA} }" | tee -a /etc/jail.conf } get_safe_jail_path() { local _safe; _safe=$(safe_jailname "$1") if [ "$1" != "$_safe" ]; then echo " path = $ZFS_JAIL_MNT/${1};" else echo "" fi } get_jail_data() { if [ "$1" = "base" ]; then echo "$BASE_MNT/data" else echo "$ZFS_DATA_MNT/$1" fi } add_jail_conf_d() { # configure IPv6 if the system has an external/public IPv6 address local _IP6="" get_public_ip ipv6 if [ -n "$PUBLIC_IP6" ]; then _IP6="ip6.addr = $(get_jail_ip6 $1);" fi local _path="$ZFS_JAIL_MNT/$1" if [ "$1" = "base" ]; then _path="$BASE_MNT"; fi store_config "/etc/jail.conf.d/$(safe_jailname $1).conf" </dev/null; then echo "removed"; fi fi fi if jail_is_running "$_safe"; then echo "jail -r $_safe" if jail -r "$_safe" 2>/dev/null; then echo "removed"; fi fi } stage_unmount() { for _fs in $(mount | grep stage | sort -u | awk '{ print $3 }'); do if [ "$(basename "$_fs")" = "stage" ]; then continue; fi echo "umount $_fs" umount "$_fs" || echo "" done # repeat, as sometimes a nested fs will prevent first try from success for _fs in $(mount | grep stage | sort -u | awk '{ print $3 }'); do if [ "$(basename "$_fs")" = "stage" ]; then continue; fi echo "umount $_fs" umount "$_fs" done if mount -t devfs | grep -q "$STAGE_MNT/dev"; then echo "umount $STAGE_MNT/dev" umount "$STAGE_MNT/dev" fi } cleanup_staged_fs() { tell_status "stage cleanup" stop_jail stage stage_unmount "$1" zfs_destroy_fs "$ZFS_JAIL_VOL/stage" -f } install_pfrule() { local _pfdir _pfdir="$(get_jail_data $1)/etc/pf.conf.d" mt6-fetch contrib pfrule.sh install -d "$_pfdir" install -C -m 0755 contrib/pfrule.sh "$_pfdir/pfrule.sh" } install_fstab() { _data_mount="$ZFS_DATA_MNT/$1" _jail_mount="$ZFS_JAIL_MNT/$1" _fstab="$ZFS_DATA_MNT/$1/etc/fstab" if [ ! -d "$_data_mount/etc" ]; then mkdir "$_data_mount/etc" || exit 1 fi tell_status "writing data mount to $_fstab" echo "# Device Mountpoint FStype Options Dump Pass#" | tee "$_fstab" || exit 1 echo "$_data_mount $_jail_mount/data nullfs rw 0 0" | tee -a "$_fstab" echo "devfs $_jail_mount/dev devfs rw 0 0" | tee -a "$_fstab" if [ -n "$JAIL_FSTAB" ]; then tell_status "appending JAIL_FSTAB to fstab" echo "$JAIL_FSTAB" | tee -a "$_fstab" || exit 1 fi if [ "$TOASTER_USE_TMPFS" = 1 ]; then if ! grep -q "$_jail_mount/tmp" "$_fstab"; then tell_status "adding tmpfs to fstab" echo "tmpfs $_jail_mount/tmp tmpfs rw,mode=01777,noexec,nosuid 0 0" | tee -a "$_fstab" echo "tmpfs $_jail_mount/var/run tmpfs rw,mode=01755,noexec,nosuid 0 0" | tee -a "$_fstab" fi fi sed -e "s|[[:space:]]$ZFS_JAIL_MNT/$1| $ZFS_JAIL_MNT/stage|" \ "$_fstab" > \ "$_fstab.stage" || exit 1 tell_status "appending pkg & ports to fstab.stage" echo "/usr/ports $STAGE_MNT/usr/ports nullfs rw 0 0" | tee -a "$_fstab.stage" echo "/var/cache/pkg $STAGE_MNT/var/cache/pkg nullfs rw 0 0" | tee -a "$_fstab.stage" # copy staged fstab into place for jail shutdown if [ ! -d "$ZFS_DATA_MNT/stage/etc" ]; then mkdir -p "$ZFS_DATA_MNT/stage/etc" || exit 1 fi cp "$_fstab.stage" "$ZFS_DATA_MNT/stage/etc/fstab" || exit 1 } create_staged_fs() { cleanup_staged_fs "$1" tell_status "stage jail filesystem setup" echo "zfs clone $BASE_SNAP $ZFS_JAIL_VOL/stage" zfs clone "$BASE_SNAP" "$ZFS_JAIL_VOL/stage" || exit 1 if [ ! -d "$ZFS_JAIL_MNT/stage/data" ]; then mkdir "$ZFS_JAIL_MNT/stage/data" || exit 1 fi if [ ! -d "$ZFS_JAIL_MNT/stage/data" ]; then tell_status "creating $ZFS_JAIL_MNT/stage/data" mkdir "$ZFS_JAIL_MNT/stage/data" || exit 1 fi stage_sysrc hostname="$1" if [ -f "$STAGE_MNT/usr/local/etc/ssmtp/ssmtp.conf" ]; then sed -i '' -e "/^hostname=/ s/_HOSTNAME_/$1/" \ "$STAGE_MNT/usr/local/etc/ssmtp/ssmtp.conf" fi assure_ip6_addr_is_declared "$1" stage_resolv_conf echo "MASQUERADE $1@$TOASTER_MAIL_DOMAIN" >> "$STAGE_MNT/etc/dma/dma.conf" zfs_create_fs "$ZFS_DATA_VOL/$1" "$ZFS_DATA_MNT/$1" install_fstab $1 install_pfrule $1 echo } enable_bsd_cache() { if ! jail_is_running bsd_cache; then return; fi if ! jail_is_running dns; then return; fi # assure services are available sockstat -4 -6 -p 80 -q -j bsd_cache | grep -q . || return sockstat -4 -6 -p 53 -q -j dns | grep -q . || return tell_status "enabling bsd_cache" store_config "$STAGE_MNT/etc/resolv.conf" "overwrite" < "$STAGE_MNT/etc/resolv.conf" echo "nameserver $(get_jail_ip6 dns)" >> "$STAGE_MNT/etc/resolv.conf" } seed_pkg_audit() { if [ "$TOASTER_PKG_AUDIT" = "1" ]; then tell_status "installing FreeBSD package audit database" stage_exec /usr/sbin/pkg audit -F || echo '' fi } enable_jail() { case " $(sysrc -n jail_list) " in *" $1 "*) #echo "jail $1 already enabled at startup" return ;; esac tell_status "enabling jail $1 at startup" sysrc jail_list+=" $1" sysrc -f /etc/periodic.conf security_status_pkgaudit_jails+=" $1" } promote_staged_jail() { seed_pkg_audit tell_status "promoting jail $1" stop_jail stage stage_clear_caches stage_unmount "$1" ipcrm -W rename_staged_to_ready "$1" stop_jail "$1" rename_active_to_last "$1" rename_ready_to_active "$1" add_jail_conf "$1" #add_automount "$1" tell_status "service jail start $1" service jail start "$1" || exit 1 enable_jail "$1" proclaim_success "$1" } stage_pkg_install() { echo "pkg -j $SAFE_NAME install -y $*" pkg -j "$SAFE_NAME" install -y "$@" } stage_port_install() { # $1 is the port directory (eg: mail/dovecot) stage_pkg_install pkgconf portconfig stage_exec make -C "/usr/ports/$1" build deinstall install clean || return 1 tell_status "port $1 installed" } stage_sysrc() { # don't use -j as this is oft called when jail is not running echo "sysrc -R $STAGE_MNT $*" sysrc -R "$STAGE_MNT" "$@" } stage_make_conf() { if grep -s "$1" "$STAGE_MNT/etc/make.conf"; then echo "preserving make.conf settings" return fi tell_status "setting $1 make.conf options" echo "$2" | tee -a "$STAGE_MNT/etc/make.conf" || exit } stage_exec() { echo "jexec $SAFE_NAME $*" jexec "$SAFE_NAME" "$@" } port_is_listening() { local _port=${1:-"25"} local _jail=${2:-"stage"} if [ -n "$(sockstat -l -q -4 -6 -p "$_port" -j "$_jail")" ]; then true else false fi } stage_listening() { local _port=${1:-"25"} local _max_tries=${2:-"3"} local _sleep=${3:-"1"} local _try=0 echo; echo -n "checking for port $_port listening in staged jail..." until port_is_listening "$_port"; do _try=$((_try + 1)) if [ "$_try" -gt "$_max_tries" ]; then echo "FAILED" exit 1 fi echo -n "." sleep "$_sleep" done echo "OK"; echo } stage_test_running() { echo "checking for process $1 in staged jail" pgrep -j stage "$1" || exit echo "ok" } unmount_pkg_cache() { if ! mount -t nullfs | grep -q "$STAGE_MNT/var/cache/pkg"; then return fi echo "unmount $STAGE_MNT/var/cache/pkg" umount "$STAGE_MNT/var/cache/pkg" || exit } freebsd_release_url_base() { _major_ver="$(/bin/freebsd-version | cut -f1 -d.)" if [ "$_major_ver" -lt "13" ]; then echo "http://ftp-archive.freebsd.org/pub/FreeBSD-Archive/old-releases" else echo "ftp://ftp.freebsd.org/pub/FreeBSD/releases" fi } stage_fbsd_package() { local _dest="$2" if [ -z "$_dest" ]; then _dest="$STAGE_MNT"; fi _file_uri="$(freebsd_release_url_base)/$(uname -m)/$FBSD_REL_VER/$1.txz" tell_status "downloading $_file_uri" fetch -m "$_file_uri" || exit echo "done" tell_status "extracting FreeBSD package $1.tgz to $_dest" tar -C "$_dest" -xpJf "$1.txz" || exit echo "done" } stage_setup_tls() { # static TLS certificates (installed at deploy) if [ ! -f "$STAGE_MNT/etc/ssl/certs/${TOASTER_MAIL_DOMAIN}.pem" ]; then tell_status "installing TLS certificate" cp /etc/ssl/certs/server.crt "$STAGE_MNT/etc/ssl/certs/${TOASTER_MAIL_DOMAIN}.pem" cp /etc/ssl/private/server.key "$STAGE_MNT/etc/ssl/private/${TOASTER_MAIL_DOMAIN}.pem" fi # dynamic TLS certs, kept up-to-date by acme.sh or certbot if [ ! -f "$STAGE_MNT/data/etc/tls/certs" ]; then # shellcheck disable=SC2174 mkdir -m 0644 -p "$STAGE_MNT/data/etc/tls/certs" cp /etc/ssl/certs/server.crt "$STAGE_MNT/data/etc/tls/certs/${TOASTER_MAIL_DOMAIN}.pem" fi if [ ! -f "$STAGE_MNT/data/etc/tls/private" ]; then # shellcheck disable=SC2174 mkdir -m 0640 -p "$STAGE_MNT/data/etc/tls/private" cp /etc/ssl/private/server.key "$STAGE_MNT/data/etc/tls/private/${TOASTER_MAIL_DOMAIN}.pem" fi } stage_enable_newsyslog() { tell_status "enabling newsyslog" sysrc -f "$STAGE_MNT/etc/rc.conf" newsyslog_enable=YES if [ ! -d "$STAGE_MNT/usr/local/etc/newsyslog.conf.d" ]; then mkdir "$STAGE_MNT/usr/local/etc/newsyslog.conf.d" fi sed -i.bak \ -e '/^#0.*newsyslog/ s/^#0/0/' \ "$STAGE_MNT/etc/crontab" } unmount_data() { # $1 is ZFS fs (eg: /data/mysql) local _data_vol; _data_vol="$ZFS_DATA_VOL/$1" if ! zfs_filesystem_exists "$_data_vol"; then return; fi local _data_mp="$STAGE_MNT/data" if mount -t nullfs | grep -q "$_data_mp"; then tell_status "unmounting data fs $_data_mp" umount -t nullfs "$_data_mp" fi } get_public_facing_nic() { local _ver=${1:-"ipv4"} export PUBLIC_NIC if [ "$_ver" = 'ipv6' ]; then PUBLIC_NIC=$(netstat -rn | grep default | awk '{ print $4 }' | tail -n1) else PUBLIC_NIC=$(netstat -rn | grep default | awk '{ print $4 }' | head -n1) fi if [ -z "$PUBLIC_NIC" ]; then echo "public NIC detection failed" exit 1 fi } get_public_ip() { local _ver=${1:-"ipv4"} get_public_facing_nic "$_ver" if [ "$_ver" = "ipv6" ]; then export PUBLIC_IP6 PUBLIC_IP6=$(ifconfig "$PUBLIC_NIC" inet6 | grep inet | grep -v fe80 | awk '{print $2}' | head -n1) else export PUBLIC_IP4 PUBLIC_IP4=$(ifconfig "$PUBLIC_NIC" inet | grep inet | awk '{print $2}' | head -n1) fi } fetch_and_exec() { mt6-fetch provision "$1.sh" sh "provision/$1.sh" } install_sentry() { if [ -z "$TOASTER_SENTRY" ]; then echo "TOASTER_SENTRY unset, skipping sentry" return fi tell_status "installing sentry" stage_pkg_install perl5 p5-Net-IP stage_exec mkdir /var/db/sentry || exit stage_exec fetch -o /var/db/sentry/sentry.pl --no-verify-peer https://raw.githubusercontent.com/msimerson/sentry/master/sentry.pl stage_exec perl /var/db/sentry/sentry.pl --update if [ -n "$TOASTER_NRPE" ]; then tell_status "installing nagios sentry plugin" stage_pkg_install nagios-plugins || exit stage_exec fetch -o /usr/local/libexec/nagios/check_sentry $TOASTER_SRC_URL/contrib/check_sentry fi } provision_mt6() { for _j in host base dns mysql redis clamav dcc geoip vpopmail rspamd spamassassin dovecot haraka haproxy webmail roundcube snappymail mailtest; do fetch_and_exec "$_j" || break done } provision_skeleton() { if [ -z "$3" ]; then echo "Usage:"; echo; echo "provision skel NAME IPv4 IPv6"; echo return fi mt6-fetch provision "skel.sh" sed -e "s/_skel/_$2/g" -e "s/ skel/ $2/g" provision/skel.sh > "provision/$2.sh" local _ucl="$ZFS_DATA_MNT/dns/unbound.conf.local" if ! grep -qs "$2" "$_ucl"; then tell_status "adding DNS for $2" tee -a "$_ucl" </dev/null | grep -q $1 } jail_rename() { if [ -z "$1" ] || [ -z "$2" ]; then echo "$0 " exit fi echo "renaming $1 to $2" service jail stop "$1" || exit for _f in data jails do zfs unmount "$ZFS_VOL/$_f/$1" zfs rename "$ZFS_VOL/$_f/$1" "$ZFS_VOL/$_f/$2" || exit zfs set mountpoint="/$_f/$2" "$ZFS_VOL/$_f/$2" || exit zfs mount "$ZFS_VOL/$_f/$2" done sed -i.bak \ -e "/^$1\s/ s/$1/$2/" \ /etc/jail.conf || exit service jail start "$2" echo "Don't forget to update your PF and/or Haproxy rules" } configure_pkg_latest() { local _pkg_host="pkg.FreeBSD.org" if [ -d "$ZFS_DATA_MNT/bsd_cache/pkg" ]; then tell_status "switching pkg to bsd_cache" _pkg_host="pkg" fi local REPODIR="$1/usr/local/etc/pkg/repos" if [ -f "$REPODIR/FreeBSD.conf" ]; then return; fi local _major_ver; _major_ver="$(/bin/freebsd-version | cut -f1 -d.)" local _repo_name="FreeBSD-ports" if [ "$_major_ver" -lt "15" ]; then _repo_name="FreeBSD"; fi tell_status "switching pkg from quarterly to latest" mkdir -p "$REPODIR" store_config "$REPODIR/FreeBSD.conf" "overwrite" < "$1" || exit 1 chmod 755 "$1" } # shellcheck disable=3044,3018 onexit() { while caller $((n++)); do :; done; } if [ "$TOASTER_BUILD_DEBUG" = "1" ]; then trap onexit EXIT fi