การตรวจสอบระยะไกลและการควบคุมอุปกรณ์ที่ใช้ Lunix/OpenWrt/Lede ผ่านพอร์ต 80...

สวัสดีทุกคน นี่เป็นประสบการณ์ครั้งแรกของฉันกับHabré ฉันต้องการเขียนเกี่ยวกับวิธีจัดการอุปกรณ์เครือข่ายบนเครือข่ายภายนอกด้วยวิธีที่ไม่ได้มาตรฐาน ที่ไม่ได้มาตรฐานหมายถึงอะไร: ในกรณีส่วนใหญ่ คุณต้องมีการจัดการอุปกรณ์บนเครือข่ายภายนอก:

  • ที่อยู่ IP สาธารณะ หรือหากอุปกรณ์อยู่หลัง NAT ของใครบางคน แสดงว่าเป็น IP สาธารณะและพอร์ต "ส่งต่อ"
  • Tunnel (PPTP/OpenVPN/L2TP+IPSec ฯลฯ) ไปยังโหนดกลางที่สามารถเข้าถึงได้

ดังนั้น คุณจะต้องมี “จักรยานของฉัน” เมื่อวิธีการมาตรฐานไม่เหมาะกับคุณ เช่น:

  1. อุปกรณ์ตั้งอยู่ด้านหลัง NAT และยกเว้น http ปกติ (พอร์ต 80) ทุกอย่างปิดอยู่ นี่เป็นสถานการณ์ปกติโดยสิ้นเชิงสำหรับเครือข่ายองค์กรขนาดใหญ่ของรัฐบาลกลาง พวกเขาสามารถลงทะเบียนพอร์ตได้ แต่ไม่ใช่ในทันที ไม่รวดเร็ว และไม่ใช่สำหรับคุณ
  2. ช่องทางการสื่อสารไม่เสถียร และ/หรือ “แคบ” ความเร็วต่ำ การสูญเสียอย่างต่อเนื่อง ความเจ็บปวดและความหงุดหงิดเมื่อพยายามจัดอุโมงค์
  3. ช่องทางการสื่อสารที่มีราคาแพงซึ่งทุกเมกะไบต์มีความสำคัญอย่างแท้จริง เช่น การสื่อสารผ่านดาวเทียม บวกกับความล่าช้าที่ยาวนานและวงดนตรีที่ "แคบ"
  4. สถานการณ์เมื่อคุณต้องการ "เล่นปาหี่" เราเตอร์ขนาดเล็กจำนวนมาก ซึ่งในอีกด้านหนึ่ง OpenWrt/Lede ได้รับการติดตั้งเพื่อขยายขีดความสามารถ และในทางกลับกัน ทรัพยากร (หน่วยความจำ) ของเราเตอร์ยังไม่เพียงพอ สำหรับทุกอย่าง.

หมายเหตุจำนวนครั้ง อะไรขัดขวางไม่ให้คุณติดตั้งแฟลชไดรฟ์เข้ากับพอร์ต USB ของเราเตอร์และขยายหน่วยความจำของเราเตอร์

บ่อยครั้งที่ข้อกำหนดมีไว้สำหรับต้นทุนของโซลูชันโดยรวม แต่บางครั้งฟอร์มแฟคเตอร์ก็มีบทบาทสำคัญเช่นกัน ตัวอย่างเช่น มี TP-Link ML3020 ที่ไซต์ พอร์ต USB เพียงพอร์ตเดียวที่ใช้สำหรับโมเด็ม 2G/3G ทั้งหมดนี้ห่อด้วยกล่องพลาสติกขนาดเล็กบางชนิดและวางไว้ในตำแหน่งที่สูง สูง (บนเสากระโดง) ไกล, ไกล (ในสนาม 30 กม. จากสถานีฐานผู้ให้บริการโทรศัพท์เคลื่อนที่ที่ใกล้ที่สุด) ใช่ คุณสามารถเสียบฮับ USB และขยายจำนวนพอร์ตได้ แต่ประสบการณ์แสดงให้เห็นว่าสิ่งนี้ยุ่งยากและไม่น่าเชื่อถือ

ดังนั้นฉันจึงพยายามอธิบายสถานการณ์ทั่วไปของฉันให้คุณฟัง: “ที่ไหนสักแห่งที่ไกลออกไป มีเราเตอร์ขนาดเล็กที่โดดเดี่ยวและสำคัญมากที่ใช้ Linux สิ่งสำคัญคือต้องรู้อย่างน้อยวันละครั้งว่าเขา "มีชีวิตอยู่" และหากจำเป็นจะมีการส่งคำสั่งไปให้เขาเช่น "ที่รัก รีบูต!"

มาดูการดำเนินการกันดีกว่า:

1) ที่ฝั่งเราเตอร์ ผ่าน cron ทุกๆ 5/10/1440 นาที หรือเมื่อใดก็ตามที่คุณต้องการ คุณต้องส่งคำขอ http ไปยังเซิร์ฟเวอร์โดยใช้ wget บันทึกผลลัพธ์ของคำขอลงในไฟล์ ทำให้ไฟล์ปฏิบัติการได้ และดำเนินการมัน

