diff --git a/gluon/gluon-autoupdater/Makefile b/gluon/gluon-autoupdater/Makefile new file mode 100644 index 0000000..559a783 --- /dev/null +++ b/gluon/gluon-autoupdater/Makefile @@ -0,0 +1,32 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=autoupdater +PKG_RELEASE:=0.1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/autoupdater + SECTION:=admin + CATEGORY:=Administration + DEPENDS:=+ecdsautils +gluon-cron + TITLE:=Automatically update firmware +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/autoupdater/install + $(CP) ./files/* $(1)/ + chmod +x $(1)/usr/sbin/autoupdate +endef + +$(eval $(call BuildPackage,autoupdater)) diff --git a/gluon/gluon-autoupdater/README.md b/gluon/gluon-autoupdater/README.md new file mode 100644 index 0000000..1caf181 --- /dev/null +++ b/gluon/gluon-autoupdater/README.md @@ -0,0 +1,5 @@ +Models +====== + +tp-link-tl-wr741n/nd-v4 +tp-link-tl-wr1043n/nd-v1 diff --git a/gluon/gluon-autoupdater/files/etc/config/autoupdater b/gluon/gluon-autoupdater/files/etc/config/autoupdater new file mode 100644 index 0000000..d86d1c2 --- /dev/null +++ b/gluon/gluon-autoupdater/files/etc/config/autoupdater @@ -0,0 +1,19 @@ +config autoupdater + option enabled 0 + option branch "stable" + option url 'http://[fdef:ffc0:3dd7::8]/~freifunk/firmware/autoupdate' + + # The updater will run once per hour and perform an update with a certain + # probability. + # 1.0 - perform an update every hour + # 0.5 - on average, perform an update every two hours + # 0.0 - inhibit any automatic updates + option probability 0.5 + + # Minimum valid signatures required to perform the update + option good_signatures 2 + + # List of public keys + list pubkey 'beea7da92ed0c19563b6c259162b4cb471aa2fdf9d3939d05fea2cf498ea7642' + list pubkey 'c75c9390cf5d7cc49a388d35f831ca379060cf7bca8c6e3d2d1ea31604597c42' + list pubkey '03e9514f137f0467c0f0ac108892c0da2b71f1039b30f863331cbd5701abd042' diff --git a/gluon/gluon-autoupdater/files/lib/gluon/cron/autoupdater b/gluon/gluon-autoupdater/files/lib/gluon/cron/autoupdater new file mode 100644 index 0000000..740503b --- /dev/null +++ b/gluon/gluon-autoupdater/files/lib/gluon/cron/autoupdater @@ -0,0 +1 @@ +0 * * * * /usr/sbin/autoupdate diff --git a/gluon/gluon-autoupdater/files/usr/sbin/autoupdate b/gluon/gluon-autoupdater/files/usr/sbin/autoupdate new file mode 100755 index 0000000..079cae2 --- /dev/null +++ b/gluon/gluon-autoupdater/files/usr/sbin/autoupdate @@ -0,0 +1,140 @@ +#!/bin/sh + +if test $(uci get autoupdater.@autoupdater[0].enabled) != 1; then + echo "autoupdater is disabled" + exit 0 +fi + +PROBABILITY=$(uci get autoupdater.@autoupdater[0].probability) + +if test "a$1" != "a-f"; then + echo | awk "END{srand();exit rand() > $PROBABILITY}" + if test $? -ne 0; then + echo "No autoupdate this time. Use -f to override" + exit 0 + fi +fi + +BASE=$(uci get autoupdater.@autoupdater[0].url) +PUBKEYS=$(uci get autoupdater.@autoupdater[0].pubkey) +GOOD_SIGNATURES=$(uci get autoupdater.@autoupdater[0].good_signatures) +BRANCH=$(uci get autoupdater.@autoupdater[0].branch) + +VERSION_FILE=/etc/firmware_version + +newer_than() { + local old="$(printf '%s\n%s\n' "$1" "$2" | sort -n | head -n 1)" + test "$1" != "$old" +} + +cleanup() { + rm -f $manifest + rm -f $fw_image + rm -f $manifest_upper + rm -f $manifest_lower +} + +trap cleanup INT TERM EXIT PIPE + +my_model="$(cat /tmp/sysinfo/model | sed 's/ /-/g' | tr '[A-Z]' '[a-z]')" + +case "$my_model" in + "tl-wdr4300") + case "$(tplink_get_hwid)" in + "360000"*) + my_model="tl-wdr3600" + ;; + esac + ;; +esac + +if [ ! -f "$VERSION_FILE" ]; then + echo "Couldn't determine firmware version!" >&2 + exit 1 +fi + +my_version="$(cat "$VERSION_FILE")" + +fw_image=$(mktemp) +manifest=$(mktemp) +manifest_upper=$(mktemp) +manifest_lower=$(mktemp) + +wget -O$manifest "$BASE"/manifest + +if test $? -ne 0; then + echo "Couldn't fetch manifest" >&2 + exit 1 +fi + +seperator_line=$(cat $manifest|grep -n "^---$"|cut -d: -f1|head -n1) + +if test -z "$seperator_line"; then + echo "Couldn't find --- marker!" >&2 + exit 1 +fi + +head -n$(($seperator_line-1)) $manifest > $manifest_upper +tail -n+$(($seperator_line+1)) $manifest > $manifest_lower + +signatures="" +while read sig; do + echo "$sig" | grep -q "^[0-9a-f]\{128\}$" + if test $? -ne 0; then + continue + fi + signatures="$signatures -s $sig" +done < $manifest_lower + +pubkeys="" +for key in $PUBKEYS; do + pubkeys="$pubkeys -p $key" +done + +ecdsaverify -n $GOOD_SIGNATURES $pubkeys $signatures $manifest_upper + +if test $? -ne 0; then + echo "Not enough valid signatures!" >&2 + exit 1 +fi + +grep -q "^BRANCH=${BRANCH}$" $manifest_upper + +if test $? -ne 0; then + echo "Wrong branch. We'are on ${BRANCH}" >&2 + exit 1 +fi + +my_firmware=$(grep "^${my_model} " $manifest_upper) + +if test $? -ne 0; then + echo "No matching firmware found (model ${my_model})" >&2 + exit 1 +fi + +fw_version=$(echo "${my_firmware}"|cut -d' ' -f2) +fw_md5=$(echo "${my_firmware}"|cut -d' ' -f3) +fw_file=$(echo "${my_firmware}"|cut -d' ' -f4) + +if newer_than "$fw_version" "$my_version"; then + echo "New version available" + wget -O$fw_image "${BASE}/${fw_file}" + if test $? -ne 0; then + echo "Error downloading image" >&2 + exit 1 + fi + + image_md5=$(md5sum "$fw_image"|cut -b-32) + if test "$image_md5" != "$fw_md5"; then + echo "Invalid image checksum" >&2 + exit 1 + fi + + echo "Upgrading firmware." + + sysupgrade "${fw_image}" +else + echo "No new firmware available" +fi + +exit 0 diff --git a/gluon/gluon-autoupdater/manifest.sample b/gluon/gluon-autoupdater/manifest.sample new file mode 100644 index 0000000..0d302ab --- /dev/null +++ b/gluon/gluon-autoupdater/manifest.sample @@ -0,0 +1,4 @@ +BRANCH=stable + +# board ver md5sum filename +tl-wdr4300 0.4 73e0788596850798d8e02a9ac577d201 sysupgrade-wdr4300.bin