PDA

Visualizza la versione completa : [C] Indirizzo di loopback


Crow©
12-07-2011, 15:18
Ciao a tutti, ho realizzato in C un client e un server ricorsivo che comunicano tramite socket, il mio problema è che il server deve accettare solo richieste da client con indirizzi di loopback con range da 127.0.0.1 a 127.255.255.255, escludendo tutti gli altri indirizzi tipo:
./client 127.0.0.1 (questo indirizzo va bene)
./client 192.168.1.2 (il server deve rifiutare la connessione e inviare un messaggio di connessione rifiutata)

ecco la parte che interessata
bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); (con questa istruzione io accetto tutti gli indirizzi) servaddr.sin_port = htons(4444);

ho provato con varie opzione, ho cambiato INADDR_ANY con INADDR_BROADCAST (Indirizzo di broadcast)
INADDR_LOOPBACK (Indirizzo di loopback (127.0.0.1) questo andrebbe bene, ma prende solo 127.0.0.1 invece mi interessa il range come già detto).

sinceramente ho cercato un pò sulla rete ma non ho trovato una soluzione spero che qualcuno mi possa dare una dritta grazie anticipatamente.

oregon
12-07-2011, 17:27
Forse non ho capito io ... è quindi il client che si deve presentare con uno di quegli indirizzi?

Se è così, controlla l'IP del client quando questo si connette ... o mi è sfuggito qualcosa?

Celebron
12-07-2011, 19:55
Originariamente inviato da oregon
Forse non ho capito io ... è quindi il client che si deve presentare con uno di quegli indirizzi?

Se è così, controlla l'IP del client quando questo si connette ... o mi è sfuggito qualcosa?
ho capito anche io come te :bhò:

Crow©
13-07-2011, 10:36
ciao grazie per le risposte gentilissimi, in effetti non sono stato molto chiaro nel presentare il problema, come dice oregon il client si dovrà presentare con l'indirizzo che gli passo io da linea di comando, adesso cercherò di farmi capire meglio, questo è lo scenario:
eseguo in server che resta sempre in attesa
poi mango in esecuzione il client con:
./client 127.0.0.1
sto settando al client l'indirizzo passatogli da linea di comando, cioè il client avrà come indirizzo IP 127.0.0.1

