Remote monitoring and management of devices based on Lunix/OpenWrt/Lede through port 80…

Hello everyone, this is my first experience on Habra. I want to write about unconventional ways to manage network equipment in an external network. What does unconventional mean? In most cases, to manage equipment in an external network, you need to have:

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

Therefore, 'my bicycle' will be necessary when standard methods don’t suit you, for example:

  1. The equipment is behind NAT, and apart from regular http (port 80), everything is closed. This is quite a normal situation for large federal corporate networks. They can configure ports, but not immediately, not quickly, and not for you.
  2. An unstable and/or 'narrow' communication channel. Low speed, constant losses. Pain and disappointment when trying to establish a tunnel.
  3. An expensive communication channel where literally every megabyte counts. For instance, satellite communication. Plus, there are high latencies and a 'narrow' bandwidth.
  4. A situation in which you need to 'juggle' a large number of small routers, on which one side has OpenWrt/Lede installed to expand capabilities, while on the other side, the router's resources (memory) are far from enough for everything.

Note number one What prevents you from connecting a 'flash drive' to the USB port of the router to expand its memory?

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

So, I tried to describe for you my typical situation: 'somewhere far away, there is a very important, lonely, and small router running Linux. It is important to know at least once a day if it is 'alive' and to send it commands if necessary, for example, 'sunshine, reboot!'

Let's move on to the implementation:

1) On the router side, every 5/10/1440 minutes, or whenever necessary, an HTTP request should be sent to the server using wget, saving the request result in a file, making the file executable, and executing 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 — this is my server's domain. Just to note: yes, you can specify a particular server IP address; we used to do that until our government, in its righteous struggle against who knows what, closed access to a large portion of DigitalOcean and Amazon 'clouds'. If you use a symbolic domain, in case of such an issue, you can easily bring up a backup cloud, redirect the domain to it, and restore device monitoring.

a.php — the name of the script on the server side. Yes, I know it's incorrect to name variables and file names with a single letter… let's just say we save a few bytes when sending the request 🙂
u — the username, the login of the device
p — the password
"-O /tmp/wa.sh" — the file on the remote router where the server's response will be saved, for example, the reboot command.

Note number two: Aaaa, why are we using wget instead of curl, since you can send HTTPS requests with curl and not just GET but POST? Aaaa because, as in the old joke, "It doesn't fit in the bucket!" Curl includes encryption libraries that are about 2MB in size, so you'll unlikely manage to build an image for a small TP-LINK ML3020, for example. But wget works just fine.

2) On the server side (I have Ubuntu), we will use Zabbix. Why: I want it to look nice (with graphs) and be convenient (to send commands through the context menu). Zabbix has a wonderful feature called zabbix-agent. Through the agent, we will invoke a PHP script on server, which will return information about whether our router was registered in the required time period. To store information about registration times and device commands, I use MySQL, a separate users table with fields like these:

		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 connection time
		  `last_ip` varchar(20) NOT NULL, // last connection IP
		  `last_port` int(11) NOT NULL, // last connection port
		  `task` text NOT NULL, // task received by the router
		  `reg_task` varchar(150) NOT NULL, // "regular" task if we want the task to execute always upon registration
		  `last_task` text NOT NULL, // task log
		  `response` text NOT NULL, // response from the device
		  `seq` int(11) NOT NULL
		) ENGINE=InnoDB DEFAULT CHARSET=utf8;

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

File a.php:

set_charset("utf8");
	// Here we are searching for our router in the database table
	$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();
		// Here we send the router its tasks
		echo $task;
		echo "n";
		echo $reg_task;
		// Here we write the response time and the router's response
		$response_history="[".date("Y-m-d H:i")."] ".$message;
		// task is sent, now we need to delete it, and after deletion, log that this task has been completed
		$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();
		}
		// Now we need to save the registration time of the user, their IP, and their message. For now, just the message
		$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();
	}
	// If we did not find the router in our database, or its status is "inactive", then a reboot command will be sent to it...
	// Why so harsh? Because routers sometimes disappear, and this is a small way to teach "new owners" a lesson. 
	else
	{
	echo "reboot";
	}
	$sql_users->close();
?>

The file agent.php (this is the script of the invoked zabbix agent):

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();
	// data exchange happens via the seq field. When registering, the device sets this field to "1"
	if (($sql_users->num_rows)==1){
		$sql_users->fetch();
		echo $seq;
	}
		
	// reset $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();
?>		

And the final step: configuring the agent and adding graphs.

If you do not have the zabbix agent installed yet, then:

apt-get install zabbix-agent

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

Add the 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" — the script called with the device registration credentials.

Adding graphs: open the zabbix web interface, select from the menu:
Configuration -> Hosts -> Create Host. Here, just specify the name of the host, its group, and the default agent interface:

Remote monitoring and management of devices based on Lunix/OpenWrt/Lede through port 80…

Now we need to add a data item for this host. Note the two fields: "key" — this is the parameter we specified in the file /etc/zabbix/zabbix_agentd.conf (in our case it's test), and "update interval" — I set it to 5 minutes, as the device registers on the server also once every five minutes.

Remote monitoring and management of devices based on Lunix/OpenWrt/Lede through port 80…

Then we add a graph. I recommend choosing "Fill" as the rendering style.

Remote monitoring and management of devices based on Lunix/OpenWrt/Lede through port 80…

The output results in something very concise, like this:

Remote monitoring and management of devices based on Lunix/OpenWrt/Lede through port 80…

To the reasonable question: "Was it worth it?", I will respond: of course, see "reasons for creating a bicycle" at the beginning of the article.

If my first verbose experience attracts readers' interest, I want to describe how to send commands to remote devices in subsequent articles. I was also able to implement the entire scheme for devices based on RouterOS (Mikrotik).

Source: habr.com

Buy reliable website hosting with DDoS protection, VPS VDS servers 🔥 Buy reliable website hosting with DDoS protection, VPS VDS servers | ProHoster