Remote monitoring and control of Lunix/OpenWrt/Lede devices via port 80…

Hello everyone, this is my first experience on Habré. I want to write about how to manage network equipment in an external network in a non-standard way. What does non-standard mean: in most cases, to control equipment in an external network, you need to:

  • Public IP address. Well, or if the equipment is behind someone's NAT, then a public IP and a "forwarded" port.
  • Tunnel (PPTP / OpenVPN / L2TP + IPSec, etc.) to the central node through which it would be available.

Therefore, you will need "my bike" when standard methods do not suit you, for example:

  1. The equipment is behind NAT and except for the usual http (port 80) everything is closed. Quite a normal situation for large federal corporate networks. They can register ports, but not immediately, not quickly, and not for you.
  2. Unstable and / or "narrow" communication channel. Low speed, constant losses. Pain and frustration when trying to organize a tunnel.
  3. An expensive communication channel, where literally every megabyte counts. For example, satellite communications. Plus big delays and a "narrow" band.
  4. The situation when you need to "juggle" a large number of small routers, on which, on the one hand, OpenWrt / Lede is installed to expand the capabilities, and on the other hand, the resources (memory) of the router are not enough for everything.

note number times And what prevents you from installing a “flash drive” into the USB port of the router and expanding the memory of the router?

Most often, the requirements for the cost of the solution as a whole, but sometimes the form factor also plays a key role. For example, there is a TP-Link ML3020 at the facility, its only USB port is used for a 2G / 3G modem, all this is wrapped in a thread of a small plastic case and placed somewhere high, high (on a mast), far, far (in field, 30 km from the nearest base station of a mobile operator). Yes, you can plug in a USB hub and expand the number of ports, but experience shows that this is cumbersome and unreliable.

So, I tried to describe to you my typical situation: “somewhere far, far away, there is a very important, lonely and small router running Linux. It is important to know at least once a day that he is “alive” and, if necessary, commands were sent to him, for example, “sunny, reboot!”

Let's move on to the implementation:

1) On the side of the router via cron, every 5/10/1440 minutes, or whenever you want, you need to send an http request to the server using wget, save the result of the request to a file, make the file executable, and execute it.

My cron line looks something like this:

File /etc/crontabs/root:

  */5 * * * * wget "http://xn--80abgfbdwanb2akugdrd3a2e5gsbj.xn--p1ai/a.php?u=user&p=password" -O /tmp/wa.sh && chmod 777 /tmp/wa.sh && /tmp/wa.sh

, where:
xn--80abgfbdwanb2akugdrd3a2e5gsbj.xn--p1ai is my server's domain. I’ll note right away: yes, you can also specify a specific server ip-address, we did this before, until our state, in a righteous outburst of struggle, I don’t know what, didn’t close access to the lion’s share of DigitalOcean and Amazon “clouds”. In the case of using a symbolic domain, if such an incident occurs, you can easily raise a backup cloud, redirect the domain to it and restore device monitoring.

a.php is the name of the script on the server side. Yes, I know it's wrong to name variables and file names with the same letter... I suggest that we save a few bytes when sending a request 🙂
u - username, hardware login
p - password
"-O /tmp/wa.sh" - a file on the remote router where the server response will be saved, for example, the reboot command.

Note number two: Ahhh, why do we use wget and not curl, because through curl you can send https requests and not GET, but POST? Ahhh, because, as in the old joke, “He climbs into the pot!”. The structure of curl includes encryption libraries with a size of about 2MB, and because of this, it is unlikely that you will be able to build an image for a small TP-LINK ML3020, for example. And with wget - please.

2) On the server side (I have Ubuntu) we will use Zabbix. Why: I want it to be beautiful (with graphs) and convenient (to send commands via the context menu). Zabbix has such a lovely thing as a zabbix agent. Through the agent, we will call a php script on the server, which will return information about whether our router was registered in the required period of time. To store information about registration time, commands for devices, I use MySQL, a separate users table with fields like this:

		CREATE TABLE `users` (
		  `id` varchar(25) NOT NULL,
		  `passwd` varchar(25) NOT NULL,
		  `description` varchar(150) NOT NULL,
		  `category` varchar(30) NOT NULL,
		  `status` varchar(10) NOT NULL,
		  `last_time` varchar(20) NOT NULL, // время последнего соединения
		  `last_ip` varchar(20) NOT NULL, // IP последнего соединения 
		  `last_port` int(11) NOT NULL, // порт последнего соединения
		  `task` text NOT NULL, // задача которую получает роутер
		  `reg_task` varchar(150) NOT NULL, // "регулярная" задача, если мы захотим чтобы задача выполнялась всегда при регистрации
		  `last_task` text NOT NULL, // лог задач
		  `response` text NOT NULL, // сюда пишется ответ устройства
		  `seq` int(11) NOT NULL
		) ENGINE=InnoDB DEFAULT CHARSET=utf8;

All sources can be taken from the Git repository at: https://github.com/BazDen/iotnet.online.git
Now PHP scripts hosted on the server side (for convenience, they can be placed in the /usr/share/zabbix/ folder):

a.php file:

