2
votes

I am trying to get both ipv4 and ipv6 adresses and connect to server with them but i can only connect with ipv4 address. It is a standard code actually. both ipv4 and ipv6 addresses are in /etc/hosts

192.155.112.18 hostname.site hostname
fe80::a00:28ff:fe23:47a0 hostname.site hostname

when i run both server and client the outputs are server:

usage: showip hostname
server: waiting for connections...
server: got connection from 192.155.112.18

client:

client: connecting to 192.155.112.18
client: connecting to 192.155.112.18
client: received 'Hello, world!'

getaddrinfo gets ipv6 address too but without interface i neeed to get fe80::a00:28ff:fe23:47a0%eth0 sth like that. How can i make a standard code get ipv4 and ipv6(with interface)

#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <signal.h>
#include <ifaddrs.h>

#define PORT "3490"  // the port users will be connecting to

void error(const char *msg)
{
    perror(msg);
    exit(1);
}
int gHostIP;
#define BACKLOG 10     // how many pending connections queue will hold

void sigchld_handler(int s)
{
   while(waitpid(-1, NULL, WNOHANG) > 0);
}

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
  if (sa->sa_family == AF_INET) 
  {
    return &(((struct sockaddr_in*)sa)->sin_addr);
   }

   return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main()
{
   int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
   struct addrinfo hints, *servinfo, *p;
   struct sockaddr_storage their_addr; // connector's address information
   socklen_t sin_size;
   struct sigaction sa;
   int yes=1;
   char s[INET6_ADDRSTRLEN];
   int rv;
       char *arg;

       arg = (char*)malloc(20*sizeof(char));

       fprintf(stderr,"usage: showip hostname\n");

       memset(&hints, 0, sizeof(hints));
       hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
       hints.ai_socktype = SOCK_STREAM;


       if ((rv = getaddrinfo("myhostname", PORT, &hints, &servinfo)) != 0) {
         fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
         return 1;
       }
       for(p = servinfo; p != NULL; p = p->ai_next) {
          if ((sockfd = socket(p->ai_family, p->ai_socktype,
                  p->ai_protocol)) == -1) {
              perror("server: socket");
            continue;
          }

          if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
                  sizeof(int)) == -1) {
              perror("setsockopt");
              exit(1);
          }
           /*if(p->ai_family == AF_INET6)
              strcat(p->ai_addr,"%eth3");*/
           if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
              close(sockfd);
              perror("server: bind");
              continue;
            }

          break;
       }

    if (p == NULL)  {
      fprintf(stderr, "server: failed to bind\n");
      return 2;
     }

     freeaddrinfo(servinfo); // all done with this structure

     if (listen(sockfd, BACKLOG) == -1) {
    perror("listen");
    exit(1);
     }

    sa.sa_handler = sigchld_handler; // reap all dead processes
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
      perror("sigaction");
      exit(1);
    }

    printf("server: waiting for connections...\n");

    while(1)
    {  // main accept() loop
      sin_size = sizeof their_addr;
      new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
      if (new_fd == -1) {
          perror("accept");
          continue;
      }

      inet_ntop(their_addr.ss_family,
          get_in_addr((struct sockaddr *)&their_addr),
          s, sizeof s);
      printf("server: got connection from %s\n", s);

      if (!fork()) { // this is the child process
          close(sockfd); // child doesn't need the listener
          if (send(new_fd, "Hello, world!", 13, 0) == -1)
            perror("send");
          close(new_fd);
          exit(0);
      }
      close(new_fd);  // parent doesn't need this
     }

     return 0;
}

client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/resource.h>
#include <sched.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <signal.h>
#include <ifaddrs.h>

#define PORT "3490" // the port client will be connecting to

#define MAXDATASIZE 100 // max number of bytes we can get at once
int gHostIP;

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}



int main(int argc, char *argv[])
{
    int sockfd, numbytes;
    char buf[MAXDATASIZE];
    struct addrinfo hints, *servinfo, *p;
    int rv;
    char s[INET6_ADDRSTRLEN];
    char *arg;
    arg = (char*)malloc(20*sizeof(char));

    struct ifaddrs *ifaddr, *ifa;
    int family, s1;
    char host[NI_MAXHOST];


    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;


    if ((rv = getaddrinfo("myhostname", PORT, &hints, &servinfo)) != 0)
    {
      fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
      return 1;
    }


    for (p = servinfo; p != NULL; p = p->ai_next)
    {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
            p->ai_protocol)) == -1) {
        perror("client: socket");
        continue;
        } 
        inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
               s, sizeof s);
         printf("\nclient: connecting to %s\n", s);
         if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        close(sockfd);
        perror("\nclient: connect");
        continue;
         }

         break;
    }

    if (p == NULL) {
        fprintf(stderr, "client: failed to connect\n");
        return 2;
    }

    inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
        s, sizeof s);
    printf("client: connecting to %s\n", s);

    freeaddrinfo(servinfo);

    if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
            perror("recv");
            exit(1);
    }

    buf[numbytes] = '\0';

    printf("client: received '%s'\n",buf);

    close(sockfd);

    return 0;
}
2
I've just tried your client code with an self-written TCP server (IPv6 enabled) and it was working just fine for me with a link-local address. I know it is not an answer, but i hope it helps to fix your problem...Gerd
The scope ID is in the sin6_scope_id field of the returned ai_addr struct.Michael Hampton
In server code, I set hints.ai_family = AF_INET6 and getting error getaddrinfo: Name or service not known Seems like getaddrinfo failed to get the details. But I can see that the ipv6 on running command 'ifconfig'. Do i need to make any config changes in my machine ?kaps

2 Answers

4
votes

You are using a link local address as your ipv6 address, its better to use a global unicast address like 2001:db8:1::1/64 instead

as root add it using this command:

ip -6 addr add 2001:db8:1::1/64 dev eth0

and on the client:

ip -6 addr add 2001:db8:1::2/64 dev eth0
0
votes

If your server bind on a ipv4 address, then you can only accept ipv4 client.

The problem is your getaddrinfo() return ipv4 first. (somebody works fine because their getaddrinfo() return ipv6 first)

so you can change code to

for (p = res; p!= NULL; p = p->ai_next) {
    if (p->ai_family == AF_INET6 && (sock = socket(p->ai_family, p-
        ai_socktype, p->ai_protocol)) < 0
    ) {}
}