1 // 2 // socks4.hpp 3 // ~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot 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 11 #ifndef SOCKS4_HPP 12 #define SOCKS4_HPP 13 14 #include <string> 15 #include <boost/asio.hpp> 16 #include <boost/array.hpp> 17 18 namespace socks4 { 19 20 const unsigned char version = 0x04; 21 22 class request 23 { 24 public: 25 enum command_type 26 { 27 connect = 0x01, 28 bind = 0x02 29 }; 30 request(command_type cmd,const boost::asio::ip::tcp::endpoint & endpoint,const std::string & user_id)31 request(command_type cmd, const boost::asio::ip::tcp::endpoint& endpoint, 32 const std::string& user_id) 33 : version_(version), 34 command_(cmd), 35 user_id_(user_id), 36 null_byte_(0) 37 { 38 // Only IPv4 is supported by the SOCKS 4 protocol. 39 if (endpoint.protocol() != boost::asio::ip::tcp::v4()) 40 { 41 throw boost::system::system_error( 42 boost::asio::error::address_family_not_supported); 43 } 44 45 // Convert port number to network byte order. 46 unsigned short port = endpoint.port(); 47 port_high_byte_ = (port >> 8) & 0xff; 48 port_low_byte_ = port & 0xff; 49 50 // Save IP address in network byte order. 51 address_ = endpoint.address().to_v4().to_bytes(); 52 } 53 buffers() const54 boost::array<boost::asio::const_buffer, 7> buffers() const 55 { 56 boost::array<boost::asio::const_buffer, 7> bufs = 57 { 58 { 59 boost::asio::buffer(&version_, 1), 60 boost::asio::buffer(&command_, 1), 61 boost::asio::buffer(&port_high_byte_, 1), 62 boost::asio::buffer(&port_low_byte_, 1), 63 boost::asio::buffer(address_), 64 boost::asio::buffer(user_id_), 65 boost::asio::buffer(&null_byte_, 1) 66 } 67 }; 68 return bufs; 69 } 70 71 private: 72 unsigned char version_; 73 unsigned char command_; 74 unsigned char port_high_byte_; 75 unsigned char port_low_byte_; 76 boost::asio::ip::address_v4::bytes_type address_; 77 std::string user_id_; 78 unsigned char null_byte_; 79 }; 80 81 class reply 82 { 83 public: 84 enum status_type 85 { 86 request_granted = 0x5a, 87 request_failed = 0x5b, 88 request_failed_no_identd = 0x5c, 89 request_failed_bad_user_id = 0x5d 90 }; 91 reply()92 reply() 93 : null_byte_(0), 94 status_() 95 { 96 } 97 buffers()98 boost::array<boost::asio::mutable_buffer, 5> buffers() 99 { 100 boost::array<boost::asio::mutable_buffer, 5> bufs = 101 { 102 { 103 boost::asio::buffer(&null_byte_, 1), 104 boost::asio::buffer(&status_, 1), 105 boost::asio::buffer(&port_high_byte_, 1), 106 boost::asio::buffer(&port_low_byte_, 1), 107 boost::asio::buffer(address_) 108 } 109 }; 110 return bufs; 111 } 112 success() const113 bool success() const 114 { 115 return null_byte_ == 0 && status_ == request_granted; 116 } 117 status() const118 unsigned char status() const 119 { 120 return status_; 121 } 122 endpoint() const123 boost::asio::ip::tcp::endpoint endpoint() const 124 { 125 unsigned short port = port_high_byte_; 126 port = (port << 8) & 0xff00; 127 port = port | port_low_byte_; 128 129 boost::asio::ip::address_v4 address(address_); 130 131 return boost::asio::ip::tcp::endpoint(address, port); 132 } 133 134 private: 135 unsigned char null_byte_; 136 unsigned char status_; 137 unsigned char port_high_byte_; 138 unsigned char port_low_byte_; 139 boost::asio::ip::address_v4::bytes_type address_; 140 }; 141 142 } // namespace socks4 143 144 #endif // SOCKS4_HPP 145