Initial commit
This commit is contained in:
commit
5584446828
37 changed files with 7962 additions and 0 deletions
52
Proxies/HTTPProxyProtocol.cs
Normal file
52
Proxies/HTTPProxyProtocol.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Secucore
|
||||
*
|
||||
* Copyright (C) 2023 Trevor Hall
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software may be modified and distributed under the terms
|
||||
* of the MIT license.
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SecuCore.Proxies
|
||||
{
|
||||
|
||||
public class HTTPProxyProtocol : IProxyProtocol
|
||||
{
|
||||
private const string httpConnectHostPort = "CONNECT {0}:{1} HTTP/1.1\r\n\r\n";
|
||||
private const string httpConnectHostPortAuth = "CONNECT {0}:{1} HTTP/1.1\r\nProxy-Authorization: Basic {2}\r\n\r\n";
|
||||
private static string CreateHTTPConnectHeaders(string destHost, int destport, string proxyUsername, string proxyPassword)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(proxyUsername) && !string.IsNullOrEmpty(proxyPassword))
|
||||
{
|
||||
//auth
|
||||
string b64 = Convert.ToBase64String(Encoding.ASCII.GetBytes(proxyUsername + ":" + proxyPassword));
|
||||
return string.Format(httpConnectHostPortAuth, destHost, destport, b64);
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Format(httpConnectHostPort, destHost, destport);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<bool> ConnectAsync(Sockets.TCPNetworkStream tcpns, string remoteHost, int remotePort, string proxyUsername, string proxyPassword, string extra)
|
||||
{
|
||||
string http_connect_headers = CreateHTTPConnectHeaders(remoteHost, remotePort, proxyUsername, proxyPassword);
|
||||
byte[] header_data = Encoding.ASCII.GetBytes(http_connect_headers);
|
||||
await tcpns.WriteAsync(header_data, 0, header_data.Length).ConfigureAwait(false);
|
||||
byte[] received = await tcpns.ReadUntilCRLFCRLF().ConfigureAwait(false);
|
||||
if (received == null) return false;
|
||||
int rlen = received.Length;
|
||||
if (rlen <= 9) return false;
|
||||
string result = Encoding.ASCII.GetString(received, 0, rlen);
|
||||
string code = result.Substring(9, 3);
|
||||
if (code != "200") return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Proxies/IProxyProtocol.cs
Normal file
25
Proxies/IProxyProtocol.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Secucore
|
||||
*
|
||||
* Copyright (C) 2023 Trevor Hall
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software may be modified and distributed under the terms
|
||||
* of the MIT license.
|
||||
*
|
||||
*/
|
||||
|
||||
using SecuCore.Sockets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SecuCore.Proxies
|
||||
{
|
||||
interface IProxyProtocol
|
||||
{
|
||||
public static async Task<bool> ConnectAsync(TCPSocket tcpns, string remoteHost, int remotePort, string proxyUsername, string proxyPassword, string extra) => false;
|
||||
}
|
||||
}
|
||||
76
Proxies/Proxy.cs
Normal file
76
Proxies/Proxy.cs
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Secucore
|
||||
*
|
||||
* Copyright (C) 2023 Trevor Hall
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software may be modified and distributed under the terms
|
||||
* of the MIT license.
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using SecuCore.Sockets;
|
||||
|
||||
namespace SecuCore.Proxies
|
||||
{
|
||||
public enum ProxyProtocol
|
||||
{
|
||||
HTTP,
|
||||
SOCKS4,
|
||||
SOCKS5
|
||||
}
|
||||
public class Proxy
|
||||
{
|
||||
private string proxyHost;
|
||||
private int proxyPort;
|
||||
private string proxyUsername;
|
||||
private string proxyPassword;
|
||||
public ProxyProtocol proxyProtocol;
|
||||
|
||||
private IPAddress proxyAddress;
|
||||
|
||||
public Proxy(string proxyString, ProxyProtocol protocol)
|
||||
{
|
||||
if (proxyString.Contains(':'))
|
||||
{
|
||||
string[] pspl = proxyString.Split(':');
|
||||
if (string.IsNullOrEmpty(pspl[0])) throw new Exception("Proxy host parse error");
|
||||
this.proxyHost = pspl[0];
|
||||
if(!int.TryParse(pspl[1], out this.proxyPort)) throw new Exception("Proxy port parse error");
|
||||
if (pspl.Length > 2) this.proxyUsername = pspl[2];
|
||||
if(pspl.Length > 3) this.proxyPassword = pspl[3];
|
||||
this.proxyProtocol = protocol;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Proxy input parse error");
|
||||
}
|
||||
}
|
||||
|
||||
public Task<bool> ConnectAsync(TCPNetworkStream tcpns, string remoteHost, int remotePort)
|
||||
{
|
||||
if (this.proxyProtocol == ProxyProtocol.HTTP)
|
||||
{
|
||||
return HTTPProxyProtocol.ConnectAsync(tcpns, remoteHost, remotePort, proxyUsername, proxyPassword, proxyHost + ":" + proxyPort);
|
||||
}else if(this.proxyProtocol == ProxyProtocol.SOCKS5)
|
||||
{
|
||||
return SOCKS5ProxyProtocol.ConnectAsync(tcpns, remoteHost, remotePort, proxyUsername, proxyPassword);
|
||||
}else if(this.proxyProtocol == ProxyProtocol.SOCKS4)
|
||||
{
|
||||
return SOCKS4ProxyProtocol.ConnectAsync(tcpns, remoteHost, remotePort, proxyUsername, proxyPassword);
|
||||
}
|
||||
return Task<bool>.FromResult(false);
|
||||
}
|
||||
public IPEndPoint GetRemoteEndpoint()
|
||||
{
|
||||
if(proxyAddress == null)
|
||||
{
|
||||
proxyAddress = IPAddress.Parse(proxyHost);
|
||||
}
|
||||
return new IPEndPoint(proxyAddress, proxyPort);
|
||||
}
|
||||
}
|
||||
}
|
||||
82
Proxies/SOCKS4ProxyProtocol.cs
Normal file
82
Proxies/SOCKS4ProxyProtocol.cs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Secucore
|
||||
*
|
||||
* Copyright (C) 2023 Trevor Hall
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software may be modified and distributed under the terms
|
||||
* of the MIT license.
|
||||
*
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
|
||||
namespace SecuCore.Proxies
|
||||
{
|
||||
public class SOCKS4ProxyProtocol : IProxyProtocol
|
||||
{
|
||||
public static async Task<bool> ConnectAsync(Sockets.TCPNetworkStream tcpns, string remoteHost, int remotePort, string proxyUsername, string proxyPassword)
|
||||
{
|
||||
byte[] conp = Socks4ConnectPacket(remoteHost, remotePort);
|
||||
await tcpns.WriteAsync(conp, 0, conp.Length).ConfigureAwait(false);
|
||||
byte[] readb = new byte[64];
|
||||
int len = await tcpns.ReadAsync(readb, 0, readb.Length).ConfigureAwait(false);
|
||||
if (len <= 0) return false;
|
||||
|
||||
if (readb[0] == 0x04)
|
||||
{
|
||||
if (readb[1] == 0x5A)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static byte[] Socks4ConnectPacket(string host, int port)
|
||||
{
|
||||
List<byte> connectionPacket = new();
|
||||
{
|
||||
var withBlock = connectionPacket;
|
||||
// Write packet feader
|
||||
withBlock.Add(4); // socks version 4
|
||||
withBlock.Add(1); // TCP Stream Connection
|
||||
|
||||
// Write port, network order
|
||||
withBlock.AddRange(PortToBytes(port));
|
||||
|
||||
// Write address, network order
|
||||
IPAddress dest = IPAddress.Parse(host);
|
||||
byte[] ipb = dest.GetAddressBytes();
|
||||
Array.Reverse(ipb);
|
||||
withBlock.AddRange(ipb);
|
||||
withBlock.Add(0);
|
||||
}
|
||||
return connectionPacket.ToArray();
|
||||
}
|
||||
|
||||
private static byte[] PortToBytes(int port)
|
||||
{
|
||||
ushort ps = (ushort)port;
|
||||
byte[] pb = BitConverter.GetBytes(ps);
|
||||
|
||||
// network order bytes
|
||||
byte[] nb = new byte[2];
|
||||
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
nb[0] = pb[1];
|
||||
nb[1] = pb[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
nb[0] = pb[0];
|
||||
nb[1] = pb[1];
|
||||
}
|
||||
return nb;
|
||||
}
|
||||
}
|
||||
}
|
||||
174
Proxies/SOCKS5ProxyProtocol.cs
Normal file
174
Proxies/SOCKS5ProxyProtocol.cs
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Secucore
|
||||
*
|
||||
* Copyright (C) 2023 Trevor Hall
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software may be modified and distributed under the terms
|
||||
* of the MIT license.
|
||||
*
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
|
||||
namespace SecuCore.Proxies
|
||||
{
|
||||
public class SOCKS5ProxyProtocol : IProxyProtocol
|
||||
{
|
||||
public static readonly byte[] Socks5greeting = { 0x5, 0x2, 0x0, 0x2 };
|
||||
|
||||
public static async Task<bool> ConnectAsync(Sockets.TCPNetworkStream tcpns, string remoteHost, int remotePort, string proxyUsername, string proxyPassword)
|
||||
{
|
||||
byte[] socksReadBuf = new byte[64];
|
||||
|
||||
await tcpns.WriteAsync(Socks5greeting, 0, Socks5greeting.Length).ConfigureAwait(false);
|
||||
|
||||
if (await tcpns.ReadAsync(socksReadBuf, 0, 2).ConfigureAwait(false) < 2) return false;
|
||||
|
||||
int vers = socksReadBuf[0];
|
||||
int authmethod = socksReadBuf[1];
|
||||
if (vers != 5 || authmethod != 0) return false;
|
||||
|
||||
byte[] conp = Socks5ConnectPacket(remoteHost, remotePort);
|
||||
|
||||
await tcpns.WriteAsync(conp, 0, conp.Length).ConfigureAwait(false);
|
||||
|
||||
int len = await tcpns.ReadAsync(socksReadBuf, 0, socksReadBuf.Length).ConfigureAwait(false);
|
||||
if (len <= 0) return false;
|
||||
|
||||
vers = (int)socksReadBuf[0];
|
||||
if (vers == 0x05)
|
||||
{
|
||||
Socks5ConnectResult status = (Socks5ConnectResult)socksReadBuf[1];
|
||||
if (status == Socks5ConnectResult.Succcess)
|
||||
{
|
||||
int boundType = socksReadBuf[3];
|
||||
int totalResponseSize = 4;
|
||||
if (boundType == 1)
|
||||
{
|
||||
totalResponseSize += 4;
|
||||
}
|
||||
else if (boundType == 3)
|
||||
{
|
||||
int strl = socksReadBuf[4];
|
||||
totalResponseSize += strl + 1;
|
||||
}
|
||||
else if (boundType == 4)
|
||||
{
|
||||
totalResponseSize += 16;
|
||||
}
|
||||
totalResponseSize += 2;
|
||||
|
||||
int remainingSize = totalResponseSize - len;
|
||||
|
||||
if (remainingSize > 0)
|
||||
{
|
||||
byte[] remainb = new byte[remainingSize];
|
||||
|
||||
len = await tcpns.ReadAsync(remainb, 0, remainb.Length).ConfigureAwait(false);
|
||||
if (len <= 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Socks5ConnectResult
|
||||
{
|
||||
Succcess,
|
||||
Failure,
|
||||
NotAllowedByRuleSet,
|
||||
NetworkUnreachable,
|
||||
HostUnreachable,
|
||||
ConnectionRefused,
|
||||
TTLExpired,
|
||||
NotSupportedProtocol
|
||||
}
|
||||
public static byte[] Socks5ConnectPacket(string host, int port)
|
||||
{
|
||||
int hostType;
|
||||
if (Regex.IsMatch(host, @"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"))
|
||||
hostType = 1; // ipv4 address
|
||||
else if (Regex.IsMatch(host, @"(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"))
|
||||
hostType = 4; // ipv6 address
|
||||
else
|
||||
hostType = 3; // domain name
|
||||
|
||||
List<byte> connectionPacket = new();
|
||||
|
||||
{
|
||||
var withBlock = connectionPacket;
|
||||
// Write packet feader
|
||||
withBlock.Add(5); // socks version 5
|
||||
withBlock.Add(1); // TCP Stream Connection
|
||||
withBlock.Add(0); // RFC Reserved 0
|
||||
|
||||
// Write address
|
||||
withBlock.Add((byte)hostType); // Address Type
|
||||
switch (hostType)
|
||||
{
|
||||
case 1 // ipv4
|
||||
:
|
||||
{
|
||||
IPAddress dest = IPAddress.Parse(host);
|
||||
withBlock.AddRange(dest.GetAddressBytes());
|
||||
break;
|
||||
}
|
||||
|
||||
case 4 // ipv6
|
||||
:
|
||||
{
|
||||
IPAddress dest = IPAddress.Parse(host);
|
||||
withBlock.AddRange(dest.GetAddressBytes());
|
||||
break;
|
||||
}
|
||||
|
||||
case 3 // domain
|
||||
:
|
||||
{
|
||||
withBlock.Add((byte)host.Length);
|
||||
withBlock.AddRange(System.Text.Encoding.UTF8.GetBytes(host));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Write port
|
||||
withBlock.AddRange(PortToBytes(port));
|
||||
}
|
||||
|
||||
return connectionPacket.ToArray();
|
||||
}
|
||||
private static byte[] PortToBytes(int port)
|
||||
{
|
||||
ushort ps = (ushort)port;
|
||||
byte[] pb = BitConverter.GetBytes(ps);
|
||||
|
||||
// network order bytes
|
||||
byte[] nb = new byte[2];
|
||||
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
nb[0] = pb[1];
|
||||
nb[1] = pb[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
nb[0] = pb[0];
|
||||
nb[1] = pb[1];
|
||||
}
|
||||
return nb;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue