mirror of
https://github.com/unraid/webgui.git
synced 2026-01-16 22:50:19 -06:00
246 lines
7.5 KiB
Bash
246 lines
7.5 KiB
Bash
#!/bin/bash
|
|
#
|
|
# script: rc.library.source
|
|
#
|
|
# Library used by nfsd, ntpd, rpc, samba, nginx, sshd, avahidaemon, show_interfaces
|
|
#
|
|
# Bergware - created for Unraid OS, October 2023
|
|
|
|
WIREGUARD="/etc/wireguard"
|
|
NETWORK_INI="/var/local/emhttp/network.ini"
|
|
NETWORK_EXTRA="/boot/config/network-extra.cfg"
|
|
|
|
ipv(){
|
|
T=${1//[^:]}
|
|
[[ ${#T} -le 1 ]] && echo 4 || echo 6
|
|
}
|
|
|
|
this(){
|
|
case $CALLER in
|
|
'avahi')
|
|
grep -Pom1 "^$1=\K.*" $CONF
|
|
;;
|
|
'smb')
|
|
grep -Pom1 "^$1 = \K.*" $CONF
|
|
;;
|
|
'ntp'|'ssh')
|
|
grep -Po "^$1 \K\S+" $CONF | tr '\n' ' ' | sed 's/ $//'
|
|
;;
|
|
'nfs')
|
|
grep -Pom1 "^RPC_NFSD_OPTS=\"$OPTIONS \K[^\"]+" $NFS
|
|
;;
|
|
'rpc')
|
|
grep -Pom1 "^RPCBIND_OPTS=\"\K[^\"]+" $RPC
|
|
;;
|
|
'nginx')
|
|
NOW=();
|
|
for ADDR in $(awk '$1=="listen" && $2~/^[0-9]|\[/ && $0~/http2; #.*$/{print $2}' $SERVERS 2>/dev/null); do
|
|
# extract ipv4 / ipv6 address
|
|
[[ $(ipv $ADDR) == 4 ]] && ADDR=${ADDR%:*} || ADDR=${ADDR#*[} ADDR=${ADDR%]*}
|
|
NOW+=($ADDR)
|
|
done
|
|
# return addresses
|
|
echo ${NOW[@]}
|
|
;;
|
|
esac
|
|
}
|
|
|
|
scan(){
|
|
grep -Pom1 "^$1=\"?\K[^\"]+" $2
|
|
}
|
|
|
|
good(){
|
|
DATA=
|
|
for i in ${BIND[@]}; do
|
|
[[ $i == $1 || $1 == 0 || ${1:0:4} == fe80 ]] && DATA=1
|
|
done
|
|
if [[ -n $2 ]]; then
|
|
for i in ${NETS[@]}; do
|
|
[[ $i == $2 || $2 == 0 || ${2:0:4} == fe80 ]] && DATA=2
|
|
done
|
|
fi
|
|
echo $DATA
|
|
}
|
|
|
|
max6(){
|
|
# ipv6 addresses in long notation
|
|
FILL=:ffff:
|
|
for INPUT in $*; do
|
|
read ADDR MASK < <(IFS=/; echo $INPUT)
|
|
[[ $ADDR =~ "$FILL" && $ADDR =~ "." ]] && BITS=${ADDR#*$FILL} ADDR=${ADDR%$FILL*}$FILL:0 || BITS=
|
|
SIZE=${ADDR//[^:]/}
|
|
[[ ${ADDR:0:1} == : ]] && ADDR=0${ADDR}
|
|
[[ ${ADDR:${#ADDR}-1} == : ]] && ADDR=${ADDR}0
|
|
ADDR=${ADDR/::/:$(for((i=1;i<=$((8-${#SIZE}));i++)); do printf "0:"; done)}
|
|
MARK= ADDR=$(for QUAD in ${ADDR//:/ }; do printf "$MARK%04x" "0x$QUAD"; MARK=:; done)
|
|
[[ -n $BITS ]] && MARK= ADDR=${ADDR%$FILL*}${FILL}$(for QUAD in ${BITS//./ }; do printf "$MARK%03x" "0x$QUAD"; MARK=.; done)
|
|
[[ -z $MASK ]] && echo $ADDR || echo $ADDR/$MASK
|
|
done
|
|
}
|
|
|
|
min6(){
|
|
# ipv6 address in short notation
|
|
FILL=:ffff:
|
|
[[ -n $1 ]] && read ADDR MASK < <(IFS=/; echo $1) || return
|
|
[[ $ADDR =~ "$FILL" && $ADDR =~ "." ]] && BITS=${ADDR#*$FILL} ADDR=${ADDR%$FILL*}$FILL || BITS=
|
|
MARK= ADDR=:$(for QUAD in ${ADDR//:/ }; do printf "$MARK%x" "0x$QUAD"; MARK=:; done)
|
|
ADDR=${ADDR/$(grep -Po ':(0(:|$)){2,8}' <<< $ADDR | sort | tail -1)/::}
|
|
[[ ${ADDR:0:2} != :: ]] && ADDR=${ADDR:1}
|
|
[[ -n $BITS ]] && MARK= ADDR=${ADDR%$FILL*}:$(for QUAD in ${BITS//./ }; do printf "$MARK%x" "0x$QUAD"; MARK=.; done)
|
|
[[ -z $MASK ]] && echo $ADDR || echo $ADDR/$MASK
|
|
}
|
|
|
|
wipe(){
|
|
WET=($*)
|
|
# remove temporary (privacy extensions) and host ipv6 addresses
|
|
for TMP in $(ip -br -6 addr show scope global temporary dev $WET 2>/dev/null | sed -r 's/metric [0-9]+//g' | awk '{$1=$2="";print}'); do
|
|
for i in ${!WET[@]}; do
|
|
[[ ${WET[$i]} == $TMP || (${WET[$i]} =~ '::' && ${WET[$i]#*/} == 128) ]] && unset 'WET[i]'
|
|
done
|
|
done
|
|
# return cleaned-up list without interface name
|
|
echo ${WET[@]/$WET}
|
|
}
|
|
|
|
main(){
|
|
min6 $(max6 $(wipe $*) | sort | head -1)
|
|
}
|
|
|
|
show(){
|
|
case $# in
|
|
1) ip -br addr show scope global to $1 2>/dev/null | awk '{print $1;exit}';;
|
|
2) ip -br addr show scope global $1 $2 2>/dev/null | awk '{print $3;exit}';;
|
|
3) if [[ $1 == -6 ]]; then main $(ip -br -6 addr show scope global $2 $3 2>/dev/null | sed -r 's/metric [0-9]+//g' | awk '{$2="";print;exit}'); else ip -br -4 addr show scope global $2 $3 2>/dev/null | awk '{print $3;exit}'; fi;;
|
|
esac
|
|
}
|
|
|
|
sub(){
|
|
[[ -z $1 ]] && return
|
|
if [[ $CALLER == smb && -z $DENY6 ]]; then
|
|
# replace netmask
|
|
[[ $(ipv $1) == 4 ]] && echo ${1/\/32/\/24} || echo ${1/\/128/\/64}
|
|
else
|
|
# remove netmask
|
|
echo ${1/\/*}
|
|
fi
|
|
}
|
|
|
|
remove(){
|
|
[[ -z $1 ]] && return
|
|
for i in ${!BIND[@]}; do
|
|
[[ ${BIND[$i]} == $1 ]] && unset 'BIND[i]'
|
|
done
|
|
}
|
|
|
|
isname(){
|
|
[[ -z ${1//[^.:]} || ${1//[^.:]} == . ]] && return 0 || return 1
|
|
}
|
|
|
|
extra_name(){
|
|
for NET in $include_interfaces; do
|
|
if $(isname $NET); then
|
|
# NET is an interface name, validate
|
|
[[ $CALLER != ntp && -n $(show dev $NET) && -z $(good $NET) ]] && BIND+=($NET)
|
|
else
|
|
# NET is an IP address, convert to name
|
|
NET=$(show $NET)
|
|
[[ $CALLER != ntp && -n $NET && -z $(good $NET) ]] && BIND+=($NET)
|
|
fi
|
|
done
|
|
for NET in $exclude_interfaces; do
|
|
if $(isname $NET); then
|
|
# NET is an interface name, remove
|
|
remove $NET
|
|
else
|
|
# NET is an IP address, convert to name and remove
|
|
remove $(show $NET)
|
|
fi
|
|
done
|
|
}
|
|
|
|
extra_addr(){
|
|
for NET in $include_interfaces; do
|
|
if $(isname $NET); then
|
|
# NET is an interface name, get IP addresses
|
|
NET4=$(sub $(show -4 dev $NET))
|
|
NET6=$(sub $(show -6 dev $NET))
|
|
else
|
|
# NET is an IP address, validate
|
|
NET4=$(sub $(show -4 to $NET))
|
|
NET6=$(sub $(show -6 to $NET))
|
|
fi
|
|
[[ $CALLER != ntp && -n $NET4 && -z $(good $NET4) ]] && IPV4=yes BIND+=($NET4)
|
|
[[ $CALLER != ntp && -n $NET6 && -z $(good $NET6) ]] && IPV6=yes BIND+=($NET6)
|
|
done
|
|
for NET in $exclude_interfaces; do
|
|
if $(isname $NET); then
|
|
# NET is an interface name, get IP addresses
|
|
remove $(sub $(show -4 dev $NET))
|
|
remove $(sub $(show -6 dev $NET))
|
|
else
|
|
# NET is an IP address
|
|
remove $(sub $(show to $NET))
|
|
fi
|
|
done
|
|
}
|
|
|
|
check(){
|
|
# quick check
|
|
[[ -n $BIND ]] && return 0;
|
|
# preset return values
|
|
BIND=(); IPV4=no; IPV6=no; FAMILY=any;
|
|
# active IPV4 interfaces (including wireguard)
|
|
NETS=()
|
|
while IFS=$'\n' read -r NET; do
|
|
NET=($NET)
|
|
# exclude wireguard tunnels for ntp
|
|
[[ ${NET:0:2} == wg && $CALLER == ntp ]] && continue
|
|
# exclude wireguard VPN docker tunnels
|
|
[[ ${NET:0:2} == wg && $(grep -Pom1 '^TYPE:1="\K[^"]+' $WIREGUARD/$NET.cfg) == 8 ]] && continue
|
|
NET1=$(sub ${NET[1]})
|
|
if [[ "avahi show" =~ "$CALLER" ]]; then
|
|
[[ -n $NET && -n $NET1 && -z $(good $NET $NET1) ]] && BIND+=($NET)
|
|
[[ -n $NET1 && $NET1 != 0 ]] && IPV4=yes NETS+=($NET1)
|
|
else
|
|
[[ -n $NET1 && -z $(good $NET1) ]] && IPV4=yes BIND+=($NET1)
|
|
fi
|
|
done <<< $(ip -br -4 addr show scope global | awk '/^(br|bond|eth|wg)[0-9]+(\.[0-9]+)?/ {print $1,$3}' | sort)
|
|
# active IPV6 interfaces (including wireguard)
|
|
NETS=()
|
|
while IFS='\n' read -r NET; do
|
|
NET=($NET)
|
|
# exclude wireguard tunnels for ntp
|
|
[[ ${NET:0:2} == wg && $CALLER == ntp ]] && continue
|
|
# exclude wireguard VPN docker tunnels
|
|
[[ ${NET:0:2} == wg && $(grep -Pom1 '^TYPE:1="\K[^"]+' $WIREGUARD/$NET.cfg) == 8 ]] && continue
|
|
NET1=$(sub $(main ${NET[@]}))
|
|
if [[ "avahi show" =~ "$CALLER" ]]; then
|
|
[[ -n $NET && -n $NET1 && -z $(good $NET $NET1) ]] && BIND+=($NET)
|
|
[[ -n $NET1 && $NET1 != 0 ]] && IPV6=yes NETS+=($NET1)
|
|
else
|
|
[[ -z $DENY6 && -n $NET1 && -z $(good $NET1) ]] && IPV6=yes BIND+=($NET1)
|
|
fi
|
|
done <<< $(ip -br -6 addr show scope global | sed -r 's/metric [0-9]+//g' | awk '/^(br|bond|eth|wg)[0-9]+(\.[0-9]+)?/{$2="";print}' | sort)
|
|
# add loopback interface
|
|
if [[ "smb nfs" =~ "$CALLER" ]]; then
|
|
[[ $IPV4 == yes ]] && BIND+=(127.0.0.1)
|
|
[[ $IPV6 == yes ]] && BIND+=(::1)
|
|
fi
|
|
# add user defined interfaces
|
|
if [[ -f $NETWORK_EXTRA ]]; then
|
|
. <(fromdos <$NETWORK_EXTRA)
|
|
[[ "avahi show" =~ "$CALLER" ]] && extra_name || extra_addr
|
|
fi
|
|
if [[ $CALLER == ssh ]]; then
|
|
# BIND stays array
|
|
BIND=(${BIND[@]})
|
|
[[ $IPV4 == yes && $IPV6 == no ]] && FAMILY=inet
|
|
[[ $IPV6 == yes && $IPV4 == no ]] && FAMILY=inet6
|
|
else
|
|
# convert array to string
|
|
BIND=${BIND[@]}
|
|
[[ $CALLER == avahi ]] && BIND=${BIND// /,}
|
|
fi
|
|
return 0
|
|
}
|