Связывание сокетов с адресами IPv6
Я пытаюсь написать веб-сервер, который прослушивает адреса как IPv4, так и IPv6. Однако код, который я изначально написал, не работал. Затем я обнаружил, что структуры IPv6 работают как для IPv4, так и для IPv6. Поэтому теперь я использую структуры IPv6, однако работают только адреса IPv4. Этот пост, почему я не могу связать сокет ipv6 с адресом локальной ссылки, который сказал добавить server.sin6_scope_id = 5;
так что я сделал это, но он по-прежнему не принимает IPv6-соединения Telnet. Любая помощь будет принята с благодарностью, потому что я полностью озадачен.
Спасибо!
Мой код ниже:
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.
2 ответа
Говоря "server.sin6_scope_id = 5;" произвольно. Я боролся с этим некоторое время сам и обнаружил, что вам нужно использовать фактическую область действия фактического интерфейса, с которым вы хотите связать. Его можно найти с помощью заметной, но полезной маленькой функции.
#include <net/if.h>
server.sin6_scope_id=if_nametoindex("eth0");
Конечно, жесткое кодирование одного конкретного адаптера - это плохое, недальновидное кодирование. Более полное решение состоит в том, чтобы пройти через все из них и сопоставить IP-адрес, который вы связываете. Следующее не является идеальным в том смысле, что оно не учитывает такие причуды, как наличие неканонических адресов и двух адаптеров с одинаковым ip и т. Д. Но, кроме того, эта примерная функция прекрасно работает и должна помочь вам начать работу.
#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;
}
Вы создаете сокет в AF_INET
семьи, но затем пытается связать его с адресом в AF_INET6
семьи. Переключиться на использование AF_INET6
в вашем звонке socket()
,