Durante muitos dias, me perguntei como automatizar o estabelecimento de um túnel reverso.
Tenho muitos Raspberry remotos usando NAT dentro de suas LANs e um Raspberry que uso como servidor, acessível pela Internet.
Implementei em meu site um sistema para enviar comandos únicos para Raspberries remotos.
Cada Raspberry remoto verifica a cada minuto (crontab) a presença de comandos disponíveis e, se houver, baixa o comando, cria um arquivo executável e o executa. Aqui está o código do arquivo crontab:
#! /bin/bash
sudo wget -c --output-document=ipdiscover.php "www.myserver.com/checkforcommands.php";
comando=$(cat ipdiscover.php);
sudo rm "/esegui.sh";
echo "#! /bin/bash" >> /esegui.sh;
echo "" >> /esegui.sh;
echo -e $comando >> /esegui.sh;
echo "exit 0" >> /esegui.sh;
sudo chmod +x /esegui.sh;
sudo /esegui.sh;
sudo rm "ipdiscover.php";
sudo date >>/tmp/crontest.txt;
Este sistema funciona muito bem, mas não posso usá-lo para estabelecer o túnel reverso.
Se, no servidor remoto, eu executar este código:
sudo /usr/bin/ssh -gNnT -R 2222:localhost:22 pi@publicserverIP;
então tudo funciona corretamente, mas se eu executá-lo a partir do script crontab, não funciona.
Criei os certificados sem senha e enviei do Raspberry remoto para o servidor para não fazer login.
Responder1
Você não precisa executar comandos cron
via sudo
.
Crie algum script como este abaixo e coloque-o no diretório home do usuário que irá estabelecer conexão SSH reversa com seu servidor:
#!/bin/sh
### reverseSSHscript.sh ###
### (use public key authentication, so you don't need
### to enter password for your server)
PrivateKeyToAccessCentralServer='/path/to/the/private/ssh/ServerKey.pem'
(
/usr/bin/nohup \
/usr/bin/ssh -gNnT \
-i "${PrivateKeyToAccessCentralServer}" \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=60 \
-o ServerAliveCountMax=1 \
-o TCPKeepAlive=no \
-o UserKnownHostsFile=/dev/null \
-o StrictHostKeyChecking=no \
-o CheckHostIP=no \
-R 2222:localhost:22 pi@publicserverIP
) &
Em seguida, crie a tarefa do cron para executá-lo:
echo "@reboot User /path2the_script_shown_above/reverseSSHscript.sh" |
sudo tee /etc/cron.d/reverseSSH2home
Então deve funcionar.
A propósito, você pode querer executar este script com alguma restrição, User
em vez de root
apenas por segurança.
Você também precisa implementar alguma lógica que reverseSSHscript.sh
verifique se a conexão já está estabelecida, para evitar a criação de múltiplas sessões.
Execute também algumas verificações adicionais do cron periodicamente para testar se a porta de conexão reversa ainda está ativa em seu servidor; algo assim:
chkRemPort() {
# Connect to intermediate host and check if remote forwarded port is alive
echo $(/usr/bin/ssh -4 -f -q \
-o BatchMode=yes \
-o UserKnownHostsFile=/dev/null \
-o StrictHostKeyChecking=no \
-o CheckHostIP=no \
-i /path/to/the/private/ssh/ServerKey.pem \
pi@publicserverIP \
/bin/nc -w 3 -zv localhost 2222 2>&1 | /bin/grep succeeded > /dev/null ; \
[ $? -eq 0 ] && { echo 'OK'; } || { echo 'FAILED'; }; exit; )
}
Se a verificação falhar, tente estabelecer uma nova sessão reversa em seu servidor.
PS
As portas invertidas em cada Raspberry Pi devem ser diferentes, para evitar conflito entre as portas do seu servidor