Automatically reboot TP-Link router WDR4300 / N750 with bash script

I wanted to reboot some TP-Link WDR4300 routers automatically, because the TP-Link firmware is rather buggy and often causes WLAN problems after a few days of use.
Sadly, rebooting those routers with current firmwares is not quite as easy as it used to be (simple and short one-line curl call). You first have to generate a cookie with the name ‘Authorization’ and value

urlencode(Basic base64($admin:md5($password)))

(pseudocode). And then you have to extract some kind of one-time key from the post-login page to get the actual HTTP address of the reboot page (http://$IP/$KEY/userRpm/SysRebootRpm.htm?Reboot=Reboot ). Did I mention you also have to set your HTTP referer to the reboot page?

Here is a bash script that automates all that and takes three arguments (IP, username, password). Note that you have to actively click “Logout” after doing something in the web interface, otherwise this script does not seem to work:

#!/bin/bash

# Reboot TP Link router on modern firmware (tested only on WDR4300/N750)
# Author: Nicolai Spohrer <nicolai@xeve.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.

if [ "$#" -ne 3 ]; then
    echo "Illegal number of parameters";
    echo "Usage: $0 ROUTER_IP USERNAME PASSWORD";
    exit;
fi

IP=$1;
USERNAME=$2;
PASSWORD=$3;


MAX_TRIES=6; # maximum number of reboot attempts
SYSLOG_TAG="restart-wdr4300.sh"

# From https://stackoverflow.com/questions/296536/urlencode-from-a-bash-script/10660730#10660730
rawurlencode() {
  local string="${1}"
  local strlen=${#string}
  local encoded=""

  for (( pos=0 ; pos<strlen ; pos++ )); do
     c=${string:$pos:1}
     case "$c" in
        [-_.~a-zA-Z0-9] ) o="${c}" ;;
        * )               printf -v o '%%%02x' "'$c"
     esac
     encoded+="${o}"
  done
  echo "${encoded}"    # You can either set a return variable (FASTER) 
  REPLY="${encoded}"   #+or echo the result (EASIER)... or both... :p
}

PASSWORD_MD5=`echo -n $PASSWORD | md5sum | cut -d " " -f 1`;
COOKIE_B64_PART=`echo -n $USERNAME":"$(echo -n $PASSWORD_MD5)|base64`;
COOKIEVAL_UNENCODED=`echo -n "Basic $COOKIE_B64_PART"`;
COOKIEVAL=`rawurlencode "$COOKIEVAL_UNENCODED"`

GET_KEY_URL=`echo "http://$IP/userRpm/LoginRpm.htm?Save=Save"`


# If the reboot sequence fails, try again $MAX_TRIES times
for i in $(seq 1 $MAX_TRIES)
do

  RESPONSE=`curl -s --cookie "Authorization=$COOKIEVAL" $GET_KEY_URL`;
  KEY=`echo $RESPONSE |  head -n 1 | cut -d '/' -f 4` # extract key from post-login-page

  sleep 1;

  REBOOT_URL="http://"$IP"/"$KEY"/userRpm/SysRebootRpm.htm?Reboot=Reboot";
  REBOOT_REFERER_URL="http://"$IP"/"$KEY"/userRpm/SysRebootRpm.htm";

  FINAL_RESPONSE=`curl -s --cookie "Authorization=$COOKIEVAL" --referer $REBOOT_REFERER_URL $REBOOT_URL`;

  MATCHES=`echo $FINAL_RESPONSE | grep -c "Restarting..."`
  if [ $MATCHES -gt 0 ]; then
    # Success!
    break
  else
    echo "Failed on try $i..."
    sleep 1;
  fi
done

if [ $MATCHES -gt 0 ]; then
  SUCCESS_TEXT="Successfully triggered reboot of $IP.";
  echo $SUCCESS_TEXT;
  logger -t $SYSLOG_TAG $SUCCESS_TEXT;
else
  FAILURE_TEXT="Apparently failed to trigger reboot of $IP.";
  echo $FAILURE_TEXT;
  logger -t $SYSLOG_TAG $FAILURE_TEXT;

  # Log failure details
  MYRAND=$RANDOM;
  MYFILES="/tmp/reboot-failure-$MYRAND";
  echo $RESPONSE > "$MYFILES-response1"
  echo $FINAL_RESPONSE > "$MYFILES-finalresponse"

  exit 1;
fi

Update 11 February, 2015:

Added delay and rudimentary check whether reboot attempt was successful.

Update 15 February, 2015:

Added option to try multiple times if the reboot attempt fails (default: 6 times).

