Add C++11 version of SOCKS4 example.
This commit is contained in:
parent
e7dbfcecb8
commit
d6209b6c73
@ -530,6 +530,8 @@ sub copy_examples
|
||||
"src/examples/cpp11/local",
|
||||
"src/examples/cpp11/multicast",
|
||||
"src/examples/cpp11/nonblocking",
|
||||
"src/examples/cpp11/operations",
|
||||
"src/examples/cpp11/socks4",
|
||||
"src/examples/cpp11/spawn",
|
||||
"src/examples/cpp11/ssl",
|
||||
"src/examples/cpp11/timeouts",
|
||||
|
@ -444,6 +444,15 @@ library that wants to perform the I/O operations itself.
|
||||
* [@../src/examples/cpp11/nonblocking/third_party_lib.cpp] ([@examples/diffs/nonblocking/third_party_lib.cpp.html diff to C++03])
|
||||
|
||||
|
||||
[heading SOCKS 4]
|
||||
|
||||
Example client program implementing the SOCKS 4 protocol for communication via
|
||||
a proxy.
|
||||
|
||||
* [@../src/examples/cpp11/socks4/sync_client.cpp] ([@examples/diffs/socks4/sync_client.cpp.html diff to C++03])
|
||||
* [@../src/examples/cpp11/socks4/socks4.hpp] ([@examples/diffs/socks4/socks4.hpp.html diff to C++03])
|
||||
|
||||
|
||||
[heading Spawn]
|
||||
|
||||
Example of using the asio::spawn() function, a wrapper around the
|
||||
|
@ -33,6 +33,7 @@ noinst_PROGRAMS = \
|
||||
multicast/receiver \
|
||||
multicast/sender \
|
||||
nonblocking/third_party_lib \
|
||||
socks4/sync_client \
|
||||
timeouts/async_tcp_client \
|
||||
timeouts/blocking_tcp_client \
|
||||
timeouts/blocking_token_tcp_client \
|
||||
@ -98,6 +99,7 @@ iostreams_http_client_SOURCES = iostreams/http_client.cpp
|
||||
multicast_receiver_SOURCES = multicast/receiver.cpp
|
||||
multicast_sender_SOURCES = multicast/sender.cpp
|
||||
nonblocking_third_party_lib_SOURCES = nonblocking/third_party_lib.cpp
|
||||
socks4_sync_client_SOURCES = socks4/sync_client.cpp
|
||||
timeouts_async_tcp_client_SOURCES = timeouts/async_tcp_client.cpp
|
||||
timeouts_blocking_tcp_client_SOURCES = timeouts/blocking_tcp_client.cpp
|
||||
timeouts_blocking_token_tcp_client_SOURCES = timeouts/blocking_token_tcp_client.cpp
|
||||
|
10
asio/src/examples/cpp11/socks4/.gitignore
vendored
Normal file
10
asio/src/examples/cpp11/socks4/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
.deps
|
||||
.dirstamp
|
||||
*.o
|
||||
*.obj
|
||||
*.exe
|
||||
sync_client
|
||||
*.ilk
|
||||
*.manifest
|
||||
*.pdb
|
||||
*.tds
|
143
asio/src/examples/cpp11/socks4/socks4.hpp
Normal file
143
asio/src/examples/cpp11/socks4/socks4.hpp
Normal file
@ -0,0 +1,143 @@
|
||||
//
|
||||
// socks4.hpp
|
||||
// ~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef SOCKS4_HPP
|
||||
#define SOCKS4_HPP
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <asio/buffer.hpp>
|
||||
#include <asio/ip/tcp.hpp>
|
||||
|
||||
namespace socks4 {
|
||||
|
||||
const unsigned char version = 0x04;
|
||||
|
||||
class request
|
||||
{
|
||||
public:
|
||||
enum command_type
|
||||
{
|
||||
connect = 0x01,
|
||||
bind = 0x02
|
||||
};
|
||||
|
||||
request(command_type cmd, const asio::ip::tcp::endpoint& endpoint,
|
||||
const std::string& user_id)
|
||||
: version_(version),
|
||||
command_(cmd),
|
||||
user_id_(user_id),
|
||||
null_byte_(0)
|
||||
{
|
||||
// Only IPv4 is supported by the SOCKS 4 protocol.
|
||||
if (endpoint.protocol() != asio::ip::tcp::v4())
|
||||
{
|
||||
throw asio::system_error(
|
||||
asio::error::address_family_not_supported);
|
||||
}
|
||||
|
||||
// Convert port number to network byte order.
|
||||
unsigned short port = endpoint.port();
|
||||
port_high_byte_ = (port >> 8) & 0xff;
|
||||
port_low_byte_ = port & 0xff;
|
||||
|
||||
// Save IP address in network byte order.
|
||||
address_ = endpoint.address().to_v4().to_bytes();
|
||||
}
|
||||
|
||||
std::array<asio::const_buffer, 7> buffers() const
|
||||
{
|
||||
return
|
||||
{
|
||||
{
|
||||
asio::buffer(&version_, 1),
|
||||
asio::buffer(&command_, 1),
|
||||
asio::buffer(&port_high_byte_, 1),
|
||||
asio::buffer(&port_low_byte_, 1),
|
||||
asio::buffer(address_),
|
||||
asio::buffer(user_id_),
|
||||
asio::buffer(&null_byte_, 1)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned char version_;
|
||||
unsigned char command_;
|
||||
unsigned char port_high_byte_;
|
||||
unsigned char port_low_byte_;
|
||||
asio::ip::address_v4::bytes_type address_;
|
||||
std::string user_id_;
|
||||
unsigned char null_byte_;
|
||||
};
|
||||
|
||||
class reply
|
||||
{
|
||||
public:
|
||||
enum status_type
|
||||
{
|
||||
request_granted = 0x5a,
|
||||
request_failed = 0x5b,
|
||||
request_failed_no_identd = 0x5c,
|
||||
request_failed_bad_user_id = 0x5d
|
||||
};
|
||||
|
||||
reply()
|
||||
: null_byte_(0),
|
||||
status_()
|
||||
{
|
||||
}
|
||||
|
||||
std::array<asio::mutable_buffer, 5> buffers()
|
||||
{
|
||||
return
|
||||
{
|
||||
{
|
||||
asio::buffer(&null_byte_, 1),
|
||||
asio::buffer(&status_, 1),
|
||||
asio::buffer(&port_high_byte_, 1),
|
||||
asio::buffer(&port_low_byte_, 1),
|
||||
asio::buffer(address_)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bool success() const
|
||||
{
|
||||
return null_byte_ == 0 && status_ == request_granted;
|
||||
}
|
||||
|
||||
unsigned char status() const
|
||||
{
|
||||
return status_;
|
||||
}
|
||||
|
||||
asio::ip::tcp::endpoint endpoint() const
|
||||
{
|
||||
unsigned short port = port_high_byte_;
|
||||
port = (port << 8) & 0xff00;
|
||||
port = port | port_low_byte_;
|
||||
|
||||
asio::ip::address_v4 address(address_);
|
||||
|
||||
return asio::ip::tcp::endpoint(address, port);
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned char null_byte_;
|
||||
unsigned char status_;
|
||||
unsigned char port_high_byte_;
|
||||
unsigned char port_low_byte_;
|
||||
asio::ip::address_v4::bytes_type address_;
|
||||
};
|
||||
|
||||
} // namespace socks4
|
||||
|
||||
#endif // SOCKS4_HPP
|
93
asio/src/examples/cpp11/socks4/sync_client.cpp
Normal file
93
asio/src/examples/cpp11/socks4/sync_client.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
//
|
||||
// sync_client.cpp
|
||||
// ~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <asio.hpp>
|
||||
#include "socks4.hpp"
|
||||
|
||||
using asio::ip::tcp;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
try
|
||||
{
|
||||
if (argc != 4)
|
||||
{
|
||||
std::cout << "Usage: sync_client <socks4server> <socks4port> <user>\n";
|
||||
std::cout << "Examples:\n";
|
||||
std::cout << " sync_client 127.0.0.1 1080 chris\n";
|
||||
std::cout << " sync_client localhost socks chris\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
asio::io_context io_context;
|
||||
|
||||
// Get a list of endpoints corresponding to the SOCKS 4 server name.
|
||||
tcp::resolver resolver(io_context);
|
||||
auto endpoints = resolver.resolve(argv[1], argv[2]);
|
||||
|
||||
// Try each endpoint until we successfully establish a connection to the
|
||||
// SOCKS 4 server.
|
||||
tcp::socket socket(io_context);
|
||||
asio::connect(socket, endpoints);
|
||||
|
||||
// Get an endpoint for the Boost website. This will be passed to the SOCKS
|
||||
// 4 server. Explicitly specify IPv4 since SOCKS 4 does not support IPv6.
|
||||
auto http_endpoint = *resolver.resolve(tcp::v4(), "www.boost.org", "http");
|
||||
|
||||
// Send the request to the SOCKS 4 server.
|
||||
socks4::request socks_request(
|
||||
socks4::request::connect, http_endpoint, argv[3]);
|
||||
asio::write(socket, socks_request.buffers());
|
||||
|
||||
// Receive a response from the SOCKS 4 server.
|
||||
socks4::reply socks_reply;
|
||||
asio::read(socket, socks_reply.buffers());
|
||||
|
||||
// Check whether we successfully negotiated with the SOCKS 4 server.
|
||||
if (!socks_reply.success())
|
||||
{
|
||||
std::cout << "Connection failed.\n";
|
||||
std::cout << "status = 0x" << std::hex << socks_reply.status();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Form the HTTP request. We specify the "Connection: close" header so that
|
||||
// the server will close the socket after transmitting the response. This
|
||||
// will allow us to treat all data up until the EOF as the response.
|
||||
std::string request =
|
||||
"GET / HTTP/1.0\r\n"
|
||||
"Host: www.boost.org\r\n"
|
||||
"Accept: */*\r\n"
|
||||
"Connection: close\r\n\r\n";
|
||||
|
||||
// Send the HTTP request.
|
||||
asio::write(socket, asio::buffer(request));
|
||||
|
||||
// Read until EOF, writing data to output as we go.
|
||||
std::array<char, 512> response;
|
||||
std::error_code error;
|
||||
while (std::size_t s = socket.read_some(
|
||||
asio::buffer(response), error))
|
||||
std::cout.write(response.data(), s);
|
||||
if (error != asio::error::eof)
|
||||
throw std::system_error(error);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cout << "Exception: " << e.what() << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user