📄 socks.cxx
字号:
/*
* socks.cxx
*
* SOCKS protocol
*
* Portable Windows Library
*
* Copyright (c) 1993-2002 Equivalence Pty. Ltd.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Portable Windows Library.
*
* The Initial Developer of the Original Code is Equivalence Pty. Ltd.
*
* $Log: socks.cxx,v $
* Revision 1.1 2006/06/29 04:18:04 joegenbaclor
* *** empty log message ***
*
* Revision 1.9 2004/04/03 08:22:21 csoutheren
* Remove pseudo-RTTI and replaced with real RTTI
*
* Revision 1.8 2003/09/08 01:42:48 dereksmithies
* Add patch from Diego Tartara <dtartara@mens2.hq.novamens.com>. Many Thanks!
*
* Revision 1.7 2002/11/06 22:47:25 robertj
* Fixed header comment (copyright etc)
*
* Revision 1.6 2002/08/05 05:40:45 robertj
* Fixed missing pragma interface/implementation
*
* Revision 1.5 2001/09/10 02:51:23 robertj
* Major change to fix problem with error codes being corrupted in a
* PChannel when have simultaneous reads and writes in threads.
*
* Revision 1.4 1999/11/23 08:45:10 robertj
* Fixed bug in user/pass authentication version, thanks Dmitry <dipa@linkline.com>
*
* Revision 1.3 1999/02/16 08:08:06 robertj
* MSVC 6.0 compatibility changes.
*
* Revision 1.2 1998/12/23 00:35:28 robertj
* UDP support.
*
* Revision 1.1 1998/12/22 10:30:24 robertj
* Initial revision
*
*/
#include <ptlib.h>
#ifdef __GNUC__
#pragma implementation "socks.h"
#endif
#include <ptclib/socks.h>
#define new PNEW
#define SOCKS_VERSION_4 ((BYTE)4)
#define SOCKS_VERSION_5 ((BYTE)5)
#define SOCKS_CMD_CONNECT ((BYTE)1)
#define SOCKS_CMD_BIND ((BYTE)2)
#define SOCKS_CMD_UDP_ASSOCIATE ((BYTE)3)
#define SOCKS_AUTH_NONE ((BYTE)0)
#define SOCKS_AUTH_USER_PASS ((BYTE)2)
#define SOCKS_AUTH_FAILED ((BYTE)0xff)
#define SOCKS_ADDR_IPV4 ((BYTE)1)
#define SOCKS_ADDR_DOMAINNAME ((BYTE)3)
#define SOCKS_ADDR_IPV6 ((BYTE)4)
///////////////////////////////////////////////////////////////////////////////
PSocksProtocol::PSocksProtocol(WORD port)
: serverHost("proxy")
{
serverPort = DefaultServerPort;
remotePort = port;
localPort = 0;
// get proxy information
PConfig config(PConfig::System, "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\");
// get the proxy configuration string
PString str = config.GetString("Internet Settings", "ProxyServer", "");
if (str.Find('=') == P_MAX_INDEX)
SetServer("socks");
else {
PStringArray tokens = str.Tokenise(";");
PINDEX i;
for (i = 0; i < tokens.GetSize(); i++) {
str = tokens[i];
PINDEX equalPos = str.Find('=');
if (equalPos != P_MAX_INDEX && (str.Left(equalPos) *= "socks")) {
SetServer(str.Mid(equalPos+1));
break;
}
}
}
}
BOOL PSocksProtocol::SetServer(const PString & hostname, const char * service)
{
return SetServer(hostname, PIPSocket::GetPortByService("tcp", service));
}
BOOL PSocksProtocol::SetServer(const PString & hostname, WORD port)
{
PINDEX colon = hostname.Find(':');
if (colon == P_MAX_INDEX)
serverHost = hostname;
else {
unsigned portnum = hostname.Mid(colon+1).AsUnsigned();
if (portnum == 0)
serverHost = hostname;
else {
serverHost = hostname.Left(colon);
port = (WORD)portnum;
}
}
if (port == 0)
port = DefaultServerPort;
serverPort = port;
return TRUE;
}
void PSocksProtocol::SetAuthentication(const PString & username, const PString & password)
{
PAssert(authenticationUsername.GetLength() < 256, PInvalidParameter);
authenticationUsername = username;
PAssert(authenticationPassword.GetLength() < 256, PInvalidParameter);
authenticationPassword = password;
}
BOOL PSocksProtocol::ConnectSocksServer(PTCPSocket & socket)
{
PIPSocket::Address ipnum;
if (!PIPSocket::GetHostAddress(serverHost, ipnum))
return FALSE;
remotePort = socket.GetPort();
socket.SetPort(serverPort);
return socket.PTCPSocket::Connect(0, ipnum);
}
BOOL PSocksProtocol::SendSocksCommand(PTCPSocket & socket,
BYTE command,
const char * hostname,
PIPSocket::Address addr)
{
if (!socket.IsOpen()) {
if (!ConnectSocksServer(socket))
return FALSE;
socket << SOCKS_VERSION_5
<< (authenticationUsername.IsEmpty() ? '\001' : '\002') // length
<< SOCKS_AUTH_NONE;
if (!authenticationUsername)
socket << SOCKS_AUTH_USER_PASS; // Simple cleartext username/password
socket.flush();
BYTE auth_pdu[2];
if (!socket.ReadBlock(auth_pdu, sizeof(auth_pdu))) // Should get 2 byte reply
return FALSE;
if (auth_pdu[0] != SOCKS_VERSION_5 || auth_pdu[1] == SOCKS_AUTH_FAILED) {
socket.Close();
SetErrorCodes(PChannel::AccessDenied, EACCES);
return FALSE;
}
if (auth_pdu[1] == SOCKS_AUTH_USER_PASS) {
// Send username and pasword
socket << '\x01'
<< (BYTE)authenticationUsername.GetLength() // Username length as single byte
<< authenticationUsername
<< (BYTE)authenticationPassword.GetLength() // Password length as single byte
<< authenticationPassword
<< ::flush;
if (!socket.ReadBlock(auth_pdu, sizeof(auth_pdu))) // Should get 2 byte reply
return FALSE;
if (/*auth_pdu[0] != SOCKS_VERSION_5 ||*/ auth_pdu[1] != 0) {
socket.Close();
SetErrorCodes(PChannel::AccessDenied, EACCES);
return FALSE;
}
}
}
socket << SOCKS_VERSION_5
<< command
<< '\000'; // Reserved
if (hostname != NULL)
socket << SOCKS_ADDR_DOMAINNAME << (BYTE)strlen(hostname) << hostname;
#if P_HAS_IPV6
else if ( addr.GetVersion() == 6 )
{
socket << SOCKS_ADDR_IPV6;
/* Should be 16 bytes */
for ( PINDEX i = 0; i < addr.GetSize(); i++ )
{
socket << addr[i];
}
}
#endif
else
socket << SOCKS_ADDR_IPV4
<< addr.Byte1() << addr.Byte2() << addr.Byte3() << addr.Byte4();
socket << (BYTE)(remotePort >> 8) << (BYTE)remotePort
<< ::flush;
return ReceiveSocksResponse(socket, localAddress, localPort);
}
BOOL PSocksProtocol::ReceiveSocksResponse(PTCPSocket & socket,
PIPSocket::Address & addr,
WORD & port)
{
int reply;
if ((reply = socket.ReadChar()) < 0)
return FALSE;
if (reply != SOCKS_VERSION_5) {
SetErrorCodes(PChannel::Miscellaneous, EINVAL);
return FALSE;
}
if ((reply = socket.ReadChar()) < 0)
return FALSE;
switch (reply) {
case 0 : // No error
break;
case 2 : // Refused permission
SetErrorCodes(PChannel::AccessDenied, EACCES);
return FALSE;
case 3 : // Network unreachable
SetErrorCodes(PChannel::NotFound, ENETUNREACH);
return FALSE;
case 4 : // Host unreachable
SetErrorCodes(PChannel::NotFound, EHOSTUNREACH);
return FALSE;
case 5 : // Connection refused
SetErrorCodes(PChannel::NotFound, EHOSTUNREACH);
return FALSE;
default :
SetErrorCodes(PChannel::Miscellaneous, EINVAL);
return FALSE;
}
// Ignore next byte (reserved)
if ((reply = socket.ReadChar()) < 0)
return FALSE;
// Get type byte for bound address
if ((reply = socket.ReadChar()) < 0)
return FALSE;
switch (reply) {
case SOCKS_ADDR_DOMAINNAME :
// Get length
if ((reply = socket.ReadChar()) < 0)
return FALSE;
if (!PIPSocket::GetHostAddress(socket.ReadString(reply), addr))
return FALSE;
break;
case SOCKS_ADDR_IPV4 :
{
in_addr add;
if (!socket.ReadBlock(&add, sizeof(add)))
return FALSE;
addr = add;
}
break;
#if P_HAS_IPV6
case SOCKS_ADDR_IPV6 :
{
in6_addr add;
if (!socket.ReadBlock(&add, sizeof(add)))
return FALSE;
addr = add;
}
break;
#endif
default :
SetErrorCodes(PChannel::Miscellaneous, EINVAL);
return FALSE;
}
WORD rxPort;
if (!socket.ReadBlock(&rxPort, sizeof(rxPort)))
return FALSE;
port = PSocket::Net2Host(rxPort);
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
PSocksSocket::PSocksSocket(WORD port)
: PSocksProtocol(port)
{
}
BOOL PSocksSocket::Connect(const PString & address)
{
if (!SendSocksCommand(*this, SOCKS_CMD_CONNECT, address, 0))
return FALSE;
port = remotePort;
return TRUE;
}
BOOL PSocksSocket::Connect(const Address & addr)
{
if (!SendSocksCommand(*this, SOCKS_CMD_CONNECT, NULL, addr))
return FALSE;
port = remotePort;
return TRUE;
}
BOOL PSocksSocket::Connect(WORD, const Address &)
{
PAssertAlways(PUnsupportedFeature);
return FALSE;
}
BOOL PSocksSocket::Listen(unsigned, WORD newPort, Reusability reuse)
{
PAssert(newPort == 0 && port == 0, PUnsupportedFeature);
PAssert(reuse, PUnsupportedFeature);
if (!SendSocksCommand(*this, SOCKS_CMD_BIND, NULL, 0))
return FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -