Beispiel #1
0
        /// <summary>绑定</summary>
        /// <param name="request"></param>
        /// <param name="session"></param>
        /// <returns></returns>
        protected void OnBind(StunMessage request, ISocketSession session)
        {
            var rs = new StunMessage
            {
                Type          = StunMessageType.BindingResponse,
                TransactionID = request.TransactionID.ReadBytes(),
                MappedAddress = session.Remote.EndPoint
            };

            //rs.SourceAddress = session.GetRelativeEndPoint(remote.Address);
            if (Public != null)
            {
                if (session.Local.IsTcp)
                {
                    rs.SourceAddress = Public[session.Port + 100000];
                }
                else
                {
                    rs.SourceAddress = Public[session.Port];
                }
            }

            // 找另一个
            ISocketSession session2    = null;
            var            anotherPort = 0;

            for (var i = 0; i < Servers.Count; i++)
            {
                var server = Servers[i];
                if (server.Local.Type == session.Local.Type && server.Local.Port != session.Local.Port)
                {
                    anotherPort = server.Port;
                    if (server.Local.IsTcp)
                    {
                        break;
                    }
                    else
                    {
                        session2 = (server as UdpServer).CreateSession(session.Remote.EndPoint);
                        if (session2 != null)
                        {
                            break;
                        }
                    }
                }
            }
            //rs.ChangedAddress = Partner ?? session2.GetRelativeEndPoint(remote.Address);
            if (Public != null)
            {
                if (session.Local.IsTcp)
                {
                    rs.ChangedAddress = Partner ?? Public[anotherPort + 100000];
                }
                else
                {
                    rs.ChangedAddress = Partner ?? Public[anotherPort];
                }
            }

            var name = Name;

            if (name == GetType().Name)
            {
                name = GetType().FullName;
            }
            rs.ServerName = String.Format("{0} v{1}", name, AssemblyX.Create(Assembly.GetExecutingAssembly()).CompileVersion);

            // 换成另一个
            if (request.ChangePort)
            {
                session = session2;
            }

            session.Send(rs.ToArray());
        }
Beispiel #2
0
 /// <summary>查询</summary>
 /// <param name="request"></param>
 /// <param name="remoteEndPoint"></param>
 /// <returns></returns>
 public StunMessage Query(StunMessage request, IPEndPoint remoteEndPoint)
 {
     EnsureSocket();
     return(Query(Socket, request, remoteEndPoint));
 }
Beispiel #3
0
        /// <summary>接收到数据时</summary>
        /// <param name="session"></param>
        /// <param name="pk"></param>
        protected override void OnReceive(INetSession session, Packet pk)
        {
            if (pk.Total > 0)
            {
                var remote = session.Remote;
                //if (remote == null && session != null) remote = session.RemoteEndPoint;

                var request = StunMessage.Read(pk.GetStream());
                WriteLog("{0} {1} {2}{3}", request.Type, remote, request.ChangeIP ? " ChangeIP" : "", request.ChangePort ? " ChangePort" : "");

                // 如果是兄弟服务器发过来的,修正响应地址
                switch (request.Type)
                {
                case StunMessageType.BindingRequest:
                    //case StunMessageType.BindingResponse:
                    request.Type = StunMessageType.BindingRequest;
                    if (request.ResponseAddress != null)
                    {
                        remote.EndPoint = request.ResponseAddress;
                    }
                    break;

                case StunMessageType.SharedSecretRequest:
                    //case StunMessageType.SharedSecretResponse:
                    request.Type = StunMessageType.SharedSecretRequest;
                    if (request.ResponseAddress != null)
                    {
                        remote.EndPoint = request.ResponseAddress;
                    }
                    break;

                default:
                    break;
                }

                // 是否需要发给伙伴
                if (request.ChangeIP)
                {
                    //if (Partner != null && !Partner.Equals(session.Host.LocalEndPoint.GetRelativeEndPoint(Partner.Address)))
                    //{
                    //    // 发给伙伴
                    //    request.ChangeIP = false;
                    //    // 记住对方的地址
                    //    request.ResponseAddress = remote.EndPoint;
                    //    //session.Send(request.GetStream(), Partner);
                    //    var us = session.Host as UdpServer;
                    //    if (us != null)
                    //    {
                    //        //us.CreateSession(Partner).Send(request.GetStream());
                    //        us.Send(request.GetStream(), Partner);
                    //    }
                    //    return;
                    //}
                    // 如果没有伙伴地址,采用不同端口代替
                    request.ChangePort = true;
                }

                // 开始分流处理
                switch (request.Type)
                {
                case StunMessageType.BindingRequest:
                    //case StunMessageType.BindingResponse:
                    OnBind(request, session.Session);
                    break;

                case StunMessageType.SharedSecretRequest:
                    break;

                default:
                    break;
                }
            }
        }
