Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding Sockets to IPv6 Addresses

I am trying to write a web server that listens on both IPv4 and IPv6 addresses. However, the code that I originally wrote did not work. Then I found out that the IPv6 structures work for both IPv4 and IPv6. So now I use the IPv6 structures however, only the IPv4 addresses work. This post, why can't i bind ipv6 socket to a linklocal address, which said to add server.sin6_scope_id = 5; so I did that but it still does not accept IPv6 telnet connections. Any help would be greatly appreciated because I am thoroughly stumped.
Thanks!

My code is below:

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.
like image 807
tpar44 Avatar asked Nov 22 '12 02:11

tpar44


2 Answers

Saying "server.sin6_scope_id = 5;" is arbitrary. I fought with this awhile myself and discovered you need to use the actual scope of the actual interface you want to bind on. It can be found with an obsure but useful little function.

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

Of course, hardcoding it to one particular adapter is bad, shortsighted coding. A more complete solution is to loop through all of them and match on the ip address you're binding. The following is not perfect in that it doesn't account for quirks like having non-canonical addresses and two adapters with the same ip, etc. But besoverall, this sample function works great and should get you started.

#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;
}
like image 135
TheHeadlessSourceMan Avatar answered Sep 17 '22 05:09

TheHeadlessSourceMan


You're creating a socket in the AF_INET family, but then trying to bind it to an address in the AF_INET6 family. Switch to using AF_INET6 in your call to socket().

like image 34
qqx Avatar answered Sep 17 '22 05:09

qqx