Skip to content

Commit

Permalink
correcting exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
TitleHHHH authored and TitleHHHH committed Sep 29, 2024
1 parent 72b6a5c commit e702cbd
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 30 deletions.
34 changes: 19 additions & 15 deletions src/QuickProxyNet/Clients/ProxyClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,30 +42,39 @@ protected ProxyClient(string protocol, string host, int port, NetworkCredential
public int ProxyPort { get; }

public IPEndPoint LocalEndPoint { get; set; }

public int WriteTimeout { get; set; }
public int ReadTimeout { get; set; }

public async Task<Stream> ConnectAsync(string host, int port, CancellationToken cancellationToken = default)
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
{
NoDelay = true,
LingerState = new LingerOption(true, 0),
SendTimeout = 10000,
ReceiveTimeout = 10000
SendTimeout = this.WriteTimeout,
ReceiveTimeout = this.ReadTimeout
};

await socket.ConnectAsync(ProxyHost, ProxyPort, cancellationToken);

try
{
await socket.ConnectAsync(ProxyHost, ProxyPort, cancellationToken);
}
catch
{
socket.Dispose();
throw;
}

var stream = new NetworkStream(socket, true);
try
{
using var reg = cancellationToken.Register(() => stream.Dispose());
await using var reg = cancellationToken.Register(s => ((IDisposable)s).Dispose(), stream);

return await ConnectAsync(stream, host, port, cancellationToken);
}
catch
{
stream.Dispose();
await stream.DisposeAsync();
throw;
}
}
Expand All @@ -78,14 +87,9 @@ public virtual async Task<Stream> ConnectAsync(string host, int port, int timeou
cancellationToken.ThrowIfCancellationRequested();


using (var ts = new CancellationTokenSource(timeout))
{
//ts.CancelAfter(TimeSpan.FromSeconds(10));
using (var linked = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, ts.Token))
{
return await ConnectAsync(host, port, linked.Token);
}
}
using var ts = new CancellationTokenSource(timeout);
using var linked = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, ts.Token);
return await ConnectAsync(host, port, linked.Token);
}

