Client IP Listing and Blocking in SignalR - c#

In Asp.net (core) .net 5, on the SignalR side, how can we list (receive) client IPs and block or allow certain IP's connections and requests by IP?
In my research, I saw that only Azure SingalR was mentioned.
How can we tell SignalR Hub to request Client IPs and accept (whitelist) or block (blacklist) public connection requests from specific IPs by coding in the application?
Is it possible ?

In SignalR you can get the ip of the user with the HttpContext.
public class AppHub : Hub
{
public string Ip => Context.GetHttpContext().Connection.RemoteIpAddress.ToString();
public override async Task OnConnectedAsync()
{
if (Ip == "::1")
{
await Clients.All.SendAsync("ReceiveMessage", "Server", "Welcome to the server!");
}
else
{
throw new Exception("You are not allowed to connect to this server!");
}
await base.OnConnectedAsync();
}
}
Another solution would be to create a hub filter wich you can find the documentation here :
https://learn.microsoft.com/en-us/aspnet/core/signalr/hub-filters?view=aspnetcore-6.0

Related

How to wait for all clients to answer to a request?

I have an ASP.NET core WebApi project which also uses SignalR to communicate with clients. This app has an action that is called by a third-party service and requires that all clients currently connected should send some info back.
The SignalR infrastructure is already being used between the server and clients, so I added this particular action:
public async Task<ActionResult> GetClientInfo()
{
await hubContext.Clients.All.GetClientInfo();
//var infos...
return Ok(infos);
}
So basically, this is what should happen:
The third-party service calls the action
The server asks all clients to send their info
The server returns OK with all the client info
Is it possible to somehow wait and make sure that all clients sent their info before returning OK?
I implemented the code as suggested like this:
public async Task<ActionResult> GetClientInfo()
{
try
{
var tasks = new List<Task<IEnumerable<ClientInfo>>>();
foreach (var client in cache.Clients.Values)
{
tasks.Add(Task.Run(async () =>
{
return await hubContext.Clients.Client(client.Id).GetClientInfo();
}));
}
var list = await Task.WhenAll(tasks);
return Ok(list);
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
cache is MemoryCache implementation that is available throughout the whole app and is based on code similar to this SO answer.

How can I get a user's IP address in C#/asp.net/MVC 5?

The following code works OK locally, but it will only get the server's IP (if I'm correct).
try
{
string externalIP;
externalIP = (new WebClient()).DownloadString("http://checkip.dyndns.org/");
externalIP = (new Regex(#"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"))
.Matches(externalIP)[0].ToString();
model.IpCreacion = externalIP;
}
catch { }
I can't test this right now, because the two guys at my office that can make this as a public URL for testing on a server aren't here today. The code is in the controller of the project, so it runs on the server every time a client executes the app, it's not actually the client who is getting the IP address.
How can I make the client get his IP address, instead of the server, executing the code I just showed?
If I managed to put this functionality in a view, would it work as I'm intending to?
UPDATE: I tried other methods posted as answers, like
string ip = System.Web.HttpContext.Current.Request.UserHostAddress;
and
model.IpCreacion = null;
model.IpCreacion = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (string.IsNullOrEmpty(model.IpCreacion))
{
model.IpCreacion = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
}
but now I'm only getting ::1 as a result. Which didn't happen before, as I was getting a correct IP address.
if you want to get client ip address,visit bellow post in stackoverflow
How can I get the client's IP address in ASP.NET MVC?
That gets only IP of server, because you send the request from Web Server to checkip.dyndns.org.
To get the client IP, you need to use JavaScript and do the same thing.
$.get('http://checkip.dyndns.org/', function(data) {
console.log(data); // client IP here.
})
UPDATED:
If you need client IP Address in ASP.NET Core, you can inject this service
private IHttpContextAccessor _accessor;
And use it as
_accessor.HttpContext.Connection.RemoteIpAddress.ToString()
Or in ASP.NET Framework
Public string GetIp()
{
string ip = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (string.IsNullOrEmpty(ip))
{
ip = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
}
return ip;
}
Public string GetIp()
{
string ip = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (string.IsNullOrEmpty(ip))
{
ip = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
}
return ip;
}

AWS Api Gateway Web Socket Post to $default forbidden

I'm trying to get my lambda to post to my aws web socket api and I am getting a Forbidden error message on the post. I have the following setup:
A public api configured using proxy+ to point to a lambda that handles all my routes.
A public web socket api that calls the above lambda.
I am testing out connectivity and my lambda correctly receives the $connect, $default and $disconnect events from the web socket api. I am trying to send a test message back to the client on open but receive the Forbidden error on the Post command.
My code is here:
public async Task<ITrWebsocketsContext> SendMessageAsync(UserDefinition userDefinition, string message)
{
var connectionIds = GetConnectionIds(userDefinition);
if (connectionIds != null)
{
foreach (var connectionId in connectionIds)
{
try
{
Console.WriteLine($"Sending to {connectionId}");
var response = await PostAsync($"https://{suppliedServiceUrl}/#connections/{connectionId}", message);
Console.WriteLine($"Sent to {connectionId}: {response}");
}
catch (ForbiddenException ex)
{
Console.WriteLine($"Exception: {SerialisableException.Serialise(ex)}");
}
catch (AmazonServiceException ex)
{
Console.WriteLine($"Exception: {SerialisableException.Serialise(ex)}");
RemoveConnection(connectionId);
}
catch (Exception ex)
{
throw;
}
}
}
return this;
}
The call to PostAsync fails.
I think this is a VPC issue as the Lambda is behind a VPC. The VPC is configured with 2 private subnets and 1 public one, with an Internet Gateway. The lambda can access the internet, so the VPC seems to be setup correctly. I also have an endpoint pointing to execute api in my region.
Any ideas on where to go? Do I need a VPC link configured for my lambda to connect to my AWS web sockets api?

How to get something from server using SignalR

I need to create method, which can request to server and return answer. But if I use SignalR, I can run server's method and server will run client's method. But how I can create something like this template?
public Response Request()
{
//???
}
if I use SignalR, I can run server's method and server will run client's method.
If you'd like to invoke hub method from .NET client application in c#, you can refer to the following code snippet.
try
{
HubConnection connection = new HubConnectionBuilder()
.WithUrl("http://localhost:61262/chatHub")
.Build();
await connection.StartAsync();
var mes = "hello";
await connection.InvokeAsync("SendMessage", "Consloe Client", mes);
// await connection.StopAsync();
}
catch (Exception ex)
{
Console.WriteLine("Can not communicate with server now, please retry later.");
}
Hub method
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
Besides, to setup Hub and client, please refer to the following articles.
Use hubs in SignalR for ASP.NET Core
ASP.NET Core SignalR .NET Client

UDP over NAT (via Internet)

I'm coding a system with server (behind NAT with UDP port forwarding, static white IP) and client (behind NAT without any custom settings).
The task is sending datas from server to client via Internet .
In order to Server knows client's endpoint (and client's router keeps translation table), Client sends every 5 second easy UDP request to Server like "Hello!".
Server code:
private void SendData(ref string destination, CancellationToken cancelToken)
{
UdpClient senderClient = new UdpClient(AddressFamily.InterNetwork);
try
{
while (true)
{
cancelToken.ThrowIfCancellationRequested();
if (string.IsNullOrEmpty(destination))
continue;
byte[] testMessage = Encoding.UTF8.GetBytes("AnyDatas");
string ip = destination.Split(':')[0];
string p = destination.Split(':')[1];
IPEndPoint clientEP = new IPEndPoint(IPAddress.Parse(ip), int.Parse(p));
senderClient.Send(testMessage, testMessage.Length, clientEP);
Thread.Sleep(3000);
}
}
catch (OperationCanceledException ex)
{ }
finally
{
if (senderClient != null)
senderClient.Close();
}
}
private void ListenConnectionSupport(ref string stClientEP, CancellationToken cancelToken)
{
IPEndPoint IpEp = new IPEndPoint(IPAddress.Any, 13001);
UdpClient listenClient = new UdpClient(IpEp);
try
{
while (true)
{
cancelToken.ThrowIfCancellationRequested();
IPEndPoint cIpEp=null;
byte[] messageBytes = listenClient.Receive(ref cIpEp);
if (Encoding.UTF8.GetString(messageBytes) == "UDP-support")
{
stClientEP = String.Format("{0}:{1}",cIpEp.Address,cIpEp.Port);
}
}
}
catch (OperationCanceledException ex)
{ }
finally
{
if (listenClient != null)
listenClient.Close();
}
}
And that works even!
But only if client under the same router, despite on sending client->server request to external server IP.
I use my smartphone like client's router and try again (client is another PC). But although server gets Hello-request and sends answer, however client gets nothing.
UPDATE-----------------
I need to develop system for scheme:
Server (192.168.0.3)-routerA (static public IP, has port forwarding for server)- INTERNET- routerB(any regular hotspot or router) - Client
Algorithm:
Client sends to routerA (in this context routerA=Server) "Hello, give me your data." For router table client sends this continusly.
Server from previous message (like STUN server) can note Client EP.
Server in WHILE(true) cycle sends datas to Client.
The error is "Client doesnt get data from server".
If that is matters
server listen 13001 port, Client knows this port number
In "one router case" case server see client's endpoint like "192.168.0.5" (his local IP) and in "two routers" case, client's endpoint looks like unknown IP (I dont know what is that, his ipconfig shows another).
Please, show me proper direction!

Categories