Home > Blockchain >  accept fills client's IP as "::"
accept fills client's IP as "::"

Time:06-12

I start a server on :: to accept all possible connections.

    void StartServer(std::string ip, unsigned int port)
    {
        union sockaddr_types
        {
            struct sockaddr_storage storage;
            struct sockaddr addr;
            struct sockaddr_in in4;
            struct sockaddr_in6 in6;
        };
        sockaddr_types address_storage = {};
        
        if (inet_pton(PF_INET, ip.c_str(), &address_storage.in4.sin_addr) == 1)
        {
            address_storage.in4.sin_family = AF_INET;
            address_storage.in4.sin_port = htons(port);
        }
        else if (inet_pton(PF_INET6, ip.c_str(), &address_storage.in6.sin6_addr) == 1)
        {
            address_storage.in6.sin6_family = AF_INET6;
            address_storage.in6.sin6_port = htons(port);
        }
        else
        {
             return;
        }
        
        SocketFd = socket(address_storage.addr.sa_family, SOCK_STREAM, 0); // SocketFd a class member or a global variable
        int opt = 1;
        int ret = 0; 
        if (setsockopt(SocketFd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
        {
            // Error
        }
        else
        {
            if ((ret = bind(SocketFd, &address_storage.addr, sizeof(address_storage))) < 0)
            {
                // Error
            }
            else
            {
                if ((ret = listen(SocketFd, QueueSize)) < 0)
                {
                     // Error               
                }
                else
                {
                    while (true) // Just to simplify example
                    {
                        int clientScoketFd = 0;
                        sockaddr_in clientAddr = {};
                        socklen_t clientAddrlen = sizeof(clientAddr);

                        if ((clientScoketFd = accept(SocketFd, (sockaddr *)&clientAddr, &clientAddrlen)) < 0)
                        {
                             // Error
                        }
                        char buff[255] = {};
                        inet_ntop(clientAddr.sin_family, &clientAddr.sin_addr, buff, sizeof(buff));
                        printf("IP %s\n", buff);
                        DoJobOnSocket(clientScoketFd, buff);
                    }
                }
            }
        }
    }

Once a client with IPv4 connects to the server the output is

                    "IP ::"

Why it is zero and not an IPv4? When I start on IPv4 address this works fine, I see client's IPv4. Is there a way to get the IPv4 here for this situation, or I have to start server on IPv4 address?

CodePudding user response:

The client probably connected to the server using IPv6 and not via IPv4. You should check the address family (sin_family in your case). If that were AF_INET, then the inet_ntop would never return ::.

Checking just the sin_family member is relatively safe, but checking sin_addr is not if the address might be an IPv6 address. You should use a struct sockaddr_storage to store the address, but cast it as a struct sockaddr and just use the sa_family member until you know which type of address it is. Then you can cast it as struct sockaddr_in or struct sockaddr_in6.

The getnameinfo function deals well with this. It does all of this automatically.

  • Related