29 comments

  • ray

    Thanks a lot for sharing this! Saved me a lot of time to figure this out. Now I can use this to auto reboot when my IP cams get disconnected (indeed I also suffer from wlan problems after a few days)

  • Leigh Wiltshire

    I’m trying to build an automated tool to allow non-technical users to check link status on a TP-Link load balancing router. I know I can use curl to do this, but I’m having the same problems with authentication. My problem is that the solution will need to run on a windows PC. Any ideas on how to modify this script to work from a windows command prompt?

    • nspo

      Although it is possible to install bash, curl etc. on Windows, the better way with less overhead would be just to (re)write everything in the language that you are using for your application. Pretty much any programming or scripting language should have tools for making HTTP requests and string manipulation.

  • Giacomo

    I’ve tried this on the TD-W8968 but it isn’t working. Is there something I can do to adapt this script to this router?

    Thanks!!!

  • Gary

    Works great on my TP-Link Archer C7. The ability to reboot a router on a schedule should be a default setting in the router. Need this to be able to update my ddns with noip.com, which only seems to happen with a reboot.

  • Pieter

    This bash file doesn’t seem to work with updated firmware. Tried to use it from an RPI system.
    Firmware Version:
    3.14.3 Build 150518 Rel.70901n
    Hardware Version:
    WDR4300 v1 00000000

  • Tin Ho

    I successfully tested the script on TP-LINK Archer C7 V2. Thanks very much for the effort made!

  • stempelo

    Thanks!!! Tp-link WR841N
    🙂 N1

  • JULIO PAVEI FURLANETTO

    im running on cygwin and I het errors on lines 2, 10 and 26 saying “$’\r’: command not found”
    can you guys help me?

  • JULIO PAVEI FURLANETTO

    realized i was not using EOL conversiion on notepad++, sorry

  • siosios

    works perfectly on my tp-link TL-WA801ND, thanks

  • Marco

    Thank you very much. The script works perfectly with Tp-Link TL-MR6400.

    • L4unch3r

      Hi Marco. May you help me to run this script? Where I have to put the values and what exactly I have to do (I’m really basic).
      Thank you very much.

  • L4uncher

    How exactly I have to run this script? Where can I put my values (user, password and IP)? I only know that to execute I have to do chmod +x but nothing else.

    • Nicolai

      As you can see when you execute the script, you have to append the parameters to the file name: (filename) ROUTER_IP USERNAME PASSWORD. If you still do not understand that, you should probably google ‘execute bash script tutorial’.

      • L4uncher

        Thank you. Now I understand (never used a bash script with arguments). May you tell me if the procedure is correct?
        Using Debian, for example, open Terminal
        1. Execute the script doing “bash script.sh IP user pass”
        2. With the same machine browser, login to the router, do something such as change some option, then logout
        3. In the Terminal should appear the token

        Sorry if I ask you this but I cannot verify this at the moment.

        • Nicolai

          You’re welcome. Step 2 and 3 should not be necessary – just executing the bash script should make the router reboot (if the script works with your model).

          • L4uncher

            Thank you Nicolai; unfortunately it doesn’t seem to be compatible with my routers Archer C2 and WDR3600; it tries to do the 6 tries and reports me this log error “line 43: md5sum: command not found” probably because of it isn’t capable to convert the URL where the password is (I think).

  • L4uncher

    Where I have to put IP user and password in the script?

    • Nicolai

      Just pass them as parameters. C.f. my other reply to this post today

    • Nicolai

      Sounds like you need to install the md5sum utility. Just google how to do that for your Linux distribution

      • L4uncher

        OK, now it says successfully triggered reboot (only for WDR3600 not Archer C2 unfortunately), really thanks Nicolai. One last question: how can I retrive the token generated to use it for Archer C2 and the curl –referer method?

      • L4uncher

        Probably it’s possible to adapt the script modifying the URL parameters; for example the Archer model has this pattern “http://$IP/MenuRpm.htm#__restart.htm” for Reboot instead of “http://”$IP”/”$KEY”/userRpm/SysRebootRpm.htm?Reboot=Reboot”

  • VPN Stuck

    Simply use:
    curl –user username:password –referer http://192.168.1.1 http://192.168.1.1/userRpm/SysRebootRpm.htm?Reboot=Reboot > /dev/null

  • Harald H

    Great script, thanks a lot! Works for a MR3420 v3 🙂
    @VPN Stuck: this simple solution does not work as it doesn’t set the mandatory cookie and it doesn’t submit the key inside the link.

Leave a Reply

Your email address will not be published. Required fields are marked *