mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2025-07-07 00:04:57 +03:00
Move generic proxy stuff from Cedar to Mayaqua
This commit moves the generic (not related to our protocol) proxy stuff from Cedar to Mayaqua, in dedicated files. The functions are refactored so that they all have the same arguments and follow the same logic. Dedicated error codes are added, in order to indicate clearly why the function(s) failed.
This commit is contained in:
@ -116,8 +116,6 @@
|
||||
#define MAX_ACCOUNT_NAME_LEN 255 // Maximum account name length
|
||||
#define MAX_USERNAME_LEN 255 // User name maximum length
|
||||
#define MAX_PASSWORD_LEN 255 // Password name maximum length
|
||||
#define MAX_PROXY_USERNAME_LEN 255 // Proxy user name maximum length
|
||||
#define MAX_PROXY_PASSWORD_LEN 255 // Proxy Password maximum length
|
||||
#define MAX_SERVER_STR_LEN 255 // Maximum length of server string
|
||||
#define MAX_CLIENT_STR_LEN 255 // Maximum length of client string
|
||||
#define MAX_HUBNAME_LEN 255 // Maximum length of HUB name
|
||||
@ -190,7 +188,6 @@
|
||||
#define TIMEOUT_MAX (60 * 1000) // Maximum timeout in seconds
|
||||
#define TIMEOUT_DEFAULT (30 * 1000) // Default number of seconds to timeout
|
||||
#define CONNECTING_TIMEOUT (15 * 1000) // Timeout in seconds of being connected
|
||||
#define CONNECTING_TIMEOUT_PROXY (4 * 1000) // Timeout in seconds of being connected (Proxy)
|
||||
#define CONNECTING_POOLING_SPAN (3 * 1000) // Polling interval of connected
|
||||
#define MIN_RETRY_INTERVAL (5 * 1000) // Minimum retry interval
|
||||
#define MAX_RETRY_INTERVAL (300 * 1000) // Maximum retry interval
|
||||
|
@ -64,8 +64,8 @@ struct CLIENT_OPTION
|
||||
UINT ProxyType; // Type of proxy
|
||||
char ProxyName[MAX_HOST_NAME_LEN + 1]; // Proxy server name
|
||||
UINT ProxyPort; // Port number of the proxy server
|
||||
char ProxyUsername[MAX_PROXY_USERNAME_LEN + 1]; // Maximum user name length
|
||||
char ProxyPassword[MAX_PROXY_PASSWORD_LEN + 1]; // Maximum password length
|
||||
char ProxyUsername[PROXY_MAX_USERNAME_LEN + 1]; // Maximum user name length
|
||||
char ProxyPassword[PROXY_MAX_PASSWORD_LEN + 1]; // Maximum password length
|
||||
char CustomHttpHeader[HTTP_CUSTOM_HEADER_MAX_SIZE + 1]; // Custom HTTP proxy header
|
||||
UINT NumRetry; // Automatic retries
|
||||
UINT RetryInterval; // Retry interval
|
||||
|
@ -6185,744 +6185,6 @@ SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect)
|
||||
return s;
|
||||
}
|
||||
|
||||
// Connect via SOCKS4
|
||||
SOCK *SocksConnectEx2(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
|
||||
char *server_host_name, UINT server_port,
|
||||
char *username, bool additional_connect,
|
||||
bool *cancel_flag, void *hWnd, UINT timeout, IP *ret_ip)
|
||||
{
|
||||
SOCK *s = NULL;
|
||||
IP ip;
|
||||
// Validate arguments
|
||||
if (c == NULL || proxy_host_name == NULL || proxy_port == 0 || server_host_name == NULL
|
||||
|| server_port == 0)
|
||||
{
|
||||
if (c != NULL)
|
||||
{
|
||||
c->Err = ERR_PROXY_CONNECT_FAILED;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get the IP address of the destination server
|
||||
if (GetIP(&ip, server_host_name) == false)
|
||||
{
|
||||
// Failure
|
||||
c->Err = ERR_CONNECT_FAILED;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (c->Halt)
|
||||
{
|
||||
// Stop
|
||||
c->Err = ERR_USER_CANCEL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Connection
|
||||
s = TcpConnectEx3(proxy_host_name, proxy_port, timeout, cancel_flag, hWnd, true, NULL, false, ret_ip);
|
||||
if (s == NULL)
|
||||
{
|
||||
// Failure
|
||||
c->Err = ERR_PROXY_CONNECT_FAILED;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Timeout setting
|
||||
SetTimeout(s, MIN(CONNECTING_TIMEOUT_PROXY, (timeout == 0 ? INFINITE : timeout)));
|
||||
|
||||
if (additional_connect == false)
|
||||
{
|
||||
c->FirstSock = s;
|
||||
}
|
||||
|
||||
// Request packet transmission
|
||||
if (SocksSendRequestPacket(c, s, server_port, &ip, username) == false)
|
||||
{
|
||||
// Failure
|
||||
if (additional_connect == false)
|
||||
{
|
||||
c->FirstSock = NULL;
|
||||
}
|
||||
Disconnect(s);
|
||||
ReleaseSock(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Receive a response packet
|
||||
if (SocksRecvResponsePacket(c, s) == false)
|
||||
{
|
||||
// Failure
|
||||
if (additional_connect == false)
|
||||
{
|
||||
c->FirstSock = NULL;
|
||||
}
|
||||
Disconnect(s);
|
||||
ReleaseSock(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SetTimeout(s, INFINITE);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// Receive a SOCKS4 response packet
|
||||
bool SocksRecvResponsePacket(CONNECTION *c, SOCK *s)
|
||||
{
|
||||
BUF *b;
|
||||
UCHAR tmp[8];
|
||||
UCHAR vn, cd;
|
||||
// Validate arguments
|
||||
if (c == NULL || s == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (RecvAll(s, tmp, sizeof(tmp), false) == false)
|
||||
{
|
||||
c->Err = ERR_DISCONNECTED;
|
||||
return false;
|
||||
}
|
||||
|
||||
b = NewBuf();
|
||||
WriteBuf(b, tmp, sizeof(tmp));
|
||||
SeekBuf(b, 0, 0);
|
||||
|
||||
ReadBuf(b, &vn, 1);
|
||||
ReadBuf(b, &cd, 1);
|
||||
|
||||
FreeBuf(b);
|
||||
|
||||
if (vn != 0)
|
||||
{
|
||||
c->Err = ERR_PROXY_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (cd)
|
||||
{
|
||||
case 90:
|
||||
// Success
|
||||
return true;
|
||||
|
||||
case 93:
|
||||
// Authentication failure
|
||||
c->Err = ERR_PROXY_AUTH_FAILED;
|
||||
return false;
|
||||
|
||||
default:
|
||||
// Connection to the server failure
|
||||
c->Err = ERR_CONNECT_FAILED;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Send a SOCKS4 request packet
|
||||
bool SocksSendRequestPacket(CONNECTION *c, SOCK *s, UINT dest_port, IP *dest_ip, char *userid)
|
||||
{
|
||||
BUF *b;
|
||||
UCHAR vn, cd;
|
||||
USHORT port;
|
||||
UINT ip;
|
||||
bool ret;
|
||||
// Validate arguments
|
||||
if (s == NULL || dest_port == 0 || dest_ip == NULL || c == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (userid == NULL)
|
||||
{
|
||||
userid = "";
|
||||
}
|
||||
|
||||
b = NewBuf();
|
||||
vn = 4;
|
||||
cd = 1;
|
||||
WriteBuf(b, &vn, 1);
|
||||
WriteBuf(b, &cd, 1);
|
||||
port = Endian16((USHORT)dest_port);
|
||||
ip = IPToUINT(dest_ip);
|
||||
WriteBuf(b, &port, 2);
|
||||
WriteBuf(b, &ip, 4);
|
||||
WriteBuf(b, userid, StrLen(userid) + 1);
|
||||
|
||||
ret = SendAll(s, b->Buf, b->Size, false);
|
||||
if (ret == false)
|
||||
{
|
||||
c->Err = ERR_DISCONNECTED;
|
||||
}
|
||||
|
||||
FreeBuf(b);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Connect via SOCKS5 (RFC1928)
|
||||
SOCK *Socks5Connect(CONNECTION *c, WPC_CONNECT *w, bool additional_connect, bool *cancel_flag, void *hWnd, UINT timeout, IP *ret_ip)
|
||||
{
|
||||
UCHAR tmp, recv_buf[2], *recv_buf_final;
|
||||
USHORT port;
|
||||
bool ret;
|
||||
SOCK *s;
|
||||
BUF *b;
|
||||
IP ip;
|
||||
// Validate arguments
|
||||
if (c == NULL || w == NULL || w->Port == 0 || w->ProxyPort == 0 || IsEmptyStr(w->HostName) || IsEmptyStr(w->ProxyHostName))
|
||||
{
|
||||
if (c != NULL)
|
||||
{
|
||||
c->Err = ERR_PROXY_CONNECT_FAILED;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (c->Halt)
|
||||
{
|
||||
// Stop
|
||||
c->Err = ERR_USER_CANCEL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Open TCP connection to the proxy server
|
||||
s = TcpConnectEx3(w->ProxyHostName, w->ProxyPort, timeout, cancel_flag, hWnd, true, NULL, false, ret_ip);
|
||||
if (s == NULL)
|
||||
{
|
||||
// Failure
|
||||
c->Err = ERR_PROXY_CONNECT_FAILED;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Set the timeout setting
|
||||
SetTimeout(s, MIN(CONNECTING_TIMEOUT_PROXY, (timeout == 0 ? INFINITE : timeout)));
|
||||
|
||||
if (additional_connect == false)
|
||||
{
|
||||
c->FirstSock = s;
|
||||
}
|
||||
|
||||
// +----+----------+----------+
|
||||
// |VER | NMETHODS | METHODS |
|
||||
// +----+----------+----------+
|
||||
// | 1 | 1 | 1 to 255 |
|
||||
// +----+----------+----------+
|
||||
//
|
||||
// X'00' NO AUTHENTICATION REQUIRED
|
||||
// X'01' GSSAPI
|
||||
// X'02' USERNAME/PASSWORD
|
||||
// X'03' to X'7F' IANA ASSIGNED
|
||||
// X'80' to X'FE' RESERVED FOR PRIVATE METHODS
|
||||
// X'FF' NO ACCEPTABLE METHOD
|
||||
|
||||
b = NewBuf();
|
||||
tmp = 5;
|
||||
WriteBuf(b, &tmp, sizeof(tmp)); // SOCKS version
|
||||
tmp = 2;
|
||||
WriteBuf(b, &tmp, sizeof(tmp)); // Number of supported methods
|
||||
tmp = 0;
|
||||
WriteBuf(b, &tmp, sizeof(tmp)); // No authentication
|
||||
tmp = 2;
|
||||
WriteBuf(b, &tmp, sizeof(tmp)); // Username/password
|
||||
|
||||
ret = SendAll(s, b->Buf, b->Size, false);
|
||||
FreeBuf(b);
|
||||
|
||||
if (ret == false)
|
||||
{
|
||||
Debug("Socks5Connect(): [Phase 1] Failed to send initial data to the server.\n");
|
||||
c->Err = ERR_DISCONNECTED;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
// +----+--------+
|
||||
// |VER | METHOD |
|
||||
// +----+--------+
|
||||
// | 1 | 1 |
|
||||
// +----+--------+
|
||||
|
||||
if (RecvAll(s, recv_buf, sizeof(recv_buf), false) == false)
|
||||
{
|
||||
Debug("Socks5Connect(): [Phase 1] Failed to receive initial data response from the server.\n");
|
||||
c->Err = ERR_DISCONNECTED;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (recv_buf[0] != 5)
|
||||
{
|
||||
Debug("Socks5Connect(): [Phase 1] Unmatching version: %u.\n", recv_buf[0]);
|
||||
c->Err = ERR_PROXY_ERROR;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
// Username/password authentication (RFC1929)
|
||||
if (recv_buf[1] == 2)
|
||||
{
|
||||
// +----+------+----------+------+----------+
|
||||
// |VER | ULEN | UNAME | PLEN | PASSWD |
|
||||
// +----+------+----------+------+----------+
|
||||
// | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
|
||||
// +----+------+----------+------+----------+
|
||||
|
||||
b = NewBuf();
|
||||
tmp = 1;
|
||||
WriteBuf(b, &tmp, sizeof(tmp)); // Authentication protocol version
|
||||
tmp = StrLen(w->ProxyUsername);
|
||||
WriteBuf(b, &tmp, sizeof(tmp)); // Username length
|
||||
WriteBuf(b, w->ProxyUsername, tmp); // Username
|
||||
tmp = StrLen(w->ProxyPassword);
|
||||
WriteBuf(b, &tmp, sizeof(tmp)); // Password length
|
||||
WriteBuf(b, w->ProxyPassword, tmp); // Password
|
||||
|
||||
ret = SendAll(s, b->Buf, b->Size, false);
|
||||
FreeBuf(b);
|
||||
|
||||
if (ret == false)
|
||||
{
|
||||
Debug("Socks5Connect(): [Phase 1] Failed to send authentication data to the server.\n");
|
||||
c->Err = ERR_DISCONNECTED;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
// +----+--------+
|
||||
// |VER | STATUS |
|
||||
// +----+--------+
|
||||
// | 1 | 1 |
|
||||
// +----+--------+
|
||||
|
||||
if (RecvAll(s, recv_buf, sizeof(recv_buf), false) == false)
|
||||
{
|
||||
Debug("Socks5Connect(): [Phase 1] Failed to receive authentication data response from the server.\n");
|
||||
c->Err = ERR_DISCONNECTED;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (recv_buf[1] != 0)
|
||||
{
|
||||
Debug("Socks5Connect(): [Phase 1] Authentication failure error code sent by the server: %u.\n", recv_buf[1]);
|
||||
c->Err = ERR_PROXY_AUTH_FAILED;
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
|
||||
// +----+-----+-------+------+----------+----------+
|
||||
// |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
|
||||
// +----+-----+-------+------+----------+----------+
|
||||
// | 1 | 1 | X'00' | 1 | Variable | 2 |
|
||||
// +----+-----+-------+------+----------+----------+
|
||||
//
|
||||
// VER protocol version: X'05'
|
||||
// CMD
|
||||
// CONNECT X'01'
|
||||
// BIND X'02'
|
||||
// UDP ASSOCIATE X'03'
|
||||
// RSV RESERVED
|
||||
// ATYP address type of following address
|
||||
// IP V4 address X'01'
|
||||
// DOMAINNAME X'03'
|
||||
// IP V6 address X'04'
|
||||
// DST.ADDR desired destination address
|
||||
// DST.PORT desired destination port in network octet order
|
||||
|
||||
// Prepare data to send
|
||||
b = NewBuf();
|
||||
tmp = 5;
|
||||
WriteBuf(b, &tmp, sizeof(tmp)); // SOCKS version
|
||||
tmp = 1;
|
||||
WriteBuf(b, &tmp, sizeof(tmp)); // Command
|
||||
tmp = 0;
|
||||
WriteBuf(b, &tmp, sizeof(tmp)); // Reserved byte
|
||||
|
||||
// Convert the hostname to an IP structure (if it's an IP address)
|
||||
StrToIP(&ip, w->HostName);
|
||||
|
||||
// If the IP structure doesn't contain an IP address, it means that the string is an hostname
|
||||
if (IsZeroIp(&ip))
|
||||
{
|
||||
UCHAR dest_length = StrLen(w->HostName);
|
||||
tmp = 3;
|
||||
WriteBuf(b, &tmp, sizeof(tmp)); // Destination type (hostname)
|
||||
WriteBuf(b, &dest_length, sizeof(dest_length)); // Destination hostname length
|
||||
WriteBuf(b, w->HostName, dest_length); // Destination hostname
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsIP6(&ip))
|
||||
{
|
||||
tmp = 4;
|
||||
WriteBuf(b, &tmp, sizeof(tmp)); // Destination type (IPv6)
|
||||
WriteBuf(b, ip.ipv6_addr, sizeof(ip.ipv6_addr)); // Destination IPv6 address
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp = 1;
|
||||
WriteBuf(b, &tmp, sizeof(tmp)); // Destination type (IPv4)
|
||||
WriteBuf(b, ip.addr, sizeof(ip.addr)); // Destination IPv4 address
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the port in network octet order
|
||||
port = Endian16((USHORT)w->Port);
|
||||
WriteBuf(b, &port, sizeof(port)); // Destination port
|
||||
|
||||
// Send data
|
||||
ret = SendAll(s, b->Buf, b->Size, false);
|
||||
FreeBuf(b);
|
||||
|
||||
if (ret == false)
|
||||
{
|
||||
Debug("Socks5Connect(): [Phase 2] Failed to send data to the server.\n");
|
||||
c->Err = ERR_DISCONNECTED;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
// +----+-----+-------+------+----------+----------+
|
||||
// |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
|
||||
// +----+-----+-------+------+----------+----------+
|
||||
// | 1 | 1 | X’00’ | 1 | Variable | 2 |
|
||||
// +----+-----+-------+------+----------+----------+
|
||||
//
|
||||
// VER protocol version: X’05’
|
||||
// REP Reply field:
|
||||
// X’00’ succeeded
|
||||
// X’01’ general SOCKS server failure
|
||||
// X’02’ connection not allowed by ruleset
|
||||
// X’03’ Network unreachable
|
||||
// X’04’ Host unreachable
|
||||
// X’05’ Connection refused
|
||||
// X’06’ TTL expired
|
||||
// X’07’ Command not supported
|
||||
// X’08’ Address type not supported
|
||||
// X’09’ to X’FF’ unassigned
|
||||
|
||||
// The packet sent by the server should always have the same size as the one we sent to it.
|
||||
// However, there are some implementations which send fixed values (aside from the first 2 bytes).
|
||||
// In order to support such implementations, we read the first 4 bytes in order to know the address type before trying to read the rest of the packet.
|
||||
recv_buf_final = Malloc(4);
|
||||
|
||||
if (RecvAll(s, recv_buf_final, 4, false) == false)
|
||||
{
|
||||
Free(recv_buf_final);
|
||||
Debug("Socks5Connect(): [Phase 2] Failed to receive response from the server.\n");
|
||||
c->Err = ERR_DISCONNECTED;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
// We only need the first two bytes (version and response code), but we have to read the entire packet from the socket
|
||||
recv_buf[0] = recv_buf_final[0];
|
||||
recv_buf[1] = recv_buf_final[1];
|
||||
|
||||
// We receive the rest of the packet by knowing the size according to the address type
|
||||
switch (recv_buf_final[3])
|
||||
{
|
||||
case 1:
|
||||
// IPv4
|
||||
recv_buf_final = ReAlloc(recv_buf_final, 6); // 4 bytes (IPv4) + 2 bytes (port)
|
||||
ret = RecvAll(s, recv_buf_final, 6, false);
|
||||
break;
|
||||
case 4:
|
||||
// IPv6
|
||||
recv_buf_final = ReAlloc(recv_buf_final, 18); // 4 bytes (IPv4) + 2 bytes (port)
|
||||
ret = RecvAll(s, recv_buf_final, 18, false);
|
||||
break;
|
||||
case 3:
|
||||
// Hostname
|
||||
ret = RecvAll(s, &tmp, 1, false);
|
||||
if (ret == true)
|
||||
{
|
||||
recv_buf_final = ReAlloc(recv_buf_final, tmp + 2); // Hostname length + 2 bytes (port)
|
||||
ret = RecvAll(s, recv_buf_final, tmp + 2, false);
|
||||
}
|
||||
}
|
||||
|
||||
Free(recv_buf_final);
|
||||
|
||||
if (ret == false)
|
||||
{
|
||||
Debug("Socks5Connect(): [Phase 2] Malformed response received from the server.\n");
|
||||
c->Err = ERR_DISCONNECTED;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (recv_buf[0] != 5)
|
||||
{
|
||||
Debug("Socks5Connect(): [Phase 2] Unmatching version: %u.\n", recv_buf_final[0]);
|
||||
c->Err = ERR_PROXY_ERROR;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (recv_buf[1] == 0)
|
||||
{
|
||||
// Success
|
||||
SetTimeout(s, INFINITE);
|
||||
return s;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug("Socks5Connect(): [Phase 2] Connection failed with error: %u\n", recv_buf[1]);
|
||||
c->Err = ERR_PROXY_ERROR;
|
||||
}
|
||||
|
||||
failure:
|
||||
if (additional_connect == false)
|
||||
{
|
||||
c->FirstSock = NULL;
|
||||
}
|
||||
|
||||
Disconnect(s);
|
||||
ReleaseSock(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Connect through a proxy
|
||||
SOCK *ProxyConnectEx2(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
|
||||
char *server_host_name, UINT server_port,
|
||||
char *username, char *password, bool additional_connect,
|
||||
bool *cancel_flag, void *hWnd, UINT timeout)
|
||||
{
|
||||
WPC_CONNECT wpc_connect;
|
||||
Zero(&wpc_connect, sizeof(wpc_connect));
|
||||
|
||||
StrCpy(wpc_connect.ProxyHostName, sizeof(wpc_connect.ProxyHostName), proxy_host_name);
|
||||
wpc_connect.ProxyPort = proxy_port;
|
||||
StrCpy(wpc_connect.HostName, sizeof(wpc_connect.HostName), server_host_name);
|
||||
wpc_connect.Port = server_port;
|
||||
StrCpy(wpc_connect.ProxyUsername, sizeof(wpc_connect.ProxyUsername), username);
|
||||
StrCpy(wpc_connect.ProxyPassword, sizeof(wpc_connect.ProxyPassword), password);
|
||||
|
||||
return ProxyConnectEx3(c, &wpc_connect, additional_connect, cancel_flag, hWnd, timeout);
|
||||
}
|
||||
SOCK *ProxyConnectEx3(CONNECTION *c, WPC_CONNECT *wpc_connect,
|
||||
bool additional_connect, bool *cancel_flag, void *hWnd,
|
||||
UINT timeout)
|
||||
{
|
||||
SOCK *s = NULL;
|
||||
bool use_auth = false;
|
||||
char tmp[MAX_SIZE];
|
||||
char auth_tmp_str[MAX_SIZE], auth_b64_str[MAX_SIZE * 2];
|
||||
char basic_str[MAX_SIZE * 2];
|
||||
UINT http_error_code;
|
||||
HTTP_HEADER *h;
|
||||
char server_host_name_tmp[256];
|
||||
UINT i, len;
|
||||
// Validate arguments
|
||||
if (c == NULL || IsEmptyStr(wpc_connect->ProxyHostName) || wpc_connect->ProxyPort == 0 || IsEmptyStr(wpc_connect->HostName) || wpc_connect->Port == 0)
|
||||
{
|
||||
if (c != NULL)
|
||||
{
|
||||
c->Err = ERR_PROXY_CONNECT_FAILED;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((IsEmptyStr(wpc_connect->ProxyUsername) || IsEmptyStr(wpc_connect->ProxyPassword)) == false)
|
||||
{
|
||||
use_auth = true;
|
||||
}
|
||||
|
||||
if (c->Halt)
|
||||
{
|
||||
// Stop
|
||||
c->Err = ERR_USER_CANCEL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Zero(server_host_name_tmp, sizeof(server_host_name_tmp));
|
||||
StrCpy(server_host_name_tmp, sizeof(server_host_name_tmp), wpc_connect->HostName);
|
||||
|
||||
len = StrLen(server_host_name_tmp);
|
||||
|
||||
for (i = 0;i < len;i++)
|
||||
{
|
||||
if (server_host_name_tmp[i] == '/')
|
||||
{
|
||||
server_host_name_tmp[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Connection
|
||||
s = TcpConnectEx3(wpc_connect->ProxyHostName, wpc_connect->ProxyPort, timeout, cancel_flag, hWnd, true, NULL, false, NULL);
|
||||
if (s == NULL)
|
||||
{
|
||||
// Failure
|
||||
c->Err = ERR_PROXY_CONNECT_FAILED;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Timeout setting
|
||||
SetTimeout(s, MIN(CONNECTING_TIMEOUT_PROXY, (timeout == 0 ? INFINITE : timeout)));
|
||||
|
||||
if (additional_connect == false)
|
||||
{
|
||||
c->FirstSock = s;
|
||||
}
|
||||
|
||||
// HTTP header generation
|
||||
if (IsStrIPv6Address(server_host_name_tmp))
|
||||
{
|
||||
IP ip;
|
||||
char iptmp[MAX_PATH];
|
||||
|
||||
StrToIP(&ip, server_host_name_tmp);
|
||||
IPToStr(iptmp, sizeof(iptmp), &ip);
|
||||
|
||||
Format(tmp, sizeof(tmp), "[%s]:%u", iptmp, wpc_connect->Port);
|
||||
}
|
||||
else
|
||||
{
|
||||
Format(tmp, sizeof(tmp), "%s:%u", server_host_name_tmp, wpc_connect->Port);
|
||||
}
|
||||
|
||||
h = NewHttpHeader("CONNECT", tmp, "HTTP/1.0");
|
||||
|
||||
if (IsEmptyStr(wpc_connect->CustomHttpHeader) == false)
|
||||
{
|
||||
TOKEN_LIST *tokens = ParseToken(wpc_connect->CustomHttpHeader, "\r\n");
|
||||
if (tokens != NULL)
|
||||
{
|
||||
for (i = 0; i < tokens->NumTokens; i++)
|
||||
{
|
||||
AddHttpValueStr(h, tokens->Token[i]);
|
||||
}
|
||||
|
||||
FreeToken(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
if (GetHttpValue(h, "User-Agent") == NULL)
|
||||
{
|
||||
AddHttpValue(h, NewHttpValue("User-Agent", (c->Cedar == NULL ? DEFAULT_USER_AGENT : c->Cedar->HttpUserAgent)));
|
||||
}
|
||||
|
||||
if (GetHttpValue(h, "Host") == NULL)
|
||||
{
|
||||
AddHttpValue(h, NewHttpValue("Host", server_host_name_tmp));
|
||||
}
|
||||
|
||||
if (GetHttpValue(h, "Content-Length") == NULL)
|
||||
{
|
||||
AddHttpValue(h, NewHttpValue("Content-Length", "0"));
|
||||
}
|
||||
|
||||
if (GetHttpValue(h, "Proxy-Connection") == NULL)
|
||||
{
|
||||
AddHttpValue(h, NewHttpValue("Proxy-Connection", "Keep-Alive"));
|
||||
}
|
||||
|
||||
if (GetHttpValue(h, "Pragma") == NULL)
|
||||
{
|
||||
AddHttpValue(h, NewHttpValue("Pragma", "no-cache"));
|
||||
}
|
||||
|
||||
if (use_auth && GetHttpValue(h, "Proxy-Authorization") == NULL)
|
||||
{
|
||||
wchar_t tmp[MAX_SIZE];
|
||||
UniFormat(tmp, sizeof(tmp), _UU("STATUS_3"), server_host_name_tmp);
|
||||
// Generate the authentication string
|
||||
Format(auth_tmp_str, sizeof(auth_tmp_str), "%s:%s",
|
||||
wpc_connect->ProxyUsername, wpc_connect->ProxyPassword);
|
||||
|
||||
// Base64 encode
|
||||
Zero(auth_b64_str, sizeof(auth_b64_str));
|
||||
Encode64(auth_b64_str, auth_tmp_str);
|
||||
Format(basic_str, sizeof(basic_str), "Basic %s", auth_b64_str);
|
||||
|
||||
AddHttpValue(h, NewHttpValue("Proxy-Authorization", basic_str));
|
||||
}
|
||||
|
||||
// Transmission
|
||||
if (SendHttpHeader(s, h) == false)
|
||||
{
|
||||
// Failure
|
||||
if (additional_connect == false)
|
||||
{
|
||||
c->FirstSock = NULL;
|
||||
}
|
||||
FreeHttpHeader(h);
|
||||
Disconnect(s);
|
||||
ReleaseSock(s);
|
||||
c->Err = ERR_PROXY_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FreeHttpHeader(h);
|
||||
|
||||
if (c->Halt)
|
||||
{
|
||||
// Stop
|
||||
if (additional_connect == false)
|
||||
{
|
||||
c->FirstSock = NULL;
|
||||
}
|
||||
Disconnect(s);
|
||||
ReleaseSock(s);
|
||||
c->Err = ERR_USER_CANCEL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Receive the results
|
||||
h = RecvHttpHeader(s);
|
||||
if (h == NULL)
|
||||
{
|
||||
// Failure
|
||||
if (additional_connect == false)
|
||||
{
|
||||
c->FirstSock = NULL;
|
||||
}
|
||||
FreeHttpHeader(h);
|
||||
Disconnect(s);
|
||||
ReleaseSock(s);
|
||||
c->Err = ERR_PROXY_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
http_error_code = 0;
|
||||
if (StrLen(h->Method) == 8)
|
||||
{
|
||||
if (Cmp(h->Method, "HTTP/1.", 7) == 0)
|
||||
{
|
||||
http_error_code = ToInt(h->Target);
|
||||
}
|
||||
}
|
||||
FreeHttpHeader(h);
|
||||
|
||||
// Check the code
|
||||
switch (http_error_code)
|
||||
{
|
||||
case 401:
|
||||
case 403:
|
||||
case 407:
|
||||
// Authentication failure
|
||||
if (additional_connect == false)
|
||||
{
|
||||
c->FirstSock = NULL;
|
||||
}
|
||||
Disconnect(s);
|
||||
ReleaseSock(s);
|
||||
c->Err = ERR_PROXY_AUTH_FAILED;
|
||||
return NULL;
|
||||
|
||||
default:
|
||||
if ((http_error_code / 100) == 2)
|
||||
{
|
||||
// Success
|
||||
SetTimeout(s, INFINITE);
|
||||
return s;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Receive an unknown result
|
||||
if (additional_connect == false)
|
||||
{
|
||||
c->FirstSock = NULL;
|
||||
}
|
||||
Disconnect(s);
|
||||
ReleaseSock(s);
|
||||
c->Err = ERR_PROXY_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TCP connection function
|
||||
SOCK *TcpConnectEx3(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd, bool no_nat_t, UINT *nat_t_error_code, bool try_start_ssl, IP *ret_ip)
|
||||
{
|
||||
|
@ -151,20 +151,6 @@ SOCK *ClientAdditionalConnectToServer(CONNECTION *c);
|
||||
bool ClientUploadAuth2(CONNECTION *c, SOCK *s);
|
||||
bool GetSessionKeyFromPack(PACK *p, UCHAR *session_key, UINT *session_key_32);
|
||||
|
||||
SOCK *ProxyConnectEx2(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
|
||||
char *server_host_name, UINT server_port,
|
||||
char *username, char *password, bool additional_connect,
|
||||
bool *cancel_flag, void *hWnd, UINT timeout);
|
||||
SOCK *ProxyConnectEx3(CONNECTION *c, WPC_CONNECT *wpc_connect,
|
||||
bool additional_connect, bool *cancel_flag, void *hWnd,
|
||||
UINT timeout);
|
||||
SOCK *SocksConnectEx2(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
|
||||
char *server_host_name, UINT server_port,
|
||||
char *username, bool additional_connect,
|
||||
bool *cancel_flag, void *hWnd, UINT timeout, IP *ret_ip);
|
||||
bool SocksSendRequestPacket(CONNECTION *c, SOCK *s, UINT dest_port, IP *dest_ip, char *userid);
|
||||
bool SocksRecvResponsePacket(CONNECTION *c, SOCK *s);
|
||||
SOCK *Socks5Connect(CONNECTION *c, WPC_CONNECT *w, bool additional_connect, bool *cancel_flag, void *hWnd, UINT timeout, IP *ret_ip);
|
||||
void CreateNodeInfo(NODE_INFO *info, CONNECTION *c);
|
||||
UINT SecureSign(SECURE_SIGN *sign, UINT device_id, char *pin);
|
||||
void ClientUploadNoop(CONNECTION *c);
|
||||
|
Reference in New Issue
Block a user