diff options
author | Bin Jin <bjin@ctrl-d.org> | 2017-03-12 17:48:20 +0800 |
---|---|---|
committer | Bin Jin <bjin@ctrl-d.org> | 2017-03-12 17:48:20 +0800 |
commit | a2a3e540f2d1a507b34eccae26de09066a2a12fa (patch) | |
tree | 1e336189acd095d761eaad252f18ee6e32b7216b /cbits/tun-macos.c | |
download | wireguard-hs-a2a3e540f2d1a507b34eccae26de09066a2a12fa.tar.xz wireguard-hs-a2a3e540f2d1a507b34eccae26de09066a2a12fa.zip |
Initial commit
Diffstat (limited to 'cbits/tun-macos.c')
-rw-r--r-- | cbits/tun-macos.c | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/cbits/tun-macos.c b/cbits/tun-macos.c new file mode 100644 index 0000000..7d57350 --- /dev/null +++ b/cbits/tun-macos.c @@ -0,0 +1,115 @@ +/** + Copyright (C) 2015 clowwindy + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +// Extracted from ShadowVPN project, with some minor modifications. + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> + +#include <net/if_utun.h> +#include <netinet/ip.h> +#include <sys/ioctl.h> +#include <sys/kern_control.h> +#include <sys/sys_domain.h> +#include <sys/uio.h> +#include <unistd.h> + +#include "tun.h" + +int tun_alloc(const char *dev_name, int threads, int *fds) { + struct ctl_info ctlInfo; + struct sockaddr_ctl sc; + int fd, utun_num; + + if (!dev_name || sscanf(dev_name, "utun%d", &utun_num) != 1) + return -1; + + memset(&ctlInfo, 0, sizeof(ctlInfo)); + + if (strlcpy(ctlInfo.ctl_name, + UTUN_CONTROL_NAME, + sizeof(ctlInfo.ctl_name)) >= sizeof(ctlInfo.ctl_name)) { + return -1; + } + + fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); + + if (fd < 0) + return -1; + + if (ioctl(fd, CTLIOCGINFO, &ctlInfo) < 0) { + close(fd); + return -1; + } + + sc.sc_id = ctlInfo.ctl_id; + sc.sc_len = sizeof(sc); + sc.sc_family = AF_SYSTEM; + sc.ss_sysaddr = AF_SYS_CONTROL; + + sc.sc_unit = utun_num + 1; + + if (connect(fd, (struct sockaddr*)&sc, sizeof(sc)) < 0) { + close(fd); + return -1; + } + + *fds = fd; + + return 1; +} + +inline int utun_modified_len(int len) { + if (len > 0) + return (len > sizeof(u_int32_t)) ? len - sizeof(u_int32_t) : 0; + else + return len; +} + +int utun_read(int fd, void *buf, size_t len) { + u_int32_t type; + struct iovec iv[2]; + + iv[0].iov_base = &type; + iv[0].iov_len = sizeof(type); + iv[1].iov_base = buf; + iv[1].iov_len = len; + + return utun_modified_len(readv(fd, iv, 2)); +} + +int utun_write(int fd, void *buf, size_t len) { + u_int32_t type; + struct iovec iv[2]; + struct ip *iph; + + iph = (struct ip *) buf; + + if (iph->ip_v == 6) + type = htonl(AF_INET6); + else + type = htonl(AF_INET); + + iv[0].iov_base = &type; + iv[0].iov_len = sizeof(type); + iv[1].iov_base = buf; + iv[1].iov_len = len; + + return utun_modified_len(writev(fd, iv, 2)); +} + |