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; } = new UselessAttribute();
  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. res.AddRange(Value.Bytes);
  52. var n = (4 - res.Count % 4) % 4; // 填充的字节数
  53. res.AddRange(BitUtils.GetRandomBytes(n));
  54. return res;
  55. }
  56. /// <returns>
  57. /// Parse 成功字节,0 则表示 Parse 失败
  58. /// </returns>
  59. public int TryParse(byte[] bytes)
  60. {
  61. if (bytes.Length < 4)
  62. {
  63. return 0;
  64. }
  65. Type = (AttributeType)BitUtils.FromBe(bytes[0], bytes[1]);
  66. Length = BitUtils.FromBe(bytes[2], bytes[3]);
  67. if (bytes.Length < 4 + Length)
  68. {
  69. return 0;
  70. }
  71. var value = bytes.Skip(4).Take(Length).ToArray();
  72. IAttribute t = Type switch
  73. {
  74. AttributeType.MappedAddress => new MappedAddressAttribute(),
  75. AttributeType.XorMappedAddress => new XorMappedAddressAttribute(_magicCookie, _transactionId),
  76. AttributeType.ResponseAddress => new ResponseAddressAttribute(),
  77. AttributeType.ChangeRequest => new ChangeRequestAttribute(),
  78. AttributeType.SourceAddress => new SourceAddressAttribute(),
  79. AttributeType.ChangedAddress => new ChangedAddressAttribute(),
  80. AttributeType.OtherAddress => new OtherAddressAttribute(),
  81. AttributeType.ReflectedFrom => new ReflectedFromAttribute(),
  82. AttributeType.ErrorCode => new ErrorCodeAttribute(),
  83. _ => new UselessAttribute()
  84. };
  85. if (t.TryParse(value))
  86. {
  87. Value = t;
  88. }
  89. return 4 + Length + (4 - Length % 4) % 4; // 对齐
  90. }
  91. }
  92. }