mirror of
https://github.com/OpenVPN/openvpn.git
synced 2026-05-28 04:03:29 -04:00
Merge 61b235d277 into d69a0dfe73
This commit is contained in:
commit
0af8e0acaa
5 changed files with 294 additions and 16 deletions
|
|
@ -45,6 +45,10 @@
|
|||
|
||||
#include "memdbg.h"
|
||||
|
||||
#ifdef TARGET_DARWIN
|
||||
#include <net/bpf.h>
|
||||
#endif
|
||||
|
||||
counter_type link_read_bytes_global; /* GLOBAL */
|
||||
counter_type link_write_bytes_global; /* GLOBAL */
|
||||
|
||||
|
|
@ -1306,15 +1310,76 @@ read_incoming_tun(struct context *c)
|
|||
|
||||
c->c2.buf = c->c2.buffers->read_tun_buf;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* we cannot end up here when using dco */
|
||||
ASSERT(!dco_enabled(&c->options));
|
||||
|
||||
sockethandle_t sh = { .is_handle = true, .h = c->c1.tuntap->hand, .prepend_sa = false };
|
||||
sockethandle_finalize(sh, &c->c1.tuntap->reads, &c->c2.buf, NULL);
|
||||
#else /* ifdef _WIN32 */
|
||||
#ifndef _WIN32
|
||||
ASSERT(buf_init(&c->c2.buf, c->c2.frame.buf.headroom));
|
||||
ASSERT(buf_safe(&c->c2.buf, c->c2.frame.buf.payload_size));
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_DARWIN)
|
||||
if (c->c1.tuntap->actual_peer_name)
|
||||
{
|
||||
int next_bpf_packet_offset = 0;
|
||||
|
||||
ASSERT(buf_init(&c->c2.buffers->read_tun_bpf_buf, 0));
|
||||
ASSERT(buf_safe(&c->c2.buffers->read_tun_bpf_buf, TUN_BPF_BUF_SIZE));
|
||||
|
||||
/* no data remaining in aux tun read buf, so read from bpf */
|
||||
if (!(c->c2.buffers->read_tun_aux_buf.len))
|
||||
{
|
||||
if (c->c1.tuntap->backend_driver == DRIVER_AFUNIX)
|
||||
{
|
||||
c->c2.buffers->read_tun_bpf_buf.len =
|
||||
(int)read_tun_afunix(c->c1.tuntap, BPTR(&c->c2.buffers->read_tun_bpf_buf), TUN_BPF_BUF_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
c->c2.buffers->read_tun_bpf_buf.len = (int)read_tun(c->c1.tuntap, BPTR(&c->c2.buffers->read_tun_bpf_buf), TUN_BPF_BUF_SIZE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* data remaining in aux tun read buf, copy it to bpf buf instead of real read */
|
||||
memcpy(c->c2.buffers->read_tun_bpf_buf.data, c->c2.buffers->read_tun_aux_buf.data, c->c2.buffers->read_tun_aux_buf.len);
|
||||
c->c2.buffers->read_tun_bpf_buf.len = c->c2.buffers->read_tun_aux_buf.len;
|
||||
|
||||
/* as we will refill the buffer only if there are still another packets, zero len for the moment */
|
||||
c->c2.buffers->read_tun_aux_buf.len = 0;
|
||||
}
|
||||
|
||||
/* this is the current bpf packet */
|
||||
struct bpf_hdr *hdr = (struct bpf_hdr *)BPTR(&c->c2.buffers->read_tun_bpf_buf);
|
||||
|
||||
/* need to split bpf packets */
|
||||
if ((unsigned int)c->c2.buffers->read_tun_bpf_buf.len > hdr->bh_hdrlen + hdr->bh_caplen)
|
||||
{
|
||||
ASSERT(buf_init(&c->c2.buffers->read_tun_aux_buf, 0));
|
||||
ASSERT(buf_safe(&c->c2.buffers->read_tun_aux_buf, TUN_BPF_BUF_SIZE));
|
||||
|
||||
next_bpf_packet_offset = BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
|
||||
|
||||
memcpy(BPTR(&c->c2.buffers->read_tun_aux_buf), (char *)hdr + next_bpf_packet_offset, c->c2.buffers->read_tun_bpf_buf.len - next_bpf_packet_offset);
|
||||
c->c2.buffers->read_tun_aux_buf.len = c->c2.buffers->read_tun_bpf_buf.len - next_bpf_packet_offset;
|
||||
}
|
||||
|
||||
/* fill standard read_tun_buf with data from current bpf packet */
|
||||
memcpy(BPTR(&c->c2.buf), (char *)hdr + hdr->bh_hdrlen, hdr->bh_caplen);
|
||||
c->c2.buf.len = hdr->bh_caplen;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c->c1.tuntap->backend_driver == DRIVER_AFUNIX)
|
||||
{
|
||||
c->c2.buf.len =
|
||||
(int)read_tun_afunix(c->c1.tuntap, BPTR(&c->c2.buf), c->c2.frame.buf.payload_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
c->c2.buf.len = (int)read_tun(c->c1.tuntap, BPTR(&c->c2.buf), c->c2.frame.buf.payload_size);
|
||||
}
|
||||
}
|
||||
#else /* TARGET_DARWIN */
|
||||
|
||||
#ifndef _WIN32
|
||||
if (c->c1.tuntap->backend_driver == DRIVER_AFUNIX)
|
||||
{
|
||||
c->c2.buf.len =
|
||||
|
|
@ -1324,7 +1389,17 @@ read_incoming_tun(struct context *c)
|
|||
{
|
||||
c->c2.buf.len = (int)read_tun(c->c1.tuntap, BPTR(&c->c2.buf), c->c2.frame.buf.payload_size);
|
||||
}
|
||||
#endif /* ifdef _WIN32 */
|
||||
|
||||
#else /* ifndef _WIN32 */
|
||||
/* we cannot end up here when using dco */
|
||||
ASSERT(!dco_enabled(&c->options));
|
||||
|
||||
sockethandle_t sh = { .is_handle = true, .h = c->c1.tuntap->hand, .prepend_sa = false };
|
||||
sockethandle_finalize(sh, &c->c1.tuntap->reads, &c->c2.buf, NULL);
|
||||
|
||||
#endif /* ifndef _WIN32 */
|
||||
|
||||
#endif /* TARGET_DARWIN */
|
||||
|
||||
#ifdef PACKET_TRUNCATION_CHECK
|
||||
ipv4_packet_size_verify(BPTR(&c->c2.buf), BLEN(&c->c2.buf), TUNNEL_TYPE(c->c1.tuntap),
|
||||
|
|
@ -2156,6 +2231,14 @@ get_io_flags_udp(struct context *c, struct multi_io *multi_io, const unsigned in
|
|||
multi_io->udp_flags = (out_socket << SOCKET_SHIFT);
|
||||
}
|
||||
|
||||
#ifdef TARGET_DARWIN
|
||||
static inline bool
|
||||
tun_read_residual(const struct context *c)
|
||||
{
|
||||
return c->c2.buffers->read_tun_aux_buf.len > 0;
|
||||
}
|
||||
#endif /* TARGET_DARWIN */
|
||||
|
||||
/*
|
||||
* This is the core I/O wait function, used for all I/O waits except
|
||||
* for the top-level server sockets.
|
||||
|
|
@ -2213,7 +2296,23 @@ io_wait(struct context *c, const unsigned int flags)
|
|||
|
||||
if (!c->sig->signal_received)
|
||||
{
|
||||
#ifdef TARGET_DARWIN
|
||||
if (flags & IOW_CHECK_RESIDUAL)
|
||||
{
|
||||
if (sockets_read_residual(c))
|
||||
{
|
||||
c->c2.event_set_status = SOCKET_READ;
|
||||
}
|
||||
else if ((!(flags & IOW_TO_LINK)) && tun_read_residual(c))
|
||||
{
|
||||
c->c2.event_set_status = TUN_READ;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & IOW_CHECK_RESIDUAL) || !((c->c2.event_set_status == SOCKET_READ) || (c->c2.event_set_status == TUN_READ)))
|
||||
#else /* TARGET_DARWIN */
|
||||
if (!(flags & IOW_CHECK_RESIDUAL) || !sockets_read_residual(c))
|
||||
#endif /* TARGET_DARWIN */
|
||||
{
|
||||
int status;
|
||||
|
||||
|
|
@ -2265,10 +2364,12 @@ io_wait(struct context *c, const unsigned int flags)
|
|||
c->c2.event_set_status = ES_TIMEOUT;
|
||||
}
|
||||
}
|
||||
#if !defined(TARGET_DARWIN)
|
||||
else
|
||||
{
|
||||
c->c2.event_set_status = SOCKET_READ;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 'now' should always be a reasonably up-to-date timestamp */
|
||||
|
|
|
|||
|
|
@ -3695,6 +3695,11 @@ init_context_buffers(const struct frame *frame)
|
|||
b->read_link_buf = alloc_buf(buf_size);
|
||||
b->read_tun_buf = alloc_buf(buf_size);
|
||||
|
||||
#if defined(TARGET_DARWIN)
|
||||
b->read_tun_aux_buf = alloc_buf(TUN_BPF_BUF_SIZE);
|
||||
b->read_tun_bpf_buf = alloc_buf(TUN_BPF_BUF_SIZE);
|
||||
#endif
|
||||
|
||||
b->aux_buf = alloc_buf(buf_size);
|
||||
|
||||
b->encrypt_buf = alloc_buf(buf_size);
|
||||
|
|
@ -3717,6 +3722,11 @@ free_context_buffers(struct context_buffers *b)
|
|||
free_buf(&b->read_tun_buf);
|
||||
free_buf(&b->aux_buf);
|
||||
|
||||
#if defined(TARGET_DARWIN)
|
||||
free_buf(&b->read_tun_aux_buf);
|
||||
free_buf(&b->read_tun_bpf_buf);
|
||||
#endif
|
||||
|
||||
#ifdef USE_COMP
|
||||
free_buf(&b->compress_buf);
|
||||
free_buf(&b->decompress_buf);
|
||||
|
|
|
|||
|
|
@ -112,8 +112,19 @@ struct context_buffers
|
|||
*/
|
||||
struct buffer read_link_buf;
|
||||
struct buffer read_tun_buf;
|
||||
|
||||
#ifdef TARGET_DARWIN
|
||||
struct buffer read_tun_aux_buf;
|
||||
struct buffer read_tun_bpf_buf;
|
||||
};
|
||||
|
||||
#define TUN_BPF_BUF_SIZE 32768
|
||||
|
||||
#else
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* always-persistent context variables
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -55,6 +55,11 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef TARGET_DARWIN
|
||||
#include <net/ndrv.h>
|
||||
#include <net/bpf.h>
|
||||
#endif
|
||||
|
||||
const char *
|
||||
print_tun_backend_driver(enum tun_driver_type driver)
|
||||
{
|
||||
|
|
@ -1879,16 +1884,137 @@ open_tun_generic(const char *dev, const char *dev_type, const char *dev_node, st
|
|||
tt->persistent_if = true;
|
||||
}
|
||||
|
||||
if ((tt->fd = open(tunname, O_RDWR)) < 0)
|
||||
#if defined(TARGET_DARWIN)
|
||||
if (strncmp(dev, "feth", 4) == 0)
|
||||
{
|
||||
msg(M_ERR, "Cannot open TUN/TAP dev %s", tunname);
|
||||
char feth_peer_name[256];
|
||||
|
||||
strncpy(feth_peer_name, dev + 4, strlen(dev) - 4);
|
||||
if (strlen(feth_peer_name))
|
||||
{
|
||||
long peer_index = strtol(feth_peer_name, NULL, 0);
|
||||
if (peer_index || dev[4] == '0')
|
||||
{
|
||||
snprintf(feth_peer_name, 9, "feth%ld", peer_index + 1000);
|
||||
msg(M_INFO, "Peer interface for %s is expected to be %s", dev, feth_peer_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg(M_ERR, "Cannot calculate feth peer interface number for TAP dev %s", tunname);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg(M_ERR, "No valid feth name %s", tunname);
|
||||
}
|
||||
|
||||
if ((tt->wfd = socket(AF_NDRV, SOCK_RAW, 0)) < 0)
|
||||
{
|
||||
msg(M_ERR, "Cannot open writing socket for TAP dev %s", tunname);
|
||||
}
|
||||
|
||||
memset(&tt->ndrv_sockaddr, 0, sizeof(tt->ndrv_sockaddr));
|
||||
tt->ndrv_sockaddr.snd_family = AF_NDRV;
|
||||
|
||||
strcpy((char *)&tt->ndrv_sockaddr.snd_name, (char *)feth_peer_name);
|
||||
msg(M_INFO, "ndrv_sockaddr.snd_name = %s", tt->ndrv_sockaddr.snd_name);
|
||||
|
||||
if (bind(tt->wfd, (struct sockaddr *)&tt->ndrv_sockaddr, sizeof(tt->ndrv_sockaddr)) < 0)
|
||||
{
|
||||
msg(M_ERR, "Cannot bind writing socket %d for TAP %s", tt->wfd, tunname);
|
||||
}
|
||||
|
||||
set_nonblock(tt->wfd);
|
||||
set_cloexec(tt->wfd); /* don't pass fd to scripts */
|
||||
|
||||
msg(M_INFO, "Writing socket for TAP device peer %s opened", feth_peer_name);
|
||||
|
||||
// Creating a read fd with bpf
|
||||
char buf[11] = { 0 };
|
||||
int bpf = 0;
|
||||
|
||||
for (int i = 0; i < 99; i++)
|
||||
{
|
||||
snprintf(buf, 11, "/dev/bpf%i", i);
|
||||
bpf = open(buf, O_RDONLY);
|
||||
|
||||
if (bpf != -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bpf == -1)
|
||||
{
|
||||
msg(M_ERR, "Cannot find free bpf for dev %s TAP", tunname);
|
||||
}
|
||||
else
|
||||
{
|
||||
tt->fd = bpf;
|
||||
}
|
||||
|
||||
int value = 1;
|
||||
|
||||
if (ioctl(bpf, BIOCIMMEDIATE, &value) == -1)
|
||||
{
|
||||
msg(M_ERR, "Cannot disable buffering for %s TAP bpf %s", tunname, buf);
|
||||
}
|
||||
|
||||
int buf_len = TUN_BPF_BUF_SIZE;
|
||||
|
||||
if (ioctl(bpf, BIOCSBLEN, &buf_len) == -1)
|
||||
{
|
||||
msg(M_ERR, "Cannot set buffer size to %d for %s TAP bpf %s", buf_len, tunname, buf);
|
||||
}
|
||||
|
||||
struct ifreq bound_if;
|
||||
|
||||
strcpy(bound_if.ifr_name, feth_peer_name);
|
||||
|
||||
if (ioctl(bpf, BIOCSETIF, &bound_if) > 0)
|
||||
{
|
||||
msg(M_ERR, "Cannot set interface %s in TAP %s bpf %s properties", feth_peer_name, tunname, buf);
|
||||
}
|
||||
|
||||
value = 1;
|
||||
|
||||
if (ioctl(bpf, BIOCSHDRCMPLT, &value) == -1)
|
||||
{
|
||||
msg(M_ERR, "Cannot disable lladdr completion for %s TAP bpf %s", tunname, buf);
|
||||
}
|
||||
|
||||
value = 1;
|
||||
|
||||
if (ioctl(bpf, BIOCPROMISC, &value) == -1)
|
||||
{
|
||||
msg(M_ERR, "Cannot enable promiscuous mode for %s TAP bpf %s", tunname, buf);
|
||||
}
|
||||
|
||||
value = 0;
|
||||
|
||||
if (ioctl(bpf, BIOCSSEESENT, &value) == -1)
|
||||
{
|
||||
msg(M_ERR, "Cannot block bpf reception of our outgoing packets on %s", buf);
|
||||
}
|
||||
|
||||
set_nonblock(tt->fd);
|
||||
set_cloexec(tt->fd); /* don't pass fd to scripts */
|
||||
msg(M_INFO, "Reading bpf for TAP device peer %s opened", feth_peer_name);
|
||||
|
||||
tt->actual_peer_name = string_alloc(feth_peer_name, NULL);
|
||||
}
|
||||
else
|
||||
#endif /* TARGET_DARWIN */
|
||||
{
|
||||
if ((tt->fd = open(tunname, O_RDWR)) < 0)
|
||||
{
|
||||
msg(M_ERR, "Cannot open TUN/TAP dev %s", tunname);
|
||||
}
|
||||
set_nonblock(tt->fd);
|
||||
set_cloexec(tt->fd); /* don't pass fd to scripts */
|
||||
msg(M_INFO, "TUN/TAP device %s opened", tunname);
|
||||
}
|
||||
}
|
||||
|
||||
set_nonblock(tt->fd);
|
||||
set_cloexec(tt->fd); /* don't pass fd to scripts */
|
||||
msg(M_INFO, "TUN/TAP device %s opened", tunname);
|
||||
|
||||
/* tt->actual_name is passed to up and down scripts and used as the ifconfig dev name */
|
||||
tt->actual_name = string_alloc(dynamic_opened ? dynamic_name : dev, NULL);
|
||||
}
|
||||
|
|
@ -1971,6 +2097,14 @@ close_tun_generic(struct tuntap *tt)
|
|||
close(tt->fd);
|
||||
}
|
||||
|
||||
#if defined(TARGET_DARWIN)
|
||||
if (tt->actual_peer_name)
|
||||
{
|
||||
close(tt->wfd);
|
||||
free(tt->actual_peer_name);
|
||||
}
|
||||
#endif /* TARGET_DARWIN */
|
||||
|
||||
free(tt->actual_name);
|
||||
clear_tuntap(tt);
|
||||
}
|
||||
|
|
@ -3111,7 +3245,15 @@ write_tun(struct tuntap *tt, uint8_t *buf, int len)
|
|||
}
|
||||
else
|
||||
{
|
||||
return write(tt->fd, buf, len);
|
||||
/* feth TAP interface */
|
||||
if (tt->actual_peer_name)
|
||||
{
|
||||
return sendto(tt->wfd, buf, len, 0, (const struct sockaddr *)&tt->ndrv_sockaddr, sizeof(tt->ndrv_sockaddr));
|
||||
}
|
||||
else
|
||||
{
|
||||
return write(tt->fd, buf, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,8 +37,13 @@
|
|||
#include "event.h"
|
||||
#include "proto.h"
|
||||
#include "misc.h"
|
||||
#include "networking.h"
|
||||
#include "dco.h"
|
||||
#include "networking.h"
|
||||
|
||||
|
||||
#ifdef TARGET_DARWIN
|
||||
#include <net/ndrv.h>
|
||||
#endif
|
||||
|
||||
enum tun_driver_type
|
||||
{
|
||||
|
|
@ -204,6 +209,11 @@ struct tuntap
|
|||
|
||||
char *actual_name; /* actual name of TUN/TAP dev, usually including unit number */
|
||||
|
||||
#ifdef TARGET_DARWIN
|
||||
char *actual_peer_name; /* actual name of macOS TAP feth dev peer interface, with original unit number + 1000) */
|
||||
struct sockaddr_ndrv ndrv_sockaddr; /* write socket for feth TAP interface */
|
||||
#endif
|
||||
|
||||
/* ifconfig parameters */
|
||||
in_addr_t local;
|
||||
in_addr_t remote_netmask;
|
||||
|
|
@ -237,6 +247,10 @@ struct tuntap
|
|||
int fd; /* file descriptor for TUN/TAP dev */
|
||||
#endif /* ifdef _WIN32 */
|
||||
|
||||
#ifdef TARGET_DARWIN
|
||||
int wfd; /* file descriptor for feth tap emulated dev write */
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_SOLARIS
|
||||
int ip_fd;
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue