2012-11-22 8 views
5

Sto provando a scrivere un server Web in ascolto su entrambi gli indirizzi IPv4 e IPv6. Tuttavia, il codice che ho originariamente scritto non funzionava. Poi ho scoperto che le strutture IPv6 funzionano sia per IPv4 che per IPv6. Quindi ora utilizzo le strutture IPv6, ma funzionano solo gli indirizzi IPv4. Questo post, why can't i bind ipv6 socket to a linklocal address, che ha detto di aggiungere server.sin6_scope_id = 5; così ho fatto ma non accetta ancora connessioni telnet IPv6. Qualsiasi aiuto sarebbe molto apprezzato perché sono completamente sconcertato.
Grazie!Binding Socket to IPv6 Addresses

Il mio codice è qui sotto:

void initialize_server(int port, int connections, char* address) 
{ 
     struct sockaddr_in6 socket_struct; 
     /*Creates the socket*/ 
     if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
     { 
       syslog(LOG_ERR, "%s\n", strerror(errno)); 
       exit(EXIT_FAILURE); 
     }/*Ends the socket creation*/ 

     /*Populates the socket address structure*/ 
       socket_struct.sin6_family = AF_INET6; 

     if(address == NULL) 
       socket_struct.sin6_addr=in6addr_any; 
     else 
     { 
       inet_pton(AF_INET6, "fe80::216:3eff:fec3:3c22", (void *)&socket_struct.sin6_addr.s6_addr); 
     } 
     socket_struct.sin6_port =htons(port); 
     socket_struct.sin6_scope_id = 0; 
     if (bind(sock_fd, (struct sockaddr*) &socket_struct, sizeof(socket_struct)) < 0) 
     { 
       syslog(LOG_ERR, "%s\n", strerror(errno)); 
       exit(EXIT_FAILURE); 
     }//Ends the binding. 

     if (listen(sock_fd, connections) <0) 
     { 
       syslog(LOG_ERR, "%s\n", strerror(errno)); 
       exit(EXIT_FAILURE); 
     }//Ends the listening function 

}//ends the initialize server function. 
+0

quello che so ipv6 è a 64 bit, quindi i server che utilizzano ipv6 devono essere in esecuzione su sistemi operativi a 64 bit. basta usare ipv4 per ora, ci sono un sacco di problemi usando ipv6 finora. – GiantHornet

+2

@GiantHornet: IPv6 non è né a 32 bit né a 64 bit; può funzionare anche su altri sistemi. –

+0

@GiantHornet sì, non penso che sia giusto perché la mia macchina Ubuntu è i686 che è a 32 bit e ha un indirizzo IPv6 – tpar44

risposta

7

si sta creando una presa in AF_INET famiglia, ma poi cercando di associarlo a un indirizzo nel AF_INET6 famiglia. Passare a utilizzare AF_INET6 nella chiamata a socket().

+0

Grazie per il suggerimento ma ancora non funziona ... – tpar44

+0

Fare quel cambiamento ha funzionato per me. – qqx

+0

appena fuori dalla curiosità si usa il 'telnet fe80 :: 216: 3eff: fec3: 3c22% eth0 8080' per testarlo? – tpar44

6

Dire "server.sin6_scope_id = 5;" è arbitrario. Ho combattuto per un po 'con me e ho scoperto che è necessario utilizzare lo scopo effettivo dell'interfaccia effettiva su cui si desidera legare. Può essere trovato con un'osservazione semplice ma utile.

#include <net/if.h> 
server.sin6_scope_id=if_nametoindex("eth0"); 

Ovviamente, l'hardcoding su un particolare adattatore è un codice errato, con una codifica miope. Una soluzione più completa è quella di collegarli tutti e abbinare sull'indirizzo IP che stai vincolando. Quanto segue non è perfetto in quanto non tiene conto di stranezze come avere indirizzi non canonici e due adattatori con lo stesso IP, ecc. Ma, a ben vedere, questa funzione di esempio funziona alla grande e dovrebbe iniziare.

#include <string.h> // strcmp 
#include <net/if.h> // if_nametoindex() 
#include <ifaddrs.h> // getifaddrs() 
#include <netdb.h> // NI_ constants 

// returns 0 on error 
unsigned getScopeForIp(const char *ip){ 
    struct ifaddrs *addrs; 
    char ipAddress[NI_MAXHOST]; 
    unsigned scope=0; 
    // walk over the list of all interface addresses 
    getifaddrs(&addrs); 
    for(ifaddrs *addr=addrs;addr;addr=addr->ifa_next){ 
     if (addr->ifa_addr && addr->ifa_addr->sa_family==AF_INET6){ // only interested in ipv6 ones 
      getnameinfo(addr->ifa_addr,sizeof(struct sockaddr_in6),ipAddress,sizeof(ipAddress),NULL,0,NI_NUMERICHOST); 
      // result actually contains the interface name, so strip it 
      for(int i=0;ipAddress[i];i++){ 
       if(ipAddress[i]=='%'){ 
        ipAddress[i]='\0'; 
        break; 
       } 
      } 
      // if the ip matches, convert the interface name to a scope index 
      if(strcmp(ipAddress,ip)==0){ 
       scope=if_nametoindex(addr->ifa_name); 
       break; 
      } 
     } 
    } 
    freeifaddrs(addrs); 
    return scope; 
}