IPV4 客户端到 IPV6 服务器连接问题

时间:2021-06-23 18:52:25

标签: c linux sockets ipv6 ipv4

我是 IPV6 的新手,我需要将我的 IPV4 代码迁移到双栈。我有两个应用程序,一个支持 IPV6(双栈)并在服务器端使用,另一个基本上是仅 IPV4 的客户端。

请注意,在同一主机上,有一台服务器和多个客户端。由于设备支持双栈,一些封闭的应用程序只能使用 IPV4 来与我的服务器通信。因此,我正在尝试使用环回 IP。

当我在服务器端为“::1”地址创建套接字时,客户端无法使用“127.0.0.1”地址连接它。但是,当我在“::”地址上运行服务器时,客户端可以连接,而在服务器端,我将客户端 IP 视为 IPV4 映射地址 (::ffff.127.0.0.1)。但问题是,出于安全考虑,我需要在“::1”地址上运行服务器

这是我在服务器端截取的代码;

   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("::1", "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;

这里是客户端;

    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("127.0.0.1", "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;

似乎禁用“IPV6_V6ONLY”选项不起作用。 另外,我已经比较了“proc/sys/net/ipv6/conf/lo”和“all”文件夹的内容。它们看起来一样(除了 use_tempaddr 和 mtu)

请帮我解决这个问题。

谢谢

0 个答案:

没有答案