เส้น 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 และ Amazon "เมฆ" หากคุณใช้โดเมนสัญลักษณ์ หากเกิดเหตุการณ์ดังกล่าว คุณสามารถเพิ่มคลาวด์สำรอง เปลี่ยนเส้นทางโดเมนไปยังโดเมนนั้น และกู้คืนการตรวจสอบอุปกรณ์ได้อย่างง่ายดาย

a.php คือชื่อของสคริปต์ฝั่งเซิร์ฟเวอร์ ใช่ ฉันรู้ว่าการตั้งชื่อตัวแปรและชื่อไฟล์ด้วยตัวอักษรเดียวกันนั้นผิด... ฉันแนะนำว่าวิธีนี้จะช่วยประหยัดไบต์ได้สองสามไบต์เมื่อส่งคำขอ :)
คุณ - ชื่อผู้ใช้, เข้าสู่ระบบฮาร์ดแวร์
พี - รหัสผ่าน
“-O /tmp/wa.sh” เป็นไฟล์บนเราเตอร์ระยะไกลที่การตอบสนองของเซิร์ฟเวอร์ เช่น คำสั่งรีบูต จะถูกบันทึก

หมายเหตุหมายเลขสอง: อ้าว ทำไมเราถึงใช้ wget ไม่ใช่ curl เพราะผ่าน curl คุณสามารถส่งคำขอ https ที่ไม่ใช่ GET แต่ส่งด้วย POST ได้ อ่า เพราะอย่างกับมุกเก่าๆ ที่ว่า "NE ปีนเข้าไปในโถ!" curl มีไลบรารีการเข้ารหัสขนาดประมาณ 2MB และด้วยเหตุนี้ คุณจึงไม่น่าจะสามารถประกอบรูปภาพสำหรับ TP-LINK ML3020 ขนาดเล็กได้ เป็นต้น และด้วย wget - ได้โปรด

2) ทางฝั่งเซิร์ฟเวอร์ (ฉันมี Ubuntu) เราจะใช้ Zabbix เหตุผล: อยากให้สวยงาม (มีกราฟ) และสะดวก (ส่งคำสั่งผ่านเมนูบริบท) แซบบิกซ์มีสิ่งมหัศจรรย์เหมือนกับตัวแทนแซบบิกซ์ เราจะเรียกสคริปต์ PHP บนเซิร์ฟเวอร์ผ่านตัวแทนซึ่งจะส่งคืนข้อมูลเกี่ยวกับว่าเราเตอร์ของเราลงทะเบียนในช่วงเวลาที่กำหนดหรือไม่ ในการจัดเก็บข้อมูลเกี่ยวกับเวลาลงทะเบียนคำสั่งสำหรับอุปกรณ์ฉันใช้ MySQL ซึ่งเป็นผู้ใช้ตารางแยกต่างหากโดยมีฟิลด์ต่อไปนี้โดยประมาณ:

		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 ที่: https://github.com/BazDen/iotnet.online.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 เลือกจากเมนู:
การตั้งค่า -> โหนดเครือข่าย -> สร้างโหนดเครือข่าย การระบุชื่อโฮสต์เครือข่าย กลุ่ม และอินเทอร์เฟซเอเจนต์เริ่มต้นก็เพียงพอแล้ว:

การตรวจสอบระยะไกลและการควบคุมอุปกรณ์ที่ใช้ Lunix/OpenWrt/Lede ผ่านพอร์ต 80...

ตอนนี้เราจำเป็นต้องเพิ่มองค์ประกอบข้อมูลสำหรับโหนดเครือข่ายนี้ ให้ความสนใจกับสองฟิลด์: "คีย์" - นี่คือพารามิเตอร์ที่เราเขียนในไฟล์ /etc/zabbix/zabbix_agentd.conf ทุกประการ (ในกรณีของเราคือการทดสอบ) และ "ช่วงเวลาอัปเดต" - ฉันตั้งไว้ที่ 5 นาที เพราะและอุปกรณ์จะถูกลงทะเบียนบนเซิร์ฟเวอร์ทุกๆ ห้านาทีด้วย

การตรวจสอบระยะไกลและการควบคุมอุปกรณ์ที่ใช้ Lunix/OpenWrt/Lede ผ่านพอร์ต 80...

ทีนี้มาเพิ่มกราฟกัน ฉันแนะนำให้เลือก "เติม" เป็นรูปแบบการเรนเดอร์

การตรวจสอบระยะไกลและการควบคุมอุปกรณ์ที่ใช้ Lunix/OpenWrt/Lede ผ่านพอร์ต 80...

ผลลัพธ์เป็นสิ่งที่กระชับมาก เช่น:

การตรวจสอบระยะไกลและการควบคุมอุปกรณ์ที่ใช้ Lunix/OpenWrt/Lede ผ่านพอร์ต 80...

สำหรับคำถามที่สมเหตุสมผล: "คุ้มไหม" ฉันจะตอบ: แน่นอนดู "เหตุผลในการสร้างจักรยาน" ในตอนต้นของบทความ

หากประสบการณ์ Graphomaniac ครั้งแรกของฉันกระตุ้นความสนใจของผู้อ่านในบทความต่อไปนี้ฉันต้องการอธิบายวิธีส่งคำสั่งไปยังอุปกรณ์ระยะไกล นอกจากนี้เรายังจัดการเพื่อใช้โครงร่างทั้งหมดสำหรับอุปกรณ์ที่ใช้ RouterOS (Mikrotik)

ที่มา: will.com

เพิ่มความคิดเห็น