2012-11-22 40 views
5

Próbuję napisać serwer sieciowy, który nasłuchuje na adresach IPv4 i IPv6. Jednak kod, który pierwotnie napisałem, nie działał. Następnie dowiedziałem się, że struktury IPv6 działają zarówno dla IPv4, jak i IPv6. Teraz używam struktur IPv6, ale działają tylko adresy IPv4. Ten post, why can't i bind ipv6 socket to a linklocal address, który powiedział, aby dodać server.sin6_scope_id = 5;, więc zrobiłem to, ale nadal nie akceptuje połączeń telnet IPv6. Każda pomoc będzie ogromnie doceniona, ponieważ jestem całkowicie zdumiona.
Dzięki!Powiązanie gniazd z adresami IPv6

Moje kodu jest poniżej:

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

co wiem, że ipv6 jest 64-bitowy, więc serwery korzystające z ipv6 muszą działać na 64-bitowych systemach operacyjnych. po prostu użyj teraz ipv4, na razie jest dużo problemów z używaniem ipv6. – GiantHornet

+2

@GiantHornet: IPv6 nie jest ani 32-bitowy ani 64-bitowy; może działać również na innych systemach. –

+0

@GiantHornet tak, nie sądzę, że to prawda, ponieważ moją maszyną ubuntu jest i686, która ma 32-bitową i ma adres IPv6 – tpar44

Odpowiedz

7

Ty tworząc gniazdo w rodzinie AF_INET, ale potem próbuje powiązać go z adresem w rodzinie AF_INET6. Przejdź na numer AF_INET6 w swoim połączeniu z numerem socket().

+0

Dzięki za podpowiedź, ale nadal nie działa ... – tpar44

+0

Dokonanie tej zmiany sprawiło, że zadziałało. – qqx

+0

tylko z ciekawości użyjesz 'telnetu fe80 :: 216: 3eff: fec3: 3c22% eth0 8080' do przetestowania? – tpar44

6

Mówiąc "server.sin6_scope_id = 5;" jest arbitralny. Walczyłem z tym przez chwilę i odkryłem, że musisz użyć rzeczywistego zasięgu rzeczywistego interfejsu, który chcesz powiązać. Można go znaleźć z pewną, ale użyteczną, małą funkcją.

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

Oczywiście, kodowanie go do jednej konkretnej karty jest złe, krótkowzroczne kodowanie. Bardziej kompletnym rozwiązaniem jest zapętlenie ich wszystkich i dopasowanie do adresu IP, który jest wiążący. Poniższe nie jest idealne, ponieważ nie uwzględnia dziwactw, takich jak posiadanie niekanonicznych adresów i dwóch adapterów z tym samym adresem IP itp. Jednak poza tym ta przykładowa funkcja działa świetnie i powinna zacząć działać.

#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; 
}