Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

PERL IO::Socket

22 views
Skip to first unread message

Flavio Bosio

unread,
Dec 9, 2011, 11:07:55 AM12/9/11
to
Dovrebbe essere semplice, vado di tcpdump

tcpdump -nnvvvS -s 0 -U -w sniff.ocsp.pcap port 2560

quindi tramite Wireshark faccio Analize -> Follow TCP Stream
====================
POST / HTTP/1.0
Content-Type: application/ocsp-request
Content-Length: 105

0g0e0>0<0:0...+............$..Qp'....h.......qQ...4...j.v.?..s.......#0!0...+.....0......#P.Qd.;oa..M....
HTTP/1.0 200 OK
Content-type: application/ocsp-response
Content-Length: 1231

0...
......0.....+.....0......0...0....m0k1.0...U....IT1.0...U...
====================

In pratica il client invia 4 linee di header (compreso \r\n/) e il
file req.der il server (la parte che mi interessa) invia 4 linee di
risposta ed il file di risposta, fine della trasmissione.

ora, qualcuno ha idea del perché se faccio:

#!/usr/bin/perl
use IO::Socket;

my $server = IO::Socket::INET->new(
Listen => 5,
LocalAddr => '192.168.1.10',
LocalPort => 2560,
Proto => 'tcp'
) or die "Can't create server socket: $!";
$server->autoflush(1);


while ($client = $server->accept()) {
$client->autoflush(1);
while (<$client>)
{
print $_;
}

lancio il client

===================
#!/bin/bash
openssl ocsp -issuer cacert.pem \
-nonce \
-CAfile cacert.pem \
-cert 03.pem \
-url http://www....com:2560 \
-resp_text
====================

e lato server vedo le 4 stringhe

======
POST / HTTP/1.0
Content-Type: application/ocsp-request
Content-Length: 105

======

dopodiché s'impalla restando fermo, ma se lato client vado di ctrl+c
lato server riceve e stampa anche il resto.

Come la sfango?



bio

unread,
Dec 12, 2011, 6:50:41 AM12/12/11
to
> e lato server vedo le 4 stringhe
>
> ======
> POST / HTTP/1.0
> Content-Type: application/ocsp-request
> Content-Length: 105
>
> ======
>
> dopodiché s'impalla restando fermo, ma se lato client vado di ctrl+c
> lato server riceve e stampa anche il resto.

Devi onorare Content-Length: il tuo server perl deve "sapere" che l'input
dovrà considerarsi concluso quando saranno stati trasmessi $contentLength
byte (in questo caso 105) e comportarsi di conseguenza.


Fabio

Flavio Bosio

unread,
Dec 12, 2011, 8:22:23 PM12/12/11
to
Il 12/12/11 12.50, bio ha scritto:

>> dopodiché s'impalla restando fermo, ma se lato client vado di ctrl+c
>> lato server riceve e stampa anche il resto.
>
> Devi onorare Content-Length: il tuo server perl deve "sapere" che l'input
> dovrà considerarsi concluso quando saranno stati trasmessi $contentLength
> byte (in questo caso 105) e comportarsi di conseguenza.

Mi sarò espresso male, segue esempio:

se faccio un semplice client:
==============
#!/usr/bin/perl -w
use IO::Socket;
use strict;
my $server = IO::Socket::INET->new(
PeerAddr => '192.168.1.10',
PeerPort => 2560,
Proto => 'tcp',
);
die "Can't create client socket: $!\n" unless $server;;

print $server "POST / HTTP/1.0\n";
print $server "Content-Type: application/ocsp-request\n";
print $server "Content-Length: 105\n";
print $server "\r\n";

open FILE, "<req.pem" or die "Can't open: $!";
binmode FILE;
while (<FILE>) {
print $server $_;
}
close FILE;

close($server);

===============

lato server vedo correttamente come ci si aspetterebbe

POST / HTTP/1.0
Content-Type: application/ocsp-request
Content-Length: 105

MGcwZTA+MDwwOjAJBgUrDgMCGgUABBT58QaHJAzeUXAn9g6XtGiy2IsVuQQUcVGA
mhc0nIWGagB2xD/OqnMd9xECAQOiIzAhMB8GCSsGAQUFBzABAgQSBBD9AtP24ybs
eYRCb8ilwDV4

ovvero l'header che ho inviato seguito dal contenuto del file req.pem,
ora, che ci sia un *Content-Length* nel mezzo a Perl dubito che importi
qualcosa, quello serve a me poi, ma per lui è una semplice sequenza di
caratteri ASCII che invia al server..

Il problema è che se anziché il suddetto script utilizzo openssl per
qualche motivo che al momento non comprendo si impalla dopo l'invio
dell'header come se aspettasse una risposta dal server (che in genere
può essere una stringa tipo HTTP/1.0 200 OK) ma dato che la
comunicazione tra client e server è stata sniffata con tcpdump e non
presenta nessuna risposta tra l'invio dell'header ed il body del file
che si fa?






