How to use proxies with the WebSocket4Net library - c#

I'm building a secure WebSockets client using C# and the WebSocket4Net library. I would like for all my connections to be proxied through a standard proxy.
This lib uses the SuperSocket.ClientEngine.Common.IProxyConnector to specify a websocket connection's proxy, but I'm not sure how I'm supposed to implement that.
Has anyone worked with this library and can offer some advice?

I had to do the same, to push all websocket connections through Fiddler, for easier debugging. Because the WebSocket4Net author chose to re-use his IProxyConnector interface, System.Net.WebProxy is not directly useable.
On this link the author suggests using the implementations from his parent library SuperSocket.ClientEngine which you can download from CodePlex and include both the SuperSocket.ClientEngine.Common.dll and SuperSocket.ClientEngine.Proxy.dll. I do not recommend this. This causes compiling issues because he (poorly) chose to use the same namespace with both ClientEngine and WebSocket4Net with IProxyConnector defined in both dll's.
What worked for me:
To get it working for debugging through Fiddler, I copied these two classes into my solution, and changed them to the local namespace:
HttpConnectProxy.cs
ProxyConnectionBase
HttpConnectProxy seemed to have a bug on the following line:
if (e.UserToken is DnsEndPoint)
change to:
if (e.UserToken is DnsEndPoint || targetEndPoint is DnsEndPoint)
After that, things worked fine. Sample code:
private WebSocket _socket;
public Initialize()
{
// initialize the client connection
_socket = new WebSocket("ws://echo.websocket.org", origin: "http://example.com");
// go through proxy for testing
var proxy = new HttpConnectProxy(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888));
_socket.Proxy = (SuperSocket.ClientEngine.IProxyConnector)proxy;
// hook in all the event handling
_socket.Opened += new EventHandler(OnSocketOpened);
//_socket.Error += new EventHandler<ErrorEventArgs>(OnSocketError);
//_socket.Closed += new EventHandler(OnSocketClosed);
//_socket.MessageReceived += new EventHandler<MessageReceivedEventArgs>(OnSocketMessageReceived);
// open the connection if the url is defined
if (!String.IsNullOrWhiteSpace(url))
_socket.Open();
}
private void OnSocketOpened(object sender, EventArgs e)
{
// send the message
_socket.Send("Hello World!");
}

Related

Why doesn't Microsoft.Azure.ServiceBus's QueueClient drop back to HTTPS? [duplicate]

I have created a very simple console application that connects to Azure ServiceBus and sends one message. I tried the latest library from Microsoft (Microsoft.Azure.ServiceBus) but no matter what I do I just get this error:
No connection could be made because the target machine actively
refused it ErrorCode: ConnectionRefused
I have tried exactly the same connection string in Service Bus Explorer and it does work just fine. Moreover I connected without problems using the older library from Microsoft (WindowsAzure.ServiceBus).
var sender = new MessageSender("endpoint", "topicName");
sender.SendAsync(new Message(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject("test"))));
I tried with .NET Framework 4.6.2 and Core, same exception. I suspect there may be some differences in the default protocol that these libraries use, but I could not figure out that for sure.
P.S. Have tried the example from Microsoft docs but result is still the same exception
The old client supported ConnectivityMode using TCP, HTTP, HTTPS, and AutoDetect. ServiceBus Explorer is using AutoDetect, trying TCP first and then failing over to HTTPS, regardless of the TransportMode you were using (SBMP or AMQP).
With the new client this has changed. TransportMode now combines both options and offers Amqp (AMQP over TCP) or AmqpWebSockets (AMQP over WebSockets). There's no AutoDetect mode. You will have to create your clients and specify TransportType as AmqpWebSockets to bypass blocked TCP port 5671 and instead use port 443.
It seems that the documentation is lacking a lot on how to connect using HTTPS (Amqp over WebSockets) but after some help from Sean Feldman in the accepted answer I managed to connect. Here is the code that I used if someone is interested:
var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(
"RootManageSharedAccessKey", // SharedAccessKeyName
"SomeToken");
var sender = new MessageSender(
"sb://mydomain.servicebus.windows.net/",
"topicName",
tokenProvider,
TransportType.AmqpWebSockets);
Or a variant that let's you have the whole connection string in one piece
var builder = new ServiceBusConnectionStringBuilder("YouConnectionString");
var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(
builder.SasKeyName,
builder.SasKey);
var sender = new MessageSender(
builder.Endpoint,
"TopicName",
tokenProvider,
TransportType.AmqpWebSockets);
It is actually possible to use ConnectionString directly but then it has to be augmented to use the right protocol.
var sender = new MessageSender("TransportType=AmqpWebSockets;Endpoint=...", "TopicName")
Or the version that allows to embed EntityPath into the ConnectionString
var connectionBuilder = new ServiceBusConnectionStringBuilder("EntityPath=MyTopic;TransportType=AmqpWebSockets;Endpoint=...")
var sender = new MessageSender(connectionBuilder);
I was having the same issue but his worked for me
var clientOptions = new ServiceBusClientOptions();
clientOptions.TransportType = ServiceBusTransportType.AmqpWebSockets;
client = new ServiceBusClient(connectionString, clientOptions);
sender = client.CreateSender(topicName);
// create a batch
using ServiceBusMessageBatch messageBatch = await sender.CreateMessageBatchAsync();

