Elmord's Magic Valley

Software, lingüística e rock'n'roll. Sometimes in English.

Truques com SSH

2017-01-24 19:40 -0200. Tags: comp, unix, network

Pous, nos últimos tempos eu aprendi algumas coisinhas novas sobre o SSH. Neste post relato algumas delas.

Port forwarding

O SSH possui duas opções, -L e -R, que permitem encaminhar conexões de uma porta local para um host remoto e vice-versa.

Porta local para um host remoto

Imagine que você está na sua máquina local, chamada midgard, e há uma máquina remota, chamada asgard, que é acessível por SSH. Você quer acessar um serviço na pora 8000 da máquina asgard a partir da máquina midgard, mas você quer tunelar o acesso por SSH (seja porque você quer que o acesso seja criptografado, ou porque a porta 8000 simplesmente não é acessivel remotamente). Você pode usar o comando:

midgard$ ssh -L 9000:127.0.0.1:8000 fulano@asgard

O resultado disso é que conexões TCP feitas para sua porta local 9000 serão tuneladas através da conexão com fulano@asgard para o endereço 127.0.0.1, porta 8000 na outra ponta. Por exemplo, se asgard tem um servidor web ouvindo na porta 8000, agora você vai poder abrir um browser em midgard, apontar para http://localhost:9000, e a conexão vai cair na porta 8000 de asgard, tudo tunelado por uma conexão SSH.

Note que o 127.0.0.1 é o endereço de destino do ponto de vista do servidor. Você poderia usar outro endereço para acessar outras máquinas na rede do servidor. Por exemplo, se a máquina vanaheim é acessível a partir de asgard, você poderia rodar:

midgard$ ssh -L 9000:vanaheim:8000 fulano@asgard

e agora todos os acessos à porta TCP 9000 da sua máquina local cairão na porta 8000 de vanaheim, tunelados através da conexão SSH com asgard.

Opcionalmente, você pode especificar um "bind address" antes da porta local, para especificar que apenas a porta 9000 de uma interface de rede específica deve ficar ouvindo por conexões. Por exemplo, você pode usar:

midgard$ ssh -L localhost:9000:vanaheim:8000 fulano@asgard

para dizer que a porta deve escutar apenas conexões da própria máquina. (Por padrão, que interfaces serão usadas é decidido pela opção GatewayPorts do cliente SSH, que defaulta para ouvir apenas na interface local de qualquer forma.) Alternativamente, pode-se passar um bind address vazio (i.e., :9000:vanaheim:8000, sem nada antes do primeiro :), para ouvir em todas as interfaces. Dessa maneira, outras máquinas na sua rede local que acessem a porta 9000 de midgard também terão o acesso tunelado para a porta 8000 de asgard. (* também funciona ao invés da string vazia, mas aí você tem que escapar o * para o shell não tentar expandir.)

Porta remota para a máquina local

Também é possível fazer o contrário: instruir o servidor SSH remoto a redirecionar alguma de suas portas para uma máquina e porta acessível a partir da sua máquina local. Para isso, utiliza-se a opção -R. Por exemplo:

midgard$ ssh -R 8000:localhost:22 fulano@asgard

Isso faz com que a porta 8000 em asgard seja tunelada para a porta 22 da máquina local. Agora, se alguém na máquina asgard acessar a porta 8000 (por exemplo, com ssh -p 8000 beltrano@localhost), a conexão vai cair na sua porta 22 local (e a pessoa terá acesso ao seu servidor SSH local). Você pode usar isso se você está atrás de um firewall ou NAT e a máquina remota é acessível pela Internet, mas a sua máquina local não, e você quer dar acesso a algum serviço da sua máquina local à máquina remota. (Já abordamos isso por aqui antes, mas menciono de novo for completeness.)

Proxy SOCKS

O SSH é capaz de funcionar como um proxy SOCKS. Para isso, utiliza-se a opção -D ("dynamic forwarding"):

midgard$ ssh -D localhost:8000 fulano@asgard

Isso faz com que o SSH ouça como um servidor SOCKS na porta 8000 da máquina local. Conexões recebidas nessa porta serão tuneladas para a máquina asgard, que funcionará como um proxy. Você pode então apontar o proxy SOCKS do seu browser ou outra aplicação para localhost, porta 8000.

