Newsgroup: it.comp.lang.perl
Titolo: [complicato] nat-traverse e sockets

Salve,
     Sto cercando di creare una serie di scripts che mi permetta di 
trasferire files anche se si è dietro NAT o firewall.
Tempo fa mi è stato suggerito l'ottimo script "nat-traverse" 
http://linide.sourceforge.net/nat-traverse/
 che risiede da entrambe le 
parti -host server- e -host client- e lanciato quasi in contemporanea 
sulle due macchine crea un collegameno UDP tra di loro.
ad esempio:
user@left  $ nat-traverse 40000:natgw-of-right:40001
user@right $ nat-traverse 40001:natgw-of-left:40000
in pi aggiungendo "--cmd" come spiegato nel sito:
"The command will be run with its STDIN and STDOUT bound to the socket, 
i.e. everything the command writes to STDOUT will be forwarded to the 
peer."
sul computer server ho questo script (
stdin.pl
)
#!/usr/bin/perl
use strict;
use warnings;
use IO::Handle;
STDOUT->autoflush();
while ( defined($_ = <STDIN>) )
{
   print STDOUT $_ , "\n";
}
Ovvero...tutto quello che riceve lo deve rimandare al mittente
Sempre sul computer "server" eseguo:
nat-traverse --cmd="/usr/bin/perl /users/larry/
stdin.pl
" 
40000:user@client:40001
e quasi in contemporanea sul computer "client" eseguo:
nat-traverse 40001:user@server:40000
...perfetto, la connessione è avvenuta con successo e tutto quello che 
digito mi viene rispedito indietro...
Ora ho bisogno nel client di legare nat-traverse ad uno script che si 
metta in ascolto e che tutto quello che riceve lo spedisca a 
nat-traverse (che a sua volta lo rispedira a user@server)
questo è lo script (
socket.pl
)
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
use IO::Handle;
STDOUT->autoflush();
my $server = IO::Socket::INET->new(LocalPort => '9999', Proto => 'tcp', 
Reuse => 1) || die $!;
my $client;
my $buff;
while ( $server->listen() )
{
   $client = $server->accept();
   $client->autoflush(1);
   while(1)
   {
      recv($client, $buff, 1024, 0);
 
      print STDOUT $buff;
 
      while ( defined($_ = <STDIN>) )
      {     
         syswrite $client, $_;
      }
   }
}
close($server);
ora rilancio sul computer server:
nat-traverse --cmd="perl /users/larry/
stdin.pl
" 40000:user@client:40001
e sul computer client eseguo:
nat-traverse --cmd="perl /users/larry/
socket.pl
" 40001:user@server:40000
...la connessione avviene con successo e sempre sul computer client 
eseguo "netstat -an" e vedo che 
socket.pl
 è in ascolto su *.9999
ora mi collego con "nc 127.0.0.1 9999" e digito qualcosa...fantastico!!! 
mi viene rispedito indietro...vuol dire che tutto il sistema 
funziona...purtroppo se continuo a digitare non mi torna indietro pi 
niente...ma socket *.9999 è ancora in ascolto!!! cosa avr sbagliato?!?!?
in pi volevo sapere, quando in 
socket.pl
 mi trovo:
recv($client, $buff, 1024, 0);
print STDOUT $buff;
while ( defined($_ = <STDIN>) )
{     
   syswrite $client, $_;
}
quella recv è bloccante? e poi...quando sto in "while defined($_ = 
<STDIN>)" devo per forza aspettare di uscire dal ciclo per poter 
riscrivere in recv?
Spero che abbiate capito tutto quello che ho scritto...
grazie

 trasferire files anche se si è dietro NAT o firewall.
Ho fatto alcuni cambiamnti allo script server ed ora ho una connessione 
stabile client/server...tuttavia non posso chiudere le connessione di nc 
(infatti quando imposto nc come server accetta solo una connessione ed 
alla fine di essa nc si chiude)
Prima vorrei vorrei darvi un idea dello scenario:
HOST1 (user@client) dietro NAT
{
   Browser per connetersi ad internet
}
HOST2 (user@server) dietro NAT
{
   Apache running on port 80
}
Con il browser da HOST1 non posso collegarmi a HOST2 per ovvi motivi in 
quanto HOST2 non è visibile ne raggiungibile direttamente dall'esterno.
Da notare che "user@server" e "user@client" sono nomi fitizi, in verità 
questi test vengono fatti in locale usando 127.0.0.1 sia come server che 
come client.
**
dal lato client (user@client) chiamo lo script:
perl 
nat-traverse.pl
 --cmd="nc -lvp 65000" 40000:user@server:40001
