mirror of
https://github.com/lucannez64/darling-lol.git
synced 2026-10-27 19:54:38 +00:00
Merge pull request #103 from lucannez64/fix/vivox-ifmedia
Handle SIOCGIFMEDIA for Vivox interface discovery
This commit is contained in:
5 files changed
+319
No files matched your search
@@ -37,6 +37,7 @@ jobs:
|
|||||||
- run: python -m unittest discover -s tests -p 'test_exec_guest.py'
|
- run: python -m unittest discover -s tests -p 'test_exec_guest.py'
|
||||||
- run: python -m unittest discover -s tests -p 'test_close_league_client_in_game.py'
|
- run: python -m unittest discover -s tests -p 'test_close_league_client_in_game.py'
|
||||||
- run: python -m unittest discover -s tests -p 'test_recover_stale_client.py'
|
- run: python -m unittest discover -s tests -p 'test_recover_stale_client.py'
|
||||||
|
- run: python -m unittest discover -s tests -p 'test_ifmedia.py'
|
||||||
- run: python -m unittest discover -s tests -p 'test_clean_stale_helpers.py'
|
- run: python -m unittest discover -s tests -p 'test_clean_stale_helpers.py'
|
||||||
- run: python -m unittest discover -s tests -p 'test_hide_league_client_in_game.py'
|
- run: python -m unittest discover -s tests -p 'test_hide_league_client_in_game.py'
|
||||||
- run: python -m unittest discover -s tests -p 'test_client_in_game_tricks.py'
|
- run: python -m unittest discover -s tests -p 'test_client_in_game_tricks.py'
|
||||||
@@ -6200,3 +6200,97 @@ diff --git a/darling/src/libsystem_kernel/emulation/src/linux_premigration/vchro
|
|||||||
ctxt->current_root = prefix_path;
|
ctxt->current_root = prefix_path;
|
||||||
ctxt->current_root_len = prefix_path_len;
|
ctxt->current_root_len = prefix_path_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diff --git a/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/helper/ioctl/socket.c b/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/helper/ioctl/socket.c
|
||||||
|
index f890ab2..8969577 100644
|
||||||
|
--- a/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/helper/ioctl/socket.c
|
||||||
|
+++ b/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/helper/ioctl/socket.c
|
||||||
|
@@ -2,12 +2,29 @@
|
||||||
|
|
||||||
|
#include <sys/errno.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
-#include <ifaddrs.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
+#include <net/if_media.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/sockio.h>
|
||||||
|
#include <netinet6/in6_var.h>
|
||||||
|
|
||||||
|
+#include <darling/emulation/xnu_syscall/bsd/impl/ioctl/ioctl.h>
|
||||||
|
+
|
||||||
|
+extern int strcmp(const char* a, const char* b);
|
||||||
|
+extern int strncmp(const char* a, const char* b, size_t n);
|
||||||
|
+extern char* strncpy(char* destination, const char* source, size_t length);
|
||||||
|
+
|
||||||
|
+#define LINUX_SIOCGIFFLAGS 0x8913
|
||||||
|
+#define LINUX_IFNAMSIZ 16
|
||||||
|
+
|
||||||
|
+struct linux_ifreq {
|
||||||
|
+ char lifr_name[LINUX_IFNAMSIZ];
|
||||||
|
+ union {
|
||||||
|
+ short lifr_flags;
|
||||||
|
+ char lifr_pad[24];
|
||||||
|
+ };
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
int handle_socket(int fd, unsigned int cmd, void* arg, int* retval)
|
||||||
|
{
|
||||||
|
switch (cmd)
|
||||||
|
@@ -19,6 +36,57 @@ int handle_socket(int fd, unsigned int cmd, void* arg, int* retval)
|
||||||
|
case SIOCAIFADDR_IN6: // set IPv6 address
|
||||||
|
*retval = -ENOTSUP;
|
||||||
|
return IOCTL_HANDLED;
|
||||||
|
+ case SIOCGIFMEDIA:
|
||||||
|
+#ifdef SIOCGIFXMEDIA
|
||||||
|
+ case SIOCGIFXMEDIA:
|
||||||
|
+#endif
|
||||||
|
+ {
|
||||||
|
+ struct ifmediareq* ifmr = (struct ifmediareq*) arg;
|
||||||
|
+ struct linux_ifreq ifr;
|
||||||
|
+ int status;
|
||||||
|
+
|
||||||
|
+ if (ifmr == NULL || ifmr->ifm_count < 0)
|
||||||
|
+ {
|
||||||
|
+ *retval = -EINVAL;
|
||||||
|
+ return IOCTL_HANDLED;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ifr.lifr_name[LINUX_IFNAMSIZ - 1] = '\0';
|
||||||
|
+ strncpy(ifr.lifr_name, ifmr->ifm_name, LINUX_IFNAMSIZ - 1);
|
||||||
|
+ status = __real_ioctl(fd, LINUX_SIOCGIFFLAGS, &ifr);
|
||||||
|
+ if (status < 0)
|
||||||
|
+ {
|
||||||
|
+ *retval = status;
|
||||||
|
+ return IOCTL_HANDLED;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (ifr.lifr_flags & IFF_LOOPBACK)
|
||||||
|
+ {
|
||||||
|
+ *retval = -ENOTSUP;
|
||||||
|
+ return IOCTL_HANDLED;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (strncmp(ifmr->ifm_name, "wl", 2) == 0)
|
||||||
|
+ ifmr->ifm_current = IFM_IEEE80211 | IFM_AUTO;
|
||||||
|
+ else
|
||||||
|
+ ifmr->ifm_current = IFM_ETHER | IFM_AUTO;
|
||||||
|
+ ifmr->ifm_mask = 0;
|
||||||
|
+ ifmr->ifm_status = ((ifr.lifr_flags & IFF_UP) && (ifr.lifr_flags & IFF_RUNNING))
|
||||||
|
+ ? (IFM_AVALID | IFM_ACTIVE) : IFM_AVALID;
|
||||||
|
+ ifmr->ifm_active = ifmr->ifm_current;
|
||||||
|
+ if (ifmr->ifm_count > 0)
|
||||||
|
+ {
|
||||||
|
+ if (ifmr->ifm_ulist == NULL)
|
||||||
|
+ {
|
||||||
|
+ *retval = -EFAULT;
|
||||||
|
+ return IOCTL_HANDLED;
|
||||||
|
+ }
|
||||||
|
+ ifmr->ifm_ulist[0] = ifmr->ifm_current;
|
||||||
|
+ }
|
||||||
|
+ ifmr->ifm_count = 1;
|
||||||
|
+ *retval = 0;
|
||||||
|
+ return IOCTL_HANDLED;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
return IOCTL_PASS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
"""Compile the added interface-media handler with inert ioctl fixtures."""
|
||||||
|
from pathlib import Path
|
||||||
|
import shutil
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import test_runtime_compatibility as sources
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipUnless(shutil.which('cc'), 'C compiler required')
|
||||||
|
class InterfaceMediaTests(unittest.TestCase):
|
||||||
|
run_c = sources.CompatibilityChecks.run_c
|
||||||
|
|
||||||
|
def test_media_queries_preserve_buffers_and_exclude_loopback(self):
|
||||||
|
patch = (Path(__file__).resolve().parents[1] / 'patches/xnu.patch').read_text()
|
||||||
|
section = patch.split('diff --git a/darling/src/libsystem_kernel/emulation/src/'
|
||||||
|
'xnu_syscall/bsd/helper/ioctl/socket.c ', 1)[1]
|
||||||
|
added = '\n'.join(line[1:] for line in section.splitlines()
|
||||||
|
if line.startswith('+') and not line.startswith('+++'))
|
||||||
|
handler = added.split('\t\tcase SIOCGIFMEDIA:', 1)[1]
|
||||||
|
self.run_c(r'''
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#define SIOCGIFMEDIA 1
|
||||||
|
#define SIOCGIFXMEDIA 2
|
||||||
|
#define IOCTL_HANDLED 1
|
||||||
|
#define IOCTL_PASS 0
|
||||||
|
#define IFF_UP 1
|
||||||
|
#define IFF_LOOPBACK 8
|
||||||
|
#define IFF_RUNNING 64
|
||||||
|
#define IFM_ETHER 0x20
|
||||||
|
#define IFM_IEEE80211 0x80
|
||||||
|
#define IFM_AUTO 0
|
||||||
|
#define IFM_AVALID 1
|
||||||
|
#define IFM_ACTIVE 2
|
||||||
|
#define LINUX_SIOCGIFFLAGS 0x8913
|
||||||
|
#define LINUX_IFNAMSIZ 16
|
||||||
|
struct linux_ifreq { char lifr_name[16]; short lifr_flags; char pad[22]; };
|
||||||
|
struct ifmediareq {
|
||||||
|
char ifm_name[16];
|
||||||
|
int ifm_current, ifm_mask, ifm_status, ifm_active, ifm_count;
|
||||||
|
int *ifm_ulist;
|
||||||
|
};
|
||||||
|
static short flags;
|
||||||
|
static int ioctl_result;
|
||||||
|
static int __real_ioctl(int fd, int command, struct linux_ifreq *request) {
|
||||||
|
assert(fd == 3 && command == LINUX_SIOCGIFFLAGS);
|
||||||
|
request->lifr_flags = flags; return ioctl_result;
|
||||||
|
}
|
||||||
|
static int handle_socket(int fd, unsigned cmd, void *arg, int *retval) {
|
||||||
|
switch (cmd) { case SIOCGIFMEDIA:
|
||||||
|
''' + handler + r'''
|
||||||
|
}
|
||||||
|
return IOCTL_PASS;
|
||||||
|
}
|
||||||
|
int main(void) {
|
||||||
|
struct ifmediareq request = {.ifm_name = "eth0"};
|
||||||
|
int result = 99, list[] = {-1, -2};
|
||||||
|
flags = IFF_UP | IFF_RUNNING;
|
||||||
|
assert(handle_socket(3, SIOCGIFMEDIA, &request, &result) == IOCTL_HANDLED);
|
||||||
|
assert(result == 0 && request.ifm_count == 1 && request.ifm_ulist == NULL);
|
||||||
|
assert(request.ifm_current == IFM_ETHER && request.ifm_active == IFM_ETHER);
|
||||||
|
assert(request.ifm_status == (IFM_AVALID | IFM_ACTIVE));
|
||||||
|
request.ifm_count = 2; request.ifm_ulist = list;
|
||||||
|
assert(handle_socket(3, SIOCGIFXMEDIA, &request, &result) == IOCTL_HANDLED);
|
||||||
|
assert(result == 0 && request.ifm_count == 1 && request.ifm_ulist == list);
|
||||||
|
assert(list[0] == IFM_ETHER && list[1] == -2);
|
||||||
|
strcpy(request.ifm_name, "wlan0"); request.ifm_count = 1;
|
||||||
|
handle_socket(3, SIOCGIFMEDIA, &request, &result);
|
||||||
|
assert(result == 0 && list[0] == IFM_IEEE80211);
|
||||||
|
flags = 0;
|
||||||
|
handle_socket(3, SIOCGIFMEDIA, &request, &result);
|
||||||
|
assert(result == 0 && request.ifm_status == IFM_AVALID);
|
||||||
|
flags = IFF_UP | IFF_RUNNING | IFF_LOOPBACK;
|
||||||
|
list[0] = -1;
|
||||||
|
handle_socket(3, SIOCGIFMEDIA, &request, &result);
|
||||||
|
assert(result == -ENOTSUP && list[0] == -1 && request.ifm_ulist == list);
|
||||||
|
flags = IFF_UP | IFF_RUNNING; request.ifm_count = -1;
|
||||||
|
handle_socket(3, SIOCGIFMEDIA, &request, &result);
|
||||||
|
assert(result == -EINVAL);
|
||||||
|
request.ifm_count = 1; request.ifm_ulist = NULL;
|
||||||
|
handle_socket(3, SIOCGIFMEDIA, &request, &result);
|
||||||
|
assert(result == -EFAULT);
|
||||||
|
handle_socket(3, SIOCGIFMEDIA, NULL, &result);
|
||||||
|
assert(result == -EINVAL);
|
||||||
|
request.ifm_count = 0; ioctl_result = -ENODEV;
|
||||||
|
handle_socket(3, SIOCGIFMEDIA, &request, &result);
|
||||||
|
assert(result == -ENODEV);
|
||||||
|
}
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Build and run the standalone SIOCGIFMEDIA probe inside Darling.
|
||||||
|
|
||||||
|
No Riot or League process is started. The probe only enumerates local
|
||||||
|
interfaces and issues SIOCGIFMEDIA, which is the call Vivox uses before
|
||||||
|
vx_req_connector_create.
|
||||||
|
"""
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
CONFIG = ROOT / 'build/config.json'
|
||||||
|
SOURCE = ROOT / 'tools/riot-ifmedia-check.c'
|
||||||
|
OUTPUT = ROOT / 'build/riot-ifmedia-check'
|
||||||
|
|
||||||
|
|
||||||
|
def find_sdk():
|
||||||
|
candidates = [
|
||||||
|
ROOT / 'build/darling-src/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk',
|
||||||
|
ROOT / 'build/darling-src/build/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk',
|
||||||
|
]
|
||||||
|
for candidate in candidates:
|
||||||
|
if (candidate / 'usr/include/sys/socket.h').is_file():
|
||||||
|
return candidate
|
||||||
|
raise SystemExit('MacOSX.sdk not found; run ./scripts/build.sh first')
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument('--guest-home', default=None,
|
||||||
|
help='guest home, e.g. /Users/example (default: build/config.json)')
|
||||||
|
parser.add_argument('--library-path', default=None,
|
||||||
|
help='extra guest DYLD_LIBRARY_PATH entry, e.g. a rebuilt kernel overlay')
|
||||||
|
parser.add_argument('--timeout', type=float, default=60)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
config = json.loads(CONFIG.read_text()) if CONFIG.exists() else {}
|
||||||
|
guest_home = args.guest_home or config.get('guest_home')
|
||||||
|
if not guest_home:
|
||||||
|
guest_home = '/Users/' + os.environ.get('USER', '')
|
||||||
|
sdk = find_sdk()
|
||||||
|
|
||||||
|
clang = shutil.which('clang')
|
||||||
|
if not clang:
|
||||||
|
raise SystemExit('clang not found')
|
||||||
|
OUTPUT.parent.mkdir(exist_ok=True)
|
||||||
|
subprocess.run([
|
||||||
|
clang, '-target', 'x86_64-apple-macosx11.0', '-D__DARWIN_UNIX03=0',
|
||||||
|
'-fuse-ld=lld', '-nostdlib', '-isysroot', str(sdk),
|
||||||
|
str(SOURCE), '-lSystem', '-o', str(OUTPUT),
|
||||||
|
], check=True)
|
||||||
|
|
||||||
|
libraries = guest_home.rstrip('/') + '/RuntimeLibraries'
|
||||||
|
if args.library_path:
|
||||||
|
libraries = args.library_path.rstrip('/') + ':' + libraries
|
||||||
|
guest_probe = '/Volumes/SystemRoot' + str(OUTPUT)
|
||||||
|
env = {key: os.environ[key] for key in ('PATH', 'HOME', 'USER', 'LOGNAME', 'DISPLAY',
|
||||||
|
'XAUTHORITY', 'XDG_RUNTIME_DIR', 'DBUS_SESSION_BUS_ADDRESS', 'LANG') if key in os.environ}
|
||||||
|
result = subprocess.run([
|
||||||
|
'darling', 'shell', 'env', 'DYLD_LIBRARY_PATH=' + libraries,
|
||||||
|
guest_probe,
|
||||||
|
], env=env, timeout=args.timeout)
|
||||||
|
return result.returncode
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main())
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// Vivox's network reachability provider calls SIOCGIFMEDIA on each interface
|
||||||
|
// and drops every interface whose ioctl fails. Darling used to pass the Darwin
|
||||||
|
// request through to Linux, which returns ENOTTY.
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_media.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/sockio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static int check(const char *name, int required) {
|
||||||
|
int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
struct ifmediareq ifmr;
|
||||||
|
memset(&ifmr, 0, sizeof(ifmr));
|
||||||
|
strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name) - 1);
|
||||||
|
errno = 0;
|
||||||
|
int rc = ioctl(sock, SIOCGIFMEDIA, &ifmr);
|
||||||
|
close(sock);
|
||||||
|
int active = (ifmr.ifm_status & (IFM_AVALID | IFM_ACTIVE)) == (IFM_AVALID | IFM_ACTIVE);
|
||||||
|
int known_type = IFM_TYPE(ifmr.ifm_current) == IFM_ETHER ||
|
||||||
|
IFM_TYPE(ifmr.ifm_current) == IFM_IEEE80211;
|
||||||
|
printf("IFMEDIA interface=%s rc=%d errno=%d current=0x%x status=0x%x active=%d type=%d\n",
|
||||||
|
name, rc, errno, ifmr.ifm_current, ifmr.ifm_status, active, known_type);
|
||||||
|
if (rc != 0) return required;
|
||||||
|
return required && (!active || !known_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
int failures = 0;
|
||||||
|
if (argc > 1) {
|
||||||
|
for (int i = 1; i < argc; i++) failures += check(argv[i], 1);
|
||||||
|
} else {
|
||||||
|
struct ifaddrs *interfaces = NULL;
|
||||||
|
char name[IFNAMSIZ] = {0};
|
||||||
|
if (getifaddrs(&interfaces) != 0) {
|
||||||
|
printf("IFMEDIA getifaddrs failed errno=%d\n", errno);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
for (struct ifaddrs *entry = interfaces; entry; entry = entry->ifa_next) {
|
||||||
|
if (!entry->ifa_addr || entry->ifa_addr->sa_family != AF_INET) continue;
|
||||||
|
if (entry->ifa_flags & IFF_LOOPBACK) continue;
|
||||||
|
strncpy(name, entry->ifa_name, sizeof(name) - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
freeifaddrs(interfaces);
|
||||||
|
if (!name[0]) {
|
||||||
|
printf("IFMEDIA no non-loopback IPv4 interface\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
failures += check(name, 1);
|
||||||
|
}
|
||||||
|
printf("IFMEDIA_CHECK failures=%d\n", failures);
|
||||||
|
return failures ? 1 : 0;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user