+1 vote
by (180 points)

We're running a Rebex FileServer. It's working great. Clients can log in and upload / download files correctly. But for logging purposes, I need to get the IP address of the connected user when the file finished uploading or downloading. I have server_FileDownloaded and server_FileUploaded methods, but I can't figure out how to get the IP address there.

Also, in the Rebex logging, I see that we have unauthorized IPs trying to access us, attempting to brute-force login. Can I block them by IP, or do I have to do that at the firewall?

Applies to: Rebex SFTP, File Server

2 Answers

0 votes
by (144k points)
 
Best answer

Rebex File Server 2017 R4 adds Session property to FileUploaded and FileDownloaded event arguments and it includes the client endpoint, making it very simple to determine the client's IP address:

server.FileUploaded += (sender, e) =>
{
    // get session's IP address
    IPAddress address = ((IPEndPoint)e.Session.ClientEndPoint).Address;
    ...
};
0 votes
by (144k points)
edited by

Update: This approach is no longer necessary. See the new answer for a simple solution available since Rebex File Server 2017 R4.


IP address is not available in FileUploaded/FileDownloaded events (yet), but you can work around this by using a custom user class and a custom Authentication event that associates an IP with a per-session user object.

Try using this custom user class:

public class CustomUser : FileServerUser
{
    private readonly string _userName;
    private readonly string _password;
    private readonly string _virtualRootPath;

    public CustomUser(string userName, string password, string virtualRootPath)
        : base(userName, password, virtualRootPath)
    {
        _userName = userName;
        _password = password;
        _virtualRootPath = virtualRootPath;
    }

    private class ActiveCustomUser : CustomUser
    {
        public IPAddress Address { get; private set; }

        public ActiveCustomUser(IPAddress address, string userName, string password, string virtualRootPath)
            : base(userName, password, virtualRootPath)
        {
            Address = address;
        }
    }

    public FileServerUser ToActiveUser(IPAddress address)
    {
        return new ActiveCustomUser(address, _userName, _password, _virtualRootPath);
    }

    public static IPAddress GetAddress(FileServerUser user)
    {
        var activeUser = user as ActiveCustomUser;
        if (activeUser == null)
            return IPAddress.None;
        else
            return activeUser.Address;
    }
}

To make it work, you have to provide Authentication and FileUploaded/FileDownloaded events:

var server = new FileServer();
server.Keys.Add(...);
server.Bind(22, FileServerProtocol.Sftp);

server.Users.Add(new CustomUser("user01", "password", @"c:\temp\SftpRoot"));

server.Authentication += (sender, e) =>
{
    var user = (CustomUser)e.Users[e.UserName];

    if (user.CheckPassword(e.Password))
    {
        e.Accept(user.ToActiveUser(e.ClientAddress));
        return;
    }

    e.Reject();
};

server.FileUploaded += (sender, e) =>
{
    IPAddress address = CustomUser.GetAddress(e.User);
    ...
};

server.Start();

Rejecting access from unwanted IP addresses is possible in Connecting event:

server.Connecting += (sender, e) =>
{
    e.Accept = IsAllowed(e.ClientAddress);
};

This will still accept the incoming connection, but it will be closed immediately without performing any SSH negotiation. If you prefer rejecting the connection attempts without accepting them first, you would have to do that at the firewall.

by (180 points)
Thanks, this all worked great.
...