CtRiX

unread,
Dec 13, 2011, 5:52:11 AM12/13/11
to
Il Tue, 13 Dec 2011 02:22:23 +0100, Flavio Bosio ha scritto:

> Il problema è che se anziché il suddetto script utilizzo openssl per
> qualche motivo che al momento non comprendo si impalla dopo l'invio
> dell'header come se aspettasse una risposta dal server (che in genere
> può essere una stringa tipo HTTP/1.0 200 OK) ma dato che la
> comunicazione tra client e server è stata sniffata con tcpdump e non
> presenta nessuna risposta tra l'invio dell'header ed il body del file
> che si fa?

Parto dalla tua conclusione.
Si fa che si parla del problema che, se non è lato client, è lato server
(che non hai descritto, mi pare).

Che cosa usi lato server ?
L'hai scritto tu o è un prodotto di pubblico dominio ?

Perchè se l'hai scritto tu, allora sono tutti "ricchi cazzi tuoi" e senza
esempi è difficile aiutarti.

Se è un prodotto di pubblico dominio o un server HTTP tradizionale
dovresti studiare.


> print $server "POST / HTTP/1.0\n";
> print $server "Content-Type: application/ocsp-request\n"; print $server
> "Content-Length: 105\n"; print $server "\r\n";

Devi *Sempre* usare, da specifica HTTP, \r\n come "a capo".
Non devi usarlo solo per il terminatore degli headers.

> open FILE, "<req.pem" or die "Can't open: $!";
> binmode FILE;
> while (<FILE>) {
> print $server $_;
> }
> close FILE;
>
> close($server);

Qui non si capisce cosa stai facendo.

>
> ===============
>
> lato server vedo correttamente come ci si aspetterebbe
>
> POST / HTTP/1.0
> Content-Type: application/ocsp-request Content-Length: 105
>
> MGcwZTA+MDwwOjAJBgUrDgMCGgUABBT58QaHJAzeUXAn9g6XtGiy2IsVuQQUcVGA
> mhc0nIWGagB2xD/OqnMd9xECAQOiIzAhMB8GCSsGAQUFBzABAgQSBBD9AtP24ybs
> eYRCb8ilwDV4

Qui invece si capisce che non stai facendo correttamente.

Come ti era stato segnalato, il content-length ha una sua importanza,
altrimenti non ci sarebbe.

DEVI e sottolineo DEVI impostarlo pari alla lunghezza del payload che
stai inviando.

*SICURAMENTE* 105 non è corretto come valore perchè stai inviando molti
più dati.

> ovvero l'header che ho inviato seguito dal contenuto del file req.pem,
> ora, che ci sia un *Content-Length* nel mezzo a Perl dubito che importi
> qualcosa, quello serve a me poi, ma per lui è una semplice sequenza di
> caratteri ASCII che invia al server..

Visto che il problema te lo hanno evidenziato e visto che continui a dire
che non ti interessa, il mio consiglio è di andarti a studiare qualche RFC
giusto perchè procedere a tastoni di solito fa perdere tempo.


Poi se usi il tuo di server, allora il discorso, come ti ho detto, cambia.
Ed in particolare:
- se usi come trasporto il protocollo HTTP, allora studiatelo ed
implementalo correttamente
- se usi come trasporto qualcosa di tua invenzione che è simile all'http,
allora senza capire cosa vuoi fare c'è poco da aiutarti.


Ah, dimenticavo.
icol.sys può non essere il NG Adatto.
Qualcosa sul perl o sulla programmazione lo è di più.

bio

