Proxy support in BNSharp
From JinxBot
- The correct title of this article is Proxy support in BN#. The substitution or omission of a # sign is because of technical restrictions.
This article describes a feature found in the very latest code for BN# that is not yet reflected in a build. It is in source code as of Revision 28. More information will be made part of the API as releases are made. For help getting the latest source, see Source code.
Implementing proxy support in BN# requires the implementation of the BNSharp.Plugins.IProxyConnector interface, and then assigning it to the ProxyConnector property. The idea behind a proxy connector is to provide the ability to modify the incoming and outgoing data packets. The proxy connector is provided with an interface that can access the real underlying connection (an IProxiedRealConnection). Please note that the client is not required to implement IProxiedRealConnection; it is provided. No assumptions about the implementing type of this object should be made, however, as it may change in the future (which is the purpose of making the public API an interface).
Sample SOCKS4 Implementation
This is a sample implementation of SOCKS4 from testing with JinxBot. It is incomplete, but should be customizable, and give insight as to the implementation of other protocols.
internal class Socks4ProxyConnector : IProxyConnector
{
private ClientProfile m_profile; // provides JinxBot settings for a single client profile
private IProxiedRealConnection m_con;
public Socks4ProxyConnector(ClientProfile settings)
{
m_profile = settings;
}
#region IProxyConnector Members
public void Initialize(IProxiedRealConnection client)
{
m_con = client;
}
public bool Negotiate()
{
DataBuffer init = new DataBuffer();
init.InsertByte(4); // version 4
init.InsertByte(1); // tcp stream
byte[] port = BitConverter.GetBytes(m_profile.Port);
init.InsertByte(port[1]); // network-order port number
init.InsertByte(port[0]);
init.InsertByteArray(m_con.ResolveEndPoint(m_profile.Server,
m_profile.Port).Address.GetAddressBytes()); // ip address of remote host
init.InsertCString("test@test.com"); // username
m_con.Send(init.UnderlyingBuffer, 0, init.Count);
byte[] result = new byte[8];
result = m_con.Receive(result, 0, 8);
return result[1] == 0x5a; // check for success
}
public System.Net.IPEndPoint ResolveEndPoint(string host, int port)
{
return m_con.ResolveEndPoint("some-socks-proxy.net", 1080);
}
public byte[] Receive(byte[] buffer, int index, int length)
{
return m_con.Receive(buffer, index, length);
}
public byte[] Receive()
{
return m_con.Receive();
}
public void Send(byte[] data, int index, int length)
{
m_con.Send(data, index, length);
}
#endregion
}
The Initialize method is called first, which provides the IProxiedRealConnection to the proxy connector; that is simply stored and used later. During the Connect method, the ResolveEndpoint method is called to determine the destination endpoint of the client connection. This method should resolve the endpoint of the proxy server.
The Negotiate method performs the actual talking to the server in order to tell it where to connect and any other authentication details. In the case of SOCKS4, it's fairly straightforward and no additional communication is necessary. Negotiation completes before connecting to the target machine; if it fails, then we quit.
This SOCKS4 implementation the provides pass-through methods for Receive(), Receive(byte[], int, int) and Send(byte[], int, int). Other protocols may modify the data in these methods, for instance, in cases of SSL. This is intended to be a generalized solution and not specific to connecting to Battle.net.

