mirror of
				https://github.com/optim-enterprises-bv/secureblue.git
				synced 2025-10-31 18:37:47 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1016 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			1016 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| # Add additional boot parameters for hardening (requires reboot)
 | |
| set-kargs-hardening:
 | |
|     #!/usr/bin/bash
 | |
|     read -p "Do you need support for 32-bit processes/syscalls? (This is mostly used by legacy software, with some exceptions, such as Steam) [y/N]: " YES
 | |
|     if [[ "$YES" == [Yy]* ]]; then
 | |
|         echo "Keeping 32-bit support."
 | |
|     else
 | |
|         IAEMU_NO="--append-if-missing=ia32_emulation=0"
 | |
|         echo "Disabling 32-bit support, for the next boot."
 | |
|     fi
 | |
|     read -p "Do you want to force disable Simultaneous Multithreading (SMT) / Hyperthreading? (This can cause a reduction in the performance of certain tasks in favor of security) (Note that in most hardware SMT will be disabled anyways to mitigate a known vulnerability, this turns it off on all hardware regardless) [y/N]: " YES
 | |
|     if [[ "$YES" == [Yy]* ]]; then
 | |
|         NOSMT_YES="--append-if-missing=nosmt=force"
 | |
|         echo "Force disabling SMT/Hyperthreading."
 | |
|     else
 | |
|         echo "Not force disabling SMT/Hyperthreading."
 | |
|     fi
 | |
|     read -p "Would you like to set additional (unstable) hardening kargs? (Warning: Setting these kargs may lead to boot issues on some hardware.) [y/N]: " YES
 | |
|     if [[ "$YES" == [Yy]* ]]; then
 | |
|     UNSTABLE_YES="--append-if-missing=efi=disable_early_pci_dma \
 | |
|         --append-if-missing=debugfs=off"
 | |
|         echo "Setting unstable hardening kargs."
 | |
|     else
 | |
|         echo "Not setting unstable hardening kargs."
 | |
|     fi
 | |
|     echo "Applying boot parameters..."
 | |
|     rpm-ostree kargs \
 | |
|       ${UNSTABLE_YES:+$UNSTABLE_YES} ${IAEMU_NO:+$IAEMU_NO} ${NOSMT_YES:+$NOSMT_YES} \
 | |
|       --append-if-missing=init_on_alloc=1 \
 | |
|       --append-if-missing=init_on_free=1 \
 | |
|       --append-if-missing=slab_nomerge \
 | |
|       --append-if-missing=page_alloc.shuffle=1 \
 | |
|       --append-if-missing=randomize_kstack_offset=on \
 | |
|       --append-if-missing=vsyscall=none \
 | |
|       --append-if-missing=lockdown=confidentiality \
 | |
|       --append-if-missing=random.trust_cpu=off \
 | |
|       --append-if-missing=random.trust_bootloader=off \
 | |
|       --append-if-missing=iommu=force \
 | |
|       --append-if-missing=intel_iommu=on \
 | |
|       --append-if-missing=amd_iommu=force_isolation \
 | |
|       --append-if-missing=iommu.passthrough=0 \
 | |
|       --append-if-missing=iommu.strict=1 \
 | |
|       --append-if-missing=pti=on \
 | |
|       --append-if-missing=module.sig_enforce=1 \
 | |
|       --append-if-missing=mitigations=auto,nosmt \
 | |
|       --append-if-missing=spectre_v2=on \
 | |
|       --append-if-missing=spec_store_bypass_disable=on \
 | |
|       --append-if-missing=l1d_flush=on \
 | |
|       --append-if-missing=gather_data_sampling=force 
 | |
|     echo "Hardening kargs applied."
 | |
| 
 | |
| # Remove all hardening boot parameters (requires reboot)
 | |
| remove-kargs-hardening:
 | |
|     #!/usr/bin/bash
 | |
|     rpm-ostree kargs \
 | |
|       --delete-if-present="init_on_alloc=1" \
 | |
|       --delete-if-present="init_on_free=1" \
 | |
|       --delete-if-present="slab_nomerge" \
 | |
|       --delete-if-present="page_alloc.shuffle=1" \
 | |
|       --delete-if-present="randomize_kstack_offset=on" \
 | |
|       --delete-if-present="vsyscall=none" \
 | |
|       --delete-if-present="lockdown=confidentiality" \
 | |
|       --delete-if-present="random.trust_cpu=off" \
 | |
|       --delete-if-present="random.trust_bootloader=off" \
 | |
|       --delete-if-present="iommu=force" \
 | |
|       --delete-if-present="intel_iommu=on" \
 | |
|       --delete-if-present="amd_iommu=force_isolation" \
 | |
|       --delete-if-present="iommu.passthrough=0" \
 | |
|       --delete-if-present="iommu.strict=1" \
 | |
|       --delete-if-present="pti=on" \
 | |
|       --delete-if-present="module.sig_enforce=1" \
 | |
|       --delete-if-present="mitigations=auto,nosmt" \
 | |
|       --delete-if-present="efi=disable_early_pci_dma" \
 | |
|       --delete-if-present="debugfs=off" \
 | |
|       --delete-if-present="spectre_v2=on" \
 | |
|       --delete-if-present="spec_store_bypass_disable=on" \
 | |
|       --delete-if-present="l1d_flush=on" \
 | |
|       --delete-if-present="gather_data_sampling=force" \
 | |
|       --delete-if-present="ia32_emulation=0"
 | |
|     echo "Hardening kargs removed."
 | |
| 
 | |
| # Harden flatpaks by preloading hardened_malloc (highest supported hwcap)
 | |
| harden-flatpak:
 | |
|     #!/usr/bin/bash
 | |
|     flatpak override --user --filesystem=host-os:ro
 | |
|     uarches="$(/usr/lib64/ld-linux-x86-64.so.2 --help | grep '(supported, searched)' | cut -d'v' -f2)"
 | |
|     bestuarch="${uarches:0:1}"
 | |
|     if [ -z "$bestuarch" ] ; then
 | |
|         echo "No microarchitecture support detected. Using default x86-64-v1 architecture."
 | |
|         flatpak override --user --env=LD_PRELOAD=/var/run/host/usr/lib64/libhardened_malloc.so
 | |
|     else
 | |
|         echo "x86-64-v$bestuarch support detected. Using x86-64-v$bestuarch microarchitecture."
 | |
|         flatpak override --user --env=LD_PRELOAD=/var/run/host/usr/lib64/glibc-hwcaps/x86-64-v"$bestuarch"/libhardened_malloc.so
 | |
|     fi
 | |
| 
 | |
| # Toggle the cups service on/off
 | |
| toggle-cups:
 | |
|     #!/usr/bin/pkexec /usr/bin/bash
 | |
|     if systemctl is-enabled --quiet cups; then
 | |
|       firewall-cmd --permanent --remove-port=631/tcp
 | |
|       firewall-cmd --permanent --remove-port=631/udp 
 | |
|       firewall-cmd --reload 
 | |
|       systemctl mask cups
 | |
|       systemctl disable cups
 | |
|       systemctl stop cups
 | |
|       systemctl daemon-reload
 | |
|       echo "Cups disabled."
 | |
|     else
 | |
|       firewall-cmd --permanent --add-port=631/tcp
 | |
|       firewall-cmd --permanent --add-port=631/udp 
 | |
|       firewall-cmd --reload 
 | |
|       systemctl unmask cups
 | |
|       systemctl enable cups
 | |
|       systemctl start cups
 | |
|       systemctl daemon-reload
 | |
|       echo "Cups enabled."
 | |
|     fi
 | |
| 
 | |
| # Toggle bluetooth kernel modules on/off (requires reboot)
 | |