in questo caso "nat-traverse" reindirizza il proprio STDIN e STDOUT a nc 
dopo essersi collegato con il "nat-traverse" che risiede sull'host 
server. La funzione di "nc" è di raccogliere richieste e spedirle nel 
tunnel UDP verso il server.
**
dal lato server (user@server) chiamo lo script:
perl 
nat-travesre.pl
 --cmd="perl 
server.pl
" 40001:user@client:40000
appena "nat-traverse" instaura la connessione con il "nat-traverse" 
residente sul computer client il proprio STDIN e STDOUT viene 
reindirizzato allo script "
server.pl
" di cui posto il codice:
#!/usr/bin/perl
use strict;
use warnings;
use lib "libwww-perl/lib";
use LWP;
use Data::Dumper;
use IO::Handle;
STDOUT->autoflush();
my (%header, $key, $req, $data, $browser, $res, $content);
$browser = LWP::UserAgent->new;
while(1)
{
   my $req = <STDIN>;
   while( defined($_ = <STDIN>) )
   {  
      s/[\r\n]+$//;
      last unless length $_;
      /^ ([\w\-]+) :[\ \t]+ (.+) $/x;
      $key = uc($1);
      $key =~ tr/-/_/;
      $header{$key} = $2
   }
 
   # $data = Dumper(\%header);
   # print STDOUT "HTTP/1.1 200 OK\n\nHello World!!!\n\n$req\n\n$data";
   $res = $browser->get("
http://127.0.0.1:80/
");
   $content = $res->content;
   print STDOUT $content;
}
__END__;
Questo script riceve la richiesta in uscita dal tunnel UDP e fa una cosa 
minima, richiede ad apache la pagina di default...index.html 
respidendola al mittente.
**
Da HOST1 ho "nc" in ascolto sulla porta 65000. (so che "nc" è un varco 
verso apache in ascolto su HOST2)
Mi collego tramite: nc 127.0.0.1 65000 e digito due volte a capo...con 
molto piacere ottengo come response: "HTTP/1.1 200 OK ...etc.." in poche 
parole mi viene riportata la semplice pagina html che risiede su HOST2. 
Sono riuscito a connettermi anche se entrambi gli HOST sono dietro NAT.
Tuttavia se da HOST1 apro il browser e digito: 
127.0.0.1:65000
 non viene 
restituito niente finchè non chiudo "nc" che è in ascolto...il che 
equivalerebbe ad un close($socket)
Come posso ovviare a questo? dovrei forse inserire un carattere di EOF?
Un'altra domanda, credete che sia sbagliato sparare tutto il contenuto 
di un file nel tunnel UDP tramite: print STDOUT $content; ?? credete che 
dovrei spedire chunks di 1024 bytes??
grazie mille

 grazie mille
Posso solo provare ad aiutarti con qualche ipotesi, per non mettere
in piedi tutta la tua infrastruttura.
1) questo STDOUT->autoflush(); sicuro che funzioni?
   prova STDOUT->autoflush(1);
2) while( defined($_ = <STDIN>) )
{
   # acquisizione headers HTTP
}
Questa non capisco come possa funzionare: Non puoi leggere fino a EOF
perche' il browser NON CHIUDERA' IN SOCKET.
Considera che il browser tipicamente esegue connessioni con
Connect: keep-alive
Non capisco come la prova con telnet possa funzionare.
Comunque credo che tu debba aspettare un (($_ = <STDIN>) eq "rn")
per la fine degli headers.
3) il 
nat-traverse.pl
 puo' introdurre un altro possibile livello
   di bufferizzazione?
Ciao
Roberto
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

    di bufferizzazione?
non credo
devo essere sincero...forse questo fatto del chiudere il socket non mi 
importa più di tanto...credo che il browser si regoli anche sul 
content-lenght restituito per sapere quando tutto il documento è 
arrivato.
ora il vero problema è che qualche volta "nc" esce ... come evitare 
questo? ecco perchè nell'altro post chiedo di come redirigere tramite 
fifo (named pipe)...
in pratica vorrei fare uno script bash in cui "nc" non esce mai, dato 
che risiede all'interno di un ciclo while true; do done;
ed è legato a STDIN e STDOUT di nat-traverse tramite due file speciali...
grazie