unread,
Dec 13, 2011, 6:30:53 AM12/13/11
to
> ovvero l'header che ho inviato seguito dal contenuto del file req.pem,
> ora, che ci sia un *Content-Length* nel mezzo a Perl dubito che importi
> qualcosa, quello serve a me poi, ma per lui è una semplice sequenza di
> caratteri ASCII che invia al server..

Al client non interessa perchè... è una informazione per il server (in
questo caso). Il tuo server perl non funziona proprio perchè non legge
l'header Content-Lenght e, quindi, non sa che la trasmissione è finita
e deve elaborare i dati, come previsto dal protocollo HTTP. Quando usi
lo stesso server perl col client perl funziona perchè hai la riga...

> print $server "\r\n";

che indica al tuo server perl che la trasmisisone è finita e ti stampa
il contenuto del buffer. Openssl invece parla HTTP vero e non ti invia
alcun "\r\n", perchè si aspetta che il server dall'altra parte parli a
a sua volta HTTP e usi Content-Lenght per il controllo di flusso.

Se vuoi ti riassumo così: il tuo server perl non è una implementazione
valida di HTTP e quindi non può parlare con un client HTTP.


Fabio

CtRiX

unread,
Dec 13, 2011, 7:27:16 AM12/13/11
to
Il Tue, 13 Dec 2011 12:30:53 +0100, bio ha scritto:

> Al client non interessa perchè... è una informazione per il server (in
> questo caso). Il tuo server perl non funziona proprio perchè non legge
> l'header Content-Lenght e, quindi, non sa che la trasmissione è finita e
> deve elaborare i dati, come previsto dal protocollo HTTP. Quando usi lo
> stesso server perl col client perl funziona perchè hai la riga...

Al client interessa l'header quando è nella risposta del server.
Obbligatorio per HTTP/1.1, facoltativo in HTTP/1.0 ma sempre utile per
scoprire, in quest'ultimo caso, degli short-read che non hanno fornito
tutto il contenuto.

> Se vuoi ti riassumo così: il tuo server perl non è una implementazione
> valida di HTTP e quindi non può parlare con un client HTTP.

Mi pare abbia incollato il codice di un client, non di un server.

Flavio Bosio

unread,
Dec 13, 2011, 8:34:06 AM12/13/11
to
Il 13/12/11 13.27, CtRiX ha scritto:
Ok ho fatto un passo avanti spero..

se invio al server un file encoded base64 vedo

POST / HTTP/1.0
Content-Type: application/ocsp-request
Content-Length: 105

MGcwZTA+MDwwOjAJBgUrDgMCGgUABBT58QaHJAzeUXAn9g6XtGiy2IsVuQQUcVGA
mhc0nIWGagB2xD/OqnMd9xECAQOiIzAhMB8GCSsGAQUFBzABAgQSBBD9AtP24ybs
eYRCb8ilwDV4

ma se lo invio in formato .der il server s'impalla dopo l'header ed il
client resta appeso

Ovviamente il server è ultra minimale ed ha il solo scopo di
visualizzare ciò che arriva effettivamente dal client

#!/usr/bin/perl -w
use IO::Socket;
$local = IO::Socket::INET->new(
Proto => 'tcp',
LocalPort => '2560',
Listen => SOMAXCONN,
Reuse => 1
) or die "$!";
$local->autoflush(1);

my $addr;
while ($addr = $local->accept()) {
my $result;
while (<$addr>) {
print "$_";
}
close $addr;
}


quindi penso sia legato alla modalità di invio binario del file.. indago.

bio

unread,
Dec 13, 2011, 8:35:42 AM12/13/11
to
> > Al client non interessa perchè... è una informazione per il server (in
> > questo caso). Il tuo server perl non funziona proprio perchè non legge
>
> Al client interessa l'header quando è nella risposta del server.

Immagino non ti sia sfuggito il "in questo caso".

> Mi pare abbia incollato il codice di un client, non di un server.

Quello del server è nel post precedente.


Fabio

CtRiX

unread,
Dec 13, 2011, 8:44:38 AM12/13/11
to
Il Tue, 13 Dec 2011 14:34:06 +0100, Flavio Bosio ha scritto:

> quindi penso sia legato alla modalità di invio binario del file..
> indago.

Ancora non si è capito cosa vuoi fare.
Consiglio:

1) leggiti le RFC di HTTP/1.0 e 1.1. Servono.

2) chiarisci bene *cosa* devi fare. Se il tuo scopo è scrivere un client,
scrivere un server o scriverli entrambi.

