Como Fazer um túnel com SSH
Imagine que você tenha um linux instalado numa intranet com ip não válido, por exemplo 192.168.1.10, e que nesta rede tenha um firewall rodando um NAT padrão.
Dai você deseja de fora pela internet acessar este seu linux que se encontra atrás do firewall. Mas você não tem nenhuma amizade com o administrador da rede para pedir um redirecionamento de portas, ou ele não permite pelas vias normais.
O que fazer??
Arregaçar as mangas e lançar mãos do interessante truque "SSH PORTFORWARD"
Com isto eu consigo fazer com que uma máquina interna faça um "forward" de qualquer porta para um maquina externa na internet de modo que eu possa capturar esta conexão mais tarde.
Primeiramente vou mostrar o modo mais básico de se fazer isto interativamente. Depois vou ensinar como automatizar pelo crontab.
Vou utilizar da seguinte nomenclatura::
REMOTEHOST = IP da Maquina na internet que você tem uma conta e roda sshd
REMOTEPORT = Porta tcp/ip na maquina remota que vai fazer o forward
LOCALHOST = IP da Maquina na intranet que vai receber o portforward
LOCALPORT = Porta tcp/ip da maquina da intranet que vai ser exportada
user = usuário que você loga na maquina remota
Com o ssh instalado você deve executar o seguinte comando:
Exemplo de como fazer um forward local do telnet para um porta numa maquina remota::
ssh -l user -R REMOTEPORT:LOCALHOST:LOCALPORT REMOTEHOST
Traduzindo em números para ficar mais fácil de visualizar::
ssh -l user -R 2323:192.168.1.10:23 200.200.200.200
Vai ser pedida a senha do usuário "user" na máquina de ip 200.200.200.200 Você digita a senha e deixa parado no prompt.
De qualquer outra maquina da internet você pode fazer::
telnet 200.200.200.200 2323
Que você cairá na maquina 192.168.1.10 da intranet. Muito legal !!!
Você não esta restrito a fazer forward somente de portas de sua maquina !! Pode especificar de qualquer uma da rede:
Exemplo::
ssh -l user -R 2222:192.168.1.99:22 200.200.200.200
Dai resgataria a conexão assim::
ssh -l user -p 2222 200.200.200.200
Você tem que às vezes remover o .ssh/know_hosts porque ele acumula chave de dois servidores de ssh diferentes e dá erro. Você pode remover somente a linha referente ao ip 200.200.200.200.
Mas este tipo de conexão é instável e portanto se você quer deixar isto um pouco mais estável deve fazer algum tipo de monitoramento da conexão e reiniciá-la quando necessário.
Eu sei que existem softwares para isto como vtun, rstunnel etc, mas tem que compilar e depender de outras bibliotecas...então elaborei uma solução simples que usa apenas ssh e bash :-)
Agora vou especificar a solução com mais detalhes.
Na máquina da intranet "LOCALHOST" vamos criar uma chave do ssh para ser possível logar sem senha no REMOTEHOST assim podemos colocar a conexão no crontab:
Tanto no LOCALHOST como no REMOTEHOST vou trabalhar com o usuário "user"
No LOCALHOST execute este comando::
ssh-keygen -t dsa
E dê enter sem colocar senha:
[root@192.168.1.10 root]# ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/root/.ssh/id_dsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_dsa.
Your public key has been saved in /root/.ssh/id_dsa.pub.
Depois copie o arquivo /root/.ssh/id_dsa.pub no REMOMEHOST em /home/user/.ssh/authorized_keys
O sshd_config que costuma ficar em /etc/ssh/sshd_config do REMOTEHOST precisa ter estas configuracoes abaixo par permitir o portforward::
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
GatewayPorts yes
AllowTcpForwarding yes
--
Uma vez feito isto você deve conseguir logar em REMOTEHOST sem senha através do comando: ssh -l user REMOTEHOST
Ultrapassado o passo acima podemos retirar a shell do user no REMOTEHOST. Edite o /etc/passwd:
user:*:1000:1000::0:0:User &:/home/user:/sbin/nologin
Já que para fazer o forward não precisa ter uma shell.
Com isto tudo preparado o comando para se conectar no REMOTEHOST fica assim::
ssh -l user -n -f -R REMOTEPORT:LOCALHOST:LOCALPORT -N REMOTEHOST
Explicando::
-l : seleciona o usuário que vai logar
-f : manda o ssh ir para background depois da execução
-n : desvia o stdin para /dev/null ou seja não aparece nada na terra, nem motd
-R : Faz o forward
-N : Não execute nenhum comando no REMOTEHOST (Por isto que podemos por a shell como nologin)
Com tudo isto montado eu fiz alguns scripts simples para rodar no crontab e garantir a conexão::
*/1 * * * * /root/bin/online.sh 200.200.200.200
0 */1 * * * /root/bin/uptime.sh 200.200.200.200
5 */1 * * * /root/bin/rmlock.sh 200.200.200.200
Estes scripts rodam em linux, não testei com freebsd, mas deve dar diferença porque o netstat é diferente.
O online.sh roda de 1 em 1 minuto para verificar se a conexão esta ativa, se não estiver ele reinicia a conexão.
Ele usa como parametro um arquivo para você dizer quais os forward que você quer fazer
- arquivo deve ter o seguinte nome: REMOTEHOST.ssh
Exemplo:
- 200.200.200.ssh:
#LOCALHOST:LOCALPORT:REMOTEHOST:REMOTEPORT 127.0.0.1:22:200.200.200.200:2222 127.0.0.1:23:200.200.200.200:2323 192.168.1.180:23:200.200.200.200:2301
O uptime.sh só para garantir de hora em hora mata todas as conexões e as restabelece.
- rmlock.sh remove o lock que o uptime.sh faz para impedir de encavalar online.sh com uptime.sh
Eu sei que está confuso, mas se alguém um dia for precisar vai entender :-))
Aqui estão os scripts:
online.sh::
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/root/bin
SERVER="$1"
FWFILE=/root/bin/$SERVER.ssh
export LANG=en
if [ -f /tmp/$SERVER ]
then
echo -e "Lock"
exit
fi
if netstat -nt tcp | grep "$SERVER:22" | grep -qi ESTABLISHED;
then
true
else
#killall -9 ssh
grep -v \# $FWFILE|\
while IFS=: read LOCALHOST LOCALPORT REMOTEHOST REMOTEPORT
do
ssh -n -f -l user -R $REMOTEPORT:$LOCALHOST:$LOCALPORT -N $REMOTEHOST
done
date | mail -s forward_update user@dominio.com.br
fi
uptime.sh:
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/root/bin
SERVER="$1"
FWFILE=/root/bin/$SERVER.ssh
export LANG=en
touch /tmp/$SERVER
netstat -ntp tcp | grep $SERVER |\
while read line ; do
set $line
proc=`echo $7 | cut -d/ -f1`
kill -9 $proc
done
grep -v \# $FWFILE|\
while IFS=: read LOCALHOST LOCALPORT REMOTEHOST REMOTEPORT
do
ssh -n -f -l user -R $REMOTEPORT:$LOCALHOST:$LOCALPORT -N $REMOTEHOST
done
date | mail -s forward_update user@dominio.com.br
rm -f /tmp/$SERVER
rmlock.sh:
#!/bin/bash
SERVER=$1
rm -f /tmp/$SERVER
E finalmente o ps.sh que server para ver os pid das conexões abertas: usa-se ps.sh 200.200.200.200
ps.sh:
#!/bin/bash
export LANG=en
SERVER=$1
netstat -ntp tcp | grep $SERVER |\
while read line ; do
set $line
proc=`echo $7 | cut -d/ -f1`
ps $proc
done
Esse tutorial lhe foi útil? Economizou tempo ou dinheiro? Que tal colaborar com o Cybershark? Qualquer dólar ajuda :) MUITO OBRIGADO!
Cadastro de usuarios
Gostaria de cadastra usuario no linux via windows, fazer um script que quando colocar passwd e senha no mesmo tempo sem precisar apertar a tecla enter. Se alguem poder me ajudar eu agradeço. Obrigado
Ajuda
Alguem conhece um servidor sshd na internet gratuito e com suporte a PORTFORWARD? Revirei tudo no Google e nao achei nada. Socorro!
sshd gratuito
Um servidor sshd gratuito e com suporte a PORTFORWARD é o OpenSSH. :-)
Parabens
gostei muito do vosso script, estava precisando disso... estou usando samba por tunel ssh via internet, isso ira me ajudar muito.
PARABENS PELO ARTIGO e SCRIPTS, OBRIGADO Huandel