<?php
// Получаем входные параметры: имя пользователя, пароль и сообщение от удаленного роутера
// Зачем нужен message ? Это способ ответа роутера, например если вы захотите посмотреть содержимое файла роутера
	$user=$_REQUEST['u'];
	$password=$_REQUEST['p'];
	$message=$_REQUEST['m'];
	
	// Подключаемся к нашей базе данных (MySQL)
	$conn=new mysqli("localhost","db_login","db_password","DB_name");
	if (mysqli_connect_errno()) {
		exit();
	}
	$conn->set_charset("utf8");
	// здесь ищем наш роутер в таблице базы данных
	$sql_users=$conn->prepare("SELECT task, reg_task, response, last_time FROM users WHERE id=? AND passwd=? AND status='active';");
	$sql_users->bind_param('ss', $user, $password);
	$sql_users->bind_result($task, $reg_task, $response, $last_time);
	$sql_users->execute();
	$sql_users->store_result();
	if (($sql_users->num_rows)==1){
		$sql_users->fetch();
		// здесь мы роутеру отправляем его задачи
		echo $task;
		echo "n";
		echo $reg_task;
		// вот здесь мы пишем время ответа и сам ответ роутера
		$response_history="[".date("Y-m-d H:i")."] ".$message;
		// задачу отправили, теперь надо ее удалить,а после удаления отметить в логах, что такая-то задача выполнена
		$last_ip=$_SERVER["REMOTE_ADDR"];
		$last_port=$_SERVER["REMOTE_PORT"];
		$ts_last_conn_time=$last_time;
		$sql_users=$conn->prepare("UPDATE users SET task='', seq=1 WHERE (id=?);");
		$sql_users->bind_param('s', $user);
		$sql_users->execute();
		if (strlen($message)>1){
			$sql_users=$conn->prepare("UPDATE users SET response=?, seq=1 WHERE (id=?);");
			$sql_users->bind_param('ss', $response_history, $user);
			$sql_users->execute();
		}
		// теперь надо сохранить время регистрации пользователя, его айпи и сообщение от него. Пока только сообщение
		$ts_now=time();
		$sql_users=$conn->prepare("UPDATE users SET last_time=?, last_ip=?, last_port=? WHERE (id=?);");
		$sql_users->bind_param('ssss', $ts_now, $last_ip, $last_port, $user);
		$sql_users->execute();
	}
	// если мы не нашли роутер в нашей базе данных, или его статус "неактивный", то ему ... будет отправлена команда reboot....
	// Почему так жестоко ? Потому что роутеры иногда пропадают, а это маленький способ проучить "новых владельцев". 
	else
	{
	echo "reboot";
	}
	$sql_users->close();
	?>

File agent.php (this is the script of the called zabbix agent):

<?php
	// файл агента Zabbix. Данный скрипт обращается к таблице users и получает "1" если устройство регистрировалось с момента последнего обращения
	// user и password - учетные данные оборудования
	$user = $argv[1];
	$password = $argv[2];
	
	// подключаемся к нашей базе данных
	$conn=new mysqli("localhost","db_user","db_password","db_name");
	if (mysqli_connect_errno()) {
		exit();
		}
	$conn->set_charset("utf8");
	$sql_users=$conn->prepare("SELECT seq FROM users WHERE id=? AND passwd=? AND status='active';");
	$sql_users->bind_param('ss', $user, $password);
	$sql_users->bind_result($seq);
	$sql_users->execute();
	$sql_users->store_result();
	// обмен данными происходит через поле seq. При регистрации железка ставит данное поле в "1"
	if (($sql_users->num_rows)==1){
		$sql_users->fetch();
		echo $seq;
	}
		
	// обнуляем $seq. 
	$sql_users=$conn->prepare("UPDATE users SET seq=0 WHERE id=? AND passwd=? AND status='active';");
	$sql_users->bind_param('ss', $user, $password);
	$sql_users->execute();
	$sql_users->close();
?>		

Well, the final stage: prescribing an agent and adding charts.

If you don't have zabbix agent installed yet, then:

apt-get install zabbix-agent

Edit the /etc/zabbix/zabbix_agentd.conf file.

We add a line:

UserParameter=test,php /usr/share/zabbix/agent.php user password

, where:
test - the name of our agent
"php /usr/share/zabbix/agent.php user password" - called script with device registration data.

Adding charts: open the zabbix web interface, select from the menu:
Setup -> Hosts -> Create host. Here it is enough to specify the host name, its group, and the default agent interface:

Remote monitoring and control of Lunix/OpenWrt/Lede devices via port 80…

Now we need to add a data element for this host. Pay attention to two fields: "key" - this is exactly the parameter that we wrote in the /etc/zabbix/zabbix_agentd.conf file (in our case it is test), and "update interval" - I set 5 minutes, because and the equipment is registered on the server, too, once every five minutes.

Remote monitoring and control of Lunix/OpenWrt/Lede devices via port 80…

Well, let's add a graph. I recommend choosing "Fill" as the drawing style.

Remote monitoring and control of Lunix/OpenWrt/Lede devices via port 80…

The output is something very concise, like this:

Remote monitoring and control of Lunix/OpenWrt/Lede devices via port 80…

To a reasonable question: “was it worth it?”, I will answer: well, of course, see “reasons for creating a bicycle” at the beginning of the article.

If my first graphomaniac experience arouses the interest of readers, then in the following articles I want to describe how to send commands to remote equipment. We also managed to implement the entire scheme for devices based on RouterOS (Mikrotiks).

Source: habr.com

Add a comment