Skip to content

Commit

Permalink
Merge pull request #667 from immense/feature/wake-on-lan
Browse files Browse the repository at this point in the history
Feature - Wake On LAN
  • Loading branch information
bitbound committed Jun 23, 2023
2 parents e6cc771 + 2cac4a5 commit 097e6a4
Show file tree
Hide file tree
Showing 50 changed files with 5,159 additions and 335 deletions.
5 changes: 3 additions & 2 deletions Agent/Interfaces/IDeviceInformationService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Remotely.Shared.Models;
using Remotely.Shared.Dtos;
using Remotely.Shared.Models;
using System;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -9,6 +10,6 @@ namespace Remotely.Agent.Interfaces
{
public interface IDeviceInformationService
{
Task<Device> CreateDevice(string deviceId, string orgId);
Task<DeviceClientDto> CreateDevice(string deviceId, string orgId);
}
}
1 change: 1 addition & 0 deletions Agent/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ private static void RegisterServices(IServiceCollection services)
// TODO: All these should be registered as interfaces.
services.AddSingleton<IAgentHubConnection, AgentHubConnection>();
services.AddSingleton<ICpuUtilizationSampler, CpuUtilizationSampler>();
services.AddSingleton<IWakeOnLanService, WakeOnLanService>();
services.AddHostedService(services => services.GetRequiredService<ICpuUtilizationSampler>());
services.AddScoped<ChatClientService>();
services.AddTransient<PSCore>();
Expand Down
11 changes: 11 additions & 0 deletions Agent/Services/AgentHubConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class AgentHubConnection : IAgentHubConnection, IDisposable

private readonly IDeviceInformationService _deviceInfoService;
private readonly IHttpClientFactory _httpFactory;
private readonly IWakeOnLanService _wakeOnLanService;
private readonly ILogger<AgentHubConnection> _logger;
private readonly ILogger _fileLogger;
private readonly ScriptExecutor _scriptExecutor;
Expand All @@ -57,6 +58,7 @@ public class AgentHubConnection : IAgentHubConnection, IDisposable
IUpdater updater,
IDeviceInformationService deviceInfoService,
IHttpClientFactory httpFactory,
IWakeOnLanService wakeOnLanService,
IEnumerable<ILoggerProvider> loggerProviders,
ILogger<AgentHubConnection> logger)
{
Expand All @@ -68,6 +70,7 @@ public class AgentHubConnection : IAgentHubConnection, IDisposable
_updater = updater;
_deviceInfoService = deviceInfoService;
_httpFactory = httpFactory;
_wakeOnLanService = wakeOnLanService;
_logger = logger;
_fileLogger = loggerProviders
.OfType<FileLoggerProvider>()
Expand Down Expand Up @@ -489,6 +492,14 @@ private void RegisterMessageHandlers()
});

_hubConnection.On("TriggerHeartbeat", SendHeartbeat);

_hubConnection.On("WakeDevice", async (string macAddress) =>
{
_logger.LogInformation(
"Received request to wake device with MAC address {macAddress}.",
macAddress);
await _wakeOnLanService.WakeDevice(macAddress);
});
}

private async Task<bool> VerifyServer()
Expand Down
57 changes: 51 additions & 6 deletions Agent/Services/DeviceInfoGeneratorBase.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
using Microsoft.Extensions.Logging;
using Remotely.Shared.Dtos;
using Remotely.Shared.Models;
using Remotely.Shared.Utilities;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.InteropServices;

namespace Remotely.Agent.Services
Expand All @@ -18,20 +22,21 @@ public DeviceInfoGeneratorBase(ILogger<DeviceInfoGeneratorBase> logger)
_logger = logger;
}

protected Device GetDeviceBase(string deviceID, string orgID)
protected DeviceClientDto GetDeviceBase(string deviceID, string orgID)
{

return new Device()
return new DeviceClientDto()
{
ID = deviceID,
Id = deviceID,
DeviceName = Environment.MachineName,
Platform = EnvironmentHelper.Platform.ToString(),
ProcessorCount = Environment.ProcessorCount,
OSArchitecture = RuntimeInformation.OSArchitecture,
OSDescription = RuntimeInformation.OSDescription,
OsArchitecture = RuntimeInformation.OSArchitecture,
OsDescription = RuntimeInformation.OSDescription,
Is64Bit = Environment.Is64BitOperatingSystem,
IsOnline = true,
OrganizationID = orgID,
MacAddresses = GetMacAddresses().ToArray(),
OrganizationId = orgID,
AgentVersion = AppVersionHelper.GetAppVersion()
};
}
Expand Down Expand Up @@ -95,5 +100,45 @@ protected List<Drive> GetAllDrives()
return null;
}
}

