Offer Tunnel as a network mode in Launchpad

Machine settings and New Machine list Tunnel next to NAT, Bridged and
None, with a line saying what it does. The inspector showed a tunnel
machine's network as None; it now says Tunnel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lakr
2026-10-01 11:21:45 +09:00
co-authored by Claude Opus 5.5
parent 17503c898c
commit 55668d450e
4 changed files with 80 additions and 0 deletions
@@ -1,6 +1,74 @@
{
"sourceLanguage" : "en",
"strings" : {
"Tunnel" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Tunnel"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "トンネル"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "터널"
}
},
"vi" : {
"stringUnit" : {
"state" : "translated",
"value" : "Đường hầm"
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "隧道"
}
}
}
},
"Traffic leaves through this Mac's own connections, so it follows the Mac's VPN." : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Traffic leaves through this Mac's own connections, so it follows the Mac's VPN."
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "通信はこの Mac 自身の接続から送られるため、Mac の VPN を経由します。"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "트래픽이 이 Mac의 자체 연결로 나가므로 Mac의 VPN을 따릅니다."
}
},
"vi" : {
"stringUnit" : {
"state" : "translated",
"value" : "Lưu lượng đi qua các kết nối của chính máy Mac này, nên sẽ đi theo VPN của máy Mac."
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "流量从这台 Mac 自己的连接发出,因此会经过 Mac 的 VPN。"
}
}
}
},
"" : {
},
@@ -107,6 +107,7 @@ nonisolated struct VPhoneLaunchpadMachine: Decodable, Hashable, Identifiable, Se
switch network.mode {
case "nat": String(localized: "NAT")
case "bridged": network.bridgeInterface.map { String(localized: "Bridged to \($0)") } ?? String(localized: "Bridged")
case "tunnel": String(localized: "Tunnel")
case "hostOnly": String(localized: "Host only")
default: String(localized: "None")
}
@@ -46,11 +46,16 @@ struct VPhoneLaunchpadMachineSettingsView: View {
Picker("Mode", selection: $network) {
Text("NAT").tag("nat")
Text("Bridged").tag("bridged")
Text("Tunnel").tag("tunnel")
Text("None").tag("none")
}
if network == "bridged" {
TextField("Interface", text: $bridgeInterface, prompt: Text("First available"))
}
if network == "tunnel" {
Text("Traffic leaves through this Mac's own connections, so it follows the Mac's VPN.")
.foregroundStyle(.secondary)
}
} header: {
Text("Network")
} footer: {
@@ -18,6 +18,7 @@ struct VPhoneLaunchpadNewMachineAdvancedView: View {
static func networkTitle(_ mode: String) -> String {
switch mode {
case "bridged": String(localized: "Bridged")
case "tunnel": String(localized: "Tunnel")
case "none": String(localized: "None")
default: String(localized: "NAT")
}
@@ -30,8 +31,13 @@ struct VPhoneLaunchpadNewMachineAdvancedView: View {
Picker("Mode", selection: $network) {
Text("NAT").tag("nat")
Text("Bridged").tag("bridged")
Text("Tunnel").tag("tunnel")
Text("None").tag("none")
}
if network == "tunnel" {
Text("Traffic leaves through this Mac's own connections, so it follows the Mac's VPN.")
.foregroundStyle(.secondary)
}
}
patchSection