| toggle-bluetooth-modules:
 | |
|     #!/usr/bin/pkexec /usr/bin/bash
 | |
|     BLUE_MOD_FILE="/etc/modprobe.d/99-bluetooth.conf"
 | |
|     if test -e $BLUE_MOD_FILE; then
 | |
|       sudo rm -f $BLUE_MOD_FILE
 | |
|       echo "Bluetooth kernel modules disabled. Reboot to take effect."
 | |
|     else
 | |
|       sudo sh -c 'echo "install bluetooth /sbin/modprobe --ignore-install bluetooth" >> "$1"' _ "$BLUE_MOD_FILE"
 | |
|       sudo sh -c 'echo "install btusb /sbin/modprobe --ignore-install btusb" >> "$1"' _ "$BLUE_MOD_FILE"
 | |
|       sudo chmod 644 $BLUE_MOD_FILE
 | |
|       echo "Bluetooth kernel modules enabled. Reboot to take effect."
 | |
|     fi
 | |
| 
 | |
| # Toggle GHNS (KDE Get New Stuff)
 | |
| toggle-ghns:
 | |
|     #!/usr/bin/pkexec /usr/bin/bash
 | |
|     KDE_GLOBALS_FILE="/etc/xdg/kdeglobals"
 | |
|     if test -e $KDE_GLOBALS_FILE; then
 | |
|       if grep -q "ghns=false" "$KDE_GLOBALS_FILE"; then
 | |
|         sed -i "s/ghns=false/ghns=true/" "$KDE_GLOBALS_FILE"
 | |
|         echo "GHNS enabled."
 | |
|       elif grep -q "ghns=true" "$KDE_GLOBALS_FILE"; then
 | |
|         sed -i "s/ghns=true/ghns=false/" "$KDE_GLOBALS_FILE"
 | |
|         echo "GHNS disabled."
 | |
|       else 
 | |
|         echo "The kdeglobals file is missing the ghns toggle."
 | |
|       fi
 | |
|     else
 | |
|       echo "No kdeglobals file found. Are you on kinoite?"
 | |
|     fi
 | |
| 
 | |
| # enable a kernel module that is disabled by modprobe.d (requires restart)
 | |
| override-enable-module mod_name:
 | |
|     #!/usr/bin/pkexec /usr/bin/bash
 | |
|     MOD_NAME="{{ mod_name }}"
 | |
|     MOD_FILE="/etc/modprobe.d/99-$MOD_NAME.conf"
 | |
|     if test -e $MOD_FILE; then
 | |
|       echo "$MOD_NAME module is already enabled."
 | |
|     else
 | |
|       sudo sh -c 'echo "install $1 /sbin/modprobe --ignore-install $1" >> "$2"' _ "$MOD_NAME" "$MOD_FILE" 
 | |
|       sudo chmod 644 $MOD_FILE
 | |
|       echo "Override created to enable $MOD_NAME module. Reboot to take effect."
 | |
|     fi
 | |
| 
 | |
| # reset the override by `just override-enable-module`, i.e. disable the module again (requires restart)
 | |
| override-reset-module mod_name:
 | |
|     #!/usr/bin/pkexec /usr/bin/bash
 | |
|     MOD_NAME="{{ mod_name }}"
 | |
|     MOD_FILE="/etc/modprobe.d/99-$MOD_NAME.conf"
 | |
|     if test -e $MOD_FILE; then
 | |
|       sudo rm -f $MOD_FILE
 | |
|       echo "The override for $MOD_NAME module has been reset. Reboot to take effect."
 | |
|     else
 | |
|       echo "No override found for $MOD_NAME module."
 | |
|     fi
 | |
| 
 | |
| # Setup USBGuard
 | |
| setup-usbguard:
 | |
|     #!/usr/bin/bash
 | |
|     echo "Notice: This will generate a policy based on your existing connected USB devices."
 | |
|     ACTIVE_USERNAME=$(whoami)
 | |
|     pkexec sh -c '
 | |
|         mkdir -p /var/log/usbguard
 | |
|         mkdir -p /etc/usbguard
 | |
|         chmod 755 /etc/usbguard
 | |
|         usbguard generate-policy > /etc/usbguard/rules.conf
 | |
|         systemctl enable --now usbguard.service
 | |
|         usbguard add-user $1
 | |
|     ' -- $ACTIVE_USERNAME
 | |
|     systemctl enable --user --now usbguard-notifier.service
 | |
| 
 | |
| # Rerun Yafti
 | |
| rerun-yafti:
 | |
|     yafti -f /usr/share/ublue-os/firstboot/yafti.yml
 | |
| 
 | |
| # Toggle anticheat support by changing ptrace scope (requires restart)
 | |
| toggle-anticheat-support:
 | |
|     #!/usr/bin/pkexec /usr/bin/bash
 | |
|     SYSCTL_HARDENING_FILE="/etc/sysctl.d/hardening.conf"
 | |
|     if grep -q "kernel.yama.ptrace_scope = 3" "$SYSCTL_HARDENING_FILE"; then
 | |
|         sed -i "s/kernel.yama.ptrace_scope = 3/kernel.yama.ptrace_scope = 1/" "$SYSCTL_HARDENING_FILE"
 | |
|         echo "Anticheat support enabled. ptrace_scope set to 1."
 | |
|     elif grep -q "kernel.yama.ptrace_scope = 1" "$SYSCTL_HARDENING_FILE"; then
 | |
|         sed -i "s/kernel.yama.ptrace_scope = 1/kernel.yama.ptrace_scope = 3/" "$SYSCTL_HARDENING_FILE"
 | |
|         echo "Anticheat support disabled. ptrace_scope set back to 3."
 | |
|     else 
 | |
|         echo "The sysctl hardening file is missing the ptrace_scope setting."
 | |
|     fi
 | |
| 
 | |
| # Toggle Gnome JIT JavaScript for GJS and WebkitGTK (requires session restart)
 | |
| toggle-gnome-jit-js:
 | |
|     #!/usr/bin/pkexec /usr/bin/bash
 | |
|     ENV_FILE="/etc/profile.d/gnome-disable-jit.sh"
 | |
|     if test -e $ENV_FILE; then
 | |
|         sudo rm -f $ENV_FILE
 | |
|         echo "JIT JavaScript for Gnome and WebkitGTK has been enabled."
 | |
|     else
 | |
|         sudo cp /usr$ENV_FILE $ENV_FILE
 | |
|         sudo chmod 644 $ENV_FILE
 | |
|         echo "JIT JavaScript for Gnome and WebkitGTK has been disabled."
 | |
|     fi
 | |
| 
 | |
| # Toggle support for using GNOME user extensions
 | |
| toggle-gnome-extensions:
 | |
|     #!/usr/bin/bash
 | |
|     GSETTING="$(gsettings get org.gnome.shell allow-extension-installation)"
 | |
|     if [[ "${GSETTING}" == "false" ]]; then
 | |
|       gsettings set org.gnome.shell allow-extension-installation true
 | |
|       echo "Support for GNOME user extensions have been enabled"
 | |
|     else
 | |
|       gsettings reset org.gnome.shell allow-extension-installation
 | |
|       echo "Support for GNOME user extensions have been disabled"
 | |
|     fi
 | |
| 
 | |
| # Toggle Xwayland support
 | |
| toggle-xwayland ACTION="prompt":
 | |
|     #!/usr/bin/pkexec /usr/bin/bash
 | |
|     source /usr/lib/ujust/ujust.sh
 | |
|     OPTION={{ ACTION }}
 | |
|     if [ "$OPTION" == "prompt" ]; then
 | |
|       echo "${bold}Toggling Xwayland (requires logout)${normal}"
 | |
