From 07d3d3d3c18993a9db6a46a500b2105dfa2f0665 Mon Sep 17 00:00:00 2001 From: Nikolay Edigaryev Date: Wed, 8 Jan 2025 00:17:07 +0400 Subject: [PATCH 1/5] tart run: introduce --net-softnet-expose --- Sources/tart/Commands/Run.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Sources/tart/Commands/Run.swift b/Sources/tart/Commands/Run.swift index 3f067cae..8d2fa96a 100644 --- a/Sources/tart/Commands/Run.swift +++ b/Sources/tart/Commands/Run.swift @@ -190,6 +190,9 @@ struct Run: AsyncParsableCommand { @Option(help: ArgumentHelp("Comma-separated list of CIDRs to allow the traffic to when using Softnet isolation\n(e.g. --net-softnet-allow=192.168.0.0/24)", valueName: "comma-separated CIDRs")) var netSoftnetAllow: String? + @Option(help: ArgumentHelp("Comma-separated list of TCP ports to expose (e.g. --net-softnet-expose 2222:22,8080:80)", valueName: "comma-separated port specifications")) + var netSoftnetExpose: String? + @Flag(help: ArgumentHelp("Restrict network access to the host-only network")) var netHost: Bool = false @@ -527,6 +530,10 @@ struct Run: AsyncParsableCommand { softnetExtraArguments += ["--allow", netSoftnetAllow] } + if let netSoftnetExpose = netSoftnetExpose { + softnetExtraArguments += ["--expose", netSoftnetExpose] + } + if netSoftnet { let config = try VMConfig.init(fromURL: vmDir.configURL) From d5c96aaeff2c85ba90cea3caa86ff437da704b32 Mon Sep 17 00:00:00 2001 From: Nikolay Edigaryev Date: Wed, 8 Jan 2025 11:54:21 +0400 Subject: [PATCH 2/5] --net-softnet-expose: add discussion --- Sources/tart/Commands/Run.swift | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Sources/tart/Commands/Run.swift b/Sources/tart/Commands/Run.swift index 8d2fa96a..2214b1cd 100644 --- a/Sources/tart/Commands/Run.swift +++ b/Sources/tart/Commands/Run.swift @@ -190,7 +190,13 @@ struct Run: AsyncParsableCommand { @Option(help: ArgumentHelp("Comma-separated list of CIDRs to allow the traffic to when using Softnet isolation\n(e.g. --net-softnet-allow=192.168.0.0/24)", valueName: "comma-separated CIDRs")) var netSoftnetAllow: String? - @Option(help: ArgumentHelp("Comma-separated list of TCP ports to expose (e.g. --net-softnet-expose 2222:22,8080:80)", valueName: "comma-separated port specifications")) + @Option(help: ArgumentHelp("Comma-separated list of TCP ports to expose (e.g. --net-softnet-expose 2222:22,8080:80)", discussion: """ + Options are comma-separated and are as follows: + + * EXTERNAL_PORT:INTERNAL_PORT — forward TCP traffic from the EXTERNAL_PORT on a host's egress interface (automatically detected and could be Wi-Fi, Ethernet and a VPN interface) to the INTERNAL_PORT on guest's IP (as reported by "tart ip") + + Note that your software should either listen on 0.0.0.0 inside of a VM or on an IP address assigned to that VM for the port forwarding to work correctly. + """, valueName: "comma-separated port specifications")) var netSoftnetExpose: String? @Flag(help: ArgumentHelp("Restrict network access to the host-only network")) From d7fef446f0062057514e705cf3032b00ee85b13c Mon Sep 17 00:00:00 2001 From: Nikolay Edigaryev Date: Wed, 8 Jan 2025 16:11:52 +0400 Subject: [PATCH 3/5] --net-softnet-expose: add a note about Softnet restrictions ...and how to disable them. --- Sources/tart/Commands/Run.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/tart/Commands/Run.swift b/Sources/tart/Commands/Run.swift index 2214b1cd..9fca0bc9 100644 --- a/Sources/tart/Commands/Run.swift +++ b/Sources/tart/Commands/Run.swift @@ -196,6 +196,8 @@ struct Run: AsyncParsableCommand { * EXTERNAL_PORT:INTERNAL_PORT — forward TCP traffic from the EXTERNAL_PORT on a host's egress interface (automatically detected and could be Wi-Fi, Ethernet and a VPN interface) to the INTERNAL_PORT on guest's IP (as reported by "tart ip") Note that your software should either listen on 0.0.0.0 inside of a VM or on an IP address assigned to that VM for the port forwarding to work correctly. + + Another thing to keep in mind is that regular Softnet restrictions will still apply even to port forwarding. So if you're planning to access your VM from LAN, and your LAN is 192.168.0.0/24, for example, then add --net-softnet-allow=192.168.0.0/24. If you only need port forwarding, to completely disable Softnet restrictions you can use --net-softnet-allow=0.0.0.0/0. """, valueName: "comma-separated port specifications")) var netSoftnetExpose: String? From 51cb040a4c581302b2f3595039d2f032e932922d Mon Sep 17 00:00:00 2001 From: Nikolay Edigaryev Date: Fri, 10 Jan 2025 01:45:51 +0400 Subject: [PATCH 4/5] =?UTF-8?q?LAN=20=E2=86=92=20local=20network?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sources/tart/Commands/Run.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/tart/Commands/Run.swift b/Sources/tart/Commands/Run.swift index 9fca0bc9..4271dbbf 100644 --- a/Sources/tart/Commands/Run.swift +++ b/Sources/tart/Commands/Run.swift @@ -197,7 +197,7 @@ struct Run: AsyncParsableCommand { Note that your software should either listen on 0.0.0.0 inside of a VM or on an IP address assigned to that VM for the port forwarding to work correctly. - Another thing to keep in mind is that regular Softnet restrictions will still apply even to port forwarding. So if you're planning to access your VM from LAN, and your LAN is 192.168.0.0/24, for example, then add --net-softnet-allow=192.168.0.0/24. If you only need port forwarding, to completely disable Softnet restrictions you can use --net-softnet-allow=0.0.0.0/0. + Another thing to keep in mind is that regular Softnet restrictions will still apply even to port forwarding. So if you're planning to access your VM from local network, and your local network is 192.168.0.0/24, for example, then add --net-softnet-allow=192.168.0.0/24. If you only need port forwarding, to completely disable Softnet restrictions you can use --net-softnet-allow=0.0.0.0/0. """, valueName: "comma-separated port specifications")) var netSoftnetExpose: String? From c6634e162132cd763d629344fc3e6de715d34bf1 Mon Sep 17 00:00:00 2001 From: Nikolay Edigaryev Date: Fri, 10 Jan 2025 02:53:44 +0400 Subject: [PATCH 5/5] Better clarify what --net-softnet does And how --net-softnet-allow can change that behavior. --- Sources/tart/Commands/Run.swift | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/Sources/tart/Commands/Run.swift b/Sources/tart/Commands/Run.swift index 4271dbbf..d02dc820 100644 --- a/Sources/tart/Commands/Run.swift +++ b/Sources/tart/Commands/Run.swift @@ -183,11 +183,29 @@ struct Run: AsyncParsableCommand { """, valueName: "interface name")) var netBridged: [String] = [] - @Flag(help: ArgumentHelp("Use software networking instead of the default shared (NAT) networking", - discussion: "Learn how to configure Softnet for use with Tart here: https://github.com/cirruslabs/softnet")) + @Flag(help: ArgumentHelp("Use software networking provided by Softnet instead of the default shared (NAT) networking", + discussion: """ + Softnet provides better network isolation and alleviates DHCP shortage on production systems. Tart invokes Softnet when this option is specified as a sub-process and communicates with it over socketpair(2). + + It is essentially a userspace packet filter which restricts the VM networking and prevents a class of security issues, such as ARP spoofing. By default, the VM will only be able to: + + * send traffic from its own MAC-address + * send traffic from the IP-address assigned to it by the DHCP + * send traffic to globally routable IPv4 addresses + * send traffic to gateway IP of the vmnet bridge (this would normally be \"bridge100\" interface) + * receive any incoming traffic + + In addition, Softnet tunes macOS built-in DHCP server to decrease its lease time from the default 86,400 seconds (one day) to 600 seconds (10 minutes). This is especially important when you use Tart to clone and run a lot of ephemeral VMs over a period of one day. + + More on Softnet here: https://github.com/cirruslabs/softnet + """)) var netSoftnet: Bool = false - @Option(help: ArgumentHelp("Comma-separated list of CIDRs to allow the traffic to when using Softnet isolation\n(e.g. --net-softnet-allow=192.168.0.0/24)", valueName: "comma-separated CIDRs")) + @Option(help: ArgumentHelp("Comma-separated list of CIDRs to allow the traffic to when using Softnet isolation\n(e.g. --net-softnet-allow=192.168.0.0/24)", discussion: """ + This option allows you bypass the private IPv4 address space restrctions imposed by --net-softnet. + + For example, you can allow the VM to communicate with the local network with e.g. --net-softnet-allow=10.0.0.0/16 or to completely disable the destination based restrictions with --net-softnet-allow=0.0.0.0/0. + """, valueName: "comma-separated CIDRs")) var netSoftnetAllow: String? @Option(help: ArgumentHelp("Comma-separated list of TCP ports to expose (e.g. --net-softnet-expose 2222:22,8080:80)", discussion: """