STUN协议检测网络环境流程

STUN(Simple Traversal of UDP over NATs,NAT的UDP简单穿越)是一种网络协议,允许位于NAT(或多重NAT)后的客户端找出自己的公网地址,查出自己位于哪种类型的NAT之后。这些信息可用来在两个同时处于NAT路由器之后的主机之间建立UDP通信,下面先简要介绍一下NAT类型。

NAT(网络地址转换)按照实现方式分为:Full Cone NAT,Restricted Cone NAT, Port Restricted Cone NAT以及Symmetric NAT四种

  • Full Cone: 同一个内部客户端的请求源IP端口X被NAT转换为同一个外部IP以及端口Y,不管这些请求是否来自一个应用还是多个应用,当X-Y关系建立后,任何外部主机向Y发送的UDP报文均可被NAT转发给X。
  • Restricted Cone:是Full Cone的受限版本,只有当内部主机曾经发送过报文的外部主机(假设为Z)发送给Y的UDP报文才会被转发。
  • Port Restricted Cone:是Restricted Cone的进一步受限版本,Z主机必须是某个特定的端口P发送的UDP报文才会被转发(这个P是内部主机对外请求时的远端端口)
  • Semmetric NAT:只有来自于内部同一个客户端,且请求同样目标才分配同一通道(这种方式极难穿透成功)

STUN客户端的工作流程图如下:

STUN协议检测网络环境流程_第1张图片

文字介绍:

  1. TEST I,向Stun服务器发起UDP连接,获取Stun服务器返回的信息(包含本机的外网地址与端口)
    • 如果没有获取到响应信息,则说明UDP通信可能被防火墙阻断,不能通信,结束检测(UDP Blocked)
    • 解析响应信息,判断外网地址端口与本机地址端口是否一致,如果一致,进入步骤2
  2. TEST II,向Stun服务器发起UDP连接并通知它用其他IP和端口返回响应,然后等待数据接收
    • 如果没有获取到数据,说明防火墙做了地址和端口过滤,只能允许目标地址端口返回信息(Sym. UDP Firewall)
    • 如果获取到数据,则是完全开放的网络环境(Open Internet)
  3. TEST II,同上
    • 如果获取到数据,终止检测(Full Cone)
    • 如果没获取到数据,向Stun服务器更换后的IP以及端口发送数据包,查看返回的外网端口与地址和第一步是否一致
      • 如果不一致,说明是对称性NAT(Symmetric NAT)
      • 如果一致,进行第4步判断是地址限制还是端口限制类型
  4. TEST III,向Stun服务器发送UDP并通知它用本IP以及其他端口响应,等待数据接收
    • 没有获取到数据,说明是端口限制(Port Restricted Cone)
    • 获取到数据,说明是地址限制 (Restricted Cone)
对应代码:

    public function getNatType(){
        
        if($this->socket == null){
            return null;
        }
        
        $res = $this->testI1();
        if($res == RET_VALUE::$_RET_TEST_I1_UDP_BLOCKED){
            return NAT_TYPE::$_NAT_TYPE_UDP_BLOCKED;
        }
        elseif($res == RET_VALUE::$_RET_TEST_I1_IP_SAME){
            $res = $this->testII();
            if($res == RET_VALUE::$_RET_TEST_II_GOT_RESP){
                return NAT_TYPE::$_NAT_TYPE_OPENED;
            }
            return NAT_TYPE::$_NAT_TYPE_SYM_UDP_FIREWALL;
        }
        else{
            $res = $this->testII();
            if($res == RET_VALUE::$_RET_TEST_II_GOT_RESP){
                return NAT_TYPE::$_NAT_TYPE_FULLCONE_NAT;
            }
            $res = $this->testI2();
            if($res == RET_VALUE::$_RET_TEST_I2_IP_DIFF){
                $res = $this->testIV();
                if($res == RET_VALUE::$_RET_TEST_IV_LOCAL){
                    return NAT_TYPE::$_NAT_TYPE_SYM_NAT_LOCAL;
                }
                return NAT_TYPE::$_NAT_TYPE_SYM_NAT;
            }
            $res = $this->testIII();
            if($res == RET_VALUE::$_RET_TEST_III_GOT_RESP){
                return NAT_TYPE::$_NAT_TYPE_REST_NAT;
            }
            if($res != null){
                return NAT_TYPE::$_NAT_TYPE_PORTREST_NAT;
            }
        }
    }

具体内容可以参照我的Github。

你可能感兴趣的:(网络,服务器,网络协议,防火墙,null,traversal)