Ejemplo n.º 1
0
    /// <summary>
    /// Gets NAT info from STUN server.
    /// </summary>
    /// <param name="host">STUN server name or IP.</param>
    /// <param name="port">STUN server port. Default port is 3478.</param>
    /// <param name="socket">UDP socket to use.</param>
    /// <returns>Returns UDP netwrok info.</returns>
    /// <exception cref="Exception">Throws exception if unexpected error happens.</exception>
    public void Query(string host, int port, Socket socket)
    {
        if (host == null)
        {
            throw new System.ArgumentNullException("host");
        }
        if (socket == null)
        {
            throw new System.ArgumentNullException("socket");
        }
        if (port < 1)
        {
            throw new System.ArgumentNullException("Port value must be >= 1 !");
        }
        if (socket.ProtocolType != ProtocolType.Udp)
        {
            throw new System.ArgumentNullException("Socket must be UDP socket !");
        }

        IPEndPoint remoteEndPoint = new IPEndPoint(System.Net.Dns.GetHostAddresses(host)[0], port);

        socket.ReceiveTimeout = 3000;
        socket.SendTimeout = 3000;

        // Test I
        STUN_Message test1 = new STUN_Message();
        test1.Type = STUN_MessageType.BindingRequest;
        transaction.doTransaction(test1, socket, remoteEndPoint);
        transactionFunc = test1ResponeFunc;
        timer.enabled = true;
    }
Ejemplo n.º 2
0
 public void doTransaction(STUN_Message pRequest)
 {
     doTransaction(pRequest, socket, remoteEndPoint);
 }
Ejemplo n.º 3
0
 public void doTransaction(STUN_Message pRequest, Socket pSocket,
     IPEndPoint pRemoteEndPoint)
 {
     request = pRequest;
     socket = pSocket;
     remoteEndPoint = pRemoteEndPoint;
     startTime = Time.realtimeSinceStartup;
     socket.SendTo(requestBytes, remoteEndPoint);
 }
Ejemplo n.º 4
0
 TransactionFunc transactionRespone(STUN_Message pRequest,TransactionFunc pFunc )
 {
     transaction.doTransaction(pRequest);
     return pFunc;
 }
Ejemplo n.º 5
0
        public STUN_Message continueTransaction()
        {
            socket.SendTo(requestBytes, remoteEndPoint);

            // We got response.
            if (socket.Poll(100, SelectMode.SelectRead))
            {
                byte[] receiveBuffer = new byte[512];
                socket.Receive(receiveBuffer);

                // Parse message
                STUN_Message response = new STUN_Message();
                response.Parse(receiveBuffer);

                // Check that transaction ID matches or not response what we want.
                if (request.TransactionID.Equals(response.TransactionID))
                {
                    return response;
                }
            }

            return null;
        }
Ejemplo n.º 6
0
 TransactionFunc test3ResponeFunc(STUN_Message pRequest)
 {
     // Restricted
     if (pRequest != null)
     {
         return succeedRespone(
             new STUN_Result(STUN_NetType.RestrictedCone, test1ResponeMessage.MappedAddress));
     }
     // Port restricted
     else
     {
         return succeedRespone(
             new STUN_Result(STUN_NetType.PortRestrictedCone, test1ResponeMessage.MappedAddress));
     }
 }
Ejemplo n.º 7
0
 TransactionFunc testI_IIResponeFunc(STUN_Message pRequest)
 {
     if (pRequest == null)
     {
         Debug.LogError("STUN Test I(II) dind't get resonse !");
         stunFail();
         return null;
     }
     else
     {
         // Symmetric NAT
         if (!test1ResponeMessage.MappedAddress.Equals(pRequest.MappedAddress))
         {
             return succeedRespone(
                 new STUN_Result(STUN_NetType.Symmetric, pRequest.MappedAddress));
         }
         else
         {
             // Test III
             STUN_Message test3 = new STUN_Message();
             test3.Type = STUN_MessageType.BindingRequest;
             test3.ChangeRequest = new STUN_t_ChangeRequest(false, true);
             return transactionRespone(test3, test3ResponeFunc);
         }
     }
 }
