socks5_util.hpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. /*
  2. * Copyright (c) 2017-2023 zhllxt
  3. *
  4. * author : zhllxt
  5. * email : 37792738@qq.com
  6. *
  7. * Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. */
  10. #ifndef __ASIO2_SOCKS5_UTIL_HPP__
  11. #define __ASIO2_SOCKS5_UTIL_HPP__
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. #pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <string_view>
  16. #include <tuple>
  17. #include <asio2/component/socks/socks5_core.hpp>
  18. namespace asio2::socks5
  19. {
  20. namespace
  21. {
  22. /**
  23. * @return tuple: error, endpoint, domain, real_data.
  24. */
  25. std::tuple<int, asio::ip::udp::endpoint, std::string_view, std::string_view>
  26. parse_udp_packet(std::string_view data, bool is_ext_protocol)
  27. {
  28. // RSV FRAG
  29. if (data.size() < std::size_t(3))
  30. return { 1,{},{},{} };
  31. std::uint16_t data_size = asio2::detail::network_to_host(
  32. std::uint16_t(*(reinterpret_cast<const std::uint16_t*>(data.data()))));
  33. data.remove_prefix(3);
  34. // ATYP
  35. if (data.size() < std::size_t(1))
  36. return { 2,{},{},{} };
  37. std::uint8_t atyp = std::uint8_t(data[0]);
  38. data.remove_prefix(1);
  39. asio::ip::udp::endpoint endpoint{};
  40. std::string_view domain;
  41. if /**/ (atyp == std::uint8_t(0x01)) // IP V4 address: X'01'
  42. {
  43. if (data.size() < std::size_t(4 + 2))
  44. return { 3,{},{},{} };
  45. asio::ip::address_v4::bytes_type addr{};
  46. for (std::size_t i = 0; i < addr.size(); i++)
  47. {
  48. addr[i] = asio::ip::address_v4::bytes_type::value_type(data[i]);
  49. }
  50. endpoint.address(asio::ip::address_v4(addr));
  51. data.remove_prefix(4);
  52. auto* p = data.data();
  53. std::uint16_t uport = asio2::detail::read<std::uint16_t>(p);
  54. endpoint.port(uport);
  55. data.remove_prefix(2);
  56. if (is_ext_protocol && data.size() != data_size)
  57. return { 4,{},{},{} };
  58. }
  59. else if (atyp == std::uint8_t(0x04)) // IP V6 address: X'04'
  60. {
  61. if (data.size() < std::size_t(16 + 2))
  62. return { 5,{},{},{} };
  63. data.remove_prefix(16 + 2);
  64. asio::ip::address_v6::bytes_type addr{};
  65. for (std::size_t i = 0; i < addr.size(); i++)
  66. {
  67. addr[i] = asio::ip::address_v6::bytes_type::value_type(data[i]);
  68. }
  69. endpoint.address(asio::ip::address_v6(addr));
  70. data.remove_prefix(16);
  71. auto* p = data.data();
  72. std::uint16_t uport = asio2::detail::read<std::uint16_t>(p);
  73. endpoint.port(uport);
  74. data.remove_prefix(2);
  75. if (is_ext_protocol && data.size() != data_size)
  76. return { 6,{},{},{} };
  77. }
  78. else if (atyp == std::uint8_t(0x03)) // DOMAINNAME: X'03'
  79. {
  80. if (data.size() < std::size_t(1))
  81. return { 7,{},{},{} };
  82. std::uint8_t domain_len = std::uint8_t(data[0]);
  83. if (domain_len == 0)
  84. return { 8,{},{},{} };
  85. data.remove_prefix(1);
  86. if (data.size() < std::size_t(domain_len + 2))
  87. return { 9,{},{},{} };
  88. domain = data.substr(0, domain_len);
  89. data.remove_prefix(domain_len);
  90. auto* p = data.data();
  91. std::uint16_t uport = asio2::detail::read<std::uint16_t>(p);
  92. endpoint.port(uport);
  93. data.remove_prefix(2);
  94. if (is_ext_protocol && data.size() != data_size)
  95. return { 10,{},{},{} };
  96. }
  97. else
  98. {
  99. return { 11,{},{},{} };
  100. }
  101. return { 0, std::move(endpoint), domain, data };
  102. }
  103. }
  104. }
  105. namespace asio2::detail
  106. {
  107. namespace
  108. {
  109. using iterator = asio::buffers_iterator<asio::streambuf::const_buffers_type>;
  110. using diff_type = typename iterator::difference_type;
  111. std::pair<iterator, bool> socks5_udp_match_role(iterator begin, iterator end) noexcept
  112. {
  113. // +----+------+------+----------+----------+----------+
  114. // |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
  115. // +----+------+------+----------+----------+----------+
  116. // | 2 | 1 | 1 | Variable | 2 | Variable |
  117. // +----+------+------+----------+----------+----------+
  118. for (iterator p = begin; p < end;)
  119. {
  120. if (end - p < static_cast<diff_type>(5))
  121. break;
  122. std::uint16_t data_size = asio2::detail::network_to_host(
  123. std::uint16_t(*(reinterpret_cast<const std::uint16_t*>(p.operator->()))));
  124. std::uint8_t atyp = std::uint8_t(p[3]);
  125. diff_type need = 0;
  126. // ATYP
  127. if /**/ (atyp == std::uint8_t(0x01))
  128. need = static_cast<diff_type>(2 + 1 + 1 + 4 + 2 + data_size);
  129. else if (atyp == std::uint8_t(0x03))
  130. need = static_cast<diff_type>(2 + 1 + 1 + p[4] + 2 + data_size);
  131. else if (atyp == std::uint8_t(0x04))
  132. need = static_cast<diff_type>(2 + 1 + 1 + 16 + 2 + data_size);
  133. else
  134. return std::pair(begin, true);
  135. if (end - p < need)
  136. break;
  137. return std::pair(p + need, true);
  138. }
  139. return std::pair(begin, false);
  140. }
  141. }
  142. // on vs2017 the std::function<asio2::net_protocol()> will cause compile error.
  143. #if defined(_MSC_VER) && (_MSC_VER < 1929)
  144. struct socks5_server_match_role
  145. {
  146. template <typename Iterator>
  147. std::pair<Iterator, bool> operator()(Iterator begin, Iterator end) const
  148. {
  149. // +----+------+------+----------+----------+----------+
  150. // |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
  151. // +----+------+------+----------+----------+----------+
  152. // | 2 | 1 | 1 | Variable | 2 | Variable |
  153. // +----+------+------+----------+----------+----------+
  154. for (Iterator p = begin; p < end;)
  155. {
  156. if (this->get_front_client_type && (*(this->get_front_client_type))() == asio2::net_protocol::tcp)
  157. return std::pair(end, true);
  158. return socks5_udp_match_role(p, end);
  159. }
  160. return std::pair(begin, false);
  161. }
  162. template<class T>
  163. void init(std::shared_ptr<T>& session_ptr)
  164. {
  165. this->get_front_client_type = std::make_shared<std::function<asio2::net_protocol()>>(
  166. [p = session_ptr.get()]() mutable
  167. {
  168. return p->get_front_client_type();
  169. });
  170. }
  171. std::shared_ptr<std::function<asio2::net_protocol()>> get_front_client_type;
  172. };
  173. #else
  174. struct socks5_server_match_role
  175. {
  176. template <typename Iterator>
  177. std::pair<Iterator, bool> operator()(Iterator begin, Iterator end) const
  178. {
  179. // +----+------+------+----------+----------+----------+
  180. // |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
  181. // +----+------+------+----------+----------+----------+
  182. // | 2 | 1 | 1 | Variable | 2 | Variable |
  183. // +----+------+------+----------+----------+----------+
  184. for (Iterator p = begin; p < end;)
  185. {
  186. if (this->get_front_client_type() == asio2::net_protocol::tcp)
  187. return std::pair(end, true);
  188. return socks5_udp_match_role(p, end);
  189. }
  190. return std::pair(begin, false);
  191. }
  192. template<class T>
  193. void init(std::shared_ptr<T>& session_ptr)
  194. {
  195. this->get_front_client_type = [p = session_ptr.get()]() mutable
  196. {
  197. return p->get_front_client_type();
  198. };
  199. }
  200. std::function<asio2::net_protocol()> get_front_client_type;
  201. };
  202. #endif
  203. }
  204. #ifdef ASIO_STANDALONE
  205. namespace asio
  206. #else
  207. namespace boost::asio
  208. #endif
  209. {
  210. template <> struct is_match_condition<asio2::detail::socks5_server_match_role> : public std::true_type {};
  211. }
  212. #endif // !__ASIO2_SOCKS5_UTIL_HPP__