포트 80을 통해 Lunix/OpenWrt/Lede 기반 장치의 원격 모니터링 및 제어…

안녕하세요 여러분, Habré에 대한 첫 경험입니다. 비표준적인 방법으로 외부 네트워크의 네트워크 장비를 관리하는 방법에 대해 글을 쓰고 싶습니다. 비표준이란 무엇을 의미합니까? 대부분의 경우 외부 네트워크에서 장비를 관리하려면 다음이 필요합니다.

  • 공용 IP 주소. 글쎄, 또는 장비가 누군가의 NAT 뒤에 있다면 공용 IP와 "전달" 포트가 필요합니다.
  • 액세스할 수 있는 중앙 노드로 터널링(PPTP/OpenVPN/L2TP+IPSec 등)합니다.

따라서 표준 방법이 적합하지 않은 경우 "내 자전거"가 필요합니다. 예를 들면 다음과 같습니다.

  1. 장비는 NAT 뒤에 위치하며 일반적인 http(포트 80)를 제외하고 모든 것이 닫혀 있습니다. 이는 대규모 연방 기업 네트워크의 경우 완전히 정상적인 상황입니다. 그들은 포트를 등록할 수 있지만 즉시, 신속하지 않고 귀하를 위해 등록할 수는 없습니다.
  2. 불안정하고 "좁은" 통신 채널. 저속, 지속적인 손실. 터널을 정리하려고 할 때의 고통과 좌절감.
  3. 문자 그대로 모든 메가바이트가 중요한 값비싼 통신 채널입니다. 예를 들어, 위성 통신. 게다가 긴 지연과 "좁은" 대역.
  4. 기능 확장을 위해 OpenWrt/Lede가 설치되어 있는 다수의 소형 라우터를 "저글링"해야 하는 상황, 다른 한편으로는 라우터의 리소스(메모리)가 충분하지 않은 경우 모두를위한.

여러 번 메모 라우터의 USB 포트에 플래시 드라이브를 설치하고 라우터의 메모리를 확장하는 것을 방해하는 이유는 무엇입니까?

대부분의 경우 요구 사항은 전체 솔루션 비용에 대한 것이지만 때로는 폼 팩터도 중요한 역할을 합니다. 예를 들어 사이트에 TP-Link ML3020이 있는데, 유일한 USB 포트는 2G/3G 모뎀에 사용됩니다. 이 모든 것은 일종의 작은 플라스틱 케이스에 싸여 높은 곳(마스트 위)에 배치됩니다. 멀리, 멀리 (현장에서 가장 가까운 이동통신사 기지국에서 30km). 예, USB 허브를 연결하고 포트 수를 확장할 수 있지만 경험상으로는 이것이 번거롭고 신뢰할 수 없는 것으로 나타났습니다.

그래서 저는 여러분에게 저의 일반적인 상황을 설명하려고 했습니다. “멀리 떨어진 곳에 Linux를 실행하는 매우 중요하고 외롭고 작은 라우터가 있습니다. 적어도 하루에 한 번 그가 "살아있다"는 것을 아는 것이 중요하며, 필요한 경우 "여보, 재부팅!"과 같은 명령이 그에게 전송됩니다.

구현을 진행해 보겠습니다.

1) 라우터 측에서 cron을 통해 5/10/1440분마다 또는 원할 때마다 wget을 사용하여 서버에 http 요청을 보내고, 요청 결과를 파일에 저장하고, 파일을 실행 가능하게 만들어야 합니다. , 그리고 그것을 실행합니다.

내 크론 라인은 다음과 같습니다.

파일 /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는 서버측 스크립트의 이름입니다. 예, 변수 이름과 파일 이름을 같은 문자로 지정하는 것이 잘못되었다는 것을 알고 있습니다... 이렇게 하면 요청을 보낼 때 몇 바이트를 절약할 수 있습니다. :)
u - 사용자 이름, 하드웨어 로그인
p - 비밀번호
"-O /tmp/wa.sh"는 재부팅 명령과 같은 서버 응답이 저장되는 원격 라우터의 파일입니다.

두 번째 참고 사항: 아, 왜 컬을 사용하지 않고 wget을 사용합니까? 컬을 통해 GET이 아닌 POST를 사용하여 https 요청을 보낼 수 있기 때문입니다. 아아, 왜냐하면 "NE가 항아리 속으로 올라간다!"라는 오래된 농담처럼 말이죠. 컬에는 크기가 약 2MB인 암호화 라이브러리가 포함되어 있기 때문에 예를 들어 작은 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/ 폴더에 배치할 수 있습니다).

.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 웹 인터페이스를 열고 메뉴에서 선택합니다.
설정 -> 네트워크 노드 -> 네트워크 노드를 생성합니다. 여기에서는 네트워크 호스트의 이름, 해당 그룹 및 기본 에이전트 인터페이스를 지정하는 것으로 충분합니다.

포트 80을 통해 Lunix/OpenWrt/Lede 기반 장치의 원격 모니터링 및 제어…

이제 이 네트워크 노드에 대한 데이터 요소를 추가해야 합니다. 두 가지 필드에 주의하세요: "키" - 이것은 정확히 /etc/zabbix/zabbix_agentd.conf 파일에 작성한 매개변수입니다(우리의 경우에는 테스트입니다). 그리고 "업데이트 간격" - 저는 5분으로 설정했습니다. , 장비도 XNUMX분에 한 번씩 서버에 등록되기 때문입니다.

포트 80을 통해 Lunix/OpenWrt/Lede 기반 장치의 원격 모니터링 및 제어…

자, 그래프를 추가해 보겠습니다. 렌더링 스타일로 "채우기"를 선택하는 것이 좋습니다.

포트 80을 통해 Lunix/OpenWrt/Lede 기반 장치의 원격 모니터링 및 제어…

출력은 매우 간결합니다. 예를 들면 다음과 같습니다.

포트 80을 통해 Lunix/OpenWrt/Lede 기반 장치의 원격 모니터링 및 제어…

"그럴 가치가 있었나요?"라는 합리적인 질문에 저는 대답하겠습니다. 물론 기사 시작 부분에 있는 "자전거를 만드는 이유"를 참조하세요.

나의 첫 번째 그래픽 매니아 경험이 독자들의 관심을 불러일으킨다면 다음 기사에서 원격 장비에 명령을 보내는 방법을 설명하고 싶습니다. 또한 우리는 RouterOS(Mikrotik)를 기반으로 하는 장치에 대한 전체 체계를 구현했습니다.

출처 : habr.com

코멘트를 추가