【问题标题】:OS X equivalent of SO_BINDTODEVICEOS X 相当于 SO_BINDTODEVICE
【发布时间】:2014-01-04 03:29:16
【问题描述】:

Linux 允许执行以下代码将套接字绑定到某个特定的网络接口。因此,通过此套接字发送的数据将始终通过原始接口进行引导。

setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name))

据我了解,此功能用于 VPN 客户端。套接字连接到远程服务器并绑定到网络接口。这样,来自 VPN 客户端的流量就不会被环回到 VPN 客户端。

是否有 OS X 相当于这样做?要么

  • 将套接字绑定到某个特定接口

  • 将 VPN 客户端中的套接字标记为不被环回。

顺便说一句。我发现了类似的问题,但我不明白答案: Writing an OS X kernel extension to implement Linux's SO_BINDTODEVICE socket option

更新 1

我发现一些 VPN 客户端使用 TUN/TAP 设备来防止环回问题。 http://backreference.org/2010/03/26/tuntap-interface-tutorial/

但是,我并不是说所有 OS X VPN 都使用它。

【问题讨论】:

    标签: linux macos sockets vpn


    【解决方案1】:

    是否使用 getifaddrs() 来识别设备的地址,然后直接绑定到该设备?或者 SO_BINDTODEVICE 除了传统的 bind() 调用还有其他行为吗?

    int BindToDevice(int sock, int family, const char* devicename)
    {
        ifaddrs* pList = NULL;
        ifaddrs* pAdapter = NULL;
        ifaddrs* pAdapterFound = NULL;
        int bindresult = -1;
    
        int result = getifaddrs(&pList);
    
        if (result < 0)
            return -1;
    
        pAdapter = pList;
        while (pAdapter)
        {
            if ((pAdapter->ifa_addr != NULL) && (pAdapter->ifa_name != NULL) && (family == pAdapter->ifa_addr->sa_family))
            {
                if (strcmp(pAdapter->ifa_name, devicename) == 0)
                {
                    pAdapterFound = pAdapter;
                    break;
                }
            }
            pAdapter = pAdapter->ifa_next;
        }
    
        if (pAdapterFound != NULL)
        {
            int addrsize = (family == AF_INET6)?sizeof(sockaddr_in6):sizeof(sockaddr_in);
            bindresult = bind(sock, pAdapterFound->ifa_addr, addrsize);
        }
    
        freeifaddrs(pList);
        return bindresult;
    }
    

    【讨论】:

    • 我的印象是 bind() 仅在我们想要执行 listen() 和 accept() 的情况下使用。但是,就我而言,我想做 connect(),因为这个套接字是给客户端的。
    • 只要路由表允许,也可以与客户端(连接)套接字一起使用。
    【解决方案2】:

    使用 RFC 3542 接口选择传出接口 (IPV6_PKTINFO)。 https://www.rfc-editor.org/rfc/rfc3542#section-6

    【讨论】:

      【解决方案3】:

      这对我有用:

      char ethInterface[4] = "en0";
      setsockopt(sock, SOL_SOCKET, IP_RECVIF, ethInterface, strlen(ethInterface));
      

      【讨论】:

      • -1 这听起来不对。根据 Stevens 的说法,这用于指定接收/发送接口的名称,但为此:“此套接字选项导致接收 UDP 数据报的接口的索引作为辅助返回recvmsg 提供的数据。”
      【解决方案4】:

      是的,使用IP_BOUND_IF

      int idx = if_nametoindex("en0");
      setsockopt(sockfd, IPPROTO_IP, IP_BOUND_IF, &idx, sizeof(idx))
      

      但是,您可以将bind() 与接口的 IP 地址一起使用,这通常更容易。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-29
        • 2011-06-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-27
        • 2011-03-01
        相关资源
        最近更新 更多