6 * Portable Windows Library
8 * Copyright (c) 1993-2002 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
25 * Revision 1.8 2003/09/08 01:42:48 dereksmithies
26 * Add patch from Diego Tartara <dtartara@mens2.hq.novamens.com>. Many Thanks!
28 * Revision 1.7 2002/11/06 22:47:25 robertj
29 * Fixed header comment (copyright etc)
31 * Revision 1.6 2002/08/05 05:40:45 robertj
32 * Fixed missing pragma interface/implementation
34 * Revision 1.5 2001/09/10 02:51:23 robertj
35 * Major change to fix problem with error codes being corrupted in a
36 * PChannel when have simultaneous reads and writes in threads.
38 * Revision 1.4 1999/11/23 08:45:10 robertj
39 * Fixed bug in user/pass authentication version, thanks Dmitry <dipa@linkline.com>
41 * Revision 1.3 1999/02/16 08:08:06 robertj
42 * MSVC 6.0 compatibility changes.
44 * Revision 1.2 1998/12/23 00:35:28 robertj
47 * Revision 1.1 1998/12/22 10:30:24 robertj
55 #pragma implementation "socks.h"
58 #include <ptclib/socks.h>
62 #define SOCKS_VERSION_4 ((BYTE)4)
63 #define SOCKS_VERSION_5 ((BYTE)5)
65 #define SOCKS_CMD_CONNECT ((BYTE)1)
66 #define SOCKS_CMD_BIND ((BYTE)2)
67 #define SOCKS_CMD_UDP_ASSOCIATE ((BYTE)3)
69 #define SOCKS_AUTH_NONE ((BYTE)0)
70 #define SOCKS_AUTH_USER_PASS ((BYTE)2)
71 #define SOCKS_AUTH_FAILED ((BYTE)0xff)
73 #define SOCKS_ADDR_IPV4 ((BYTE)1)
74 #define SOCKS_ADDR_DOMAINNAME ((BYTE)3)
75 #define SOCKS_ADDR_IPV6 ((BYTE)4)
78 ///////////////////////////////////////////////////////////////////////////////
80 PSocksProtocol::PSocksProtocol(WORD port
)
83 serverPort
= DefaultServerPort
;
87 // get proxy information
88 PConfig
config(PConfig::System
, "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\");
90 // get the proxy configuration string
91 PString str
= config
.GetString("Internet Settings", "ProxyServer", "");
92 if (str
.Find('=') == P_MAX_INDEX
)
95 PStringArray tokens
= str
.Tokenise(";");
97 for (i
= 0; i
< tokens
.GetSize(); i
++) {
99 PINDEX equalPos
= str
.Find('=');
100 if (equalPos
!= P_MAX_INDEX
&& (str
.Left(equalPos
) *= "socks")) {
101 SetServer(str
.Mid(equalPos
+1));
109 BOOL
PSocksProtocol::SetServer(const PString
& hostname
, const char * service
)
111 return SetServer(hostname
, PIPSocket::GetPortByService("tcp", service
));
115 BOOL
PSocksProtocol::SetServer(const PString
& hostname
, WORD port
)
117 PINDEX colon
= hostname
.Find(':');
118 if (colon
== P_MAX_INDEX
)
119 serverHost
= hostname
;
121 unsigned portnum
= hostname
.Mid(colon
+1).AsUnsigned();
123 serverHost
= hostname
;
125 serverHost
= hostname
.Left(colon
);
126 port
= (WORD
)portnum
;
131 port
= DefaultServerPort
;
139 void PSocksProtocol::SetAuthentication(const PString
& username
, const PString
& password
)
141 PAssert(authenticationUsername
.GetLength() < 256, PInvalidParameter
);
142 authenticationUsername
= username
;
143 PAssert(authenticationPassword
.GetLength() < 256, PInvalidParameter
);
144 authenticationPassword
= password
;
148 BOOL
PSocksProtocol::ConnectSocksServer(PTCPSocket
& socket
)
150 PIPSocket::Address ipnum
;
151 if (!PIPSocket::GetHostAddress(serverHost
, ipnum
))
154 remotePort
= socket
.GetPort();
155 socket
.SetPort(serverPort
);
156 return socket
.PTCPSocket::Connect(0, ipnum
);
160 BOOL
PSocksProtocol::SendSocksCommand(PTCPSocket
& socket
,
162 const char * hostname
,
163 PIPSocket::Address addr
)
165 if (!socket
.IsOpen()) {
166 if (!ConnectSocksServer(socket
))
169 socket
<< SOCKS_VERSION_5
170 << (authenticationUsername
.IsEmpty() ? '\001' : '\002') // length
172 if (!authenticationUsername
)
173 socket
<< SOCKS_AUTH_USER_PASS
; // Simple cleartext username/password
177 if (!socket
.ReadBlock(auth_pdu
, sizeof(auth_pdu
))) // Should get 2 byte reply
180 if (auth_pdu
[0] != SOCKS_VERSION_5
|| auth_pdu
[1] == SOCKS_AUTH_FAILED
) {
182 SetErrorCodes(PChannel::AccessDenied
, EACCES
);
186 if (auth_pdu
[1] == SOCKS_AUTH_USER_PASS
) {
187 // Send username and pasword
189 << (BYTE
)authenticationUsername
.GetLength() // Username length as single byte
190 << authenticationUsername
191 << (BYTE
)authenticationPassword
.GetLength() // Password length as single byte
192 << authenticationPassword
195 if (!socket
.ReadBlock(auth_pdu
, sizeof(auth_pdu
))) // Should get 2 byte reply
198 if (/*auth_pdu[0] != SOCKS_VERSION_5 ||*/ auth_pdu
[1] != 0) {
200 SetErrorCodes(PChannel::AccessDenied
, EACCES
);
206 socket
<< SOCKS_VERSION_5
208 << '\000'; // Reserved
209 if (hostname
!= NULL
)
210 socket
<< SOCKS_ADDR_DOMAINNAME
<< (BYTE
)strlen(hostname
) << hostname
;
212 else if ( addr
.GetVersion() == 6 )
214 socket
<< SOCKS_ADDR_IPV6
;
215 /* Should be 16 bytes */
216 for ( PINDEX i
= 0; i
< addr
.GetSize(); i
++ )
223 socket
<< SOCKS_ADDR_IPV4
224 << addr
.Byte1() << addr
.Byte2() << addr
.Byte3() << addr
.Byte4();
226 socket
<< (BYTE
)(remotePort
>> 8) << (BYTE
)remotePort
229 return ReceiveSocksResponse(socket
, localAddress
, localPort
);
233 BOOL
PSocksProtocol::ReceiveSocksResponse(PTCPSocket
& socket
,
234 PIPSocket::Address
& addr
,
238 if ((reply
= socket
.ReadChar()) < 0)
241 if (reply
!= SOCKS_VERSION_5
) {
242 SetErrorCodes(PChannel::Miscellaneous
, EINVAL
);
246 if ((reply
= socket
.ReadChar()) < 0)
253 case 2 : // Refused permission
254 SetErrorCodes(PChannel::AccessDenied
, EACCES
);
257 case 3 : // Network unreachable
258 SetErrorCodes(PChannel::NotFound
, ENETUNREACH
);
261 case 4 : // Host unreachable
262 SetErrorCodes(PChannel::NotFound
, EHOSTUNREACH
);
265 case 5 : // Connection refused
266 SetErrorCodes(PChannel::NotFound
, EHOSTUNREACH
);
270 SetErrorCodes(PChannel::Miscellaneous
, EINVAL
);
274 // Ignore next byte (reserved)
275 if ((reply
= socket
.ReadChar()) < 0)
278 // Get type byte for bound address
279 if ((reply
= socket
.ReadChar()) < 0)
283 case SOCKS_ADDR_DOMAINNAME
:
285 if ((reply
= socket
.ReadChar()) < 0)
288 if (!PIPSocket::GetHostAddress(socket
.ReadString(reply
), addr
))
292 case SOCKS_ADDR_IPV4
:
295 if (!socket
.ReadBlock(&add
, sizeof(add
)))
302 case SOCKS_ADDR_IPV6
:
305 if (!socket
.ReadBlock(&add
, sizeof(add
)))
313 SetErrorCodes(PChannel::Miscellaneous
, EINVAL
);
318 if (!socket
.ReadBlock(&rxPort
, sizeof(rxPort
)))
321 port
= PSocket::Net2Host(rxPort
);
326 ///////////////////////////////////////////////////////////////////////////////
328 PSocksSocket::PSocksSocket(WORD port
)
329 : PSocksProtocol(port
)
334 BOOL
PSocksSocket::Connect(const PString
& address
)
336 if (!SendSocksCommand(*this, SOCKS_CMD_CONNECT
, address
, 0))
344 BOOL
PSocksSocket::Connect(const Address
& addr
)
346 if (!SendSocksCommand(*this, SOCKS_CMD_CONNECT
, NULL
, addr
))
354 BOOL
PSocksSocket::Connect(WORD
, const Address
&)
356 PAssertAlways(PUnsupportedFeature
);
361 BOOL
PSocksSocket::Listen(unsigned, WORD newPort
, Reusability reuse
)
363 PAssert(newPort
== 0 && port
== 0, PUnsupportedFeature
);
364 PAssert(reuse
, PUnsupportedFeature
);
366 if (!SendSocksCommand(*this, SOCKS_CMD_BIND
, NULL
, 0))
374 BOOL
PSocksSocket::Accept()
379 return ReceiveSocksResponse(*this, remoteAddress
, remotePort
);
383 BOOL
PSocksSocket::Accept(PSocket
& socket
)
385 // If is right class, transfer the SOCKS socket to class to receive the accept
386 // The "listener" socket is implicitly closed as there is really only one
387 // handle in a SOCKS BIND operation.
388 PAssert(socket
.IsDescendant(PSocksSocket::Class()), PUnsupportedFeature
);
389 os_handle
= ((PSocksSocket
&)socket
).TransferHandle(*this);
394 int PSocksSocket::TransferHandle(PSocksSocket
& destination
)
396 // This "transfers" the socket from one onstance to another.
398 int the_handle
= os_handle
;
399 destination
.SetReadTimeout(readTimeout
);
400 destination
.SetWriteTimeout(writeTimeout
);
402 // Close the instance of the socket but don't actually close handle.
409 BOOL
PSocksSocket::GetLocalAddress(Address
& addr
)
419 BOOL
PSocksSocket::GetLocalAddress(Address
& addr
, WORD
& port
)
430 BOOL
PSocksSocket::GetPeerAddress(Address
& addr
)
435 addr
= remoteAddress
;
440 BOOL
PSocksSocket::GetPeerAddress(Address
& addr
, WORD
& port
)
445 addr
= remoteAddress
;
451 void PSocksSocket::SetErrorCodes(PChannel::Errors errCode
, int osErr
)
453 SetErrorValues(errCode
, osErr
);
457 ///////////////////////////////////////////////////////////////////////////////
459 PSocks4Socket::PSocks4Socket(WORD port
)
465 PSocks4Socket::PSocks4Socket(const PString
& host
, WORD port
)
472 PObject
* PSocks4Socket::Clone() const
474 return new PSocks4Socket(remotePort
);
478 BOOL
PSocks4Socket::SendSocksCommand(PTCPSocket
& socket
,
480 const char * hostname
,
483 if (hostname
!= NULL
) {
484 if (!GetHostAddress(hostname
, addr
))
489 if (!ConnectSocksServer(*this))
493 PString user
= PProcess::Current().GetUserName();
494 socket
<< SOCKS_VERSION_4
496 << (BYTE
)(remotePort
>> 8) << (BYTE
)remotePort
497 << addr
.Byte1() << addr
.Byte2() << addr
.Byte3() << addr
.Byte4()
501 return ReceiveSocksResponse(socket
, localAddress
, localPort
);
505 BOOL
PSocks4Socket::ReceiveSocksResponse(PTCPSocket
& socket
,
510 if ((reply
= socket
.ReadChar()) < 0)
513 if (reply
!= 0 /*!= SOCKS_VERSION_4*/) {
514 SetErrorCodes(PChannel::Miscellaneous
, EINVAL
);
518 if ((reply
= socket
.ReadChar()) < 0)
522 case 90 : // No error
525 case 91 : // Connection refused
526 SetErrorCodes(PChannel::NotFound
, EHOSTUNREACH
);
529 case 92 : // Refused permission
530 SetErrorCodes(PChannel::AccessDenied
, EACCES
);
534 SetErrorCodes(PChannel::Miscellaneous
, EINVAL
);
539 if (!socket
.ReadBlock(&rxPort
, sizeof(rxPort
)))
542 port
= PSocket::Net2Host(rxPort
);
545 if ( socket
.ReadBlock(&add
, sizeof(add
)) )
555 ///////////////////////////////////////////////////////////////////////////////
557 PSocks5Socket::PSocks5Socket(WORD port
)
563 PSocks5Socket::PSocks5Socket(const PString
& host
, WORD port
)
570 PObject
* PSocks5Socket::Clone() const
572 return new PSocks5Socket(remotePort
);
576 ///////////////////////////////////////////////////////////////////////////////
578 PSocksUDPSocket::PSocksUDPSocket(WORD port
)
579 : PSocksProtocol(port
)
584 PSocksUDPSocket::PSocksUDPSocket(const PString
& host
, WORD port
)
585 : PSocksProtocol(port
)
591 PObject
* PSocksUDPSocket::Clone() const
593 return new PSocksUDPSocket(port
);
597 BOOL
PSocksUDPSocket::Connect(const PString
& address
)
599 if (!SendSocksCommand(socksControl
, SOCKS_CMD_UDP_ASSOCIATE
, address
, 0))
602 socksControl
.GetPeerAddress(serverAddress
);
607 BOOL
PSocksUDPSocket::Connect(const Address
& addr
)
609 if (!SendSocksCommand(socksControl
, SOCKS_CMD_UDP_ASSOCIATE
, NULL
, addr
))
612 socksControl
.GetPeerAddress(serverAddress
);
617 BOOL
PSocksUDPSocket::Connect(WORD
, const Address
&)
619 PAssertAlways(PUnsupportedFeature
);
624 BOOL
PSocksUDPSocket::Listen(unsigned, WORD newPort
, Reusability reuse
)
626 PAssert(newPort
== 0 && port
== 0, PUnsupportedFeature
);
627 PAssert(reuse
, PUnsupportedFeature
);
629 if (!SendSocksCommand(socksControl
, SOCKS_CMD_UDP_ASSOCIATE
, NULL
, 0))
632 socksControl
.GetPeerAddress(serverAddress
);
638 BOOL
PSocksUDPSocket::GetLocalAddress(Address
& addr
)
648 BOOL
PSocksUDPSocket::GetLocalAddress(Address
& addr
, WORD
& port
)
659 BOOL
PSocksUDPSocket::GetPeerAddress(Address
& addr
)
664 addr
= remoteAddress
;
669 BOOL
PSocksUDPSocket::GetPeerAddress(Address
& addr
, WORD
& port
)
674 addr
= remoteAddress
;
680 BOOL
PSocksUDPSocket::ReadFrom(void * buf
, PINDEX len
, Address
& addr
, WORD
& port
)
682 PBYTEArray
newbuf(len
+262);
685 if (!PUDPSocket::ReadFrom(newbuf
.GetPointer(), newbuf
.GetSize(), rx_addr
, rx_port
))
688 if (rx_addr
!= serverAddress
|| rx_port
!= serverPort
)
693 case SOCKS_ADDR_DOMAINNAME
:
694 if (!PIPSocket::GetHostAddress(PString((const char *)&newbuf
[5], (PINDEX
)newbuf
[4]), addr
))
697 port_pos
= newbuf
[4]+5;
700 case SOCKS_ADDR_IPV4
:
701 memcpy(&addr
, &newbuf
[4], 4);
706 SetErrorCodes(PChannel::Miscellaneous
, EINVAL
);
710 port
= (WORD
)((newbuf
[port_pos
] << 8)|newbuf
[port_pos
+1]);
711 memcpy(buf
, &newbuf
[port_pos
+2], len
);
717 BOOL
PSocksUDPSocket::WriteTo(const void * buf
, PINDEX len
, const Address
& addr
, WORD port
)
719 PBYTEArray
newbuf(len
+10);
720 BYTE
* bufptr
= newbuf
.GetPointer();
722 // Build header, bytes 0, 1 & 2 are zero
724 bufptr
[3] = SOCKS_ADDR_IPV4
;
725 memcpy(bufptr
+4, &addr
, 4);
726 bufptr
[8] = (BYTE
)(port
>> 8);
727 bufptr
[9] = (BYTE
)port
;
728 memcpy(bufptr
+10, buf
, len
);
730 return PUDPSocket::WriteTo(newbuf
, newbuf
.GetSize(), serverAddress
, serverPort
);
734 void PSocksUDPSocket::SetErrorCodes(PChannel::Errors errCode
, int osErr
)
736 SetErrorValues(errCode
, osErr
);
740 // End of File ///////////////////////////////////////////////////////////////