diff --git a/v2rayN/ServiceLib.Tests/CoreConfig/Singbox/CoreConfigSingboxServiceTests.cs b/v2rayN/ServiceLib.Tests/CoreConfig/Singbox/CoreConfigSingboxServiceTests.cs index 2f12d22f..158ba239 100644 --- a/v2rayN/ServiceLib.Tests/CoreConfig/Singbox/CoreConfigSingboxServiceTests.cs +++ b/v2rayN/ServiceLib.Tests/CoreConfig/Singbox/CoreConfigSingboxServiceTests.cs @@ -54,6 +54,29 @@ public class CoreConfigSingboxServiceTests cfg.inbounds.Should().Contain(i => i.type == "tun"); } + [Fact] + public void GenerateClientConfigContent_BindInterface_ShouldUseDialBindInterface() + { + var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box); + config.CoreBasicItem.BindInterface = "eth0"; + CoreConfigTestFactory.BindAppManagerConfig(config); + + var node = CoreConfigTestFactory.CreateVmessNode(ECoreType.sing_box); + var context = CoreConfigTestFactory.CreateContext(config, node, ECoreType.sing_box) with + { + IsTunEnabled = true, + }; + + var result = new CoreConfigSingboxService(context).GenerateClientConfigContent(); + + result.Success.Should().BeTrue($"ret msg: {result.Msg}"); + var cfg = JsonUtils.Deserialize(result.Data!.ToString())!; + var proxy = cfg.outbounds.First(o => o.tag == Global.ProxyTag); + + proxy.bind_interface.Should().Be("eth0"); + proxy.detour.Should().BeNullOrEmpty(); + } + [Fact] public void GenerateClientConfigContent_PolicyGroup_ShouldExpandChildrenAndBuildSelector() { diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxConfigTemplateService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxConfigTemplateService.cs index c081fbe3..4fffe27c 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxConfigTemplateService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxConfigTemplateService.cs @@ -72,7 +72,7 @@ public partial class CoreConfigSingboxService } foreach (var outbound in _coreConfig.outbounds ?? []) { - outbound.detour = ShouldBindNet(outbound) ? bindInterface : null; + outbound.bind_interface = ShouldBindNet(outbound) ? bindInterface : null; } } diff --git a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml.cs index ab58081d..f00dbe36 100644 --- a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml.cs @@ -77,6 +77,7 @@ public partial class OptionSettingWindow : WindowBase this.Bind(ViewModel, vm => vm.defAllowInsecure, v => v.togdefAllowInsecure.IsChecked).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.sendThrough, v => v.txtsendThrough.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.mux4SboxProtocol, v => v.cmbmux4SboxProtocol.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.enableCacheFile4Sbox, v => v.togenableCacheFile4Sbox.IsChecked).DisposeWith(disposables);