Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Net;
- using System.Net.Sockets;
- using System.Threading;
- namespace Server
- {
- public delegate void SocksClosedHandler(SOCKSclient sc);
- /// <summary>
- /// Various states, the socks client can be
- /// </summary>
- public enum SocksState
- {
- /// <summary>
- /// Connected, but version not yet determined (no traffic)
- /// </summary>
- VersionSelection,
- /// <summary>
- /// Destination not yet selected
- /// </summary>
- Destination,
- /// <summary>
- /// Destination selected and connection open
- /// </summary>
- Open,
- /// <summary>
- /// Socket closed
- /// </summary>
- Closed
- }
- public class SOCKSclient
- {
- #region BYTE_POS
- private const int P_NMETHODS = 1;
- private const int P_VER = 0;
- private const int P_METHODS = 2;
- private const int P_METHOD = 1;
- private const int P_CMD = 1;
- private const int P_RSV = 2;
- private const int P_ATYP = 3;
- private const int P_DNSLEN = 4;
- #endregion
- #region SOCKS4
- private const int S4_IP = 4;
- private const int S4_PORT = 2;
- private const int S4_CTYPE = 1;
- #endregion
- #region AUTH_METHODS
- private const byte M_NO_AUTH_REQUIRED = 0x00;
- private const byte M_GSSAPI = 0x01;
- private const byte M_USERNAME_PASSWORD = 0x02;
- private const byte M_NO_ACCEPTABLE_METHOD = 0xFF;
- #endregion
- #region CMD_TYPE
- private const byte CMD_TCP = 0x01;
- private const byte CMD_SRV = 0x02;
- private const byte CMD_UDP = 0x03;
- #endregion
- #region A_TYPE
- private const byte A_IP4 = 0x01;
- private const byte A_DNS = 0x03;
- private const byte A_IP6 = 0x04;
- #endregion
- #region CON_ANSWERS
- private const byte C_OK = 0;
- private const byte C_SOCKS_ERROR = 1;
- private const byte C_DENIED = 2;
- private const byte C_NET_UNREACHABLE = 3;
- private const byte C_HOST_UNREACHABLE = 4;
- private const byte C_REFUSED = 5;
- private const byte C_TTL_EXPIRED = 6;
- private const byte C_CMD_INVALID = 7;
- private const byte C_ATYP_INVALID = 8;
- #endregion
- private List<byte> LoginSelection;
- private EventSocket c;
- private EventSocket r;
- private Thread T;
- public event SocksClosedHandler SocksClosed;
- private SocksState Status;
- public SOCKSclient(EventSocket es)
- {
- SocksClosed += new SocksClosedHandler(SOCKSclient_SocksClosed);
- LoginSelection = new List<byte>();
- c = es;
- r = null;
- Status = SocksState.VersionSelection;
- c.DataReceived += new DataTransferredHandler(c_DataReceived);
- c.Disconnected += new DisconnectedHandler(c_Disconnected);
- }
- ~SOCKSclient()
- {
- Close();
- }
- void SOCKSclient_SocksClosed(SOCKSclient sc)
- {
- //NOOP EVENT
- }
- public void Close()
- {
- Status = SocksState.Closed;
- if (c != null)
- {
- c.Disconnect(true);
- c = null;
- }
- if (r != null)
- {
- r.Disconnect(true);
- r = null;
- }
- if (LoginSelection != null)
- {
- LoginSelection.Clear();
- LoginSelection = null;
- }
- if (T != null)
- {
- T.Join(2000);
- try
- {
- T.Abort();
- }
- catch
- {
- }
- }
- SocksClosed(this);
- }
- void c_Disconnected(IPEndPoint Remote)
- {
- Console.WriteLine("SOCKS: LDisconnected");
- Close();
- }
- void c_DataReceived(byte[] data)
- {
- switch (Status)
- {
- case SocksState.VersionSelection:
- LoginSelection.AddRange(data);
- if (LoginSelection.Count > 2)
- {
- switch(LoginSelection[P_VER])
- {
- case 5:
- if (LoginSelection.Count > 2)
- {
- if (LoginSelection.Count == 2 + LoginSelection[P_NMETHODS])
- {
- for (int i = 0; i < LoginSelection[P_NMETHODS]; i++)
- {
- if (LoginSelection[2 + i] == M_NO_AUTH_REQUIRED)
- {
- //Method ok, now in Destination select status
- c.send(new byte[] { 5, M_NO_AUTH_REQUIRED });
- LoginSelection.Clear();
- Status = SocksState.Destination;
- Console.WriteLine("Version 5 accepted");
- break;
- }
- }
- }
- else
- {
- c.send(new byte[] { 5, M_NO_ACCEPTABLE_METHOD });
- Console.WriteLine("unacceptable v5 auth");
- Close();
- }
- }
- break;
- case 4:
- //check for full data
- if (LoginSelection.Count == 9)
- {
- //Remove null terminator
- LoginSelection.RemoveAt(8);
- byte[] FullData = LoginSelection.ToArray();
- LoginSelection.Clear();
- try
- {
- r = new EventSocket(ExtractDest(4,FullData));
- Status = SocksState.Open;
- r.DataReceived += new DataTransferredHandler(r_DataReceived);
- r.Disconnected += new DisconnectedHandler(r_Disconnected);
- FullData[P_VER] = 0;
- FullData[S4_CTYPE] = 90;
- c.send(FullData);
- T = new Thread(new ThreadStart(checkCon));
- T.IsBackground = true;
- T.Start();
- Console.WriteLine("Version 4 accepted");
- }
- catch
- {
- Close();
- }
- }
- break;
- default:
- Console.WriteLine("Unknown version");
- Close();
- break;
- }
- }
- break;
- case SocksState.Destination:
- LoginSelection.AddRange(data);
- if (LoginSelection.Count > 7)
- {
- if (LoginSelection[P_CMD] == CMD_TCP)
- {
- //Check if IPv4 or DNS name
- if ((LoginSelection.Count == 10 && LoginSelection[P_ATYP] == A_IP4) || (LoginSelection[P_ATYP] == A_DNS && LoginSelection.Count == 7 + LoginSelection[P_DNSLEN]))
- {
- try
- {
- r = new EventSocket(ExtractDest(5, LoginSelection.ToArray()));
- Status = SocksState.Open;
- r.DataReceived += new DataTransferredHandler(r_DataReceived);
- r.Disconnected += new DisconnectedHandler(r_Disconnected);
- LoginSelection[P_CMD] = C_OK;
- c.send(LoginSelection.ToArray());
- T = new Thread(new ThreadStart(checkCon));
- T.IsBackground = true;
- T.Start();
- Console.WriteLine("Version 5 open");
- }
- catch
- {
- LoginSelection[P_CMD] = C_HOST_UNREACHABLE;
- c.send(LoginSelection.ToArray());
- Close();
- }
- }
- else
- {
- LoginSelection[P_CMD] = C_ATYP_INVALID;
- c.send(LoginSelection.ToArray());
- Close();
- }
- }
- else
- {
- LoginSelection[P_CMD] = C_CMD_INVALID;
- c.send(LoginSelection.ToArray());
- Close();
- }
- LoginSelection.Clear();
- }
- break;
- case SocksState.Open:
- try
- {
- r.send(data);
- }
- catch
- {
- Close();
- }
- break;
- case SocksState.Closed:
- Close();
- break;
- }
- }
- void r_Disconnected(IPEndPoint Remote)
- {
- Console.WriteLine("SOCKS: RDisconnected");
- Close();
- }
- void r_DataReceived(byte[] data)
- {
- Console.WriteLine("SOCKS: RDATA");
- c.send(data);
- }
- void checkCon()
- {
- while (c!=null && r!=null && c.IsConnected && r.IsConnected)
- {
- Thread.Sleep(500);
- }
- Close();
- }
- private IPEndPoint ExtractDest(int Version,byte[] Data)
- {
- switch (Version)
- {
- case 4:
- return new IPEndPoint(IPAddress.Parse(string.Format("{0}.{1}.{2}.{3}", Data[S4_IP], Data[S4_IP + 1], Data[S4_IP + 2], Data[S4_IP + 3])), Data[S4_PORT] * 256 + Data[S4_PORT + 1]);
- case 5:
- IPEndPoint tempEP = null;
- switch (Data[P_ATYP])
- {
- case 1:
- tempEP = new IPEndPoint(IPAddress.Parse(string.Format("{0}.{1}.{2}.{3}", Data[P_DNSLEN], Data[P_DNSLEN + 1], Data[P_DNSLEN + 2], Data[P_DNSLEN + 3])), Data[P_DNSLEN + 4] * 256 + Data[P_DNSLEN + 5]);
- break;
- case 3:
- byte[] DNSname = new byte[P_DNSLEN];
- Array.Copy(Data, P_DNSLEN + 1, DNSname, 0, Data[P_DNSLEN]);
- IPAddress[] ia = EventSocket.lookup(Encoding.ASCII.GetString(DNSname), true);
- if (ia != null)
- {
- return new IPEndPoint(ia[0], Data[Data.Length - 2] * 256 + Data[Data.Length - 1]);
- }
- else
- {
- Close();
- }
- break;
- case 4:
- //IPv6 not allowed
- break;
- }
- return tempEP;
- default:
- return null;
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement