앞에서 Telegram BOT 강좌를 이용하여 텔레그램이 설치가 되었다면
라즈베리파이 내부에서만 텔레그램을 통해 메시지를 보낼수 있을것이다.
Telegram BOT 강좌 4부 참조
2015/07/21 - [강좌/RaspberryPI 활용] - 라즈베리파이 Telegram BOT 만들기 4부 - Telegram CLI 데몬 실행 및 서비스 등록
ex)
echo "msg 홍길동 메시지 보내봅니다" | nc localhost 8888
nc 뒤에 localhost 만 라즈베리파이의 IP로 변경하면 다른 장비에서도 사용 할 수 있지 않을까? 싶지만 작동하지 않는다.
echo "msg 홍길동 메시지 보내봅니다" | nc 192.168.0.199 8888
분명 -P 옵션으로 8888 포트를 열었지만 라즈베리파이 내부에서만 작동 하지 다른 장비에서는 작동하지 않는다.
그 비밀(?)은 바로 Telegram CLI 의 소스에 숨겨져 있다.
Telegram 소스가 위치한 경로로 이동해보자.
cd /home/pi/tg
여기에서 main.c 파일을 vi 또는 nano 에디터로 열어 보면
int main 함수 아래쪽 (필자는 919 라인에 있다)을 보자.
882 int main (int argc, char **argv) { 883 signal (SIGSEGV, termination_signal_handler); 884 signal (SIGABRT, termination_signal_handler); 885 signal (SIGBUS, termination_signal_handler); 886 signal (SIGQUIT, termination_signal_handler); 887 signal (SIGFPE, termination_signal_handler); 888 889 signal (SIGPIPE, SIG_IGN); 890 891 signal (SIGTERM, sig_term_handler); 892 signal (SIGINT, sig_term_handler); 893 894 rl_catch_signals = 0; 895 896 897 log_level = 10; 898 899 args_parse (argc, argv); 900 901 change_user_group (); 902 903 if (port > 0) { 904 struct sockaddr_in serv_addr; 905 int yes = 1; 906 sfd = socket (AF_INET, SOCK_STREAM, 0); 907 if (sfd < 0) { 908 perror ("socket"); 909 exit(1); 910 } 911 912 if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0) { 913 perror("setsockopt"); 914 exit(1); 915 } 916 memset (&serv_addr, 0, sizeof (serv_addr)); 917 918 serv_addr.sin_family = AF_INET; 919 serv_addr.sin_addr.s_addr = accept_any_tcp ? INADDR_ANY : htonl (0x7f000001); 920 serv_addr.sin_port = htons (port); |
919 라인에서 설정하는 저 부분 중 accept_any_tcp 플래그가 True 일때는 INADDR_ANY 를
FALSE 라면 htonl(0x7f000001) 값을 세팅하게 되어 있다.
htonl(0x7f000001) 이 값은 INADDR_LOOPBACK 이라는 플래그로 정의되어 있는데
LOOPBACK 네트워크의 접속만 허용하겠다 라는 의미이다.
몇일전 Telegram cli 소스에서는 accept_any_tcp 라는 항목이 없었는데 최근 소스에 추가가 되어 있다.
4부에서 데몬으로 실행할때 옵션에서 accept_any_tcp 라는 옵션만 더 추가하면 다른 네트워크에서도 접근이 가능한 소켓을 Listen 한다.
telegram-cli -h 를 해도 나오지 않는 항목이기 때문에 소스를 보지 않는 이상 알 수 없는 옵션이다.
(최근 소스를 받아보면 help 에 해당 옵션이 나온다)
bin/telegram-cli -s bot/basicbot.lua -P 8888 -e "contact_list" --accept_any_tcp -L /var/log/telegram.log -d & |
위 명령으로 데몬을 띄우면 다른 장비에서도 라즈베리파이의 IP와 8888 포트 정보를 이용하여
netcat 을 통해 메시지를 보낼 수 있다.
제목과 전혀 다른 내용이 전개 되었는데 PHP는 도대체 어디 간거야? 라는 의문이 있을것이다.
지금까지의 내용은 그냥 알아두기 수준으로만 하고 넘어가는것이 좋다.
왜냐하면 위와 같이 LOOPBACK 네트워크가 아닌 모든 네트워크에서 접속을 다 받을수 있다면 공격자가 라즈베리파이의 IP와 포트로 수많은 메시지를 보낼 수가 있게된다.
Telegram CLI 의 소켓은 보안성이 없고 그저 모든 명령을 다 받아 처리하게 되어 있기 때문에
심각한 보안 문제가 발생 할 수 있다.
telegram-cli 로 모르는 사람에게 온갖 스팸 메시지가 보내 질 수도 있는것이다.
필자는 LOOPBACK 으로만 소켓을 열고 php 를 이용해서 메시지를 전송한다.
준비 과정은 다음과 같다.
1. 라즈베리파이에 Apache+ php 또는 NginX + php 를 설치 한다.
웹서버와 php 를 설치하는 방법은 수많은 블로그에서 다루고 있으니 생략한다.
필자는 Apache + PHP 로 구성하였다.
2. php 파일을 작성한다.
PHP를 이용해서 텔레그램으로 메시지를 보내는 방법으로 다음과 같이 코딩하였다.
1. PHP에서 GET parameter 중 password 키를 지정하여 해당 Password 값과 일치 하지 않는다면 요청을 무시한다.
2. password 가 일치 한다면 Text File 을 전송 받는다.
3. 전송 받은 Text File을 Local Network 의 Telegram-CLI 에 전송 하도록 요청한다.
필자는 PHP 개발을 잘 몰라서 여기저기 구글링하여 다음과 같이 개발하였다.
<?php
header("Content-Type: text/html; charset=UTF-8");
// 4.1.0 이전의 PHP에서는, $_FILES 대신에 $HTTP_POST_FILES를
// 사용해야 합니다.
$pw=$_POST["password"];
// 뒷부분의 엄청나게 긴 패스워드는 'password' 라는 문자열을 SHA256 으로 해쉬한 결과값이다.
// 각 사용자는 자신의 고유 Password 를 설정하여 사용하면 된다.
$pwcmp = strcmp($pw, '5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8');
$tgsend_text_shell="/home/pi/tg/bot/shell/tgtext.sh";
$ipauth="/tmp/ipauth.txt";
// Password 가 일치하지 않는 경우 접속한 사용자의 IP를 텔레그램으로 전송
if($pwcmp){
echo "Unauthorized user";
ignore_user_abort(1);
$f = fopen($ipauth, "w");
$tp="(".date('Y/m/d-H:i:s').") ".$_SERVER['REMOTE_ADDR'];
fwrite($f, "인증되지 않은 사용자가 File Upload를 시도하였습니다\n");
fwrite($f, $tp."\n");
$pwtxt ="PASSWORD : ".$pw;
fwrite($f, $pwtxt."\n");
fwrite($f, $_SERVER['HTTP_USER_AGENT']."\n");
fclose($f);
exec($tgsend_text_shell." ".escapeshellarg($ipauth));
}else{
$uploaddir = '/tmp/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
echo "파일이 유효하고, 성공적으로 업로드 되었습니다.\n";
} else {
print "파일이 유효하지 않습니다!\n";
}
// 업로드 된 Text 파일을 Telegram 으로 전송한다.
exec($tgsend_text_shell." "."홍길동"." ".escapeshellarg($uploadfile));
}
?>
위 코드를 아래의 경로에 저장한다.
/var/www/tgcli.php
주의 :
위 코드에서 "5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8"
이 Password 부분은 각 사용자가 변경하여 사용하여야 한다.
필자는 SHA256 생성기 (http://www.convertstring.com/ko/Hash/SHA256) 를 이용해서 암호를 해쉬한 값을 사용한다.
위 Hash 코드는 'password' 라는 문자열을 SHA256으로 해쉬한 값이다. 그대로 사용하면 안된다.
좀 더 보안에 신경을 써야 한다면 php 파일 내부에 암호를 저장하는게 아닌 다른곳에 저장해두고 php에서 읽어오게 해야 더 좋을듯..
위와 같이 저장하였다면 90%는 성공이다.
이제 다른 장비에서 사용 하는 방법은 다음과 같다.
필자는 curl 이라는 유틸을 이용해서 사용한다.
다른 리눅스 장비에서 다음 명령어를 입력하여 실행해보자.
/tmp/temp.txt 파일을 라즈베리파이의 php 로 전송을 하는 명령어이다.
당연히 /tmp/temp.txt 파일이 있어야 한다.
모든 과정이 정상적으로 되었다면 텔레그램으로 해당 텍스트 파일의 내용이 전송 되었을 것이다.
위 php 파일을 응용하면 파일이 아닌 GET Parameter에 내용을 직접 전달 할 수도 있다.
이 강좌는 난이도가 조금 있습니다.
차근 차근 따라해 보시고 잘 안되는 부분이나 궁금하신 점은 질문 게시판을 이용해 주세요.
감사합니다.