Beispiel #4
0
        ///// <summary>在指定服务器上执行查询</summary>
        ///// <param name="host"></param>
        ///// <param name="port"></param>
        ///// <returns></returns>
        //public StunResult QueryWithServer(String host, Int32 port = 3478)
        //{
        //    try
        //    {
        //        return QueryWithServer(NetHelper.ParseAddress(host), port);
        //    }
        //    catch { return null; }
        //}

        /// <summary>在指定服务器上执行查询</summary>
        /// <param name="address"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public StunResult QueryWithServer(IPAddress address, Int32 port)
        {
            EnsureSocket();
            var client = Socket as ISocketClient;
            var remote = new IPEndPoint(address, port);

            // Test I
            // 测试网络是否畅通
            var msg = new StunMessage();

            msg.Type = StunMessageType.BindingRequest;
            var rs = Query(client, msg, remote);

            // UDP blocked.
            if (rs == null)
            {
                return(new StunResult(StunNetType.Blocked, null));
            }

            WriteLog("服务器:{0}", rs.ServerName);
            WriteLog("映射地址:{0}", rs.MappedAddress);
            WriteLog("源地址:{0}", rs.SourceAddress);
            WriteLog("新地址:{0}", rs.ChangedAddress);
            var remote2 = rs.ChangedAddress;

            // Test II
            // 要求改变IP和端口
            msg.ChangeIP   = true;
            msg.ChangePort = true;
            msg.ResetTransactionID();

            // 如果本地地址就是映射地址,表示没有NAT。这里的本地地址应该有问题,永远都会是0.0.0.0
            //if (client.LocalEndPoint.Equals(test1response.MappedAddress))
            var pub = rs.MappedAddress;

            if (pub != null && client.Local.Port == pub.Port && pub.Address.IsLocal())
            {
                // 要求STUN服务器从另一个地址和端口向当前映射端口发送消息。如果收到,表明是完全开放网络;如果没收到,可能是防火墙阻止了。
                rs = Query(client, msg, remote);
                // Open Internet.
                if (rs != null)
                {
                    return(new StunResult(StunNetType.OpenInternet, pub));
                }

                // Symmetric UDP firewall.
                return(new StunResult(StunNetType.SymmetricUdpFirewall, pub));
            }
            else
            {
                rs = Query(client, msg, remote);
                if (rs != null && pub == null)
                {
                    pub = rs.MappedAddress;
                }
                // Full cone NAT.
                if (rs != null)
                {
                    return(new StunResult(StunNetType.FullCone, pub));
                }

                // Test II
                msg.ChangeIP   = false;
                msg.ChangePort = false;
                msg.ResetTransactionID();

                // 如果是Tcp,这里需要准备第二个重用的Socket
                if (client.Local.IsTcp)
                {
                    EnsureSocket2();
                    client = Socket2 as ISocketClient;
                }

                rs = Query(client, msg, remote2);
                // 如果第二服务器没响应,重试
                if (rs == null)
                {
                    rs = Query(client, msg, remote2);
                }
                if (rs != null && pub == null)
                {
                    pub = rs.MappedAddress;
                }
                if (rs == null)
                {
                    return(new StunResult(StunNetType.Blocked, pub));
                }

                // 两次映射地址不一样,对称网络
                if (!rs.MappedAddress.Equals(pub))
                {
                    return(new StunResult(StunNetType.Symmetric, pub));
                }

                // Test III
                msg.ChangeIP   = false;
                msg.ChangePort = true;
                msg.ResetTransactionID();

                rs = Query(client, msg, remote2);
                if (rs != null && pub == null)
                {
                    pub = rs.MappedAddress;
                }
                // 受限
                if (rs != null)
                {
                    return(new StunResult(StunNetType.AddressRestrictedCone, pub));
                }

                // 端口受限
                return(new StunResult(StunNetType.PortRestrictedCone, pub));
            }
        }