Click here to Skip to main content
15,895,777 members
Articles / Programming Languages / C#

Internet Magic (Proxy Server) Windows Application

Rate me:
Please Sign up or sign in to vote.
3.00/5 (8 votes)
10 Apr 2010CPOL3 min read 68.7K   8.8K   38  
Windows application which creates a proxy server to share Internet over any TCP/IP network
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using internet_magic;

namespace internet_magic.Socks {

///<summary>Implements the SOCKS4 and SOCKS4a protocols.</summary>
internal sealed class Socks4Handler : SocksHandler {
	///<summary>Initializes a new instance of the Socks4Handler class.</summary>
	///<param name="ClientConnection">The connection with the client.</param>
	///<param name="Callback">The method to call when the SOCKS negotiation is complete.</param>
	///<exception cref="ArgumentNullException"><c>Callback</c> is null.</exception>
	public Socks4Handler(Socket ClientConnection, NegotiationCompleteDelegate Callback) : base(ClientConnection, Callback) {}
	///<summary>Checks whether a specific request is a valid SOCKS request or not.</summary>
	///<param name="Request">The request array to check.</param>
	///<returns>True is the specified request is valid, false otherwise</returns>
	protected override bool IsValidRequest(byte [] Request) {
		try {
			if (Request[0] != 1 && Request[0] != 2) { //CONNECT or BIND
				Dispose(false);
			} else {
				if (Request[3] == 0 && Request[4] == 0 && Request[5] == 0 && Request[6] != 0) { //Use remote DNS
					int Ret = Array.IndexOf(Request, (byte)0, 7);
					if (Ret > -1)
						return Array.IndexOf(Request, (byte)0, Ret + 1) != -1;
				} else {
					return Array.IndexOf(Request, (byte)0, 7) != -1;
				}
			}
		} catch {}
		return false;
	}
	///<summary>Processes a SOCKS request from a client.</summary>
	///<param name="Request">The request to process.</param>
	protected override void ProcessRequest(byte [] Request) {
		int Ret;
		try {
			if (Request[0] == 1) { // CONNECT
				IPAddress RemoteIP;
				int RemotePort = Request[1] * 256 + Request[2];
				Ret = Array.IndexOf(Request, (byte)0, 7);
				Username = Encoding.ASCII.GetString(Request, 7, Ret - 7);
				if (Request[3] == 0 && Request[4] == 0 && Request[5] == 0 && Request[6] != 0) {// Use remote DNS
					Ret = Array.IndexOf(Request, (byte)0, Ret + 1);
                    RemoteIP = Dns.GetHostEntry(Encoding.ASCII.GetString(Request, Username.Length + 8, Ret - Username.Length - 8)).AddressList[0];
				} else { //Do not use remote DNS
					RemoteIP = IPAddress.Parse(Request[3].ToString() + "." + Request[4].ToString() + "." + Request[5].ToString() + "." + Request[6].ToString());
				}
				RemoteConnection = new Socket(RemoteIP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
				RemoteConnection.BeginConnect(new IPEndPoint(RemoteIP, RemotePort), new AsyncCallback(this.OnConnected), RemoteConnection);
			} else if (Request[0] == 2) { // BIND
				byte [] Reply = new byte[8];
				long LocalIP = Listener.GetLocalExternalIP().Address;
				AcceptSocket = new Socket(IPAddress.Any.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
				AcceptSocket.Bind(new IPEndPoint(IPAddress.Any, 0));
				AcceptSocket.Listen(50);
				RemoteBindIP = IPAddress.Parse(Request[3].ToString() + "." + Request[4].ToString() + "." + Request[5].ToString() + "." + Request[6].ToString());
				Reply[0] = 0;  //Reply version 0
				Reply[1] = 90;  //Everything is ok :)
                Reply[2] = (byte)(Math.Floor((double)((IPEndPoint)AcceptSocket.LocalEndPoint).Port / 256));  //Port/1
				Reply[3] = (byte)(((IPEndPoint)AcceptSocket.LocalEndPoint).Port % 256);  //Port/2
                Reply[4] = (byte)(Math.Floor((double)(LocalIP % 256)));  //IP Address/1
                Reply[5] = (byte)(Math.Floor((double)(LocalIP % 65536) / 256));  //IP Address/2
                Reply[6] = (byte)(Math.Floor((double)(LocalIP % 16777216) / 65536));  //IP Address/3
                Reply[7] = (byte)(Math.Floor((double)LocalIP / 16777216));  //IP Address/4
				Connection.BeginSend(Reply, 0, Reply.Length, SocketFlags.None, new AsyncCallback(this.OnStartAccept), Connection);
			}
		} catch {
			Dispose(91);
		}
	}
	///<summary>Called when we're successfully connected to the remote host.</summary>
	///<param name="ar">The result of the asynchronous operation.</param>
	private void OnConnected(IAsyncResult ar) {
		try {
			RemoteConnection.EndConnect(ar);
			Dispose(90);
		} catch {
			Dispose(91);
		}
	}
	///<summary>Sends a reply to the client connection and disposes it afterwards.</summary>
	///<param name="Value">A byte that contains the reply code to send to the client.</param>
	protected override void Dispose(byte Value) {
		byte [] ToSend;
		try {
            ToSend = new byte[]{0, Value, (byte)(Math.Floor((double)((IPEndPoint)RemoteConnection.RemoteEndPoint).Port / 256)),
		                                   (byte)(((IPEndPoint)RemoteConnection.RemoteEndPoint).Port % 256),
		                                   (byte)(Math.Floor((double)(((IPEndPoint)RemoteConnection.RemoteEndPoint).Address.Address % 256))),
		                                   (byte)(Math.Floor((double)(((IPEndPoint)RemoteConnection.RemoteEndPoint).Address.Address % 65536) / 256)),
		                                   (byte)(Math.Floor((double)(((IPEndPoint)RemoteConnection.RemoteEndPoint).Address.Address % 16777216) / 65536)),
		                                   (byte)(Math.Floor((double)((IPEndPoint)RemoteConnection.RemoteEndPoint).Address.Address / 16777216))};
		} catch {
			ToSend = new byte[]{0, 91, 0, 0, 0, 0, 0, 0};
		}
		try {
			Connection.BeginSend(ToSend, 0, ToSend.Length, SocketFlags.None, (AsyncCallback)(ToSend[1] == 90 ? new AsyncCallback(this.OnDisposeGood) : new AsyncCallback(this.OnDisposeBad)), Connection);
		} catch {
			Dispose(false);
		}
	}
	///<summary>Called when there's an incoming connection in the AcceptSocket queue.</summary>
	///<param name="ar">The result of the asynchronous operation.</param>
	protected override void OnAccept(IAsyncResult ar) {
		try {
			RemoteConnection = AcceptSocket.EndAccept(ar);
			AcceptSocket.Close();
			AcceptSocket = null;
			if (RemoteBindIP.Equals(((IPEndPoint)RemoteConnection.RemoteEndPoint).Address))
				Dispose(90);
			else
				Dispose(91);
		} catch {
			Dispose(91);
		}
	}
}

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions