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);