コード例 #1
0
        /// <summary>
        /// Parses an array of bytes containing every attributes of a message and
        /// add them to managed and unmanaged attributes lists
        /// </summary>
        /// <param name="attributes">The array of byte which contains every attributes of a message</param>
        private void ImportAttributes(byte[] attributes)
        {
            Int32 offset           = 0;
            Int32 attributesLength = attributes.Length;

            while (offset < attributesLength)
            {
                // We retrieve length and add it attribute header length (4 bytes)
                UInt16 valueLength     = BitConverter.ToUInt16(StunUtilities.SubArray(attributes, offset + 2, 2), 0);
                UInt16 attributeLength = (UInt16)(StunUtilities.ReverseBytes(valueLength) + 4);

                // Adjust original length to a padded 32bit length
                if (attributeLength % 4 != 0)
                {
                    attributeLength = (UInt16)(attributeLength + (4 - attributeLength % 4));
                }

                StunAttribute attr = StunUtilities.SubArray(attributes, offset, attributeLength);

                // When doing auto conversion of a byte array, according to STUN RFC 5389
                // only the first attribute of a given type must be taken into account
                this.SetAttribute(attr, false);

                offset += attributeLength;
            }
        }
コード例 #2
0
        /// <summary>
        /// Computes a HMAC SHA1 based on this StunMessage attributes
        /// </summary>
        /// <param name="hmacSha1Key">The key of HMAC SHA1 computation algorithm</param>
        /// <returns>The HMAC computed value of this StunMessage</returns>
        private byte[] ComputeHMAC(byte[] hmacSha1Key)
        {
            byte[] hashed;

            using (HMACSHA1 hmacSha1 = new HMACSHA1(hmacSha1Key))
            {
                StunMessage thisCopy = new StunMessage(this.MethodType, this.MethodClass, this.TransactionID);

                foreach (var item in this.attributesList)
                {
                    if (item.Key == StunAttributeType.MessageIntegrity)
                    {
                        break;
                    }

                    thisCopy.SetAttribute(item.Value);
                }

                if (this.Stun.FingerPrint != null)
                {
                    thisCopy.SetAttribute(this.Stun.FingerPrint);
                }

                byte[] thisCopyBytes = thisCopy;

                // Insert a fake message length for HMAC computation as described in [RFC5489#15.4]
                UInt16 dummyLength = StunUtilities.ReverseBytes((UInt16)(thisCopy.MessageLength + 24)); // 20 hmac + 4 header

                BitConverter.GetBytes(dummyLength).CopyTo(thisCopyBytes, 2);

                hashed = hmacSha1.ComputeHash(thisCopyBytes);
            }

            return(hashed);
        }
コード例 #3
0
        /// <summary>
        /// Convert a network-byte ordered array of bytes to a StunAttributeType
        /// </summary>
        /// <param name="bytes">An array of 2 bytes (16bits) representing an attribute type</param>
        /// <returns>
        /// The StunAttributeType matching the array of bytes
        /// Returns StunAttributeType.Unmanaged if the byte array doesn't match any StunAttributeType StunValue's
        /// </returns>
        public static StunAttributeType BytesToAttributeType(byte[] bytes)
        {
            UInt16 type = StunUtilities.ReverseBytes(BitConverter.ToUInt16(bytes, 0));

            foreach (FieldInfo field in typeof(StunAttributeType).GetFields())
            {
                Object[] fieldAttributes = field.GetCustomAttributes(typeof(StunValueAttribute), false);

                if (fieldAttributes.Length == 1)
                {
                    StunValueAttribute stunValueAttribute = fieldAttributes.GetValue(0) as StunValueAttribute;

                    if (stunValueAttribute != null &&
                        stunValueAttribute.Value == type)
                    {
                        return((StunAttributeType)Enum.Parse(typeof(StunAttributeType), field.Name));
                    }
                }
            }
            return(StunAttributeType.Unmanaged);
        }
コード例 #4
0
        /// <summary>
        /// Sample usage of this StunClient
        /// </summary>
        /// <param name="args">Unused</param>
        private static void Main(string[] args)
        {
            KeyValuePair <IPEndPoint, IPEndPoint> stunKeyValue = StunUtilities.GetMappedAddressFrom(null,
                                                                                                    new IPEndPoint(IPAddress.Parse("66.228.45.110"), StunClient.DEFAULT_STUN_PORT),
                                                                                                    ProtocolType.Udp);

            StunMessage msg = new StunMessage(StunMethodType.Binding, StunMethodClass.Request, StunUtilities.NewTransactionId);

            msg.Stun.Realm    = new UTF8Attribute(StunAttributeType.Realm, "Hello World !");
            msg.Stun.Username = new UTF8Attribute(StunAttributeType.Username, "Bob");

            byte[]      octets  = msg;
            StunMessage msgCopy = octets;

            // Reuse of an existing local IPEndPoint makes the three requests returning
            // the same MappedAddress IPEndPoint if this client is behind a Cone NAT
            StunClient cli1 = new StunClient(stunKeyValue.Key,
                                             new IPEndPoint(IPAddress.Parse("66.228.45.110"), StunClient.DEFAULT_STUNS_PORT),
                                             ProtocolType.Tcp, null,
                                             (sender, certificate, chain, sslPolicyErrors) => true);

            // Sample TLS over TCP working with ejabberd but may not work with the sample server IP given here
            cli1.Connect();
            StunMessage resp1 = cli1.SendMessage(msgCopy);

            cli1.Disconnect();

            msgCopy.ClearAttributes();

            StunClient cli2 = new StunClient(stunKeyValue.Key,
                                             new IPEndPoint(IPAddress.Parse("132.177.123.13"), StunClient.DEFAULT_STUN_PORT),
                                             ProtocolType.Udp, null, null);

            cli2.Connect();
            StunMessage resp2 = cli2.SendMessage(msgCopy);

            cli2.Disconnect();
        }
