a lot
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
#include "UMNSystem.h"
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#ifdef __APPLE__
|
||||
#include <net/if.h>
|
||||
#include <net/if_utun.h>
|
||||
#include <sys/kern_control.h>
|
||||
#include <sys/sys_domain.h>
|
||||
#endif
|
||||
|
||||
int umn_utun_open(char *name, size_t name_capacity) {
|
||||
#ifdef __APPLE__
|
||||
int fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
|
||||
if (fd < 0) return -1;
|
||||
struct ctl_info info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
strlcpy(info.ctl_name, UTUN_CONTROL_NAME, sizeof(info.ctl_name));
|
||||
if (ioctl(fd, CTLIOCGINFO, &info) < 0) { close(fd); return -1; }
|
||||
struct sockaddr_ctl address;
|
||||
memset(&address, 0, sizeof(address));
|
||||
address.sc_len = sizeof(address); address.sc_family = AF_SYSTEM;
|
||||
address.ss_sysaddr = AF_SYS_CONTROL; address.sc_id = info.ctl_id; address.sc_unit = 0;
|
||||
if (connect(fd, (struct sockaddr *)&address, sizeof(address)) < 0) { close(fd); return -1; }
|
||||
socklen_t length = (socklen_t)name_capacity;
|
||||
if (getsockopt(fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, name, &length) < 0) { close(fd); return -1; }
|
||||
return fd;
|
||||
#else
|
||||
(void)name; (void)name_capacity; errno = ENOTSUP; return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int umn_get_peer_eid(int socket_fd, uid_t *uid, gid_t *gid) {
|
||||
#ifdef __APPLE__
|
||||
return getpeereid(socket_fd, uid, gid);
|
||||
#else
|
||||
struct ucred credential; socklen_t size = sizeof(credential);
|
||||
if (getsockopt(socket_fd, SOL_SOCKET, SO_PEERCRED, &credential, &size) < 0) return -1;
|
||||
*uid = credential.uid; *gid = credential.gid; return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int umn_send_fd(int socket_fd, int passed_fd, const void *data, size_t length) {
|
||||
struct iovec io = { .iov_base = (void *)data, .iov_len = length };
|
||||
char control[CMSG_SPACE(sizeof(int))]; memset(control, 0, sizeof(control));
|
||||
struct msghdr message; memset(&message, 0, sizeof(message));
|
||||
message.msg_iov = &io; message.msg_iovlen = 1;
|
||||
message.msg_control = control; message.msg_controllen = sizeof(control);
|
||||
struct cmsghdr *header = CMSG_FIRSTHDR(&message);
|
||||
header->cmsg_level = SOL_SOCKET; header->cmsg_type = SCM_RIGHTS; header->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
memcpy(CMSG_DATA(header), &passed_fd, sizeof(int));
|
||||
ssize_t result = sendmsg(socket_fd, &message, 0);
|
||||
if (result < 0) return -1;
|
||||
if ((size_t)result != length) { errno = EIO; return -1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t umn_recv_fd(int socket_fd, int *passed_fd, void *data, size_t capacity) {
|
||||
struct iovec io = { .iov_base = data, .iov_len = capacity };
|
||||
char control[CMSG_SPACE(sizeof(int))]; memset(control, 0, sizeof(control));
|
||||
struct msghdr message; memset(&message, 0, sizeof(message));
|
||||
message.msg_iov = &io; message.msg_iovlen = 1;
|
||||
message.msg_control = control; message.msg_controllen = sizeof(control);
|
||||
ssize_t result = recvmsg(socket_fd, &message, 0);
|
||||
if (result <= 0) return result;
|
||||
*passed_fd = -1;
|
||||
for (struct cmsghdr *header = CMSG_FIRSTHDR(&message); header; header = CMSG_NXTHDR(&message, header)) {
|
||||
if (header->cmsg_level == SOL_SOCKET && header->cmsg_type == SCM_RIGHTS && header->cmsg_len >= CMSG_LEN(sizeof(int))) {
|
||||
memcpy(passed_fd, CMSG_DATA(header), sizeof(int)); break;
|
||||
}
|
||||
}
|
||||
if (*passed_fd < 0) { errno = EBADMSG; return -1; }
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user