From 4642f9ed1d8d2a60068c51cb39ed38d785554da9 Mon Sep 17 00:00:00 2001 From: Angelo Failla Date: Sat, 11 Oct 2025 08:53:08 +0100 Subject: [PATCH] feat: Allow specifying vmnet network UUID to disable DHCP (on vmnet.host network only) This commit introduces a new `--vmnet-network-uuid` command-line option to allow setting the `vmnet_network_identifier_key` for vmnet. This property is only applicable to a vmnet_interface in VMNET_HOST_MODE. If this property is set, the vmnet_interface is added to an isolated network with the specified identifier. No DHCP service is provided on this network. This is useful for certain applications where the users need an isolated network and are running their own dhcp to assign IPs in such network. See issue [#139](https://github.com/lima-vm/socket_vmnet/issues/139) Signed-off-by: Angelo Failla --- README.md | 57 +++++++++++++++++++++++++++++++++++-------------------- cli.c | 40 +++++++++++++++++++++++++------------- cli.h | 2 ++ main.c | 5 +++++ 4 files changed, 70 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index e1a5978..4132d81 100644 --- a/README.md +++ b/README.md @@ -12,27 +12,28 @@ Unlike `vde_vmnet`, `socket_vmnet` does not depend on VDE. -- [Install](#install) - - [From binary](#from-binary) - - [From source](#from-source) - - [From Homebrew](#from-homebrew) - - [From MacPorts](#from-macports) -- [Usage](#usage) - - [QEMU](#qemu) - - [Lima](#lima) -- [Advanced usage](#advanced-usage) - - [Multi VM](#multi-vm) - - [Bridged mode](#bridged-mode) -- [FAQs](#faqs) - - [Why does `socket_vmnet` require root?](#why-does-socket_vmnet-require-root) - - [Is it possible to run `socket_vmnet` with SETUID?](#is-it-possible-to-run-socket_vmnet-with-setuid) + - [Install](#install) + - [From binary](#from-binary) + - [From source](#from-source) + - [From Homebrew](#from-homebrew) + - [From MacPorts](#from-macports) + - [Usage](#usage) + - [QEMU](#qemu) + - [Lima](#lima) + - [Advanced usage](#advanced-usage) + - [Multi VM](#multi-vm) + - [Bridged mode](#bridged-mode) + - [FAQs](#faqs) + - [Why does `socket_vmnet` require root?](#why-does-socket_vmnet-require-root) + - [Is it possible to run `socket_vmnet` with SETUID?](#is-it-possible-to-run-socket_vmnet-with-setuid) - [How is socket_vmnet related to vde_vmnet?](#how-is-socket_vmnet-related-to-vde_vmnet) - - [How is socket_vmnet related to QEMU-builtin vmnet support?](#how-is-socket_vmnet-related-to-qemu-builtin-vmnet-support) - - [How to use static IP addresses?](#how-to-use-static-ip-addresses) - - [How to reserve DHCP addresses?](#how-to-reserve-dhcp-addresses) - - [IP address is not assigned](#ip-address-is-not-assigned) -- [Links](#links) -- [Troubleshooting](#troubleshooting) + - [How is socket_vmnet related to QEMU-builtin vmnet support?](#how-is-socket_vmnet-related-to-qemu-builtin-vmnet-support) + - [How to use static IP addresses?](#how-to-use-static-ip-addresses) + - [How to reserve DHCP addresses?](#how-to-reserve-dhcp-addresses) + - [IP address is not assigned](#ip-address-is-not-assigned) + - [How to setup a vmnet host network without DHCP?](#how-to-setup-a-vmnet-host-network-without-dhcp) + - [Links](#links) + - [Troubleshooting](#troubleshooting) @@ -122,7 +123,7 @@ Run the following command to start the daemon: sudo /opt/socket_vmnet/bin/socket_vmnet --vmnet-gateway=192.168.105.1 /var/run/socket_vmnet ``` -> [!TIP] +> [!TIP] > `sudo make install` is also available in addition to `sudo make install.bin`. > The former one installs the launchd service (see below) too. @@ -430,6 +431,20 @@ sudo /usr/libexec/ApplicationFirewall/socketfilterfw --add /usr/libexec/bootpd /usr/libexec/ApplicationFirewall/socketfilterfw --unblock /usr/libexec/bootpd ``` +### How to setup a vmnet host network without DHCP? + +Some users may need to disable the vmnet framework's DHCP for various scenarios, such as: + +- Create a host network where all VMs have static IPs. +- Run a custom DHCP server on one VM to assign IPs to others on the same network. + +Disabling macOS DHCP only works in `--vmnet-mode=host` if you provide a `--vmnet-network-idenfitier`. +For example, to create a host network without DHCP on `socket_vmnet`: + +```bash +sudo /opt/socket_vmnet/bin/socket_vmnet --vmnet-mode=host --vmnet-network-identifier=$(uuidgen) +``` + ## Links - https://developer.apple.com/documentation/vmnet diff --git a/cli.c b/cli.c index 4aeccc0..feb36c6 100644 --- a/cli.c +++ b/cli.c @@ -48,6 +48,12 @@ static void print_usage(const char *argv0) { "specified\n"); printf("--vmnet-interface-id=UUID vmnet interface ID (default: " "random)\n"); + printf("--vmnet-network-identifier=UUID The identifier(uuid) to uniquely identify the network. \n" + " This property is only applicable to a vmnet_interface\n" + " in VMNET_HOST_MODE.\n" + " If this property is set, the vmnet_interface is added to \n" + " an isolated network with the specified\n" + " identifier. No DHCP service is provided on this network.\n"); printf("--vmnet-nat66-prefix=PREFIX:: The IPv6 prefix to use with " "shared mode.\n"); printf(" The prefix must be a ULA i.e. " @@ -72,6 +78,7 @@ enum { CLI_OPT_VMNET_MASK, CLI_OPT_VMNET_INTERFACE_ID, CLI_OPT_VMNET_NAT66_PREFIX, + CLI_OPT_VMNET_NETWORK_IDENTIFIER, }; struct cli_options *cli_options_parse(int argc, char *argv[]) { @@ -82,18 +89,19 @@ struct cli_options *cli_options_parse(int argc, char *argv[]) { } const struct option longopts[] = { - {"socket-group", required_argument, NULL, CLI_OPT_SOCKET_GROUP }, - {"vmnet-mode", required_argument, NULL, CLI_OPT_VMNET_MODE }, - {"vmnet-interface", required_argument, NULL, CLI_OPT_VMNET_INTERFACE }, - {"vmnet-gateway", required_argument, NULL, CLI_OPT_VMNET_GATEWAY }, - {"vmnet-dhcp-end", required_argument, NULL, CLI_OPT_VMNET_DHCP_END }, - {"vmnet-mask", required_argument, NULL, CLI_OPT_VMNET_MASK }, - {"vmnet-interface-id", required_argument, NULL, CLI_OPT_VMNET_INTERFACE_ID}, - {"vmnet-nat66-prefix", required_argument, NULL, CLI_OPT_VMNET_NAT66_PREFIX}, - {"pidfile", required_argument, NULL, 'p' }, - {"help", no_argument, NULL, 'h' }, - {"version", no_argument, NULL, 'v' }, - {0, 0, 0, 0 }, + {"socket-group", required_argument, NULL, CLI_OPT_SOCKET_GROUP }, + {"vmnet-mode", required_argument, NULL, CLI_OPT_VMNET_MODE }, + {"vmnet-interface", required_argument, NULL, CLI_OPT_VMNET_INTERFACE }, + {"vmnet-gateway", required_argument, NULL, CLI_OPT_VMNET_GATEWAY }, + {"vmnet-dhcp-end", required_argument, NULL, CLI_OPT_VMNET_DHCP_END }, + {"vmnet-mask", required_argument, NULL, CLI_OPT_VMNET_MASK }, + {"vmnet-interface-id", required_argument, NULL, CLI_OPT_VMNET_INTERFACE_ID }, + {"vmnet-nat66-prefix", required_argument, NULL, CLI_OPT_VMNET_NAT66_PREFIX }, + {"vmnet-network-identifier", required_argument, NULL, CLI_OPT_VMNET_NETWORK_IDENTIFIER}, + {"pidfile", required_argument, NULL, 'p' }, + {"help", no_argument, NULL, 'h' }, + {"version", no_argument, NULL, 'v' }, + {0, 0, 0, 0 }, }; int opt = 0; while ((opt = getopt_long(argc, argv, "hvp:", longopts, NULL)) != -1) { @@ -134,6 +142,12 @@ struct cli_options *cli_options_parse(int argc, char *argv[]) { case CLI_OPT_VMNET_NAT66_PREFIX: res->vmnet_nat66_prefix = strdup(optarg); break; + case CLI_OPT_VMNET_NETWORK_IDENTIFIER: + if (uuid_parse(optarg, res->vmnet_network_identifier) < 0) { + ERRORF("Failed to parse network identifier UUID \"%s\"", optarg); + goto error; + } + break; case 'p': res->pidfile = strdup(optarg); break; @@ -191,7 +205,7 @@ struct cli_options *cli_options_parse(int argc, char *argv[]) { goto error; } if (res->vmnet_gateway == NULL) { - if (res->vmnet_mode != VMNET_BRIDGED_MODE) { + if (res->vmnet_mode != VMNET_BRIDGED_MODE && res->vmnet_mode != VMNET_HOST_MODE) { WARN("--vmnet-gateway=IP should be explicitly specified to " "avoid conflicting with other applications"); } diff --git a/cli.h b/cli.h index f79fe00..8d67c92 100644 --- a/cli.h +++ b/cli.h @@ -20,6 +20,8 @@ struct cli_options { char *vmnet_mask; // --vmnet-interface-id, corresponds to vmnet_interface_id_key uuid_t vmnet_interface_id; + // --vmnet-network-identifier, corresponds to vmnet_network_identifier_key + uuid_t vmnet_network_identifier; // --vmnet-nat66-prefix, corresponds to vmnet_nat66_prefix_key char *vmnet_nat66_prefix; // -p, --pidfile; writes pidfile using permissions of socket_vmnet diff --git a/main.c b/main.c index 2506674..890e680 100644 --- a/main.c +++ b/main.c @@ -230,6 +230,11 @@ static interface_ref start(struct state *state, struct cli_options *cliopt) { INFOF("Using network interface \"%s\"", cliopt->vmnet_interface); xpc_dictionary_set_string(dict, vmnet_shared_interface_name_key, cliopt->vmnet_interface); } + + if (!uuid_is_null(cliopt->vmnet_network_identifier)) { + xpc_dictionary_set_uuid(dict, vmnet_network_identifier_key, cliopt->vmnet_network_identifier); + } + if (cliopt->vmnet_gateway != NULL) { xpc_dictionary_set_string(dict, vmnet_start_address_key, cliopt->vmnet_gateway); xpc_dictionary_set_string(dict, vmnet_end_address_key, cliopt->vmnet_dhcp_end);