Proxy et SSH
Qui a dit que les connexions SSH et les proxys posent problème quand on veux les utiliser en même temps?
Je dis ça c’est pour le frime, ça m’a un peut cassé les pieds (pas longtemps) du coup j’ai cherché une solution pour pouvoir me connecter à mon serveur perso depuis la connexion de mon université et j’ai trouvé un petit truc tout simple que je m’en vais vous expliquer…
Tout d’abord il est nécessaire de connaitre un port ouvert dans le proxy. Le port 80 bien évidement mais si vous avez un serveur web il vous est utile… par contre il est possible que le 443 (https) ne vous serve pas. Si ces deux là sont utilisés par votre serveur, regardez du coté des ports correspondants au pop, imap, smtp… Dans mon cas ce sera le 443 mais ça ne change pas grand chose.
Le principe est simple, vous faites écouter votre serveur SSH sur un port qui est ouvert dans le proxy, pour cela :
#vi /etc/ssh/sshd_config
Et ajouter :
Port 443
Du coté serveur ça sera tout, sans oublier bien évidemment de redémarrer le service…
Coté Client maintenant il va falloir rajouter un script qui sera appelé lors de l’initialisation de la connexion SSH par le biais du fichier de configuration du client SSH.
Le script est relativement long, vous le trouverez donc en fin d’article afin de ne pas nuire à la lisibilité de ce dernier. Copiez/collez le ou vous voulez (je l’ai mis dans /usr/local/bin) avec le nom ssh-https-tunnel. Il est aussi disponible dans la “box” en page d’accueil. Il y a 2 ou 4 variables à modifier à partir de la ligne 33, tout d’abord le nom du proxy qui vous pose problème (ou son IP) puis son port d’écoute et éventuellement l’id/mdp que vous devez utiliser pour vous y connecter
Il faut maintenant modifier la configuration de votre client SSH afin qu’il utilise le script et nous allons en profiter pour automatiser un peut la connexion…
Pour cela nous allons éditer (créer) le fichier de configuration propre à votre utilisateur :
$ vi ~/.ssh/config
et ajoutez y cela :
host ma_connexion
hostname mon_serveur
user _mon_utilisateur
localforward 8000 127.0.0.1:8000
ProxyCommand /usr/local/bin/ssh-https-tunnel %h %p
Port 443
La première ligne signal que les lignes à suivre sont des ‘options’ pour la connexion ‘ma_connexion’.
La deuxième permet de spécifier l’hôte sur lequel se connecter.
Viens ensuite l’utilisateur qui sera utilisé pour se logger sur l’hôte.
La quatrième ligne configure dés la connexion une redirection de port (le port 8000 de l’hôte est renvoyé sur le port 8000 du pc qui a l’IP 127.0.0.1 ce qui n’est autre que l’ip local de la carte réseau de toute machine, aussi appelé localhost).
La cinquième ligne spécifie d’utiliser notre script précédent.
Enfin la dernière ligne renseigne sur le port d’écoute du serveur distant.
Avec tout cela, lorsque, dans une console, depuis un poste derrière un proxy, vous tapperez :
$ ssh ma_connexion
Votre PC se connectera directement avec l’utilisateur indiqué sur le serveur/port indiqué en effectuant les autres options, le tout à travers le proxy qui vous gênait… Cependant évitez de le dire à votre admin réseau, il pourrait faire la gueule :$
Merci à Mark Suter pour le script utilisé.
———————————– ssh-https-tunnel—————————————-
#!/usr/bin/perl -T -w
# Copyright (C) 2001,2002 Mark Suter <suter@humbug.org.au>
#
# This program tunnels a secure shell connection via a https proxy as
# the ProxyCommand program. The destination secure shell server needs
# to be running on port 443 unless the proxy is very lenient.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id: ssh-https-tunnel,v 2.7 2003/10/07 02:22:12 suter Exp $
use strict;
use IO::Socket;
use IO::Select;
################################
## Start User Configuration ##
################################
# Proxy details
my $host = “proxy”;
my $port = 8080;
# Proxy authentication (only if needed!)
my $user = “”;
my $pass = “”;
# Add an entry to ~/.ssh/config so “ssh remote.example.org” uses
# this program to proxy the connection.
#
# host remote.example.org
# Port 443
# ProxyCommand /path/to/ssh-https-tunnel %h %p
#
# Many proxies will timeout connections very quickly when there is
# no activity. If you ssh client supports it, add the following to the
# ~/.ssh/config file.
#
# ProtocolKeepAlives 5
#
# Another popular method is to X-Forward something like “xclock -update 5″
# to keep the connection “active.”
#
# If you are behind a Microsoft ISA server, this script can be used with
# http://apserver.sourceforge.net/ to tunnel connections out.
################################
## End User Configuration ##
################################
## Taken from “MIME::Base64::old_encode_base64″ to avoid that dependancy
sub auth_header($$) {
my ($user, $pass) = @_;
sub encode_base64 ($;$)
{
my $eol = $_[1];
$eol = “\n” unless defined $eol;
my $res = pack(“u”, $_[0]);
# Remove first character of each line, remove newlines
$res =~ s/^.//mg;
$res =~ s/\n//g;
$res =~ tr|` -_|AA-Za-z0-9+/|; # `# help emacs
# fix padding at the end
my $padding = (3 – length($_[0]) % 3) % 3;
$res =~ s/.{$padding}$/’=’ x $padding/e if $padding;
# break encoded string into lines of no more than 76 characters each
if (length $eol) {
$res =~ s/(.{1,76})/$1$eol/g;
}
return $res;
}
return “Proxy-Authorization: Basic ” . encode_base64 (“$user:$pass”, “1512″);
}
## Tunnel the connection and return a handle for it
sub tunnel_connect($$$$$$) {
my ($host, $port, $user, $pass, $remote_host, $remote_port) = @_;
my $socket = IO::Socket::INET->new(PeerAddr => $host, PeerPort => $port)
or die “$0: Can’t connect to $host:$port: $!\n”;
$socket->print(“CONNECT $remote_host:$remote_port HTTP/1.01512″,
$user ? auth_header($user, $pass) : “”,
“1512″) or die “$0: Can’t write: $!\n”;
local $/ = “12″;
my $response = $socket->getline() or die “$0: Can’t read: $!\n”;
$response =~ /^HTTP\/… 2/i or die “$0: CONNECT failed: $response”;
do { $response = $socket->getline() or die “$0: Can’t read: $!\n”; }
until $response =~ /^\s+$/;
return $socket;
}
## Move data from one handle to another
sub proxy_data($$) {
my ($source, $destination) = @_;
my ($buffer, $length, $offset, $bytes) = (“”, 0, 0, 0);
$length = sysread($source, $buffer, 4096, $offset) or return 0;
while ($length) {
$bytes = syswrite($destination, $buffer, $length, $offset) or return 0;
$offset += $bytes;
$length -= $bytes;
}
return 1;
}
## Check we have two arguments
defined $ARGV[0] and defined $ARGV[1] or die “Usage $0 <host> <port>\n”;
## Setup the tunnel
my $proxy = tunnel_connect($host, $port, $user, $pass, $ARGV[0], $ARGV[1]);
## Shift data around in each direction
my $sel = IO::Select->new( [ \*STDIN, $proxy ], [ $proxy, \*STDOUT ] );
SELECT: while (my @ready = $sel->can_read()) {
foreach my $handle (@ready) {
proxy_data($$handle[0], $$handle[1]) or last SELECT;
}
}