Why is my server code not working with IPv6?

2

Recently I've been writing a small C server using the UNIX sockets API for just a few tests. The program works perfectly with IPv4 , but the same does not happen with IPv6 ...

Follow the code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <netdb.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define STR_PORT "9009"

int make_server_socket(void){

    int sockfd;
    struct addrinfo *res=NULL, hints;

    memset(&hints, 0, sizeof(hints));

    hints.ai_flags=AI_PASSIVE;
    hints.ai_family=AF_UNSPEC;
    hints.ai_socktype=SOCK_STREAM;
    hints.ai_protocol=IPPROTO_TCP;

    if(getaddrinfo(NULL, STR_PORT, &hints, &res)!=0){

        sockfd=-1;

    }else{

        if((sockfd=socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP))!=-1){

            if(bind(sockfd, res->ai_addr, res->ai_addrlen)<0){

                sockfd=-1;
            }
        }

        freeaddrinfo(res);
    }

    return sockfd;
}

int main(void){

    int sockfd=make_server_socket();

    if(sockfd<0){

        printf("\n*make_server_socket(): ERROR!\n");

    }else{

        if(listen(sockfd, 1)<0){

            printf("\n*listen(): ERROR!\n");
            perror("ERROR DESCRIPTION");

        }else{

            int csockfd=accept(sockfd, NULL, NULL);

            if(csockfd<0){

                printf("\n*accept(): ERROR!\n");
                perror("ERROR DESCRIPTION");

            }else{

                int rv=write(csockfd, "Real Muthaphuckkin G's", 23);

                if(rv!=23){

                    printf("\nsend(23): FAIL\n");

                }else{

                    printf("\nsend(23): SUCCESSFUL\n");
                }

                close(csockfd);
            }

            close(sockfd);
        }
    }

    return 0;
}

Compiled and working code:

Connecting to the server via IPv4 local address:

zherkezhi@zherkezhi :~/Documents/C$ nc -4 127.0.0.1 9009
Real Muthaphuckkin G's
zherkezhi@zherkezhi:~/Documents/C$ #Funcionou perfeitamente!

Connecting to the server via IPv6 local address:

zherkezhi@zherkezhi:~/Documents/C$ nc -6 ::1 9009
zherkezhi@zherkezhi:~/Documents/C$ #não aconteceu nada *_*

Nmap output (while the server was running):

Scanning local IPv4 address :

zherkezhi@zherkezhi:~/Documents/C$ nmap 127.0.0.1

Starting Nmap 7.60 ( https://nmap.org ) at 2018-10-26 10:49 -03
Nmap scan report for localhost (127.0.0.1)
Host is up (0.000052s latency).
Not shown: 997 closed ports
PORT     STATE SERVICE
631/tcp  open  ipp
3306/tcp open  mysql
9009/tcp open  pichat

Nmap done: 1 IP address (1 host up) scanned in 0.06 seconds

Scanning IPv6 Local Address :

zherkezhi@zherkezhi:~/Documents/C$ nmap -6 ::1

Starting Nmap 7.60 ( https://nmap.org ) at 2018-10-26 10:46 -03
Nmap scan report for ip6-localhost (::1)
Host is up (0.000060s latency).
Not shown: 999 closed ports
PORT    STATE SERVICE
631/tcp open  ipp

Nmap done: 1 IP address (1 host up) scanned in 0.09 seconds

What do I have to do for my code to work with IPv6 correctly?

    
asked by anonymous 26.10.2018 / 15:55

1 answer

4

You can not use IPv4 and IPv6 on the same socket.

In the case in question, if you want to attend IPv6 then you need to specify the family

hints.ai_family = AF_INET6;  

or specify ipv6

if (getaddrinfo("::", STR_PORT, &hints, &res) !=0) {  

For your application to accept IPv6 connections, but in this case the application will not accept IPv4 connections.

CORRECTION

It is possible to accept IPv4 and IPv6 connections on the same socket by using special IPv6 addresses called "IPv4-Mapped IPv6 Address". In this case, to bind localhost we use the IPv6 :: 0.0.0.0 address.

Below is an example of use.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <netdb.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <errno.h>

static char port[10] = "9009";
static char addr[20] = "::0.0.0.0";

static int make_server_socket(void)
{
  int sockfd;
  struct addrinfo *res = NULL, hints;

  memset(&hints, 0, sizeof(hints));

  hints.ai_flags = AI_PASSIVE;
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_protocol = IPPROTO_TCP;

  if (getaddrinfo(addr, port, &hints, &res) !=0)
  {
    printf("* erro em getaddrinfo\n");
    exit(1);
  }

  if ((sockfd=socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP)) == -1)
  {
    int err = errno;
    printf("* erro %d na criacao do socket\n", err);
    exit(1);
  }

  int reuse = 1;
  if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0)
  {
    int err = errno;
    printf("* erro %d no setsockopt\n", err);
    exit(1);
  }

  if (bind(sockfd, res->ai_addr, res->ai_addrlen) < 0)
  {
    int err = errno;
    printf("* erro %d no bind\n", err);
    exit(1);
  }

  freeaddrinfo(res);
  return sockfd;
}

int main(int argc, char* argv[])
{
  int sockfd = make_server_socket();

  if (argc > 1)
    strncpy(addr, argv[1], 19);

  if (argc > 2)
    strncpy(port, argv[2], 9);

  if (listen(sockfd, 1) < 0)
  {
    int err = errno;
    printf("* erro %d no listen\n", err);
    exit(1);
  }

  for (;;)
  {
    int csockfd = accept(sockfd, NULL, NULL);
    if (csockfd == -1)
    {
      int err = errno;
      printf("* erro %d no accept\n", err);
      exit(1);
    }

    printf("* conexao iniciada\n");

    int rv = write(csockfd, "Real Muthaphuckkin G's\n", 24);
    if (rv == -1)
    {
      int err = errno;
      printf("* errno %d no envio\n");
      exit(1);
    }
    printf("* envio bem sucedido\n");
    close(csockfd);
    printf("* conexao fechada\n");
  }
}

Netstat on Linux:

zv@localhost Misc]$ netstat -ant | grep 9009  
tcp6       0      0 :::9009                 :::*                    OUÇA      
[zv@localhost Misc]$ 

Telnet on Linux:

[zv@localhost Misc]$ telnet -4 127.0.0.1 9009
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Real Muthaphuckkin G's
Connection closed by foreign host.

[zv@localhost Misc]$ telnet -6 ::1 9009
Trying ::1...
Connected to ::1.
Escape character is '^]'.
Real Muthaphuckkin G's
Connection closed by foreign host.
[zv@localhost Misc]$ 
    
27.10.2018 / 01:14