|       echo 'For which DE/WM do you want to toggle Xwayland?'
 | |
|       OPTION=$(ugum choose "GNOME" "KDE Plasma" "Sway")
 | |
|     elif [ "$OPTION" == "help" ]; then
 | |
|       echo "Usage: ujust toggle-xwayland <option>"
 | |
|       echo "  <option>: Specify the quick option - 'gnome', 'plasma', or 'sway'"
 | |
|       echo "  Use 'gnome' to Toggle Xwayland for GNOME."
 | |
|       echo "  Use 'plasma' to Toggle Xwayland for KDE Plasma."
 | |
|       echo "  Use 'sway' to Toggle Xwayland for Sway."
 | |
|       exit 0
 | |
|     fi
 | |
|     if [ "$OPTION" == "GNOME" ] || [ "${OPTION,,}" == "gnome" ]; then
 | |
|       GNOME_XWAYLAND_FILE="/etc/systemd/user/org.gnome.Shell@wayland.service.d/override.conf"
 | |
|       if test -e $GNOME_XWAYLAND_FILE; then
 | |
|         sudo rm -f $GNOME_XWAYLAND_FILE
 | |
|         echo "Xwayland for GNOME has been enabled."
 | |
|       else
 | |
|         sudo cp /usr$GNOME_XWAYLAND_FILE $GNOME_XWAYLAND_FILE
 | |
|         sudo chmod 644 $GNOME_XWAYLAND_FILE
 | |
|         echo "Xwayland for GNOME has been disabled."
 | |
|       fi
 | |
|     elif [ "$OPTION" == "KDE Plasma" ] || [ "${OPTION,,}" == "plasma" ]; then
 | |
|       PLASMA_XWAYLAND_FILE="/etc/systemd/user/plasma-kwin_wayland.service.d/override.conf"
 | |
|       if test -e $PLASMA_XWAYLAND_FILE; then
 | |
|         sudo rm -f $PLASMA_XWAYLAND_FILE
 | |
|         echo "Xwayland for KDE Plasma has been enabled."
 | |
|       else
 | |
|         sudo cp /usr$PLASMA_XWAYLAND_FILE $PLASMA_XWAYLAND_FILE
 | |
|         sudo chmod 644 $PLASMA_XWAYLAND_FILE
 | |
|         echo "Xwayland for KDE Plasma has been disabled."
 | |
|       fi
 | |
|     elif [ "$OPTION" == "Sway" ] || [ "${OPTION,,}" == "sway" ]; then
 | |
|       SWAY_XWAYLAND_FILE="/etc/sway/config.d/99-noxwayland.conf"
 | |
|       if test -e $SWAY_XWAYLAND_FILE; then
 | |
|         sudo rm -f $SWAY_XWAYLAND_FILE
 | |
|         echo "Xwayland for Sway has been enabled."
 | |
|       else
 | |
|         sudo cp /usr$SWAY_XWAYLAND_FILE $SWAY_XWAYLAND_FILE
 | |
|         sudo chmod 644 $SWAY_XWAYLAND_FILE
 | |
|         echo "Xwayland for Sway has been disabled."
 | |
|       fi
 | |
|     fi
 | |
| 
 | |
| # Toggle bash environment lockdown (mitigates LD_PRELOAD attacks)
 | |
| toggle-bash-environment-lockdown:
 | |
|     #!/usr/bin/bash
 | |
|     BASH_ENV_FILES=("$HOME/.bashrc" "$HOME/.bash_profile")
 | |
|     echo "${b}WARNING${n} This will overwrite your .bashrc and .bash_profile."
 | |
|     echo "This is needed to ensure the mitigation is effective."
 | |
|     echo "Do you understand?"
 | |
|     echo "Please type in \"YES I UNDERSTAND\" and press enter"
 | |
|     read ACCEPT
 | |
|     if [ "$ACCEPT" == "YES I UNDERSTAND" ]; then
 | |
|       if lsattr "${BASH_ENV_FILES[0]}" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then
 | |
|         echo "Bash environment '(${BASH_ENV_FILES[@]})' is locked down. Unlocking it."
 | |
|         for file in "${BASH_ENV_FILES[@]}"; do
 | |
|             pkexec chattr -i "$file"
 | |
|         done
 | |
|       else
 | |
|         echo "Bash environment '(${BASH_ENV_FILES[@]})' is unlocked. Locking it."
 | |
|         echo "
 | |
|     # .bashrc
 | |
| 
 | |
|     # Source global definitions
 | |
|     if [ -f /etc/bashrc ]; then
 | |
|         . /etc/bashrc
 | |
|     fi
 | |
| 
 | |
|     # User specific environment
 | |
|     if ! [[ "\$PATH" =~ "\$HOME/.local/bin:\$HOME/bin:" ]]; then
 | |
|         PATH="\$HOME/.local/bin:\$HOME/bin:\$PATH"
 | |
|     fi
 | |
|     export PATH
 | |
| 
 | |
|     # Uncomment the following line if you don't like systemctl's auto-paging feature:
 | |
|     # export SYSTEMD_PAGER=
 | |
| 
 | |
|     unset rc
 | |
|           " > ~/.bashrc
 | |
| 
 | |
|         echo "
 | |
|     # .bash_profile
 | |
| 
 | |
|     # Get the aliases and functions
 | |
|     if [ -f ~/.bashrc ]; then
 | |
|         . ~/.bashrc
 | |
|     fi
 | |
| 
 | |
|     # User specific environment and startup programs
 | |
|         " > ~/.bash_profile
 | |
| 
 | |
|         for file in "${BASH_ENV_FILES[@]}"; do
 | |
|             pkexec chattr +i "$file"
 | |
|         done
 | |
|       fi
 | |
|     else
 | |
|       echo "Capitalization matters when you type \"YES I UNDERSTAND\""
 | |
|     fi
 | |
| 
 | |
| # Audit secureblue
 | |
| audit-secureblue:
 | |
|     #!/bin/bash
 | |
| 
 | |
|     STATUS_SUCCESS="SUCCESS"
 | |
|     STATUS_WARNING="WARNING"
 | |
|     STATUS_FAILURE="FAILURE"
 | |
|     print_status() {
 | |
|         local check_name="$1"
 | |
|         local status="$2"
 | |
| 
 | |
|         local color_code
 | |
|         case "$status" in
 | |
|             $STATUS_SUCCESS) color_code=32 ;; # Green
 | |
|             $STATUS_WARNING) color_code=33 ;; # Yellow
 | |
|             $STATUS_FAILURE) color_code=31 ;;    # Red
 | |
|             *) color_code=0 ;;
 | |
|         esac
 | |
| 
 | |
|         local formatted_status
 | |