Ejemplo n.º 8
0
 TransactionFunc noNATResponeFunc(STUN_Message pRequest)
 {
     STUN_Result lResult;
     // Open Internet.
     if (pRequest != null)
     {
         lResult = new STUN_Result(STUN_NetType.OpenInternet, pRequest.MappedAddress);
     }
     // Symmetric UDP firewall.
     else
     {
         lResult = new STUN_Result(STUN_NetType.SymmetricUdpFirewall, pRequest.MappedAddress);
     }
     return succeedRespone(lResult);
 }
Ejemplo n.º 9
0
    TransactionFunc test1ResponeFunc(STUN_Message test1response)
    {
        // UDP blocked.
        if (test1response == null)
        {
            result = new STUN_Result(STUN_NetType.UdpBlocked, null);
            stunFail();
            return null;
        }
        else
        {
            test1ResponeMessage = test1response;
            // Test II
            STUN_Message test2 = new STUN_Message();
            test2.Type = STUN_MessageType.BindingRequest;
            test2.ChangeRequest = new STUN_t_ChangeRequest(true, true);

            // No NAT.
            if (transaction.socket.LocalEndPoint.Equals(test1response.MappedAddress))
            {
                return transactionRespone(test2, noNATResponeFunc);
            }
            // NAT
            else
            {
                return transactionRespone(test2, NATResponeFunc);
            }
        }
    }
Ejemplo n.º 10
0
    TransactionFunc NATResponeFunc(STUN_Message pRequest)
    {
        // Full cone NAT.
        if (pRequest != null)
        {
            return succeedRespone(
                new STUN_Result(STUN_NetType.FullCone, pRequest.MappedAddress));
        }
        else
        {
            STUN_Message test12 = new STUN_Message();
            test12.Type = STUN_MessageType.BindingRequest;

            return transactionRespone(test12, testI_IIResponeFunc);
        }
    }
