]> tinc-vpn.org Git - tinc/commitdiff
Add support for vmnet-bridged and vmnet-shared
authorEric Karge <eric.karge@innoq.com>
Thu, 13 Feb 2025 12:19:19 +0000 (13:19 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Mon, 30 Mar 2026 20:32:34 +0000 (22:32 +0200)
doc/tinc.conf.5.in
src/bsd/darwin/vmnet.c
src/bsd/darwin/vmnet.h
src/bsd/device.c

index 75f5f403b91227215d99c5023b9dae500fda0a4a..b23245795d59b9460bd4040fda1191e61d2fbe89 100644 (file)
@@ -274,11 +274,19 @@ This mode should support both IPv4 and IPv6 packets.
 .It utun Pq OS X
 Set type to utun.
 This mode should support both IPv4 and IPv6 packets.
-.It vmnet Pq OS X
-Set type to vmnet.
+.It vmnet-host Pq OS X
+Set type to vmnet-host.
 Like with tap, Tinc will expect packets read from the virtual network device
 to start with an Ethernet header.
-Use VmnetAddr and VmnetNetmask settings to configure the device address/network
+.It vmnet-shared Pq OS X
+Set type to vmnet-shared.
+Like with tap, Tinc will expect packets read from the virtual network device
+to start with an Ethernet header.
+.It vmnet-bridged Pq OS X
+Set type to vmnet-bridged.
+Like with tap, Tinc will expect packets read from the virtual network device
+to start with an Ethernet header.
+Use BridgedIf settings to select the bridged physical device
 .It tap Pq BSD and Linux
 Set type to tap.
 Tinc will expect packets read from the virtual network device
index 8eef73de2d2162c01ee0413dae9e71cc5dd83d2d..4662cc10f2814d991e7c0052851f87980207365e 100644 (file)
@@ -37,16 +37,18 @@ static int read_socket[2];
 static void macos_vmnet_read(void);
 static const char *str_vmnet_status(vmnet_return_t status);
 
-int macos_vmnet_open(void) {
+int macos_vmnet_open(const char device[]) {
        if(socketpair(AF_UNIX, SOCK_DGRAM, 0, read_socket)) {
                logger(DEBUG_ALWAYS, LOG_ERR, "Unable to create socket: %s", strerror(errno));
                return -1;
        }
 
-       if_queue = dispatch_queue_create("org.tinc-vpn.vmnet.if_queue", DISPATCH_QUEUE_SERIAL);
-
        xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
-       xpc_dictionary_set_uint64(if_desc, vmnet_operation_mode_key, VMNET_HOST_MODE);
+       xpc_dictionary_set_uint64(if_desc, vmnet_operation_mode_key,
+               !strncmp(device, "vmnet-bridged", 14) ? VMNET_BRIDGED_MODE :
+               !strncmp(device, "vmnet-shared", 13) ? VMNET_SHARED_MODE :
+               VMNET_HOST_MODE
+       );
        xpc_dictionary_set_bool(if_desc, vmnet_enable_isolation_key, 0);
        xpc_dictionary_set_bool(if_desc, vmnet_allocate_mac_address_key, false);
     if (macos_vmnet_addr) {
@@ -54,10 +56,15 @@ int macos_vmnet_open(void) {
        xpc_dictionary_set_string(if_desc, vmnet_end_address_key, macos_vmnet_addr);
        xpc_dictionary_set_string(if_desc, vmnet_subnet_mask_key, macos_vmnet_netmask);
        }
+       if (macos_vmnet_bridged_if) {
+               xpc_dictionary_set_string(if_desc, vmnet_shared_interface_name_key, macos_vmnet_bridged_if);
+       }
     if (macos_vmnet_nat66_prefix) {
        xpc_dictionary_set_string(if_desc, vmnet_nat66_prefix_key, macos_vmnet_nat66_prefix);
     }
 
+       if_queue = dispatch_queue_create("org.tinc-vpn.vmnet.if_queue", DISPATCH_QUEUE_SERIAL);
+
        dispatch_semaphore_t if_started_sem = dispatch_semaphore_create(0);
        vmnet_if = vmnet_start_interface(
                if_desc, if_queue,
@@ -68,25 +75,37 @@ int macos_vmnet_open(void) {
                        }
                        dispatch_semaphore_signal(if_started_sem);
                });
-       dispatch_semaphore_wait(if_started_sem, DISPATCH_TIME_FOREVER);
+       if (vmnet_if) {
+               dispatch_semaphore_wait(if_started_sem, DISPATCH_TIME_FOREVER);
+       }
        dispatch_release(if_started_sem);
 
+       if (if_status == VMNET_SUCCESS) {
+               read_iov_in.iov_base = malloc(max_packet_size);
+               read_iov_in.iov_len = max_packet_size;
+
+               if_status = vmnet_interface_set_event_callback(
+                       vmnet_if, VMNET_INTERFACE_PACKETS_AVAILABLE, if_queue,
+                       ^(interface_event_t event_type, xpc_object_t event) {
+                               macos_vmnet_read();
+                       });
+       }
+
        xpc_release(if_desc);
 
        if(if_status != VMNET_SUCCESS) {
                logger(DEBUG_ALWAYS, LOG_ERR, "Unable to create vmnet device: %s", str_vmnet_status(if_status));
+               if (vmnet_if) {
+                       vmnet_stop_interface(vmnet_if, if_queue, ^(vmnet_return_t result) {});
+                       vmnet_if = NULL;
+               }
+               if_status = VMNET_SETUP_INCOMPLETE;
+               dispatch_release(if_queue);
+               close(read_socket[0]);
+               close(read_socket[1]);
                return -1;
        }
 
-    read_iov_in.iov_base = malloc(max_packet_size);
-    read_iov_in.iov_len = max_packet_size;
-
-       vmnet_interface_set_event_callback(
-               vmnet_if, VMNET_INTERFACE_PACKETS_AVAILABLE, if_queue,
-               ^(interface_event_t event_type, xpc_object_t event) {
-               macos_vmnet_read();
-       });
-
        return read_socket[0];
 }
 
@@ -96,24 +115,24 @@ int macos_vmnet_close(int fd) {
                return -1;
        }
 
-       vmnet_interface_set_event_callback(vmnet_if, VMNET_INTERFACE_PACKETS_AVAILABLE, NULL, NULL);
-
        dispatch_semaphore_t if_stopped_sem = dispatch_semaphore_create(0);
-       vmnet_stop_interface(
+       if_status = vmnet_stop_interface(
                vmnet_if, if_queue,
                ^(vmnet_return_t status) {
                        if_status = status;
                        dispatch_semaphore_signal(if_stopped_sem);
                });
-       dispatch_semaphore_wait(if_stopped_sem, DISPATCH_TIME_FOREVER);
+       if (if_status == VMNET_SUCCESS) {
+               dispatch_semaphore_wait(if_stopped_sem, DISPATCH_TIME_FOREVER);
+       }
        dispatch_release(if_stopped_sem);
 
        if(if_status != VMNET_SUCCESS) {
                logger(DEBUG_ALWAYS, LOG_ERR, "Unable to close vmnet device: %s", str_vmnet_status(if_status));
                return -1;
        }
-       if_status = VMNET_SETUP_INCOMPLETE;
 
+       if_status = VMNET_SETUP_INCOMPLETE;
        dispatch_release(if_queue);
 
     read_iov_in.iov_len = 0;
index 08cc35d1ecaa09b11172f5bbbad84852c6ac48a1..d9ddc4244b11b5085d55221fe08915551b8d1a4e 100644 (file)
 #include <sys/types.h>
 
 char * macos_vmnet_addr;
+char * macos_vmnet_bridged_if;
 char * macos_vmnet_netmask;
 char * macos_vmnet_nat66_prefix;
 
-int macos_vmnet_open(void);
+int macos_vmnet_open(const char device[]);
 int macos_vmnet_close(int fd);
 ssize_t macos_vmnet_write(uint8_t *buffer, size_t buflen);
 
index 9294860c8b083f2623a8496444bf624a405aa9b5..ac504509a7e2f023b7041bfdc4b61620a00dead5 100644 (file)
@@ -153,11 +153,14 @@ static bool setup_device(void) {
 
 #endif
 #ifdef ENABLE_VMNET
-               else if(!strcasecmp(type, "vmnet")) {
-                       device = xstrdup("vmnet");
+               else if(!strcasecmp(type, "vmnet-host")
+                               || !strcasecmp(type, "vmnet-shared")
+                               || !strcasecmp(type, "vmnet-bridged")) {
+                       device = xstrdup(type);
                        device_type = DEVICE_TYPE_VMNET;
                        get_config_string(lookup_config(&config_tree, "VmnetAddr"), &macos_vmnet_addr);
                        get_config_string(lookup_config(&config_tree, "VmnetNetmask"), &macos_vmnet_netmask);
+                       get_config_string(lookup_config(&config_tree, "VmnetBridgedIf"), &macos_vmnet_bridged_if);
                        get_config_string(lookup_config(&config_tree, "VmnetNat66Prefix"), &macos_vmnet_nat66_prefix);
                }
 
@@ -227,7 +230,7 @@ static bool setup_device(void) {
 #ifdef ENABLE_VMNET
 
        case DEVICE_TYPE_VMNET: {
-               device_fd = macos_vmnet_open();
+               device_fd = macos_vmnet_open(device);
        }
        break;
 #endif