Attribute.cs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. using STUN.Enums;
  2. using STUN.Message.Attributes;
  3. using STUN.Utils;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. namespace STUN.Message
  8. {
  9. /// <summary>
  10. /// https://tools.ietf.org/html/rfc5389#section-15
  11. /// </summary>
  12. public class Attribute
  13. {
  14. /*
  15. Length 是大端
  16. 必须4字节对齐
  17. 对齐的字节可以是任意值
  18. 0 1 2 3
  19. 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  20. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  21. | Type | Length |
  22. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  23. | Value (variable) ....
  24. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  25. */
  26. public AttributeType Type { get; set; } = AttributeType.Useless;
  27. public ushort Length { get; set; }
  28. public int RealLength => Type == AttributeType.Useless ? 0 : 4 + Length + (4 - Length % 4) % 4;
  29. public IAttribute? Value { get; set; }
  30. private readonly byte[] _magicCookie;
  31. private readonly byte[] _transactionId;
  32. public Attribute()
  33. {
  34. _magicCookie = new byte[4];
  35. _transactionId = new byte[12];
  36. }
  37. public Attribute(byte[] magicCookie, byte[] transactionId)
  38. {
  39. if (magicCookie.Length != 4 || transactionId.Length != 12)
  40. {
  41. throw new ArgumentException(@"Wrong Transaction ID length");
  42. }
  43. _magicCookie = magicCookie;
  44. _transactionId = transactionId;
  45. }
  46. public IEnumerable<byte> ToBytes()
  47. {
  48. var res = new List<byte>();
  49. res.AddRange(Convert.ToUInt16(Type).ToBe());
  50. res.AddRange(Length.ToBe());
  51. if (Value != null)
  52. {
  53. res.AddRange(Value.Bytes);
  54. }
  55. var n = (4 - res.Count % 4) % 4; // 填充的字节数
  56. res.AddRange(BitUtils.GetRandomBytes(n));
  57. return res;
  58. }
  59. /// <returns>
  60. /// Parse 成功字节,0 则表示 Parse 失败
  61. /// </returns>
  62. public int TryParse(byte[] bytes)
  63. {
  64. if (bytes.Length < 4)
  65. {
  66. return 0;
  67. }
  68. Type = (AttributeType)BitUtils.FromBe(bytes[0], bytes[1]);
  69. Length = BitUtils.FromBe(bytes[2], bytes[3]);
  70. if (bytes.Length < 4 + Length)
  71. {
  72. return 0;
  73. }
  74. var value = bytes.Skip(4).Take(Length).ToArray();
  75. IAttribute t = Type switch
  76. {
  77. AttributeType.MappedAddress => new MappedAddressAttribute(),
  78. AttributeType.XorMappedAddress => new XorMappedAddressAttribute(_magicCookie, _transactionId),
  79. AttributeType.ResponseAddress => new ResponseAddressAttribute(),
  80. AttributeType.ChangeRequest => new ChangeRequestAttribute(),
  81. AttributeType.SourceAddress => new SourceAddressAttribute(),
  82. AttributeType.ChangedAddress => new ChangedAddressAttribute(),
  83. AttributeType.OtherAddress => new OtherAddressAttribute(),
  84. AttributeType.ReflectedFrom => new ReflectedFromAttribute(),
  85. AttributeType.ErrorCode => new ErrorCodeAttribute(),
  86. _ => new UselessAttribute()
  87. };
  88. Value = t.TryParse(value) ? t : null;
  89. return 4 + Length + (4 - Length % 4) % 4; // 对齐
  90. }
  91. }
  92. }