2010-03-01 9 views
8

Devo aggiungere il supporto IPv6 a un'applicazione esistente basata su socket che attualmente supporta solo IPv4. Per abbracciare l'era in arrivo di IPv6, qualcuno mi ha ordinato di aggiungere un'interfaccia IPv6 per l'app e lasciare che il mondo esterno scelga l'interfaccia IPv4 o l'interfaccia IPv6 quando cerca di comunicare con l'app.C'è qualche differenza tra IPv4 e IPv6 a livello di socket?

La mia domanda è: è vero che per il livello API di gestione socket in Linux, non c'è alcuna differenza tra la gestione di un socket basato su IPv4 e socket basato su IPv6?

Inoltre, è possibile consentire a un socket di ascoltare su due indirizzi IP con la stessa porta? Se questo è vero, immagino che implementare il requisito sia un lavoro banale.

risposta

6

Non è possibile ascoltare su 2 indirizzi IP diversi con 1 socket TCP, tuttavia se si ascoltano tutte le interfacce utilizzando l'indirizzo in6addr_any, che includerà anche tutti gli indirizzi IPv4 (anche se, ad esempio, Linux ha un'opzione del kernel per disabilitare quella mappatura).

L'API socket (versione più recente) è abbastanza trasparente per l'utilizzo di IPv4 o IPv6, ma è necessario prestare particolare attenzione a come un'applicazione IPv4 viene codificata in genere.

ad es. questo codice IPv4 che accetta una connessione e stampa l'indirizzo dell'host remoto:

struct sockaddr_in client_addr; 
socklen_t addr_len = sizeof(client_addr); 
client_data->fd = accept(server_fd,(struct sockaddr*)&client_addr,&addr_len); 
log_printf("New client from %s\n",inet_ntoa(client_addr.sin_addr.s_addr)); 

dovrebbero essere convertiti a quanto segue, che gestisce sia IPv4 che IPv6

struct sockaddr_storage client_addr; 
char numeric_addr[INET6_ADDRSTRLEN]; 
socklen_t addr_len = sizeof(client_addr); 
client_data->fd = accept(server_fd,(struct sockaddr*)&client_addr,&addr_len); 
if(client_addr.ss_family == AF_INET) 
    log_printf("New client from %s\n",inet_ntop(client_addr.ss_family,((struct sockaddr_in*)&client_addr)->sin_addr.s_addr ,numeric_addr,sizeof numeric_addr)); 
else if(client_addr.ss_family == AF_INET6) 
    log_printf("New client from %s\n",inet_ntop(client_addr.ss_family,((struct sockaddr_in6*)&client_addr)->sin6_addr ,numeric_addr,sizeof numeric_addr)); 

Anche se credo potrebbe farlo ancora più elegante e trasparente con getaddrinfo()

Ecco note aggiuntive su IP strato di indipendenza: http://uw714doc.sco.com/en/SDK_netapi/sockC.PortIPv4appIPv6.html http://www.kame.net/newsletter/19980604/

+0

@nos: grazie per il tuo aiuto. Ho ancora una domanda, è possibile associare un socket udp a più di un indirizzo IP? per esempio, uno per ipv4 e uno per ipv6 totalmente 2. –

+1

No, non è possibile associare un socket UDP a più di 1 (o tutti) indirizzi IP. È possibile tuttavia con SCTP, utilizzando le sue funzionalità multi-homing. Per TCP o UDP devi creare 1 socket per ciascun indirizzo che desideri ascoltare, a meno che non desideri ascoltare tutti gli indirizzi IP – nos

+0

Per ottenere socket dualstack, esiste un'opzione socket che abilita o disabilita il comportamento dualstack - cerca IPV6_V6ONLY per maggiori informazioni. Se non lo fai, il tuo programma fallirà misteriosamente su determinati SO, su versioni specifiche. – christopher

0

Credo che ci sia una differenza, principalmente come vengono assegnati/visualizzati gli indirizzi IP e le maschere di sottorete.

I metodi che accettano l'indirizzo IPv4 in entrata, non funzioneranno e genereranno un'eccezione se viene fornito un IPv6 puro, pertanto i metodi dovranno verificare quale tipo di connessione è stato avviato, a parte quello che non penso così.

0

IPv6 è uno spazio di indirizzi a 128 bit e offre più funzionalità (stateless, multicast, elaborazione più semplice per i router, solo per citarne alcuni) rispetto a IPv4 (che è a 32 bit), lo spazio di indirizzi per IPv4 si sta esaurendo, ma con l'aiuto di NAT/SNAT può aumentare la longevità del protocollo IPv4. L'utilizzo di IPv6 dipende dal fatto che il sistema operativo sia in grado di supportare il nuovo protocollo. È sicuramente disponibile su Windows 7, Linux ... La cosa principale è che IPv6 è retrocompatibile con IPv4 ...

Per rispondere alla tua domanda, che dipende dal livello API fornito dal sistema operativo in grado di supportare lo stack di rete IPv6 , Ecco un esempio di IPv6 prese esempio come si trova sul MSDN, per Linux, l'utilizzo di prese è per lo più la stessa cosa con l'eccezione che si prevede di utilizzare ...

Spero che questo aiuti, i migliori saluti, Tom .

4

Gran parte della gestione della presa è la stessa per IPv4 e IPv6. Sul server, una volta associato l'indirizzo, le chiamate a listen, accept, recv e send funzioneranno tutte allo stesso modo per entrambe le connessioni IPv4 e IPv6.

Ma le funzioni che si occupano di indirizzi come ad esempio connect, bind, avranno bisogno getsockname, getpeername da modificare come è necessario utilizzare un . Inoltre, è necessario modificare le funzioni che funzionano con l'indirizzo (ad esempio, le chiamate a inet_addr devono essere modificate in inet_pton).

Su Linux, se si associa a in6addr_any, connessioni IPv4 e IPv6 a quella porta funziona (anche se questo potrebbe ascoltare più di 2 indirizzi perché sarà anche ascoltare sul loopback IPv4 127.0.0.1 e il loopback IPv6 ::1) . Ma su Windows, non sono mai stato in grado di farlo funzionare e ho bisogno di ascoltare su un socket per IPv4 e un socket diverso per IPv6.

+3

In Windows, la possibilità per un singolo socket di ascoltare e accettare entrambi i client IPv4 e IPv6 su una singola porta è stata introdotta in Vista, tramite l'architettura dello stack di socket dual-stack riprogettata. Creare un socket di ascolto IPv6 e impostare su False la nuova opzione socket IPV6_V6ONLY per consentire l'accesso ai client IPv4. –

+0

@RemyLeabeauTeamB - grazie - quell'informazione è molto utile. –

2

Beej's Guide to Network Programming risolve le differenze nella codifica per IPv4 e IPv6. http://beej.us/guide/bgnet/

Ha dedicato una sezione alla modifica del codice IPv4 esistente per gestire IPv6.

Inoltre, spiega come codificare in modo astratto a livello di socket in modo che non sia necessario sapere se si tratti o meno di un indirizzo IPv4 o di un IPv6.

Problemi correlati