private IEnumerable<string> GetMacAddresses()
{
var macAddress = new List<string>();

try
{
var nics = NetworkInterface.GetAllNetworkInterfaces();

if (!nics.Any())
{
return macAddress;
}

var onlineNics = nics
.Where(c =>
c.NetworkInterfaceType != NetworkInterfaceType.Loopback &&
c.OperationalStatus == OperationalStatus.Up);

foreach (var adapter in onlineNics)
{
var ipProperties = adapter.GetIPProperties();

var unicastAddresses = ipProperties.UnicastAddresses;
if (!unicastAddresses.Any(temp => temp.Address.AddressFamily == AddressFamily.InterNetwork))
{
continue;
}

var address = adapter.GetPhysicalAddress();
macAddress.Add(address.ToString());
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while getting MAC addresses.");
}

return macAddress;
}
}
}
3 changes: 2 additions & 1 deletion Agent/Services/Linux/DeviceInfoGeneratorLinux.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.Extensions.Logging;
using Remotely.Agent.Interfaces;
using Remotely.Shared.Dtos;
using Remotely.Shared.Models;
using Remotely.Shared.Services;
using Remotely.Shared.Utilities;
Expand All @@ -26,7 +27,7 @@ public class DeviceInfoGeneratorLinux : DeviceInfoGeneratorBase, IDeviceInformat
_cpuUtilSampler = cpuUtilSampler;
}

