diff --git a/src/Cedar/CM.c b/src/Cedar/CM.c index 42a2b412..f982a2cb 100644 --- a/src/Cedar/CM.c +++ b/src/Cedar/CM.c @@ -6150,6 +6150,8 @@ void CmImportAccountMainEx(HWND hWnd, wchar_t *filename, bool overwrite) t->ClientOption->RequireMonitorMode = old_option->RequireMonitorMode; t->ClientOption->RequireBridgeRoutingMode = old_option->RequireBridgeRoutingMode; t->ClientOption->DisableQoS = old_option->DisableQoS; + t->ClientOption->BindLocalIP = old_option->BindLocalIP;// Source IP address for outgoing connection + t->ClientOption->BindLocalPort = old_option->BindLocalPort;// Source port number for outgoing connection // Inherit the authentication data CiFreeClientAuth(t->ClientAuth); @@ -6456,9 +6458,55 @@ void CmDetailDlgUpdate(HWND hWnd, CM_ACCOUNT *a) Disable(hWnd, R_BRIDGE); Disable(hWnd, R_MONITOR); Disable(hWnd, R_NO_ROUTING); +#if TYPE_BINDLOCALIP + Disable(hWnd, E_BIND_LOCALIP);// Source IP address for outgoing connection + Disable(hWnd, E_BIND_LOCALPORT);// Source port number for outgoing connection +#endif + } } +#if TYPE_BINDLOCALIP +// Set the value of the IP type +void SetIp(HWND hWnd, UINT id, IP* ip) +{ + char tmp[MAX_SIZE]; + // Validate arguments + if (hWnd == NULL || ip == NULL) + { + return; + } + + IPToStr(tmp, sizeof(tmp), ip); + SetTextA(hWnd, id, tmp); +} + +// Get an IP address +bool GetIp(HWND hWnd, UINT id, IP* ip) +{ + char tmp[MAX_SIZE]; + // Validate arguments + if (hWnd == NULL || ip == NULL) + { + return false; + } + + Zero(ip, sizeof(IP)); + + if (GetTxtA(hWnd, id, tmp, sizeof(tmp)) == false) + { + return false; + } + + if (StrToIP(ip, tmp) == false) + { + return false; + } + + return true; +} +#endif + // Advanced Settings dialog procedure UINT CmDetailDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param) { @@ -6495,6 +6543,11 @@ UINT CmDetailDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *pa Check(hWnd, R_NO_ROUTING, a->ClientOption->NoRoutingTracking); Check(hWnd, R_DISABLE_QOS, a->ClientOption->DisableQoS); Check(hWnd, R_DISABLE_UDP, a->ClientOption->NoUdpAcceleration); +#if TYPE_BINDLOCALIP + SetIp(hWnd, E_BIND_LOCALIP, &a->ClientOption->BindLocalIP);// Source IP address for outgoing connection + SetIntEx(hWnd, E_BIND_LOCALPORT, a->ClientOption->BindLocalPort);// Source port number for outgoing connection + //Disable(hWnd, E_BIND_LOCALPORT); // You can not edit +#endif // Select the Connection Mode if (a->LinkMode == false) @@ -6542,6 +6595,20 @@ UINT CmDetailDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *pa Focus(hWnd, E_INTERVAL); break; } +#if TYPE_BINDLOCALIP + // Source IP address for outgoing connection + IP tmpIP; + if (GetIp(hWnd, E_BIND_LOCALIP, &tmpIP) == false) + { + FocusEx(hWnd, E_BIND_LOCALIP); + break; + } + // Source port number for outgoing connection + if ((GetInt(hWnd, E_BIND_LOCALPORT) < 0) || (GetInt(hWnd, E_BIND_LOCALPORT) > 65535)){ + FocusEx(hWnd, E_BIND_LOCALPORT); + break; + } +#endif a->ClientOption->MaxConnection = num; a->ClientOption->AdditionalConnectionInterval = GetInt(hWnd, E_INTERVAL); @@ -6559,6 +6626,10 @@ UINT CmDetailDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *pa a->ClientOption->NoRoutingTracking = IsChecked(hWnd, R_NO_ROUTING); a->ClientOption->DisableQoS = IsChecked(hWnd, R_DISABLE_QOS); a->ClientOption->NoUdpAcceleration = IsChecked(hWnd, R_DISABLE_UDP); +#if TYPE_BINDLOCALIP + a->ClientOption->BindLocalIP = tmpIP;// Source IP address for outgoing connection + a->ClientOption->BindLocalPort = GetInt(hWnd, E_BIND_LOCALPORT);// Source port number for outgoing connection +#endif if (a->LinkMode) { diff --git a/src/Cedar/Client.c b/src/Cedar/Client.c index 406a9db1..1432228e 100644 --- a/src/Cedar/Client.c +++ b/src/Cedar/Client.c @@ -4345,6 +4345,9 @@ void InRpcClientOption(CLIENT_OPTION *c, PACK *p) PackGetStr(p, "CustomHttpHeader", c->CustomHttpHeader, sizeof(c->CustomHttpHeader)); PackGetStr(p, "HubName", c->HubName, sizeof(c->HubName)); PackGetStr(p, "DeviceName", c->DeviceName, sizeof(c->DeviceName)); + PackGetIp(p, "BindLocalIP", &c->BindLocalIP);// Source IP address for outgoing connection + c->BindLocalPort = PackGetInt(p, "BindLocalPort");// Source port nubmer for outgoing connection + c->UseEncrypt = PackGetInt(p, "UseEncrypt") ? true : false; c->UseCompress = PackGetInt(p, "UseCompress") ? true : false; c->HalfConnection = PackGetInt(p, "HalfConnection") ? true : false; @@ -4405,6 +4408,8 @@ void OutRpcClientOption(PACK *p, CLIENT_OPTION *c) PackAddBool(p, "FromAdminPack", c->FromAdminPack); PackAddBool(p, "NoUdpAcceleration", c->NoUdpAcceleration); PackAddData(p, "HostUniqueKey", c->HostUniqueKey, SHA1_SIZE); + PackAddIp(p, "BindLocalIP", &c->BindLocalIP);// Source IP address for outgoing connection + PackAddInt(p, "BindLocalPort", c->BindLocalPort);// Source port number for outgoing connection } // CLIENT_AUTH @@ -9299,7 +9304,9 @@ CLIENT_OPTION *CiLoadClientOption(FOLDER *f) o->DisableQoS = CfgGetBool(f, "DisableQoS"); o->FromAdminPack = CfgGetBool(f, "FromAdminPack"); o->NoUdpAcceleration = CfgGetBool(f, "NoUdpAcceleration"); - + CfgGetIp(f, "BindLocalIP", &o->BindLocalIP);// Source IP address for outgoing connection + o->BindLocalPort = CfgGetInt(f, "BindLocalPort");// Source port number for outgoing connection + b = CfgGetBuf(f, "HostUniqueKey"); if (b != NULL) { @@ -9853,6 +9860,8 @@ void CiWriteClientOption(FOLDER *f, CLIENT_OPTION *o) CfgAddBool(f, "RequireBridgeRoutingMode", o->RequireBridgeRoutingMode); CfgAddBool(f, "DisableQoS", o->DisableQoS); CfgAddBool(f, "NoUdpAcceleration", o->NoUdpAcceleration); + CfgAddIp(f, "BindLocalIP", &o->BindLocalIP);// Source IP address for outgoing connection + CfgAddInt(f, "BindLocalPort", o->BindLocalPort);// Source port number for outgoing connection if (o->FromAdminPack) { diff --git a/src/Cedar/Connection.h b/src/Cedar/Connection.h index 16c44f4b..954738fe 100644 --- a/src/Cedar/Connection.h +++ b/src/Cedar/Connection.h @@ -58,6 +58,7 @@ struct RC4_KEY_PAIR UCHAR ServerToClientKey[16]; UCHAR ClientToServerKey[16]; }; +#define TYPE_BINDLOCALIP 1 // Enable HMI user to edit Source IP address & Source port number for outgoing connection // Client Options // Do not change item size or order and only add new items at the end! @@ -106,6 +107,8 @@ struct CLIENT_OPTION UCHAR HostUniqueKey[SHA1_SIZE]; // Host unique key char CustomHttpHeader[HTTP_CUSTOM_HEADER_MAX_SIZE]; // Custom HTTP proxy header char HintStr[MAX_HOST_NAME_LEN + 1]; // Hint string for NAT-T + IP BindLocalIP; // Source IP address for outgoing connection + UINT BindLocalPort; // Source port number for outgoing connection }; // Client authentication data diff --git a/src/Cedar/Protocol.c b/src/Cedar/Protocol.c index 761bc773..8b0b5bf1 100644 --- a/src/Cedar/Protocol.c +++ b/src/Cedar/Protocol.c @@ -6196,6 +6196,8 @@ SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect) { volatile bool *cancel_flag = NULL; char hostname[MAX_HOST_NAME_LEN]; + char localaddr[MAX_HOST_NAME_LEN]; + bool save_resolved_ip = false; CLIENT_OPTION *o; SESSION *sess; @@ -6255,10 +6257,48 @@ SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect) if (o->PortUDP == 0) { + IP *localIP; + UINT localport; + + // Top of Bind outgoing connection + // Decide the binding operation which is explicitly executed on the client-side + + // In the case of first TCP/IP connection + if (additional_connect == false) { + if (sess->ClientOption->NoRoutingTracking == false) { + localIP = BIND_LOCALIP_NULL; // Specify not to bind + } + else { + Debug("ClientConnectGetSocket(): Using client option %r and %d for binding\n" + , sess->ClientOption->BindLocalIP, sess->ClientOption->BindLocalPort); + // Nonzero address is for source IP address to bind. Zero address is for dummy not to bind. + if (IsZeroIP(&sess->ClientOption->BindLocalIP) == true) { + localIP = BIND_LOCALIP_NULL; + } + else { + localIP = &sess->ClientOption->BindLocalIP; + } + } + } + // In the case of second and subsequent TCP/IP connections + else { + // Bind the socket to the actual local IP address of first TCP / IP connection + localIP = &sess->LocalIP_CacheForNextConnect; + //localIP = BIND_LOCALIP_NULL; // Specify not to bind for test + } + if (sess->ClientOption->BindLocalPort == 0) { + localport = BIND_LOCALPORT_NULL; + } + else { + localport = sess->ClientOption->BindLocalPort + Count(sess->Connection->CurrentNumConnection) - 1; + Debug("ClientConnectGetSocket(): Additional port number %u\n", localport); + } + // Bottom of Bind outgoing connection + // If additional_connect == false, enable trying to NAT-T connection // If additional_connect == true, follow the IsRUDPSession setting in this session // In additional connect or redirect we do not need ssl verification as the certificate is always compared with a saved one - sock = TcpIpConnectEx2(hostname, c->ServerPort, + sock = BindTcpIpConnectEx2(localIP, localport, hostname, c->ServerPort, (bool *)cancel_flag, c->hWndForUI, &nat_t_err, (additional_connect ? (!sess->IsRUDPSession) : false), true, ((additional_connect || c->UseTicket) ? NULL : sess->SslOption), &ssl_err, o->HintStr, &resolved_ip); } @@ -6328,6 +6368,33 @@ SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect) StrCpy(in.HttpCustomHeader, sizeof(in.HttpCustomHeader), o->CustomHttpHeader); StrCpy(in.HttpUserAgent, sizeof(in.HttpUserAgent), c->Cedar->HttpUserAgent); + // Top of Bind outgoing connection + // In the case of first TCP/IP connection + if (additional_connect == false) { + if (sess->ClientOption->NoRoutingTracking == false) { + in.BindLocalIP = BIND_LOCALIP_NULL; // Specify not to bind + } + else { + if (IsZeroIP(&sess->ClientOption->BindLocalIP) == true) { + in.BindLocalIP = BIND_LOCALIP_NULL; + } + else { + in.BindLocalIP = &sess->ClientOption->BindLocalIP; + } + } + } + // In the case of second and subsequent TCP/IP connections + else { + in.BindLocalIP = &sess->LocalIP_CacheForNextConnect; + } + if (sess->ClientOption->BindLocalPort == 0) { + in.BindLocalPort = BIND_LOCALPORT_NULL; + } + else { + in.BindLocalPort = sess->ClientOption->BindLocalPort + Count(sess->Connection->CurrentNumConnection) - 1; + } + // Bottom of Bind outgoing connection + #ifdef OS_WIN32 in.Hwnd = c->hWndForUI; #endif @@ -6338,13 +6405,16 @@ SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect) switch (o->ProxyType) { case PROXY_HTTP: - ret = ProxyHttpConnect(&out, &in, cancel_flag); +// ret = ProxyHttpConnect(&out, &in, cancel_flag); + ret = BindProxyHttpConnect(&out, &in, cancel_flag); // Bind outgoing connection break; case PROXY_SOCKS: - ret = ProxySocks4Connect(&out, &in, cancel_flag); +// ret = ProxySocks4Connect(&out, &in, cancel_flag); + ret = BindProxySocks4Connect(&out, &in, cancel_flag); // Bind outgoing connection break; case PROXY_SOCKS5: - ret = ProxySocks5Connect(&out, &in, cancel_flag); +// ret = ProxySocks5Connect(&out, &in, cancel_flag); + ret = BindProxySocks5Connect(&out, &in, cancel_flag); // Bind outgoing connection break; default: c->Err = ERR_INTERNAL_ERROR; @@ -6379,6 +6449,25 @@ SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect) Debug("ClientConnectGetSocket(): Saved %s IP address %r for future connections.\n", hostname, &resolved_ip); } + // Top of Bind outgoing connection + IPToStr(localaddr, sizeof(localaddr), &sock->LocalIP); + + // In the case of first TCP/IP connection, save the local IP address + if (additional_connect == false) { + c->Session->LocalIP_CacheForNextConnect = sock->LocalIP; + Debug("ClientConnectGetSocket(): Saved local IP address %r for future connections.\n", &sock->LocalIP); + } + // In the case of second and subsequent TCP/IP connections, check to see whether or not the local IP address is same as the first one + else { + if (memcmp(sock->LocalIP.address, c->Session->LocalIP_CacheForNextConnect.address, sizeof(sock->LocalIP.address)) == 0) { + Debug("ClientConnectGetSocket(): Binded local IP address %s OK\n", localaddr); + } + else { + Debug("ClientConnectGetSocket(): Binded local IP address %s NG\n", localaddr); + } + } + // Bottom of Bind outgoing connection + return sock; } @@ -6409,15 +6498,41 @@ UINT ProxyCodeToCedar(UINT code) // 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) { - return TcpConnectEx4(hostname, port, timeout, cancel_flag, hWnd, no_nat_t, nat_t_error_code, try_start_ssl, NULL, NULL, NULL, ret_ip); + return BindTcpConnectEx3(BIND_LOCALIP_NULL, BIND_LOCALPORT_NULL, hostname, port, timeout, cancel_flag, hWnd, no_nat_t, nat_t_error_code, try_start_ssl, ret_ip); } -SOCK *TcpConnectEx4(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd, bool no_nat_t, UINT *nat_t_error_code, bool try_start_ssl, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip) + +SOCK *TcpConnectEx4(char * hostname, UINT port, UINT timeout, bool * cancel_flag, void *hWnd, bool no_nat_t, UINT *nat_t_error_code, bool try_start_ssl, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip) +{ + return BindTcpConnectEx4(BIND_LOCALIP_NULL, BIND_LOCALPORT_NULL, hostname, port, timeout, cancel_flag, hWnd, no_nat_t, nat_t_error_code, try_start_ssl, ssl_option, ssl_err, hint_str, ret_ip); +} + +// Connect with TCP/IP +SOCK *TcpIpConnectEx(char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, IP *ret_ip) +{ + return BindTcpIpConnectEx(BIND_LOCALIP_NULL, BIND_LOCALPORT_NULL, hostname, port, cancel_flag, hWnd, nat_t_error_code, no_nat_t, try_start_ssl, ret_ip); +} + +SOCK *TcpIpConnectEx2(char * hostname, UINT port, bool * cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip) +{ + return BindTcpIpConnectEx2(BIND_LOCALIP_NULL, BIND_LOCALPORT_NULL, hostname, port, cancel_flag, hWnd, nat_t_error_code, no_nat_t, try_start_ssl, ssl_option, ssl_err, hint_str, ret_ip); +} + +// 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) +SOCK *BindTcpConnectEx3(IP *localIP, UINT localport, 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) +{ +// return TcpConnectEx4(hostname, port, timeout, cancel_flag, hWnd, no_nat_t, nat_t_error_code, try_start_ssl, NULL, NULL, NULL, ret_ip); + return BindTcpConnectEx4(localIP, localport, hostname, port, timeout, cancel_flag, hWnd, no_nat_t, nat_t_error_code, try_start_ssl, NULL, NULL, NULL, ret_ip); +} +//SOCK *TcpConnectEx4(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd, bool no_nat_t, UINT *nat_t_error_code, bool try_start_ssl, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip) +SOCK *BindTcpConnectEx4(IP *localIP, UINT localport, char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd, bool no_nat_t, UINT *nat_t_error_code, bool try_start_ssl, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip) { #ifdef OS_WIN32 if (hWnd == NULL) { #endif // OS_WIN32 - return ConnectEx5(hostname, port, timeout, cancel_flag, (no_nat_t ? NULL : VPN_RUDP_SVC_NAME), nat_t_error_code, try_start_ssl, true, ssl_option, ssl_err, hint_str, ret_ip); +// return ConnectEx5(hostname, port, timeout, cancel_flag, (no_nat_t ? NULL : VPN_RUDP_SVC_NAME), nat_t_error_code, try_start_ssl, true, ssl_option, ssl_err, hint_str, ret_ip); + return BindConnectEx5(localIP, localport, hostname, port, timeout, cancel_flag, (no_nat_t ? NULL : VPN_RUDP_SVC_NAME), nat_t_error_code, try_start_ssl, true, ssl_option, ssl_err, hint_str, ret_ip); #ifdef OS_WIN32 } else @@ -6428,11 +6543,14 @@ SOCK *TcpConnectEx4(char *hostname, UINT port, UINT timeout, bool *cancel_flag, } // Connect with TCP/IP -SOCK *TcpIpConnectEx(char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, IP *ret_ip) +//SOCK *TcpIpConnectEx(char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, IP *ret_ip) +SOCK *BindTcpIpConnectEx(IP *localIP, UINT localport, char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, IP *ret_ip) { - return TcpIpConnectEx2(hostname, port, cancel_flag, hWnd, nat_t_error_code, no_nat_t, try_start_ssl, NULL, NULL, NULL, ret_ip); +// return TcpIpConnectEx2(hostname, port, cancel_flag, hWnd, nat_t_error_code, no_nat_t, try_start_ssl, NULL, NULL, NULL, ret_ip); + return BindTcpIpConnectEx2(localIP, localport, hostname, port, cancel_flag, hWnd, nat_t_error_code, no_nat_t, try_start_ssl, NULL, NULL, NULL, ret_ip); } -SOCK *TcpIpConnectEx2(char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip) +//SOCK *TcpIpConnectEx2(char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip) +SOCK *BindTcpIpConnectEx2(IP *localIP, UINT localport, char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip) { SOCK *s = NULL; UINT dummy_int = 0; @@ -6447,7 +6565,8 @@ SOCK *TcpIpConnectEx2(char *hostname, UINT port, bool *cancel_flag, void *hWnd, return NULL; } - s = TcpConnectEx4(hostname, port, 0, cancel_flag, hWnd, no_nat_t, nat_t_error_code, try_start_ssl, ssl_option, ssl_err, hint_str, ret_ip); +// s = TcpConnectEx4(hostname, port, 0, cancel_flag, hWnd, no_nat_t, nat_t_error_code, try_start_ssl, ssl_option, ssl_err, hint_str, ret_ip); + s = BindTcpConnectEx4(localIP, localport, hostname, port, 0, cancel_flag, hWnd, no_nat_t, nat_t_error_code, try_start_ssl, ssl_option, ssl_err, hint_str, ret_ip); if (s == NULL) { return NULL; diff --git a/src/Cedar/Protocol.h b/src/Cedar/Protocol.h index 28f68717..112b365a 100644 --- a/src/Cedar/Protocol.h +++ b/src/Cedar/Protocol.h @@ -115,6 +115,11 @@ bool ClientConnect(CONNECTION *c); SOCK *ClientConnectToServer(CONNECTION *c); SOCK *TcpIpConnectEx(char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, IP *ret_ip); SOCK *TcpIpConnectEx2(char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip); + +// New function named with prefix "Bind" binds outgoing connection to a specific address. New one is wrapped in original one. +SOCK* BindTcpIpConnectEx(IP *localIP, UINT localport, char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, IP *ret_ip); +SOCK* BindTcpIpConnectEx2(IP *localIP, UINT localport, char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip); + bool ClientUploadSignature(SOCK *s); bool ClientDownloadHello(CONNECTION *c, SOCK *s); bool ServerDownloadSignature(CONNECTION *c, char **error_detail_str); @@ -124,6 +129,10 @@ SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect); 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); SOCK *TcpConnectEx4(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd, bool no_nat_t, UINT *nat_t_error_code, bool try_start_ssl, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip); +// New function named with prefix "Bind" binds outgoing connection to a specific address. New one is wrapped in original one. +SOCK* BindTcpConnectEx3(IP *localIP, UINT localport, 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); +SOCK* BindTcpConnectEx4(IP *localIP, UINT localport, char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd, bool no_nat_t, UINT *nat_t_error_code, bool try_start_ssl, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip); + UINT ProxyCodeToCedar(UINT code); void InitProtocol(); diff --git a/src/Cedar/SMInner.h b/src/Cedar/SMInner.h index 2a9158ec..f54ea8c0 100644 --- a/src/Cedar/SMInner.h +++ b/src/Cedar/SMInner.h @@ -41,7 +41,10 @@ typedef struct SETTING char HubName[MAX_HUBNAME_LEN + 1]; // HUB name UCHAR HashedPassword[SHA1_SIZE]; // Password CLIENT_OPTION ClientOption; // Client Option - UCHAR Reserved[10240 - sizeof(UINT) * 8 - SHA1_SIZE - HTTP_CUSTOM_HEADER_MAX_SIZE - MAX_HOST_NAME_LEN - 1]; // Reserved area + +#define SRC_SIZE (sizeof(IP) + sizeof(UINT)) // Source IP address & port number for outgoing connection +// UCHAR Reserved[10240 - sizeof(UINT) * 8 - SHA1_SIZE - HTTP_CUSTOM_HEADER_MAX_SIZE - MAX_HOST_NAME_LEN - 1]; // Reserved area + UCHAR Reserved[10240 - sizeof(UINT) * 8 - SHA1_SIZE - HTTP_CUSTOM_HEADER_MAX_SIZE - MAX_HOST_NAME_LEN - 1 - SRC_SIZE]; // Reserved area } SETTING; // Structure declaration diff --git a/src/Cedar/Session.c b/src/Cedar/Session.c index d680a73a..00a9e817 100644 --- a/src/Cedar/Session.c +++ b/src/Cedar/Session.c @@ -609,6 +609,24 @@ void SessionMain(SESSION *s) WHERE; } } + + // If all the specified number of tcp connections are not alive continuously, then terminate the session. + UINT num_tcp_conn = LIST_NUM(s->Connection->Tcp->TcpSockList); + UINT max_conn = s->ClientOption->MaxConnection; + + if ((s->CurrentConnectionEstablishTime + + (UINT64)(s->ClientOption->AdditionalConnectionInterval * 1000 * 2 + CONNECTING_TIMEOUT * 2)) + <= Tick64()) + { + if (s->ClientOption->BindLocalPort != 0 || num_tcp_conn == 0) + { + timeouted = true; + WHERE; + } + } + //Debug("SessionMain(): The number of TCP connections short... Num_Tcp_Conn=%d Max_Conn=%d Curr_Conn_Time=%llu Tick64=%llu\n" + // , num_tcp_conn, max_conn, s->CurrentConnectionEstablishTime, Tick64()); + } } @@ -1430,6 +1448,7 @@ void ClientThread(THREAD *t, void *param) while (true) { Zero(&s->ServerIP_CacheForNextConnect, sizeof(IP)); + Zero(&s->LocalIP_CacheForNextConnect, sizeof(IP)); // Assigned by first outgoing connection Zero(s->UnderlayProtocol, sizeof(s->UnderlayProtocol)); Zero(s->ProtocolDetails, sizeof(s->ProtocolDetails)); diff --git a/src/Cedar/Session.h b/src/Cedar/Session.h index 992a56f4..8056446a 100644 --- a/src/Cedar/Session.h +++ b/src/Cedar/Session.h @@ -130,6 +130,7 @@ struct SESSION UCHAR Padding[2]; IP ServerIP_CacheForNextConnect; // Server IP, cached for next connect + IP LocalIP_CacheForNextConnect; // Local IP, cached for next connect (2nd and subsequent), assigned by first outgoing connection UINT64 CreatedTime; // Creation date and time UINT64 LastCommTime; // Last communication date and time diff --git a/src/Mayaqua/Network.c b/src/Mayaqua/Network.c index de0b053e..cb6c33be 100644 --- a/src/Mayaqua/Network.c +++ b/src/Mayaqua/Network.c @@ -13116,7 +13116,6 @@ SOCK *ListenEx63(UINT port, bool local_only, bool enable_ca, IP *listen_ip) #ifdef OS_WIN32 if (enable_ca) { - setsockopt(s, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, (char *)&true_flag, sizeof(true_flag)); backlog = 1; } #endif @@ -13642,6 +13641,62 @@ int connect_timeout(SOCKET s, struct sockaddr *addr, int size, int timeout, bool } } #else +#if 0 +LPSTR PrintError(int ErrorCode) +{ + static char Message[1024]; + + // If this program was multithreaded, we'd want to use + // FORMAT_MESSAGE_ALLOCATE_BUFFER instead of a static buffer here. + // (And of course, free the buffer when we were done with it) + + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, ErrorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)Message, 1024, NULL); + return Message; +} +#else +char *PrintError(int ErrorCode) +{ + char *Message; + switch (ErrorCode) { + case WSAEFAULT: + Message = "Bad address."; + break; + + case WSAEWOULDBLOCK: + Message = "Resource temporarily unavailable."; + break; + + case WSAEINPROGRESS: + Message = "Operation now in progress."; + break; + + case WSAEALREADY: + Message = "Operation already in progress."; + break; + + case WSAEAFNOSUPPORT: + Message = "Address family not supported by protocol family."; + break; + + case WSAEADDRINUSE: + Message = "Address already in use."; + break; + + case WSAEADDRNOTAVAIL: + Message = "Cannot assign requested address."; + break; + + default: + Message = ""; + break; + } + return Message; +} +#endif + // Connection with timeout (Win32 version) int connect_timeout(SOCKET s, struct sockaddr *addr, int size, int timeout, bool *cancel_flag) { @@ -13773,8 +13828,71 @@ void SetSockHighPriority(SOCK *s, bool flag) SetSockTos(s, (flag ? 16 : 0)); } +// Bind the socket to IPv4 or IPV6 address +int bind_sock(SOCKET sock, IP *ip, UINT port) +{ + //char tmp[MAX_HOST_NAME_LEN + 1]; + //memset(tmp, 0, sizeof(tmp)); + //IPToStr(tmp, sizeof(tmp), ip); + //Debug("bind_sock(): Binding... IP address %s:%d\n", tmp, port); + + if (IsIP4(ip)) + { + // Declare variables + struct sockaddr_in sockaddr_in; + + Zero(&sockaddr_in, sizeof(sockaddr_in)); + + // Set up the sockaddr structure + sockaddr_in.sin_family = AF_INET; + IPToInAddr(&sockaddr_in.sin_addr, ip); + sockaddr_in.sin_port = htons((USHORT)port); + //inet_pton(AF_INET, tmp, &addr_in.sin_addr.s_addr); + + UINT true_flag = 1; + // This only have enabled for UNIX system since there is a bug + // in the implementation of REUSEADDR in Windows OS + (void)setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&true_flag, sizeof(true_flag)); + + // Bind the socket using the information in the sockaddr structure + return (bind(sock, (struct sockaddr *)&sockaddr_in, sizeof(sockaddr_in))); + } + else + { + // Declare variables + struct sockaddr_in6 sockaddr_in; + + Zero(&sockaddr_in, sizeof(sockaddr_in)); + + // Set up the sockaddr structure + sockaddr_in.sin6_family = AF_INET6; + IPToInAddr6(&sockaddr_in.sin6_addr, ip); + sockaddr_in.sin6_scope_id = ip->ipv6_scope_id; + sockaddr_in.sin6_port = htons((USHORT)port); + //inet_pton(AF_INET6, tmp, &sockaddr_in.sin6_addr.s6_bytes); + + UINT true_flag = 1; +#ifdef OS_UNIX + // It is necessary to set the IPv6 Only flag on a UNIX system + (void)setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &true_flag, sizeof(true_flag)); +#endif // OS_UNIX + // This only have enabled for UNIX system since there is a bug + // in the implementation of REUSEADDR in Windows OS + (void)setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&true_flag, sizeof(true_flag)); + + // Bind the socket using the information in the sockaddr structure + return (bind(sock, (struct sockaddr *)&sockaddr_in, sizeof(sockaddr_in))); + } +} + // Connect to the IPv4 host using a socket -SOCKET ConnectTimeoutIPv4(IP *ip, UINT port, UINT timeout, bool *cancel_flag) +SOCKET ConnectTimeoutIPv4(IP* ip, UINT port, UINT timeout, bool* cancel_flag) +{ + return BindConnectTimeoutIPv4(BIND_LOCALIP_NULL, BIND_LOCALPORT_NULL, ip, port, timeout, cancel_flag); +} + +// Connect to the IPv4 host using a socket +SOCKET BindConnectTimeoutIPv4(IP* localIP, UINT localport, IP* ip, UINT port, UINT timeout, bool* cancel_flag) { SOCKET s; struct sockaddr_in sockaddr4; @@ -13791,6 +13909,34 @@ SOCKET ConnectTimeoutIPv4(IP *ip, UINT port, UINT timeout, bool *cancel_flag) // Socket creation s = socket(AF_INET, SOCK_STREAM, 0); + + // Top of Bind outgoing connection + if (s != INVALID_SOCKET) { + int ier; + IP tmpIP; + + if (localIP == BIND_LOCALIP_NULL) { + StrToIP(&tmpIP, "0.0.0.0"); // A NULL address for the argument "localIP" is treated as if "0::0" in IPV4 was specified. + localIP = &tmpIP; + } + + if ((IsZeroIP(localIP) == false) || (localport != 0)) { + + // Bind the socket + if (bind_sock(s, localIP, localport) != 0) { +#ifdef OS_WIN32 + ier = WSAGetLastError(); + Debug("IPv4 bind() failed with error: %d %s\n", ier, PrintError(ier)); +#else + Debug("IPv4 bind() failed with error: %d %s\n", errno, strerror(errno)); +#endif + closesocket(s); + s = INVALID_SOCKET; + } + } + } + // Bottom of Bind outgoing connection + if (s != INVALID_SOCKET) { // Connection @@ -14053,7 +14199,21 @@ void ConnectThreadForRUDP(THREAD *thread, void *param) } // IPv4 connection thread (multiple protocols, multiple addresses) -void ConnectThreadForIPv4(THREAD *thread, void *param) +void ConnectThreadForIPv4(THREAD* thread, void* param) +{ + CONNECT_SERIAL_PARAM* p = (CONNECT_SERIAL_PARAM*)param; + if (thread == NULL || p == NULL) + { + return; + } + p->LocalIP = BIND_LOCALIP_NULL; + p->LocalPort = BIND_LOCALPORT_NULL; + return BindConnectThreadForIPv4(thread, param); +} + +// IPv4 connection thread (multiple protocols, multiple addresses) +//void ConnectThreadForIPv4(THREAD* thread, void* param) +void BindConnectThreadForIPv4(THREAD *thread, void *param) { SOCKET s = INVALID_SOCKET; IP current_ip; @@ -14106,7 +14266,8 @@ void ConnectThreadForIPv4(THREAD *thread, void *param) if (use_natt == false) { // Normal connection without using NAT-T - s = ConnectTimeoutIPv4(ip, p->Port, p->Timeout, p->CancelFlag); +// s = ConnectTimeoutIPv4(ip, p->Port, p->Timeout, p->CancelFlag); + s = BindConnectTimeoutIPv4(p->LocalIP, p->LocalPort, ip, p->Port, p->Timeout, p->CancelFlag); if (s != INVALID_SOCKET) { @@ -14408,7 +14569,21 @@ void ConnectThreadForIPv4(THREAD *thread, void *param) } // IPv6 connection thread (multiple addresses) -void ConnectThreadForIPv6(THREAD *thread, void *param) +void ConnectThreadForIPv6(THREAD* thread, void* param) +{ + CONNECT_SERIAL_PARAM* p = (CONNECT_SERIAL_PARAM*)param; + if (thread == NULL || p == NULL) + { + return; + } + p->LocalIP = BIND_LOCALIP_NULL; + p->LocalPort = BIND_LOCALPORT_NULL; + return BindConnectThreadForIPv6(thread, param); +} + +// IPv6 connection thread (multiple addresses) +//void ConnectThreadForIPv6(THREAD *thread, void *param) +void BindConnectThreadForIPv6(THREAD* thread, void* param) { SOCKET s = INVALID_SOCKET; IP current_ip; @@ -14463,6 +14638,34 @@ void ConnectThreadForIPv6(THREAD *thread, void *param) // Socket creation s = socket(AF_INET6, SOCK_STREAM, 0); + + // Top of Bind outgoing connection + if (s != INVALID_SOCKET){ + int ier; + IP tmpIP; + + if (p->LocalIP == BIND_LOCALIP_NULL) { + StrToIP(&tmpIP, "0::0"); // A NULL address for the argument "p->LocalIP" is treated as if "0::0" in IPV6 was specified. + p->LocalIP = &tmpIP; + } + + if ((IsZeroIP(p->LocalIP) == false) || (p->LocalPort != 0)){ + + // Bind the socket + if (bind_sock(s, p->LocalIP, p->LocalPort) != 0) { +#ifdef OS_WIN32 + ier = WSAGetLastError(); + Debug("IPv6 bind() failed with error: %d %s\n", ier, PrintError(ier)); +#else + Debug("IPv6 bind() failed with error: %d %s\n", errno, strerror(errno)); +#endif + closesocket(s); + s = INVALID_SOCKET; + } + } + } + // Bottom of Bind outgoing connection + if (s != INVALID_SOCKET) { // Connection @@ -14588,6 +14791,18 @@ SOCK *ConnectEx4(char *hostname, UINT port, UINT timeout, bool *cancel_flag, cha return ConnectEx5(hostname, port, timeout, cancel_flag, nat_t_svc_name, nat_t_error_code, try_start_ssl, no_get_hostname, NULL, NULL, NULL, ret_ip); } SOCK *ConnectEx5(char *hostname, UINT port, UINT timeout, bool *cancel_flag, char *nat_t_svc_name, UINT *nat_t_error_code, bool try_start_ssl, bool no_get_hostname, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip) +{ + return BindConnectEx5(BIND_LOCALIP_NULL, BIND_LOCALPORT_NULL, hostname, port, timeout, cancel_flag, nat_t_svc_name, nat_t_error_code, try_start_ssl, no_get_hostname, ssl_option, ssl_err, hint_str, ret_ip); +} + +//SOCK* ConnectEx4(char* hostname, UINT port, UINT timeout, bool* cancel_flag, char* nat_t_svc_name, UINT* nat_t_error_code, bool try_start_ssl, bool no_get_hostname, IP* ret_ip) +SOCK *BindConnectEx4(IP *localIP, UINT localport, char *hostname, UINT port, UINT timeout, bool *cancel_flag, char *nat_t_svc_name, UINT *nat_t_error_code, bool try_start_ssl, bool no_get_hostname, IP *ret_ip) +{ +// return ConnectEx5(hostname, port, timeout, cancel_flag, nat_t_svc_name, nat_t_error_code, try_start_ssl, no_get_hostname, NULL, NULL, NULL, ret_ip); + return BindConnectEx5(localIP, localport, hostname, port, timeout, cancel_flag, nat_t_svc_name, nat_t_error_code, try_start_ssl, no_get_hostname, NULL, NULL, NULL, ret_ip); +} +//SOCK *ConnectEx5(char *hostname, UINT port, UINT timeout, bool *cancel_flag, char *nat_t_svc_name, UINT *nat_t_error_code, bool try_start_ssl, bool no_get_hostname, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip) +SOCK *BindConnectEx5(IP *localIP, UINT localport, char *hostname, UINT port, UINT timeout, bool *cancel_flag, char *nat_t_svc_name, UINT *nat_t_error_code, bool try_start_ssl, bool no_get_hostname, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip) { bool dummy = false; bool use_natt = false; @@ -14683,6 +14898,16 @@ SOCK *ConnectEx5(char *hostname, UINT port, UINT timeout, bool *cancel_flag, cha if (LIST_NUM(iplist_v6) > 0) { p6.IpList = iplist_v6; + + if (localIP == BIND_LOCALIP_NULL) { + p6.LocalIP = BIND_LOCALIP_NULL; // Make the NULL address passing through + } + else { + CopyIP(&p6.LocalIP_Cache, localIP); + p6.LocalIP = &p6.LocalIP_Cache; + } + p6.LocalPort = localport; + p6.Port = port; p6.Timeout = timeout; StrCpy(p6.Hostname, sizeof(p6.Hostname), hostname); @@ -14696,13 +14921,24 @@ SOCK *ConnectEx5(char *hostname, UINT port, UINT timeout, bool *cancel_flag, cha p6.Ret_Ip = &ret_ip6; p6.RetryDelay = 250; p6.Delay = 0; - t6 = NewThread(ConnectThreadForIPv6, &p6); +// t6 = NewThread(ConnectThreadForIPv6, &p6); + t6 = NewThread(BindConnectThreadForIPv6, &p6); // For binding a socket } // IPv4 connection thread if (LIST_NUM(iplist_v4) > 0) { p4.IpList = iplist_v4; + + if (localIP == BIND_LOCALIP_NULL) { + p4.LocalIP = BIND_LOCALIP_NULL; // Make the NULL address passing through + } + else { + CopyIP(&p4.LocalIP_Cache, localIP); + p4.LocalIP = &p4.LocalIP_Cache; + } + p4.LocalPort = localport; + p4.Port = port; p4.Timeout = timeout; StrCpy(p4.Hostname, sizeof(p4.Hostname), hostname); @@ -14721,7 +14957,8 @@ SOCK *ConnectEx5(char *hostname, UINT port, UINT timeout, bool *cancel_flag, cha p4.Ret_Ip = &ret_ip4; p4.RetryDelay = 250; p4.Delay = 250; // Delay by 250ms to prioritize IPv6 (RFC 6555 recommends 150-250ms, Chrome uses 300ms) - t4 = NewThread(ConnectThreadForIPv4, &p4); +// t4 = NewThread(ConnectThreadForIPv4, &p4); + t4 = NewThread(BindConnectThreadForIPv4, &p4); // For binding a socket } if (t6 == NULL || t4 == NULL) diff --git a/src/Mayaqua/Network.h b/src/Mayaqua/Network.h index 861993c2..39e3f5fc 100644 --- a/src/Mayaqua/Network.h +++ b/src/Mayaqua/Network.h @@ -812,6 +812,9 @@ struct RUDP_STACK struct CONNECT_SERIAL_PARAM { LIST *IpList; + UINT LocalPort; // Local port number to bind + IP *LocalIP; // Local IP address to bind. NULL address allowed to use. + IP LocalIP_Cache; // Local IP address to bind UINT Port; UINT Timeout; char Hostname[MAX_SIZE]; @@ -950,6 +953,10 @@ void ConnectThreadForRUDP(THREAD *thread, void *param); void ConnectThreadForOverDnsOrIcmp(THREAD *thread, void *param); void ConnectThreadForIPv4(THREAD *thread, void *param); void ConnectThreadForIPv6(THREAD *thread, void *param); + +void BindConnectThreadForIPv4(THREAD *thread, void *param); +void BindConnectThreadForIPv6(THREAD *thread, void *param); + SOCK *CreateTCPSock(SOCKET s, bool is_ipv6, IP *current_ip, bool no_get_hostname, char *hostname_original); SOCK *NewRUDPClientNatT(char *svc_name, IP *ip, UINT *error_code, UINT timeout, bool *cancel, char *hint_str, char *target_hostname); RUDP_STACK *NewRUDPServer(char *svc_name, RUDP_STACK_INTERRUPTS_PROC *proc_interrupts, RUDP_STACK_RPC_RECV_PROC *proc_rpc_recv, void *param, UINT port, bool no_natt_register, bool over_dns_mode, volatile UINT *natt_global_udp_port, UCHAR rand_port_id, IP *listen_ip); @@ -1113,6 +1120,14 @@ SOCK *ConnectEx3(char *hostname, UINT port, UINT timeout, bool *cancel_flag, cha SOCK *ConnectEx4(char *hostname, UINT port, UINT timeout, bool *cancel_flag, char *nat_t_svc_name, UINT *nat_t_error_code, bool try_start_ssl, bool no_get_hostname, IP *ret_ip); SOCK *ConnectEx5(char *hostname, UINT port, UINT timeout, bool *cancel_flag, char *nat_t_svc_name, UINT *nat_t_error_code, bool try_start_ssl, bool no_get_hostname, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip); SOCKET ConnectTimeoutIPv4(IP *ip, UINT port, UINT timeout, bool *cancel_flag); + +// New function named with prefix "Bind" binds outgoing connection to a specific address. New one is wrapped in original one. +#define BIND_LOCALIP_NULL NULL // NULL IP address specifies no binding +#define BIND_LOCALPORT_NULL 0 // NULL port number specifies no binding +SOCK *BindConnectEx4(IP *localIP, UINT localport, char *hostname, UINT port, UINT timeout, bool *cancel_flag, char *nat_t_svc_name, UINT *nat_t_error_code, bool try_start_ssl, bool no_get_hostname, IP *ret_ip); +SOCK *BindConnectEx5(IP *localIP, UINT localport, char *hostname, UINT port, UINT timeout, bool *cancel_flag, char *nat_t_svc_name, UINT *nat_t_error_code, bool try_start_ssl, bool no_get_hostname, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip); +SOCKET BindConnectTimeoutIPv4(IP *localIP, UINT localport, IP *ip, UINT port, UINT timeout, bool *cancel_flag); + bool SetSocketBufferSize(SOCKET s, bool send, UINT size); UINT SetSocketBufferSizeWithBestEffort(SOCKET s, bool send, UINT size); void InitUdpSocketBufferSize(SOCKET s); diff --git a/src/Mayaqua/Proxy.c b/src/Mayaqua/Proxy.c index 37f5c159..fa0ea096 100644 --- a/src/Mayaqua/Proxy.c +++ b/src/Mayaqua/Proxy.c @@ -16,11 +16,25 @@ SOCK *Internal_ProxyTcpConnect(PROXY_PARAM_IN *param, volatile bool *cancel_flag } #endif - return ConnectEx4(param->Hostname, param->Port, param->Timeout, (bool *)cancel_flag, NULL, NULL, false, true, resolved_ip); + //return ConnectEx4(param->Hostname, param->Port, param->Timeout, (bool*)cancel_flag, NULL, NULL, false, true, resolved_ip); + return BindConnectEx4(param->BindLocalIP, param->BindLocalPort, param->Hostname, param->Port, param->Timeout, (bool *)cancel_flag, NULL, NULL, false, true, resolved_ip); } // Connect to an HTTP proxy UINT ProxyHttpConnect(PROXY_PARAM_OUT *out, PROXY_PARAM_IN *in, volatile bool *cancel_flag) +{ + // Validate arguments + if (out == NULL || in == NULL || in->Port == 0 || in->TargetPort == 0 || IsEmptyStr(in->Hostname) || IsEmptyStr(in->TargetHostname)) + { + return PROXY_ERROR_PARAMETER; + } + in->BindLocalIP = BIND_LOCALIP_NULL; + in->BindLocalPort = BIND_LOCALPORT_NULL; + return BindProxyHttpConnect(out, in, cancel_flag); +} + +// Connect to an HTTP proxy +UINT BindProxyHttpConnect(PROXY_PARAM_OUT *out, PROXY_PARAM_IN *in, volatile bool *cancel_flag) { bool dummy_cancel_flag = false, use_auth = false; char target_hostname[MAX_HOST_NAME_LEN + 1]; @@ -208,6 +222,19 @@ FAILURE: // Connect to a SOCKS5 proxy (RFC1928, RFC1929 defines username/password authentication) UINT ProxySocks5Connect(PROXY_PARAM_OUT *out, PROXY_PARAM_IN *in, volatile bool *cancel_flag) +{ + // Validate arguments + if (out == NULL || in == NULL || in->Port == 0 || in->TargetPort == 0 || IsEmptyStr(in->Hostname) || IsEmptyStr(in->TargetHostname)) + { + return PROXY_ERROR_PARAMETER; + } + in->BindLocalIP = BIND_LOCALIP_NULL; + in->BindLocalPort = BIND_LOCALPORT_NULL; + return BindProxySocks5Connect(out, in, cancel_flag); +} + +// Connect to a SOCKS5 proxy (RFC1928, RFC1929 defines username/password authentication) +UINT BindProxySocks5Connect(PROXY_PARAM_OUT *out, PROXY_PARAM_IN *in, volatile bool *cancel_flag) { bool dummy_cancel_flag = false; UCHAR tmp, recv_buf[2], *recv_buf_final; @@ -521,6 +548,19 @@ FAILURE: // Connect to a SOCKS4 proxy UINT ProxySocks4Connect(PROXY_PARAM_OUT *out, PROXY_PARAM_IN *in, volatile bool *cancel_flag) +{ + // Validate arguments + if (out == NULL || in == NULL || in->Port == 0 || in->TargetPort == 0 || IsEmptyStr(in->Hostname) || IsEmptyStr(in->TargetHostname)) + { + return PROXY_ERROR_PARAMETER; + } + in->BindLocalIP = BIND_LOCALIP_NULL; + in->BindLocalPort = BIND_LOCALPORT_NULL; + return BindProxySocks4Connect(out, in, cancel_flag); +} + +// Connect to a SOCKS4 proxy +UINT BindProxySocks4Connect(PROXY_PARAM_OUT *out, PROXY_PARAM_IN *in, volatile bool *cancel_flag) { bool dummy_cancel_flag = false; UCHAR tmp, recv_buf[8]; diff --git a/src/Mayaqua/Proxy.h b/src/Mayaqua/Proxy.h index 2f8325ca..626bd886 100644 --- a/src/Mayaqua/Proxy.h +++ b/src/Mayaqua/Proxy.h @@ -30,6 +30,8 @@ struct PROXY_PARAM_IN UINT Timeout; char HttpCustomHeader[HTTP_CUSTOM_HEADER_MAX_SIZE]; char HttpUserAgent[HTTP_HEADER_USER_AGENT_MAX_SIZE + 1]; + IP *BindLocalIP; // Source IP address for outgoing connection + UINT BindLocalPort; // UINT used not USHORT // Source port number for outgoing connection #ifdef OS_WIN32 void *Hwnd; #endif @@ -45,4 +47,9 @@ UINT ProxyHttpConnect(PROXY_PARAM_OUT *out, PROXY_PARAM_IN *in, volatile bool *c UINT ProxySocks5Connect(PROXY_PARAM_OUT *out, PROXY_PARAM_IN *in, volatile bool *cancel_flag); UINT ProxySocks4Connect(PROXY_PARAM_OUT *out, PROXY_PARAM_IN *in, volatile bool *cancel_flag); +// New function named with prefix "Bind" binds outgoing connection to a specific address. New one is wrapped in original one. +UINT BindProxyHttpConnect(PROXY_PARAM_OUT *out, PROXY_PARAM_IN *in, volatile bool *cancel_flag); +UINT BindProxySocks5Connect(PROXY_PARAM_OUT *out, PROXY_PARAM_IN *in, volatile bool *cancel_flag); +UINT BindProxySocks4Connect(PROXY_PARAM_OUT *out, PROXY_PARAM_IN *in, volatile bool *cancel_flag); + #endif diff --git a/src/PenCore/PenCore.rc b/src/PenCore/PenCore.rc index 3d356d3c..47ca1f5c 100644 --- a/src/PenCore/PenCore.rc +++ b/src/PenCore/PenCore.rc @@ -13,7 +13,7 @@ #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// -// 日文 resources +// 日Eresources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_JPN) #ifdef _WIN32 @@ -1654,14 +1654,18 @@ BEGIN LTEXT "@S_MODE",S_MODE,254,169,166,17 CONTROL "@R_BRIDGE",R_BRIDGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,254,191,166,9 CONTROL "@R_MONITOR",R_MONITOR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,254,205,166,9 - GROUPBOX "@STATIC17",IDC_STATIC,222,225,205,30 - CONTROL "@R_NO_ROUTING",R_NO_ROUTING,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,233,238,181,9 - ICON ICO_WARNING,S_WARNING_ICON,223,261,18,18 - LTEXT "@STATIC18",IDC_STATIC,247,261,180,26 + GROUPBOX "@STATIC17", IDC_STATIC, 222, 225, 205, 43 + CONTROL "@R_NO_ROUTING",R_NO_ROUTING,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,233,234,181,9 + LTEXT "@STATIC20", IDC_STATIC, 233, 243, 58, 17 + EDITTEXT E_BIND_LOCALIP, 292, 243, 126, 11, ES_RIGHT | ES_AUTOHSCROLL + LTEXT "@STATIC21", IDC_STATIC, 233, 255, 58, 12 + EDITTEXT E_BIND_LOCALPORT, 292, 255, 40, 11, ES_RIGHT | ES_AUTOHSCROLL + ICON ICO_WARNING,S_WARNING_ICON,223,270,18,18 + LTEXT "@STATIC18",IDC_STATIC,247,270,180,26 DEFPUSHBUTTON "@IDOK",IDOK,294,291,64,15 PUSHBUTTON "@IDCANCEL",IDCANCEL,363,291,64,15 ICON ICO_SWITCH,IDC_STATIC,230,169,18,18 -END + END D_CM_NEW_VLAN DIALOGEX 0, 0, 251, 98 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU @@ -4865,12 +4869,12 @@ END // BIN_WINPCAP BIN "Dummy.bin" -#endif // 日文 resources +#endif // 日Eresources ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// -// 中文 (台灣) resources +// 中E(台灣) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHT) #ifdef _WIN32 @@ -4886,12 +4890,12 @@ LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. ICO_LANG_TRADITIONAL_CHINESE ICON "LANG_TRADITIONAL_CHINESE.ico" -#endif // 中文 (台灣) resources +#endif // 中E(台灣) resources ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// -// 英文 (美國) resources +// 英E(EE resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 @@ -4952,7 +4956,7 @@ BMP_ZURUKKO BITMAP "Zurukko.bmp" BMP_VPNGATEEN BITMAP "VPNGateEN.bmp" BMP_VPNGATEJA BITMAP "VPNGateJA.bmp" BMP_UNIVTSUKUBA BITMAP "UnivTsukuba.bmp" -#endif // 英文 (美國) resources +#endif // 英E(EE resources ///////////////////////////////////////////////////////////////////////////// diff --git a/src/PenCore/resource.h b/src/PenCore/resource.h index 384d3ff9..2c886a3a 100644 --- a/src/PenCore/resource.h +++ b/src/PenCore/resource.h @@ -339,6 +339,8 @@ #define C_NUM_TCP 1075 #define B_TRUST 1076 #define E_INTERVAL 1076 +#define E_BIND_LOCALIP 9076 // Bind source IP address +#define E_BIND_LOCALPORT 9077 // Bind source port number #define B_PROXY_CONFIG 1077 #define B_SERVER_CERT 1078 #define B_VIEW_SERVER_CERT 1079 diff --git a/src/bin/hamcore/strtable_en.stb b/src/bin/hamcore/strtable_en.stb index 0f79db28..5634379f 100644 --- a/src/bin/hamcore/strtable_en.stb +++ b/src/bin/hamcore/strtable_en.stb @@ -2421,6 +2421,8 @@ STATIC17 Other Confi&gurations: R_NO_ROUTING No Adjustments of &Routing Table STATIC18 Keep the settings default in this dialog unless you are told to do so by a system administrator, or you have expertise for networking and security. STATIC19 The VoIP / QoS functions handle high priority packets such as IP telephone packets (VoIP) to be transmitted faster. +STATIC20 Source IP Address: +STATIC21 Source Port Number: R_DISABLE_QOS Disable VoIP / &QoS Functions IDOK &OK IDCANCEL Cancel diff --git a/src/bin/hamcore/strtable_ja.stb b/src/bin/hamcore/strtable_ja.stb index b7e2f4eb..3e195742 100644 --- a/src/bin/hamcore/strtable_ja.stb +++ b/src/bin/hamcore/strtable_ja.stb @@ -2424,6 +2424,8 @@ STATIC17 桐株身摰(&G): R_NO_ROUTING 怒潦喋啜潦怒株矽游衣銵芥(&R) STATIC18 株身摰駁U株身摰柴胯瑯嫘蝞∠蝷箝游胯潦胯颯准乓芥恍U西底亥∼桀游隞亙臬氬芥扼 STATIC19 VoIP / QoS 撖曉璈賬雿輻具具IP 餉店晞芥押桀芸摨艾桅晞 VPN 折思扼整 +STATIC20 靽∪IPU研: +STATIC21 靽∪潦芸: R_DISABLE_QOS VoIP / QoS 撖曉璈賬∪嫘怒(&Q) IDOK &OK IDCANCEL 准喋颯