stun.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
  4. */
  5. #include <sys/types.h>
  6. #include <arpa/inet.h>
  7. #include <string.h>
  8. #include <stdio.h>
  9. #include "stun.h"
  10. static uint8_t tx_buf[256];
  11. bool stun_msg_is_valid(const void *data, size_t len)
  12. {
  13. const struct stun_msg_hdr *hdr = data;
  14. if (len <= sizeof(*hdr))
  15. return false;
  16. return hdr->magic == htonl(STUN_MAGIC);
  17. }
  18. static void *stun_msg_init(uint16_t type)
  19. {
  20. struct stun_msg_hdr *hdr = (struct stun_msg_hdr *)tx_buf;
  21. memset(hdr, 0, sizeof(*hdr));
  22. hdr->msg_type = htons(type);
  23. hdr->magic = htonl(STUN_MAGIC);
  24. return hdr;
  25. }
  26. static void *stun_msg_add_tlv(uint16_t type, uint16_t len)
  27. {
  28. struct stun_msg_hdr *hdr = (struct stun_msg_hdr *)tx_buf;
  29. uint16_t data_len = ntohs(hdr->msg_len);
  30. struct stun_msg_tlv *tlv;
  31. void *data = hdr + 1;
  32. data += data_len;
  33. tlv = data;
  34. tlv->type = htons(type);
  35. tlv->len = htons(len);
  36. if (len & 3)
  37. len = (len + 3) & ~3;
  38. data_len += sizeof(*tlv) + len;
  39. hdr->msg_len = htons(data_len);
  40. return tlv + 1;
  41. }
  42. static void
  43. stun_msg_parse_attr(const struct stun_tlv_policy *policy,
  44. const struct stun_msg_tlv **tb, int len,
  45. const struct stun_msg_tlv *tlv)
  46. {
  47. uint16_t type;
  48. int i;
  49. type = ntohs(tlv->type);
  50. for (i = 0; i < len; i++) {
  51. if (policy[i].type != type)
  52. continue;
  53. if (ntohs(tlv->len) < policy[i].min_len)
  54. return;
  55. tb[i] = tlv;
  56. return;
  57. }
  58. }
  59. static void
  60. stun_msg_parse(const struct stun_tlv_policy *policy,
  61. const struct stun_msg_tlv **tb, int len,
  62. const void *data, size_t data_len)
  63. {
  64. const struct stun_msg_hdr *hdr = data;
  65. const struct stun_msg_tlv *tlv;
  66. const void *end = data + data_len;
  67. uint16_t cur_len;
  68. data += sizeof(*hdr);
  69. while (1) {
  70. tlv = data;
  71. data = tlv + 1;
  72. if (data > end)
  73. break;
  74. cur_len = ntohs(tlv->len);
  75. if (data + cur_len > end)
  76. break;
  77. stun_msg_parse_attr(policy, tb, len, tlv);
  78. data += (cur_len + 3) & ~3;
  79. }
  80. }
  81. const void *stun_msg_request_prepare(struct stun_request *req, size_t *len,
  82. uint16_t response_port)
  83. {
  84. struct stun_msg_hdr *hdr;
  85. FILE *f;
  86. hdr = stun_msg_init(STUN_MSGTYPE_BINDING_REQUEST);
  87. if (response_port) {
  88. uint16_t *tlv_port = stun_msg_add_tlv(STUN_TLV_RESPONSE_PORT, 2);
  89. *tlv_port = htons(response_port);
  90. }
  91. f = fopen("/dev/urandom", "r");
  92. if (!f)
  93. return NULL;
  94. if (fread(hdr->transaction, 12, 1, f) != 1)
  95. return NULL;
  96. fclose(f);
  97. memcpy(req->transaction, hdr->transaction, sizeof(req->transaction));
  98. req->pending = true;
  99. req->port = 0;
  100. *len = htons(hdr->msg_len) + sizeof(*hdr);
  101. return hdr;
  102. }
  103. bool stun_msg_request_complete(struct stun_request *req, const void *data,
  104. size_t len)
  105. {
  106. enum {
  107. PARSE_ATTR_MAPPED,
  108. PARSE_ATTR_XOR_MAPPED,
  109. __PARSE_ATTR_MAX
  110. };
  111. const struct stun_msg_tlv *tb[__PARSE_ATTR_MAX];
  112. static const struct stun_tlv_policy policy[__PARSE_ATTR_MAX] = {
  113. [PARSE_ATTR_MAPPED] = { STUN_TLV_MAPPED_ADDRESS, 8 },
  114. [PARSE_ATTR_XOR_MAPPED] = { STUN_TLV_XOR_MAPPED_ADDRESS, 8 }
  115. };
  116. const struct stun_msg_hdr *hdr = data;
  117. const void *tlv_data;
  118. uint16_t port;
  119. if (!req->pending)
  120. return false;
  121. if (!stun_msg_is_valid(data, len))
  122. return false;
  123. if (hdr->msg_type != htons(STUN_MSGTYPE_BINDING_RESPONSE))
  124. return false;
  125. if (memcmp(hdr->transaction, req->transaction, sizeof(hdr->transaction)) != 0)
  126. return false;
  127. stun_msg_parse(policy, tb, __PARSE_ATTR_MAX, data, len);
  128. if (tb[PARSE_ATTR_XOR_MAPPED]) {
  129. tlv_data = tb[PARSE_ATTR_XOR_MAPPED] + 1;
  130. tlv_data += 2;
  131. port = ntohs(*(const uint16_t *)tlv_data);
  132. port ^= STUN_MAGIC >> 16;
  133. } else if (tb[PARSE_ATTR_MAPPED]) {
  134. tlv_data = tb[PARSE_ATTR_MAPPED] + 1;
  135. tlv_data += 2;
  136. port = ntohs(*(const uint16_t *)tlv_data);
  137. } else
  138. return false;
  139. req->port = port;
  140. return true;
  141. }