コード例 #5
0
        /// <summary>
        /// TODO: Documentation RefreshAllocation
        /// </summary>
        /// <param name="allocation"></param>
        /// <param name="lifeTime"></param>
        public void RefreshAllocation(TurnAllocation allocation, UInt32 lifeTime)
        {
            StunMessage msg = new StunMessage(StunMethodType.Refresh, StunMethodClass.Request, StunUtilities.NewTransactionId);

            msg.Stun.Username = new UTF8Attribute(StunAttributeType.Username, allocation.Username);
            msg.Stun.Realm    = new UTF8Attribute(StunAttributeType.Realm, allocation.Realm);
            msg.Stun.Nonce    = new UTF8Attribute(StunAttributeType.Nonce, allocation.Nonce);
            msg.Turn.LifeTime = new StunAttribute(StunAttributeType.LifeTime, BitConverter.GetBytes(StunUtilities.ReverseBytes(lifeTime)));

            msg.AddMessageIntegrity(allocation.Password, true);

            this.StunClient.BeginSendMessage(msg, null);
        }
コード例 #6
0
        /// <summary>
        /// TODO: Documentation StunClient_OnReceivedSuccessResponse
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="receivedMsg"></param>
        /// <param name="sentMsg"></param>
        /// <param name="transactionObject"></param>
        private void StunClient_OnReceivedSuccessResponse(object sender, StunMessage receivedMsg, StunMessage sentMsg, object transactionObject)
        {
            switch (receivedMsg.MethodType)
            {
            case StunMethodType.Allocate:
                TurnAllocation allocation = new TurnAllocation()
                {
                    Username             = sentMsg.Stun.Username.ValueString,
                    Password             = transactionObject as String,
                    Realm                = sentMsg.Stun.Realm.ValueString,
                    Nonce                = sentMsg.Stun.Nonce.ValueString,
                    RelayedMappedAddress = receivedMsg.Turn.XorRelayedAddress,
                    MappedAddress        = receivedMsg.Stun.XorMappedAddress,
                    StartTime            = DateTime.Now,
                    LifeTime             = StunUtilities.ReverseBytes(BitConverter.ToUInt32(receivedMsg.Turn.LifeTime.Value, 0))
                };

                if (this.Allocations.ContainsKey(receivedMsg.Turn.XorRelayedAddress))
                {
                    this.Allocations[receivedMsg.Turn.XorRelayedAddress] = allocation;
                }
                else
                {
                    this.Allocations.Add(receivedMsg.Turn.XorRelayedAddress, allocation);

                    if (this.OnAllocateSucceed != null)
                    {
                        this.OnAllocateSucceed(this, allocation, sentMsg, receivedMsg);
                    }
                }
                break;

            case StunMethodType.CreatePermission:
                TurnPermission permission = new TurnPermission()
                {
                    PeerAddress = sentMsg.Turn.XorPeerAddress,
                    StartTime   = DateTime.Now,
                    LifeTime    = 300
                };
                TurnAllocation permAllocation = transactionObject as TurnAllocation;

                if (permAllocation.Permissions.ContainsKey(sentMsg.Turn.XorPeerAddress))
                {
                    permAllocation.Permissions[sentMsg.Turn.XorPeerAddress] = permission;
                }
                else
                {
                    permAllocation.Permissions.Add(sentMsg.Turn.XorPeerAddress, permission);

                    if (this.OnCreatePermissionSucceed != null)
                    {
                        this.OnCreatePermissionSucceed(this, permAllocation, permission, sentMsg, receivedMsg);
                    }
                }

                break;

            case StunMethodType.ChannelBind:
                TurnChannel channel = new TurnChannel()
                {
                    Channel     = sentMsg.Turn.ChannelNumber,
                    PeerAddress = sentMsg.Turn.XorPeerAddress,
                    StartTime   = DateTime.Now,
                    LifeTime    = 600
                };
                TurnAllocation channelAllocation = transactionObject as TurnAllocation;

                if (channelAllocation.Channels.ContainsKey(sentMsg.Turn.ChannelNumber))
                {
                    channelAllocation.Channels[sentMsg.Turn.ChannelNumber] = channel;
                }
                else
                {
                    channelAllocation.Channels.Add(sentMsg.Turn.ChannelNumber, channel);

                    if (this.OnChannelBindSucceed != null)
                    {
                        this.OnChannelBindSucceed(this, transactionObject as TurnAllocation, channel, sentMsg, receivedMsg);
                    }
                }
                break;

            case StunMethodType.ConnectionBind:
                if (this.OnConnectionBindSucceed != null)
                {
                    this.OnConnectionBindSucceed(this, transactionObject as Socket, receivedMsg);
                }
                break;
            }
        }