Ejemplo n.º 11
0
        /// <summary>
        /// Gets NAT info from STUN server.
        /// </summary>
        /// <param name="host">STUN server name or IP.</param>
        /// <param name="port">STUN server port. Default port is 3478.</param>
        /// <param name="socket">UDP socket to use.</param>
        /// <returns>Returns UDP netwrok info.</returns>
        /// <exception cref="Exception">Throws exception if unexpected error happens.</exception>
        public static STUN_Result Query(string host,int port,Socket socket)
        {
            if(host == null){
                throw new ArgumentNullException("host");
            }
            if(socket == null){
                throw new ArgumentNullException("socket");
            }
            if(port < 1){
                throw new ArgumentException("Port value must be >= 1 !");
            }
            if(socket.ProtocolType != ProtocolType.Udp){
                throw new ArgumentException("Socket must be UDP socket !");
            }

            IPEndPoint remoteEndPoint = new IPEndPoint(System.Net.Dns.GetHostAddresses(host)[0],port);
            
            /*
                In test I, the client sends a STUN Binding Request to a server, without any flags set in the
                CHANGE-REQUEST attribute, and without the RESPONSE-ADDRESS attribute. This causes the server 
                to send the response back to the address and port that the request came from.
            
                In test II, the client sends a Binding Request with both the "change IP" and "change port" flags
                from the CHANGE-REQUEST attribute set.  
              
                In test III, the client sends a Binding Request with only the "change port" flag set.
                          
                                    +--------+
                                    |  Test  |
                                    |   I    |
                                    +--------+
                                         |
                                         |
                                         V
                                        /\              /\
                                     N /  \ Y          /  \ Y             +--------+
                      UDP     <-------/Resp\--------->/ IP \------------->|  Test  |
                      Blocked         \ ?  /          \Same/              |   II   |
                                       \  /            \? /               +--------+
                                        \/              \/                    |
                                                         | N                  |
                                                         |                    V
                                                         V                    /\
                                                     +--------+  Sym.      N /  \
                                                     |  Test  |  UDP    <---/Resp\
                                                     |   II   |  Firewall   \ ?  /
                                                     +--------+              \  /
                                                         |                    \/
                                                         V                     |Y
                              /\                         /\                    |
               Symmetric  N  /  \       +--------+   N  /  \                   V
                  NAT  <--- / IP \<-----|  Test  |<--- /Resp\               Open
                            \Same/      |   I    |     \ ?  /               Internet
                             \? /       +--------+      \  /
                              \/                         \/
                              |                           |Y
                              |                           |
                              |                           V
                              |                           Full
                              |                           Cone
                              V              /\
                          +--------+        /  \ Y
                          |  Test  |------>/Resp\---->Restricted
                          |   III  |       \ ?  /
                          +--------+        \  /
                                             \/
                                              |N
                                              |       Port
                                              +------>Restricted

            */

            try{
                // Test I
                STUN_Message test1 = new STUN_Message();
                test1.Type = STUN_MessageType.BindingRequest;
                STUN_Message test1response = DoTransaction(test1,socket,remoteEndPoint,1600);
    
                // UDP blocked.
                if(test1response == null){
                    return new STUN_Result(STUN_NetType.UdpBlocked,null);
                }
                else{
                    // Test II
                    STUN_Message test2 = new STUN_Message();
                    test2.Type = STUN_MessageType.BindingRequest;
                    test2.ChangeRequest = new STUN_t_ChangeRequest(true,true);

                    // No NAT.
                    if(socket.LocalEndPoint.Equals(test1response.MappedAddress)){
                        STUN_Message test2Response = DoTransaction(test2,socket,remoteEndPoint,1600);
                        // Open Internet.
                        if(test2Response != null){
                            return new STUN_Result(STUN_NetType.OpenInternet,test1response.MappedAddress);
                        }
                        // Symmetric UDP firewall.
                        else{
                            return new STUN_Result(STUN_NetType.SymmetricUdpFirewall,test1response.MappedAddress);
                        }
                    }
                    // NAT
                    else{
                        STUN_Message test2Response = DoTransaction(test2,socket,remoteEndPoint,1600);
            
                        // Full cone NAT.
                        if(test2Response != null){
                            return new STUN_Result(STUN_NetType.FullCone,test1response.MappedAddress);
                        }
                        else{
                            /*
                                If no response is received, it performs test I again, but this time, does so to 
                                the address and port from the CHANGED-ADDRESS attribute from the response to test I.
                            */

                            // Test I(II)
                            STUN_Message test12 = new STUN_Message();
                            test12.Type = STUN_MessageType.BindingRequest;

                            STUN_Message test12Response = DoTransaction(test12,socket,test1response.ChangedAddress,1600);
                            if(test12Response == null){
                                throw new Exception("STUN Test I(II) dind't get resonse !");
                            }
                            else{
                                // Symmetric NAT
                                if(!test12Response.MappedAddress.Equals(test1response.MappedAddress)){
                                    return new STUN_Result(STUN_NetType.Symmetric,test1response.MappedAddress);
                                }
                                else{
                                    // Test III
                                    STUN_Message test3 = new STUN_Message();
                                    test3.Type = STUN_MessageType.BindingRequest;
                                    test3.ChangeRequest = new STUN_t_ChangeRequest(false,true);

                                    STUN_Message test3Response = DoTransaction(test3,socket,test1response.ChangedAddress,1600);
                                    // Restricted
                                    if(test3Response != null){
                                        return new STUN_Result(STUN_NetType.RestrictedCone,test1response.MappedAddress);
                                    }
                                    // Port restricted
                                    else{
                                        return new STUN_Result(STUN_NetType.PortRestrictedCone,test1response.MappedAddress);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            finally{
                // Junk all late responses.
                DateTime startTime = DateTime.Now;
                while(startTime.AddMilliseconds(200) > DateTime.Now){
                    // We got response.
                    if(socket.Poll(1,SelectMode.SelectRead)){
                        byte[] receiveBuffer = new byte[512];
                        socket.Receive(receiveBuffer);
                    }
                }
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Does STUN transaction. Returns transaction response or null if transaction failed.
        /// </summary>
        /// <param name="request">STUN message.</param>
        /// <param name="socket">Socket to use for send/receive.</param>
        /// <param name="remoteEndPoint">Remote end point.</param>
        /// <param name="timeout">Timeout in milli seconds.</param>
        /// <returns>Returns transaction response or null if transaction failed.</returns>
        private static STUN_Message DoTransaction(STUN_Message request,Socket socket,IPEndPoint remoteEndPoint,int timeout)
        {                        
            byte[] requestBytes = request.ToByteData();                              
            DateTime startTime = DateTime.Now;
            // Retransmit with 500 ms.
            while(startTime.AddMilliseconds(timeout) > DateTime.Now){
                try{
                    socket.SendTo(requestBytes,remoteEndPoint);

                    // We got response.
                    if(socket.Poll(500 * 1000,SelectMode.SelectRead)){
                        byte[] receiveBuffer = new byte[512];
                        socket.Receive(receiveBuffer);

                        // Parse message
                        STUN_Message response = new STUN_Message();
                        response.Parse(receiveBuffer);
                
                        // Check that transaction ID matches or not response what we want.
                        if(Net_Utils.CompareArray(request.TransactionID,response.TransactionID)){                            
                            return response;
                        }
                    }
                }
                catch{
                }
            }

            return null;
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Resolves socket local end point to public end point.
        /// </summary>
        /// <param name="stunServer">STUN server.</param>
        /// <param name="port">STUN server port. Default port is 3478.</param>
        /// <param name="socket">UDP socket to use.</param>
        /// <returns>Returns public IP end point.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>stunServer</b> or <b>socket</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        /// <exception cref="IOException">Is raised when no connection to STUN server.</exception>
        public static IPEndPoint GetPublicEP(string stunServer,int port,Socket socket)
        {
            if(stunServer == null){
                throw new ArgumentNullException("stunServer");
            }
            if(stunServer == ""){
                throw new ArgumentException("Argument 'stunServer' value must be specified.");
            }
            if(port < 1){
                throw new ArgumentException("Invalid argument 'port' value.");
            }
            if(socket == null){
                throw new ArgumentNullException("socket");
            }
            if(socket.ProtocolType != ProtocolType.Udp){
                throw new ArgumentException("Socket must be UDP socket !");
            }

            IPEndPoint remoteEndPoint = new IPEndPoint(System.Net.Dns.GetHostAddresses(stunServer)[0],port);

            try{
                // Test I
                STUN_Message test1 = new STUN_Message();
                test1.Type = STUN_MessageType.BindingRequest;
                STUN_Message test1response = DoTransaction(test1,socket,remoteEndPoint,1000);
    
                // UDP blocked.
                if(test1response == null){
                    throw new IOException("Failed to STUN public IP address. STUN server name is invalid or firewall blocks STUN.");
                }

                return test1response.SourceAddress;
            }
            catch{
                throw new IOException("Failed to STUN public IP address. STUN server name is invalid or firewall blocks STUN.");
            }
            finally{
                // Junk all late responses.
                DateTime startTime = DateTime.Now;
                while(startTime.AddMilliseconds(200) > DateTime.Now){
                    // We got response.
                    if(socket.Poll(1,SelectMode.SelectRead)){
                        byte[] receiveBuffer = new byte[512];
                        socket.Receive(receiveBuffer);
                    }
                }
            }
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Does STUN transaction. Returns transaction response or null if transaction failed.
        /// </summary>
        /// <param name="request">STUN message.</param>
        /// <param name="socket">Socket to use for send/receive.</param>
        /// <param name="remoteEndPoint">Remote end point.</param>
        /// <returns>Returns transaction response or null if transaction failed.</returns>
        private static STUN_Message DoTransaction(STUN_Message request,Socket socket,IPEndPoint remoteEndPoint)
        {
            byte[] requestBytes = request.ToByteData();
            DateTime startTime = DateTime.Now;
            // We do it only 2 sec and retransmit with 100 ms.
            while(startTime.AddSeconds(2) > DateTime.Now){
                try{
                    socket.SendTo(requestBytes,remoteEndPoint);

                    // We got response.
                    if(socket.Poll(100,SelectMode.SelectRead)){
                        byte[] receiveBuffer = new byte[512];
                        socket.Receive(receiveBuffer);

                        // Parse message
                        STUN_Message response = new STUN_Message();
                        response.Parse(receiveBuffer);

                        // Check that transaction ID matches or not response what we want.
                        if(request.TransactionID.Equals(response.TransactionID)){
                            return response;
                        }
                    }
                }
                catch{
                }
            }

            return null;
        }