mirror of
https://github.com/unraid/webgui.git
synced 2025-12-31 14:40:36 -06:00
308 lines
12 KiB
Bash
Executable File
308 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# script: create_network_ini
|
|
#
|
|
# Copyright 2005-2025, Lime Technology
|
|
# Copyright 2012-2025, Bergware International.
|
|
#
|
|
# create initial network.ini file on system start
|
|
# create system welcome message
|
|
# update files on DHCP events 'BOUND[6] IPV4LL EXPIRE'
|
|
# update services listening interfaces / addresses
|
|
# exclude non-existing interfaces from config
|
|
|
|
[[ (-z $reason && -z $1) || (-n $reason && ! "BOUND6 IPV4LL EXPIRE" =~ $reason) ]] && exit 0
|
|
|
|
INI="/var/local/emhttp/network.ini.new"
|
|
STA="/var/local/emhttp/statics.ini.new"
|
|
CFG="/boot/config/network.cfg"
|
|
DOCKER="/boot/config/docker.cfg"
|
|
SYSTEM="/sys/class/net"
|
|
|
|
declare -A VLANID USE_DHCP IPADDR NETMASK GATEWAY METRIC USE_DHCP6 IPADDR6 NETMASK6 GATEWAY6 PRIVACY6 METRIC6 DESCRIPTION PROTOCOL
|
|
|
|
# run & log functions
|
|
. /etc/rc.d/rc.runlog
|
|
|
|
# return variable value from file
|
|
var(){
|
|
[[ -r "$2" ]] && grep -Pom1 "^$1=\"\K[^\"]+" "$2"
|
|
}
|
|
|
|
# return interface index
|
|
index(){
|
|
cat $SYSTEM/$1/ifindex 2>/dev/null
|
|
}
|
|
|
|
# convert netmask to prefix
|
|
mask2cidr(){
|
|
[[ -z $1 ]] && return
|
|
local MASK=$(eval eval echo "'\$((('{"${1//./,}"}'>>'{7..0}')%2))'")
|
|
eval echo '$(('"${MASK// /+}"'))'
|
|
}
|
|
|
|
# convert prefix to netmask
|
|
cidr2mask(){
|
|
[[ -z $1 ]] && return
|
|
local MASK=$(eval echo '$(((1<<32)-1<<32-$1>>'{3..0}'*8&255))')
|
|
echo "${MASK// /.}"
|
|
}
|
|
|
|
# return dns nameserver entry
|
|
dns() {
|
|
[[ $1 == 4 ]] && ADDR='(\d{1,3}\.){3}\d+' || ADDR='([0-9a-fA-F]{1,4}::?){1,7}[0-9a-fA-F]*'
|
|
grep -Po "^nameserver \K$ADDR" /etc/resolv.conf
|
|
}
|
|
|
|
if [[ -s $CFG ]]; then
|
|
# import existing settings
|
|
. <(fromdos <$CFG)
|
|
else
|
|
# import default settings
|
|
IPADDR=
|
|
NETMASK=
|
|
GATEWAY=
|
|
USE_DHCP=yes
|
|
DHCP_KEEPRESOLV=no
|
|
BONDING=yes
|
|
BRIDGING=yes
|
|
fi
|
|
|
|
# prepare empty file
|
|
echo -n >$INI
|
|
echo -n >$STA
|
|
|
|
# loop thru all defined interfaces (=1 in case of legacy)
|
|
for ((i=0; i<${SYSNICS:-1}; i++)); do
|
|
IFACE=${IFNAME[$i]:-eth$i}
|
|
ETH=${IFACE/#bond/eth}
|
|
ETH=${ETH/#br/eth}
|
|
# don't store when non-existing
|
|
[[ -e $SYSTEM/$ETH ]] || continue
|
|
echo "[$ETH]" >>$INI
|
|
if [[ $i -eq 0 ]]; then
|
|
# process legacy settings
|
|
[[ $BRIDGING == yes ]] && BRNICS=eth0
|
|
[[ $BONDING == yes ]] && BRNICS=bond0
|
|
[[ $BONDING == yes ]] && IFACE=bond0
|
|
[[ $BRIDGING == yes ]] && IFACE=br0
|
|
[[ $BONDING == yes ]] && BONDNICS=${BONDNICS:-eth0 eth1 eth2 eth3}
|
|
if [[ ${USE_DHCP:-yes} == yes ]]; then
|
|
# force DNS setting to automatic if not set
|
|
DHCP_KEEPRESOLV=${DHCP_KEEPRESOLV:-no}
|
|
else
|
|
# force DNS setting to static
|
|
DHCP_KEEPRESOLV=yes
|
|
fi
|
|
if [[ ${USE_DHCP6:-yes} == yes ]]; then
|
|
# force DNS6 setting to automatic if not set
|
|
DHCP6_KEEPRESOLV=${DHCP6_KEEPRESOLV:-no}
|
|
else
|
|
# force DNS6 setting to static
|
|
DHCP6_KEEPRESOLV=yes
|
|
fi
|
|
echo "DHCP_KEEPRESOLV=\"$DHCP_KEEPRESOLV\"" >>$INI
|
|
if [[ $DHCP_KEEPRESOLV == no ]]; then
|
|
# dhcp assigned DNSv4 servers
|
|
DNS4=$(dns 4)
|
|
x=1
|
|
for SERVER in $DNS4; do
|
|
echo "DNS_SERVER$x=\"$SERVER\"" >>$INI
|
|
((x++))
|
|
done
|
|
else
|
|
# static assigned DNSv4 servers
|
|
echo "DNS_SERVER1=\"$DNS_SERVER1\"" >>$INI
|
|
echo "DNS_SERVER2=\"$DNS_SERVER2\"" >>$INI
|
|
echo "DNS_SERVER3=\"$DNS_SERVER3\"" >>$INI
|
|
fi
|
|
echo "DHCP6_KEEPRESOLV=\"$DHCP6_KEEPRESOLV\"" >>$INI
|
|
if [[ $DHCP6_KEEPRESOLV == no ]]; then
|
|
# dhcp assigned DNSv6 servers
|
|
DNS6=$(dns 6)
|
|
x=1
|
|
for SERVER6 in $DNS6; do
|
|
echo "DNS6_SERVER$x=\"$SERVER6\"" >>$INI
|
|
((x++))
|
|
done
|
|
else
|
|
# static assigned DNSv6 servers
|
|
echo "DNS6_SERVER1=\"$DNS6_SERVER1\"" >>$INI
|
|
echo "DNS6_SERVER2=\"$DNS6_SERVER2\"" >>$INI
|
|
echo "DNS6_SERVER3=\"$DNS6_SERVER3\"" >>$INI
|
|
fi
|
|
fi
|
|
[[ -n ${BONDNICS[$i]} ]] && echo "BONDING=\"yes\"" >>$INI || echo "BONDING=\"no\"" >>$INI
|
|
echo "BONDNAME=\"${BONDNAME[$i]:-bond0}\"" >>$INI
|
|
echo "BONDNICS=\"${BONDNICS[$i]// /,}\"" >>$INI
|
|
echo "BONDING_MODE=\"${BONDING_MODE[$i]:-1}\"" >>$INI
|
|
echo "BONDING_MIIMON=\"${BONDING_MIIMON[$i]:-100}\"" >>$INI
|
|
[[ -n ${BRNICS[$i]} ]] && echo "BRIDGING=\"yes\"" >>$INI || echo "BRIDGING=\"no\"" >>$INI
|
|
echo "BRNAME=\"${BRNAME[$i]:-br0}\"" >>$INI
|
|
echo "BRNICS=\"${BRNICS[$i]// /,}\"" >>$INI
|
|
echo "BRSTP=\"${BRSTP[$i]:-0}\"" >>$INI
|
|
echo "BRFD=\"${BRFD[$i]:-0}\"" >>$INI
|
|
echo "DESCRIPTION:0=\"${DESCRIPTION[$i]}\"" >>$INI
|
|
echo "PROTOCOL:0=\"${PROTOCOL[$i]}\"" >>$INI
|
|
echo "USE_DHCP:0=\"${USE_DHCP[$i]}\"" >>$INI
|
|
if [[ ${USE_DHCP[$i]} == yes ]]; then
|
|
# get dhcp assigned ipv4 address & mask
|
|
NET=($(ip -4 -br addr show scope global primary dev $IFACE | awk '{sub("/"," ",$3);print $3;exit}'))
|
|
GW=$(ip -4 route show to default dev $IFACE | awk '{print $3;exit}')
|
|
echo "IPADDR:0=\"${NET[0]}\"" >>$INI
|
|
echo "NETMASK:0=\"$(cidr2mask ${NET[1]})\"" >>$INI
|
|
echo "GATEWAY:0=\"$GW\"" >>$INI
|
|
echo "METRIC:0=\"${METRIC[$i]}\"" >>$INI
|
|
else
|
|
# get static assigned ipv4 address & mask
|
|
echo "IPADDR:0=\"${IPADDR[$i]}\"" >>$INI
|
|
echo "NETMASK:0=\"${NETMASK[$i]}\"" >>$INI
|
|
echo "GATEWAY:0=\"${GATEWAY[$i]}\"" >>$INI
|
|
echo "METRIC:0=\"${METRIC[$i]}\"" >>$INI
|
|
# store static ipv4 assignment
|
|
IPV4="$(ip -4 -br addr show scope global primary dev $IFACE | awk '{$2="";print;exit}')"
|
|
if [[ -n $IPV4 ]]; then
|
|
echo "$IPV4" >>$STA
|
|
GW4="$(ip -4 route show to default dev $IFACE)"
|
|
[[ -n $GW4 ]] && echo "$IFACE GW4 $GW4" >>$STA
|
|
fi
|
|
fi
|
|
echo "USE_DHCP6:0=\"${USE_DHCP6[$i]}\"" >>$INI
|
|
if [[ ${USE_DHCP6[$i]} == yes ]]; then
|
|
# get auto assigned ipv6 address & prefix
|
|
NET6=($(ip -6 -br addr show scope global primary -deprecated dev $IFACE | awk '{sub("/"," ",$3);print $3;exit}'))
|
|
GW6=$(ip -6 route show to default dev $IFACE | awk '{print $3;exit}')
|
|
echo "IPADDR6:0=\"${NET6[0]}\"" >>$INI
|
|
echo "NETMASK6:0=\"${NET6[1]}\"" >>$INI
|
|
echo "GATEWAY6:0=\"$GW6\"" >>$INI
|
|
echo "METRIC6:0=\"${METRIC6[$i]}\"" >>$INI
|
|
echo "PRIVACY6:0=\"${PRIVACY6[$i]}\"" >>$INI
|
|
else
|
|
# get static assigned ipv6 address & prefix
|
|
echo "IPADDR6:0=\"${IPADDR6[$i]}\"" >>$INI
|
|
echo "NETMASK6:0=\"${NETMASK6[$i]}\"" >>$INI
|
|
echo "GATEWAY6:0=\"${GATEWAY6[$i]}\"" >>$INI
|
|
echo "METRIC6:0=\"${METRIC6[$i]}\"" >>$INI
|
|
echo "PRIVACY6:0=\"\"" >>$INI
|
|
# store static ipv6 assignment
|
|
IPV6="$(ip -6 -br addr show scope global primary -deprecated dev $IFACE | awk '{$2="";print;exit}')"
|
|
if [[ -n $IPV6 ]]; then
|
|
echo "$IPV6" >>$STA
|
|
GW6="$(ip -6 route show to default dev $IFACE)"
|
|
[[ -n $GW6 ]] && echo "$IFACE GW6 $GW6" >>$STA
|
|
fi
|
|
fi
|
|
echo "USE_MTU=\"${USE_MTU[$i]}\"" >>$INI
|
|
echo "MTU=\"${MTU[$i]}\"" >>$INI
|
|
if [[ -n ${VLANS[$i]} ]]; then
|
|
# process VLAN interfaces
|
|
echo "TYPE=\"trunk\"" >>$INI
|
|
for ((j=1; j<${VLANS[$i]}; j++)); do
|
|
echo "VLANID:$j=\"${VLANID[$i,$j]}\"" >>$INI
|
|
echo "DESCRIPTION:$j=\"${DESCRIPTION[$i,$j]}\"" >>$INI
|
|
echo "PROTOCOL:$j=\"${PROTOCOL[$i,$j]}\"" >>$INI
|
|
echo "USE_DHCP:$j=\"${USE_DHCP[$i,$j]}\"" >>$INI
|
|
DEV=$IFACE.${VLANID[$i,$j]}
|
|
if [[ ${USE_DHCP[$i,$j]} == yes ]]; then
|
|
# get dhcp assigned ipv4 address & cidr2mask
|
|
NET=($(ip -4 -br addr show scope global primary dev $DEV | awk '{sub("/"," ",$3);print $3;exit}'))
|
|
GW=$(ip -4 route show to default dev $DEV | awk '{print $3;exit}')
|
|
echo "IPADDR:$j=\"${NET[0]}\"" >>$INI
|
|
echo "NETMASK:$j=\"$(cidr2mask ${NET[1]})\"" >>$INI
|
|
echo "GATEWAY:$j=\"$GW\"" >>$INI
|
|
echo "METRIC:$j=\"${METRIC[$i,$j]}\"" >>$INI
|
|
else
|
|
# get static assigned ipv4 address & mask
|
|
echo "IPADDR:$j=\"${IPADDR[$i,$j]}\"" >>$INI
|
|
echo "NETMASK:$j=\"${NETMASK[$i,$j]}\"" >>$INI
|
|
echo "GATEWAY:$j=\"${GATEWAY[$i,$j]}\"" >>$INI
|
|
echo "METRIC:$j=\"${METRIC[$i,$j]}\"" >>$INI
|
|
# store static ipv4 assignment
|
|
IPV4="$(ip -4 -br addr show scope global primary dev $DEV | awk '{$2="";print;exit}')"
|
|
if [[ -n $IPV4 ]]; then
|
|
echo "${IPV4/@$IFACE/}" >>$STA
|
|
GW4="$(ip -4 route show to default dev $DEV)"
|
|
[[ -n $GW4 ]] && echo "$DEV GW4 $GW4" >>$STA
|
|
fi
|
|
fi
|
|
echo "USE_DHCP6:$j=\"${USE_DHCP6[$i,$j]}\"" >>$INI
|
|
DEV=$IFACE.${VLANID[$i,$j]}
|
|
if [[ ${USE_DHCP6[$i,$j]} == yes ]]; then
|
|
# get auto assigned ipv6 address & prefix
|
|
NET6=($(ip -6 -br addr show scope global primary -deprecated dev $DEV | awk '{sub("/"," ",$3);print $3;exit}'))
|
|
GW6=$(ip -6 route show to default dev $DEV | awk '{print $3;exit}')
|
|
echo "IPADDR6:$j=\"${NET6[0]}\"" >>$INI
|
|
echo "NETMASK6:$j=\"${NET6[1]}\"" >>$INI
|
|
echo "GATEWAY6:$j=\"$GW6\"" >>$INI
|
|
echo "METRIC6:$j=\"${METRIC6[$i,$j]}\"" >>$INI
|
|
echo "PRIVACY6:$j=\"${PRIVACY6[$i,$j]}\"" >>$INI
|
|
else
|
|
# get static assigned ipv6 address & prefix
|
|
echo "IPADDR6:$j=\"${IPADDR6[$i,$j]}\"" >>$INI
|
|
echo "NETMASK6:$j=\"${NETMASK6[$i,$j]}\"" >>$INI
|
|
echo "GATEWAY6:$j=\"${GATEWAY6[$i,$j]}\"" >>$INI
|
|
echo "METRIC6:$j=\"${METRIC6[$i,$j]}\"" >>$INI
|
|
echo "PRIVACY6:$j=\"\"" >>$INI
|
|
# store static ipv6 assignment
|
|
IPV6="$(ip -6 -br addr show scope global primary -deprecated dev $DEV | awk '{$2="";print;exit}')"
|
|
if [[ -n $IPV6 ]]; then
|
|
echo "${IPV6/@$IFACE/}" >>$STA
|
|
GW6="$(ip -6 route show to default dev $DEV)"
|
|
[[ -n $GW6 ]] && echo "$DEV GW6 $GW6" >>$STA
|
|
fi
|
|
fi
|
|
done
|
|
else
|
|
# interface without VLANs
|
|
echo "TYPE=\"access\"" >>$INI
|
|
fi
|
|
done
|
|
# atomically update file
|
|
mv $INI ${INI%.*}
|
|
mv $STA ${STA%.*}
|
|
|
|
# add or remove IPv4 assignment from attached interface when Docker custom network access is allowed
|
|
[[ ${interface:0:2} == br || $interface == wlan0 ]] && LINK=shim-$interface || LINK=vhost${interface//[^0-9.]/}
|
|
if [[ -e $SYSTEM/$LINK && $(var DOCKER_ALLOW_ACCESS $DOCKER) == yes ]]; then
|
|
IPV4=$(ip -4 -br addr show scope global primary dev $interface | awk '{print $3;exit}')
|
|
[[ $interface == wlan0 ]] && INDEX=3000 || INDEX=1000
|
|
INDEX=$(($INDEX - 1 + $(index $interface)))
|
|
case $reason in
|
|
'BOUND' | 'BOUND6')
|
|
# re-add IPv4 address of parent (if docker is running)
|
|
[[ -S /var/run/docker.sock ]] && ip addr add $IPV4 metric $INDEX dev $LINK
|
|
;;
|
|
'EXPIRE')
|
|
# remove IPv4 address of parent
|
|
ip addr del $IPV4 metric $INDEX dev $LINK
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
log "interface=${interface:-$1}, reason=$reason, protocol=$protocol"
|
|
# delayed execution
|
|
/usr/local/emhttp/webGui/scripts/update_services 20
|
|
|
|
# generate our welcome text (management interface only)
|
|
if [[ -z $interface || "eth0 br0 bond0 wlan0" =~ $interface ]]; then
|
|
. /etc/unraid-version
|
|
echo -e "Unraid Server OS version: $version" >/etc/issue
|
|
# find management interface
|
|
[[ -e $SYSTEM/bond0 ]] && DEV=bond0 || DEV=eth0
|
|
[[ -e $SYSTEM/br0 ]] && DEV=br0
|
|
IPV4=$(ip -4 -br addr show scope global primary dev $DEV | awk '{print $3;exit}' | sed -r 's/\/[0-9]+//')
|
|
IPV6=$(ip -6 -br addr show scope global primary -deprecated dev $DEV | awk '{print $3;exit}' | sed -r 's/\/[0-9]+//')
|
|
# show current IP assignment
|
|
[[ -n $IPV4 ]] && echo " IPv4 address: $IPV4" >>/etc/issue || echo " IPv4 address: not set" >>/etc/issue
|
|
[[ -n $IPV6 ]] && echo " IPv6 address: $IPV6" >>/etc/issue || echo " IPv6 address: not set" >>/etc/issue
|
|
if [[ -e $SYSTEM/wlan0 ]]; then
|
|
echo "Wireless network:" >>/etc/issue
|
|
IPV4=$(ip -4 -br addr show scope global primary dev wlan0 | awk '{print $3;exit}' | sed -r 's/\/[0-9]+//')
|
|
IPV6=$(ip -6 -br addr show scope global primary -deprecated dev wlan0 | awk '{print $3;exit}' | sed -r 's/\/[0-9]+//')
|
|
[[ -n $IPV4 ]] && echo " IPv4 address: $IPV4" >>/etc/issue || echo " IPv4 address: not set" >>/etc/issue
|
|
[[ -n $IPV6 ]] && echo " IPv6 address: $IPV6" >>/etc/issue || echo " IPv6 address: not set" >>/etc/issue
|
|
fi
|
|
echo >>/etc/issue
|
|
fi
|
|
exit 0
|