|         formatted_status=$(printf "%*s" $(( (7 + ${#status}) / 2 )) "$status")
 | |
|         formatted_status=$(printf "%-7s" "$formatted_status")
 | |
| 
 | |
|         printf "%-64s [ \033[%dm%s\033[0m ]\n" "$check_name"... "$color_code" "$formatted_status"
 | |
|     }
 | |
| 
 | |
|     hasPermission() {
 | |
|         local permissions=$1
 | |
|         local prefix=$2
 | |
|         local query=$3
 | |
|         local line=$(grep "^${prefix}=" <<< "$permissions" | sed -e "s/^${prefix}=//" -e "s/#.*//")
 | |
|         IFS=';' read -r -a list <<< "$line"
 | |
|         for p in ${list[@]}; do
 | |
|             if [[ "$p" =~ ^$query$ ]]; then
 | |
|                 return
 | |
|             fi
 | |
|         done
 | |
|         return 1
 | |
|     }
 | |
| 
 | |
|     KARGS=$(rpm-ostree kargs)
 | |
|     KARGS_LIST=(
 | |
|         "init_on_alloc=1"
 | |
|         "init_on_free=1"
 | |
|         "slab_nomerge"
 | |
|         "page_alloc.shuffle=1"
 | |
|         "randomize_kstack_offset=on"
 | |
|         "vsyscall=none"
 | |
|         "lockdown=confidentiality"
 | |
|         "random.trust_cpu=off"
 | |
|         "random.trust_bootloader=off"
 | |
|         "iommu=force"
 | |
|         "intel_iommu=on"
 | |
|         "amd_iommu=force_isolation"
 | |
|         "iommu.passthrough=0"
 | |
|         "iommu.strict=1"
 | |
|         "pti=on"
 | |
|         "module.sig_enforce=1"
 | |
|         "mitigations=auto,nosmt"
 | |
|         "spectre_v2=on"
 | |
|         "spec_store_bypass_disable=on"
 | |
|         "l1d_flush=on"
 | |
|         "gather_data_sampling=force"
 | |
|         "efi=disable_early_pci_dma"
 | |
|         "debugfs=off"
 | |
|         "ia32_emulation=0"
 | |
|     )
 | |
| 
 | |
|     for karg in "${KARGS_LIST[@]}"; do
 | |
|         KARG_TEST_STRING="Checking for $karg karg"
 | |
|         if echo "$KARGS" | grep -q "$karg"; then
 | |
|             print_status "$KARG_TEST_STRING" "$STATUS_SUCCESS"
 | |
|         else
 | |
|             print_status "$KARG_TEST_STRING" "$STATUS_FAILURE"
 | |
|         fi
 | |
|     done
 | |
| 
 | |
|     SYSCTL_TEST_STRING="Ensuring no sysctl overrides"
 | |
|     readarray -t sysctl_hardening_conf < <(grep -v -E -e "^#" -e "^$" </usr/etc/sysctl.d/hardening.conf)
 | |
|     declare -A sysctl_hardening
 | |
|     for line in "${sysctl_hardening_conf[@]}"; do
 | |
|         parameter="$(sed -E -e "s/(.*) = .*/\1/"  <<<"$line")"
 | |
|         value="$(sed -E "s/.* = (.*)/\1/" <<<"$line")"
 | |
|         sysctl_hardening["$parameter"]+="$value"
 | |
|     done
 | |
|     sysctl_results="$(sysctl -a 2> >(grep -v "sysctl: permission denied on key "))"
 | |
|     sysctl_errors=()
 | |
|     for sysctl_parameter in "${!hardening[@]}"; do
 | |
|         hardened_parameter_value="${hardening["$sysctl_parameter"]}"
 | |
|         parameter_name="$(sed -E -e "s/\./\\\./g" -e "s/\*/\.\*/" <<<"$sysctl_parameter")"
 | |
|         readarray -t sysctl_parameter_values < <(grep -E "^$key = " <<<"$sysctl_results")
 | |
|         for parameter_value in "${sysctl_parameter_values[@]}"; do
 | |
|             parameter_value="$(sed -E  -e "s/.* = (.*)/\1/" -e "s/\t/ /g" <<<"$result" | tr -s " " )"
 | |
|             if [[ "$parameter_value" != "$hardened_parameter_value" && ("$hardened_parameter_value" != 0 && "$parameter_value" != disabled) ]]; then
 | |
|                 sysctl_errors+=("$sysctl_parameter should be $hardened_parameter_value, found $parameter_value")
 | |
|             fi
 | |
|         done
 | |
|     done
 | |
|     if [[ "${#sysctl_errors}" == 0 ]] && diff /usr/etc/sysctl.d/hardening.conf /etc/sysctl.d/hardening.conf > /dev/null; then
 | |
|         print_status "$SYSCTL_TEST_STRING" "$STATUS_SUCCESS"
 | |
|     else
 | |
|         print_status "$SYSCTL_TEST_STRING" "$STATUS_FAILURE"
 | |
|         for error in "${sysctl_errors[@]}"; do
 | |
|             echo "> $error"
 | |
|         done
 | |
|     fi
 | |
| 
 | |
|     SIGNED_IMAGE_TEST_STRING="Ensuring a signed image is in use"
 | |
|     if rpm-ostree status | grep -q "● ostree-image-signed"; then
 | |
|         print_status "$SIGNED_IMAGE_TEST_STRING" "$STATUS_SUCCESS"
 | |
|     else
 | |
|         print_status "$SIGNED_IMAGE_TEST_STRING" "$STATUS_FAILURE"
 | |
|     fi
 | |
| 
 | |
|     MODPROBE_TEST_STRING="Ensuring no modprobe overrides"
 | |
|     readarray -t unwanted_modules < <(comm -12 <(lsmod | cut -f 1 -d " " | sort) <(cat /usr/etc/modprobe.d/blacklist.conf | grep -E '^(blacklist)|(install)' | cut -f 2 -d " " | sort))
 | |
|     if [[ "${#unwanted_modules[@]}" == 0 ]] && diff /usr/etc/modprobe.d/blacklist.conf /etc/modprobe.d/blacklist.conf > /dev/null; then
 | |
|         print_status "$MODPROBE_TEST_STRING" "$STATUS_SUCCESS"
 | |
|     else
 | |
|         print_status "$MODPROBE_TEST_STRING" "$STATUS_FAILURE"
 | |
|         for module in "${unwanted_modules[@]}"; do
 | |
|             echo "> $module is in blacklist.conf but it is loaded"
 | |
|             if [[ "$module" == "bluetooth" ]]; then
 | |
|                 bluetooth_loaded=true
 | |
|             fi
 | |
|         done
 | |
|     fi
 | |
| 
 | |
|     PTRACE_TEST_STRING="Ensuring ptrace is forbidden"
 | |
|     if [[ "$(cat /proc/sys/kernel/yama/ptrace_scope)" == 3 ]]; then
 | |
|         print_status "$PTRACE_TEST_STRING" "$STATUS_SUCCESS"
 | |
|     else
 | |
|         print_status "$PTRACE_TEST_STRING" "$STATUS_FAILURE"
 | |
|         ptrace_allowed=true
 | |
|     fi
 | |
| 
 | |
|     AUTHSELECT_TEST_STRING="Ensuring no authselect overrides"
 | |
|     if diff /usr/etc/authselect /etc/authselect --suppress-common-lines -r > /dev/null; then
 | |
|         print_status "$AUTHSELECT_TEST_STRING" "$STATUS_SUCCESS"
 | |
|     else
 | |
|         print_status "$AUTHSELECT_TEST_STRING" "$STATUS_FAILURE"
 | |
|     fi
 | |
| 
 | |
|     CONTAINER_POLICY_TEST_STRING="Ensuring no container policy overrides"
 | |
|     if diff /usr/etc/containers/policy.json /etc/containers/policy.json > /dev/null && [ ! -f $HOME/.config/containers/policy.json ]; then
 | |
|         print_status "$CONTAINER_POLICY_TEST_STRING" "$STATUS_SUCCESS"
 | |
|     else
 | |
|         print_status "$CONTAINER_POLICY_TEST_STRING" "$STATUS_FAILURE"
 | |
|     fi
 | |
| 
 | |
|     USBGUARD_TEST_STRING="Ensuring usbguard is active"
 | |
|     if systemctl is-active --quiet usbguard; then
 | |
|         print_status "$USBGUARD_TEST_STRING" "$STATUS_SUCCESS"
 | |
|     else
 | |
|         print_status "$USBGUARD_TEST_STRING" "$STATUS_FAILURE"
 | |
|     fi
 | |
| 
 | |
|     CHRONYD_TEST_STRING="Ensuring chronyd is active"
 | |
|     if systemctl is-active --quiet chronyd; then
 | |
|         print_status "$CHRONYD_TEST_STRING" "$STATUS_SUCCESS"
 | |
|     else
 | |
|         print_status "$CHRONYD_TEST_STRING" "$STATUS_FAILURE"
 | |
|     fi
 | |
| 
 | |
|     SECUREDNS_TEST_STRING="Ensuring system DNS resolution is secure"
 | |
|     if systemctl is-active --quiet systemd-resolved; then
 | |
|         DNSSEC_STATUS="$(cat /etc/systemd/resolved.conf.d/10-securedns.conf | grep "DNSSEC")"
 | |
|         DOT_STATUS="$(cat /etc/systemd/resolved.conf.d/10-securedns.conf | grep "DNSOverTLS")"
 | |
|         if [[ "$DNSSEC_STATUS" == "DNSSEC=true" && "$DOT_STATUS" == "DNSOverTLS=true" ]]; then
 | |
|             print_status "$SECUREDNS_TEST_STRING" "$STATUS_SUCCESS"
 | |
|         else
 | |
|             print_status "$SECUREDNS_TEST_STRING" "$STATUS_FAILURE"
 | |
|         fi
 | |
|     else
 | |
|         print_status "$SECUREDNS_TEST_STRING" "$STATUS_FAILURE"
 | |
|     fi
 | |
| 
 | |
|     BASH_TEST_STRING="Ensuring bash environment lockdown"
 | |
|     BASH_ENV_FILES=(~/.bashrc ~/.bash_profile)
 | |
|     all_locked=1
 | |
| 
 | |
|     for file in "${BASH_ENV_FILES[@]}"; do
 | |
|         if [ -f "$file" ]; then
 | |
|             if lsattr "$file" 2>/dev/null | awk '{print $1}' | grep -q 'i'; then
 | |
|                 continue
 | |
|             else
 | |
|                 all_locked=0
 | |
|                 break
 | |
|             fi
 | |
|         else
 | |
|             all_locked=0
 | |
|             break
 | |
|         fi
 | |
|     done
 | |
| 
 | |
|     if [ "$all_locked" -eq 1 ]; then
 | |
|         print_status "$BASH_TEST_STRING" "$STATUS_SUCCESS"
 | |
|     else
 | |
|         print_status "$BASH_TEST_STRING" "$STATUS_FAILURE"
 | |
|     fi
 | |
| 
 | |
|     WHEEL_TEST_STRING="Ensuring user is not a member of wheel"
 | |
|     if groups | grep -q "\bwheel\b"; then
 | |
|         print_status "$WHEEL_TEST_STRING" "$STATUS_FAILURE"
 | |
|     else
 | |
|         print_status "$WHEEL_TEST_STRING" "$STATUS_SUCCESS"
 | |
|     fi
 | |
| 
 | |
|     GNOME_XWAYLAND_TEST_STRING="Ensuring xwayland is disabled for GNOME"
 | |
|     if [ -f "/etc/systemd/user/org.gnome.Shell@wayland.service.d/override.conf" ]; then
 | |
|         print_status "$GNOME_XWAYLAND_TEST_STRING" "$STATUS_SUCCESS"
 | |
|     else
 | |
|         print_status "$GNOME_XWAYLAND_TEST_STRING" "$STATUS_FAILURE"
 | |
|     fi
 | |
| 
 | |
|     PLASMA_XWAYLAND_TEST_STRING="Ensuring xwayland is disabled for KDE Plasma"
 | |
|     if [ -f "/etc/systemd/user/plasma-kwin_wayland.service.d/override.conf" ]; then
 | |
|         print_status "$PLASMA_XWAYLAND_TEST_STRING" "$STATUS_SUCCESS"
 | |
|     else
 | |
|         print_status "$PLASMA_XWAYLAND_TEST_STRING" "$STATUS_FAILURE"
 | |
|     fi
 | |
| 
 | |
|     SWAY_XWAYLAND_TEST_STRING="Ensuring xwayland is disabled for Sway"
 | |
|     if [ -f "/etc/sway/config.d/99-noxwayland.conf" ]; then
 | |
|         print_status "$SWAY_XWAYLAND_TEST_STRING" "$STATUS_SUCCESS"
 | |
|     else
 | |
|         print_status "$SWAY_XWAYLAND_TEST_STRING" "$STATUS_FAILURE"
 | |
|     fi
 | |
| 
 | |
|     EXTENSIONS_TEST_STRING="Ensuring GNOME user extensions are disabled"
 | |
|     if command -v gnome-shell &> /dev/null; then
 | |
|         if [ "$(gsettings get org.gnome.shell allow-extension-installation)" = "false" ]; then
 | |
|             print_status "$EXTENSIONS_TEST_STRING" "$STATUS_SUCCESS"
 | |
|         else
 | |
|             print_status "$EXTENSIONS_TEST_STRING" "$STATUS_FAILURE"
 | |
|         fi
 | |
|     fi
 | |
| 
 | |
|     SELINUX_TEST_STRING="Ensuring SELinux is in Enforcing mode"
 | |
|     if [ "$(getenforce)" = "Enforcing" ]; then
 | |
|         print_status "$SELINUX_TEST_STRING" "$STATUS_SUCCESS"
 | |
|     else
 | |
|         print_status "$SELINUX_TEST_STRING" "$STATUS_FAILURE"
 | |
|     fi
 | |
| 
 | |
|     ENVIRONMENT_TEST_STRING="Ensuring no environment file overrides"
 | |
|     if diff /usr/etc/environment /etc/environment > /dev/null; then
 | |
|         print_status "$ENVIRONMENT_TEST_STRING" "$STATUS_SUCCESS"
 | |
|     else
 | |
|         print_status "$ENVIRONMENT_TEST_STRING" "$STATUS_WARNING"
 | |
|     fi
 | |
| 
 | |
|     GHNS_TEST_STRING="Ensuring KDE GHNS is disabled"
 | |
|     KDE_GLOBALS_FILE="/etc/xdg/kdeglobals"
 | |
|     if test -e $KDE_GLOBALS_FILE; then
 | |
|         GHNS_STRING="$(grep 'ghns=false' $KDE_GLOBALS_FILE)"
 | |
|         if [[ $GHNS_STRING == "ghns=false" ]]; then
 | |
|             print_status "$GHNS_TEST_STRING" "$STATUS_SUCCESS"
 | |
|         else
 | |
|             print_status "$GHNS_TEST_STRING" "$STATUS_FAILURE"
 | |
|         fi
 | |
|     fi
 | |
| 
 | |
|     HARDENED_MALLOC_TEST_STRING="Ensuring hardened_malloc is set in ld.so.preload"
 | |
|     if diff /usr/etc/ld.so.preload /etc/ld.so.preload > /dev/null; then
 | |
|         print_status "$HARDENED_MALLOC_TEST_STRING" "$STATUS_SUCCESS"
 | |
|     else
 | |
|         print_status "$HARDENED_MALLOC_TEST_STRING" "$STATUS_FAILURE"
 | |
|     fi
 | |
| 
 | |
|     SECUREBOOT_TEST_STRING="Ensuring secure boot is enabled"
 | |
|     if [ "$(mokutil --sb-state)" == "SecureBoot enabled" ]; then
 | |
|         print_status "$SECUREBOOT_TEST_STRING" "$STATUS_SUCCESS"
 | |
|     else
 | |
|         print_status "$SECUREBOOT_TEST_STRING" "$STATUS_FAILURE"
 | |
|     fi
 | |
| 
 | |
|     if command -v flatpak &> /dev/null; then
 | |
|         remotes="$(flatpak remotes -d)"
 | |
|         while read -r remote ; do
 | |
|             ref="$(cut -f 1 <<<"$remote")"
 | |
|             url="$(cut -f 3 <<< "$remote")"
 | |
|             subset="$(cut -f 5 <<< "$remote")"
 | |
|             remote_string="Auditing flatpak remote $ref"
 | |
|             if [[ "$url" != "https://dl.flathub.org/repo/" && "$url" != "https://dl.flathub.org/beta-repo/" ]]; then
 | |
|                 print_status "$remote_string" "$STATUS_FAILURE"
 | |
|                 echo "> $ref is configured with an unknown url!"
 | |
|             elif [ "$subset" != "verified" ]; then
 | |
|                 print_status "$remote_string" "$STATUS_FAILURE"
 | |
|                 echo "> $ref is not a verified repo!"
 | |
|             else
 | |
|                 print_status "$remote_string" "$STATUS_SUCCESS"
 | |
|             fi
 | |
|         done <<< "$remotes"
 | |
| 
 | |
|         declare -A flatpaks
 | |
|         while read -r ref version; do
 | |
|             flatpaks+=(["${ref}"]="${ref}//${version}")
 | |
|         done < <(flatpak list | sort -k 1 | cut --fields 2,4)
 | |
| 
 | |
|         for f in ${!flatpaks[@]}; do
 | |
|             warnings=()
 | |
|             status="$STATUS_SUCCESS"
 | |
|             fullref=${flatpaks["$f"]}
 | |
|             permissions=$(flatpak info --show-permissions "$fullref")
 | |
| 
 | |
|             if hasPermission "$permissions" "shared" "network"; then
 | |
|                 [[ "$status" != "$STATUS_FAILURE" ]] && status="$STATUS_WARNING"
 | |
|                 warnings+=("> $f has network access!")
 | |
|             fi
 | |
|             if hasPermission "$permissions" "sockets" "x11" && ! hasPermission "$permissions" "sockets" "fallback-x11"; then
 | |
|                 status="$STATUS_FAILURE"
 | |
|                 warnings+=("> $f has x11 access!")
 | |
|             fi
 | |
|             if hasPermission "$permissions" "sockets" "session-bus"; then
 | |
|                 [[ "$status" != "$STATUS_FAILURE" ]] && status="$STATUS_WARNING"
 | |
|                 warnings+=("> $f has access to the D-Bus session bus!")
 | |
|             fi
 | |
|             if hasPermission "$permissions" "sockets" "system-bus"; then
 | |
|                 [[ "$status" != "$STATUS_FAILURE" ]] && status="$STATUS_WARNING"
 | |
|                 warnings+=("> $f has access to the D-Bus system bus!")
 | |
|             fi
 | |
|             if ! hasPermission "$permissions" "LD_PRELOAD" .*"/libhardened_malloc.so"; then
 | |
|                 status="$STATUS_FAILURE"
 | |
|                 warnings+=("> $f is not using hardened_malloc!")
 | |
|             fi
 | |
|             if [[ "$bluetooth_loaded" == "true" ]] && hasPermission "$permissions" "features" "bluetooth"; then
 | |
|                 status="$STATUS_FAILURE"
 | |
|                 warnings+=("> $f has bluetooth access!")
 | |
|             fi
 | |
|             if [[ "$ptrace_allowed" == "true" ]] && hasPermission "$permissions" "features" "devel"; then
 | |
|                 status="$STATUS_FAILURE"
 | |
|                 warnings+=("> $f has ptrace access!")
 | |
|             fi
 | |
|             if hasPermission "$permissions" "shared" "ipc"; then
 | |
|             status="$STATUS_FAILURE"
 | |
|                 warnings+=("> $f has inter-process communications access!")
 | |
|             fi
 | |
|             flatpak_test_string="Auditing $f"
 | |
|             print_status "$flatpak_test_string" "$status"
 | |
|             for warning in "${warnings[@]}"; do
 | |
|                 echo "$warning"
 | |
|             done
 | |
|         done
 | |
|     fi
 | |
| 
 | |
| # Debug dump pastebin for issue reporting
 | |
| debug-info:
 | |
|     #!/usr/bin/bash
 | |
|     rpm_ostree_status=$(echo -e "=== Rpm-Ostree Status ===\n"; rpm-ostree status --verbose)
 | |
|     sysinfo=$(echo -e "\n"; fpaste --sysinfo --printonly)
 | |
|     flatpaks=$(echo "=== Flatpaks Installed ==="; flatpak list --columns=application,version,options)
 | |
|     audit_results=$(echo -e "\n=== Audit Results ===\n"; ujust audit-secureblue)
 | |
|     local_overrides=$(echo -e "\n=== Listing Local Overrides ===\n"; ujust check-local-overrides)
 | |
|     recent_events=$(echo -e "\n=== Recent System Events ===\n"; journalctl -b -p err..alert --since "1 hour ago")
 | |
|     failed_services=$(echo -e "\n=== Failed Services ===\n"; systemctl list-units --state=failed)
 | |
|     content="$rpm_ostree_status$sysinfo$flatpaks$audit_results$local_overrides$recent_events$failed_services"
 | |
|     echo "$content" | fpaste --confirm --private=1
 | |
| 
 | |
| # setup system DNS resolution
 | |
| dns-selector:
 | |
|     #! /bin/run0 /bin/bash
 | |
|     # constants
 | |
|     readonly resolved_conf="/etc/systemd/resolved.conf.d/10-securedns.conf"
 | |
|     readonly policy_file="/etc/chromium/policies/managed/10-securedns-browser.json"
 | |
|     mkdir -p /etc/systemd/resolved.conf.d/
 | |
|     mkdir -p /etc/chromium/policies/managed/
 | |
|     # variables
 | |
|     valid_input="0"
 | |
|     resolver_selection=""
 | |
|     resolver_subselection=""
 | |
|     resolver_has_second_ip=""
 | |
|     resolver_supports_ipv6=""
 | |
|     resolver_ipv4_address=""
 | |
|     resolver_ipv4_address_2=""
 | |
|     resolver_ipv6_address=""
 | |
|     resolver_ipv6_address_2=""
 | |
|     resolver_hostname=""
 | |
|     resolver_https_address=""
 | |
|     set_browser_policy=""
 | |
| 
 | |
|     echo "Below will be some options to set the DNS resolver for systemd-resolved."
 | |
|     echo "All resolvers support DNS-over-TLS (DoT) or DNS-over-QUIC (DoQ), DNS-over-HTTPS (DoH), and DNSSEC."
 | |
|     echo "Please select which DNS resolver you would like to set:"
 | |
|     echo "    0) Network Resolver - security may vary (system default state)"
 | |
|     echo "    1) Control D - has content filtering, anycast"
 | |
|     echo "    2) Mullvad - has content filtering, anycast"
 | |
|     echo "    3) Cloudflare - very fast with some data collection, anycast"
 | |
|     echo "    4) DNSForge - powerful filtering but can be very slow"
 | |
|     echo "    5) Custom Resolver - use a custom resolver (must support DoT/DoQ and DNSSEC, DoH support is also required to set a browser policy should that be desired)"
 | |
|     while [[ "$valid_input" == "0" ]]; do
 | |
|         read -p "Selection [0-5]: " resolver_selection
 | |
|         if [[ "$resolver_selection" == [012345]* ]]; then
 | |
|             valid_input="1"
 | |
|         else
 | |
|             echo "That is not a valid selection."
 | |
|         fi
 | |
|     done
 | |
|     valid_input="0"
 | |
| 
 | |
|     echo "" # blank space
 | |
|     case "$resolver_selection" in
 | |
|         0)
 | |
|             echo "Resetting resolved to default state."
 | |
|             if [[ -f "$policy_file" ]]; then
 | |
|                 rm $policy_file
 | |
|                 echo "Removed browser policy."
 | |
|             fi
 | |
|             cp /usr$resolved_conf $resolved_conf
 | |
|             systemctl restart systemd-resolved
 | |
|             echo "Configuration file for resolved reset and service restarted."
 | |
|             exit 0
 | |
|             ;;
 | |
|         1)
 | |
|             resolver_has_second_ip="y"
 | |
|             resolver_supports_ipv6="y"
 | |
|             echo "Setting resolver Control D."
 | |
|             echo "What content would you like to filter:"
 | |
|             echo "    0) No filtering"
 | |
|             echo "    1) Malware: Malware filtering"
 | |
|             echo "    2) Standard: Malware + ad and tracker filtering"
 | |
|             echo "    3) Social: Standard + social media filtering"
 | |
|             echo "    4) Family: Social + adult content filtering (also enables safe search in major search engines)"
 | |
|             while [[ "$valid_input" == "0" ]]; do
 | |
|                 read -p "Selection [0-4]: " resolver_subselection
 | |
|                 if [[ "$resolver_subselection" == [01234]* ]]; then
 | |
|                     valid_input="1"
 | |
|                 else
 | |
|                     echo "That is not a valid selection."
 | |
|                 fi
 | |
|             done
 | |
|             valid_input="0"
 | |
|             case "$resolver_subselection" in
 | |
|                 0)
 | |
|                     resolver_ipv4_address="76.76.2.0"
 | |
|                     resolver_ipv4_address_2="76.76.10.0"
 | |
|                     resolver_ipv6_address="2606:1a40::"
 | |
|                     resolver_ipv6_address_2="2606:1a40:1::"
 | |
|                     resolver_hostname="p0.freedns.controld.com"
 | |
|                     resolver_https_address="https://freedns.controld.com/p0"
 | |
|                     ;;
 | |
|                 1)
 | |
