Skip to content

Commit b6652cf

Browse files
support for apple 26 no dhcp
1 parent 8701ef4 commit b6652cf

3 files changed

Lines changed: 95 additions & 32 deletions

File tree

cli.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ static void print_usage(const char *argv0) {
6363
printf(" The prefix must be a ULA i.e. "
6464
"start with fd00::/8.\n");
6565
printf(" (default: random)\n");
66+
printf("--vmnet-disable-dhcp disable the vmnet DHCP server "
67+
"(requires macOS 26;\n");
68+
printf(" lets an external DHCP server own "
69+
"the subnet)\n");
6670
printf("-p, --pidfile=PIDFILE save pid to PIDFILE\n");
6771
printf("-h, --help display this help and exit\n");
6872
printf("-v, --version display version information and "
@@ -83,6 +87,7 @@ enum {
8387
CLI_OPT_VMNET_INTERFACE_ID,
8488
CLI_OPT_VMNET_NAT66_PREFIX,
8589
CLI_OPT_VMNET_NETWORK_IDENTIFIER,
90+
CLI_OPT_VMNET_DISABLE_DHCP,
8691
};
8792

8893
struct cli_options *cli_options_parse(int argc, char *argv[]) {
@@ -102,6 +107,7 @@ struct cli_options *cli_options_parse(int argc, char *argv[]) {
102107
{"vmnet-interface-id", required_argument, NULL, CLI_OPT_VMNET_INTERFACE_ID },
103108
{"vmnet-nat66-prefix", required_argument, NULL, CLI_OPT_VMNET_NAT66_PREFIX },
104109
{"vmnet-network-identifier", required_argument, NULL, CLI_OPT_VMNET_NETWORK_IDENTIFIER},
110+
{"vmnet-disable-dhcp", no_argument, NULL, CLI_OPT_VMNET_DISABLE_DHCP },
105111
{"pidfile", required_argument, NULL, 'p' },
106112
{"help", no_argument, NULL, 'h' },
107113
{"version", no_argument, NULL, 'v' },
@@ -152,6 +158,9 @@ struct cli_options *cli_options_parse(int argc, char *argv[]) {
152158
goto error;
153159
}
154160
break;
161+
case CLI_OPT_VMNET_DISABLE_DHCP:
162+
res->vmnet_disable_dhcp = true;
163+
break;
155164
case 'p':
156165
res->pidfile = strdup(optarg);
157166
break;

cli.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ struct cli_options {
2424
uuid_t vmnet_network_identifier;
2525
// --vmnet-nat66-prefix, corresponds to vmnet_nat66_prefix_key
2626
char *vmnet_nat66_prefix;
27+
// --vmnet-disable-dhcp; disables the vmnet DHCP server (requires macOS 26)
28+
bool vmnet_disable_dhcp;
2729
// -p, --pidfile; writes pidfile using permissions of socket_vmnet
2830
char *pidfile;
2931
// arg

main.c

Lines changed: 84 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -224,48 +224,100 @@ static void on_vmnet_packets_available(interface_ref iface, int64_t estim_count,
224224

225225
static interface_ref start(struct state *state, struct cli_options *cliopt) {
226226
INFOF("Initializing vmnet.framework (mode %d)", cliopt->vmnet_mode);
227-
xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
228-
xpc_dictionary_set_uint64(dict, vmnet_operation_mode_key, cliopt->vmnet_mode);
229-
if (cliopt->vmnet_interface != NULL) {
230-
INFOF("Using network interface \"%s\"", cliopt->vmnet_interface);
231-
xpc_dictionary_set_string(dict, vmnet_shared_interface_name_key, cliopt->vmnet_interface);
232-
}
233-
234-
if (!uuid_is_null(cliopt->vmnet_network_identifier)) {
235-
xpc_dictionary_set_uuid(dict, vmnet_network_identifier_key, cliopt->vmnet_network_identifier);
236-
}
237-
238-
if (cliopt->vmnet_gateway != NULL) {
239-
xpc_dictionary_set_string(dict, vmnet_start_address_key, cliopt->vmnet_gateway);
240-
xpc_dictionary_set_string(dict, vmnet_end_address_key, cliopt->vmnet_dhcp_end);
241-
xpc_dictionary_set_string(dict, vmnet_subnet_mask_key, cliopt->vmnet_mask);
242-
}
243-
244-
xpc_dictionary_set_uuid(dict, vmnet_interface_id_key, cliopt->vmnet_interface_id);
245-
246-
if (cliopt->vmnet_nat66_prefix != NULL) {
247-
xpc_dictionary_set_string(dict, vmnet_nat66_prefix_key, cliopt->vmnet_nat66_prefix);
248-
}
249227

250228
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
251-
252-
__block interface_ref iface;
253-
__block vmnet_return_t status;
254-
229+
__block interface_ref iface = NULL;
230+
__block vmnet_return_t status = VMNET_FAILURE;
255231
__block uint64_t max_bytes = 0;
256-
iface = vmnet_start_interface(
257-
dict, state->host_queue, ^(vmnet_return_t x_status, xpc_object_t x_param) {
232+
vmnet_start_interface_completion_handler_t on_started =
233+
^(vmnet_return_t x_status, xpc_object_t x_param) {
258234
status = x_status;
259235
if (x_status == VMNET_SUCCESS) {
260236
print_vmnet_start_param(x_param);
261237
max_bytes = xpc_dictionary_get_uint64(x_param, vmnet_max_packet_size_key);
262238
}
263239
dispatch_semaphore_signal(sem);
264-
});
265-
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
266-
xpc_release(dict);
240+
};
241+
242+
if (cliopt->vmnet_disable_dhcp) {
243+
// The DHCP server can only be disabled via the vmnet_network_configuration
244+
// API, which is macOS 26+. Guard at both compile time (SDK has the symbols)
245+
// and runtime (the host actually provides them).
246+
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 260000
247+
if (__builtin_available(macOS 26.0, *)) {
248+
vmnet_return_t st = VMNET_FAILURE;
249+
vmnet_network_configuration_ref cfg =
250+
vmnet_network_configuration_create(cliopt->vmnet_mode, &st);
251+
if (cfg == NULL) {
252+
ERRORF("vmnet_network_configuration_create: [%d] %s", st, vmnet_strerror(st));
253+
return NULL;
254+
}
255+
if (cliopt->vmnet_interface != NULL) {
256+
INFOF("Using network interface \"%s\"", cliopt->vmnet_interface);
257+
st = vmnet_network_configuration_set_external_interface(cfg, cliopt->vmnet_interface);
258+
if (st != VMNET_SUCCESS) {
259+
ERRORF("vmnet_network_configuration_set_external_interface: [%d] %s", st,
260+
vmnet_strerror(st));
261+
return NULL;
262+
}
263+
}
264+
if (cliopt->vmnet_gateway != NULL) {
265+
struct in_addr subnet, mask;
266+
if (!inet_aton(cliopt->vmnet_gateway, &subnet) || !inet_aton(cliopt->vmnet_mask, &mask)) {
267+
ERRORN("inet_aton");
268+
return NULL;
269+
}
270+
vmnet_network_configuration_set_ipv4_subnet(cfg, &subnet, &mask);
271+
}
272+
vmnet_network_configuration_disable_dhcp(cfg);
273+
vmnet_network_ref net = vmnet_network_create(cfg, &st);
274+
if (net == NULL) {
275+
ERRORF("vmnet_network_create: [%d] %s", st, vmnet_strerror(st));
276+
return NULL;
277+
}
278+
xpc_object_t desc = xpc_dictionary_create(NULL, NULL, 0);
279+
iface = vmnet_interface_start_with_network(net, desc, state->host_queue, on_started);
280+
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
281+
xpc_release(desc);
282+
} else {
283+
ERROR("--vmnet-disable-dhcp requires macOS 26.0 or later");
284+
return NULL;
285+
}
286+
#else
287+
ERROR("--vmnet-disable-dhcp requires building against the macOS 26 SDK or later");
288+
return NULL;
289+
#endif
290+
} else {
291+
xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
292+
xpc_dictionary_set_uint64(dict, vmnet_operation_mode_key, cliopt->vmnet_mode);
293+
if (cliopt->vmnet_interface != NULL) {
294+
INFOF("Using network interface \"%s\"", cliopt->vmnet_interface);
295+
xpc_dictionary_set_string(dict, vmnet_shared_interface_name_key, cliopt->vmnet_interface);
296+
}
297+
298+
if (!uuid_is_null(cliopt->vmnet_network_identifier)) {
299+
xpc_dictionary_set_uuid(dict, vmnet_network_identifier_key, cliopt->vmnet_network_identifier);
300+
}
301+
302+
if (cliopt->vmnet_gateway != NULL) {
303+
xpc_dictionary_set_string(dict, vmnet_start_address_key, cliopt->vmnet_gateway);
304+
xpc_dictionary_set_string(dict, vmnet_end_address_key, cliopt->vmnet_dhcp_end);
305+
xpc_dictionary_set_string(dict, vmnet_subnet_mask_key, cliopt->vmnet_mask);
306+
}
307+
308+
xpc_dictionary_set_uuid(dict, vmnet_interface_id_key, cliopt->vmnet_interface_id);
309+
310+
if (cliopt->vmnet_nat66_prefix != NULL) {
311+
xpc_dictionary_set_string(dict, vmnet_nat66_prefix_key, cliopt->vmnet_nat66_prefix);
312+
}
313+
314+
iface = vmnet_start_interface(dict, state->host_queue, on_started);
315+
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
316+
xpc_release(dict);
317+
}
318+
267319
if (status != VMNET_SUCCESS) {
268-
ERRORF("vmnet_start_interface: [%d] %s", status, vmnet_strerror(status));
320+
ERRORF("vmnet start interface: [%d] %s", status, vmnet_strerror(status));
269321
return NULL;
270322
}
271323

0 commit comments

Comments
 (0)