diff --git a/PortProxyTool/PortProxy.cs b/PortProxyTool/PortProxy.cs new file mode 100644 index 0000000..afb82ac --- /dev/null +++ b/PortProxyTool/PortProxy.cs @@ -0,0 +1,150 @@ +using System.Diagnostics; +using System.Text; + +namespace PortProxyTool; + +public static class PortProxy +{ + public static PortProxyItem[] GetPortProxies() + { + var output = ExecuteCommand("show all"); + var lines = output.ToList(); + var items = new List(); + + if (output.Length <= 0) return items.ToArray(); + PortProxyType? currentType = null; + for (var i = 0; i < lines.Count; i++) + { + var line = lines[i]; + var type = CheckPosition(line); + if (type != null) + { + currentType = type.Value; + if (i + 1 >= lines.Count) continue; + lines.RemoveAt(i + 1); + lines.RemoveAt(i + 1); + } + else if (currentType != null) + { + var values = line.Split([' '], StringSplitOptions.RemoveEmptyEntries); + if (values.Length < 2) continue; + var listenAddress = values[0]; + if (!ushort.TryParse(values[1], out var listenPort)) + { + Remove(type, listenAddress, values[1]); + continue; + } + + string? targetAddress = null; + ushort? targetPort = null; + if (values.Length >= 4) + { + targetAddress = values[2]; + if (!ushort.TryParse(values[3], out var targetPortParse)) + targetPort = null; + else + targetPort = targetPortParse; + } + + items.Add(new PortProxyItem + { + Type = currentType.Value, + ListenAddress = listenAddress, + ListenPort = listenPort, + TargetAddress = targetAddress, + TargetPort = targetPort + }); + } + } + + return items.ToArray(); + } + + public static string Remove(PortProxyType? type, string listenAddress, string listenPort, string protocol = "tcp") + { + var output = + ExecuteCommand( + $"delete {type?.ToString().ToLower()} listenaddress=\"{listenAddress}\" listenport=\"{listenPort}\" protocol=\"{protocol}\""); + return output.Length > 0 ? output[0] : string.Empty; + } + + public static string Remove(PortProxyItem item) + { + return Remove(item.Type, item.ListenAddress, item.ListenPort.ToString()); + } + + public static string Add(PortProxyType type, string listenAddress, ushort listenPort, string connectAddress, ushort connectPort, string protocol = "tcp") + { + var output = + ExecuteCommand( + $"delete {type.ToString().ToLower()} listenaddress=\"{listenAddress}\" listenport=\"{listenPort}\" connectAddress=\"{connectAddress}\" connectPort=\"{connectPort}\" protocol=\"{protocol}\""); + return output.Length > 0 ? output[0] : string.Empty; + } + + public static string Add(PortProxyItem item) + { + return Add(item.Type, item.ListenAddress, item.ListenPort, item.TargetAddress!, item.TargetPort ?? 0); + } + + public static string Set(PortProxyType type, string listenAddress, ushort listenPort, string connectAddress, ushort connectPort, string protocol = "tcp") + { + var output = + ExecuteCommand( + $"set {type.ToString().ToLower()} listenaddress=\"{listenAddress}\" listenport=\"{listenPort}\" connectAddress=\"{connectAddress}\" connectPort=\"{connectPort}\" protocol=\"{protocol}\""); + return output.Length > 0 ? output[0] : string.Empty; + } + + public static string Set(PortProxyItem item) + { + return Set(item.Type, item.ListenAddress, item.ListenPort, item.TargetAddress!, item.TargetPort ?? 0); + } + + private static string[] ExecuteCommand(string command) + { + var startInfo = new ProcessStartInfo + { + FileName = "netsh", + Arguments = $"interface portproxy {command}", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8 + }; + + using var process = new Process(); + process.StartInfo = startInfo; + process.Start(); + var output = process.StandardOutput.ReadToEnd(); + var error = process.StandardError.ReadToEnd(); + process.WaitForExit(); + + var lines = new List(); + if (!string.IsNullOrEmpty(error)) + lines.AddRange(error.Split([Environment.NewLine], StringSplitOptions.RemoveEmptyEntries)); + lines.AddRange(output.Split([Environment.NewLine], StringSplitOptions.RemoveEmptyEntries)); + + return lines.ToArray(); + } + + private static PortProxyType? CheckPosition(string input) + { + var ipv4Index = input.IndexOf("ipv4", StringComparison.Ordinal); + var ipv6Index = input.IndexOf("ipv6", StringComparison.Ordinal); + + if (ipv4Index != -1 && ipv6Index != -1) + { + if (ipv4Index < ipv6Index) return PortProxyType.V4ToV6; + + if (ipv4Index > ipv6Index) return PortProxyType.V6ToV4; + + return null; + } + + if (ipv4Index != -1) return PortProxyType.V4ToV4; + + if (ipv6Index != -1) return PortProxyType.V6ToV6; + + return null; + } +} \ No newline at end of file diff --git a/PortProxyTool/PortProxyItem.cs b/PortProxyTool/PortProxyItem.cs new file mode 100644 index 0000000..aeb5831 --- /dev/null +++ b/PortProxyTool/PortProxyItem.cs @@ -0,0 +1,10 @@ +namespace PortProxyTool; + +public class PortProxyItem +{ + public required PortProxyType Type { get; set; } + public required string ListenAddress { get; set; } + public required ushort ListenPort { get; set; } + public required string? TargetAddress { get; set; } + public required ushort? TargetPort { get; set; } +} \ No newline at end of file diff --git a/PortProxyTool/PortProxyType.cs b/PortProxyTool/PortProxyType.cs new file mode 100644 index 0000000..1f4ce77 --- /dev/null +++ b/PortProxyTool/PortProxyType.cs @@ -0,0 +1,9 @@ +namespace PortProxyTool; + +public enum PortProxyType +{ + V4ToV4, + V4ToV6, + V6ToV6, + V6ToV4 +} \ No newline at end of file