|                     resolver_ipv4_address="76.76.2.1"
 | |
|                     resolver_ipv4_address_2="76.76.10.1"
 | |
|                     resolver_ipv6_address="2606:1a40::1"
 | |
|                     resolver_ipv6_address_2="2606:1a40:1::1"
 | |
|                     resolver_hostname="p1.freedns.controld.com"
 | |
|                     resolver_https_address="https://freedns.controld.com/p1"
 | |
|                     ;;
 | |
|                 2)
 | |
|                     resolver_ipv4_address="76.76.2.2"
 | |
|                     resolver_ipv4_address_2="76.76.10.2"
 | |
|                     resolver_ipv6_address="2606:1a40::2"
 | |
|                     resolver_ipv6_address_2="2606:1a40:1::2"
 | |
|                     resolver_hostname="p2.freedns.controld.com"
 | |
|                     resolver_https_address="https://freedns.controld.com/p2"
 | |
|                     ;;
 | |
|                 3)
 | |
|                     resolver_ipv4_address="76.76.2.3"
 | |
|                     resolver_ipv4_address_2="76.76.10.3"
 | |
|                     resolver_ipv6_address="2606:1a40::3"
 | |
|                     resolver_ipv6_address_2="2606:1a40:1::3"
 | |
|                     resolver_hostname="p3.freedns.controld.com"
 | |
