Suggest local interfaces in bind setting

This commit is contained in:
2dust
2026-11-06 15:19:31 +08:00
parent 2010477f38
commit 052f6f0fec
5 changed files with 99 additions and 11 deletions
+80
View File
@@ -0,0 +1,80 @@
namespace ServiceLib.Common;
public static class NetworkUtils
{
private static readonly HashSet<NetworkInterfaceType> _allowedPhysicalInterfaceTypes =
[
NetworkInterfaceType.Ethernet,
NetworkInterfaceType.Wireless80211,
NetworkInterfaceType.GigabitEthernet,
NetworkInterfaceType.FastEthernetFx,
NetworkInterfaceType.FastEthernetT,
];
private static readonly string[] _allowedPhysicalNameKeywords =
[
// Windows / Generic
"ethernet", "wlan", "wi-fi", "wifi",
// Linux
"eth", "enp", "ens", "eno", "enx", "wlp", "wlan",
// macOS
"en0", "en1", "en2", "airport",
// Chinese
"以太网", "无线", "局域网"
];
private static readonly string[] _virtualNameBlacklistKeywords =
[
// Generic
"virtual", "loopback", "loop back",
// Common virtual adapters
"hyper-v", "vmware", "virtualbox", "vbox", "docker", "veth", "virbr", "cni",
"flannel", "cali", "kube", "wintun", "wireguard", "zerotier", "tailscale", "utun",
// Chinese
"虚拟", "回环", "环回"
];
public static List<string> GetLocalNetworkInterfaceNames()
{
try
{
return NetworkInterface.GetAllNetworkInterfaces()
.Where(IsAllowedPhysicalInterface)
.Select(x => x.Name)
.Where(x => !string.IsNullOrWhiteSpace(x))
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(x => x)
.ToList();
}
catch
{
return [];
}
}
private static bool IsAllowedPhysicalInterface(NetworkInterface ni)
{
if (ni.OperationalStatus != OperationalStatus.Up)
{
return false;
}
var interfaceText = $"{ni.Name} {ni.Description}";
if (_virtualNameBlacklistKeywords.Any(keyword => interfaceText.Contains(keyword, StringComparison.OrdinalIgnoreCase)))
{
return false;
}
if (_allowedPhysicalInterfaceTypes.Contains(ni.NetworkInterfaceType))
{
return true;
}
return _allowedPhysicalNameKeywords.Any(keyword => interfaceText.Contains(keyword, StringComparison.OrdinalIgnoreCase));
}
}
@@ -53,7 +53,8 @@
Grid.Row="0"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}" />
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="0"
Grid.Column="2"
@@ -167,7 +168,8 @@
Grid.Row="9"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}" />
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="10"
@@ -180,7 +182,8 @@
Grid.Row="10"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}" />
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="12"
@@ -437,12 +440,13 @@
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsBindInterface}" />
<TextBox
x:Name="txtbindInterface"
<ComboBox
x:Name="cmbbindInterface"
Grid.Row="22"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}" />
Width="300"
Margin="{StaticResource Margin4}"
IsEditable="True" />
<TextBlock
Grid.Row="22"
Grid.Column="2"
@@ -463,6 +467,7 @@
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
PlaceholderText="0.0.0.0" />
<TextBlock
Grid.Row="23"
@@ -5,7 +5,7 @@ namespace v2rayN.Desktop.Views;
public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
{
private static Config _config;
private static Config _config;
public OptionSettingWindow()
{
@@ -59,6 +59,7 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
cmbRoutingRulesSourceUrl.ItemsSource = Global.RoutingRulesSources;
cmbIPAPIUrl.ItemsSource = Global.IPAPIUrls;
cmbRootCertificateProvider.ItemsSource = Global.RootCertProviders;
cmbbindInterface.ItemsSource = NetworkUtils.GetLocalNetworkInterfaceNames().AppendEmpty();
cmbMainGirdOrientation.ItemsSource = Utils.GetEnumNames<EGirdOrientation>();
@@ -81,7 +82,7 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
this.Bind(ViewModel, vm => vm.Loglevel, v => v.cmbloglevel.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DefFingerprint, v => v.cmbdefFingerprint.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DefUserAgent, v => v.cmbdefUserAgent.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.BindInterface, v => v.txtbindInterface.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.BindInterface, v => v.cmbbindInterface.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Mux4RayConcurrency, v => v.txtmux4RayConcurrency.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Mux4RayXudpConcurrency, v => v.txtmux4RayXudpConcurrency.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Mux4RayXudpProxyUDP443, v => v.cmbmux4RayXudpProxyUDP443.SelectedValue).DisposeWith(disposables);
+3 -2
View File
@@ -497,13 +497,14 @@
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsBindInterface}" />
<TextBox
<ComboBox
x:Name="txtbindInterface"
Grid.Row="22"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin8}"
Style="{StaticResource DefTextBox}" />
IsEditable="True"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="22"
Grid.Column="2"
@@ -55,6 +55,7 @@ public partial class OptionSettingWindow
cmbRoutingRulesSourceUrl.ItemsSource = Global.RoutingRulesSources;
cmbIPAPIUrl.ItemsSource = Global.IPAPIUrls;
cmbRootCertificateProvider.ItemsSource = Global.RootCertProviders;
txtbindInterface.ItemsSource = NetworkUtils.GetLocalNetworkInterfaceNames().AppendEmpty();
cmbMainGirdOrientation.ItemsSource = Utils.GetEnumNames<EGirdOrientation>();