From e43d0242cbd429a7dba7fcb994e9e114ea41c7d0 Mon Sep 17 00:00:00 2001 From: teldra Date: Mon, 22 Jun 2020 18:18:07 +0200 Subject: [PATCH] firewall.sh: many improvements --- firewall.sh | 368 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 239 insertions(+), 129 deletions(-) diff --git a/firewall.sh b/firewall.sh index 5841e58..e72ec7c 100755 --- a/firewall.sh +++ b/firewall.sh @@ -1,33 +1,53 @@ #!/bin/bash #config -alldevs=(enp0s25 wlp2s0 vpn0 vpn-gateway) +if [ "$EUID" -ne 0 ] + then echo "Please run as root" + exit +fi +CFG="/etc/firewall.cfg" -hometcp=(ssh vncd misc) -homeudp=(avahi-daemon) -outtcp=(ssh) -outudp=() +if [[ ! -f "${CFG}" ]]; then + for i in $(ip -oneline addr show scope global|awk '{print $2}'|uniq); do + devs+=($i) + done + echo "alldevs=(${devs[*]})" > "${CFG}" + echo "ignore=()" >> "${CFG}" + echo "hometcp=(ssh)" >> "${CFG}" + echo "homeudp=()" >> "${CFG}" + echo "outtcp=(ssh)" >> "${CFG}" + echo "outudp=()" >> "${CFG}" + echo "vpntcp=(ssh)" >> "${CFG}" + echo "vpnudp=()" >> "${CFG}" + echo "VPN_UNRESTRICTED=1" >> "${CFG}" + echo "" >> "${CFG}" + echo "nft="/usr/sbin/nft"" >> "${CFG}" + echo "" >> "${CFG}" + echo "declare -A ports=(" >> "${CFG}" + echo " [ssh]=22" >> "${CFG}" + echo " [smtp]=25" >> "${CFG}" + echo " [dns]=53" >> "${CFG}" + echo " [netbios-ssn]=139" >> "${CFG}" + echo " [dovecot]=143" >> "${CFG}" + echo " [microsoft-ds]=445" >> "${CFG}" + echo " [cups-ipp]=631" >> "${CFG}" + echo " [imaps]=993" >> "${CFG}" + echo " [kdeconnect]=1714-1764" >> "${CFG}" + echo " [avahi-daemon]=5353" >> "${CFG}" + echo " [vncd]=5900" >> "${CFG}" + echo " [mpd]=6600" >> "${CFG}" + echo " [mpd-audio]=8000" >> "${CFG}" + echo " [misc]=8080" >> "${CFG}" + echo " [syncthing]=8384" >> "${CFG}" + echo " [wireguard]=51820" >> "${CFG}" + echo " [mosh]=60000-61000" >> "${CFG}" + echo ")" >> "${CFG}" + echo "${CFG} missed. Example created. Exit" + exit +else + source "${CFG}" +fi -declare -A ports=( - [ssh]=22 - [smtp]=25 - [dns]=53 - [netbios-ssn]=139 - [dovecot]=143 - [microsoft-ds]=445 - [cups-ipp]=631 - [imaps]=993 - [kdeconnect]=1714-1764 - [avahi-daemon]=5353 - [vncd]=5900 - [mpd]=6600 - [mpd-audio]=8000 - [misc]=8080 - [syncthing]=8384 - [wireguard]=51820 - [mosh]=60000-61000 -) -nft="/usr/sbin/nft" ##script @@ -57,6 +77,7 @@ do done help +[[ $LIST == "1" ]] && sudo nft -a list ruleset && exit flush check_deviceinput get_devices @@ -65,7 +86,6 @@ init add_device remove_device set_rules -[[ $LIST == "1" ]] && echo " " && sudo nft list ruleset -a exit 0 @@ -101,9 +121,9 @@ location() { LOCATION=home elif [[ "${HOME}" == "out" ]]; then LOCATION=out - else - LOCATION=out fi + else + LOCATION=out fi fi case $LOCATION in @@ -117,6 +137,12 @@ location() { debug location: "${LOCATION[@]}" debug tcp ports: "${portstcp[@]}" debug udp ports: "${portsudp[@]}" + if [[ ! "$VPN_UNRESTRICTED" == "1" ]]; then + debug vpntcp ports: "${vpntcp[@]}" + debug vpnudp ports: "${vpnudp[@]}" + elif [[ "$VPN_UNRESTRICTED" == "1" ]]; then + debug "vpn ports unrestricted" + fi } check_deviceinput() { @@ -174,10 +200,20 @@ get_devices() { if [[ -n $AUTOMATIC ]]; then if [[ $NM == "1" ]]; then for i in $(LANG=en_US.UTF-8 nmcli device status|grep " connected"|awk '{print $1}'); do + for item2 in "${ignore[@]}"; do + if [[ $i == "$item2" ]]; then + continue 2 + fi + done DEVON+=("$i") done else for i in $(ip -oneline addr show scope global|awk '{print $2}'|uniq); do + for item2 in "${ignore[@]}"; do + if [[ $i == "$item2" ]]; then + continue 2 + fi + done DEVON+=("$i") done fi @@ -200,14 +236,16 @@ get_devices() { DEVOFF+=("$i") done fi - + for i in "${ignore[@]}"; do + DEVOFF+=("$i") + done debug alldevices: "${alldevs[*]}" debug devices on: "${DEVON[*]}" debug devices off: "${DEVOFF[*]}" } function init() { - if ! $nft list ruleset -a |grep -q "table inet filter"; then + if ! $nft -a list ruleset | grep -q "table inet filter"; then debug "Initialise rule: nft add table inet filter" $nft add table inet filter $nft add chain inet filter INPUT \{ type filter hook input priority 0 \; policy drop \; \} @@ -225,25 +263,19 @@ function init() { add_device() { if [[ -n "${DEVON[*]}" ]]; then for _device in "${DEVON[@]}" "${VPNON[@]}"; do - if ! $nft list table inet filter -a|grep -q "INPUT_${_device}"; then + if ! $nft -a list table inet filter | grep -q "INPUT_${_device}"; then debug "Add device: ${_device}" $nft add chain inet filter INPUT_"${_device}" fi - if ! $nft list ruleset -a |grep -q "jump INPUT_${_device}"; then + if ! $nft -a list ruleset | grep -q "jump INPUT_${_device}"; then $nft add rule inet filter INPUT iif "${_device}" jump INPUT_"${_device}" fi - if ! $nft list ruleset -a |grep -i "${_device}"| grep -q "${_device}: accept icmpv4 types"; then + if ! $nft -a list ruleset | grep -i "${_device}" | grep -q "${_device}: accept icmpv4 types"; then $nft add rule inet filter INPUT_"${_device}" ip protocol icmp accept comment \""${_device}": accept icmpv4 types\" fi - if ! $nft list ruleset -a |grep -i "${_device}"| grep -q "${_device}: accept icmpv6 types"; then + if ! $nft -a list ruleset | grep -i "${_device}" | grep -q "${_device}: accept icmpv6 types"; then $nft add rule inet filter INPUT_"${_device}" ip6 nexthdr icmpv6 accept comment \""${_device}": accept icmpv6 types\" fi - if [[ $_device == *"vpn"* ]]; then - if ! $nft list ruleset -a |grep -q "$_device: accept all"; then - debug "$_device: add rule \"$_device: accept all\"" - $nft add rule inet filter INPUT_"${_device}" accept comment \""$_device": accept all\" - fi - fi done fi } @@ -251,10 +283,10 @@ add_device() { remove_device() { if [[ -n "${DEVOFF[*]}" ]]; then for _device in "${DEVOFF[@]}"; do - if $nft list table inet filter -a|grep -q "INPUT_${_device}"; then + if $nft -a list table inet filter | grep -q "INPUT_${_device}"; then debug "Delete device: ${_device}" $nft flush chain inet filter INPUT_"${_device}" - HANDLE=$($nft list table inet filter -a|grep "jump INPUT_${_device}"|awk '{print $NF}') + HANDLE=$($nft -a list table inet filter | grep "jump INPUT_${_device}" | awk '{print $NF}') $nft delete rule inet filter INPUT handle "${HANDLE}" $nft delete chain inet filter INPUT_"${_device}" fi @@ -273,7 +305,7 @@ getports() { unchangedtcp=() unchangedudp=() for _prot in tcp udp; do - for _port in $($nft list ruleset -a|grep -e dport| grep "${dev}"|grep "${_prot}"|awk '{print $12}'| tr ' ' '\n'); do + for _port in $($nft -a list ruleset | grep -e dport | grep "${dev}" | grep "${_prot}" | awk '{print $12}' | tr ' ' '\n'); do if [[ $_prot == "tcp" ]]; then istportstcp+=("$_port") elif [[ $_prot == "udp" ]]; then @@ -282,84 +314,168 @@ getports() { done done - #TCP - for item1 in "${portstcp[@]}"; do - for item2 in "${istportstcp[@]}"; do - if [[ $item1 == "$item2" ]]; then - unchangedtcp+=("$item1") - break - fi - done - done - turnofftcp=() - for item1 in "${istportstcp[@]}"; do - for item2 in "${portstcp[@]}"; do - [[ $item1 == "$item2" ]] && continue 2 - done - turnofftcp+=("$item1") - done - if [[ ! $2 == "off" ]]; then - turnontcp=() - for item1 in "${portstcp[@]}"; do - for item2 in "${istportstcp[@]}"; do - [[ $item1 == "$item2" ]] && continue 2 - done - turnontcp+=("$item1") - done - fi + if [[ ! ${dev} == *"vpn"* ]]; then + #TCP + unchangedtcp=() + for item1 in "${portstcp[@]}"; do + for item2 in "${istportstcp[@]}"; do + if [[ $item1 == "$item2" ]]; then + unchangedtcp+=("$item1") + break + fi + done + done + turnofftcp=() + for item1 in "${istportstcp[@]}"; do + for item2 in "${portstcp[@]}"; do + [[ $item1 == "$item2" ]] && continue 2 + done + turnofftcp+=("$item1") + done + if [[ ! $2 == "off" ]]; then + turnontcp=() + for item1 in "${portstcp[@]}"; do + for item2 in "${istportstcp[@]}"; do + [[ $item1 == "$item2" ]] && continue 2 + done + turnontcp+=("$item1") + done + fi - #UDP - for item1 in "${portsudp[@]}"; do - for item2 in "${istportsudp[@]}"; do - if [[ $item1 == "$item2" ]]; then - unchangedudp+=("$item1") - break - fi - done - done + #UDP + unchangedudp=() + for item1 in "${portsudp[@]}"; do + for item2 in "${istportsudp[@]}"; do + if [[ $item1 == "$item2" ]]; then + unchangedudp+=("$item1") + break + fi + done + done - turnoffudp=() - for item1 in "${istportsudp[@]}"; do - for item2 in "${portsudp[@]}"; do - [[ $item1 == "$item2" ]] && continue 2 - done + turnoffudp=() + for item1 in "${istportsudp[@]}"; do + for item2 in "${portsudp[@]}"; do + [[ $item1 == "$item2" ]] && continue 2 + done - # If we reached here, nothing matched. - turnoffudp+=("$item1") - done - if [[ ! $2 == "off" ]]; then - turnonudp=() - for item1 in "${portsudp[@]}"; do - for item2 in "${istportsudp[@]}"; do - [[ $item1 == "$item2" ]] && continue 2 - done + # If we reached here, nothing matched. + turnoffudp+=("$item1") + done + if [[ ! $2 == "off" ]]; then + turnonudp=() + for item1 in "${portsudp[@]}"; do + for item2 in "${istportsudp[@]}"; do + [[ $item1 == "$item2" ]] && continue 2 + done - # If we reached here, nothing matched. - turnonudp+=("$item1") - done - fi + # If we reached here, nothing matched. + turnonudp+=("$item1") + done + fi + + + elif [[ ${dev} == *"vpn"* ]]; then + #TCP VPN + unchangedtcp=() + for item1 in "${vpntcp[@]}"; do + for item2 in "${istportstcp[@]}"; do + if [[ $item1 == "$item2" ]]; then + unchangedtcp+=("$item1") + break + fi + done + done + turnofftcp=() + for item1 in "${istportstcp[@]}"; do + for item2 in "${vpntcp[@]}"; do + [[ $item1 == "$item2" ]] && continue 2 + done + turnofftcp+=("$item1") + done + if [[ ! $2 == "off" ]]; then + vpnturnontcp=() + for item1 in "${vpntcp[@]}"; do + for item2 in "${istportstcp[@]}"; do + [[ $item1 == "$item2" ]] && continue 2 + done + turnontcp+=("$item1") + done + fi + + + #UDP + unchangedudp=() + for item1 in "${vpnudp[@]}"; do + for item2 in "${istportsudp[@]}"; do + if [[ $item1 == "$item2" ]]; then + unchangedudp+=("$item1") + break + fi + done + done + + turnoffudp=() + for item1 in "${istportsudp[@]}"; do + for item2 in "${vpnudp[@]}"; do + [[ $item1 == "$item2" ]] && continue 2 + done + + # If we reached here, nothing matched. + turnoffudp+=("$item1") + done + if [[ ! $2 == "off" ]]; then + turnonudp=() + for item1 in "${vpnudp[@]}"; do + for item2 in "${istportsudp[@]}"; do + [[ $item1 == "$item2" ]] && continue 2 + done + + # If we reached here, nothing matched. + turnonudp+=("$item1") + done + if [[ ! "$VPN_UNRESTRICTED" == "1" ]]; then + if $nft -a list ruleset | grep -q "${dev}: accept all"; then + debug "${dev}: remove rule \"${dev}: accept all\"" + HANDLER=$($nft -a list table inet filter | grep "${dev}: accept all" | awk '{print $NF}') + $nft delete rule inet filter INPUT_"${dev}" handle "${HANDLER}" + fi + MAKEVPNRULES=y + elif [[ "$VPN_UNRESTRICTED" == "1" ]]; then + if ! $nft -a list ruleset | grep -q "${dev}: accept all"; then + debug "${dev}: add rule \"${dev}: accept all\"" + $nft add rule inet filter INPUT_"${dev}" accept comment \""${dev}": accept all\" + fi + MAKEVPNRULES=n + turnofftcp=("${turnontcp[@]}" "${unchangedtcp[@]}") + turnoffudp=("${turnonudp[@]}" "${unchangedudp[@]}") + fi + fi + fi } function addrule() { + [[ $MAKEVPNRULES == "n" ]] && return portnumber=$1 portname=$2 protocol=$3 device=$4 - if ! $nft list table inet filter -a |grep -q "INPUT: allow ${portname} ${portnumber} ${protocol} ${device}"; then + if ! $nft -a list table inet filter | grep -q "INPUT: allow ${portname} ${portnumber} ${protocol} ${device}"; then debug "$device: add rule for ${portname} (${portnumber}, ${protocol})" #$nft add rule inet filter INPUT iif "${device}" "${protocol}" dport "${portnumber}" ct state new log accept comment \"INPUT: allow "${portname}" "${portnumber}" "${protocol}" "${device}"\" $nft add rule inet filter INPUT_"${_device}" "${protocol}" dport "${portnumber}" ct state new log accept comment \"INPUT: allow "${portname}" "${portnumber}" "${protocol}" "${device}"\" fi } + function removerule() { portnumber=$1 portname=$2 protocol=$3 device=$4 HANDLER="" - HANDLER=$($nft list table inet filter -a |grep "INPUT: allow ${portname} ${portnumber} ${protocol} ${device}" | awk '{print $NF}') + HANDLER=$($nft -a list table inet filter | grep "INPUT: allow ${portname} ${portnumber} ${protocol} ${device}" | awk '{print $NF}') if [[ $HANDLER ]]; then debug "$device: remove rule for ${portname} (${portnumber}, ${protocol})" #$nft delete rule inet filter INPUT handle "${HANDLER}" @@ -369,41 +485,35 @@ function removerule() { set_rules() { for _device in "${DEVOFF[@]}"; do - if [[ ! ${_device} == *"vpn"* ]]; then - getports "${_device}" off - for _pn in "${turnofftcp[@]}"; do - removerule "${ports[$_pn]}" "${_pn}" tcp "${_device}" - done - - for _pn in "${turnoffudp[@]}"; do - removerule "${ports[$_pn]}" "${_pn}" udp "${_device}" - done - for _pn in "${unchangedtcp[@]}"; do - removerule "${ports[$_pn]}" "${_pn}" tcp "${_device}" - done - - for _pn in "${unchangedudp[@]}"; do - removerule "${ports[$_pn]}" "${_pn}" udp "${_device}" - done - fi + getports "${_device}" off + for _pn in "${turnofftcp[@]}"; do + removerule "${ports[$_pn]}" "${_pn}" tcp "${_device}" + done + for _pn in "${turnoffudp[@]}"; do + removerule "${ports[$_pn]}" "${_pn}" udp "${_device}" + done + for _pn in "${unchangedtcp[@]}"; do + removerule "${ports[$_pn]}" "${_pn}" tcp "${_device}" + done + for _pn in "${unchangedudp[@]}"; do + removerule "${ports[$_pn]}" "${_pn}" udp "${_device}" + done done for _device in "${DEVON[@]}"; do - if [[ ! "${_device}" == *"vpn"* ]]; then - getports "${_device}" - for _pn in "${turnofftcp[@]}"; do - removerule "${ports[$_pn]}" "${_pn}" tcp "${_device}" - done - for _pn in "${turnoffudp[@]}"; do - removerule "${ports[$_pn]}" "${_pn}" udp "${_device}" - done - for _pn in "${turnontcp[@]}"; do - addrule "${ports[$_pn]}" "${_pn}" tcp "${_device}" - done - for _pn in "${turnonudp[@]}"; do - addrule "${ports[$_pn]}" "${_pn}" udp "${_device}" - done - fi + getports "${_device}" + for _pn in "${turnofftcp[@]}"; do + removerule "${ports[$_pn]}" "${_pn}" tcp "${_device}" + done + for _pn in "${turnoffudp[@]}"; do + removerule "${ports[$_pn]}" "${_pn}" udp "${_device}" + done + for _pn in "${turnontcp[@]}"; do + addrule "${ports[$_pn]}" "${_pn}" tcp "${_device}" + done + for _pn in "${turnonudp[@]}"; do + addrule "${ports[$_pn]}" "${_pn}" udp "${_device}" + done done }