Skip to content

Commit c9f3311

Browse files
Adds support for monitoring specific processes (#230)
1 parent 6e055d8 commit c9f3311

File tree

4 files changed

+100
-3
lines changed

4 files changed

+100
-3
lines changed

msgraph-developer-proxy/ProxyCommandHandler.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ public class ProxyCommandHandler : ICommandHandler {
1313
public Option<int?> Port { get; set; }
1414
public Option<LogLevel?> LogLevel { get; set; }
1515
public Option<bool?> Record { get; set; }
16+
public Option<IEnumerable<int>?> WatchPids { get; set; }
17+
public Option<IEnumerable<string>?> WatchProcessNames { get; set; }
1618

1719
private readonly PluginEvents _pluginEvents;
1820
private readonly ISet<Regex> _urlsToWatch;
@@ -21,12 +23,16 @@ public class ProxyCommandHandler : ICommandHandler {
2123
public ProxyCommandHandler(Option<int?> port,
2224
Option<LogLevel?> logLevel,
2325
Option<bool?> record,
26+
Option<IEnumerable<int>?> watchPids,
27+
Option<IEnumerable<string>?> watchProcessNames,
2428
PluginEvents pluginEvents,
2529
ISet<Regex> urlsToWatch,
2630
ILogger logger) {
2731
Port = port ?? throw new ArgumentNullException(nameof(port));
2832
LogLevel = logLevel ?? throw new ArgumentNullException(nameof(logLevel));
2933
Record = record ?? throw new ArgumentNullException(nameof(record));
34+
WatchPids = watchPids ?? throw new ArgumentNullException(nameof(watchPids));
35+
WatchProcessNames = watchProcessNames ?? throw new ArgumentNullException(nameof(watchProcessNames));
3036
_pluginEvents = pluginEvents ?? throw new ArgumentNullException(nameof(pluginEvents));
3137
_urlsToWatch = urlsToWatch ?? throw new ArgumentNullException(nameof(urlsToWatch));
3238
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
@@ -49,6 +55,14 @@ public async Task<int> InvokeAsync(InvocationContext context) {
4955
if (record is not null) {
5056
Configuration.Record = record.Value;
5157
}
58+
var watchPids = context.ParseResult.GetValueForOption(WatchPids);
59+
if (watchPids is not null) {
60+
Configuration.WatchPids = watchPids;
61+
}
62+
var watchProcessNames = context.ParseResult.GetValueForOption(WatchProcessNames);
63+
if (watchProcessNames is not null) {
64+
Configuration.WatchProcessNames = watchProcessNames;
65+
}
5266

5367
CancellationToken? cancellationToken = (CancellationToken?)context.BindingContext.GetService(typeof(CancellationToken?));
5468

msgraph-developer-proxy/ProxyConfiguration.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,7 @@ public class ProxyConfiguration {
2727
[JsonPropertyName("logLevel")]
2828
[JsonConverter(typeof(JsonStringEnumConverter))]
2929
public LogLevel LogLevel { get; set; } = LogLevel.Info;
30+
public IEnumerable<int> WatchPids { get; set; } = new List<int>();
31+
public IEnumerable<string> WatchProcessNames { get; set; } = new List<string>();
3032
}
3133

msgraph-developer-proxy/ProxyEngine.cs

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,13 +245,81 @@ private void OnCancellation() {
245245

246246
async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e) {
247247
// Ensures that only the targeted Https domains are proxyied
248-
if (!IsProxiedHost(e.HttpClient.Request.RequestUri.Host)) {
248+
if (!IsProxiedHost(e.HttpClient.Request.RequestUri.Host) ||
249+
!IsProxiedProcess(e)) {
249250
e.DecryptSsl = false;
250251
}
251252
await Task.CompletedTask;
252253
}
253254

254-
async Task OnRequest(object sender, SessionEventArgs e) {
255+
private int GetProcessId(TunnelConnectSessionEventArgs e)
256+
{
257+
if (RunTime.IsWindows) {
258+
return e.HttpClient.ProcessId.Value;
259+
}
260+
261+
var psi = new ProcessStartInfo {
262+
FileName = "lsof",
263+
Arguments = $"-i :{e.ClientRemoteEndPoint.Port}",
264+
UseShellExecute = false,
265+
RedirectStandardOutput = true,
266+
CreateNoWindow = true
267+
};
268+
var proc = new Process {
269+
StartInfo = psi
270+
};
271+
proc.Start();
272+
var output = proc.StandardOutput.ReadToEnd();
273+
proc.WaitForExit();
274+
275+
var lines = output.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
276+
var matchingLine = lines.FirstOrDefault(l => l.Contains($"{e.ClientRemoteEndPoint.Port}->"));
277+
if (matchingLine is null) {
278+
return -1;
279+
}
280+
var pidString = Regex.Matches(matchingLine, @"^.*?\s+(\d+)")?.FirstOrDefault()?.Groups[1]?.Value;
281+
if (pidString is null) {
282+
return -1;
283+
}
284+
285+
var pid = -1;
286+
if (int.TryParse(pidString, out pid))
287+
{
288+
return pid;
289+
}
290+
else {
291+
return -1;
292+
}
293+
}
294+
295+
private bool IsProxiedProcess(TunnelConnectSessionEventArgs e) {
296+
// If no process names or IDs are specified, we proxy all processes
297+
if (!_config.WatchPids.Any() &&
298+
!_config.WatchProcessNames.Any()) {
299+
return true;
300+
}
301+
302+
var processId = GetProcessId(e);
303+
if (processId == -1) {
304+
return false;
305+
}
306+
307+
if (_config.WatchPids.Any() &&
308+
_config.WatchPids.Contains(processId)) {
309+
return true;
310+
}
311+
312+
if (_config.WatchProcessNames.Any()) {
313+
var processName = Process.GetProcessById(processId).ProcessName;
314+
if (_config.WatchProcessNames .Contains(processName)) {
315+
return true;
316+
}
317+
}
318+
319+
return false;
320+
}
321+
322+
async Task OnRequest(object sender, SessionEventArgs e) {
255323
var method = e.HttpClient.Request.Method.ToUpper();
256324
// The proxy does not intercept or alter OPTIONS requests
257325
if (method is not "OPTIONS" && IsProxiedHost(e.HttpClient.Request.RequestUri.Host)) {
@@ -276,6 +344,7 @@ private void HandleRequest(SessionEventArgs e) {
276344

277345
private bool IsProxiedHost(string hostName) => _hostsToWatch.Any(h => h.IsMatch(hostName));
278346

347+
279348
// Modify response
280349
async Task OnBeforeResponse(object sender, SessionEventArgs e) {
281350
// read response headers

msgraph-developer-proxy/ProxyHost.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ internal class ProxyHost {
1111
private Option<int?> _portOption;
1212
private Option<LogLevel?> _logLevelOption;
1313
private Option<bool?> _recordOption;
14+
private Option<IEnumerable<int>?> _watchPidsOption;
15+
private Option<IEnumerable<string>?> _watchProcessNamesOption;
1416
private static Option<string?>? _configFileOption;
1517

1618
private static bool _configFileResolved = false;
@@ -63,13 +65,23 @@ public ProxyHost() {
6365
});
6466

6567
_recordOption = new Option<bool?>("--record", "Use this option to record all request logs");
68+
69+
_watchPidsOption = new Option<IEnumerable<int>?>("--watch-pids", "The IDs of processes to watch for requests");
70+
_watchPidsOption.ArgumentHelpName = "pids";
71+
_watchPidsOption.AllowMultipleArgumentsPerToken = true;
72+
73+
_watchProcessNamesOption = new Option<IEnumerable<string>?>("--watch-process-names", "The names of processes to watch for requests");
74+
_watchProcessNamesOption.ArgumentHelpName = "processNames";
75+
_watchProcessNamesOption.AllowMultipleArgumentsPerToken = true;
6676
}
6777

6878
public RootCommand GetRootCommand() {
6979
var command = new RootCommand {
7080
_portOption,
7181
_logLevelOption,
7282
_recordOption,
83+
_watchPidsOption,
84+
_watchProcessNamesOption,
7385
// _configFileOption is set during the call to load
7486
// `ProxyCommandHandler.Configuration`. As such, it's always set here
7587
_configFileOption!
@@ -79,6 +91,6 @@ public RootCommand GetRootCommand() {
7991
return command;
8092
}
8193

82-
public ProxyCommandHandler GetCommandHandler(PluginEvents pluginEvents, ISet<Regex> urlsToWatch, ILogger logger) => new ProxyCommandHandler(_portOption, _logLevelOption, _recordOption, pluginEvents, urlsToWatch, logger);
94+
public ProxyCommandHandler GetCommandHandler(PluginEvents pluginEvents, ISet<Regex> urlsToWatch, ILogger logger) => new ProxyCommandHandler(_portOption, _logLevelOption, _recordOption, _watchPidsOption, _watchProcessNamesOption, pluginEvents, urlsToWatch, logger);
8395
}
8496

0 commit comments

Comments
 (0)