|                     resolver_https_address="https://freedns.controld.com/p3"
 | |
|                     ;;
 | |
|                 4)
 | |
|                     resolver_ipv4_address="76.76.2.4"
 | |
|                     resolver_ipv4_address_2="76.76.10.4"
 | |
|                     resolver_ipv6_address="2606:1a40::4"
 | |
|                     resolver_ipv6_address_2="2606:1a40:1::4"
 | |
|                     resolver_hostname="family.freedns.controld.com"
 | |
|                     resolver_https_address="https://freedns.controld.com/family"
 | |
|                     ;;
 | |
|             esac
 | |
|             ;;
 | |
|         2)
 | |
|             resolver_has_second_ip="n"
 | |
|             resolver_supports_ipv6="y"
 | |
|             echo "Setting resolver Mullvad."
 | |
|             echo "What content would you like to filter:"
 | |
|             echo "    0) No filtering"
 | |
|             echo "    1) Standard: Ad and tracker filtering"
 | |
|             echo "    2) Base: Standard + malware filtering"
 | |
|             echo "    3) Extended: Base + social media filtering"
 | |
|             echo "    4) Family: Base + gambling and adult content filtering"
 | |
|             echo "    5) All: Family + social media filtering"
 | |
|             while [[ "$valid_input" == "0" ]]; do
 | |
