المراقبة والتحكم عن بعد في الأجهزة المستندة إلى Lunix/OpenWrt/Lede عبر المنفذ 80...

مرحباً بالجميع، هذه أول تجربة لي في حبري. أريد أن أكتب عن كيفية إدارة معدات الشبكة على شبكة خارجية بطريقة غير قياسية. ماذا يعني غير قياسي: في معظم الحالات، لإدارة المعدات على شبكة خارجية، تحتاج إلى:

  • عنوان IP العام. حسنًا، أو إذا كانت المعدات موجودة خلف NAT لشخص ما، فعندئذٍ عنوان IP عام ومنفذ "مُعاد توجيهه".
  • نفق (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 وأمازون. إذا كنت تستخدم مجالًا رمزيًا، في حالة حدوث مثل هذا الحادث، يمكنك بسهولة رفع سحابة احتياطية وإعادة توجيه المجال إليها واستعادة مراقبة الجهاز.

a.php هو اسم البرنامج النصي من جانب الخادم. نعم، أعلم أنه من الخطأ تسمية المتغيرات وأسماء الملفات بنفس الحرف... أقترح بهذه الطريقة أن نحفظ بضعة بايتات عند إرسال الطلب :)
ش - اسم المستخدم، تسجيل الدخول إلى الأجهزة
ع - كلمة المرور
"-O /tmp/wa.sh" هو ملف موجود على جهاز التوجيه البعيد حيث سيتم حفظ استجابة الخادم، على سبيل المثال أمر إعادة التشغيل.

ملاحظة رقم اثنين: آه، لماذا نستخدم wget وليس curl، لأنه عبر curl يمكنك إرسال طلبات https ليس باستخدام GET، ولكن باستخدام POST؟ آه لأنه، كما في النكتة القديمة "NE يصعد إلى الجرة!" يتضمن curl مكتبات تشفير يبلغ حجمها حوالي 2 ميجابايت، ولهذا السبب فمن غير المحتمل أن تتمكن من تجميع صورة لجهاز TP-LINK ML3020 صغير، على سبيل المثال. ومع wget - من فضلك.

2) من جانب الخادم (لدي Ubuntu) سنستخدم Zabbix. السبب: أريد أن تكون جميلة (مع الرسوم البيانية) ومريحة (إرسال الأوامر عبر قائمة السياق). لدى Zabbix شيء رائع مثل وكيل 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

حيث:
الاختبار هو اسم وكيلنا
"كلمة مرور المستخدم php /usr/share/zabbix/agent.php" - نص يسمى يشير إلى بيانات تسجيل الجهاز.

إضافة المخططات: افتح واجهة ويب zabbix، وحدد من القائمة:
الإعدادات -> عقد الشبكة -> إنشاء عقدة شبكة. ويكفي هنا تحديد اسم مضيف الشبكة ومجموعته وواجهة الوكيل الافتراضية:

المراقبة والتحكم عن بعد في الأجهزة المستندة إلى Lunix/OpenWrt/Lede عبر المنفذ 80...

نحتاج الآن إلى إضافة عنصر بيانات لعقدة الشبكة هذه. انتبه إلى حقلين: "المفتاح" - هذا هو بالضبط المعلمة التي كتبناها في الملف /etc/zabbix/zabbix_agentd.conf (في حالتنا هو اختبار)، و"الفاصل الزمني للتحديث" - قمت بتعيينه على 5 دقائق لأنه يتم أيضًا تسجيل الجهاز على الخادم مرة كل خمس دقائق.

المراقبة والتحكم عن بعد في الأجهزة المستندة إلى Lunix/OpenWrt/Lede عبر المنفذ 80...

حسنا، دعونا نضيف رسما بيانيا. أوصي باختيار "Fill" كنمط العرض.

المراقبة والتحكم عن بعد في الأجهزة المستندة إلى Lunix/OpenWrt/Lede عبر المنفذ 80...

الإخراج شيء مقتضب للغاية، على سبيل المثال مثل هذا:

المراقبة والتحكم عن بعد في الأجهزة المستندة إلى Lunix/OpenWrt/Lede عبر المنفذ 80...

على السؤال المعقول: "هل كان الأمر يستحق ذلك؟"، سأجيب: حسنًا، بالطبع، راجع "أسباب إنشاء دراجة" في بداية المقال.

إذا كانت تجربتي الأولى في الرسم البياني تثير اهتمام القراء، ففي المقالات التالية أريد أن أصف كيفية إرسال الأوامر إلى المعدات البعيدة. تمكنا أيضًا من تنفيذ المخطط بأكمله للأجهزة القائمة على RouterOS (Mikrotik).

المصدر: www.habr.com

إضافة تعليق