CtRiX

unread,
Dec 13, 2011, 9:06:41 AM12/13/11
to
Il Fri, 09 Dec 2011 17:07:55 +0100, Flavio Bosio ha scritto:

> dopodiché s'impalla restando fermo, ma se lato client vado di ctrl+c
> lato server riceve e stampa anche il resto.
>
> Come la sfango?

Comunque con quel codice il perl va a leggere riga per riga.

Se la fine della riga (Del payload) non contiene un EOL, la lettura non
ritorna e quindi il server rimane in attesa.
Quando interrompi il client, chiudi il socket ed il server esce dal loop.

Come ti è stato detto devi andare a ONORARE il content length e leggere
in input SOLO quei bytes indicati nel content length.

Flavio Bosio

unread,
Dec 13, 2011, 9:31:36 AM12/13/11
to
Il 13/12/11 14.44, CtRiX ha scritto:
Vorrei fare il server, come client useremo openssl.

Ricapitolando, da qualche test fatto il problema stà nell'invio del file
binario,

In pratica il file binario è privo di eof il ché impalla il server

Questo lo si capisce manipolando il client PERL dato che il client
openssl non è manipolabile, per cui se inserisco un

print $server "\n";

dopo aver inviato il contenuto del file .der ed imposto il server in
binmode passa tutto e vedo

POST / HTTP/1.0
Content-Type: application/ocsp-request
Content-Length: 105

0g0e0>0<0:0 +???$
?Qp'???h?؋?qQ??4???jv??Ϊs??#0!0 +0???g ?4?Eo~5^?<?

il problema quindi è riuscire a far si che il server non si pianti ma
come impedirlo se il file è privo di eof?

Flavio Bosio

unread,
Dec 13, 2011, 9:32:27 AM12/13/11
to
Il 13/12/11 15.06, CtRiX ha scritto:
Ok e come si fa?

Quasimodo

unread,
Dec 13, 2011, 9:35:25 AM12/13/11
to
Conti i byte ricevuti!

Flavio Bosio

unread,
Dec 13, 2011, 9:54:30 AM12/13/11
to
Il 13/12/11 15.35, Quasimodo ha scritto:

>> Ok e come si fa?
>
> Conti i byte ricevuti!

Ok ma mi sono impallato con la lettura

#!/usr/bin/perl -w
use IO::Socket;
my $port=shift || die "Usage server.pl <port>\n";
my $server = IO::Socket::INET->new( Proto => 'tcp',
LocalPort => $port,
Listen => SOMAXCONN,
Reuse => 1);
die "can't setup server" unless $server;

binmode $server;

while ($client = $server->accept()) {
$client->autoflush(1);

binmode $client;
my $cl;
my $content;
my $n;
while(my $line = <$client>)
{
next if($line =~ /^POST \/ HTTP\/1.0/);
next if($line =~ /^Content-Type: application\/ocsp-request/);
if($line =~ /Content-length:/isg)
{
($cl) = $line =~ /Content-Length: ([0-9]+)/i;
}
next if($line =~ /^Content-Length:/);
next if($line =~ /^\r\n/);

#print "$line";
#qui andrebbe la funzione di lettura
#read FILEHANDLE, SCALAR, LENGTH

open(IN, ">in.der") or die "can't open in.der\n";
binmode(IN);
print IN $content;
close IN;


}

#risposta al client <>

close $client;
}



CtRiX

unread,
Dec 13, 2011, 10:07:29 AM12/13/11
to
Il Tue, 13 Dec 2011 15:32:27 +0100, Flavio Bosio ha scritto:

> Ok e come si fa?

Guarda, i consigli sono due:
1) cerca di capire i socket, l'accesso concorrente di più client e l'HTTP
come protocollo.
Questo ti serve per capire cosa stai facendo e i potenziali problemi a
cui vai incontro.
Se un giorno avrai bug o problemi col codice, le informazioni che ti ho
consigliato di studiare sono *fondamentali* per il problem solving

2) parallelamente al punto 1) il perl ha il vantaggio che esiste già
scritto quasi tutto.
Quindi, senza reinventare la ruota, usa google per trovare un modulo
carino che implementi già un server web.
Risparmi sicuramente tempo.

Darkbyte

