#!/bin/bash MYPWD="$(dirname $(realpath $0))" help() { echo "$0: Ask avm's JUIS update service for latest firmware infos like download url" cat << 'EOX' Parameters: -a [Prio4] Actions, shows the URL if there is a newer version, prepended with the HWR. -i [Prio3] Computer, shows the URL if there is a newer version. -s [Prio2] Fritzbox, shows if a new version is available. Response is cached in: "/tmp/.juis_check" -d [Prio1] RAW-output of the response (or no -a, -i and -s). --nofb Do not try to read values from the local Fritzbox in juis_boxinfo.xml or older jason_boxinfo.xml files, but use random if vaiable is not set. --dect Dect-Update: Searches for a firmware for an dect device. --bpjm BPjM-Update: Searches for the encrypted BPjM-Modul file. To format the bpjm file and remove hashes for empty strings: cat $RAWFILE | hexdump -s 64 -v -e '16/1 "%02x" " " 16/1 "%02x" " " 1/1 "%02x\n"' | sed 's/d41d8cd98f00b204e9800998ecf8427e 00$//' - 1st row is the hash of protocol + domain (without subdomain), eg "http://example.com". - 2nd row is the hash of the path + file, eg "/directory/file.extension" or empty. To read the CRC32 checksum in the header: head -c4 $RAWFILE | xxd -p To calculate the CRC32 checksum of the body: crc32 <( tail -c +$((1 + 4)) $RAWFILE ) --info InfoMessage: Searches for a very important info message by avm. --down Downgrade: Searches for latest release firmware, like "Zurück zum offiziellen FRITZ!OS". "Buildtype" should not be "1". Without --dect, --bpjm, --info and --down, a firmware for a Fritzbox is searched. --plain Forces to use http. AVM uses this only. --https Forces to use https. Curl is mandatory for https. Without --plain and --https, the default is https if curl is installed. But on fritzbox only if "FREETZ_ADD_JUIS_CHECK__SSL" is set. Variables: On Fritzbox no variables are needed and missing will be read from the device. On Computer the hardware-recision "HW" is mandatory and for very old (HWR<150) devices you have to set (at least the "Major" part of) "Version". With Dect: The hardware number "DHW" is mandatory additional, the software version "DSW" and type "DTP" are optional. Name Default if not set Comment ---------------------------------------------------------------------------------------------------------------------------------------------------------- HW [mandatory] The HWR code of the device, eg "226" for Fritzbox 7590 Version [HW].00.00-00000 The "HW" as "Major" does not work with HW<150 Name [random] There is no space in the name but a zero-width space: "printf '\342\200\212'". Or copy & paste examples below. OEM avm Examples: "avm", "avme", "kdg", "1und1", "lgi", "otwo" Lang de Examples: "de", "en", "es", "it", "fr", "pl", "nl" Annex B (Kabel for docsis) Extender use "Ohne", docsis devices "Kabel". Country 049 Examples: "049", "99", "041", "0420", "0421", "043", "044", "045", "046", "047", "048", "061", "064", "066", "0972" Buildtype 1 (1000 for --down) Common values: "1"=retail, "1001"=labor, "1000"=inhaus Serial [random] Example: "123456789ABC" Nonce [random] Example: "123456789aBcDeEfGhIjkL==" Flag [shuffle] If you do not want to set a flag use "empty", for docsis devices "cable_retail" is added. UserAgent [shuffle] Values: "Box", "TestClient" or "BoxInternetCheck" Provider [shuffle] Use "empty" if you want no value ProviderName [empty] This is not added if not set ManualRequest [shuffle] Values: "true" or "false" UpdateConfig [shuffle] Values: "1" or "3" DHW (dect) [mandatory] The MHW code of the device, eg "06.08" for Dect 302 DSW (dect) 00.00 The firmware version of the dect device to check, "00.00" works always. DTP (dect) 1 Values: "1"=Dect, "2"=PLC, "3"=LTE Examples: env - tools/juis_check --dect Version=154.07.25-80000 Name=FRITZ\!Box 7590 HW=226 DHW=06.03 -i -s -d env - tools/juis_check --bpjm Version=154.07.25-80000 Name=FRITZ\!Box 7590 HW=226 OEM=avm Lang=de Country=049 -i -s -d env - tools/juis_check --info Version=84.06.87-92934 Name=FRITZ\!Box Fon WLAN 7390 HW=156 -i -s -d env - tools/juis_check --down HW=267 -i -s -d env - tools/juis_check Version=154.07.39-90000 Name=FRITZ\!Box 7590 HW=226 Buildtype=1001 Annex=B -i -s -d env - tools/juis_check Version=252.07.20 Name=FRITZ\!Box 6660 Cable HW=252 Flag=cable_retail Annex=Kabel -i -s -d env - tools/juis_check Version=29.04.87 HW=94 -i -s -d env - tools/juis_check Version=67 HW=137 -i -s -d env - tools/juis_check HW=156 -i -s -d env - tools/juis_check HW=259 -i -s -d for x in $(seq 150 300); do env - tools/juis_check HW=$x -a; done for x in $(seq 200 300); do env - tools/juis_check HW=$x Buildtype=1001 -a; done for x in $(seq 10 109); do [ ${#x} != 3 ] && x="0$x"; env - tools/juis_check --dect HW=259 DHW=${x::-1}.0${x:2} -a; done Or just: tools/juis m # f EOX exit } js() { [ -e "$1" ] && sed -rn "s/^<.:$2>(.*)<.*/\1/p" "$1" ; } main() { local x soap avmca url host sdir docsis flags Envelope body post cache info payload day ser local line='################################################################' local type='text/xml; charset="utf-8"' local zwsp="$(printf '\342\200\212')" #soap='SOAPAction: "http://jason.avm.de/updatecheck/BoxFirmwareUpdateCheck"' [ -z "$Nonce" ] && Nonce="$(dd if=/dev/urandom bs=16 count=1 2>/dev/null | base64)" [ -z "$UserAgent" ] && UserAgent="$(echo 'Box TestClient BoxInternetCheck' | sed 's/ /\n/g' | shuf | head -n1)" [ -z "$ManualRequest" ] && ManualRequest="$(echo 'true false' | sed 's/ /\n/g' | shuf | head -n1)" [ -z "$UpdateConfig" ] && UpdateConfig="$(echo '1 3' | sed 's/ /\n/g' | shuf | head -n1)" [ -z "$Provider" ] && Provider="$(echo 'null oma_ipclient oma_lan vodafone2_vdsl' | sed 's/ /\n/g' | shuf | head -n1 | grep -v '^null$')" [ "$Provider" == "empty" ] && Provider='' [ -z "$Serial" ] && while [ "${#Serial}" != "12" ]; do Serial="$(hexdump -n6 -e '/1 "%02X"' /dev/urandom | sed 's/[^0-9A-F]//g')"; done if [ "$BIX" != "n" ]; then [ -e '/var/juis_boxinfo.xml' ] && info='/var/juis_boxinfo.xml' [ -e '/var/jason_boxinfo.xml' ] && info='/var/jason_boxinfo.xml' fi [ -z "$Name" ] && Name="$(js $info 'Name')" [ -z "$HW" ] && HW="$(js $info 'HW')" case "$HW" in 175|176|182|187|213|220|231|233|252|267) docsis='y' ;; esac [ -z "$OEM" ] && OEM="$(js $info 'OEM')" [ -z "$OEM" ] && OEM="avm" [ -z "$Lang" ] && Lang="$(js $info 'Lang')" [ -z "$Lang" ] && Lang="de" [ -z "$Annex" ] && Annex="$(js $info 'Annex')" if [ -z "$Annex" ]; then [ -n "$docsis" ] && Annex="Kabel" || Annex="B" fi [ -z "$Country" ] && Country="$(js $info 'Country')" [ -z "$Country" ] && Country="049" [ -z "$Flag" ] && Flag="$(js $info 'Flag')" [ -z "$Buildtype" ] && Buildtype="$(js $info 'Buildtype')" if [ -z "$Buildtype" ]; then [ "$CHK" == "BoxFirmwareDowngradeCheck" ] && Buildtype="1000" || Buildtype="1" fi if [ -z "$Name" ]; then while [ "${#Name}" != "4" ]; do Name="$Name$(hexdump -n1 -e '/1 "%02X"' /dev/urandom | sed -rn 's/.*([0-9]).*/\1/p')"; done Name="FRITZ\!Box$zwsp$Name" fi if [ -z "$Version" ]; then Version="$(js $info 'Version')" if [ -n "$Version" ]; then Buildnumber="$(js $info 'Buildnumber')" [ -z "$Buildnumber" ] && Buildnumber="$(js $info 'Revision')" [ -n "$Buildnumber" ] && Version="$Version-$Buildnumber" fi if [ -z "$Version" ]; then if [ "$HW" -ge 150 2>/dev/null ]; then if [ "$HW" -lt 248 2>/dev/null ]; then Version="$(( $HW - 72 ))" else Version="$HW" fi fi fi fi Buildnumber="${Version#*-}" x="${Version%-*}" Major="${x%%.*}" x="${x#*.}" Minor="${x%.*}" Minor="${Minor#0}" Patch="${x#*.}" [ "$Buildnumber" == "$Version" ] && Buildnumber="00000" [ "$Minor" == "$x" ] && Minor="00" [ "$Patch" == "$x" ] && Patch="00" [ -z "$HW" ] && echo "You have to provide 'HW'." 1>&2 && exit 1 [ -z "$Version" ] && echo "You have to provide 'HW' and 'Version'." 1>&2 && exit 1 if [ "$SSL" == 'y' ]; then avmca="$MYPWD/avm-rootca.pem" [ -e "/etc/avm_root_ca.pem" ] && avmca="/etc/avm_root_ca.pem" [ -e "/etc/jasonii_root_ca.pem" ] && avmca="/etc/jasonii_root_ca.pem" host="jws.avm.de" # https-cert matches hostname else host="$HW.jws.avm.de" # no wirldcard certificate fi #old: /Jason/UpdateCheck sdir='/Jason/UpdateInfoService' Envelope='xmlns:e="http://juis.avm.de/updateinfo" xmlns:q="http://juis.avm.de/request">' if [ "$CHK" == "BoxMessageCheck" ]; then sdir='/Jason/MessageInfoService' Envelope='xmlns:e="http://juis.avm.de/messageinfo" xmlns:q="http://juis.avm.de/request" xmlns:s="http://juis.avm.de/response">' fi url="$host$sdir" if [ "$CHK" == "BPjMUpdateCheck" ]; then while [ "${#day}" != "1" ]; do day="$day$(hexdump -n4 -e '/1 "%02X"' /dev/urandom | sed -rn 's/.*([012]).*/\1/p')"; done while [ "${#day}" != "2" ]; do day="$day$(hexdump -n1 -e '/1 "%02X"' /dev/urandom | sed -rn 's/.*([0-9]).*/\1/p')"; done payload="$(( $(date +%Y%m) - 100 ))$day" fi if [ "$CHK" == "DeviceFirmwareUpdateCheck" ]; then [ -z "$DHW" ] && echo "For --dect you have to provide 'DHW'." 1>&2 && exit 1 [ -z "$DSW" ] && DSW="00.00" [ -z "$DTP" ] && DTP="1" while [ "${#ser}" != "12" ]; do ser="$ser$(hexdump -n1 -e '/1 "%02X"' /dev/urandom | sed -rn 's/.*([0-9]).*/\1/p')"; done payload=" $DTP $DHW $DSW $ser $Lang" fi if [ -n "$ProviderName" ]; then ProviderName=" $ProviderName" fi if [ -z "${Flag// /}" ]; then Flag="$(echo 'null mesh_master mesh_master_no_trusted mesh_repeater mesh_repeater_no_trusted' | sed 's/ /\n/g' | shuf | head -n1)" Flag="$Flag $(echo 'null medium_lan medium_dsl' | sed 's/ /\n/g' | shuf | head -n1)" Flag="$Flag $(echo 'null null crashreport myfritz_letsencrypt botnet_detection avm_acs prov_acs' | sed 's/ /\n/g' | shuf | head -n3)" [ -n "$docsis" ] && Flag="$Flag cable_retail" [ -z "${Flag// /}" ] && Flag='empty' fi for x in ${Flag//null/}; do flags="${x/empty/} $flags"; done flags="$(echo "$flags" | grep -v '^$')" body=$(cat << EOX $Nonce $UserAgent $ManualRequest ${Name//$zwsp/ } $HW $Major $Minor $Patch $Buildnumber $Buildtype $Serial $OEM $Lang $Country $Annex $flags $UpdateConfig $Provider$ProviderName$payload EOX ) post=$(cat << EOX POST /${url#*/} HTTP/1.1 Host: ${url%%/*}:80 Content-Length: ${#body} Content-Type: ${type} ${soap} ${body} EOX ) cache='/tmp/.juis_check' [ "$DEV" == 'i' -o "$DEV" == 'a' ] && cache='/dev/null' if [ "$SSL" == 'y' ]; then resp="$(curl -s -X POST -H "${type}" ${soap:+-H $soap} -d "${body}" "https://${url}" --cacert "${avmca}" \ | tee $cache | sed 's,><,>\n<,g' | sed 's,$//g')" else resp="$(echo -e "${post}" | nc ${url%%/*} 80 2>/dev/null \ | tee $cache | sed 's,><,>\n<,g' | sed 's,$//g')" fi [ -z "$resp" ] && echo 'Did not received an anser.' 1>&2 && exit 1 case "$DEV" in a) URL="$(echo "$resp" | sed -n "s/^//p")" [ -n "$URL" ] && ( [ "$CHK" == "DeviceFirmwareUpdateCheck" ] && echo "$DHW=$URL" || echo "$HW=$URL" ) ;; i) URL="$(echo "$resp" | sed -n "s/^//p")" [ -n "$URL" ] && echo "URL=$URL" ;; s) VER="$(echo "$resp" | sed -n "s/^//p")" [ -n "$VER" -a "$VER" != "$Version" ] && echo "Found newer version: $VER" 1>&2 || echo "No newer version found." 1>&2 ;; *) echo -e "Using SSL:=${SSL:-n}\n\nRequest:\n$line" [ "$SSL" == 'y' ] && echo -ne "$body" || echo -ne "$post" echo -e "\n$line\n\nResponse:\n$line" if command -v xmllint &>/dev/null; then grep '^<' -v "$cache" grep '^<' "$cache" | xmllint --format - else echo "$resp" fi echo -e "$line\n" rm "$cache" ;; esac } DEV='' SSL='' BIX='' CHK='BoxFirmwareUpdateCheck' args() { [ "${#*}" == '0' ] && help local DEVA DEVI DEVS DEVD for x in $*; do l="${x%=*}" r="${x#*=}" [ "$x" == '-a' ] && DEVA='x' [ "$x" == '-i' ] && DEVI='x' [ "$x" == '-s' ] && DEVS='x' [ "$x" == '-d' ] && DEVD='x' [ "$x" == '--nofb' ] && BIX='n' [ "$x" == '--down' ] && CHK='BoxFirmwareDowngradeCheck' [ "$x" == '--info' ] && CHK='BoxMessageCheck' [ "$x" == '--bpjm' ] && CHK='BPjMUpdateCheck' [ "$x" == '--dect' ] && CHK='DeviceFirmwareUpdateCheck' [ "$x" == '--plain' ] && SSL='n' [ "$x" == '--https' ] && SSL='y' [ "$x" == "$l" ] && continue eval $l="$r" done [ -n "$DEVA" ] && DEV='a' [ -n "$DEVI" ] && DEV='i' [ -n "$DEVS" ] && DEV='s' [ -n "$DEVD" ] && DEV='d' [ "$SSL" == 'y' ] && [ -z "$(command -v curl)" ] && echo 'Curl is mandatory for https.' 1>&2 && exit 1 if [ -z "$SSL" ]; then command -v curl >/dev/null && SSL='y' || SSL='n' if [ -e '/etc/.freetz-ng-version' ]; then grep -q "^FREETZ_ADD_JUIS_CHECK__SSL='y'" /etc/options.cfg 2>/dev/null || SSL='n' fi fi } args "$@" main