|                 read -p "Selection [0-5]: " resolver_subselection
 | |
|                 if [[ "$resolver_subselection" == [012345]* ]]; then
 | |
|                     valid_input="1"
 | |
|                 else
 | |
|                     echo "That is not a valid selection."
 | |
|                 fi
 | |
|             done
 | |
|             valid_input="0"
 | |
|             case "$resolver_subselection" in
 | |
|                 0)
 | |
|                     resolver_ipv4_address="194.242.2.2"
 | |
|                     resolver_ipv6_address="2a07:e340::2"
 | |
|                     resolver_hostname="dns.mullvad.net"
 | |
|                     ;;
 | |
|                 1)
 | |
|                     resolver_ipv4_address="194.242.2.3"
 | |
|                     resolver_ipv6_address="2a07:e340::3"
 | |
|                     resolver_hostname="adblock.dns.mullvad.net"
 | |
|                     ;;
 | |
|                 2)
 | |
|                     resolver_ipv4_address="194.242.2.4"
 | |
|                     resolver_ipv6_address="2a07:e340::4"
 | |
|                     resolver_hostname="base.dns.mullvad.net"
 | |
|                     ;;
 | |
|                 3)
 | |
|                     resolver_ipv4_address="194.242.2.5"
 | |
|                     resolver_ipv6_address="2a07:e340::5"
 | |
|                     resolver_hostname="extended.dns.mullvad.net"
 | |
|                     ;;
 | |
|                 4)
 | |
|                     resolver_ipv4_address="194.242.2.6"
 | |
|                     resolver_ipv6_address="2a07:e340::6"
 | |
|                     resolver_hostname="family.dns.mullvad.net"
 | |
|                     ;;
 | |
|                 5)
 | |
|                     resolver_ipv4_address="194.242.2.9"
 | |
|                     resolver_ipv6_address="2a07:e340::9"
 | |
|                     resolver_hostname="all.dns.mullvad.net"
 | |
|                     ;;
 | |
|             esac
 | |
|             resolver_https_address="https://$resolver_hostname/dns-query"
 | |
|             ;;
 | |
|         3)
 | |
|             resolver_has_second_ip="y"
 | |
|             resolver_supports_ipv6="y"
 | |
|             echo "Setting resolver Cloudflare. (glory to the cloud)"
 | |
|             echo "What content would you like to filter:"
 | |
|             echo "    0) No filtering"
 | |
|             echo "    1) Security: Malware filtering"
 | |
|             echo "    2) Family: Security + adult content filtering"
 | |
|             while [[ "$valid_input" == "0" ]]; do
 | |
|                 read -p "Selection [0-2]: " resolver_subselection
 | |
|                 if [[ "$resolver_subselection" == [012]* ]]; then
 | |
|                     valid_input="1"
 | |
|                 else
 | |
|                     echo "That is not a valid selection."
 | |
|                 fi
 | |
|             done
 | |
|             valid_input="0"
 | |
|             case "$resolver_subselection" in
 | |
|                 0)
 | |
