why can't i bind ipv6 socket to a linklocal address
Asked Answered
M

1

11
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>

void error(char *msg)
{
  perror(msg);
  exit(0);
}
int main(int argc, char *argv[])
{
   int sock, length, fromlen, n;
   struct sockaddr_in6 server;
   struct sockaddr_in6  from;

   int portNr = 5555;
   char buf[1024];

   length = sizeof (struct sockaddr_in6);

   sock=socket(AF_INET6, SOCK_DGRAM, 0);
   if (sock < 0) error("Opening socket");

   bzero((char *)&server, length);
   server.sin6_family=AF_INET6;
   server.sin6_addr=in6addr_any;
   server.sin6_port=htons(portNr);

   inet_pton( AF_INET6, "fe80::21f:29ff:feed:2f7e", (void *)&server.sin6_addr.s6_addr);
   //inet_pton( AF_INET6, "::1", (void *)&server.sin6_addr.s6_addr);

   if (bind(sock,(struct sockaddr *)&server,length)<0)
       error("binding");
   fromlen = sizeof(struct sockaddr_in6);
   while (1) {
       n = recvfrom(sock,buf,1024,0,(struct sockaddr *)&from,&fromlen);
       if (n < 0) error("recvfrom");
       write(1,"Received a datagram: ",21);
       write(1,buf,n);
       n = sendto(sock,"Got your message\n",17,
                  0,(struct sockaddr *)&from,fromlen);
       if (n  < 0) error("sendto");
   }
}

when I compile and run the above code I got :

binding: Invalid argument

and if change to bind the ::1 and leave other thing unchanged in the source code, the code works! so could you tell me what's wrong with my code ? thanks in advance.

Morehouse answered 16/3, 2010 at 15:39 Comment(0)
H
17

For link-local addresses, you also need to specify the scope ID of the network interface that is associated with the address... something like this:

server.sin6_scope_id = 5;   /* or whatever the scope ID is for the network interface you want to communicate over */

You can use getifaddrs() to find the various scope IDs available on your systems, and the network interfaces they correspond to.

(Yes, it's a pain... alternatively you might be able to append something like "%en0" to the end of the string you pass to inet_pton(), and inet_pton() might do the work for you... I'm not sure if inet_pton() handles that syntax or not)

Hinshelwood answered 16/3, 2010 at 16:42 Comment(2)
inet_pton doesn't handle %if appended strings. You can use getaddrinfo to work with % appended ip6 address string representations. See man page linux.die.net/man/3/getaddrinfoClaypoole
For those reading this answer, please note the scope_id is the index of the interface you want to communicate over. Since fe80 is present for each interfaces by default, we need to specify which interface that link local address is referring to. So the value 5 is given as an example. To get that index, you need to use if_nametoindex (const char *ifname) from the interface name. The interface name is returned by interating over the data structure populated by getifaddrs(struct ifaddrs **ifap).Bloodshed

© 2022 - 2024 — McMap. All rights reserved.