大家好,这是我第一次体验哈布雷。 我想写一篇如何以非标准的方式管理外部网络上的网络设备。 非标准是什么意思:在大多数情况下,要管理外部网络上的设备,您需要:
- 公共 IP 地址。 好吧,或者如果设备位于某人的 NAT 之后,则需要一个公共 IP 和一个“转发”端口。
- 到中心节点的隧道(PPTP/OpenVPN/L2TP+IPSec 等),通过该隧道可对其进行访问。
- 该设备位于NAT后面,除了通常的http(端口80)之外,一切都是关闭的。 对于大型联邦企业网络来说,这是完全正常的情况。 他们可以注册端口,但不会立即、不会很快,而且不会为您注册。
- 不稳定和/或“狭窄”的沟通渠道。 速度低,损耗恒定。 尝试组织隧道时的痛苦和挫败感。
- 这是一种昂贵的通信渠道,几乎每一兆字节都很重要。 例如,卫星通信。 加上长延迟和“窄”频带。
- 需要“杂耍”大量小型路由器的情况,一方面安装了OpenWrt/Lede来扩展能力,另一方面路由器的资源(内存)又不够用对于一切。
注意次数 是什么阻止您将闪存驱动器安装到路由器的 USB 端口并扩展路由器的内存?
大多数情况下,要求是针对整个解决方案的成本,但有时外形因素也起着关键作用。 例如,现场有一个TP-Link ML3020,它唯一的USB端口用于2G/3G调制解调器,所有这些都被包裹在某种小塑料盒中,并放置在高高的地方(在桅杆上),很远很远(在现场,距离最近的移动运营商基站 30 公里)。 是的,您可以插入USB集线器并扩展端口数量,但经验表明这很麻烦且不可靠。
所以,我试图向你们描述我的典型情况:“在很远很远的地方,有一个非常重要、孤独的小型路由器,运行着 Linux。 重要的是每天至少一次知道他“还活着”,并且如有必要,会向他发送命令,例如“亲爱的,重新启动!”
让我们继续实施:
1)在路由器端,通过cron,每隔5/10/1440分钟,或者任何时候,需要使用wget向服务器发送http请求,将请求结果保存到文件中,使文件可执行,并执行它。
我的 cron 行看起来像这样:
文件/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
哪里:
xn--80abgfbdwanb2akugdrd3a2e5gsbj.xn--p1ai是我服务器的域。 让我立即指出:是的,您可以指定服务器的特定IP地址,我们曾经这样做,直到我们的状态,在一种正义的斗争冲动中,我会说,我不知道,阻止了对狮子的访问DigitalOcean 和亚马逊“云”的份额。 如果您使用符号域,如果发生此类事件,您可以轻松地建立备份云,将域重定向到它并恢复设备监控。
a.php 是服务器端脚本的名称。 是的,我知道用相同的字母命名变量和文件名是错误的......我建议这样我们在发送请求时节省一些字节:)
u - 用户名,硬件登录
p - 密码
“-O /tmp/wa.sh”是远程路由器上的一个文件,其中将保存服务器响应,例如重新启动命令。
注意事项二: 啊啊,为什么我们使用 wget 而不是curl,因为通过curl 你可以不使用GET 而是使用POST 发送https 请求? 啊,因为,正如老笑话中所说的“NE 爬进罐子里!” 例如,curl 包含大小约为 2MB 的加密库,因此您不太可能为小型 TP-LINK ML3020 组装映像。 还有 wget - 请。
2)在服务器端(我有Ubuntu)我们将使用Zabbix。 为什么:我希望它美观(带有图表)且方便(通过上下文菜单发送命令)。 Zabbix有zabbix代理这么奇妙的东西。 通过代理,我们将调用服务器上的 PHP 脚本,该脚本将返回有关我们的路由器是否在要求的时间内注册的信息。 为了存储有关注册时间、设备命令的信息,我使用 MySQL,一个单独的表 users ,大约包含以下字段:
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;
所有源代码都可以从 Git 存储库下载:
现在PHP脚本放置在服务器端(为了方便,可以放置在/usr/share/zabbix/文件夹中):
a.php 文件:
<?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();
?>
Agent.php文件(这是zabbix代理调用的脚本):
<?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();
?>
好吧,最后阶段:注册代理并添加时间表。
如果您还没有安装zabbix代理,那么:
apt-get install zabbix-agent
编辑文件/etc/zabbix/zabbix_agentd.conf。
添加行:
UserParameter=test,php /usr/share/zabbix/agent.php user password
哪里:
test 是我们代理的名称
“php /usr/share/zabbix/agent.php 用户密码” - 指示设备注册数据的调用脚本。
添加图表:打开zabbix web界面,从菜单中选择:
设置 -> 网络节点 -> 创建网络节点。 这里指定网络主机的名称、其组和默认代理接口就足够了:
现在我们需要为此网络节点添加一个数据元素。 注意两个字段:“key” - 这正是我们在 /etc/zabbix/zabbix_agentd.conf 文件中写入的参数(在我们的例子中是 test),以及“update Interval” - 我将其设置为 5 分钟,因为设备也每五分钟在服务器上注册一次。
好吧,让我们添加一个图表。 我建议选择“填充”作为渲染风格。
输出非常简洁,例如:
对于合理的问题:“值得吗?”,我会回答:嗯,当然,请参阅文章开头的“创造自行车的原因”。
如果我的第一次写字经历引起了读者的兴趣,那么在接下来的文章中我想描述如何向远程设备发送命令。 我们还成功地为基于 RouterOS (Mikrotik) 的设备实现了整个方案。
来源: habr.com