|                     resolver_ipv4_address="1.1.1.1"
 | |
|                     resolver_ipv4_address_2="1.0.0.1"
 | |
|                     resolver_ipv6_address="2606:4700:4700::1111"
 | |
|                     resolver_ipv6_address_2="2606:4700:4700::1001"
 | |
|                     resolver_hostname="cloudflare-dns.com"
 | |
|                     ;;
 | |
|                 1)
 | |
|                     resolver_ipv4_address="1.1.1.2"
 | |
|                     resolver_ipv4_address_2="1.0.0.2"
 | |
|                     resolver_ipv6_address="2606:4700:4700::1112"
 | |
|                     resolver_ipv6_address_2="2606:4700:4700::1002"
 | |
|                     resolver_hostname="security.cloudflare-dns.com"
 | |
|                     ;;
 | |
|                 2)
 | |
|                     resolver_ipv4_address="1.1.1.3"
 | |
|                     resolver_ipv4_address_2="1.0.0.3"
 | |
|                     resolver_ipv6_address="2606:4700:4700::1113"
 | |
|                     resolver_ipv6_address_2="2606:4700:4700::1003"
 | |
|                     resolver_hostname="family.cloudflare-dns.com"
 | |
|                     ;;
 | |
|             esac
 | |
|             resolver_https_address="https://$resolver_hostname/dns-query"
 | |
|             ;;
 | |
|         4)
 | |
|             resolver_has_second_ip="y"
 | |
|             resolver_supports_ipv6="y"
 | |
|             echo "Setting resolver DNSForge."
 | |
|             echo "What content would you like to filter:"
 | |
|             echo "    0) Standard: Ad, tracker, and malware filtering"
 | |
|             echo "    1) Clean: Standard + adult content filtering"
 | |
|             echo "    2) Hard: Clean + stricter ad, tracker, and malware filtering"
 | |
|             while [[ "$valid_input" == "0" ]]; do
 | |
|                 read -p "Selection [0-2]: " resolver_subselection
 | |
|                 if [[ "$resolver_subselection" == [012]* ]]; then
 | |
|                     valid_input="1"
 | |
|                 else
 | |
|                     echo "That is not a valid selection."
 | |
|                 fi
 | |
|             done
 | |
|             valid_input="0"
 | |
|             case "$resolver_subselection" in
 | |
|                 0)
 | |
|                     resolver_ipv4_address="176.9.93.198"
 | |
|                     resolver_ipv4_address_2="176.9.1.117"
 | |
|                     resolver_ipv6_address="2a01:4f8:151:34aa::198"
 | |
|                     resolver_ipv6_address_2="2a01:4f8:141:316d::117"
 | |
|                     resolver_hostname="dnsforge.de"
 | |
|                     ;;
 | |
|                 1)
 | |
|                     resolver_ipv4_address="49.12.223.2"
 | |
|                     resolver_ipv4_address_2="49.12.43.208"
 | |
|                     resolver_ipv6_address="2a01:4f8:c17:4fbc::2"
 | |
|                     resolver_ipv6_address_2="2a01:4f8:c012:ed89::208"
 | |
|                     resolver_hostname="clean.dnsforge.de"
 | |
|                     ;;
 | |
|                 2)
 | |
|                     resolver_ipv4_address="49.12.222.213"
 | |
|                     resolver_ipv4_address_2="88.198.122.154"
 | |
|                     resolver_ipv6_address="2a01:4f8:c17:2c61::213"
 | |
|                     resolver_ipv6_address_2="2a01:4f8:c013:5ec0::154"
 | |
|                     resolver_hostname="hard.dnsforge.de"
 | |
|                     ;;
 | |
|             esac
 | |
|             resolver_https_address="https://$resolver_hostname/dns-query"
 | |
|             ;;
 | |
|         5)
 | |
|             echo "Setting custom resolver."
 | |
|             echo "NOTE: If the resolver does not support DoT/DoQ or DNSSEC, this process will not work."
 | |
|             echo ""
 | |
|             echo "Please provide the technical information."
 | |
|             read -p "Please enter the resolver's IP address (e.g. '1.1.1.2'): " resolver_ipv4_address
 | |
|             read -p "Does the resolver provide two distinct IP addresses (e.g. '1.1.1.2' and '1.0.0.2')? [Y/n] " resolver_has_second_ip
 | |
|             if [[ "$resolver_has_second_ip" == [Yy]* ]]; then
 | |
|                 read -p "Please enter the resolver's second IP address: " resolver_ipv4_address_2
 | |
|             fi
 | |
|             read -p "Does the resolver support IPv6 (e.g. '2606:4700:4700::1112')? [Y/n] " resolver_supports_ipv6
 | |
|             if [[ "$resolver_supports_ipv6" == [Yy]* ]]; then
 | |
|                 read -p "Please enter the resolver's IPv6 address: " resolver_ipv6_address
 | |
|                 if [[ "$resolver_has_second_ip" == [Yy]* ]]; then
 | |
|                     read -p "Please enter the resolver's second IPv6 address: " resolver_ipv6_address_2
 | |
|                 fi
 | |
|             fi
 | |
|             read -p "Please enter the second resolver's hostname (e.g. 'security.cloudflare-dns.com'): " resolver_hostname
 | |
|             ;;
 | |
|     esac
 | |
| 
 | |
|     read -p "Would you like the resolver to be set in the default browser (hardened-chromium) via management policy? [Y/n] " set_browser_policy
 | |
|     if [[ "$set_browser_policy" == [Yy]* && "$resolver_selection" == 5 ]]; then
 | |
|         read -p "Please enter the second resolver's HTTPS address (e.g. 'https://security.cloudflare-dns.com/dns-query'): " resolver_https_address
 | |
|     fi
 | |
| 
 | |
|     resolved_conf_dns_string="DNS="
 | |
|     resolved_conf_dns_string+=" $resolver_ipv4_address"
 | |
|     resolved_conf_dns_string+="#$resolver_hostname"
 | |
|     if [[ "$resolver_has_second_ip" == [Yy]* ]]; then
 | |
|         resolved_conf_dns_string+=" $resolver_ipv4_address_2"
 | |
|         resolved_conf_dns_string+="#$resolver_hostname"
 | |
|     fi
 | |
|     if [[ "$resolver_supports_ipv6" == [Yy]* ]]; then
 | |
|         resolved_conf_dns_string+=" $resolver_ipv6_address"
 | |
|         resolved_conf_dns_string+="#$resolver_hostname"
 | |
|         if [[ "$resolver_has_second_ip" == [Yy]* ]]; then
 | |
|             resolved_conf_dns_string+=" $resolver_ipv6_address_2"
 | |
|             resolved_conf_dns_string+="#$resolver_hostname"
 | |
|         fi
 | |
|     fi
 | |
| 
 | |
|     cat << EOF > "$resolved_conf"
 | |
|     [Resolve]
 | |
|     DNSSEC=true
 | |
|     DNSOverTLS=true
 | |
|     $resolved_conf_dns_string
 | |
|     EOF
 | |
| 
 | |
|     systemctl restart systemd-resolved
 | |
| 
 | |
|     echo "Config file for resolved configured with selected resolver and service restarted."
 | |
| 
 | |
|     if [[ "$set_browser_policy" != [Yy]* ]]; then
 | |
|         exit 0
 | |
|     fi
 | |
|     cat << EOF > "$policy_file"
 | |
|     {
 | |
|         "DnsOverHttpsMode": "secure",
 | |
|         "DnsOverHttpsTemplates": "$resolver_https_address"
 | |
|     }
 | |
|     EOF
 | |
| 
 | |
|     echo "Browser policy set with selected resolver."
 | 
