Go to the documentation of this file.
43 #define UP_TYPE_PROXY "HTTP Proxy"
53 (*hpo)->http_version =
"1.0";
66 const int timeout_sec,
69 volatile int *signal_received)
95 tv.tv_sec = timeout_sec;
98 status = select(sd + 1, &reads, NULL, NULL, &tv);
101 if (*signal_received)
142 msg(
M_INFO,
"PROXY: read '%c' (%d)", c, (
int)c);
161 if (!isprint(c) && !isspace(c))
173 if (lastc ==
'\r' && c ==
'\n')
197 const ssize_t size = send(sd, buf, strlen(buf),
MSG_NOSIGNAL);
198 if (size != (ssize_t) strlen(buf))
306 volatile int *signal_received)
311 if (!
recv_line(sd, buf,
sizeof(buf), timeout,
true, NULL, signal_received))
329 volatile int *signal_received)
335 if (!
recv_line(sd, buf,
sizeof(buf), timeout,
true, NULL, signal_received))
346 if (ret ==
HTTP_AUTH_NONE && !strncmp(buf,
"Proxy-Authenticate: ", 20))
348 if (!strncmp(buf+20,
"Basic ", 6))
354 #if PROXY_DIGEST_AUTH
355 else if (!strncmp(buf+20,
"Digest ", 7))
363 else if (!strncmp(buf+20,
"NTLM", 4))
394 bool starts_with_quote =
false;
397 for (c = max_key_len-1; (*str && (*str !=
'=') && c--); )
413 starts_with_quote =
true;
416 for (c = max_value_len-1; *str && c--; str++)
432 if (!starts_with_quote)
448 if (!escape && starts_with_quote)
471 const char *content = pa;
493 while (*content && isspace(*content))
507 msg(
M_FATAL,
"HTTP_PROXY: server not specified");
530 msg(
M_WARN,
"NTLM v1 authentication has been removed in OpenVPN 2.7. Will try to use NTLM v2 authentication.");
540 msg(
M_FATAL,
"ERROR: unknown HTTP authentication method: '%s'",
579 bool host_header_sent =
false;
590 snprintf(buf,
sizeof(buf),
"%s: %s",
595 host_header_sent =
true;
600 snprintf(buf,
sizeof(buf),
"%s",
604 host_header_sent =
true;
608 msg(
D_PROXY,
"Send to HTTP proxy: '%s'", buf);
615 if (!host_header_sent)
617 snprintf(buf,
sizeof(buf),
"Host: %s", host);
618 msg(
D_PROXY,
"Send to HTTP proxy: '%s'", buf);
628 snprintf(buf,
sizeof(buf),
"User-Agent: %s",
630 msg(
D_PROXY,
"Send to HTTP proxy: '%s'", buf);
655 bool processed =
false;
680 snprintf(buf,
sizeof(buf),
"CONNECT %s:%s HTTP/%s",
685 msg(
D_PROXY,
"Send to HTTP proxy: '%s'", buf);
705 snprintf(buf,
sizeof(buf),
"Proxy-Authorization: Basic %s",
707 msg(
D_PROXY,
"Attempting Basic Proxy-Authorization");
718 snprintf(buf,
sizeof(buf),
"Proxy-Connection: Keep-Alive");
724 snprintf(buf,
sizeof(buf),
"Proxy-Authorization: NTLM %s",
726 msg(
D_PROXY,
"Attempting NTLM Proxy-Authorization phase 1");
754 msg(
D_PROXY,
"HTTP proxy returned: '%s'", buf);
757 nparms = sscanf(buf,
"%*s %d", &
status);
762 while (nparms >= 1 &&
status == 407)
764 msg(
D_PROXY,
"Proxy requires authentication");
782 msg(
D_PROXY,
"HTTP proxy returned: '%s'", buf);
786 snprintf(get,
sizeof(get),
"%%*s NTLM %%%zus",
sizeof(buf2) - 1);
787 nparms = sscanf(buf, get, buf2);
798 msg(
D_PROXY,
"Received NTLM Proxy-Authorization phase 2 response");
801 while (
recv_line(sd, NULL, 0, 2,
true, NULL, signal_received))
808 snprintf(buf,
sizeof(buf),
"CONNECT %s:%s HTTP/%s",
813 msg(
D_PROXY,
"Send to HTTP proxy: '%s'", buf);
822 snprintf(buf,
sizeof(buf),
"Proxy-Connection: Keep-Alive");
834 msg(
D_PROXY,
"Attempting NTLM Proxy-Authorization phase 3");
839 msg(
D_PROXY,
"NTLM Proxy-Authorization phase 3 failed: received corrupted data from proxy server");
842 snprintf(buf,
sizeof(buf),
"Proxy-Authorization: NTLM %s", np3);
845 msg(
D_PROXY,
"Send to HTTP proxy: '%s'", buf);
866 msg(
D_PROXY,
"HTTP proxy returned: '%s'", buf);
869 nparms = sscanf(buf,
"%*s %d", &
status);
873 #if PROXY_DIGEST_AUTH
882 const char *http_method =
"CONNECT";
883 const char *nonce_count =
"00000001";
884 const char *qop =
"auth";
887 char *opaque_kv =
"";
889 uint8_t cnonce_raw[8];
894 const char *realm =
get_pa_var(
"realm", pa, &gc);
895 const char *nonce =
get_pa_var(
"nonce", pa, &gc);
896 const char *algor =
get_pa_var(
"algorithm", pa, &gc);
897 const char *opaque =
get_pa_var(
"opaque", pa, &gc);
899 if (!realm || !nonce)
902 "from server: realm= or nonce= missing" );
912 snprintf(uri,
sizeof(uri),
"%s:%s",
918 const int len = strlen(opaque)+16;
920 snprintf(opaque_kv, len,
", opaque=\"%s\"", opaque);
941 snprintf(buf,
sizeof(buf),
"%s %s HTTP/%s",
946 msg(
D_PROXY,
"Send to HTTP proxy: '%s'", buf);
961 int sret = snprintf(buf,
sizeof(buf),
"Proxy-Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", qop=%s, nc=%s, cnonce=\"%s\", response=\"%s\"%s",
972 if (sret >=
sizeof(buf))
977 msg(
D_PROXY,
"Send to HTTP proxy: '%s'", buf);
996 msg(
D_PROXY,
"HTTP proxy returned: '%s'", buf);
999 nparms = sscanf(buf,
"%*s %d", &
status);
1004 msg(
D_PROXY,
"HTTP proxy: digest method not supported");
1021 msg(
D_PROXY,
"HTTP proxy authenticate '%s'", pa);
1025 msg(
D_PROXY,
"HTTP proxy: support for basic auth and other cleartext proxy auth methods is disabled");
1036 msg(
D_PROXY,
"HTTP proxy: do not recognize the authentication method required by proxy");
1045 msg(
D_PROXY,
"HTTP proxy: no support for proxy authentication method");
1052 if (nparms < 1 ||
status != 200)
1074 while (
recv_line(sd, NULL, 0, 2,
false, lookahead, signal_received))
1082 if (lookahead &&
BLEN(lookahead))
volatile int signal_received
void DigestCalcResponse(IN HASHHEX HA1, IN char *pszNonce, IN char *pszNonceCount, IN char *pszCNonce, IN char *pszQop, IN char *pszMethod, IN char *pszDigestUri, IN HASHHEX HEntity, OUT HASHHEX Response)
uint8_t * make_base64_string2(const uint8_t *str, int src_len, struct gc_arena *gc)
static struct user_pass static_proxy_user_pass
#define GET_USER_PASS_PREVIOUS_CREDS_FAILED
static struct gc_arena gc_new(void)
static bool send_line_crlf(socket_descriptor_t sd, const char *src)
static int get_proxy_authenticate(socket_descriptor_t sd, int timeout, char **data, volatile int *signal_received)
const char * http_version
#define buf_init(buf, offset)
const char * auth_file_up
char username[USER_PASS_LEN]
const char * auth_method_string
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
static void get_user_pass_http(struct http_proxy_info *p, const bool force)
int openvpn_base64_encode(const void *data, int size, char **str)
struct http_proxy_options options
void DigestCalcHA1(IN char *pszAlg, IN char *pszUserName, IN char *pszRealm, IN char *pszPassword, IN char *pszNonce, IN char *pszCNonce, OUT HASHHEX SessionKey)
#define GET_USER_PASS_MANAGEMENT
Container for unidirectional cipher and HMAC key material.
bool establish_http_proxy_passthru(struct http_proxy_info *p, socket_descriptor_t sd, const char *host, const char *port, struct event_timeout *server_poll_timeout, struct buffer *lookahead, struct signal_info *sig_info)
int get_server_poll_remaining_time(struct event_timeout *server_poll_timeout)
char * string_alloc(const char *str, struct gc_arena *gc)
static void store_proxy_authenticate(struct http_proxy_info *p, char *data)
#define MAX_CUSTOM_HTTP_HEADER
void purge_user_pass(struct user_pass *up, const bool force)
static bool send_crlf(socket_descriptor_t sd)
static bool buf_write_u8(struct buffer *dest, uint8_t data)
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc)
static void openvpn_fd_set(socket_descriptor_t fd, fd_set *setp)
static bool get_user_pass(struct user_pass *up, const char *auth_file, const char *prefix, const unsigned int flags)
Retrieves the user credentials from various sources depending on the flags.
static bool send_line(socket_descriptor_t sd, const char *buf)
Wrapper structure for dynamically allocated memory.
int rand_bytes(uint8_t *output, int len)
Wrapper for secure random number generator.
static bool buf_write(struct buffer *dest, const void *src, size_t size)
struct http_proxy_options * init_http_proxy_options_once(struct http_proxy_options **hpo, struct gc_arena *gc)
char * proxy_authenticate
Garbage collection arena used to keep track of dynamically allocated memory.
static bool recv_line(socket_descriptor_t sd, char *buf, int len, const int timeout_sec, const bool verbose, struct buffer *lookahead, volatile int *signal_received)
void free_buf(struct buffer *buf)
SOCKET socket_descriptor_t
static char * get_pa_var(const char *key, const char *pa, struct gc_arena *gc)
static void clear_user_pass_http(void)
static const char * username_password_as_base64(const struct http_proxy_info *p, struct gc_arena *gc)
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
const char * ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_arena *gc)
static SERVICE_STATUS status
static void gc_free(struct gc_arena *a)
static bool add_proxy_headers(struct http_proxy_info *p, socket_descriptor_t sd, const char *host, const char *port)
#define ALLOC_OBJ_CLEAR(dptr, type)
static bool get_key_value(const char *str, char *key, char *value, int max_key_len, int max_value_len, const char **endptr)
static char * format_hex(const uint8_t *data, int size, int maxoutput, struct gc_arena *gc)
char password[USER_PASS_LEN]
static void get_signal(volatile int *sig)
Copy the global signal_received (if non-zero) to the passed-in argument sig.
#define GET_USER_PASS_INLINE_CREDS
const char * ntlm_phase_1(const struct http_proxy_info *p, struct gc_arena *gc)
uint8_t * make_base64_string(const uint8_t *str, struct gc_arena *gc)
void register_signal(struct signal_info *si, int signum, const char *signal_text)
Register a soft signal in the signal_info struct si respecting priority.
struct buffer alloc_buf(size_t size)
struct http_proxy_info * http_proxy_new(const struct http_proxy_options *o)
struct http_custom_header custom_headers[MAX_CUSTOM_HTTP_HEADER]
static bool buf_defined(const struct buffer *buf)
bool buf_printf(struct buffer *buf, const char *format,...)
void http_proxy_close(struct http_proxy_info *hp)
uint8_t * data
Pointer to the allocated memory.