Files
webgui/etc/rc.d/rc.library.source
T
2023-07-10 04:15:50 +02:00

235 lines
6.4 KiB
Plaintext

# Library file: /etc/rc.d/rc.library.source
# Used by nfsd, ntpd, rpc, samba, nginx, sshd, avahidaemon, show_interfaces
#
# bergware - updated for Unraid, June 2023
WIREGUARD="/etc/wireguard"
NETWORK_INI="/var/local/emhttp/network.ini"
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:4} == fe80 ]] && data=$1
done
if [[ -n $2 ]]; then
for i in ${nets[@]}; do
[[ $i == $2 || ${2:0:4} == fe80 ]] && data=$2
done
fi
echo $data
}
max6() {
# ipv6 addresses in long notation
for x in $*; do
read a m < <(IFS=/; echo $x)
c=${a//[^:]/}
[[ ${a:0:1} == : ]] && s=9 || s=8
[[ ${a:${#a}-1} == : ]] && s=9
a=${a/::/:$(for((i=1;i<=$((s-${#c}));i++)); do printf "0:"; done)}
a=$(for q in ${a//:/ }; do printf "$d%04x" "0x$q"; d=:; done)
[[ -z $m ]] && echo $a || echo $a/$m
done
}
min6() {
# ipv6 address in short notation
[[ -n $1 ]] && read a m < <(IFS=/; echo $1) || return
a=$(for q in ${a//:/ }; do printf "$d%x" "0x$q"; d=:; done)
a=${a/$(grep -Po '(^|:)(0(:|$)){1,8}' <<< $a|sort|tail -1)/::}
[[ -z $m ]] && echo $a || echo $a/$m
}
wipe() {
wet=($*)
# remove temporary (privacy extensions) ipv6 addresses
for tmp in $(ip -br -6 addr show scope global temporary dev $wet 2>/dev/null|awk '{$1=$2="";print}'); do
for i in ${!wet[@]}; do
[[ ${wet[$i]} == $tmp ]] && 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) [[ $1 == -6 ]] && main $(ip -br -6 addr show scope global $2 $3 2>/dev/null|awk '{$2="";print;exit}') || ip -br -4 addr show scope global $2 $3 2>/dev/null|awk '{print $3;exit}';;
esac
}
sub() {
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() {
[[ $# -eq 0 ]] && 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)
net1=$(sub ${net[1]})
if [[ "avahi show" =~ $CALLER ]]; then
[[ -n $net && -n $net1 && -z $(good $net $net1) ]] && bind+=($net)
[[ -n $net1 ]] && ipv4=yes nets+=($net1)
else
# exclude wireguard tunnels for ntp
[[ $CALLER == ntp ]] && name=$(show $net1) || name=
[[ ${name:0:2} != wg && -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}')
# active ipv6 interfaces (including wireguard)
nets=()
while IFS='\n' read -r net; do
net=($net)
net1=$(sub $(main ${net[@]}))
if [[ "avahi show" =~ $CALLER ]]; then
[[ -n $net && -n $net1 && -z $(good $net $net1) ]] && bind+=($net)
[[ -n $net1 ]] && ipv6=yes nets+=($net1)
else
# exclude wireguard tunnels for ntp
[[ $CALLER == ntp ]] && name=$(show $net1) || name=
[[ -z $deny6 && ${name:0:2} != wg && -n $net1 && -z $(good $net1) ]] && ipv6=yes bind+=($net1)
fi
done <<< $(ip -br -6 addr show scope global|awk '/^(br|bond|eth|wg)[0-9]+(\.[0-9]+)?/{$2="";print}')
# 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 $EXTRA ]]; then
. <(/usr/bin/fromdos <$EXTRA)
if [[ "avahi show" =~ $CALLER ]]; then
extra_name
else
extra_addr
fi
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
}