Trunk_Proxy.patch

Patch made by Thomas Bruderer <[email protected]> - Mirco Bauer, 04/10/2009 01:30 PM

Download (80.6 KB)

 
IrcConnection/IrcConnection.cs (working copy)
7 7
 *
8 8
 * SmartIrc4net - the IRC library for .NET/C# <http://smartirc4net.sf.net>
9 9
 *
10
 * Copyright (c) 2003-2005 Mirco Bauer <[email protected]> <http://www.meebey.net>
10
 * Copyright (c) 2003-2009 Mirco Bauer <[email protected]> <http://www.meebey.net>
11
 * Copyright (c) 2008-2009 Thomas Bruderer <[email protected]>
11 12
 * 
12 13
 * Full LGPL License: <http://www.gnu.org/licenses/lgpl.txt>
13 14
 * 
......
33 34
using System.Threading;
34 35
using System.Reflection;
35 36
using System.Net.Sockets;
37
using System.Net;
38
using Org.Mentalis.Network.ProxySocket;
36 39
#if NET_2_0
37 40
using System.Net.Security;
38 41
#endif
......
78 81
        private DateTime         _LastPingSent;
79 82
        private DateTime         _LastPongReceived;
80 83
        private TimeSpan         _Lag;
84
        private IPEndPoint       _ProxyEndPoint;
85
        private ProxyTypes       _ProxyType = ProxyTypes.None;
86
        private string           _ProxyUser = "";
87
        private string           _ProxyPass = "";
81 88
        
82 89
        /// <event cref="OnReadLine">
83 90
        /// Raised when a \r\n terminated line is read from the socket
......
386 393
                return _Lag;
387 394
            }
388 395
        }
396
        
397
        /// <summary>
398
        /// If you want to use a Proxy, set the ProxyEndPoint to Adress and Port of the Proxy you want to use.
399
        /// </summary>
400
        public IPEndPoint ProxyEndPoint {
401
            get {
402
                return _ProxyEndPoint;
403
            }
404
            set {
405
                _ProxyEndPoint = value;
406
            }
407
        }
408
        
409
        /// <summary>
410
        /// Standard Setting is to use no Proxy Server, if you Set this to any other value, 
411
        /// you have to set the ProxyEndPoint aswell (and give credentials if needed)
412
        /// Default: Org.Mentalis.Network.ProxySocket.ProxyTypes.None
413
        /// </summary>
414
        public ProxyTypes ProxyType {
415
            get {
416
                
417
                return _ProxyType;
418
            }
419
            set {
420
                _ProxyType = value;
421
            }
422
        }
423
        
424
        /// <summary>
425
        /// Username to your Proxy Server
426
        /// </summary>
427
        public string ProxyUser {
428
            get {
429
                return _ProxyUser;
430
            }
431
            set {
432
                
433
                _ProxyUser = (value!=null)?value:"";
434
            }
435
        }
436
        
437
        /// <summary>
438
        /// Password to your Proxy Server
439
        /// </summary>
440
        public string ProxyPass {
441
            get {
442
                return _ProxyPass;
443
            }
444
            set {
445
                _ProxyPass = (value!=null)?value:"";
446
            }
447
        }
389 448

  
390 449
        /// <summary>
391 450
        /// Initializes the message queues, read and write thread
......
453 512
                OnConnecting(this, EventArgs.Empty);
454 513
            }
455 514
            try {
456
                System.Net.IPAddress ip = System.Net.Dns.Resolve(Address).AddressList[0];
457 515
                _TcpClient = new IrcTcpClient();
458 516
                _TcpClient.NoDelay = true;
517

  
518
                // Socks 4/5 Proxy
519
                ProxySocket socksProxy = new ProxySocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
520
                socksProxy.ProxyEndPoint = _ProxyEndPoint;
521
                socksProxy.ProxyType = _ProxyType;
522
                socksProxy.ProxyUser = _ProxyUser;
523
                socksProxy.ProxyPass = _ProxyPass;
524
                _TcpClient.Client = socksProxy;
525
                
526
                
459 527
                _TcpClient.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, 1);
460 528
                // set timeout, after this the connection will be aborted
461 529
                _TcpClient.ReceiveTimeout = _SocketReceiveTimeout * 1000;
462 530
                _TcpClient.SendTimeout = _SocketSendTimeout * 1000;
463
                _TcpClient.Connect(ip, port);
531
                if (_ProxyType != ProxyTypes.None) {
532
                    //TODO: use multiple ports too!
533
                    socksProxy.Connect(Address, port);
534
                } else {
535
                    // FIXME: this is not needed but should help merging the IPv6 changes! (just use always the if case!)
536
                    System.Net.IPAddress ip = System.Net.Dns.Resolve(Address).AddressList[0];
537
                    _TcpClient.Connect(ip, port);
538
                }
464 539
                
540
                
465 541
                Stream stream = _TcpClient.GetStream();
