IPV4 Client to IPV6 Server Connection Problem

arsaalandailyUK 26 Reputation points
2021-06-23T18:58:02.02+00:00

I am new at IPV6 and I need to migrate my IPV4 code to dual-stack. I have two applications, one supports IPV6 (dual stack) and used at server side and the other one is IPV4 only client basically.

Note that, on same host, there are one server and multiple clients. Since the device supports dual stack, some closed applications have to use IPV4 only to communicate my server. Because of that, I am trying to use loopback IPs.

When I create a socket on server side for "::1" address, client cannot connect it by using "127.0.0.1" address. But, when I run the server on "::" address, client can connect and on sever side, I see the client IP as IPV4 mapped address (::ffff.127.0.0.1). But the thing is, I need to run the server on "::1" address because of some security concern.

Here is my code snipped on server side;
struct addrinfo hints, *result, *rp;
int rc = 0;
int sck = -1;

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

   rc = getaddrinfo(NULL, "9999", &hints, &result);
   if (rc != 0) {
       goto fail;
   }

   if (!result) {
       goto fail;
   }

   for (rp = result; rp != NULL; rp = rp->ai_next) {
       sck = socket(rp->ai_family, rp->ai_socktype, 0);
       if (sck == -1) {
           continue;
       }
       int yes = 1;
       if (setsockopt(sck, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0) {
           goto fail;
       }
       int v6OnlyEnabled = 0;
       if (setsockopt(sck, IPPROTO_IPV6, IPV6_V6ONLY, &v6OnlyEnabled, sizeof(v6OnlyEnabled)) != 0) {
           goto fail;
       }

       if (bind(sck, rp->ai_addr, rp->ai_addrlen) == 0) {
           break; //Success
       }

       //Fail
       close(sck);
       sck = -1;
   }

   freeaddrinfo(result);

   if (sck == -1) {
       goto fail;
   }

   rc = listen(sck, 10);
   if (rc < 0) {
       //error
       goto fail;
   }

fail:

   close(sck);
   sck = -1;

and here is the client side;

struct addrinfo hints, *addr_list, *cur;
    int retry = 0;
    int sck = -1;
    int rc = 0;
    int val;
    long arg;
    struct pollfd pollfd;
    socklen_t len = 0;


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

    rc = getaddrinfo(NULL, "9999", &hints, &addr_list);

    if (rc != 0) {
        printf("fail: %d\n", __LINE__);
        goto fail;
    }

    for (cur = addr_list; (cur != NULL); cur = cur->ai_next) {
        sck = socket(cur->ai_family, cur->ai_socktype, 0);
        if (sck < 0) {
            continue;
        }

        arg = fcntl(sck, F_GETFL, NULL);
        arg |= O_NONBLOCK;
        if (fcntl(sck, F_SETFL, arg) < 0) {
            printf("fail: %d\n", __LINE__);
            goto fail;
        }

        retry = 3;
        while (--retry) {
            //connecting
            rc = connect(sck, cur->ai_addr, cur->ai_addrlen);

            if (rc == 0) {
                printf("OK: %d\n", __LINE__);
                break;
            }

            pollfd.fd = sck;
            pollfd.events = POLLIN | POLLOUT;
            pollfd.revents = 0;
            rc = poll(&pollfd, 1, 100000);
            if (rc == 0) {
                //timeout
                printf("fail: %d\n", __LINE__);
                close(sck);
                sck = -1;
                break;
            }

            len = sizeof(val);
            rc = getsockopt(sck, SOL_SOCKET, SO_ERROR, (void *) (&val), &len);
            if (rc < 0) {
                //fail
                printf("fail: %d\n", __LINE__);
                close(sck);
                sck = -1;
                break;
            }

            if (val == EALREADY || val == EINPROGRESS) {
                //connecting
                printf("connecting: %d\n", __LINE__);
                break;
            }

            if (val == ECONNREFUSED) {
                (void)poll((void *)0, (unsigned long)0, (int)1000);
            }
        }
    }
    freeaddrinfo(addr_list);

    if (sck < 0)
        printf("fail %d\n", __LINE__);

fail:

   close(sck);
   sck = -1;

It seem disabling "IPV6_V6ONLY" option is not working. Also, I already compare "proc/sys/net/ipv6/conf/lo" and "all" folders' content. They seem same (except use_tempaddr nad mtu)

Please help me on that.

Thanks

Windows development Windows API - Win32
Windows for business Windows Server User experience Other
{count} vote

Accepted answer
  1. Xiaopo Yang - MSFT 12,731 Reputation points Microsoft External Staff
    2021-06-24T06:38:21.11+00:00

    You can refer to the Answer for Binding an IPv6 socket to an IPv6-mapped-IPv4-address. Wish The MSDN:IPv6-Enabled Server Code also help you.

    1 person found this answer helpful.
    0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.