TwitchLib Help- Work around old TwitchClient() method

I was watching a tutorial on how to script a bot using C# and the instructor used (to my knowledge) an old call to TwitchClient which takes credentials and references. However, it is currently not the case and I'm wondering now what might be a good way to work around it. Currently, the method takes a websocket and logger but I have suspicion that you still need to use credentials and references.
Any help will be appreciated.
Here's the video with the timestamp: https://youtu.be/5f1T9hQqJps?t=8m3s
Instead of the single line in the video, these two lines should now achieve mostly the same effect:
client = new TwitchClient();
client.Initialize(credentials, "channel");
If you want to also enable logging (like in the video), then you will need to provide an instance of ILogger to the first call like so:
client = new TwitchClient(null, myLoggingInstance);
The WebSocket parameter is used for testing (so you can generate your own traffic to test your bot), the docs advise not to set this.
its quite simple actually, even the github page shows a simple example:
ConnectionCredentials credentials = new ConnectionCredentials("twitch_username", "access_token");
var clientOptions = new ClientOptions
{
MessagesAllowedInPeriod = 750,
ThrottlingPeriod = TimeSpan.FromSeconds(30)
};
WebSocketClient customClient = new WebSocketClient(clientOptions);
client = new TwitchClient(customClient);
client.Initialize(credentials, "channel");
client.OnLog += Client_OnLog;
client.Connect();
then later declare this function:
private void Client_OnLog(object sender, OnLogArgs e)
{
Console.WriteLine($"{e.DateTime.ToString()}: {e.BotUsername} - {e.Data}");
}

Edit WCF message before it is sent to server

We recently had to upgrade our Win 8.1 store app to Win 10. Part of that change was modifying our NetTcpBindings to instead be BasicHttpBindings for file uploads since UWP does not currently support NetTcpBindings. Our issue is that when the client calls the UploadFileMethod on the proxy class, we intercept the message before it is sent to the server so we can apply headers that are used later as follows:
public async Task UploadFileAsync(RemoteFileInfo request)
{
using (new OperationContextScope(this.InnerChannel))
{
string nameSpace = #"http://tempuri.org";
OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("FileName", nameSpace, request.FileName));
OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("Length", nameSpace,
request.Length));
await Channel.UploadFileAsync(request);
}
}
This used to work fine when we were using NetTcpBinding but since we switched to BasicHttpBinding that code is now throwing an exception on the line:
await Channel.UploadFileAsync(request);
With the exception reading:
This message cannot support the operation because it has been written.
After reading up on this exception it appears that we cannot mess with the request object at all before it is sent to the server when using BasicHttpBinding. If that is the case, how can we add OutgoingMessageHeaders to the message using properties of the request itself?
Edit: The proxy class is created as follows:
var imageProxy = new RTMImageServiceProxy(globalContext.Win10UploadBinding,
globalContext.ImageEndpointAddress);
Where Win10UploadBinding is configured as so:
BasicHttpBinding win10BasicBinding = new BasicHttpBinding();
win10BasicBinding.Security.Mode = BasicHttpSecurityMode.None;
win10BasicBinding.TransferMode = TransferMode.Streamed;
win10BasicBinding.SendTimeout = new TimeSpan(0, 0, 2, 0);
win10BasicBinding.MaxReceivedMessageSize = 2147483647;
this.win10UploadBinding = win10BasicBinding;
and globalContext is just a static class I used to store commonly-used variables.
Apparently it turns out that once written cannot be altered so create a copy with adjusted headers. Equivalent issue was brought up here.
Anyway, I encourage you to create custom message inspector: class deriving IClientMessageInspector, as far as client is concerned. It provides separation between method being invoced and headers being adjusted.

Bouncy Castle TLS API usage

