В роутер tp link скрипт

Как оказалось, в гигабитном роутере TP-LINK TL-WR1042ND нет управления при помощи консоли. Но роутеры, как известно, иногда виснут. Точнее, сам роутер продолжает работать и откликаться на команды управления из админки и VPN показывает, что он подключен, но интернет при этом не доступен. Иногда это происходит по вине самого устройства, иногда проблемы со стороны провайдера, и перезагрузка часто решает проблему. При чем, желательно, чтобы это происходило автоматически. Поэтому было принято решение перегружать роутер при помощи HTTP GET запроса…

После непродолжительного исследования были найдены такие команды:

Разорвать VPN соединение:

http://login:pass@192.168.0.1/userRpm/StatusRpm.htm?Disconnect=Disconnect&wan=1

Подключить VPN:

http://login:pass@192.168.0.1/userRpm/StatusRpm.htm?Connect=Connect&wan=1

Перезагрузить роутер:

http://login:pass@192.168.0.1/userRpm/SysRebootRpm.htm?Reboot=1

Но, как оказалось, управлять этими командами роутером напрямую не получается. Они работают только при авторизации в админке роутера через браузер и то только можно увидеть их выполнение с помощью firebug, а напрямую, при вводе в адресную строку работает только команды дисконнекта/коннекта VPN. Команды срабатывают, но при этом все равно выдается ошибка. Перезагрузить роутер таким образом не получается.

Мгновенно выскакивает «You have no authority to access this router!» и ничего не происходит.

Самое интересное, что так:

http://login:pass@192.168.0.1/userRpm/StatusRpm.htm?Disconnect=Disconnect&wan=1

выдает ту же ошибку, но с некоторой задержкой, а запрос выполняется — т.е. wan отключается.

При этом в админку входит по ссылке с прописанной авторизацией: http://login:pass@192.168.0.1 и управление из админки дальше работает!

Перезагрузка из Linux

Меня больше интересовала перезагрузка из линукса, но такая команда не срабатывала:

wget --http-user=login --http-password=pass --post-data="reboot=true" http://192.168.0.1/userRpm/SysRebootRpm.htm

ошибка:

