mirror of
https://dev.iopsys.eu/feed/iopsys.git
synced 2026-03-14 21:10:11 +01:00
595 lines
15 KiB
Bash
Executable file
595 lines
15 KiB
Bash
Executable file
#!/bin/sh
|
|
|
|
echo $$ > /var/run/iup.pid
|
|
|
|
. /lib/functions.sh
|
|
. /lib/functions/network.sh
|
|
. /lib/functions/savecfg.sh
|
|
. /lib/functions/dhcp_option_relay.sh
|
|
. /usr/share/libubox/jshn.sh
|
|
|
|
include /lib/upgrade
|
|
include /lib/network
|
|
|
|
export IUPCONFFILES=/tmp/iup/sysupgrade.conffiles.tar.gz
|
|
export IUPMD5=/etc/configchecksums
|
|
export CONFILESLURP='/tmp/iup/*.conf'
|
|
export IUPTEMP="/tmp/iup"
|
|
export INTERACTIVE=0
|
|
export VERBOSE=0
|
|
export CONF=1
|
|
export DESKEY=
|
|
export MAC=
|
|
export RANGE=10
|
|
export RETRYSTOP=5
|
|
export SLEEP=10
|
|
|
|
json_load "$(ubus call router.system info)"
|
|
json_select system
|
|
json_get_var MAC basemac
|
|
json_select ..
|
|
json_select keys
|
|
json_get_var DESKEY des
|
|
json_select ..
|
|
|
|
# MAC lowercase to uppercase and remove ':'
|
|
MAC=$(echo $MAC | tr '[a-z]' '[A-Z]' | tr -d ':')
|
|
|
|
# Convert DESKEY to HEX format
|
|
DESKEY=$(echo $DESKEY | tr -d '\n' | hexdump -e '16/1 "%02x"')
|
|
|
|
|
|
# no verbose: no output
|
|
# -v log to system log
|
|
# -v -v log to system log and console
|
|
# -v -v -v log to system log, console and stderr
|
|
v() {
|
|
[ "$VERBOSE" -eq 0 ] && return
|
|
[ "$VERBOSE" -eq 1 ] && logger -t $0[$$] "$@" && return
|
|
[ "$VERBOSE" -eq 2 ] && logger -s -t $0[$$] "$@" >/dev/console 2>&1 && return
|
|
[ "$VERBOSE" -eq 3 ] && logger -s -t $0[$$] "$@" 2>&1 | tee /dev/console && return
|
|
}
|
|
|
|
vv() {
|
|
VERBOSE="$(($VERBOSE + 1))"
|
|
v "$@"
|
|
VERBOSE="$(($VERBOSE - 1))"
|
|
|
|
}
|
|
|
|
get_packages()
|
|
{
|
|
local pack
|
|
pack=$(grep -w 'package' $1)
|
|
pack=${pack//package/}
|
|
#pack=${pack//[\'|\"]/}
|
|
echo $pack | tr -d '\"' | tr -d "'"
|
|
}
|
|
|
|
reload ()
|
|
{
|
|
local pack
|
|
pack=$(get_packages $1)
|
|
v "Calling ubus call uci commit for $pack"
|
|
for packname in $pack
|
|
do
|
|
ubus call uci commit '{"config":"'$packname'"}'
|
|
sleep 1
|
|
done
|
|
}
|
|
|
|
save_usercfg()
|
|
{
|
|
savecfg_save_config fw_redirect fw_parental wifi
|
|
}
|
|
|
|
apply_usercfg()
|
|
{
|
|
# decide to save the user changes based on keepuserconfig received through provisioning
|
|
local keep
|
|
config_load provisioning
|
|
config_get_bool keep configserver keepuserconfig "0"
|
|
v "apply_usercfg(): keepuserconfig = $keep"
|
|
if [ "$keep" != "1" ] ; then
|
|
savecfg_rm_files
|
|
return
|
|
fi
|
|
|
|
savecfg_apply_config fw_redirect fw_parental wifi
|
|
}
|
|
|
|
handle_provisioning() {
|
|
local config="$1"
|
|
local default="$2"
|
|
local enabled
|
|
local url
|
|
local tftpfile
|
|
local host
|
|
local md5
|
|
local defaultreset
|
|
local pack
|
|
local packname
|
|
local number=$RANDOM
|
|
local retry=1
|
|
local number
|
|
local incsleep=$SLEEP
|
|
let "number %= $RANGE"
|
|
if [[ ! -e $IUPTEMP ]]; then
|
|
mkdir $IUPTEMP
|
|
fi
|
|
touch $IUPCONFFILES
|
|
config_get_bool enabled "$config" enabled "$default"
|
|
config_get_bool defaultreset "$config" defaultreset
|
|
config_get deckey "$config" deckey
|
|
if [ "$enabled" -eq 1 ]; then
|
|
if [ "$config" == "iup" ]; then
|
|
v "Using url received in dhcp options"
|
|
config_get url "$config" urliup
|
|
else
|
|
config_get url "$config" url
|
|
fi
|
|
url=${url//\$MAC/$MAC}
|
|
v "Downloading from url \"$url\""
|
|
|
|
while [ $retry -le $RETRYSTOP ]
|
|
do
|
|
if [ ${url%%:*} == "tftp" ]; then
|
|
tftpfile=${url#*\/\/}
|
|
host=${tftpfile%%\/*}
|
|
tftpfile=${tftpfile#*\/}
|
|
|
|
/usr/bin/tftp -l $IUPCONFFILES -r "$tftpfile" -g "$host"
|
|
else
|
|
get_image "$url" "cat" > $IUPCONFFILES
|
|
fi
|
|
if [ -s $IUPCONFFILES ]; then
|
|
v "Download finished"
|
|
retry=$((RETRYSTOP + 1))
|
|
else
|
|
v "Download failed, retrying in $incsleep seconds"
|
|
sleep $incsleep
|
|
incsleep=$((incsleep * retry + number))
|
|
retry=$((retry+1))
|
|
fi
|
|
done
|
|
fi
|
|
if [ ! -s "$IUPCONFFILES" ] && [ "$enabled" -eq 1 ]; then
|
|
echo "File not Found"
|
|
reboot="off"
|
|
CONF=0
|
|
else
|
|
handle_Downloaded_file $deckey
|
|
fi
|
|
}
|
|
|
|
handle_Downloaded_file()
|
|
{
|
|
local DECKEY
|
|
local KEY
|
|
[ -n "$1" ] && DECKEY=$(echo $1 | tr -d '\n' | hexdump -e '16/1 "%02x"')
|
|
KEY=${DECKEY:-$DESKEY}
|
|
local img_type
|
|
case "$(get_image_type "$IUPCONFFILES")" in
|
|
"INTENO") img_type=2 ;;
|
|
"CFE+FS") img_type=1 ;;
|
|
"FS") img_type=0 ;;
|
|
*) img_type="UNKNOWN";;
|
|
esac
|
|
|
|
if [ "$img_type" == "UNKNOWN" ] ; then
|
|
case "$(hexdump -v -n 2 -e '1/1 "%02x"' $IUPCONFFILES)" in
|
|
1f8b)
|
|
v "Downloaded file is an unencrypted config"
|
|
md5=$(md5sum $IUPCONFFILES)
|
|
md5="${md5%% *}" # remove the first space and everything after it
|
|
md5sum "$IUPCONFFILES" >> "$IUPMD5.temp"
|
|
if grep -q "$md5" "$IUPMD5"; then
|
|
v "Config is already up to date, nothing to do"
|
|
#because config is up to date we need to disable last step reboot if set
|
|
reboot="off"
|
|
rm -rf $IUPTEMP
|
|
else
|
|
save_usercfg
|
|
cd $IUPTEMP
|
|
tar xvzf $IUPCONFFILES
|
|
for f in $CONFILESLURP
|
|
do
|
|
v "File to be applied $f and config $(cat $f)"
|
|
uci -f $f import
|
|
done
|
|
pack=$(get_packages $CONFILESLURP)
|
|
v "Packages to be commited: $pack"
|
|
for packname in $pack
|
|
do
|
|
uci commit $packname
|
|
done
|
|
apply_usercfg
|
|
reboot=`uci -q get provisioning.configserver.reboot`
|
|
if [ "$reboot" != "on" ]; then
|
|
sync
|
|
reload $CONFILESLURP
|
|
fi
|
|
rm -rf $IUPTEMP
|
|
|
|
cp /rom/etc/uci-defaults/* /etc/uci-defaults/
|
|
sync
|
|
fi
|
|
;;
|
|
*)
|
|
v "Downloaded file is an encrypted config"
|
|
if [ $KEY ]; then
|
|
openssl enc -d -des-ede -nosalt -K $KEY -iv "0000000000000000" -in $IUPCONFFILES -out $IUPCONFFILES.tmp
|
|
if [ $? -eq 0 ]; then
|
|
v "Decryption successful"
|
|
mv $IUPCONFFILES.tmp $IUPCONFFILES
|
|
handle_Downloaded_file
|
|
else
|
|
v "Decryption Failed! Exiting"
|
|
rm -rf $IUPTEMP
|
|
exit 1
|
|
fi
|
|
else
|
|
v "No Key Defined"
|
|
rm -rf $IUPTEMP
|
|
exit 1
|
|
fi
|
|
;;
|
|
esac
|
|
else
|
|
v "Downloaded file is a firmware, will start reflashing"
|
|
if [ "$defaultreset" -eq 1 ]; then
|
|
v "Not saving configuration over reflash"
|
|
/sbin/sysupgrade -v -n $IUPCONFFILES
|
|
else
|
|
v "Saving configuration over reflash"
|
|
/sbin/sysupgrade -v $IUPCONFFILES
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# function: change_to_vlan
|
|
# arg 1 = vlan id
|
|
# arg 2 = vlan priority
|
|
# arg 3 = $INTERFACE
|
|
change_to_vlan() {
|
|
# local variables.
|
|
local name="vlan$1" # construct name = vlan + vlanid.
|
|
local base_dev # varible holding device name of wan port.
|
|
local wan_if # variable holding wan interfaces.
|
|
local new_wan_if #
|
|
|
|
# extract device name.
|
|
network_get_device base_dev $3
|
|
|
|
# bring down old interface/device.
|
|
ifdown "${base_dev}"
|
|
v "option 132: bringing down old if: ${base_dev}"
|
|
|
|
# extract base name of device.
|
|
base_dev=$(echo ${base_dev} | cut -d. -f1)
|
|
|
|
# add "VLAN interface" to the "end of the file".
|
|
uci add network device
|
|
uci rename network.@device[-1]=${name}
|
|
uci set network.@device[-1].type=8021q
|
|
uci set network.@device[-1].ifname=${base_dev}
|
|
uci set network.@device[-1].name="${base_dev}.${1}"
|
|
uci set network.@device[-1].vid=${1}
|
|
uci set network.@device[-1].priority=${2}
|
|
# and commit the change.
|
|
uci commit network
|
|
v "option 132: committed update to file network"
|
|
|
|
# reload configuration files.
|
|
ubus call network reload
|
|
v "option 132: reload network config"
|
|
|
|
# replace old interface (like eth0.1 with new eth0.101).
|
|
wan_if=$(uci get network.$3.ifname)
|
|
v "option 132: old network.${3}.ifname: $wan_if"
|
|
|
|
# loop through the string, remove any word close to "base_dev".
|
|
for word in ${wan_if}; do
|
|
#echo $word
|
|
case $word in
|
|
${base_dev}*) # don't add if.
|
|
;;
|
|
*) new_wan_if=${word}' '${new_wan_if} # add if.
|
|
#new_wan_if+=" ${word}" # probably not working in ash.
|
|
;;
|
|
esac
|
|
done
|
|
# append new interface.
|
|
new_wan_if=${new_wan_if}${base_dev}.${1}
|
|
uci set network.wan.ifname="${new_wan_if}"
|
|
# and commit the change.
|
|
uci commit network
|
|
v "option 132: committed update to file network: ifname=${new_wan_if}"
|
|
|
|
# reboot into new if configuration.
|
|
vv "Rebooting"
|
|
export REBOOT_REASON=iup
|
|
/sbin/reboot
|
|
}
|
|
|
|
handle_option224()
|
|
{
|
|
if [ -z "$1" ] ; then
|
|
echo "No argument"
|
|
return 1
|
|
fi
|
|
|
|
if [ $(echo $1|grep -o "," | wc -l) -eq 0 ] ; then
|
|
url=$1
|
|
else
|
|
url=$(echo $1|cut -d',' -f1)
|
|
a=$(echo $1|cut -d',' -f2)
|
|
b=$(echo $1|cut -d',' -f3)
|
|
c=$(echo $1|cut -d',' -f4)
|
|
fi
|
|
|
|
currdate=$(date +"%Y-%m-%d")
|
|
|
|
active=0
|
|
if [ -z $a ] ; then
|
|
active=1
|
|
elif [ $a ] && [ $b ] && [ $a -lt 25 ] ; then
|
|
#Time
|
|
begin=$(date +%s -d"$currdate $a")
|
|
now=$(date +%s)
|
|
end=$((begin+3600*$b))
|
|
if [ $now -gt $begin ] && [ $now -lt $end ] ; then
|
|
active=1
|
|
fi
|
|
elif [ $a ] && [ $b ] && [ $c ] && [ $a -gt 25 ] ; then
|
|
#Date
|
|
y=$(echo $a| cut -c1-4)
|
|
m=$(echo $a| cut -c5-6)
|
|
d=$(echo $a| cut -c7-8)
|
|
begin=$(date +%s -d"$y-$m-$d $b")
|
|
now=$(date +%s)
|
|
end=$((begin+3600*$c))
|
|
if [ $now -gt $begin ] && [ $now -lt $end ] ; then
|
|
active=1
|
|
fi
|
|
else
|
|
echo "Bad format"
|
|
return 1
|
|
fi
|
|
|
|
softwareminuspath=${url##*/}
|
|
|
|
if [ $url ] && [ $active -eq 1 ]; then
|
|
v "Software version to download \"$softwareminuspath\""
|
|
local sysinfo=$(ubus call router.system info)
|
|
json_load "$sysinfo"
|
|
json_select system
|
|
json_get_var firmware firmware
|
|
local firmware_new=${softwareminuspath%.*} # remove extension (.w, .y or .y2) from filename
|
|
if [ "$firmware_new" != "$firmware" ] ; then
|
|
v "Firmware found $url will start flashing"
|
|
v "Currently running firmware: \"$firmware\""
|
|
v "Newly received firmware: \"$firmware_new\""
|
|
wait_for_dns $url
|
|
v "Start flashing"
|
|
/sbin/sysupgrade -v $url &
|
|
return 1
|
|
else
|
|
v "Firmware is up to date, nothing to do"
|
|
return 0
|
|
fi
|
|
fi
|
|
}
|
|
|
|
|
|
parse_dhcp_options()
|
|
{
|
|
local the_json="$@"
|
|
|
|
# process the dhcp_option_relay sections
|
|
dhcp_option_relay_parse "$the_json"
|
|
|
|
# Process IUP related DHCP options #
|
|
local privopt224 privopt225 privopt226 vendorspecinf httpurl128
|
|
local tftp bootfile vlanid vlanpriority interface
|
|
|
|
json_load "$the_json"
|
|
json_get_var interface interface
|
|
json_get_var privopt224 privopt224
|
|
json_get_var privopt225 privopt225
|
|
json_get_var privopt226 privopt226
|
|
json_get_var vendorspecinf vendorspecinf # option 43
|
|
json_get_var httpurl128 httpurl128
|
|
json_get_var tftp tftp # option 66
|
|
json_get_var bootfile bootfile #option 67
|
|
json_get_var vlanid vlanid # option 132
|
|
json_get_var vlanpriority vlanpriority # option 133
|
|
|
|
if [ $privopt224 ]; then
|
|
v "dhcp option 224 firmware url $privopt224"
|
|
handle_option224 $privopt224
|
|
[ $? -eq 1 ] && exit
|
|
fi
|
|
|
|
if [ $vendorspecinf ]; then
|
|
v "dhcp option 43 tr69 url $vendorspecinf"
|
|
url=${vendorspecinf%%,*}; rest=${vendorspecinf#*,}
|
|
provisioningcode=${rest%%,*};
|
|
[ -f /etc/config/cwmp ] && uci_set_state cwmp acs dhcp_url "$url"
|
|
uci_set_state provisioning iup urlcwmp "$url"
|
|
uci_set_state provisioning iup url "$url"
|
|
uci_set_state provisioning iup provisioningcode "$provisioningcode"
|
|
elif [ $httpurl128 ]; then
|
|
v "dhcp option 128 http config url $httpurl128"
|
|
uci_set_state provisioning iup urliup "$httpurl128"
|
|
elif [ $tftp ]; then
|
|
v "dhcp option 66 tftp config url $tftp"
|
|
if [ ${bootfile:0:1} == '/' ]; then
|
|
uci_set_state provisioning iup urliup "tftp://$tftp$bootfile"
|
|
else
|
|
uci_set_state provisioning iup urliup "tftp://$tftp/$bootfile"
|
|
fi
|
|
fi
|
|
|
|
# vlanid (and vlanpriority)
|
|
if [ -n "$vlanid" -a -n "$vlanpriority" ]; then
|
|
v "dhcp option 132 vlanid: ${vlanid} vlanpriority: ${vlanpriority}"
|
|
change_to_vlan ${vlanid} ${vlanpriority} ${interface}
|
|
elif [ -n "$vlanid" ]; then
|
|
v "dhcp option 132 vlanid: ${vlanid}"
|
|
change_to_vlan ${vlanid} 0 ${interface}
|
|
elif [ -n "$privopt225" ] || [ -n "$privopt226" ]; then
|
|
# opt225 and opt226 can be used together or separatly
|
|
if [ -n "$privopt225" ]; then
|
|
v "dhcp option 225: $privopt225"
|
|
# option225 is allowd to change only once per CPE
|
|
if [ "$(uci get -q ice.cloud.frozen)" != "1" ] ; then
|
|
uci set ice.cloud.frozen="1"
|
|
uci set ice.cloud.enabled="1"
|
|
uci set ice.cloud.server="$privopt225"
|
|
fi
|
|
fi
|
|
if [ -n "$privopt226" ]; then
|
|
v "dhcp option 226: $privopt226"
|
|
[ -z "$(uci get -q ice.dhcp)" ] && uci set ice.dhcp="dhcp"
|
|
uci set ice.dhcp.opt226connectionid="$privopt226"
|
|
ubus send dhcp.opt226connectionid '{"opt226connectionid":"","value":"'$privopt226'"}'
|
|
fi
|
|
uci commit
|
|
fi
|
|
}
|
|
|
|
# wait_for_default_gateway to become reachable
|
|
# return 0 if the default gateway is reachable
|
|
# return 1 if the default gateway is not reachable after $wait_time
|
|
wait_for_default_gateway()
|
|
{
|
|
local gateway
|
|
local device
|
|
local wait_time=120
|
|
local wait_interval=10
|
|
|
|
while [ true ] ; do
|
|
|
|
gateway=""
|
|
device=""
|
|
network_flush_cache
|
|
network_get_gateway gateway wan #true
|
|
network_get_device device wan
|
|
device="${device:+-I }$device"
|
|
if ping -q -w 1 -c 1 $device $gateway >/dev/null 2>&1 ; then
|
|
[ "$wait_time" -lt "60" ] && v "Default gateway $gateway is reachable"
|
|
sleep $wait_interval
|
|
return 0
|
|
fi
|
|
|
|
# try the nameservers too
|
|
for ns in $(grep nameserver /var/resolv.conf.auto | awk '{print $2}'); do
|
|
if ping -q -w 1 -c 1 $device $ns >/dev/null 2>&1 ; then
|
|
[ "$wait_time" -lt "60" ] && v "Name server $ns is reachable"
|
|
sleep $wait_interval
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
v "Waiting for default gateway or name server. Countdown $wait_time seconds"
|
|
sleep $wait_interval
|
|
wait_time=$((wait_time - wait_interval))
|
|
[ "$wait_time" -le "0" ] && break # timer expired
|
|
done
|
|
|
|
return 1 # default gateway and name server are not reachable
|
|
}
|
|
|
|
|
|
main()
|
|
{
|
|
|
|
while [ -n "$1" ]; do
|
|
case "$1" in
|
|
-v) export VERBOSE="$(($VERBOSE + 1))";;
|
|
-q) export VERBOSE="$(($VERBOSE - 1))";;
|
|
--dhcp-options)
|
|
shift
|
|
parse_dhcp_options "$@"
|
|
exit 0
|
|
;;
|
|
-*)
|
|
echo "Invalid option: $1"
|
|
exit 1
|
|
;;
|
|
*) break;;
|
|
esac
|
|
shift;
|
|
done
|
|
|
|
if ! wait_for_default_gateway ; then
|
|
v "Neither default gateway nor name server are reachable. Aborting iup."
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -f $IUPMD5 ]; then
|
|
v "Creating file $IUPMD5"
|
|
touch $IUPMD5
|
|
fi
|
|
|
|
|
|
local iupurl
|
|
local configurl
|
|
local software
|
|
local sofwareminuspath
|
|
|
|
config_load provisioning
|
|
#check if iup should be used or if its overridden by /etc/config
|
|
config_get configurl configserver url
|
|
config_get reboot configserver reboot
|
|
config_get iupurl iup urliup
|
|
|
|
if [ $configurl ]; then
|
|
handle_provisioning configserver "0"
|
|
elif [ $iupurl ]; then
|
|
handle_provisioning iup "1"
|
|
else
|
|
v "No provisioning server configured"
|
|
exit
|
|
fi
|
|
|
|
config_load provisioning
|
|
config_foreach handle_provisioning subconfig "0"
|
|
config_get software uppgradeserver url
|
|
sofwareminuspath=${software##*/}
|
|
|
|
if [ $software ]; then
|
|
v "Software version to download \"$sofwareminuspath\""
|
|
local sysinfo=$(ubus call router.system info)
|
|
json_load "$sysinfo"
|
|
json_select system
|
|
json_get_var firmware firmware
|
|
json_get_var filesystem filesystem
|
|
if [ "$filesystem" == "JFFS2" ] ; then
|
|
firmware=$firmware.w
|
|
else
|
|
firmware=$firmware.y3
|
|
fi
|
|
if [ "$sofwareminuspath" == "${sofwareminuspath/$firmware/}" ] ; then
|
|
v "Software \"$software\""
|
|
handle_provisioning uppgradeserver "0"
|
|
else
|
|
v "Will not update software, already up to date"
|
|
fi
|
|
fi
|
|
|
|
if [ $CONF -eq 1 ]; then
|
|
mv "$IUPMD5.temp" $IUPMD5
|
|
fi
|
|
|
|
if [ "$reboot" == "on" ]; then
|
|
vv "Rebooting"
|
|
export REBOOT_REASON=iup
|
|
/sbin/reboot
|
|
fi
|
|
|
|
rm -rf /var/run/iup.pid
|
|
}
|
|
|
|
main $@
|