adesso questo è il mio problema se al client gli passo gli indirizzi 127.0.0.1, 127.0.0.2, 127.0.0.3 .......127.0.0.n, tutto va a buon fine e io sono contento(questo è il primo punto dell'esercizio).

Adesso il secondo punto dell'esercizio mi dice che se gli passo un indirizzo come 192.168.1.2, devo fare in modo che il server deve rifiutare la connessione e inviare un messaggio al client dicendogli che l'indirizzo ip non può essere usato.
ho provato a fare
./client 192.168.1.2
il client mi dice errore in connect, non riesco proprio ad effettuare la connessione, ho verificato che ho un problema nella funzione connect, va in stallo.

per aiutarvi a capire meglio il problema dovrei postare il codice?

grazie a tutti

valia
13-07-2011, 10:42
penso che ti stai confondendo un po'.
Se l'indirizzo va bene la connessione viene accettata e puoi comunicare.
Se l'indirizzo non va bene, il server non accetta la connessione e visto che non l'accetta, come può inviarti il mex indirizzo non buono?
In questi casi dovresti interpretare l'errore connection refused come indirizzo non buono.

Altrimenti è da modificare il server in modo da accettare cmq la connessione solo per inviare il mex indirizzo non valido (ma penso sia uno spreco di risorse)

Crow©
13-07-2011, 11:17
ciao valia allora questa è la traccia:
Si sviluppi un applicazione client-server che implementa il seguente protocollo:
- Il client legge dallo standard input la stringa f e la invia al server;
- Il server recupera l'indirizzo IP sul quale ha ricevuto la richiesta, cerca tale valore nel file f e restituisce il nome di dominio associato. Se l indirizzo non è presente nel file il server deve restituire la stringa servizio non disponibile; se il file non esiste deve restituire la stringa file inesistente.
L applicazione deve utilizzare socket di tipo stream ed il server deve essere ricorsivo.Il server deve girare sulla porta 4444 e deve utilizzare le opzioni dei socket per consentire il riutilizzo delle porte.
Di seguito un case test del programma.
Supponiamo che il client venga eseguito lanciando il comando
-> client xxx f
Dove xxx è l'indirizzo del server e f è il nome del file il cui contenuto è:
127.0.0.1 www.nomedominio.it
127.0.0.2 mail.nomemail.it
127.0.0.3 ns.nomens.it

se xxx = 127.0.0.1 allora il server risponde con www.nomedominio.it;
se xxx = 127.0.0.2 allora il server risponde con mail.nomemail.it;
se xxx = 127.0.0.4 allora il server risponde con servizio non disponibile;
se xxx = 192.168.10.1 allora il server risponde con connessione rifiutata;
se xxx = 127.0.0.1 e f = rubrica allora il server risponde con file inesistente.

tutto va bene solo che con l'indirizzo 192.168.10.1 non riesco a fargli rispondere con connessione rifiutata.
:spy:

valia
13-07-2011, 11:25
devi distinguere varie situazioni:


1. xxx = 127.0.0.1 allora il server risponde con www.nomedominio.it;
2. xxx = 127.0.0.2 allora il server risponde con mail.nomemail.it;
3. xxx = 127.0.0.4 allora il server risponde con servizio non disponibile;
4. xxx = 192.168.10.1 allora il server risponde con connessione rifiutata;
5. xxx = 127.0.0.1 e f = rubrica allora il server risponde con file inesistente.

nei casi 1, 2, 3 e 5 tu comunque riesci a connetterti (perché il server accetta il tuo indirizzo) e riesci a leggere correttamente la risposta alla tua richiesta (variabile a seconda dei vari casi in cui si presenta il tutto).

Ma nel caso 4 devi distinguere come ti dicevo due situazioni:

1. visto l'indirizzo non valido rifiuti la connessione (suppongo ritorni 500) e questo è il messaggio di connessione rifiutata che tu ovviamente lato client trasformi in una stringa user-friendly
2. ti connetti e mandi il mex indirizzo non valido

come vedi il caso 2 è fondamentalmente errato perché supponi che riesci a connetterti e ottieni come risposta picche, ma in realtà tu non devi connetterti, devi ottenere picche in partenza.
Uno sforzo in più ti consente di dire che indirizzo non valido (lato server) rifiuti la connessione (avrai un error code) e quell'error code che passi rifiutando la connessione potrebbe essere un indice che indica proprio connessione rifiutata.

La mia interpretazione dell'esercizio è questa, ovviamente il docente saprà dirti a riguardo, per me l'opzione 1 è quella corretta

Crow©
13-07-2011, 12:19
grazie valia, allora non so se ho capito bene, comunque il primo caso è quello che mi occorre,
il client tenta di effettuare la connessione, tramite la funziona connect, il server rifiuta e restituisce una errore quel errore il client lo trasforma in messaggio user-friendly, o sbaglio?
comunque ho trovato sulla gapil questo: EAFNOSUPPORT l’indirizzo non ha una famiglia di indirizzi corretta nel relativo campo, può fare al mio caso?

valia
13-07-2011, 12:27
stai scrivendo tu il server?
Puoi sfruttare uno esistente (come hai visto) come puoi farne tornare uno tuo che di sicuro non va in conflitto con altri, l'importante è come poi lo interpreti lato client (insomma client e server devono avere un vocabolario comune per cui PICCHE significa per tutti e due la stessa cosa).
Se scrivi tu il server, deciderei io il codice proprio per evitare altre anomalie (ma sono scelte implementative)

Crow©
13-07-2011, 13:16
Sia il server che il client non sono stati scritti interamente da me, ma solo in parte, ecco il codice


int main(int argc, char **argv){
pid_t pid;
int listensd, connsd;
struct sockaddr_in servaddr, cliaddr;
socklen_t servaddr_len, cliaddr_len;
char buff[MAXLINE];
char msg[MAXLINE] = "prova di utilizzo di getsockname()";
time_t ticks;
FILE *file;

if( (listensd = socket(AF_INET, SOCK_STREAM, 0)) < 0) err_sys("errore in socket");

bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(4444);

int tr=1;
// permette il riutilizzo della porta
if (setsockopt(listensd,SOL_SOCKET,SO_REUSEADDR,&tr,sizeof(int)) == -1){
err_sys("errore in setsockopt");
exit(1);
}

if( (bind(listensd, (SA *) &servaddr, sizeof(servaddr))) < 0) err_sys("errore in bind");

if( listen(listensd, LISTENQ) < 0 ) err_sys("errore in listen");

getsockname(listensd, (SA *) &servaddr, &servaddr_len); /* ottiene l'indirizzo IP ed il numero di porta assegnati al socket di ascolto */

inet_ntop(AF_INET, &servaddr.sin_addr, buff, sizeof(buff)); /* estrae dalla struct sockaddr_in l'indirizzo IP e lo copia come stringa in un buffer */

printf("Socket di ascolto: \tIndirizzo IP %s, porta %d\n", buff,ntohs(servaddr.sin_port));

for ( ; ; ) {
cliaddr_len = sizeof(cliaddr);
if( (connsd = accept(listensd, (SA *) &cliaddr, &cliaddr_len)) < 0) err_sys("errore in accept");

getsockname(connsd, (SA *) &servaddr, &servaddr_len); /* ottiene l'indirizzo IP ed il numero di porta assegnati al socket di connessione restituito dall'accept */

inet_ntop(AF_INET, &servaddr.sin_addr, buff, sizeof(buff));
printf("Socket di connessione: \tIndirizzo IP %s, porta %d\n", buff, ntohs(servaddr.sin_port));

printf("Indirizzo del peer: \tIndirizzo IP %s, porta %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, buff, sizeof(buff)), ntohs(cliaddr.sin_port) );
/* stampa indirizzo IP e numero di porta del client.Non serve chiamare getpeername */

if((pid = fork()) == 0 ){

if( close(listensd) == -1 ) err_sys("errore in close");
//-------------------------------------------------------------------------------
char indirizzo[11],i[100],dominio[100],nomefile[10];
int flag=0,n=0;
n = read(connsd, nomefile, sizeof(nomefile));
nomefile[n] = '\0';
printf("%s la cui lunghezza è %d\n",nomefile,strlen(nomefile));

if((file=fopen(nomefile,"r"))==NULL) {
err_sys("File inesistente");
exit(1);
}
getsockname(connsd, (SA *) &servaddr, &servaddr_len);
inet_ntop(AF_INET, &servaddr.sin_addr,indirizzo, sizeof(indirizzo));
// printf("Socket di ascolto: \tIndirizzo IP %s, porta %d\n",indirizzo, ntohs(servaddr.sin_port));
while(fscanf(file,"%s %s",i,dominio)!=EOF){
if ((strcmp(indirizzo,i)) == 0) {
flag=1;
break;
}
}
fclose(file);
if(!flag) strcpy(dominio,"Servizio non disponibile");
sprintf(msg,"%s\n",dominio);
//--------------------------------------------------------------------------------
if( (write(connsd, msg, strlen(msg)) != strlen(msg)) ) err_sys("errore in write");
if( close(connsd) == -1 ) err_sys("errore in close");
exit(0);
}

if( close(connsd) == -1 ) err_sys("errore in close");
}
}


il client

int main(int argc, char **argv){
int sockd, n;
char buff[MAXLINE], recvline[MAXLINE + 1],sendline[MAXLINE];
struct sockaddr_in servaddr, localaddr, peeraddr;
socklen_t localaddr_len, peeraddr_len;

if ( argc != 3 ) err_quit("utilizzo: sockname_client <IPaddress>");

if ((sockd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) err_sys("errore in socket");

bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(4444);
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0 ) err_quit("errore in inet_pton per %s", argv[1]);

if ( connect(sockd, (SA *) &servaddr, sizeof(servaddr)) < 0 ) err_sys("errore in connect");

localaddr_len = sizeof(localaddr);
getsockname(sockd, (SA *) &localaddr, &localaddr_len);
/* ottiene l'indirizzo Ip ed il numero di porta assegnati dal sistema operativo alla connessione con endpoint identificato da sockd */

printf("Indirizzo locale: indirizzo IP %s, porta %d\n",inet_ntop(AF_INET, &localaddr.sin_addr, buff, sizeof(buff)),ntohs(localaddr.sin_port));

peeraddr_len = sizeof(peeraddr);
getpeername(sockd, (SA *) &peeraddr, &peeraddr_len);
/* ottiene l'indirizzo Ip ed il numero di porta del peer nella connessione identificata da sockd.L'altro endpoint è identificato dal socket di comunicazione del
server e non dal socket di ascolto. */

printf("Indirizzo del peer: indirizzo IP %s, porta %d\n",inet_ntop(AF_INET, &peeraddr.sin_addr, buff, sizeof(buff)),ntohs(peeraddr.sin_port));

sprintf(sendline,"%s%c",argv[2],'\0');
printf("%s la cui dimensione e %d\n",sendline,strlen(sendline));
if( writen(sockd, sendline, strlen(sendline)) != strlen(sendline) ) err_sys("errore in write");

if( (n = read(sockd, recvline, MAXLINE)) < 0 ) err_sys("errore in read");
recvline[n] = 0;
printf("%s", recvline);

exit(0);
}

l'area delimitata dalla tratteggiatura è stata modificata da me, il resto è stato fatto dal prof.

Loading