Outras opções úteis

-C habilita compressão da conexão. E útil principalmente com conexões lentas (numa rede local, a compressão não compensa muito).

Por padrão, se você usa um dos comandos de redirecionamento de portas acima, o SSH faz o redirecionamento e abre uma sessão de shell comum. Se você quer apenas fazer o redirecionamento, pode usar as opções -N (não executa comando remoto) e -f (vai para background (forks) depois de pedir a senha). As opções podem ser combinadas em um único argumento (e.g., -CNf).

Escapes e comandos especiais

Em uma sessão SSH, a seqüência ENTER ~ é reconhecida como um prefixo de escape para acessar uma série de comandos especiais. Se você digitar ENTER ~ ?, verá uma lista de todos os comandos disponíveis:

Supported escape sequences:
 ~.   - terminate connection (and any multiplexed sessions)
 ~B   - send a BREAK to the remote system
 ~C   - open a command line
 ~R   - request rekey
 ~V/v - decrease/increase verbosity (LogLevel)
 ~^Z  - suspend ssh
 ~#   - list forwarded connections
 ~&   - background ssh (when waiting for connections to terminate)
 ~?   - this message
 ~~   - send the escape character by typing it twice
(Note that escapes are only recognized immediately after newline.)

O comando ENTER ~ C abre um prompt onde é possível fazer e cancelar redirecionamentos de porta, com uma sintaxe análoga à das opções vistas anteriormente:

ENTER ~ C
ssh> ?
Commands:
      -L[bind_address:]port:host:hostport    Request local forward
      -R[bind_address:]port:host:hostport    Request remote forward
      -D[bind_address:]port                  Request dynamic forward
      -KL[bind_address:]port                 Cancel local forward
      -KR[bind_address:]port                 Cancel remote forward
      -KD[bind_address:]port                 Cancel dynamic forward

Pasmem.

Observações

O uso das opções de redirecionamento pode ser controlado/desabilitado na configuração do servidor. Consulte a man page sshd_config(5) para mais informações.

2 comentários

SSH passivo/reverso

2012-10-03 15:31 -0300. Tags: comp, unix, network

Problema: queremos acessar uma máquina por SSH, mas a máquina "alvo" está atrás de um roteador que faz NAT e não é viável reconfigurar o roteador para redirecionar uma porta, ou a máquina está por trás de um firewall que não permite conexões de entrada.

Solução: o SSH tem uma feature chamada remote forwarding. Se você executa o comando:

ssh -R porta_remota:endereço_local:porta_local usuário@máquina_remota

Isso serve para encaminhar qualquer porta da máquina remota para a máquina local, mas em particular serve para encaminhar uma porta qualquer da máquina remota para a porta 22 (ssh) da máquina local. Na máquina que queremos acessar por SSH, executamos:

ssh -R 9000:127.0.0.1:22 usuário@máquina_a_partir_da_qual_queremos_fazer_o_acesso

Na máquina de onde queremos fazer o acesso, executamos:

ssh -p 9000 127.0.0.1

E pronto! Quando acessarmos a porta 9000 da máquina de origem, o SSH encaminhará a conexão para a porta 22 da máquina alvo, onde o servidor SSH da máquina alvo atenderá a conexão.

[* É possível ouvir em outras interfaces, ao invés de apenas a interface loopback. Basta usar -R bind_address:porta_remota:endereço_local:porta_local, especificando em que endereços se quer ouvir através do bind_address. Um bind_address vazio (i.e., :porta_remota:endereço_local:porta_local (note o : inicial)) ouve em todas as interfaces.]

Comentários

IP do futuro, vinte anos atrás

2012-05-23 01:08 -0300. Tags: comp, network

Disclaimer: este post não tem foco. ¡Viva Zapata!

Tudo começou quando eu meditava sobre o IPv6. A versão atual do IP (o IPv4, definido em 1981) usa endereços de 32 bits, o que dá cerca de 4 bilhões de endereços possíveis. Esse número já é pouco por si só (não dá para entregar um IP para cada pessoa no mundo, por exemplo), e para piorar a situação a galera dos anos oitenta distribuiu faixas de IPs de uma maneira ridiculamente esbanjadora (a sua máquina, por exemplo, possui nada menos do que 16 777 214 endereços locais: todos os endereços de host de 127.0.0.1 a 127.255.255.254). A fonte infinita de IPs começou a acabar no ano passado, com a exaustão dos IPs do IANA (órgão mundial responsável pela alocação de endereços IP, entre outras coisas) e da APNIC (organização à qual o IANA delega a alocação de IPs na Ásia e Oceania); os IPs das outras regiões hão de acabar em breve. Vale notar que já se está fazendo altas gambiarras há anos para contornar a exaustão, como o uso de NAT, que permite que várias máquinas em uma rede privada compartilhem do mesmo IP na Internet. O NAT destrói o princípio de dar um endereço único para cada máquina, e é o responsável por bagunçar seus torrents e complicar sua vida ao tentar acessar sua máquina de casa remotamente.

A solução em vias de adoção é o IPv6, definido em 1998. O IPv6 usa endereços de 128 bits, o que nos dá cerca de 340 undecilhões de endereços possíveis. (2128 = 340 282 366 920 938 463 463 374 607 431 768 211 456.) O espaço de endereçamento não vai acabar tão cedo, mesmo com os desperdícios que já se apressaram em fazer, a menos que comecemos a dar IPs únicos para moléculas.

Mas de qualquer forma, eu me perguntava: por que 128 bits? Por que não tornar o endereço um valor de tamanho arbitrário? Teríamos uma quantidade infinita de endereços, e evitaríamos desperdício com um campo mais longo do que precisa ser. A máquina que processa o pacote IP teria mais trabalho para decodificar o pacote, mas a diferença não é necessariamente significativa; na prática, a máquina/roteador teria um tamanho limite interno (e.g., 128 bits), e ao ler o pacote extrairia o endereço e o colocaria em um registrador/região de memória de tamanho fixo. A vantagem aqui é que se no futuro quisermos mais IPs, o protocolo permanece inalterado: quando esgotarmos o espaço de endereços de 64 bits, gradualmente atualizamos a infra-estrutura da rede para aumentar o limite de 128 para 256 bits; quando consumirmos 128, aumentamos de 256 para 512. Aumentando o limite (bem) antes do necessário, garantimos que o sistema que estamos construindo hoje funcionará corretamente pelos próximos dez ou vinte anos. (Você está escrevendo hoje os sistemas velhos de daqui a vinte anos. Já parou para pensar nisso?)

Um possível problema com simplesmente atribuir um natural a cada máquina é o roteamento: as tabelas de roteamento para faixas de números tenderiam a crescer cada vez mais. Uma solução seria usar valores estruturados hierarquicamente: o primeiro byte escolheria a sub-rede apropriada no nível mais alto da hierarquia, o segundo byte a sub-rede dentro dessa sub-rede, e assim por diante, com quantos níveis de hierarquia se quisesse. O caminho de roteamento está implícito na estrutura do endereço. O problema é que esgotada a capacidade de um nível de hierarquia, não é mais possível expandir o espaço de endereçamento desse nível sem renumerar as máquinas existentes (reorganizando a hierarquia para adicionar mais um nível, por exemplo). A menos que cada sub-rede também seja indicada com um número de tamanho arbitrário; um endereço, então, é uma lista de números naturais. A parte divertida é que você receberia do seu provedor um prefixo da lista, e poderia criar uma hierarquia qualquer sob esse prefixo, visível na Internet. Endereços de tamanho variável com campos de tamanho variável não parecem algo particularmente amigável à performance, entretanto.

Pelo visto a idéia de endereço de tamanho variável é tão antiga quanto a Internet. Segundo Vint Cerf, segundo a Wikipédia:

The decision to put a 32-bit address space on there was the result of a year's battle among a bunch of engineers who couldn't make up their minds about 32, 128, or variable-length. And after a year of fighting, I said—I'm now at ARPA, I'm running the program, I'm paying for this stuff, I'm using American tax dollars, and I wanted some progress because we didn't know if this was going to work. So I said: OK, it's 32-bits. That's enough for an experiment; it's 4.3 billion terminations. Even the Defense Department doesn't need 4.3 billion of everything and couldn't afford to buy 4.3 billion edge devices to do a test anyway. So at the time I thought we were doing an experiment to prove the technology and that if it worked we'd have opportunity to do a production version of it. Well, it just escaped! It got out and people started to use it, and then it became a commercial thing. So this [IPv6] is the production attempt at making the network scalable.

Na leitura page-down-driven que eu tinha feito desse artigo, entretanto, não tinha visto essa passagem. O que foi muito bom, pois eu saí a procurar se alguém já tinha proposto alguma coisa similar no mundo. Caí nesta página. O cara fala muito e diz pouco (ou eu estava de mau humor quando li esta e outras páginas dele). Ele propõe basicamente a mesma coisa que eu propus. Além disso ele propõe uma arquitetura chamada Nimrod (que não tem nada que ver com a linguagem de programação Nimrod), que implementa a idéia e resolve um outro problema que eu nunca tinha parado para pensar sobre: que a arquitetura IP mistura a noção de endereço (o meio para atingir uma máquina) com a noção de identificador da máquina. Se uma máquina tem mais de uma placa de rede, ela terá dois IPs, e não terá um identificador único. Se a máquina troca de IP, ela perde sua identidade, e as conexões abertas são perdidas.

Na minha busca por propostas de sucessores alternativos do IPv4, encontrei uma listinha de RFCs relevantes na Wikipédia. Uma delas, a descrição do TP/IX, de 1993, contém a seguinte pérola:

2.1 Is 64 Bits Enough?

Consider: (thought experiment) 32 bits presently numbers "all" of the computers in the world, and another 32 bits could be used to number all of the bytes of on-line storage on each computer. (Most have a lot less than 4 gigabytes on-line, the ones that have more could be notionally assigned more than one address.)

So: 64 bits is enough to number every byte of online storage in existence today, in a hierarchical structured numbering plan.

Far more than one address, camarada.

O TP/IX não é muito diferente do IPv4, sendo as principais diferenças os tamanhos dos endereços e de alguns outros campos. Em contraste com ele, temos a Pip Near-term Architecture. O Pip é uma daquelas coisas que cheiram a Common Lisp: overengineered, faz absolutamente tudo o que você já concebeu e tudo o que você não concebeu, e levanta suspeitas quanto a performance. Em resumo, it's The Right Thing. (Na prática, a performance do Pip provavelmente seria equiparável à do IP. (O paralelo com o Common Lisp é forte.)) Há muitas idéias interessantes no Pip, e vale a pena dar uma lida na RFC. O Pip usa um ID de tamanho fixo para identificar uma máquina, mas usa endereços hierárquicos de tamanho variável para identificar as redes. A RFC prevê o caso de o nível mais alto da hierarquia se esgotar, e sugere que não haveria grandes dificuldades em adicionar um novo nível acima do nível mais alto caso isso ocorresse. Segundo a RFC, algumas das idéias do Pip foram incorporadas ao SIPP (a.k.a. IPv6), mas não sei se essa informação reflete a encarnação atual do IPv6.

E vejam só o que eu descobri: na busca por propostas antigas de sucessores do IPv4, caí nesta página não sei mais como, e vejam só o que temos:

15 March 1992: A Revision of IP Address Classifications
Frank Solenski and Frank Kastenholz proposed C# (C-sharp) IP addresses. This Internet-Draft was available at the Big-Internet list.

¿Qué cosa, no?

Comentários

Main menu

Posts recentes

Comentários recentes

Tags

comp (114) prog (51) life (44) unix (32) random (27) lang (27) about (24) mind (22) mundane (21) pldesign (20) in-english (19) lisp (17) web (17) ramble (15) img (13) rant (12) privacy (10) scheme (8) freedom (8) lash (7) music (7) esperanto (7) bash (7) academia (7) home (6) mestrado (6) shell (6) conlang (5) copyright (5) misc (5) worldly (4) book (4) php (4) latex (4) editor (4) politics (4) etymology (3) wrong (3) android (3) film (3) tour-de-scheme (3) kbd (3) c (3) security (3) emacs (3) network (3) poem (2) cook (2) physics (2) comic (2) llvm (2) treta (2) lows (2) audio (1) wm (1) philosophy (1) kindle (1) pointless (1) perl (1)

Elsewhere

Quod vide


Copyright © 2010-2018 Vítor De Araújo
O conteúdo deste blog, a menos que de outra forma especificado, pode ser utilizado segundo os termos da licença Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International.

Powered by Blognir.