I want to communicate between Server and Client using sockets using bouncy castle TLS library.
I went through many documentation(which was insufficient for me) but I did not get any idea how to do this,
I am using BouncyCastle v1.7.48(runtime version=v2.0.50727) binary,
and I have found these info,
I have to use, Org.BouncyCastle.Crypto.Tls namespace and TlsProtocolHandler class.
To achieve TLS communication,
what API I should use in server side?
what API I should use in client side?
System.IO.Stream inputStream, outputStream;
TlsProtocolHandler tls = new TlsProtocolHandler(inputStream, outputStream);
What are the parameters inputStream and outputStream?
public virtual void Connect(TlsClient tlsClient);
where, TlsClient is an interface, and that contains many interfaces inside.
4. How to use the above API? I have to declare new classes and implement methods inside that to all?
Please help me with this Bouncy Castle.
EDIT 1:
I created one class which inherits from an abstract class called DefaultTlsClient.
Then I could create an instance of my class and pass it for interface reference.
So I could send the parameter like this. tls.Connect(tlsClient);
I am not initializing any parameters except I mentioned above.
(Sockets are connected before these operation on 2055)
But I am not sure handshake is complete or not. My program will go to reading state.
There is no server-side TLS API in bouncy castle. You can read on main page that they support only client-side.
For client-side you have found right classes already. TlsProtocolHandler does the job, but it won't work without custom classes. Here is example code:
// Need class with TlsClient in inheritance chain
class MyTlsClient : DefaultTlsClient
{
public override TlsAuthentication GetAuthentication()
{
return new MyTlsAuthentication();
}
}
// Need class to handle certificate auth
class MyTlsAuthentication : TlsAuthentication
{
public TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
{
// return client certificate
return null;
}
public void NotifyServerCertificate(Certificate serverCertificate)
{
// validate server certificate
}
}
class Program
{
static void Main(string[] args)
{
TcpClient client = new TcpClient();
client.Connect(IPAddress.Loopback, 6000);
// input/output streams are deprecated, just pass client stream
TlsProtocolHandler handler = new TlsProtocolHandler(client.GetStream());
handler.Connect(new MyTlsClient());
// handshake completed
// use handler.Stream.Write/Read for sending app data
Console.ReadLine();
}
}
I have tested this with my tcp server and received client hello.
Keep in mind it is TLS in version 1.0 so if u need other version or server api then I recommend using other library (.NET framework supports TLS).

SignalR Client connection issues? Can't connect to path with HubConnection()

I've been trying to look in the wiki about doing this, I'm following it, but I seem to be missing something?
So here is where I am at:
I have a client side JS that works fine locally.
I now want to send something via an API to update the client side version.I should use SignalR Client right?
This is what i have:
var connection = new HubConnection("http://localhost/test/echo", useDefaultUrl: false);
Global.asax
RouteTable.Routes.MapConnection<MyConnection>("echo", "echo/{*operation}");
I'm getting an error along the lines of no cancellation token is declared....
Is it that I'm not hitting my HubConnection page?
If you need me to clarify let me know.
Thanks,
UPDATE:
Thanks for replying! I'm still uncertain on how a Hub can talk to a persistent connection?
This is what I have so far...
namespace ConnectionHubDemo{
public class ChatHub : Hub
{
public void SendMessage(string message)
{
Clients.NewMessage(message);
}
}
public class ConnectionHub
{
public string test(string data)
{
//Will this talk to my PersistentConnection?
var connection = new HubConnection("http://localhost/test", false);
var myHub = connection.CreateProxy("ConnectionHubDemo.ServiceHub");
//How would I send a message to my persisten connection?
//myHub...
//If succcessful bla bla bla
return data;
}
}
}
That's because you're not using Hubs. You're mixing Hubs and PersistentConnections. On the server Hubs are automatically routed so there's no need to map anything (see https://github.com/SignalR/SignalR/wiki/Hubs). From the wiki:
Unlike low level PersistentConnections, there's no need to specify a route for the hub as they are automatically accessible over a special url (/signalr). This url is configurable:
To make the client side work you just declare a HubConnection with the root url (see https://github.com/SignalR/SignalR/wiki/SignalR-Client-Hubs). Again from the documentation:
To connect to a hub using SignalR, create a HubConnection with the appropriate url.
NOTE: This url will not point to a specific connection. But will instead point to the root of your site.
Example
var connection = new HubConnection("http://mysite/");
So in your case, this would be:
var connection = new HubConnection("http://localhost/test");
Hope this helps.
UPDATE
Hubs DO NOT talk to persistent connections. All you have to do is follow the documentation. My answer above shows how to use Hubs on the server and on the client.
If you want to use Persistent connections then look at the documentation https://github.com/SignalR/SignalR/wiki/PersistentConnection (Server) and https://github.com/SignalR/SignalR/wiki/SignalR-Client (Client).

Categories

Resources