首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带IPv6网络的NAT64套接字

带IPv6网络的NAT64套接字
EN

Stack Overflow用户
提问于 2017-10-01 14:40:31
回答 1查看 682关注 0票数 0

我正在尝试使用BSD为UE3实现UE3套接字连接。我已经成功地从UE4移植了代码,该代码使用了所有sockaddr_in6和其他相对于IPv6结构和变量的代码。

连接到常规网络或4G时运行良好,但通过Mac共享功能连接到NAT64网络(需要苹果批准)时,Connect()总是返回ENETUNREACH。我用一个iPad4和iPhone6S进行了测试,修改了很多代码(删除setIPv6Only函数、使用AF_UNSPEC查看等等),但它们中的任何一个都没有进展。

调试一些数据发现,getaddrinfo()正在从DNS返回一个IPv4,即使我在DNS表中设置了AAAA配置,指向一个允许IPv6的Amazon服务器(我最近添加了最后一部分,因为我之前认为服务器端也应该需要一个IPv6 )

下面是DNS查询:

代码语言:javascript
复制
FScopeLock ScopeLock(&HostByNameSynch);
addrinfo* AddrInfo = NULL;

// We are only interested in IPv6 addresses.
addrinfo HintAddrInfo;
appMemzero(&HintAddrInfo, sizeof(HintAddrInfo));

/* We only care about IPV6 results */
HintAddrInfo.ai_family = AF_INET6;//AF_UNSPEC;
HintAddrInfo.ai_socktype = SOCK_STREAM;
HintAddrInfo.ai_flags = AI_DEFAULT;

INT ErrorCode = SE_HOST_NOT_FOUND;
ErrorCode = getaddrinfo(HostName, NULL, &HintAddrInfo, &AddrInfo);
//ESocketErrors SocketError = TranslateGAIErrorCode(ErrorCode);
if (ErrorCode == SE_NO_ERROR)
{
    for (; AddrInfo != nullptr; AddrInfo = AddrInfo->ai_next)
    {
        if (AddrInfo->ai_family == AF_INET6)
        {
            /*sockaddr_in6* IPv6SockAddr = reinterpret_cast<sockaddr_in6*>(AddrInfo->ai_addr);
            if (IPv6SockAddr != nullptr)
            {
                static_cast<FInternetAddrBSDIPv6&>(OutAddr).SetIp(IPv6SockAddr->sin6_addr);
                return SE_NO_ERROR;
            }*/

            struct sockaddr_in6 input_socket6;
            memset (&input_socket6, 0, sizeof(struct sockaddr_in6));
            memcpy (&input_socket6, AddrInfo->ai_addr, AddrInfo->ai_addrlen);

            Addr.SetIp(input_socket6.sin6_addr);
            ErrorCode = 0;  // good to go.
            break;
        }
    }
}

freeaddrinfo(AddrInfo);

return ErrorCode;

以下是连接部分:

代码语言:javascript
复制
UBOOL FSocketBSD::Connect(const FInternetAddrBSDIPv6& Addr)
{
INT Err = 0;

Err = connect(Socket, (sockaddr*)(FInternetAddrBSDIPv6&)Addr, sizeof(sockaddr_in6));//connect(Socket,Addr,sizeof(struct sockaddr_in));

debugf(TEXT("TCP Connect to with V6 %s"), *Addr.ToString(TRUE) );

if (Err == 0)
{
    return TRUE;
}
else 
{
    debugf(TEXT("TCP ERROR Connect with result: %s"), GSocketSubsystem->GetSocketError(Err) );
}

Err = GSocketSubsystem->GetLastErrorCode();
INT Return = FALSE;
switch (Err)
{
    case 0:
    case EAGAIN:
    case EINPROGRESS:
    case EINTR:
        Return = TRUE;
        break;
}
return Return;
}

以下是套接字的创建:

代码语言:javascript
复制
SOCKET Socket = INVALID_SOCKET;
FSocketBSD* NewSocket = NULL;

// Creates a stream (TCP) socket
Socket = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
NewSocket = (Socket != INVALID_SOCKET) ? new FSocketBSD(Socket,SOCKTYPE_Streaming,SocketDescription) : NULL;

if (!NewSocket)
{
    debugf(NAME_Init, TEXT("Failed to create IPv6 socket %s [%s]"), *SocketDescription);
}
else 
{
    NewSocket->SetIPv6Only(false);

    // disable the SIGPIPE exception 
    int bAllow = 1;
    setsockopt(Socket, SOL_SOCKET, SO_NOSIGPIPE, &bAllow, sizeof(bAllow)); 
}

