Why is my server code not working with Ipv6?

Asked

Viewed 90 times

2

I recently wrote a small C server using the sockets API from UNIX only for some tests. The program works perfectly with Ipv4, but the same does not happen with Ipv6...

Follows 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;
}

Code compiled and in operation:

Connecting to the server via local address Ipv4:

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 local address Ipv6:

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

nmap output (while the server was running):

Scanning for local address Ipv4:

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 for local address Ipv6:

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 I have to do to make my code work with Ipv6 correctly?

1 answer

4

You cannot use Ipv4 and Ipv6 in the same socket.

In the case in question, if you want to meet Ipv6 then you need to specify the family

hints.ai_family = AF_INET6;  

or else 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

You can accept Ipv4 and Ipv6 connections in the same socket by using special Ipv6 addresses called "Ipv4-Mapped Ipv6 Address". In this case, to bind to localhost we use the Ipv6 address ::0.0.0.0.

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]$ 

Browser other questions tagged

You are not signed in. Login or sign up in order to post.