unread,
Dec 14, 2011, 7:04:06 AM12/14/11
to
Io bazzico il Perl da poco, e non vorrei per questo dire un'amenità,
però credo che il problema sia nel while(my $line = <$client>), nel
senso che tu tenti di leggere dal sock una "linea" di testo, quindi
resti in attesa di ricevere un dato con un \n alla fine e questo va
bene finché devi ricevere le prime quattro linee del client.
Però una volta intercettata la linea "\r\n" dovresti uscire dal while
e leggere i dati dal sock in modo "binario" fino ad aver ricevuto la
quantità di byte indicati in precedenza nel content-length. Solo a
quel punto il tuo script può tornare ad effettuare la lettura nella
modalità "testo" del tipo while ($line = <$client>).

Flavio Bosio

unread,
Dec 14, 2011, 10:05:24 AM12/14/11
to
Il 14/12/11 13.04, Darkbyte ha scritto:
E qui si impiastra il tutto, se leggo while(my $line =<$client>)
estrapolo il content-length e tento di leggere in binario non funziona,
se invece leggo tutto in binario allora funziona ma non posso leggere il
parametro content-length.

al momento ho una versione perfettamente funzionante con

my ($header, $data);
my $data_header = recv($client, $header, 80, 0);
my $from_client = recv( $client, $data, 106,0);
my $length = length($data);

ma questo funziona solo a patto che l'header sia 80 e i dati 105 cosa
non sempre vera dato che openssl legge dal certificato l'Authority
Information Access e nel caso trova

OCSP - URI:http://ocsp.infocert.it/OCSPServer_ICE/OCSPServlet

imposta l'header con

POST /OCSPServer_ICE/OCSPServlet HTTP/1.0
Content-Type: application/ocsp-request
Content-Length: 107

il ché ci riporta al problema di leggere sto benedetto Content-Length

Flavio Bosio

unread,
Dec 14, 2011, 10:51:04 AM12/14/11
to
Il 14/12/11 13.04, Darkbyte ha scritto:
Ecco come ho risolto:


while ($client = $server->accept()) {
$client->autoflush(1);

my $data;
my $from_client = recv( $client, $data, 1024,0);

open(IN, ">in.der") or die "can't open in.der\n";
binmode(IN);
print IN $data;
close IN;

open(FILE, "<in.der");
open(FILEOUT,">myout.der");
binmode(FILEOUT);
binmode(FILE);

while(my $line =<FILE>)
{
next if($line =~ /^POST \/ HTTP\/1.0/);
next if($line =~ /^Content-Type: application\/ocsp-request/);
next if($line =~ /^Content-Length:/);
next if($line =~ /^\r\n/);

print FILEOUT $line;
}
close FILE;
close FILEOUT;

a questo punto si può processare myout.der e rispedire al client la risposta

Darkbyte

unread,
Dec 14, 2011, 3:14:19 PM12/14/11
to
Come leggi in binario? Usi $client->recv()?

CtRiX

unread,
Dec 16, 2011, 7:14:25 AM12/16/11
to
Il Wed, 14 Dec 2011 16:51:04 +0100, Flavio Bosio ha scritto:

> Ecco come ho risolto:

Come ti avevo suggerito, io avrei usato HTTP::Daemon o qualcosa di simile.
Il tuo codice gestisce sempre un client solo alla volta (e quindi non
scala).

Flavio Bosio

unread,
Dec 16, 2011, 11:10:39 AM12/16/11
to
Il 16/12/11 13.14, CtRiX ha scritto:
> Il Wed, 14 Dec 2011 16:51:04 +0100, Flavio Bosio ha scritto:
>
>> Ecco come ho risolto:
>
> Come ti avevo suggerito, io avrei usato HTTP::Daemon o qualcosa di simile.

Sto lavorando ad un implementazione su Apache.. dammi tempo.

> Il tuo codice gestisce sempre un client solo alla volta (e quindi non
> scala).

Se il problema fosse solo quello, basterebbe forkare il processo con

while ($client = $server->accept()) {
$client->autoflush(1);

next if my $pid = fork;
die "fork - $!\n" unless defined $pid;

e killarlo alla chiusura del client

close $client;
exit(fork);

Ma prima bisognerebbe implementare la gestione dei nomi dei file
temporanei con qualcosa tipo File::Temp, nonché pensare ad un Timeout di
eventuali sessioni aperte
0 new messages