14#ifndef OPENVPN_TRANSPORT_CLIENT_HTTPCLI_H
15#define OPENVPN_TRANSPORT_CLIENT_HTTPCLI_H
105 if (opt.
exists(
"http-proxy"))
108 if (obj->parse_options(opt))
134 else if (auth ==
"auto-nct")
139 else if (auth ==
"basic")
144 else if (auth ==
"digest")
149 else if (auth ==
"ntlm")
154 else if (auth ==
"none")
160 throw Exception(
"Unsupported HTTP proxy auth method: " + auth);
168 for (OptionList::IndexList::const_iterator i = hpo->begin(); i != hpo->end(); ++i)
170 const Option &o = opt[*i];
171 const std::string &type = o.
get(1, 64);
172 if (type ==
"VERSION")
177 else if (type ==
"AGENT")
182 else if (type ==
"EXT1" || type ==
"EXT2" || type ==
"CUSTOM-HEADER")
185 h->p1 = o.
get(2, 512);
250 if (!
config->http_proxy_options)
292 return impl->send_queue_empty();
309 return impl->send_queue_size();
317 impl->reset_align_adjust(align_adjust);
327 proto +=
"-via-HTTP";
374 Client(openvpn_io::io_context &io_context_arg,
400 return impl->send(buf);
409 return impl->send(buf);
416 std::ostringstream
os;
424 std::ostringstream
os;
445 catch (
const std::exception &e)
472 catch (
const std::exception &e)
487 for (
size_t i = 0; i < buf.
size(); ++i)
515 throw Exception(
"HTTP proxy header parse error");
542 impl->set_raw_mode(
false);
549 catch (
const std::exception &e)
573 impl->set_raw_mode_write(
false);
619 if (
config->http_proxy_options->auth_method ==
None)
620 throw Exception(
"HTTP proxy authentication is disabled");
626 if (
config->http_proxy_options->username.empty())
635 if (method ==
Any || method ==
Ntlm)
655 if (method ==
Any || method ==
Basic)
660 if (!
config->http_proxy_options->allow_cleartext_auth)
661 throw Exception(
"HTTP proxy basic authentication not allowed by user preference");
668 throw Exception(
"HTTP proxy-authenticate method not allowed / supported");
685 throw Exception(
"HTTP proxy unexpected EOF: reply incomplete");
687 throw Exception(
"HTTP proxy general error");
695 std::ostringstream
os;
697 os <<
"Proxy-Authorization: Basic "
713 const std::string http_method =
"CONNECT";
714 const std::string nonce_count =
"00000001";
715 const std::string qop =
"auth";
724 unsigned char cnonce_raw[8];
725 config->rng->rand_bytes(cnonce_raw,
sizeof(cnonce_raw));
726 const std::string cnonce =
render_hex(cnonce_raw,
sizeof(cnonce_raw));
735 config->http_proxy_options->username,
737 config->http_proxy_options->password,
754 std::ostringstream
os;
756 os <<
"Proxy-Authorization: Digest username=\"" <<
config->http_proxy_options->username <<
"\", realm=\"" << realm <<
"\", nonce=\"" << nonce <<
"\", uri=\"" << uri <<
"\", qop=" << qop <<
", nc=" << nonce_count <<
", cnonce=\"" << cnonce <<
"\", response=\"" << response <<
"\"";
758 os <<
", opaque=\"" + opaque +
"\"";
765 catch (
const std::exception &e)
793 std::ostringstream
os;
795 os <<
"Proxy-Connection: Keep-Alive\r\n";
796 os <<
"Proxy-Authorization: NTLM " << phase_1_reply <<
"\r\n";
808 const unsigned int content_length = parse_number_throw<unsigned int>(content_length_str,
"content-length");
820 throw Exception(
"NTLM phase-2 status is not ProxyAuthenticationRequired");
823 if (!phase_2_response.empty())
826 throw Exception(
"NTLM phase-2 response missing");
839 config->http_proxy_options->username,
840 config->http_proxy_options->password,
843 std::ostringstream
os;
845 os <<
"Proxy-Connection: Keep-Alive\r\n";
846 os <<
"Proxy-Authorization: NTLM " << phase_3_reply <<
"\r\n";
852 catch (
const std::exception &e)
854 std::string what{e.what()};
855 if (what.find(
"openssl_digest_error") != std::string::npos)
868 bool host_header_sent =
false;
873 for (Options::CustomHeaderList::const_iterator i = headers.begin(); i != headers.end(); ++i)
878 os << h.
p1 <<
": " << h.
p2 <<
"\r\n";
880 host_header_sent =
true;
884 os << h.
p1 <<
"\r\n";
885 const std::string h5 = h.
p1.substr(0, 5);
887 host_header_sent =
true;
894 const std::string &user_agent =
config->http_proxy_options->user_agent;
895 if (!user_agent.empty())
896 os <<
"User-Agent: " << user_agent <<
"\r\n";
900 if (!host_header_sent)
934 std::ostringstream
os;
935 os <<
"DNS resolve error on '" <<
proxy_host <<
"' for TCP (HTTP proxy): " << error.message();
970 if (
config->socket_protect)
981 socket.set_option(openvpn_io::ip::tcp::no_delay(
true));
985 self->start_impl_(error); });
999 config->free_list_max_size,
1002 impl->set_raw_mode(
true);
1013 std::ostringstream
os;
1032 std::ostringstream
os;
1033 const std::string &http_version =
config->http_proxy_options->http_version;
1035 if (!http_version.empty())
1045 const std::string
str =
os.str();
1056 return *
config->remote_list;
1060 return *
config->http_proxy_options->proxy_server;
#define OPENVPN_ASYNC_HANDLER
void async_resolve_cancel()
void async_resolve_lock()
typename RESOLVER_TYPE::results_type results_type
virtual void async_resolve_name(const std::string &host, const std::string &port)
std::string encode(const V &data) const
void add(const Buffer &buf)
size_t size() const
Returns the size of the buffer in T objects.
void advance(const size_t delta)
Advances the buffer by the specified delta.
bool empty() const
Returns true if the buffer is empty.
T pop_front()
Removes and returns the first element from the buffer.
RemoteList::Ptr remote_list
size_t free_list_max_size
SocketProtect * socket_protect
Options::Ptr http_proxy_options
TransportClient::Ptr new_transport_client_obj(openvpn_io::io_context &io_context, TransportClientParent *parent) override
DigestFactory::Ptr digest_factory
RCPtr< ClientConfig > Ptr
void gen_headers(std::ostringstream &os)
void tcp_error_handler(const char *error)
void proxy_read_handler(BufferAllocated &buf)
HTTP::ReplyParser::status http_reply_status
void proxy_error(const Error::Type fatal_err, const std::string &what)
openvpn_io::ip::tcp::socket socket
IP::Addr server_endpoint_addr() const override
Client(openvpn_io::io_context &io_context_arg, ClientConfig *config_arg, TransportClientParent *parent_arg)
void ntlm_auth_phase_1(HTTPProxy::ProxyAuthenticate &pa)
LinkImpl::protocol::endpoint server_endpoint
void proxy_connected(BufferAllocated &buf, const bool notify_parent)
void tcp_write_queue_needs_send()
std::unique_ptr< HTTP::HTMLSkip > html_skip
std::string get_ntlm_phase_2_response()
bool transport_has_send_queue() override
RemoteList & proxy_remote_list() const
bool ntlm_phase_2_response_pending
void transport_stop_requeueing() override
unsigned int n_transactions
void ntlm_auth_phase_3(const std::string &phase_2_response)
void proxy_half_connected()
bool tcp_read_handler(BufferAllocated &buf)
bool transport_send(BufferAllocated &buf) override
TCPTransport::TCPLink< openvpn_io::ip::tcp, Client *, false > LinkImpl
void server_endpoint_info(std::string &host, std::string &port, std::string &proto, std::string &ip_addr) const override
HTTP::ReplyParser http_parser
RemoteList & remote_list() const
ProxyResponseLimit proxy_response_limit
Protocol transport_protocol() const override
bool send(BufferAllocated &buf)
void drain_html(BufferAllocated &buf)
void start_impl_(const openvpn_io::error_code &error)
TransportClientParent * parent
void reset_align_adjust(const size_t align_adjust) override
void digest_auth(HTTPProxy::ProxyAuthenticate &pa)
HTTPProxy::ProxyAuthenticate::Ptr get_proxy_authenticate_header(const char *type)
bool transport_send_const(const Buffer &buf) override
void basic_auth(HTTPProxy::ProxyAuthenticate &pa)
bool transport_send_queue_empty() override
void transport_reparent(TransportClientParent *parent_arg) override
size_t drain_content_length
void ntlm_auth_phase_2_pre()
void create_http_connect_msg(BufferAllocated &buf)
void transport_start() override
void resolve_callback(const openvpn_io::error_code &error, results_type results) override
size_t transport_send_queue_size() override
bool send_const(const Buffer &cbuf)
bool allow_cleartext_auth
bool parse_options(const OptionList &opt)
static Ptr parse(const OptionList &opt)
void proxy_server_set_enable_cache(const bool enable_cache)
void proxy_server_precache(RemoteList::Ptr &r)
void set_proxy_server(const std::string &host, const std::string &port)
RemoteList::Ptr proxy_server
static std::string calcResponse(DigestFactory &digest_factory, const std::string &hA1, const std::string &nonce, const std::string &nonce_count, const std::string &cnonce, const std::string &qop, const std::string &method, const std::string &digestUri, const std::string &hEntity)
static std::string calcHA1(DigestFactory &digest_factory, const std::string &alg, const std::string &username, const std::string &realm, const std::string &password, const std::string &nonce, const std::string &cnonce)
static std::string phase_1()
static std::string phase_3(DigestFactory &digest_factory, const std::string &phase_2_response, const std::string &dom_username, const std::string &password, StrongRandomAPI &rng)
RCPtr< ProxyAuthenticate > Ptr
std::string to_string() const
status consume(Reply &req, const unsigned char input)
static Addr from_asio(const openvpn_io::ip::address &addr)
std::string to_string() const
const char * version_string() const
const IndexList * get_index_ptr(const std::string &name) const
const Option * get_ptr(const std::string &name) const
std::vector< unsigned int > IndexList
bool exists(const std::string &name) const
std::string get_optional(const size_t index, const size_t max_len) const
void touch(bool lightly=false) const
const std::string & get(const size_t index, const size_t max_len) const
void reset() noexcept
Points this RCPtr<T> to nullptr safely.
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
void set_endpoint_range(EPRANGE &endpoint_range)
bool endpoint_available(std::string *server_host, std::string *server_port, Protocol *transport_protocol) const
void get_endpoint(EP &endpoint) const
void next(Advance type=Advance::Addr)
bool get_enable_cache() const
void set_enable_cache(const bool enable_cache_arg)
LinkCommon< Protocol, ReadHandler, RAW_MODE_ONLY > Base
#define OPENVPN_THROW_EXCEPTION(stuff)
#define OPENVPN_LOG_NTNL(args)
#define OPENVPN_LOG(args)
@ ProxyAuthenticationRequired
bool parse(const OptionList &options, const std::string &opt_name, const unsigned int flags, std::vector< std::string > *user_pass)
interpret user-pass option
int strcasecmp(const char *s1, const char *s2)
std::string render_hex(const unsigned char *data, size_t size, const bool caps=false)
std::string buf_to_string(const Buffer &buf)
void buf_write_string(Buffer &buf, const std::string &str)
void lines_exceeded() override
void bytes_exceeded() override
virtual void transport_connecting()=0
virtual void transport_pre_resolve()=0
virtual void transport_error(const Error::Type fatal_err, const std::string &err_text)=0
virtual void proxy_error(const Error::Type fatal_err, const std::string &err_text)=0
virtual bool transport_is_openvpn_protocol()=0
virtual void transport_wait()=0
virtual void transport_recv(BufferAllocated &buf)=0
virtual void transport_wait_proxy()=0
virtual void transport_needs_send()=0
RCPtr< TransportClient > Ptr
os<< "Session Name: "<< tbc-> session_name<< '\n';os<< "Layer: "<< tbc-> layer str()<< '\n'