Connecting to 192.168.0.1:80... connected.
HTTP request sent, awaiting response... 401 N/A
Reusing existing connection to 192.168.0.1:80.
HTTP request sent, awaiting response... 200 No headers, assuming HTTP/0.9
Length: unspecified
Saving to: `SysRebootRpm.htm'

К тому же, при помощи wget не удавалось даже выполнить Disconnect/Connect VPN.

На русском форуме TP-LINK была открыта тема, но в результате обсуждения, решения найти не удалось.
Английская техподдержка на запрос «How i can reboot my device by bash script?»
ответила следующее: «this is not possible to reboot devices in a such way».
Ticket#2013101610000131

Решение все же было найдено. Не вдаваясь в подробности скажу что роутер при GET запросе проверяет:

  1. Http basic авторизацию.
  2. User-Agent браузера.
  3. Корректное поле рефер, которое всегда будет просто http://IP адресом роутера, т.к. роутер использует редиректы.

Cookie для авторизации не используются.

С этим всем отлично справляется команда curl.

Скрипт перезагрузки роутера

Итак, привожу скрипт перезагрузки роутера, который у меня получился:

#!/bin/sh
WATCHED_IP="8.8.8.8"
ROUTER_IP="192.168.0.1"
USERNAME="login"
PASSWORD="pass"

# watch for remote host
ping -q -c 1 "$WATCHED_IP" > /dev/null && exit

# exit if router is down
ping -q -c 1 "$ROUTER_IP" > /dev/null || exit

curl --basic --user "$USERNAME:$PASSWORD" -A "Mozilla/4.73 [en] (X11; U; Linux 2.2.15 i686)" --refer "http://$ROUTER_IP" "$ROUTER_IP/userRpm/SysRebootRpm.htm?Reboot=reboot"

Соответственно, скрипт реконнекта VPN:

#!/bin/sh
WATCHED_IP="8.8.8.8"
ROUTER_IP="192.168.0.1"
USERNAME="login"
PASSWORD="pass"

# watch for remote host
ping -q -c 1 "$WATCHED_IP" > /dev/null && exit

# exit if router is down
ping -q -c 1 "$ROUTER_IP" > /dev/null || exit

curl --basic --user "$USERNAME:$PASSWORD" -A "Mozilla/4.73 [en] (X11; U; Linux 2.2.15 i686)" --refer "http://$ROUTER_IP" "$ROUTER_IP/userRpm/StatusRpm.htm?Disconnect=Disconnect&wan=1"
#sleep 1
curl --basic --user "$USERNAME:$PASSWORD" -A "Mozilla/4.73 [en] (X11; U; Linux 2.2.15 i686)" --refer "http://$ROUTER_IP" "$ROUTER_IP/userRpm/StatusRpm.htm?Connect=Connect&wan=1"

Поставил в cron скрипт реконнекта при отсутствии пинга dns гугля — проверка каждые 3 минуты.
Скрипт перезагрузки проверяет наличие интернета каждые 15 минут.

login:pass, конечно, нужно будет поставить свои. Файлы скриптов назвать, например, tplink_reboot.sh и tplink_reconnect.sh, сохранить на сервере, дать права на выполнение и добавить в планировщик.

Уже пару раз выручило:
tplink_reconnect.zip
tplink_reboot.zip


PS:
на форуме https://forum.tp-linkru.ru Scorokhod поделился своим вариантом перезагрузки роутера при помощи WGET, за что ему огромное спасибо:

wget --http-user=%login% --http-password=%password% --user-agent="Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36" --referer=http://%router_ip%/userRpm/SysRebootRpm.htm http://%router_ip%/userRpm/SysRebootRpm.htm?Reboot=1

Вместо «login», «password» и «router_ip» подставить соответственно логин, пароль и IP маршрутизатора без кавычек и процентов :-)

WGET для Windows можно взять здесь: http://gnuwin32.sourceforge.net/packages/wget.htm, качать нужно «Complete package, except sources — Setup».

Перезагрузка из Windows

Готовая сборка Wget + Bat скрипт для перезагрузки (только перегружает):
скачать tplink_reboot_wget.zip (подходит для большинства моделей Tplink, не только WR1042ND)

Перезагрузка из Android

(спасибо за этот код neolead)

Для андроид в данном изложении требуется root. Если нет рута.. то в конце checknet заменить на step1

—manual
Requirements:

Установить Busybox https://play.google.com/store/apps/deta … on.busybox
и Android Terminal emulator https://play.google.com/store/apps/deta … ndroidterm
—to do list
Перемонтировать/system на запись «su -c mount rw,remount /system»
Поместить допустим в /system/script,»su -c chmod 0777 /system/script/»
Дать скрипту права на исполнение «su -c chmod 0755 /system/script/ping2.sh»
Добавить в автозапуск в настройках терминала.

у меня работает в машине как переподключение,затем перезагрузка wifi после трёх фейлов…

-----ping2.sh
#!/system/bin/sh
pingip=8.8.8.8
login=admin #Username
password=admin #Password
router_ip=192.168.0.1 #Ip of router
sleep_time=30 #Time to next check
sleep_rbt_time=70 #Time to waiting of reboot
f1=10 #First pause in sec
f2=30 #Second pause in sec
increment=0
b64_auth=$(echo $login:$password | base64|rev|cut -c 2-|rev)
network=toyota #SSID name of wifi

while true
do

function checknet()
{
ssid=0
while [ "$ssid" != "$network" ]
do
ssid=$(su -c dumpsys wifi|grep "* ID:"|cut -f 2 -d \")
echo ssid=$ssid
echo network=$network
if [ "$ssid" = "$network" ]; then
echo "Correct Wifi Network"
else
echo "False Wifi Network,press Enter key"
read -rs
fi
done
}

function slp()

{
increment=0
echo "will sleep $sleep_time sec"
sleep $sleep_time #check again
}

function wifi_conn()
{
echo modem reconnect
printf "GET /userRpm/StatusRpm.htm?Disconnect=Disconnect&wan=1 HTTP/1.0\r\nReferer: http://$router_ip/userRpm/StatusRpm.htm\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.1.1650.63 Safari/537.36\r\nAccept: */*\r\nHost: $router_ip\r\nConnection: Keep-Alive\r\nAuthorization: Basic $b64_auth=\r\n\r\n"|nc -w 5 -i 1 $router_ip 80 >/dev/nul
printf "GET /userRpm/StatusRpm.htm?Connect=Connect&wan=1 HTTP/1.0\r\nReferer: http://$router_ip/userRpm/StatusRpm.htm\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.1.1650.63 Safari/537.36\r\nAccept: */*\r\nHost: $router_ip\r\nConnection: Keep-Alive\r\nAuthorization: Basic $b64_auth=\r\n\r\n"|nc -w 5 -i 1 $router_ip 80 >/dev/nul
}

function wifi_rst()
{
#echo LOGIN:$b64_auth=
increment=$(( $increment +1 ))
echo Reboot Times=$increment

if [ "$increment" -eq 3 ]; then
echo "We Already Reboot = $increment times"
echo "We Stop Rebooting"
read -rs $'Press any key to continue monitoring...\n' -n1 key
else
printf "GET /userRpm/SysRebootRpm.htm?Reboot=1 HTTP/1.0\r\nReferer: http://$router_ip/userRpm/SysRebootRpm.htm\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.1.1650.63 Safari/537.36\r\nAccept: */*\r\nHost: $router_ip\r\nConnection: Keep-Alive\r\nAuthorization: Basic $b64_auth=\r\n\r\n"|nc -w 5 -i 1 $router_ip 80 >/dev/nul
echo "Now reboot request was send,will sleep $sleep_rbt_time sec"
sleep $sleep_rbt_time
fi
}
checknet

if ping -c 1 $pingip >/dev/null
then
echo "all good step 1"
slp
else
if ping -c 1 $router_ip >/dev/null
then
echo Router is pinging - channel is down
else
echo Router is down - channel is down
increment = 3
wifi_rst
fi
echo Bad Ass step 1 - will wait $f1 sec!
sleep $f1 #give it a few seconds to complete
fi

if ping -c 1 $pingip >/dev/null
then
echo "all good step 2"
slp
else
echo Bad Ass step 2 - will wait $f2 sec!
sleep $f2 #give it a few seconds to complete
fi

if ping -c 1 $pingip >/dev/null
then
echo "all good step 3 "
slp
else
wifi_conn
echo Bad Ass step 3 - Reconnect!
wifi_conn
fi

if ping -c 1 $pingip >/dev/null
then
echo "all good step 4 "
slp
else
echo Bad Ass step 3 - Reconnect!
wifi_rst
fi
done

Скетч Arduino для плат на базе микроконтроллера ESP32

(спасибо за этот код p-a-h-a)


#include <WiFi.h> 
#include <HTTPClient.h>
const char* IP_port = "http:// 192. 168. 0.1:80"; // Убрать пробелы, заменить на свой адрес
#define RouterLogin "admin"
#define RouterPassword "admin"
void setup() {
  Serial.begin(115200);
  WiFi.begin("ssid", "pass");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500); Serial.print(".");
  }
    HTTPClient http;
    http.begin(String(IP_port) + "/userRpm/SysRebootRpm.htm?Reboot=1");
    http.setAuthorization(RouterLogin, RouterPassword);
    http.addHeader("User-Agent","ESP32 wrower");
    http.addHeader("Referer", String(IP_port) + "/userRpm/SysRebootRpm.htm");
    Serial.printf("[HTTP] GET...code: %d\n", http.GET());
//    Serial.println(http.getString()); // Выдаст вебстраничку ответа 
    http.end();
}
  void loop() {}

Время на прочтение
11 мин

Количество просмотров 33K

Однажды передо мной встала задача реализации программного управления одним из распространенных домашних Wi-Fi маршрутизаторов TP-Link TL-WR841N, у которого, к сожалению, нет интерфейса управления через командную строку (telnet, SSH). Я хотел, чтобы мой Telegram бот, реализованный на Python на базе SBC в локальной домашней сети, на основе моих команд выполнял следующие функции управления маршрутизатором:

  • Перезагрузка маршрутизатора
  • Открытие/закрытие NAT Port Forwarding к внутренним WEB-сервисам
  • Открытие/закрытие удаленного доступа к маршрутизатору из WAN (интернет)
  • Определение устройств, зарегистрированных в локальной WiFi сети маршрутизатора

Конечно, все это пользователь может выполнять и сам вручную с помощью WEB-интерфейса, но, во-первых, мне хотелось автоматизировать эти функции, во-вторых, иногда это нужно делать удаленно, а я не хотел постоянно держать открытым доступ к управлению маршрутизатором по незашифрованному HTTP через интернет по соображениям безопасности. Управление с помощью «закрытого» Telegram бота мне показалось более надежным.

Для доступа к управлению маршрутизатором я использовал единственный доступный интерфейс — пользовательский WEB-интерфейс, взаимодействие с которым реализовал с помощью HTTP запросов Python requests. Для того, чтобы определить, какие HTTP GET запросы необходимо направлять на маршрутизатор, я использовал всем известный сниффер трафика Wireshark. Проще говоря, я с помощью Python requests воспроизвел те запросы, которые увидел в Wireshark, в необходимой последовательности.

Импорт, авторизация и исходные параметры

Итак, прежде всего импортируем в Python библиотеку requests, на базе которой мы будем реализовывать HTTP запросы.

import requests

В качестве исходных параметров укажем внутренний IP адрес маршрутизатора в виде строки HTTP запроса. В моем случае это 192.168.0.1.

router_ip='http://192.168.0.1'

Для авторизации нам понадобится токен, вычисление которого осуществляется на основе логина и пароля пользователя. Функция вычисления токена задана в JS скрипте на маршрутизаторе 192.168.0.1/login/encrypt.js. Выглядит он вот так.

encrypt.js

function hex_md5(s)
{ 
	return binl2hex(core_md5(str2binl(s), s.length * 8));
}

function core_md5(x, len)
{
  /* append padding */
  x[len >> 5] |= 0x80 << ((len) % 32);
  x[(((len + 64) >>> 9) << 4) + 14] = len;

  var a =  1732584193;
  var b = -271733879;
  var c = -1732584194;
  var d =  271733878;

  for(var i = 0; i < x.length; i += 16)
  {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;

    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
  }
  return Array(a, b, c, d);

}

function md5_cmn(q, a, b, x, s, t)
{
  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
  return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y)
{
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}

function bit_rol(num, cnt)
{
  return (num << cnt) | (num >>> (32 - cnt));
}

function str2binl(str)
{
  var bin = Array();
  var mask = (1 << 8) - 1;
  for(var i = 0; i < str.length * 8; i += 8)
    bin[i>>5] |= (str.charCodeAt(i / 8) & mask) << (i%32);
  return bin;
}

function binl2hex(binarray)
{
  var hex_tab = "0123456789abcdef";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i++)
  {
    str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
           hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
  }
  return str;
}

function Base64Encoding(input) 
{
	var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
	var output = "";
	var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
	var i = 0;

	//input = utf8_encode(input);

	while (i < input.length) 
	{

		chr1 = input.charCodeAt(i++);
		chr2 = input.charCodeAt(i++);
		chr3 = input.charCodeAt(i++);

		enc1 = chr1 >> 2;
		enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
		enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
		enc4 = chr3 & 63;

		if (isNaN(chr2)) {
			enc3 = enc4 = 64;
		} else if (isNaN(chr3)) {
			enc4 = 64;
		}

		output = output +
		keyStr.charAt(enc1) + keyStr.charAt(enc2) +
		keyStr.charAt(enc3) + keyStr.charAt(enc4);

	}
 
	return output;
}

function utf8_encode (string) 
{
	string = string.replace(/\r\n/g,"\n");
	var utftext = "";

	for (var n = 0; n < string.length; n++) {

		var c = string.charCodeAt(n);

		if (c < 128) {
			utftext += String.fromCharCode(c);
		}
		else if((c > 127) && (c < 2048)) {
			utftext += String.fromCharCode((c >> 6) | 192);
			utftext += String.fromCharCode((c & 63) | 128);
		}
		else {
			utftext += String.fromCharCode((c >> 12) | 224);
			utftext += String.fromCharCode(((c >> 6) & 63) | 128);
			utftext += String.fromCharCode((c & 63) | 128);
		}

	}

	return utftext;
}

Но, признаюсь, я не стал портировать эту функцию из JS в Python. Я упростил подход и посмотрел значение параметра, которое отправляет мой браузер в Wireshark.

Выделенный запрос — это запрос авторизации, который мы воспроизведем чуть позже. Таким образом, я скопировал параметр Cookie pair в запросе авторизации

auth_token='Authorization=Basic%20YWRtaW46YjAxYzZmYzYyMDgwMzA5Y2ZiMzc2ZTE4NzI3YzMwNzk%3D'

Пожалуй, это не самый изящный, но простой подход. Кроме того, мы не будем хранить логин и пароль от маршрутизатора в текстовом открытом виде, что, на мой взгляд, не так плохо.

Перейдем к функции авторизации.

def login():
    r = requests.get(router_ip+'/userRpm/LoginRpm.htm?Save=Save',headers={'Referer':router_ip+'/','Cookie': auth_token})

    if r.status_code==200:
        x=1
        while x<3:
            try:
                session_id=r.text[r.text.index(router_ip)+len(router_ip)+1:r.text.index('userRpm')-1]
                return session_id
                break
            except ValueError:
                return 'Login error'
            x+=1
    else:
        return 'IP unreachable'

Цикл while я использовал, так как маршрутизатор не всегда авторизовывал моего бота с первого раза. Возможно, у вас получится обойтись без него.

В случае успешной авторизации функция возвращает значение session_id. Это идентификатор сессии, который генерирует маршрутизатор при авторизации. После прохождения авторизации session_id должен присутствовать во всех последующих HTTP запросах к маршрутизатору.

Далее реализуем функцию выхода logout.

def logout(session_id):
    r = requests.get(router_ip+'/'+session_id+'/userRpm/LogoutRpm.htm',headers={'Referer':router_ip+'/'+session_id+'/userRpm/MenuRpm.htm','Cookie': auth_token})  
    if r.status_code==200:
        return 'Loging out: '+str(r.status_code)
    else:
        return 'Unable to logout''

Я делаю logout после каждой операции, так как маршрутизатор позволяет одновременно подключаться только одному пользователю. Поэтому, если ваш бот авторизуется и не выйдет из маршрутизатора, то вы не сможете на него зайти до тех пор, пока маршрутизатор не закроет открытую сессию по таймауту через несколько минут. Таким образом, я решил строго придерживаться последовательности «login -> операция -> logout».

Кстати, стоит учесть, что, если кто-то уже авторизован на маршрутизаторе, то бот, очевидно, не сможет авторизоваться до тех пор, пока пользователь не сделает logout, или активная сессия не закроется по таймауту. Одним словом, «кто первый встал, того и тапки.» Стоит отметить, что Python бот выполняет операции управления маршрутизатором за доли секунд. Таким образом, ваш маршрутизатор не будет занят ботом в течении продолжительного времени.

Перезагрузка, NAP Port Forwarding

Перейдем к операциям, которые мы можем выполнять после успешной авторизации.

#Перезагрузка
r = requests.get(router_ip+'/'+session+'/userRpm/SysRebootRpm.htm?Reboot=%D0%9F%D0%B5%D1%80%D0%B5%D0%B7%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%B8%D1%82%D1%8C',headers={'Referer':router_ip+'/'+session+'/userRpm/SysRebootRpm.htm','Cookie': auth_token})

#Открыть Port Forwarding
r = requests.get(router_ip+'/'+session+'/userRpm/VirtualServerRpm.htm?doAll=EnAll&Page=1',headers={'Referer':router_ip+'/'+session+'/userRpm/VirtualServerRpm.htm','Cookie': auth_token})

#Закрыть Port Forwarding
r = requests.get(router_ip+'/'+session+'/userRpm/VirtualServerRpm.htm?doAll=DisAll&Page=1',headers={'Referer':router_ip+'/'+session+'/userRpm/VirtualServerRpm.htm','Cookie': auth_token})

Здесь я бы хотел подчеркнуть, что указанные запросы активируют/деактивируют

все правила

Port Forwarding, созданные ранее в соответствующем разделе управления маршрутизатором.

Проще говоря, запросы аналогичны нажатию кнопок «Включить все» и «Отключить все». По аналогии можно реализовать и создание/активацию отдельных правил.

Удаленный доступ к маршрутизатору из WAN (интернет)

#Задание IP адреса удаленного управления
r = requests.get(router_ip+'/'+session+'/userRpm/ManageControlRpm.htm?port=5110&ip='+remote_ip+'&Save=%D0%A1%D0%BE%D1%85%D1%80%D0%B0%D0%BD%D0%B8%D1%82%D1%8C',headers={'Referer':router_ip+'/'+session+'/userRpm/SysRebootRpm.htm','Cookie': auth_token})

Здесь параметр remote_ip задает IP-адрес удаленного управления, т.е. тот IP адрес, с которого разрешено удаленно заходить на маршрутизатор через интернет.

remote_ip=’255.255.255.255’ #открыто для всех.
remote_ip=’0.0.0.0’ #закрыто для всех.

При желании можно указывать конкретный IP адрес, с которого вы хотите удаленно подключиться к маршрутизатору.

Определение списка подключенных устройств

#Определение подключенных устройств

r = requests.get(router_ip+'/'+session+'/userRpm/WlanStationRpm.htm',headers={'Referer':router_ip+'/'+session+'/userRpm/MenuRpm.htm','Cookie': auth_token})

presence='Дома находятся:'
if 'DC-31-54-97-51-06' in r.text:
            presence=presence+'\n'+'DC-31-54-97-51-06'

Для чего нужен функционал определения устройств, зарегистрированных в домашней сети WiFi. Допустим, у меня есть смартфон с WiFi и MAC адресом DC-31-54-97-51-06. Когда я прихожу домой, мой смартфон регистрируется в домашней сети WiFi. Таким нехитрым способом я могу отслеживать свое присутствие (а точнее, присутствие своего смартфона) в домашней сети (т.е. дома). Этот функционал позволяет автоматизировать ряд функций, связанных с определением моего присутствия. Например, когда я прихожу домой, отключается детектор движения камеры наблюдения и т.д. Ранее я использовал определение присутствия устройств в сети с помощью Ping’а их IP адресов, но в итоге разочаровался в данном методе, так как смартфоны, как оказалось, неохотно и не всегда отвечают на Ping. Дополнительно я использую сниффер ARP пакетов, реализованный на Python, который позволяет отследить момент регистрации устройства с определенным MAC адресом в сети WiFi.

Итак, r.text в коде выше возвращает среди прочего список MAC адресов устройств, зарегистрированных в WiFi сети маршрутизатора. Что вы будете делать с этим списком, зависит только от вашей фантазии.

var hostList = new Array(
"94-36-44-8F-2F-ED", 5, 23487, 10618, 2, 
"60-46-37-C0-43-FC", 5, 27088, 10126, 2, 
"EF-71-44-63-51-E1", 5, 600, 364, 2, 
"77-25-9D-99-ED-33", 5, 1547, 1722, 2, 
0,0 );

Итак, мне остается только подытожить. Весь код выглядит следующим образом.

router.py

import requests

router_ip='http://192.168.0.1'
auth_token='Authorization=Basic%20YWRtaW46YjAxYzZmYzYyMDgwMzA5Y2ZiMzc2ZTE4NzI3YzMwNzk%3D'

def logout(session_id):
    r = requests.get(router_ip+'/'+session_id+'/userRpm/LogoutRpm.htm',headers={'Referer':router_ip+'/'+session_id+'/userRpm/MenuRpm.htm','Cookie': auth_token})  
    if r.status_code==200:
        return 'Loging out: '+str(r.status_code)
    else:
        return 'Unnable to logout'

def login():

    r = requests.get(router_ip+'/userRpm/LoginRpm.htm?Save=Save',headers={'Referer':router_ip+'/','Cookie': auth_token})

    if r.status_code==200:
        x=1
        while x<3:
            try:
                session_id=r.text[r.text.index(router_ip)+len(router_ip)+1:r.text.index('userRpm')-1]
                return session_id
                break

            except ValueError:
                return 'Login error'
            
            x+=1
    else:
        return 'IP unreachable'

def routercontrol(operation,remote_ip='255.255.255.255'):
 
        #Авторизация

    if login()=='IP unreachable' or login()=='Login error':
        return login()
        exit(0)

    else:
        session=login()
        print ('Login OK: '+session)
 
    if operation=='Enable ports': 

        #Открыть Port Forwarding
        r = requests.get(router_ip+'/'+session+'/userRpm/VirtualServerRpm.htm?doAll=EnAll&Page=1',headers={'Referer':router_ip+'/'+session+'/userRpm/VirtualServerRpm.htm','Cookie': auth_token})
        status=str(r.status_code)
        print (logout(session))
        return 'Enable all ports: '+status+' http://31.207.73.10:8082'
 
    elif operation=='Disable ports':

        #Закрыть Port Forwarding
        r = requests.get(router_ip+'/'+session+'/userRpm/VirtualServerRpm.htm?doAll=DisAll&Page=1',headers={'Referer':router_ip+'/'+session+'/userRpm/VirtualServerRpm.htm','Cookie': auth_token})
        status=str(r.status_code)
        print (logout(session))
        return 'Disable all ports: '+status
 
    elif operation=='Reboot':

        #Перезагрузка
        r = requests.get(router_ip+'/'+session+'/userRpm/SysRebootRpm.htm?Reboot=%D0%9F%D0%B5%D1%80%D0%B5%D0%B7%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%B8%D1%82%D1%8C',headers={'Referer':router_ip+'/'+session+'/userRpm/SysRebootRpm.htm','Cookie': auth_token})
        status=str(r.status_code)
        print (logout(session))
        return 'Reboot: '+status
 
    elif operation=='Remote IP':
   
        #Задание IP адреса удаленного управления
        r = requests.get(router_ip+'/'+session+'/userRpm/ManageControlRpm.htm?port=5110&ip='+remote_ip+'&Save=%D0%A1%D0%BE%D1%85%D1%80%D0%B0%D0%BD%D0%B8%D1%82%D1%8C',headers={'Referer':router_ip+'/'+session+'/userRpm/SysRebootRpm.htm','Cookie': auth_token})
        status=str(r.status_code)
        print (logout(session))
        return 'Remote IP '+remote_ip+': '+status

    elif operation=='Check presence':
  
        #Определение подключенных устройств
        r = requests.get(router_ip+'/'+session+'/userRpm/WlanStationRpm.htm',headers={'Referer':router_ip+'/'+session+'/userRpm/MenuRpm.htm','Cookie': auth_token})
        status=str(r.status_code)
        print (logout(session))
        presence='Дома находятся:'

        if 'DC-31-54-97-51-06' in r.text:
            presence=presence+'\n'+'DC-31-54-97-51-06'
        return presence 

    else:
        return 'Wrong command'

Очевидно, аналогичным образом можно автоматизировать и другие функции управления устройствами, лишенными командной строки, с помощью доступа к WEB-интерфейсу. Например, я подобным образом с помощью HTTP Post реализовал reboot IP камеры DLink. Спасибо за внимание!

I wanted to know whether there is a tool that allows me to connect to a router and shut it down, and then reboot it from a python script.

I know that if I write:

import os
os.system("ssh -l root 192.168.2.1")

I can connect through python to my router. But then, I don’t know how to apply the router’s password, and to log into it, in order to reboot it.

So after working on it a bit here is the code that I have written in order to connect to my router with an SSH session using a python script:

import os, urllib, urllib2, re

def InterfaceControl():
    #os.system("echo training")
    os.system("ssh -l root 192.168.2.1")
    os.system("echo yes")
    os.system("echo My_ROUTER_PASSWORD")
    os.system("shutdown -r")



def main():
    InterfaceControl()


if __name__=="__main__":
    main()

The problem is that I still can’t connect to my router with this code, and moreover, IDLE (the editor I use for python scripts) crashes. Can anyone help me improve this code?

enzo's user avatar

enzo

10k3 gold badges15 silver badges40 bronze badges

asked Mar 13, 2013 at 13:22

sadek's user avatar

4

It depends on your tplink device model and firmware, because auth algorithm differ from model to model.

I wrote this python script which works fine for my tp link W740N. The code explains how to authenticate on this device using requests package

#!/usr/bin/python3
# imports
from requests import get
from base64 import b64encode
from urllib.parse import quote


# constants
tplink = '192.168.0.1'
user = 'admin'
password = 'admin'
url_template = 'http://{}/userRpm/SysRebootRpm.htm?Reboot=Reboot'


if __name__ == '__main__':
    auth_bytes = bytes(user+':'+password, 'utf-8')
    auth_b64_bytes = b64encode(auth_bytes)
    auth_b64_str = str(auth_b64_bytes, 'utf-8')

    auth_str = quote('Basic {}'.format(auth_b64_str))

    auth = {
    'Referer': 'http://'+tplink+'/', 
    'Authorization': auth_str,
    }

    reboot_url = url_template.format(tplink)
    
    r = get(reboot_url, headers=auth)

TheGoldenTree's user avatar

answered Nov 30, 2017 at 4:14

Alex Gluhov's user avatar

I think you could look at the router admin pages and see the post parameters it sends. In the script you could mimic the same.

I think most routers use basic authentication over https.

EDIT: found this.

wget -qO- --user=admin --password=admin-password http://192.168.1.2/userRpm/SysRebootRpm.htm?Reboot=Reboot

src: http://blog.taragana.com/old-code-how-to-reboot-tp-link-router-11849

My wget manual tells me -q is for quiet. Don’t know what the 0- is. You could also do something similar with curl.
Note: some tp-link devices require the referer header be sent. In curl for example, -H 'Referer: http://192.168.0.1'

I could do the same in python using the following code.

from urllib.request import urlopen, Request
import base64
req = Request('http://192.168.0.1/userRpm/SysRebootRpm.htm?Reboot=Reboot')
req.add_header('Authorization', ('Basic %s' % base64.b64encode('uname:pass'.encode('ascii')).decode('ascii')))
req.add_header('Referer', 'http://192.168.0.1')
urlopen(req)

answered Dec 11, 2016 at 7:50

DebD's user avatar

DebDDebD

3833 silver badges21 bronze badges

A few options I have found, depending on the specific device (I couldn’t find any documentation for the API anywhere, so I guess all of these come from individuals reverse-engineering for their own needs):

  • menahishayan/TP-Link-Archer-C50-API is the clearest structure, showing the cgi commands and payloads for the commands that are implemented. Starting from the main definitions in init.py as a model, I used Wireshark to capture the API interactions when I use the web interface, I was able to implement the commands that I needed quite quickly.
  • epsi95/TPLink-Python is easy to use and shows the command flow. I used it to double-check the headers I was sending (I had missed referer which is needed). It didn’t work for my router (Archer C2), returning HTTP status 500.
  • tplink-wr-api seems to be another candidate, but I didn’t get any extra information there for my router.

It is important to complete all commands within one Python requests.session session, and make sure to implement your router’s ‘logout’ functionality at the end of each interaction before closing the session. If you don’t (at least on the C2), you won’t be able to run further commands or log in to the web interface without waiting for a timeout or resetting the router. Instead, HTTP status 403 is returned from cgi commands and you will get a message on the web interface that only one administrator can log in at a time.

answered Nov 30, 2021 at 8:44

rolinger's user avatar

rolingerrolinger

6858 silver badges18 bronze badges

I think for a new firmware version, you need
referer and user-agent to work.

MendelG's user avatar

MendelG

15.1k4 gold badges26 silver badges54 bronze badges

answered Aug 25, 2017 at 8:42

Argo Saputro's user avatar

Skip to content

Below is an example of the TP-Link router reboot script, I will test it on TL-WR720N 2.0 from Ubuntu Server.

#!/bin/sh
ROUTER_IP="192.168.24.174"
USERNAME="admin"
PASSWORD="admin"

# exit if router is down
ping -q -c 1 "$ROUTER_IP" > /dev/null || exit

curl --basic --user "$USERNAME:$PASSWORD" -A "Mozilla/4.73 [en] (X11; U; Linux 2.2.15 i686)" --refer "http://$ROUTER_IP" "$ROUTER_IP/userRpm/SysRebootRpm.htm?Reboot=reboot"

The contents of the script will be placed in a new file, for example, using the nano editor (“CTRL+X” to exit and “y” to save the changes):

nano file.sh

And make it executable:

chmod 777 file.sh

After this, we execute:

./file.sh

Similarly, you can perform other functions instead of rebooting.

TP-LINK Remote Management

Multiple Batch scripts designed to control and monitor most TP-Link Routers through cURL.

Tested on TD-W8950ND V2 and TD-W8960N V5 (Most useless piece of garbage I have ever purchased).

1. Interactive Router Control:

Interactive Router Control.bat is an interactive batch script has the ability to:

  • Reboot Router
  • Change/Renew IP
  • Disable/Enable Wireless AP

2. Monitor WAN Statistics:

Make sure to create a Basic Task in the Task Scheduler to run «Track WAN Statistics.bat» every X mins.

Consists of 2 batch scripts used to monitor WAN Service (Internet Traffic) Bandwidth consumption.

  • Track WAN Statistics.bat : Fetch and save logged traffic then reset the statistics counter.

  • View Statistics.bat : View saved data in Gigs and Megs

  • В режиме точки доступа не могу зайти в роутер
  • В одну сеть роутер и модем
  • В режиме роутера нет днс
  • В одном свитче роутер и пк
  • В режиме роутера не работает tp link