return NewSocket;


UBOOL FSocketBSD::SetIPv6Only(UBOOL bIPv6Only)
{
    INT v6only = bIPv6Only ? 1 : 0;
    UBOOL bOk = setsockopt(Socket,IPPROTO_IPV6,IPV6_V6ONLY,(char*) &v6only,sizeof( v6only )) == 0;

    if(bOk == false)
    {
        //check(SocketSubsystem);
        debugf(NAME_Init, TEXT("Failed to set sock opt for socket (%s)"), GSocketSubsystem->GetSocketError());
    }

    return bOk;
}

下面是一些调试信息:

代码语言:javascript
复制
[0009.49] Log: TCP SetIp TCHAR u101si.info
[0009.49] Log: TCP GetHostByNameFromCache with FInternetAddrBSDIPv6
[0009.49] Log: TCP GetHostByName starting async task
[0009.49] Log: TCP Performing DNS lookup for u101si.info
[0009.66] Log: TCP SetIp in6_addr
[0009.66] Log: TCP AddHostNameToCache with FInternetAddrBSDIPv6
[0009.66] Log: TCP Tick DNS lookup
[0009.66] Log: TCP AInternetLink Resolve success
[0009.66] ScriptLog: [TcpLinkClient] resolved to 54.169.208.63:4646
[0009.66] Log: Host addr is WIFI: 169.254.23.45
[0009.66] Log: TCP BindPort with NewSocket at 0.0.0.0
[0009.66] Log: TCP SetIp FInternetIpAddr for 0.0.0.0
[0009.66] Log: TCP SetIp in_addr
[0009.66] Log: TCP Using IPv4 address: 0.0.0.0  on an ipv6 socket
[0009.66] Log: TCP Bind for 0.0.0.0:0 result: 1
[0009.66] ScriptLog: [TcpLinkClient] Bound to port: 60885
[0009.66] Log: TCP Open with 54.169.208.63
[0009.66] Log: TCP SetIp with INT value: 917098559
[0009.66] Log: TCP SetIp in_addr
[0009.66] Log: TCP Using IPv4 address: 54.169.208.63  on an ipv6 socket
[0009.66] Log: TCP Connect to with V6 [::ffff:54.169.208.63]:4646
[0009.66] Log: TCP ERROR Connect with result: SE_ENETUNREACH

我从未使用过IPv6协议或低级套接字连接,所以我在这里迷失了方向。这是导致客户端问题的原因吗?DNS查找问题?服务器不接受IPv6客户端?

提前感谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-10-03 15:46:11

在这个设备上做了多次测试后,我让它正常工作了。

问题在于DNS缓存,即返回过时的IP和调用getaddrinfo()。当添加端口参数时,它在DNS中触发正确的寄存器:a用于IPv4,AAAA用于IPv6。

这是对IPv4和IPv6的调用:

代码语言:javascript
复制
FInternetAddrBSDIPv6& Addr;
struct addrinfo *res, *res0;

// We are only interested in IPv6 addresses.
addrinfo HintAddrInfo;
appMemzero(&HintAddrInfo, sizeof(HintAddrInfo));

HintAddrInfo.ai_family = AF_UNSPEC;
HintAddrInfo.ai_socktype = SOCK_STREAM;
//HintAddrInfo.ai_protocol = IPPROTO_TCP;
HintAddrInfo.ai_flags = AI_DEFAULT;

INT ErrorCode = SE_HOST_NOT_FOUND;
ErrorCode = getaddrinfo(HostName, "1212", &HintAddrInfo, &res0);

if (ErrorCode == SE_NO_ERROR)
{
    for (res = res0; res; res = res->ai_next) 
    {
        debugf(TEXT("TCP GetHostByName with DNS successful"));

        if (res->ai_addr != 0)
        {
            if( res->ai_family == AF_INET6 )
            {
                struct sockaddr_in6 input_socket6;
                memset (&input_socket6, 0, sizeof(struct sockaddr_in6));
                memcpy (&input_socket6, res->ai_addr, res->ai_addrlen);

                Addr.SetIp(input_socket6.sin6_addr);
                ErrorCode = 0;  // good to go.
                break;
            }
            else if( res->ai_family == AF_INET )
            {
                const in_addr &IP = ((sockaddr_in *) res->ai_addr)->sin_addr;
                Addr.SetIp(IP);
                ErrorCode = 0;  // good to go.
                break;
            }
        }

    }
}

freeaddrinfo(res0);

return ErrorCode;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46513473

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档