542

  
466 543
#if NET_2_0
467 544
                if (_UseSsl) {
468 545
                    SslStream sslStream = new SslStream(stream, false, delegate {
SocksProxy/AuthMethod.cs (revision 0)
1
/*
2
    Copyright � 2002, The KPD-Team
3
    All rights reserved.
4
    http://www.mentalis.org/
5

  
6
  Redistribution and use in source and binary forms, with or without
7
  modification, are permitted provided that the following conditions
8
  are met:
9

  
10
    - Redistributions of source code must retain the above copyright
11
       notice, this list of conditions and the following disclaimer. 
12

  
13
    - Neither the name of the KPD-Team, nor the names of its contributors
14
       may be used to endorse or promote products derived from this
15
       software without specific prior written permission. 
16

  
17
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
  THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
  OF THE POSSIBILITY OF SUCH DAMAGE.
29
*/
30

  
31
using System;
32
using System.Net;
33
using System.Net.Sockets;
34

  
35
namespace Org.Mentalis.Network.ProxySocket.Authentication {
36
	/// <summary>
37
	/// Implements a SOCKS authentication scheme.
38
	/// </summary>
39
	/// <remarks>This is an abstract class; it must be inherited.</remarks>
40
	internal abstract class AuthMethod {
41
		/// <summary>
42
		/// Initializes an AuthMethod instance.
43
		/// </summary>
44
		/// <param name="server">The socket connection with the proxy server.</param>
45
		public AuthMethod(Socket server) {
46
			Server = server;
47
		}
48
		/// <summary>
49
		/// Authenticates the user.
50
		/// </summary>
51
		/// <exception cref="ProxyException">Authentication with the proxy server failed.</exception>
52
		/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
53
		/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
54
		/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
55
		public abstract void Authenticate();
56
		/// <summary>
57
		/// Authenticates the user asynchronously.
58
		/// </summary>
59
		/// <param name="callback">The method to call when the authentication is complete.</param>
60
		/// <exception cref="ProxyException">Authentication with the proxy server failed.</exception>
61
		/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
62
		/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
63
		/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
64
		public abstract void BeginAuthenticate(HandShakeComplete callback);
65
		/// <summary>
66
		/// Gets or sets the socket connection with the proxy server.
67
		/// </summary>
68
		/// <value>The socket connection with the proxy server.</value>
69
		protected Socket Server {
70
			get {
71
				return m_Server;
72
			}
73
			set {
74
				if (value == null)
75
					throw new ArgumentNullException();
76
				m_Server = value;
77
			}
78
		}
79
		/// <summary>
80
		/// Gets or sets a byt array that can be used to store data.
81
		/// </summary>
82
		/// <value>A byte array to store data.</value>
83
		protected byte[] Buffer {
84
			get {
85
				return m_Buffer;
86
			}
87
			set {
88
				m_Buffer = value;
89
			}
90
		}
91
		/// <summary>
92
		/// Gets or sets the number of bytes that have been received from the remote proxy server.
93
		/// </summary>
94
		/// <value>An integer that holds the number of bytes that have been received from the remote proxy server.</value>
95
		protected int Received {
96
			get {
97
				return m_Received;
98
			}
99
			set {
100
				m_Received = value;
101
			}
102
		}
103
		// private variables
104
		/// <summary>Holds the value of the Buffer property.</summary>
105
		private byte[] m_Buffer;
106
		/// <summary>Holds the value of the Server property.</summary>
107
		private Socket m_Server;
108
		/// <summary>Holds the address of the method to call when the proxy has authenticated the client.</summary>
109
		protected HandShakeComplete CallBack;
110
		/// <summary>Holds the value of the Received property.</summary>
111
		private int m_Received;
112
	}
113
}
SocksProxy/AuthNone.cs (revision 0)
1
/*
2
    Copyright � 2002, The KPD-Team
3
    All rights reserved.
4
    http://www.mentalis.org/
5

  
6
  Redistribution and use in source and binary forms, with or without
7
  modification, are permitted provided that the following conditions
8
  are met:
9

  
10
    - Redistributions of source code must retain the above copyright
11
       notice, this list of conditions and the following disclaimer. 
12

  
13
    - Neither the name of the KPD-Team, nor the names of its contributors
14
       may be used to endorse or promote products derived from this
15
       software without specific prior written permission. 
16

  
17
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
  THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
  OF THE POSSIBILITY OF SUCH DAMAGE.
29
*/
30

  
31
using System;
32
using System.Net;
33
using System.Net.Sockets;
34

  
35
namespace Org.Mentalis.Network.ProxySocket.Authentication {
36
	/// <summary>
37
	/// This class implements the 'No Authentication' scheme.
38
	/// </summary>
39
	internal sealed class AuthNone : AuthMethod {
40
		/// <summary>
41
		/// Initializes an AuthNone instance.
42
		/// </summary>
43
		/// <param name="server">The socket connection with the proxy server.</param>
44
		public AuthNone(Socket server) : base(server) {}
45
		/// <summary>
46
		/// Authenticates the user.
47
		/// </summary>
48
		public override void Authenticate() {
49
			return; // Do Nothing
50
		}
51
		/// <summary>
52
		/// Authenticates the user asynchronously.
53
		/// </summary>
54
		/// <param name="callback">The method to call when the authentication is complete.</param>
55
		/// <remarks>This method immediately calls the callback method.</remarks>
56
		public override void BeginAuthenticate(HandShakeComplete callback) {
57
			callback(null);
58
		}
59
	}
60
}
SocksProxy/AuthUserPass.cs (revision 0)
1
/*
2
    Copyright � 2002, The KPD-Team
3
    All rights reserved.
4
    http://www.mentalis.org/
5

  
6
  Redistribution and use in source and binary forms, with or without
7
  modification, are permitted provided that the following conditions
8
  are met:
9

  
10
    - Redistributions of source code must retain the above copyright
11
       notice, this list of conditions and the following disclaimer. 
12

  
13
    - Neither the name of the KPD-Team, nor the names of its contributors
14
       may be used to endorse or promote products derived from this
15
       software without specific prior written permission. 
16

  
17
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
  THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
  OF THE POSSIBILITY OF SUCH DAMAGE.
29
*/
30

  
31
using System;
32
using System.Net;
33
using System.Net.Sockets;
34
using System.Text;
35

  
36
namespace Org.Mentalis.Network.ProxySocket.Authentication {
37
	/// <summary>
38
	/// This class implements the 'username/password authentication' scheme.
39
	/// </summary>
40
	internal sealed class AuthUserPass : AuthMethod {
41
		/// <summary>
42
		/// Initializes a new AuthUserPass instance.
43
		/// </summary>
44
		/// <param name="server">The socket connection with the proxy server.</param>
45
		/// <param name="user">The username to use.</param>
46
		/// <param name="pass">The password to use.</param>
47
		/// <exception cref="ArgumentNullException"><c>user</c> -or- <c>pass</c> is null.</exception>
48
		public AuthUserPass(Socket server, string user, string pass) : base(server) {
49
			Username = user;
50
			Password = pass;
51
		}
52
		/// <summary>
53
		/// Creates an array of bytes that has to be sent if the user wants to authenticate with the username/password authentication scheme.
54
		/// </summary>
55
		/// <returns>An array of bytes that has to be sent if the user wants to authenticate with the username/password authentication scheme.</returns>
56
		private byte[] GetAuthenticationBytes() {
57
			byte[] buffer = new byte[3 + Username.Length + Password.Length];
58
			buffer[0] = 1;
59
			buffer[1] = (byte)Username.Length;
60
			Array.Copy(Encoding.ASCII.GetBytes(Username), 0, buffer, 2, Username.Length);
61
			buffer[Username.Length + 2] = (byte)Password.Length;
62
			Array.Copy(Encoding.ASCII.GetBytes(Password), 0, buffer, Username.Length + 3, Password.Length);
63
			return buffer;
64
		}
65
		/// <summary>
66
		/// Starts the authentication process.
67
		/// </summary>
68
		public override void Authenticate() {
69
			Server.Send(GetAuthenticationBytes());
70
			byte[] buffer = new byte[2];
71
			int received = 0;
72
			while (received != 2) {
73
				received += Server.Receive(buffer, received, 2 - received, SocketFlags.None);
74
			}
75
			if (buffer[1] != 0) {
76
				Server.Close();
77
				throw new ProxyException("Username/password combination rejected.");
78
			}
79
			return;
80
		}
81
		/// <summary>
82
		/// Starts the asynchronous authentication process.
83
		/// </summary>
84
		/// <param name="callback">The method to call when the authentication is complete.</param>
85
		public override void BeginAuthenticate(HandShakeComplete callback) {
86
			CallBack = callback;
87
			Server.BeginSend(GetAuthenticationBytes(), 0, 3 + Username.Length + Password.Length, SocketFlags.None, new AsyncCallback(this.OnSent), Server);
88
			return;
89
		}
90
		/// <summary>
91
		/// Called when the authentication bytes have been sent.
92
		/// </summary>
93
		/// <param name="ar">Stores state information for this asynchronous operation as well as any user-defined data.</param>
94
		private void OnSent(IAsyncResult ar) {
95
			try {
96
				Server.EndSend(ar);
97
				Buffer = new byte[2];
98
				Server.BeginReceive(Buffer, 0, 2, SocketFlags.None, new AsyncCallback(this.OnReceive), Server);
99
			} catch (Exception e) {
100
				CallBack(e);
101
			}
102
		}
103
		/// <summary>
104
		/// Called when the socket received an authentication reply.
105
		/// </summary>
106
		/// <param name="ar">Stores state information for this asynchronous operation as well as any user-defined data.</param>
107
		private void OnReceive(IAsyncResult ar) {
108
			try {
109
				Received += Server.EndReceive(ar);
110
				if (Received == Buffer.Length)
111
					if (Buffer[1] == 0)
112
						CallBack(null);
113
					else
114
						throw new ProxyException("Username/password combination not accepted.");
115
				else
116
					Server.BeginReceive(Buffer, Received, Buffer.Length - Received, SocketFlags.None, new AsyncCallback(this.OnReceive), Server);
117
			} catch (Exception e) {
118
				CallBack(e);
119
			}
120
		}
121
		/// <summary>
122
		/// Gets or sets the username to use when authenticating with the proxy server.
123
		/// </summary>
124
		/// <value>The username to use when authenticating with the proxy server.</value>
125
		/// <exception cref="ArgumentNullException">The specified value is null.</exception>
126
		private string Username {
127
			get {
128
				return m_Username;
129
			}
130
			set {
131
				if (value == null)
132
					throw new ArgumentNullException();
133
				m_Username = value;
134
			}
135
		}
136
		/// <summary>
137
		/// Gets or sets the password to use when authenticating with the proxy server.
138
		/// </summary>
139
		/// <value>The password to use when authenticating with the proxy server.</value>
140
		/// <exception cref="ArgumentNullException">The specified value is null.</exception>
141
		private string Password {
142
			get {
143
				return m_Password;
144
			}
145
			set {
146
				if (value == null)
147
					throw new ArgumentNullException();
148
				m_Password = value;
149
			}
150
		}
151
		// private variables
152
		/// <summary>Holds the value of the Username property.</summary>
153
		private string m_Username;
154
		/// <summary>Holds the value of the Password property.</summary>
155
		private string m_Password;
156
	}
157
}
SocksProxy/IAsyncProxyResult.cs (revision 0)
1
/*
2
    Copyright � 2002, The KPD-Team
3
    All rights reserved.
4
    http://www.mentalis.org/
5

  
6
  Redistribution and use in source and binary forms, with or without
7
  modification, are permitted provided that the following conditions
8
  are met:
9

  
10
    - Redistributions of source code must retain the above copyright
11
       notice, this list of conditions and the following disclaimer. 
12

  
13
    - Neither the name of the KPD-Team, nor the names of its contributors
14
       may be used to endorse or promote products derived from this
15
       software without specific prior written permission. 
16

  
17
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
  THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
  OF THE POSSIBILITY OF SUCH DAMAGE.
29
*/
30

  
31
using System;
32
using System.Threading;
33

  
34
namespace Org.Mentalis.Network.ProxySocket {
35
	/// <summary>
36
	/// A class that implements the IAsyncResult interface. Objects from this class are returned by the BeginConnect method of the ProxySocket class.
37
	/// </summary>
38
	internal class IAsyncProxyResult : IAsyncResult {
39
		/// <summary>Initializes the internal variables of this object</summary>
40
		/// <param name="stateObject">An object that contains state information for this request.</param>
41
		internal void Init(object stateObject) {
42
			m_StateObject = stateObject;
43
			m_Completed = false;
44
			if (m_WaitHandle != null)
45
				m_WaitHandle.Reset();
46
		
47
		}
48
		/// <summary>Initializes the internal variables of this object</summary>
49
		internal void Reset() {
50
			m_StateObject = null;
51
			m_Completed = true;
52
			if (m_WaitHandle != null)
53
				m_WaitHandle.Set();
54
		}
55
		/// <summary>Gets a value that indicates whether the server has completed processing the call. It is illegal for the server to use any client supplied resources outside of the agreed upon sharing semantics after it sets the IsCompleted property to "true". Thus, it is safe for the client to destroy the resources after IsCompleted property returns "true".</summary>
56
		/// <value>A boolean that indicates whether the server has completed processing the call.</value>
57
		public bool IsCompleted {
58
			get {
59
				return m_Completed;
60
			}
61
		}
62
		/// <summary>Gets a value that indicates whether the BeginXXXX call has been completed synchronously. If this is detected in the AsyncCallback delegate, it is probable that the thread that called BeginInvoke is the current thread.</summary>
63
		/// <value>Returns false.</value>
64
		public bool CompletedSynchronously {
65
			get {
66
				return false;
67
			}
68
		}
69
		/// <summary>Gets an object that was passed as the state parameter of the BeginXXXX method call.</summary>
70
		/// <value>The object that was passed as the state parameter of the BeginXXXX method call.</value>
71
		public object AsyncState {
72
			get {
73
				return m_StateObject;
74
			}
75
		}
76
		/// <summary>
77
		/// The AsyncWaitHandle property returns the WaitHandle that can use to perform a WaitHandle.WaitOne or WaitAny or WaitAll. The object which implements IAsyncResult need not derive from the System.WaitHandle classes directly. The WaitHandle wraps its underlying synchronization primitive and should be signaled after the call is completed. This enables the client to wait for the call to complete instead polling. The Runtime supplies a number of waitable objects that mirror Win32 synchronization primitives e.g. ManualResetEvent, AutoResetEvent and Mutex.
78
		/// WaitHandle supplies methods that support waiting for such synchronization objects to become signaled with "any" or "all" semantics i.e. WaitHandle.WaitOne, WaitAny and WaitAll. Such methods are context aware to avoid deadlocks. The AsyncWaitHandle can be allocated eagerly or on demand. It is the choice of the IAsyncResult implementer.
79
		///</summary>
80
		/// <value>The WaitHandle associated with this asynchronous result.</value>
81
		public WaitHandle AsyncWaitHandle {
82
			get {
83
				if (m_WaitHandle == null)
84
					m_WaitHandle = new ManualResetEvent(false);
85
				return m_WaitHandle;
86
			}
87
		}
88
		// private variables
89
		/// <summary>Used internally to represent the state of the asynchronous request</summary>
90
		internal bool m_Completed = true;
91
		/// <summary>Holds the value of the StateObject property.</summary>
92
		private object m_StateObject;
93
		/// <summary>Holds the value of the WaitHandle property.</summary>
94
		private ManualResetEvent m_WaitHandle;
95
	}
96
}
SocksProxy/ProxyException.cs (revision 0)
1
/*
2
    Copyright � 2002, The KPD-Team
3
    All rights reserved.
4
    http://www.mentalis.org/
5

  
6
  Redistribution and use in source and binary forms, with or without
7
  modification, are permitted provided that the following conditions
8
  are met:
9

  
10
    - Redistributions of source code must retain the above copyright
11
       notice, this list of conditions and the following disclaimer. 
12

  
13
    - Neither the name of the KPD-Team, nor the names of its contributors
14
       may be used to endorse or promote products derived from this
15
       software without specific prior written permission. 
16

  
17
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
  THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
  OF THE POSSIBILITY OF SUCH DAMAGE.
29
*/
30

  
31
using System;
32

  
33
namespace Org.Mentalis.Network.ProxySocket {
34
	/// <summary>
35
	/// The exception that is thrown when a proxy error occurs.
36
	/// </summary>
37
	public class ProxyException : Exception {
38
		/// <summary>
39
		/// Initializes a new instance of the ProxyException class.
40
		/// </summary>
41
		public ProxyException() : this("An error occured while talking to the proxy server.") {}
42
		/// <summary>
43
		/// Initializes a new instance of the ProxyException class.
44
		/// </summary>
45
		/// <param name="message">The message that describes the error.</param>
46
		public ProxyException(string message) : base(message) {}
47
		/// <summary>
48
		/// Initializes a new instance of the ProxyException class.
49
		/// </summary>
50
		/// <param name="socks5Error">The error number returned by a SOCKS5 server.</param>
51
		public ProxyException(int socks5Error) : this(ProxyException.Socks5ToString(socks5Error)) {}
52
		/// <summary>
53
		/// Converts a SOCKS5 error number to a human readable string.
54
		/// </summary>
55
		/// <param name="socks5Error">The error number returned by a SOCKS5 server.</param>
56
		/// <returns>A string representation of the specified SOCKS5 error number.</returns>
57
		public static string Socks5ToString(int socks5Error) {
58
			switch(socks5Error) {
59
				case 0:
60
					return "Connection succeeded.";
61
				case 1:
62
					return "General SOCKS server failure.";
63
				case 2:
64
					return "Connection not allowed by ruleset.";
65
				case 3:
66
					return "Network unreachable.";
67
				case 4:
68
					return "Host unreachable.";
69
				case 5:
70
					return "Connection refused.";
71
				case 6:
72
					return "TTL expired.";
73
				case 7:
74
					return "Command not supported.";
75
				case 8:
76
					return "Address type not supported.";
77
				default:
78
					return "Unspecified SOCKS error.";
79
			}
80
		}
81
	}
82
}
SocksProxy/ProxySocket.cs (revision 0)
1
/*
2
    Copyright � 2002, The KPD-Team
3
    All rights reserved.
4
    http://www.mentalis.org/
5

  
6
  Redistribution and use in source and binary forms, with or without
7
  modification, are permitted provided that the following conditions
8
  are met:
9

  
10
    - Redistributions of source code must retain the above copyright
11
       notice, this list of conditions and the following disclaimer. 
12

  
13
    - Neither the name of the KPD-Team, nor the names of its contributors
14
       may be used to endorse or promote products derived from this
15
       software without specific prior written permission. 
16

  
17
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
  THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
  OF THE POSSIBILITY OF SUCH DAMAGE.
29
*/
30

  
31
using System;
32
using System.Net;
33
using System.Net.Sockets;
34

  
35
// Implements a number of classes to allow Sockets to connect trough a firewall.
36
namespace Org.Mentalis.Network.ProxySocket {
37
	/// <summary>
38
	/// Specifies the type of proxy servers that an instance of the ProxySocket class can use.
39
	/// </summary>
40
	public enum ProxyTypes {
41
		/// <summary>No proxy server; the ProxySocket object behaves exactly like an ordinary Socket object.</summary>
42
		None,
43
		/// <summary>A SOCKS4[A] proxy server.</summary>
44
		Socks4,
45
		/// <summary>A SOCKS5 proxy server.</summary>
46
		Socks5
47
	}
48
	/// <summary>
49
	/// Implements a Socket class that can connect trough a SOCKS proxy server.
50
	/// </summary>
51
	/// <remarks>This class implements SOCKS4[A] and SOCKS5.<br>It does not, however, implement the BIND commands, so you cannot .</br></remarks>
52
	public class ProxySocket : Socket {
53
		/// <summary>
54
		/// Initializes a new instance of the ProxySocket class.
55
		/// </summary>
56
		/// <param name="addressFamily">One of the AddressFamily values.</param>
57
		/// <param name="socketType">One of the SocketType values.</param>
58
		/// <param name="protocolType">One of the ProtocolType values.</param>
59
		/// <exception cref="SocketException">The combination of addressFamily, socketType, and protocolType results in an invalid socket.</exception>
60
		public ProxySocket (AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) : this(addressFamily, socketType, protocolType, "") {}
61
		/// <summary>
62
		/// Initializes a new instance of the ProxySocket class.
63
		/// </summary>
64
		/// <param name="addressFamily">One of the AddressFamily values.</param>
65
		/// <param name="socketType">One of the SocketType values.</param>
66
		/// <param name="protocolType">One of the ProtocolType values.</param>
67
		/// <param name="proxyUsername">The username to use when authenticating with the proxy server.</param>
68
		/// <exception cref="SocketException">The combination of addressFamily, socketType, and protocolType results in an invalid socket.</exception>
69
		/// <exception cref="ArgumentNullException"><c>proxyUsername</c> is null.</exception>
70
		public ProxySocket (AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, string proxyUsername) : this(addressFamily, socketType, protocolType, proxyUsername, "") {}
71
		/// <summary>
72
		/// Initializes a new instance of the ProxySocket class.
73
		/// </summary>
74
		/// <param name="addressFamily">One of the AddressFamily values.</param>
75
		/// <param name="socketType">One of the SocketType values.</param>
76
		/// <param name="protocolType">One of the ProtocolType values.</param>
77
		/// <param name="proxyUsername">The username to use when authenticating with the proxy server.</param>
78
		/// <param name="proxyPassword">The password to use when authenticating with the proxy server.</param>
79
		/// <exception cref="SocketException">The combination of addressFamily, socketType, and protocolType results in an invalid socket.</exception>
80
		/// <exception cref="ArgumentNullException"><c>proxyUsername</c> -or- <c>proxyPassword</c> is null.</exception>
81
		public ProxySocket (AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, string proxyUsername, string proxyPassword) : base(addressFamily, socketType, protocolType) {
82
			ProxyUser = proxyUsername;
83
			ProxyPass = proxyPassword;
84
			ToThrow = new InvalidOperationException();
85
		}
86
		/// <summary>
87
		/// Establishes a connection to a remote device.
88
		/// </summary>
89
		/// <param name="remoteEP">An EndPoint that represents the remote device.</param>
90
		/// <exception cref="ArgumentNullException">The remoteEP parameter is a null reference (Nothing in Visual Basic).</exception>
91
		/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
92
		/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
93
		/// <exception cref="ProxyException">An error occured while talking to the proxy server.</exception>
94
		public new void Connect(EndPoint remoteEP) {
95
			if (remoteEP == null)
96
				throw new ArgumentNullException("<remoteEP> cannot be null.");
97
			if (this.ProtocolType != ProtocolType.Tcp || ProxyType == ProxyTypes.None || ProxyEndPoint == null)
98
				base.Connect(remoteEP);
99
			else {
100
				base.Connect(ProxyEndPoint);
101
				if (ProxyType == ProxyTypes.Socks4)
102
					(new Socks4Handler(this, ProxyUser)).Negotiate((IPEndPoint)remoteEP);
103
				else if (ProxyType == ProxyTypes.Socks5)
104
					(new Socks5Handler(this, ProxyUser, ProxyPass)).Negotiate((IPEndPoint)remoteEP);
105
			}
106
		}
107
		/// <summary>
108
		/// Establishes a connection to a remote device.
109
		/// </summary>
110
		/// <param name="host">The remote host to connect to.</param>
111
		/// <param name="port">The remote port to connect to.</param>
112
		/// <exception cref="ArgumentNullException">The host parameter is a null reference (Nothing in Visual Basic).</exception>
113
		/// <exception cref="ArgumentException">The port parameter is invalid.</exception>
114
		/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
115
		/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
116
		/// <exception cref="ProxyException">An error occured while talking to the proxy server.</exception>
117
		/// <remarks>If you use this method with a SOCKS4 server, it will let the server resolve the hostname. Not all SOCKS4 servers support this 'remote DNS' though.</remarks>
118
		public void Connect(string host, int port) {
119
			if (host == null)
120
				throw new ArgumentNullException("<host> cannot be null.");
121
			if (port <= 0 || port > 65535)
122
				throw new ArgumentException("Invalid port.");
123
			if (this.ProtocolType != ProtocolType.Tcp || ProxyType == ProxyTypes.None || ProxyEndPoint == null)
124
				base.Connect(new IPEndPoint(Dns.Resolve(host).AddressList[0], port));
125
			else {
126
				base.Connect(ProxyEndPoint);
127
				if (ProxyType == ProxyTypes.Socks4)
128
					(new Socks4Handler(this, ProxyUser)).Negotiate(host, port);
129
				else if (ProxyType == ProxyTypes.Socks5)
130
					(new Socks5Handler(this, ProxyUser, ProxyPass)).Negotiate(host, port);
131
			}
132
		}
133
		/// <summary>
134
		/// Begins an asynchronous request for a connection to a network device.
135
		/// </summary>
136
		/// <param name="remoteEP">An EndPoint that represents the remote device.</param>
137
		/// <param name="callback">The AsyncCallback delegate.</param>
138
		/// <param name="state">An object that contains state information for this request.</param>
139
		/// <returns>An IAsyncResult that references the asynchronous connection.</returns>
140
		/// <exception cref="ArgumentNullException">The remoteEP parameter is a null reference (Nothing in Visual Basic).</exception>
141
		/// <exception cref="SocketException">An operating system error occurs while creating the Socket.</exception>
142
		/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
143
		public new IAsyncResult BeginConnect(EndPoint remoteEP, AsyncCallback callback, object state) {
144
			if (remoteEP == null || callback == null)
145
				throw new ArgumentNullException();
146
			if (this.ProtocolType != ProtocolType.Tcp || ProxyType == ProxyTypes.None || ProxyEndPoint == null) {
147
				return base.BeginConnect(remoteEP, callback, state);
148
			} else {
149
				CallBack = callback;
150
				if (ProxyType == ProxyTypes.Socks4) {
151
					AsyncResult = (new Socks4Handler(this, ProxyUser)).BeginNegotiate((IPEndPoint)remoteEP, new HandShakeComplete(this.OnHandShakeComplete), ProxyEndPoint);
152
					return AsyncResult;
153
				} else if(ProxyType == ProxyTypes.Socks5) {
154
					AsyncResult = (new Socks5Handler(this, ProxyUser, ProxyPass)).BeginNegotiate((IPEndPoint)remoteEP, new HandShakeComplete(this.OnHandShakeComplete), ProxyEndPoint);
155
					return AsyncResult;
156
				}
157
				return null;
158
			}
159
		}
160
		/// <summary>
161
		/// Begins an asynchronous request for a connection to a network device.
162
		/// </summary>
163
		/// <param name="host">The host to connect to.</param>
164
		/// <param name="port">The port on the remote host to connect to.</param>
165
		/// <param name="callback">The AsyncCallback delegate.</param>
166
		/// <param name="state">An object that contains state information for this request.</param>
167
		/// <returns>An IAsyncResult that references the asynchronous connection.</returns>
168
		/// <exception cref="ArgumentNullException">The host parameter is a null reference (Nothing in Visual Basic).</exception>
169
		/// <exception cref="ArgumentException">The port parameter is invalid.</exception>
170
		/// <exception cref="SocketException">An operating system error occurs while creating the Socket.</exception>
171
		/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
172
		public IAsyncResult BeginConnect(string host, int port, AsyncCallback callback, object state) {
173
			if (host == null || callback == null)
174
				throw new ArgumentNullException();
175
			if (port <= 0 || port >  65535)
176
				throw new ArgumentException();
177
			CallBack = callback;
178
			if (this.ProtocolType != ProtocolType.Tcp || ProxyType == ProxyTypes.None || ProxyEndPoint == null) {
179
				RemotePort = port;
180
				AsyncResult = BeginDns(host, new HandShakeComplete(this.OnHandShakeComplete));
181
				return AsyncResult;
182
			} else {
183
				if (ProxyType == ProxyTypes.Socks4) {
184
					AsyncResult = (new Socks4Handler(this, ProxyUser)).BeginNegotiate(host, port, new HandShakeComplete(this.OnHandShakeComplete), ProxyEndPoint);
185
					return AsyncResult;
186
				} else if(ProxyType == ProxyTypes.Socks5) {
187
					AsyncResult = (new Socks5Handler(this, ProxyUser, ProxyPass)).BeginNegotiate(host, port, new HandShakeComplete(this.OnHandShakeComplete), ProxyEndPoint);
188
					return AsyncResult;
189
				}
190
				return null;
191
			}
192
		}
193
		/// <summary>
194
		/// Ends a pending asynchronous connection request.
195
		/// </summary>
196
		/// <param name="asyncResult">Stores state information for this asynchronous operation as well as any user-defined data.</param>
197
		/// <exception cref="ArgumentNullException">The asyncResult parameter is a null reference (Nothing in Visual Basic).</exception>
198
		/// <exception cref="ArgumentException">The asyncResult parameter was not returned by a call to the BeginConnect method.</exception>
199
		/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
200
		/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
201
		/// <exception cref="InvalidOperationException">EndConnect was previously called for the asynchronous connection.</exception>
202
		/// <exception cref="ProxyException">The proxy server refused the connection.</exception>
203
		public new void EndConnect(IAsyncResult asyncResult) {
204
			if (asyncResult == null)
205
				throw new ArgumentNullException();
206
			if (!asyncResult.IsCompleted)
207
				throw new ArgumentException();
208
			if (ToThrow != null)
209
				throw ToThrow;
210
			return;
211
		}
212
		/// <summary>
213
		/// Begins an asynchronous request to resolve a DNS host name or IP address in dotted-quad notation to an IPAddress instance.
214
		/// </summary>
215
		/// <param name="host">The host to resolve.</param>
216
		/// <param name="callback">The method to call when the hostname has been resolved.</param>
217
		/// <returns>An IAsyncResult instance that references the asynchronous request.</returns>
218
		/// <exception cref="SocketException">There was an error while trying to resolve the host.</exception>
219
		internal IAsyncProxyResult BeginDns(string host, HandShakeComplete callback) {
220
			try {
221
				Dns.BeginResolve(host, new AsyncCallback(this.OnResolved), this);
222
				return new IAsyncProxyResult();
223
			} catch {
224
				throw new SocketException();
225
			}
226
		}
227
		/// <summary>
228
		/// Called when the specified hostname has been resolved.
229
		/// </summary>
230
		/// <param name="asyncResult">The result of the asynchronous operation.</param>
231
		private void OnResolved(IAsyncResult asyncResult) {
232
			try {
233
				IPHostEntry dns = Dns.EndResolve(asyncResult);
234
				base.BeginConnect(new IPEndPoint(dns.AddressList[0], RemotePort), new AsyncCallback(this.OnConnect), State);
235
			} catch (Exception e) {
236
				OnHandShakeComplete(e);
237
			}
238
		}
239
		/// <summary>
240
		/// Called when the Socket is connected to the remote host.
241
		/// </summary>
242
		/// <param name="asyncResult">The result of the asynchronous operation.</param>
243
		private void OnConnect(IAsyncResult asyncResult) {
244
			try {
245
				base.EndConnect(asyncResult);
246
				OnHandShakeComplete(null);
247
			} catch (Exception e) {
248
				OnHandShakeComplete(e);
249
			}
250
		}
251
		/// <summary>
252
		/// Called when the Socket has finished talking to the proxy server and is ready to relay data.
253
		/// </summary>
254
		/// <param name="error">The error to throw when the EndConnect method is called.</param>
255
		private void OnHandShakeComplete(Exception error) {
256
			if (error != null)
257
				this.Close();
258
			ToThrow = error;
259
			AsyncResult.Reset();
260
			if (CallBack != null)
261
				CallBack(AsyncResult);
262
		}
263
		/// <summary>
264
		/// Gets or sets the EndPoint of the proxy server.
265
		/// </summary>
266
		/// <value>An IPEndPoint object that holds the IP address and the port of the proxy server.</value>
267
		public IPEndPoint ProxyEndPoint {
268
			get {
269
				return m_ProxyEndPoint;
270
			}
271
			set {
272
				m_ProxyEndPoint = value;
273
			}
274
		}
275
		/// <summary>
276
		/// Gets or sets the type of proxy server to use.
277
		/// </summary>
278
		/// <value>One of the ProxyTypes values.</value>
279
		public ProxyTypes ProxyType {
280
			get {
281
				return m_ProxyType;
282
			}
283
			set {
284
				m_ProxyType = value;
285
			}
286
		}
287
		/// <summary>
288
		/// Gets or sets a user-defined object.
289
		/// </summary>
290
		/// <value>The user-defined object.</value>
291
		private object State {
292
			get {
293
				return m_State;
294
			}
295
			set {
296
				m_State = value;
297
			}
298
		}
299
		/// <summary>
300
		/// Gets or sets the username to use when authenticating with the proxy.
301
		/// </summary>
302
		/// <value>A string that holds the username that's used when authenticating with the proxy.</value>
303
		/// <exception cref="ArgumentNullException">The specified value is null.</exception>
304
		public string ProxyUser {
305
			get {
306
				return m_ProxyUser;
307
			}
308
			set {
309
				if (value == null)
310
					throw new ArgumentNullException();
311
				m_ProxyUser = value;
312
			}
313
		}
314
		/// <summary>
315
		/// Gets or sets the password to use when authenticating with the proxy.
316
		/// </summary>
317
		/// <value>A string that holds the password that's used when authenticating with the proxy.</value>
318
		/// <exception cref="ArgumentNullException">The specified value is null.</exception>
319
		public string ProxyPass {
320
			get {
321
				return m_ProxyPass;
322
			}
323
			set {
324
				if (value == null)
325
					throw new ArgumentNullException();
326
				m_ProxyPass = value;
327
			}
328
		}
329
		/// <summary>
330
		/// Gets or sets the asynchronous result object.
331
		/// </summary>
332
		/// <value>An instance of the IAsyncProxyResult class.</value>
333
		private IAsyncProxyResult AsyncResult {
334
			get {
335
				return m_AsyncResult;
336
			}
337
			set {
338
				m_AsyncResult = value;
339
			}
340
		}
341
		/// <summary>
342
		/// Gets or sets the exception to throw when the EndConnect method is called.
343
		/// </summary>
344
		/// <value>An instance of the Exception class (or subclasses of Exception).</value>
345
		private Exception ToThrow {
346
			get {
347
				return m_ToThrow;
348
			}
349
			set {
350
				m_ToThrow = value;
351
			}
352
		}
353
		/// <summary>
354
		/// Gets or sets the remote port the user wants to connect to.
355
		/// </summary>
356
		/// <value>An integer that specifies the port the user wants to connect to.</value>
357
		private int RemotePort {
358
			get {
359
				return m_RemotePort;
360
			}
361
			set {
362
				m_RemotePort = value;
363
			}
364
		}
365
		// private variables
366
		/// <summary>Holds the value of the State property.</summary>
367
		private object m_State;
368
		/// <summary>Holds the value of the ProxyEndPoint property.</summary>
369
		private IPEndPoint m_ProxyEndPoint = null;
370
		/// <summary>Holds the value of the ProxyType property.</summary>
371
		private ProxyTypes m_ProxyType = ProxyTypes.None;
372
		/// <summary>Holds the value of the ProxyUser property.</summary>
373
		private string m_ProxyUser = null;
374
		/// <summary>Holds the value of the ProxyPass property.</summary>
375
		private string m_ProxyPass = null;
376
		/// <summary>Holds a pointer to the method that should be called when the Socket is connected to the remote device.</summary>
377
		private AsyncCallback CallBack = null;
378
		/// <summary>Holds the value of the AsyncResult property.</summary>
379
		private IAsyncProxyResult m_AsyncResult;
380
		/// <summary>Holds the value of the ToThrow property.</summary>
381
		private Exception m_ToThrow = null;
382
		/// <summary>Holds the value of the RemotePort property.</summary>
383
		private int m_RemotePort;
384
	}
385
}
SocksProxy/Socks4Handler.cs (revision 0)
1
/*
2
    Copyright � 2002, The KPD-Team
3
    All rights reserved.
4
    http://www.mentalis.org/
5

  
6
  Redistribution and use in source and binary forms, with or without
7
  modification, are permitted provided that the following conditions
8
  are met:
9

  
10
    - Redistributions of source code must retain the above copyright
11
       notice, this list of conditions and the following disclaimer. 
12

  
13
    - Neither the name of the KPD-Team, nor the names of its contributors
14
       may be used to endorse or promote products derived from this
15
       software without specific prior written permission. 
16

  
17
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
  THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
  OF THE POSSIBILITY OF SUCH DAMAGE.
29
*/
30

  
31
using System;
32
using System.Net;
33
using System.Net.Sockets;
34
using System.Text;
35

  
36
namespace Org.Mentalis.Network.ProxySocket {
37
	/// <summary>
38
	/// Implements the SOCKS4[A] protocol.
39
	/// </summary>
40
	internal sealed class Socks4Handler : SocksHandler {
41
		/// <summary>
42
		/// Initilizes a new instance of the SocksHandler class.
43
		/// </summary>
44
		/// <param name="server">The socket connection with the proxy server.</param>
45
		/// <param name="user">The username to use when authenticating with the server.</param>
46
		/// <exception cref="ArgumentNullException"><c>server</c> -or- <c>user</c> is null.</exception>
47
		public Socks4Handler(Socket server, string user) : base(server, user) {}
48
		/// <summary>
49
		/// Creates an array of bytes that has to be sent when the user wants to connect to a specific host/port combination.
50
		/// </summary>
51
		/// <param name="host">The host to connect to.</param>
52
		/// <param name="port">The port to connect to.</param>
53
		/// <returns>An array of bytes that has to be sent when the user wants to connect to a specific host/port combination.</returns>
54
		/// <remarks>Resolving the host name will be done at server side. Do note that some SOCKS4 servers do not implement this functionality.</remarks>
55
		/// <exception cref="ArgumentNullException"><c>host</c> is null.</exception>
56
		/// <exception cref="ArgumentException"><c>port</c> is invalid.</exception>
57
		private byte[] GetHostPortBytes(string host, int port) {
58
			if (host == null)
59
				throw new ArgumentNullException();
60
			if (port <= 0 || port > 65535)
61
				throw new ArgumentException();
62
			byte [] connect = new byte[10 + Username.Length + host.Length];
63
			connect[0] = 4;
64
			connect[1] = 1;
65
			Array.Copy(PortToBytes(port), 0, connect, 2, 2);
66
			connect[4] = connect[5] = connect[6] = 0;
67
			connect[7] = 1;
68
			Array.Copy(Encoding.ASCII.GetBytes(Username), 0, connect, 8, Username.Length);
69
			connect[8 + Username.Length] = 0;
70
			Array.Copy(Encoding.ASCII.GetBytes(host), 0, connect, 9 + Username.Length, host.Length);
71
			connect[9 + Username.Length + host.Length] = 0;
72
			return connect;
73
		}
74
		/// <summary>
75
		/// Creates an array of bytes that has to be sent when the user wants to connect to a specific IPEndPoint.
76
		/// </summary>
77
		/// <param name="remoteEP">The IPEndPoint to connect to.</param>
78
		/// <returns>An array of bytes that has to be sent when the user wants to connect to a specific IPEndPoint.</returns>
79
		/// <exception cref="ArgumentNullException"><c>remoteEP</c> is null.</exception>
80
		private byte[] GetEndPointBytes(IPEndPoint remoteEP) {
81
			if (remoteEP == null)
82
				throw new ArgumentNullException();
83
			byte [] connect = new byte[9 + Username.Length];
84
			connect[0] = 4;
85
			connect[1] = 1;
86
			Array.Copy(PortToBytes(remoteEP.Port), 0, connect, 2, 2);
87
			Array.Copy(AddressToBytes(remoteEP.Address.Address), 0, connect, 4, 4);
88
			Array.Copy(Encoding.ASCII.GetBytes(Username), 0, connect, 8, Username.Length);
89
			connect[8 + Username.Length] = 0;
90
			return connect;
91
		}
92
		/// <summary>
93
		/// Starts negotiating with the SOCKS server.
94
		/// </summary>
95
		/// <param name="host">The host to connect to.</param>
96
		/// <param name="port">The port to connect to.</param>
97
		/// <exception cref="ArgumentNullException"><c>host</c> is null.</exception>
98
		/// <exception cref="ArgumentException"><c>port</c> is invalid.</exception>
99
		/// <exception cref="ProxyException">The proxy rejected the request.</exception>
100
		/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
101
		/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
102
		public override void Negotiate(string host, int port) {
103
			Negotiate(GetHostPortBytes(host, port));
104
		}
105
		/// <summary>
106
		/// Starts negotiating with the SOCKS server.
107
		/// </summary>
108
		/// <param name="remoteEP">The IPEndPoint to connect to.</param>
109
		/// <exception cref="ArgumentNullException"><c>remoteEP</c> is null.</exception>
110
		/// <exception cref="ProxyException">The proxy rejected the request.</exception>
111
		/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
112
		/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
113
		public override void Negotiate(IPEndPoint remoteEP) {
114
			Negotiate(GetEndPointBytes(remoteEP));
115
		}
116
		/// <summary>
117
		/// Starts negotiating with the SOCKS server.
118
		/// </summary>
119
		/// <param name="connect">The bytes to send when trying to authenticate.</param>
120
		/// <exception cref="ArgumentNullException"><c>connect</c> is null.</exception>
121
		/// <exception cref="ArgumentException"><c>connect</c> is too small.</exception>
122
		/// <exception cref="ProxyException">The proxy rejected the request.</exception>
123
		/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
124
		/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
125
		private void Negotiate(byte [] connect) {
126
			if (connect == null)
127
				throw new ArgumentNullException();
128
			if (connect.Length < 2)
129
				throw new ArgumentException();
130
			Server.Send(connect);
131
			byte [] buffer = ReadBytes(8);
132
			if (buffer[1] != 90) {
133
				Server.Close();
134
				throw new ProxyException("Negotiation failed.");	
135
			}
136
		}
137
		/// <summary>
138
		/// Starts negotiating asynchronously with a SOCKS proxy server.
139
		/// </summary>
140
		/// <param name="host">The remote server to connect to.</param>
141
		/// <param name="port">The remote port to connect to.</param>
142
		/// <param name="callback">The method to call when the connection has been established.</param>
143
		/// <param name="proxyEndPoint">The IPEndPoint of the SOCKS proxy server.</param>
144
		/// <returns>An IAsyncProxyResult that references the asynchronous connection.</returns>
145
		public override IAsyncProxyResult BeginNegotiate(string host, int port, HandShakeComplete callback, IPEndPoint proxyEndPoint) {
146
			ProtocolComplete = callback;
147
			Buffer = GetHostPortBytes(host, port);
148
			Server.BeginConnect(proxyEndPoint, new AsyncCallback(this.OnConnect), Server);
149
			AsyncResult = new IAsyncProxyResult();
150
			return AsyncResult;
151
		}
152
		/// <summary>
153
		/// Starts negotiating asynchronously with a SOCKS proxy server.
154
		/// </summary>
155
		/// <param name="remoteEP">An IPEndPoint that represents the remote device.</param>
156
		/// <param name="callback">The method to call when the connection has been established.</param>
157
		/// <param name="proxyEndPoint">The IPEndPoint of the SOCKS proxy server.</param>
158
		/// <returns>An IAsyncProxyResult that references the asynchronous connection.</returns>
159
		public override IAsyncProxyResult BeginNegotiate(IPEndPoint remoteEP, HandShakeComplete callback, IPEndPoint proxyEndPoint) {
160
			ProtocolComplete = callback;
161
			Buffer = GetEndPointBytes(remoteEP);
162
			Server.BeginConnect(proxyEndPoint, new AsyncCallback(this.OnConnect), Server);
163
			AsyncResult = new IAsyncProxyResult();
164
			return AsyncResult;
165
		}
166
		/// <summary>
167
		/// Called when the Socket is connected to the remote proxy server.
168
		/// </summary>
169
		/// <param name="ar">Stores state information for this asynchronous operation as well as any user-defined data.</param>
170
		private void OnConnect(IAsyncResult ar) {
171
			try {
172
				Server.EndConnect(ar);
173
			} catch (Exception e) {
174
				ProtocolComplete(e);
175
				return;
176
			}
177
			try {
178
				Server.BeginSend(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnSent), Server);
179
			} catch (Exception e) {
180
				ProtocolComplete(e);
181
			}
182
		}
183
		/// <summary>
184
		/// Called when the Socket has sent the handshake data.
185
		/// </summary>
186
		/// <param name="ar">Stores state information for this asynchronous operation as well as any user-defined data.</param>
187
		private void OnSent(IAsyncResult ar) {
188
			try {
189
				if (Server.EndSend(ar) < Buffer.Length) {
190
					ProtocolComplete(new SocketException());
191
					return;
192
				}
193
			} catch (Exception e) {
194
				ProtocolComplete(e);
195
				return;
196
			}
197
			try {
198
				Buffer = new byte[8];
199
				Received = 0;
200
				Server.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReceive), Server);
201
			} catch (Exception e) {
202
				ProtocolComplete(e);
203
			}
204
		}
205
		/// <summary>
206
		/// Called when the Socket has received a reply from the remote proxy server.
207
		/// </summary>
208
		/// <param name="ar">Stores state information for this asynchronous operation as well as any user-defined data.</param>
209
		private void OnReceive(IAsyncResult ar) {
210
			try {
211
				int received = Server.EndReceive(ar);
212
				if (received <= 0) {
213
					ProtocolComplete(new SocketException());
214
					return;
215
				}
216
				Received += received;
217
				if (Received == 8) {
218
					if (Buffer[1] == 90)
219
						ProtocolComplete(null);
220
					else {
221
						Server.Close();
222
						ProtocolComplete(new ProxyException("Negotiation failed."));
223
					}
224
				} else {
225
					Server.BeginReceive(Buffer, Received, Buffer.Length - Received, SocketFlags.None, new AsyncCallback(this.OnReceive), Server);
226
				}
227
			} catch (Exception e) {
228
				ProtocolComplete(e);
229
			}
230
		}
231
	}
232
}
233

  
234

  
SocksProxy/Socks5Handler.cs (revision 0)
1
/*
2
    Copyright � 2002, The KPD-Team
3
    All rights reserved.
4
    http://www.mentalis.org/
5

  
6
  Redistribution and use in source and binary forms, with or without
7
  modification, are permitted provided that the following conditions
8
  are met:
9

  
10
    - Redistributions of source code must retain the above copyright
11
       notice, this list of conditions and the following disclaimer. 
12

  
13
    - Neither the name of the KPD-Team, nor the names of its contributors
14
       may be used to endorse or promote products derived from this
15
       software without specific prior written permission. 
16

  
17
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
  THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
  OF THE POSSIBILITY OF SUCH DAMAGE.
29
*/
30

  
31
using System;
32
using System.Net;
33
using System.Net.Sockets;
34
using System.Text;
35
using Org.Mentalis.Network.ProxySocket.Authentication;
36

  
37
namespace Org.Mentalis.Network.ProxySocket {
38
	/// <summary>
39
	/// Implements the SOCKS5 protocol.
40
	/// </summary>
41
	internal sealed class Socks5Handler : SocksHandler {
42
		/// <summary>
43
		/// Initiliazes a new Socks5Handler instance.
44
		/// </summary>
45
		/// <param name="server">The socket connection with the proxy server.</param>
46
		/// <exception cref="ArgumentNullException"><c>server</c>  is null.</exception>
47
		public Socks5Handler(Socket server) : this(server, "") {}
48
		/// <summary>
49
		/// Initiliazes a new Socks5Handler instance.
50
		/// </summary>
51
		/// <param name="server">The socket connection with the proxy server.</param>
52
		/// <param name="user">The username to use.</param>
53
		/// <exception cref="ArgumentNullException"><c>server</c> -or- <c>user</c> is null.</exception>
54
		public Socks5Handler(Socket server, string user) : this(server, user, "") {}
55
		/// <summary>
56
		/// Initiliazes a new Socks5Handler instance.
57
		/// </summary>
58
		/// <param name="server">The socket connection with the proxy server.</param>
59
		/// <param name="user">The username to use.</param>
60
		/// <param name="pass">The password to use.</param>
61
		/// <exception cref="ArgumentNullException"><c>server</c> -or- <c>user</c> -or- <c>pass</c> is null.</exception>
62
		public Socks5Handler(Socket server, string user, string pass) : base(server, user) {
63
			Password = pass;
64
		}
65
		/// <summary>
66
		/// Starts the synchronous authentication process.
67
		/// </summary>
68
		/// <exception cref="ProxyException">Authentication with the proxy server failed.</exception>
69
		/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
70
		/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
71
		/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
72
		private void Authenticate() {
73
			Server.Send(new byte [] {5, 2, 0, 2});
74
			byte[] buffer = ReadBytes(2);
75
			if (buffer[1] == 255)
76
				throw new ProxyException("No authentication method accepted.");
77
			AuthMethod authenticate;
78
			switch (buffer[1]) {
79
				case 0:
80
					authenticate = new AuthNone(Server);
81
					break;
82
				case 2:
83
					authenticate = new AuthUserPass(Server, Username, Password);
84
					break;
85
				default:
86
					throw new ProtocolViolationException();
87
			}
88
			authenticate.Authenticate();
89
		}
90
		/// <summary>
91
		/// Creates an array of bytes that has to be sent when the user wants to connect to a specific host/port combination.
92
		/// </summary>
93
		/// <param name="host">The host to connect to.</param>
94
		/// <param name="port">The port to connect to.</param>
95
		/// <returns>An array of bytes that has to be sent when the user wants to connect to a specific host/port combination.</returns>
96
		/// <exception cref="ArgumentNullException"><c>host</c> is null.</exception>
97
		/// <exception cref="ArgumentException"><c>port</c> or <c>host</c> is invalid.</exception>
98
		private byte[] GetHostPortBytes(string host, int port) {
99
			if (host == null)
100
				throw new ArgumentNullException();
101
			if (port <= 0 || port > 65535 || host.Length > 255)
102
				throw new ArgumentException();
103
			byte [] connect = new byte[7 + host.Length];
104
			connect[0] = 5;
105
			connect[1] = 1;
106
			connect[2] = 0; //reserved
107
			connect[3] = 3;
108
			connect[4] = (byte)host.Length;
109
			Array.Copy(Encoding.ASCII.GetBytes(host), 0, connect, 5, host.Length);
110
			Array.Copy(PortToBytes(port), 0, connect, host.Length + 5, 2);
111
			return connect;
112
		}
113
		/// <summary>
114
		/// Creates an array of bytes that has to be sent when the user wants to connect to a specific IPEndPoint.
115
		/// </summary>
116
		/// <param name="remoteEP">The IPEndPoint to connect to.</param>
117
		/// <returns>An array of bytes that has to be sent when the user wants to connect to a specific IPEndPoint.</returns>
118
		/// <exception cref="ArgumentNullException"><c>remoteEP</c> is null.</exception>
119
		private byte[] GetEndPointBytes(IPEndPoint remoteEP) {
120
			if (remoteEP == null)
121
				throw new ArgumentNullException();
122
			byte [] connect = new byte[10];
123
			connect[0] = 5;
124
			connect[1] = 1;
125
			connect[2] = 0; //reserved
126
			connect[3] = 1;
127
			Array.Copy(AddressToBytes(remoteEP.Address.Address), 0, connect, 4, 4);
128
			Array.Copy(PortToBytes(remoteEP.Port), 0, connect, 8, 2);
129
			return connect;
130
		}
131
		/// <summary>
132
		/// Starts negotiating with the SOCKS server.
133
		/// </summary>
134
		/// <param name="host">The host to connect to.</param>
135
		/// <param name="port">The port to connect to.</param>
136
		/// <exception cref="ArgumentNullException"><c>host</c> is null.</exception>
137
		/// <exception cref="ArgumentException"><c>port</c> is invalid.</exception>
138
		/// <exception cref="ProxyException">The proxy rejected the request.</exception>
139
		/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
140
		/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
141
		/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
142
		public override void Negotiate(string host, int port) {
143
			Negotiate(GetHostPortBytes(host, port));
144
		}
145
		/// <summary>
146
		/// Starts negotiating with the SOCKS server.
147
		/// </summary>
148
		/// <param name="remoteEP">The IPEndPoint to connect to.</param>
149
		/// <exception cref="ArgumentNullException"><c>remoteEP</c> is null.</exception>
150
		/// <exception cref="ProxyException">The proxy rejected the request.</exception>
151
		/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
152
		/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
153
		/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
154
		public override void Negotiate(IPEndPoint remoteEP) {
155
			Negotiate(GetEndPointBytes(remoteEP));
156
		}
157
		/// <summary>
158
		/// Starts negotiating with the SOCKS server.
159
		/// </summary>
160
		/// <param name="connect">The bytes to send when trying to authenticate.</param>
161
		/// <exception cref="ArgumentNullException"><c>connect</c> is null.</exception>
162
		/// <exception cref="ArgumentException"><c>connect</c> is too small.</exception>
163
		/// <exception cref="ProxyException">The proxy rejected the request.</exception>
164
		/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
165
		/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
166
		/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
167
		private void Negotiate(byte[] connect) {
168
			Authenticate();
169
			Server.Send(connect);
170
			byte[] buffer = ReadBytes(4);
171
			if (buffer[1] != 0) {
172
				Server.Close();
173
				throw new ProxyException(buffer[1]);
174
			}
175
			switch(buffer[3]) {
176
				case 1:
177
					buffer = ReadBytes(6); //IPv4 address with port
178
					break;
179
				case 3:
180
					buffer = ReadBytes(1);
181
					buffer = ReadBytes(buffer[0] + 2); //domain name with port
182
					break;
183
				case 4:
184
					buffer = ReadBytes(18); //IPv6 address with port
185
					break;
186
				default:
187
					Server.Close();
188
					throw new ProtocolViolationException();
189
			}
190
		}
191
		/// <summary>
192
		/// Starts negotiating asynchronously with the SOCKS server. 
193
		/// </summary>
194
		/// <param name="host">The host to connect to.</param>
195
		/// <param name="port">The port to connect to.</param>
196
		/// <param name="callback">The method to call when the negotiation is complete.</param>
197
		/// <param name="proxyEndPoint">The IPEndPoint of the SOCKS proxy server.</param>
198
		/// <returns>An IAsyncProxyResult that references the asynchronous connection.</returns>
... This diff was truncated because it exceeds the maximum size that can be displayed.