Files
2026-08-31 16:44:54 -05:00

77 lines
3.2 KiB
C

#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;
}