2009-07-12 17 views
5

Sto scrivendo una semplice applicazione server TCP utilizzando i socket. Per quanto ne so posso ottenere l'indirizzo IP e la porta del client dopo aver chiamato accept().Rifiuto della connessione da un host

Ora supponiamo di avere una lista di ban e voglio vietare alcuni indirizzi IP dal mio server. C'è un modo migliore di accettare la connessione e poi rilasciarla?

C'è un modo per ottenere l'IP e la porta del client prima di accettare la connessione? Se accettiamo() perché non abbiamo qualcosa come reject()? C'è un modo per rifiutare la connessione o semplicemente ignorare il tentativo di connessione da un host?

+0

potresti aggiungere tag per quale lingua usi? Non sono un esperto di Sockets, ma ho un po 'di esperienza con Actionscript e C# /. NET – BerggreenDK

+2

E anche il sistema operativo ... Windows vs Unix potrebbe fare una grande differenza qui. Non penso che esista una soluzione portatile, ma potrei sbagliarmi. –

risposta

13

L'implementazione di TCP completa normalmente il TCP 3-way handshake prima che il processo utente ha anche l'accesso alla connessione, e la funzione accept() ottiene semplicemente la prossima connessione dalla coda. Quindi è troppo tardi per fingere che il server non funzioni. Funziona allo stesso modo per i normali dati TCP; l'implementazione TCP non attende che l'applicazione abbia effettivamente i dati recv() prima che venga inviato un ACK TCP. Ciò impedisce all'altro di ritrasmettere inutilmente pacchetti che sono stati ricevuti correttamente e consente al throughput di rimanere elevato, anche quando l'applicazione è impantanata con altre cose. Nel caso di nuove connessioni (pacchetti SYN), ciò consente al kernel di proteggere se stesso (e l'applicazione) dagli attacchi di alluvione SYN.

Sebbene non siano portatili, molte piattaforme forniscono una sorta di funzionalità firewall che consentirà il filtraggio delle connessioni in ingresso in base all'indirizzo IP/porta. Tuttavia, di solito è configurato a livello di sistema e non da una singola applicazione.

+0

Quindi, se ascolto su una porta, la connessione verrà stabilita in background, indipendentemente dal fatto che io voglia o no? – Calmarius

+1

La chiamata listen() indica al sistema operativo che si desidera stabilire una connessione corretta sulla porta. Quindi, a meno che non si filtri il pacchetto a un livello inferiore (regola del firewall), risponderà a qualsiasi richiesta di connessione a questa porta. Se decidi che non vuoi una connessione particolare, puoi sempre chiuderla(), che è ciò che faranno alcune delle altre risposte qui. – mark4o

4

On finestre: guardare WSAAccept, può essere che è quello che ti serve:

SOCKET WSAAccept(
    __in  SOCKET s, 
    __out struct sockaddr *addr, 
    __inout LPINT addrlen, 
    __in  LPCONDITIONPROC lpfnCondition, 
    __in  DWORD dwCallbackData 
); 

lpfnCondition - l'indirizzo di una funzione condizione di applicazione specificato opzionale che farà un accetta/rifiuta decisione in base alle informazioni sul chiamante trasmesse come parametri e facoltativamente creare o unire un gruppo socket assegnando un valore appropriato al parametro g di risultato di questa funzione. Se questo parametro è NULL, non viene chiamata alcuna funzione di condizione.

Per linux soluzione: GNU Common C++ - classe TCPSocket, ha metodi onAccept() e reject().

virtual bool TCPSocket::onAccept (  const InetHostAddress &  ia, 
     tpport_t port 
    ) [inline, protected, virtual] 

Un metodo da chiamare in una classe derivata TCPSocket che funge da un server quando viene accettata una richiesta di connessione.

Il server può implementare regole specifiche del protocollo per escludere il socket remoto dall'accettazione restituendo false. Il metodo Peek può essere utilizzato anche per questo scopo.


Tuttavia, si può solo vicino presa dopo accettato se pre-condizione è falsa :)

+0

Se non c'è altra soluzione, accetterò e chiuderò immediatamente la presa come aprire una porta per chiederti chi sei e chiuderla se sei bannato ... Ma non voglio affatto aprire quella porta. Voglio fare in modo che gli utenti vietati pensino che il server sia semplicemente inattivo. – Calmarius

+0

Quello che vuoi è più elegante, tuttavia nello sviluppo abbiamo bisogno di equilibrio tra caratteristiche gratitudine e tempo/denaro speso su di esso. Come in XP ha detto - farlo nel modo più semplice, in seguito è possibile venire e refactoring. –

1

TCP Wrapper è diventato molto diffuso su piattaforme simili a UNIX. Sì, la connessione viene controllata solo dopo ilaccept; tuttavia, se lo fai comunque, potresti anche usare la stessa configurazione che tutti usano.

In sostanza, il programma è sia gestita con tcpd o modificati per utilizzare libwrap direttamente, in questo modo:

#include <tcpd.h> 
connfd = accept(listenfd, (struct sockaddr *)&addr, &addrlen); 
if (!hosts_ctl("my_program", STRING_UNKNOWN, inet_ntoa(addr.sin_addr), STRING_UNKNOWN)) { 
    fprintf(stderr, "Client %s connection disallowed\n", inet_ntoa(addr.sin_addr)); 
    close(connfd); 
} 

Poi si configura /etc/hosts.allow e /etc/hosts.deny secondo i vostri desideri, per esempio

 
# /etc/hosts.allow 
my_program: 127.0.0.1 10. 192.168. 

# /etc/hosts.deny 
my_program: ALL 

Questo farà sì che my_program a respingere tutti i tentativi di connessione provenienti da indirizzi non locali, ma può essere cambiato senza toccare my_program a tutti.

-1

il concetto di non accettare la connessione in base all'indirizzo IP non funzionerà se si sta svolgendo il NAT.

Problemi correlati