public abstract ValueTask<Stream> ConnectAsync(Stream source, string host, int port,
Expand Down
2 changes: 0 additions & 2 deletions src/QuickProxyNet/Clients/Socks4Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ public Socks4Client(string host, int port, NetworkCredential credentials) : base
{
}

protected bool IsSocks4a { get; set; }

public override ProxyType Type => ProxyType.SOCKS4;


Expand Down
3 changes: 3 additions & 0 deletions src/QuickProxyNet/IProxyClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ public interface IProxyClient

IPEndPoint LocalEndPoint { get; set; }

int WriteTimeout { get; set; }
int ReadTimeout { get; set; }


Task<Stream> ConnectAsync(string host, int port, CancellationToken cancellationToken = default);
ValueTask<Stream> ConnectAsync(Stream source, string host, int port, CancellationToken cancellationToken = default);
Expand Down
26 changes: 13 additions & 13 deletions src/QuickProxyNet/Internal/SocksHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ internal static async ValueTask EstablishSocks5TunnelAsync(Stream stream, string
// If the server is behaving well, it shouldn't pick username and password auth
// because we don't claim to support it when we don't have credentials.
// Just being defensive here.
throw new ProxyProtocolException("SR.net_socks_auth_required");
throw new ProxyProtocolException("SOCKS server requested username & password authentication.");

// +----+------+----------+------+----------+
// |VER | ULEN | UNAME | PLEN | PASSWD |
Expand All @@ -98,12 +98,12 @@ await WriteAsync(stream, buffer.AsMemory(0, 3 + usernameLength + passwordLength)
// +----+--------+
await ReadToFillAsync(stream, buffer.AsMemory(0, 2), async).ConfigureAwait(false);
if (buffer[0] != SubnegotiationVersion || buffer[1] != Socks5_Success)
throw new ProxyProtocolException("SR.net_socks_auth_failed");
throw new ProxyProtocolException("Failed to authenticate with the SOCKS server.");
break;
}

default:
throw new ProxyProtocolException("SR.net_socks_no_auth_method");
throw new ProxyProtocolException("SOCKS server did not return a suitable authentication method.");
}


Expand Down Expand Up @@ -154,13 +154,13 @@ await WriteAsync(stream, buffer.AsMemory(0, 3 + usernameLength + passwordLength)
// +----+-----+-------+------+----------+----------+
await ReadToFillAsync(stream, buffer.AsMemory(0, 5), async).ConfigureAwait(false);
VerifyProtocolVersion(ProtocolVersion5, buffer[0]);
if (buffer[1] != Socks5_Success) throw new ProxyProtocolException("SR.net_socks_connection_failed");
if (buffer[1] != Socks5_Success) throw new ProxyProtocolException("SOCKS server failed to connect to the destination.");
var bytesToSkip = buffer[3] switch
{
ATYP_IPV4 => 5,
ATYP_IPV6 => 17,
ATYP_DOMAIN_NAME => buffer[4] + 2,
_ => throw new ProxyProtocolException("SR.net_socks_bad_address_type")
_ => throw new ProxyProtocolException("SOCKS server returned an unknown address type.")
};
await ReadToFillAsync(stream, buffer.AsMemory(0, bytesToSkip), async).ConfigureAwait(false);
// response address not used
Expand Down Expand Up @@ -196,7 +196,7 @@ internal static async ValueTask EstablishSocks4TunnelAsync(Stream stream, bool i
else if (hostIP.IsIPv4MappedToIPv6)
ipv4Address = hostIP.MapToIPv4();
else
throw new ProxyProtocolException("SR.net_socks_ipv6_notsupported");
throw new ProxyProtocolException("SOCKS4 does not support IPv6 addresses.");
}
else if (!isVersion4a)
{
Expand All @@ -210,10 +210,10 @@ internal static async ValueTask EstablishSocks4TunnelAsync(Stream stream, bool i
}
catch (Exception ex)
{
throw new ProxyProtocolException("SR.net_socks_no_ipv4_address", ex);
throw new ProxyProtocolException("Failed to resolve the destination host to an IPv4 address.s", ex);
}

if (addresses.Length == 0) throw new ProxyProtocolException("SR.net_socks_no_ipv4_address");
if (addresses.Length == 0) throw new ProxyProtocolException("Failed to resolve the destination host to an IPv4 address.s");

ipv4Address = addresses[0];
}
Expand Down Expand Up @@ -260,9 +260,9 @@ internal static async ValueTask EstablishSocks4TunnelAsync(Stream stream, bool i
// Nothing to do
break;
case Socks4_AuthFailed:
throw new ProxyProtocolException("SR.net_socks_auth_failed");
throw new ProxyProtocolException("Failed to authenticate with the SOCKS server.");
default:
throw new ProxyProtocolException("SR.net_socks_connection_failed");
throw new ProxyProtocolException("SOCKS server failed to connect to the destination.");
}
// response address not used
}
Expand All @@ -281,15 +281,15 @@ private static byte EncodeString(ReadOnlySpan<char> chars, Span<byte> buffer, st
catch
{
Debug.Assert(Encoding.UTF8.GetByteCount(chars) > 255);
throw new ProxyProtocolException("SR.Format(SR.net_socks_string_too_long:" + parameterName);
throw new ProxyProtocolException($"Encoding the {parameterName} took more than the maximum of 255 bytes" );
}
}

private static void VerifyProtocolVersion(byte expected, byte version)
{
if (expected != version)
throw new ProxyProtocolException(
$"SR.Format(SR.net_socks_unexpected_version: expected: {expected} version: {version}");
$"Unexpected SOCKS protocol version. Required {expected}, got {version}.");
}

private static ValueTask WriteAsync(Stream stream, Memory<byte> buffer, bool async)
Expand All @@ -309,6 +309,6 @@ private static async ValueTask ReadToFillAsync(Stream stream, Memory<byte> buffe
? await stream.ReadAtLeastAsync(buffer, buffer.Length, false).ConfigureAwait(false)
: stream.ReadAtLeast(buffer.Span, buffer.Length, false);

if (bytesRead < buffer.Length) throw new IOException("SR.net_http_invalid_response_premature_eof");
if (bytesRead < buffer.Length) throw new IOException("The response ended prematurely.");
}
}

0 comments on commit e702cbd

Please sign in to comment.