Pergunta (TL; DR)
Ao atribuir portas dinamicamente para encaminhamento remoto ( -R
opção aka ), como um script na máquina remota (por exemplo, proveniente de .bashrc
) determina quais portas foram escolhidas pelo OpenSSH?
fundo
Eu uso o OpenSSH (nas duas extremidades) para conectar-se ao nosso servidor central, que eu compartilho com vários outros usuários. Para a minha sessão remota (por enquanto), gostaria de encaminhar X, cups e pulseaudio.
O mais trivial é encaminhar o X, usando a -X
opção O endereço X alocado é armazenado na variável ambiental DISPLAY
e, a partir disso, posso determinar a porta TCP correspondente, na maioria dos casos. Mas quase nunca preciso, porque Xlib honra DISPLAY
.
Eu preciso de um mecanismo semelhante para copos e pulseaudio. O básico para ambos os serviços existe, na forma de variáveis ambientais CUPS_SERVER
e PULSE_SERVER
, respectivamente. Aqui estão alguns exemplos de uso:
ssh -X -R12345:localhost:631 -R54321:localhost:4713 datserver
export CUPS_SERVER=localhost:12345
lowriter #and I can print using my local printer
lpr -P default -o Duplex=DuplexNoTumble minutes.pdf #printing through the tunnel
lpr -H localhost:631 -P default -o Duplex=DuplexNoTumble minutes.pdf #printing remotely
mpg123 mp3s/van_halen/jump.mp3 #annoy co-workers
PULSE_SERVER=localhost:54321 mpg123 mp3s/van_halen/jump.mp3 #listen to music through the tunnel
O problema está definido CUPS_SERVER
e PULSE_SERVER
corretamente.
Usamos muito o encaminhamento de portas e, portanto, preciso de alocações dinâmicas de portas. Alocações de porta estática não são uma opção.
O OpenSSH possui um mecanismo para alocação dinâmica de porta no servidor remoto, especificando 0
como porta de ligação para encaminhamento remoto (a -R
opção). Usando o comando a seguir, o OpenSSH alocará dinamicamente portas para copas e encaminhamento de pulso.
ssh -X -R0:localhost:631 -R0:localhost:4713 datserver
Quando eu uso esse comando, ssh
imprimo o seguinte para STDERR
:
Allocated port 55710 for remote forward to 127.0.0.1:4713
Allocated port 41273 for remote forward to 127.0.0.1:631
Existe a informação que eu quero! Por fim, quero gerar:
export CUPS_SERVER=localhost:41273
export PULSE_SERVER=localhost:55710
No entanto, as mensagens "Porta alocada ..." são criadas na minha máquina local e enviadas para as STDERR
quais não consigo acessar na máquina remota. Curiosamente, o OpenSSH parece não ter meios de recuperar informações sobre encaminhamentos de portas.
Como obtenho essas informações para colocá-las em um script shell para definir adequadamente CUPS_SERVER
e PULSE_SERVER
no host remoto?
Becos-sem-saída
A única coisa fácil que pude encontrar foi aumentar a verbosidade sshd
até que essas informações possam ser lidas nos logs. Isso não é viável, pois essas informações divulgam muito mais informações do que é sensato tornar acessível por usuários não-root.
Eu estava pensando em aplicar um patch ao OpenSSH para oferecer suporte a uma sequência de escape adicional que imprime uma boa representação da estrutura interna permitted_opens
, mas mesmo se é isso que eu quero, ainda não consigo script acessando as seqüências de escape do cliente pelo lado do servidor.
Deve haver uma maneira melhor
A abordagem a seguir parece muito instável e está limitada a uma sessão SSH por usuário. No entanto, preciso de pelo menos duas sessões simultâneas e outros usuários ainda mais. Mas eu tentei ...
Quando as estrelas estão alinhadas corretamente, depois de sacrificar uma galinha ou duas, posso abusar do fato de sshd
não ter sido iniciado como meu usuário, mas eliminado privilégios após o login bem-sucedido, para fazer isso:
obter uma lista de números de porta para todos os soquetes de escuta que pertencem ao meu usuário
netstat -tlpen | grep ${UID} | sed -e 's/^.*:\([0-9]\+\) .*$/\1/'
obter uma lista de números de porta para todos os soquetes de escuta que pertencem aos processos que meu usuário iniciou
lsof -u ${UID} 2>/dev/null | grep LISTEN | sed -e 's/.*:\([0-9]\+\) (LISTEN).*$/\1/'
Todas as portas que estão no primeiro set, mas não no segundo set têm uma alta probabilidade de ser meus portos de encaminhamento e, na verdade subtrair os rendimentos conjuntos
41273
,55710
e6010
; copos, pulso e X, respectivamente.6010
é identificado como a porta X usandoDISPLAY
.41273
é a porta de copos, porquelpstat -h localhost:41273 -a
retorna0
.55710
é a porta de pulso, porquepactl -s localhost:55710 stat
retorna0
. (Ele até imprime o nome do host do meu cliente!)
(Para fazer a subtração definida I sort -u
e armazenar a saída das linhas de comando acima e use comm
para fazer a subtração.)
O Pulseaudio permite identificar o cliente e, para todos os efeitos, pode servir de âncora para separar as sessões SSH que precisam ser separadas. No entanto, eu não encontrei uma maneira de amarrar 41273
, 55710
e 6010
ao mesmo sshd
processo. netstat
não divulgará essas informações para usuários não raiz. Eu só recebo um -
na PID/Program name
coluna em que gostaria de ler 2339/54
(neste exemplo em particular). Tão perto ...
fonte
netstat
não mostrará o PID para processos que você não possui ou que são espaço no kernel. Por exemploRespostas:
Pegue dois (veja o histórico de uma versão que faz scp do lado do servidor e é um pouco mais simples); isso deve ser feito. A essência disso é esta:
Primeiro, configure no lado remoto, você precisa habilitar o envio de uma variável env na configuração do sshd :
Encontre a linha com
AcceptEnv
e adicioneMY_PORT_FILE
a ela (ou adicione a linha naHost
seção direita , se ainda não houver uma). Para mim, a linha tornou-se esta:Lembre-se também de reiniciar o sshd para que isso entre em vigor.
Além disso, para que os scripts abaixo funcionem, faça
mkdir ~/portfiles
no lado remoto!No lado local, um trecho de script que será
O trecho de script:
Em seguida, um trecho para o lado remoto, adequado para .bashrc :
Nota : É claro que o código acima não é exaustivamente testado e pode conter todos os tipos de bugs, erros de copiar e colar, etc. Qualquer pessoa que o utilize melhor também o entenderá, use por sua conta e risco! Testei-o usando apenas a conexão localhost e funcionou para mim no meu ambiente de teste. YMMV.
fonte
scp
do lado remoto para o local, o que não posso. Eu tinha uma abordagem semelhante, mas seria envolvidassh
em segundo plano depois de estabelecer a conexão, depois enviá-lo do local para o remoto viascp
e, em seguida, puxar ossh
cliente para o primeiro plano e executar um script no lado remoto. Não descobri como criar scripts de plano de fundo e primeiro plano para processos locais e remotos. Embrulhar e integrar ossh
cliente local a alguns scripts remotos como esse não parece ser uma boa abordagem.(while [ ... ] ; do sleep 1 ; done ; scp ... )&
. Em seguida, aguarde em primeiro plano no servidor.bashrc
(supondo que o cliente envie a variável env correta) para o arquivo aparecer. Atualizarei a resposta mais tarde após alguns testes (provavelmente não haverá tempo até amanhã).~/.ssh-${PID}-forwards
Um snippet para o lado local, adequado para .bashrc:
fonte
Consegui o mesmo criando um canal no cliente local e redirecionando o stderr para o canal que também é redirecionado para a entrada do ssh. Não requer várias conexões ssh para presumir uma porta conhecida livre que possa falhar. Dessa forma, o banner de logon e o texto "Porta alocada ### ..." são redirecionados para o host remoto.
Eu tenho um script simples no host
getsshport.sh
que é executado no host remoto que lê a entrada redirecionada e analisa a porta. Enquanto esse script não terminar, o encaminhamento remoto ssh permanecerá aberto.lado local
3>&1 1>&2 2>&3
é um pequeno truque para trocar stderr e stdout, para que o stderr seja canalizado para cat e toda a saída normal do ssh seja mostrada no stderr.lado remoto ~ / getsshport.sh
Eu tentei
grep
a mensagem "porta alocada" no lado local primeiro antes de enviá-lo através de ssh, mas parece que o ssh irá bloquear esperando o tubo para abrir em stdin. O grep não abre o pipe para escrever até receber algo, então isso basicamente gera um impasse.cat
no entanto, parece não ter esse mesmo comportamento e abre o canal para gravação imediatamente, permitindo que o ssh abra a conexão.este é o mesmo problema no lado remoto, e por que
read
linha por linha, em vez de apenas grep do stdin - caso contrário, `/ tmp / alocados 'não será gravado até que o túnel ssh seja fechado, o que derrota todo o propósito~/getsshport.sh
É preferível canalizar o stderr do ssh em um comando como , pois sem especificar um comando, o texto do banner ou o que mais estiver no pipe é executado no shell remoto.fonte
renice +10 $$; exec cat
antes dodone
para economizar recursos.Essa é uma manipulação complicada, do lado do servidor, semelhante
SSH_CONNECTION
ouDISPLAY
seria ótima, mas não é fácil de acrescentar: parte do problema é que apenas ossh
cliente conhece o destino local, o pacote de solicitação (para o servidor) contém somente o endereço e a porta remotos.As outras respostas aqui têm várias soluções despretensiosas para capturar esse lado do cliente e enviá-lo ao servidor. Aqui está uma abordagem alternativa que não é muito mais bonita para ser honesta, mas pelo menos essa parte feia é mantida no lado do cliente ;-)
SendEnv
para que possamos enviar algumas variáveis de ambiente nativamente pelo ssh (provavelmente não padrão)AcceptEnv
para aceitar o mesmo (provavelmente não ativado por padrão)ssh
saída do stderr do cliente com uma biblioteca carregada dinamicamente e atualize o ambiente do cliente ssh durante a configuração da conexãoIsso funciona (felizmente, por enquanto, de qualquer maneira) porque os encaminhadores remotos são configurados e registrados antes da troca do ambiente (confirme com
ssh -vv ...
). A biblioteca carregada dinamicamente precisa capturar awrite()
função libc (ssh_confirm_remote_forward()
→logit()
→do_log()
→write()
). Redirecionar ou agrupar funções em um binário ELF (sem recompilar) é uma ordem de magnitude mais complexa do que fazer o mesmo para uma função em uma biblioteca dinâmica.No cliente
.ssh/config
(ou linha de comando-o SendEnv ...
)No servidor
sshd_config
(é necessária alteração raiz / administrativa)Essa abordagem funciona para clientes Linux e não requer nada de especial no servidor; deve funcionar para outros * nix com alguns pequenos ajustes. Funciona de pelo menos OpenSSH 5.8p1 a 7.5p1.
Compilar com
gcc -Wall -shared -ldl -Wl,-soname,rfwd -o rfwd.so rfwd.c
Invoke com:O código:
(Existem algumas armadilhas glibc bear relacionadas ao versionamento de símbolo com essa abordagem, mas
write()
não há esse problema.)Se você se sente corajoso, pode pegar o
setenv()
código relacionado e corrigi-lo nassh.c
ssh_confirm_remote_forward()
função de retorno de chamada.Isso define variáveis de ambiente nomeadas
SSH_RFWD_nnn
, inspecione-as no seu perfil, por exemplo, embash
Ressalvas:
ssh
no momento, não registra claramente o encaminhamento completo do formulário * local: port: remote: port * (se necessário, é necessária uma análise adicional dedebug1
mensagensssh -v
), mas você não precisa disso para o seu caso de usoVocê pode (em parte) fazer isso de maneira interativa com a fuga
~#
, estranhamente a implementação ignora os canais que estão ouvindo, apenas lista os abertos (por exemplo, TCP ESTABELECIDO) e, em nenhum caso, imprime os campos úteis. Vejochannels.c
channel_open_message()
Você pode corrigir essa função para imprimir os detalhes dos
SSH_CHANNEL_PORT_LISTENER
slots, mas isso apenas fornece os encaminhamentos locais (os canais não são a mesma coisa que os encaminhamentos reais ). Ou você pode corrigi-lo para despejar as duas tabelas de encaminhamento daoptions
estrutura global :Isso funciona bem, embora não seja uma solução "programática", com a ressalva de que o código do cliente (ainda está sinalizado como XXX na fonte) atualiza a lista quando você adiciona / remove encaminhamentos on-the-fly (
~C
)Se o (s) servidor (es) for Linux, você tem mais uma opção, essa é a que eu geralmente uso, embora seja para encaminhamento local e não remoto.
lo
é 127.0.0.1/8, no Linux você pode vincular de forma transparente a qualquer endereço no 127/8 ; portanto, você pode usar portas fixas se usar endereços 127.xyz exclusivos, por exemplo:Isso está sujeito à ligação de portas privilegiadas <1024, o OpenSSH não suporta recursos Linux e possui uma verificação de UID codificada na maioria das plataformas.
Os octetos sabiamente escolhidos (mnemônicos ordinais ASCII no meu caso) ajudam a desembaraçar a bagunça no final do dia.
fonte