public Task<Device> CreateDevice(string deviceId, string orgId)
public Task<DeviceClientDto> CreateDevice(string deviceId, string orgId)
{
var device = GetDeviceBase(deviceId, orgId);

Expand Down
3 changes: 2 additions & 1 deletion Agent/Services/MacOS/DeviceInfoGeneratorMac.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.Extensions.Logging;
using Remotely.Agent.Interfaces;
using Remotely.Shared.Dtos;
using Remotely.Shared.Models;
using Remotely.Shared.Services;
using System;
Expand All @@ -17,7 +18,7 @@ public DeviceInfoGeneratorMac(IProcessInvoker processInvoker, ILogger<DeviceInfo
{
_processInvoker = processInvoker;
}
public async Task<Device> CreateDevice(string deviceId, string orgId)
public async Task<DeviceClientDto> CreateDevice(string deviceId, string orgId)
{
var device = GetDeviceBase(deviceId, orgId);

Expand Down
39 changes: 39 additions & 0 deletions Agent/Services/WakeOnLanService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace Remotely.Agent.Services
{
public interface IWakeOnLanService
{
Task WakeDevice(string macAddress);
}

public class WakeOnLanService : IWakeOnLanService
{
public async Task WakeDevice(string macAddress)
{
var macBytes = Convert.FromHexString(macAddress);

using var client = new UdpClient();

var macData = Enumerable
.Repeat(macBytes, 16)
.SelectMany(x => x);

var packet = Enumerable
.Repeat((byte)0xFF, 6)
.Concat(macData)
.ToArray();

var broadcastAddress = System.Net.IPAddress.Parse("255.255.255.255");
// WOL usually uses port 9.
var endpoint = new IPEndPoint(broadcastAddress, 9);
await client.SendAsync(packet, packet.Length, endpoint);
}
}
}
3 changes: 2 additions & 1 deletion Agent/Services/Windows/DeviceInfoGeneratorWin.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Immense.RemoteControl.Desktop.Native.Windows;
using Microsoft.Extensions.Logging;
using Remotely.Agent.Interfaces;
using Remotely.Shared.Dtos;
using Remotely.Shared.Models;
using System;
using System.Linq;
Expand All @@ -20,7 +21,7 @@ public class DeviceInfoGeneratorWin : DeviceInfoGeneratorBase, IDeviceInformatio
_cpuUtilSampler = cpuUtilSampler;
}

public Task<Device> CreateDevice(string deviceId, string orgId)
public Task<DeviceClientDto> CreateDevice(string deviceId, string orgId)
{
var device = GetDeviceBase(deviceId, orgId);

Expand Down
12 changes: 2 additions & 10 deletions Server/API/AgentUpdateController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ public class AgentUpdateController : ControllerBase
private readonly ILogger<AgentUpdateController> _logger;
private readonly IApplicationConfig _appConfig;
private readonly IWebHostEnvironment _hostEnv;
private readonly IServiceHubSessionCache _serviceSessionCache;
private readonly IAgentHubSessionCache _serviceSessionCache;

public AgentUpdateController(IWebHostEnvironment hostingEnv,
IApplicationConfig appConfig,
IServiceHubSessionCache serviceSessionCache,
IAgentHubSessionCache serviceSessionCache,
IHubContext<AgentHub> agentHubContext,
ILogger<AgentUpdateController> logger)
{
Expand Down Expand Up @@ -154,14 +154,6 @@ private async Task<bool> CheckForDeviceBan(string deviceIp)
var bannedDevices = _serviceSessionCache.GetAllDevices().Where(x => x.PublicIP == deviceIp);
var connectionIds = _serviceSessionCache.GetConnectionIdsByDeviceIds(bannedDevices.Select(x => x.ID));

// TODO: Remove when devices have been removed.
var command = "sc delete Remotely_Service & taskkill /im Remotely_Agent.exe /f";
await _agentHubContext.Clients.Clients(connectionIds).SendAsync("ExecuteCommand",
"cmd",
command,
Guid.NewGuid().ToString(),
Guid.NewGuid().ToString());

await _agentHubContext.Clients.Clients(connectionIds).SendAsync("UninstallAgent");

return true;
Expand Down
4 changes: 2 additions & 2 deletions Server/API/RemoteControlController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class RemoteControlController : ControllerBase
{
private readonly IHubContext<AgentHub> _serviceHub;
private readonly IDesktopHubSessionCache _desktopSessionCache;
private readonly IServiceHubSessionCache _serviceSessionCache;
private readonly IAgentHubSessionCache _serviceSessionCache;
private readonly IApplicationConfig _appConfig;
private readonly IOtpProvider _otpProvider;
private readonly IHubEventHandler _hubEvents;
Expand All @@ -41,7 +41,7 @@ public class RemoteControlController : ControllerBase
IDataService dataService,
IDesktopHubSessionCache desktopSessionCache,
IHubContext<AgentHub> serviceHub,
IServiceHubSessionCache serviceSessionCache,
IAgentHubSessionCache serviceSessionCache,
IOtpProvider otpProvider,
IHubEventHandler hubEvents,
IApplicationConfig appConfig,
Expand Down
4 changes: 2 additions & 2 deletions Server/API/ScriptingController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ public class ScriptingController : ControllerBase
private readonly IHubContext<AgentHub> _agentHubContext;

private readonly IDataService _dataService;
private readonly IServiceHubSessionCache _serviceSessionCache;
private readonly IAgentHubSessionCache _serviceSessionCache;
private readonly IExpiringTokenService _expiringTokenService;

private readonly UserManager<RemotelyUser> _userManager;

public ScriptingController(UserManager<RemotelyUser> userManager,
IDataService dataService,
IServiceHubSessionCache serviceSessionCache,
IAgentHubSessionCache serviceSessionCache,
IExpiringTokenService expiringTokenService,
IHubContext<AgentHub> agentHub)
{
Expand Down
18 changes: 17 additions & 1 deletion Server/Components/Devices/DeviceCard.razor
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@
<span class="ml-2">View Only</span>
</button>
</li>
<li>
<button class="dropdown-item" @onclick="() => WakeDevice()">
<i class="oi oi-power-standby" title="Wake Device"></i>
<span class="ml-2">Wake</span>
</button>
</li>
<li>
<FileInputButton ClassNames="dropdown-item btn btn-primary"
OnChanged="OnFileInputChanged">
Expand Down Expand Up @@ -200,6 +206,16 @@
<input class="form-control" readonly value="@Device.PublicIP" />
</div>

<div class="font-weight-bold text-info mt-2">
MAC Addresses
</div>
<div>
<input
class="form-control"
readonly
value="@(string.Join(", ", Device.MacAddresses ?? Array.Empty<string>()))" />
</div>

<EditForm Model="Device" OnValidSubmit="HandleValidSubmit">
<DataAnnotationsValidator />

Expand All @@ -218,7 +234,7 @@
<InputSelect @bind-Value="Device.DeviceGroupID" class="form-control">
<option value="">None</option>

@foreach (var group in DataService.GetDeviceGroups(Username))
@foreach (var group in _deviceGroups)
{
<option @key="group.ID" value="@group.ID">@group.Name</option>
}
Expand Down

0 comments on commit 097e6a4

Please sign in to comment.