feat(native-proxy): OS proxy configuration (Windows + macOS + Linux) - #427
Draft
kdroidFilter wants to merge 6 commits into
Draft
feat(native-proxy): OS proxy configuration (Windows + macOS + Linux)#427kdroidFilter wants to merge 6 commits into
kdroidFilter wants to merge 6 commits into
Conversation
New `native-proxy` module exposing the OS proxy configuration, modelled on `native-ssl` and ported from Chromium's `net::ProxyConfigServiceWin` and `net::ProxyResolverWinHttp`: - `WinHttpGetIEProxyConfigForCurrentUser` for the effective configuration (WPAD flag, PAC URL, proxy string, bypass list) - `WinHttpGetProxyForUrl` for PAC/WPAD resolution, without auto-logon first and retried with it only on ERROR_WINHTTP_LOGIN_FAILURE - `RegNotifyChangeKeyValue` on the Internet Settings / Policies / Connections keys for change notification, with Chromium's 2 s coalescing delay - Chromium-compatible parsing of per-scheme proxy strings and bypass rules (glob patterns, CIDR blocks, `<local>`, `<-loopback>`, implicit loopback) `NativeProxy.install()` publishes a `ProxySelector` backed by the OS configuration, keeping the previous default as fallback. macOS and Linux use a no-op provider: `isSupported` is false and everything degrades to direct.
Port Chromium's ProxyConfigServiceLinux resolution order: - GNOME-like: org.gnome.system.proxy via dlopen'd libgio - KDE: kioslaverc under ~/.config and XDG_CONFIG_DIRS - Fallback: http_proxy / https_proxy / all_proxy / no_proxy / SOCKS_SERVER PAC/WPAD is reported but not evaluated (no WinHTTP equivalent). Change detection polls the configuration; GSettings D-Bus signals require a process-default GMainContext the JVM does not drive.
kdroidFilter
force-pushed
the
feat/native-proxy
branch
from
August 5, 2026 21:36
37d230c to
c3e9677
Compare
InterlockedCompareExchangePointer is not a freestanding intrinsic on ARM64 MSVC and pulls an unresolved _InterlockedCompareExchangePointer under /NODEFAULTLIB. Use InitOnceExecuteOnce (kernel32) for the WinHTTP session and wake-event singletons, and fail the ARM64 link step hard when it errors.
Port Chromium's ProxyConfigServiceMac / ProxyResolverApple: - SCDynamicStoreCopyProxies for the effective configuration (per-scheme HTTP/HTTPS/FTP/SOCKS, ExceptionsList, ExcludeSimpleHostnames, PAC URL, ProxyAutoDiscoveryEnable) - CFNetworkExecuteProxyAutoConfigurationURL for PAC evaluation, pumping a private CFRunLoop mode so the call stays synchronous from the JVM - SCDynamicStore notification keys for change detection (no polling) Verified on a Mac with a live HTTP/HTTPS/SOCKS proxy: config matches `scutil --proxy`, loopback stays DIRECT, install() wires the JVM selector.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
New
native-proxymodule — the proxy counterpart tonative-ssl: it exposes theOS proxy configuration to JVM desktop apps on Windows, macOS and Linux.
The implementation follows Chromium's proxy stack so the effective proxy matches
what Edge/Chrome/Safari resolve, including machine-wide and managed settings.
ProxyConfigServiceWin+ProxyResolverWinHttpProxyConfigServiceMac+ProxyResolverAppleSCDynamicStore+CFNetworkExecuteProxyAutoConfigurationURLProxyConfigServiceLinuxorg.gnome.system.proxy) → KDEkioslaverc→ env varsSystemProxySettings(autoDetect / pacUrl / rules / bypass)net::ProxyConfigProxyRules— single list vs per-scheme (http=…;https=…;socks=…),socks=defaults to SOCKS4 and serves unlisted schemesProxyConfig::ProxyRules::ParseFromStringProxyBypassRules/BypassRule— glob hostname patterns, leading.rewritten to*.,:portandscheme://restrictions, CIDR blocks,<local>,<-loopback>, implicit localhost + link-local bypassnet::ProxyBypassRulesfAutoLogonIfChallenged=FALSEfirst, retriedTRUEonly onERROR_WINHTTP_LOGIN_FAILUREProxyResolverWinHttpCFNetworkExecuteProxyAutoConfigurationURLon a private CFRunLoop mode (10 s timeout)ProxyResolverAppleRegNotifyChangeKeyValueon the 6 HKCU/HKLM Internet Settings + Policies + Connections keys, 2 s coalescing delayProxyConfigServiceWinSCDynamicStoreproxy-key notifications, 2 s coalescing delayProxyConfigServiceMacGMainContextthe JVM does not drive)Native bridges
nucleus_proxy.dll(x64 + ARM64),/NODEFAULTLIBCRT-free likenative-sslnativeGetProxyConfig()→WinHttpGetIEProxyConfigForCurrentUseras 4 stringsnativeResolveProxyForUrl(url, pacUrl)→ proxy list,""for DIRECT,nullon failurenativeWaitForConfigChange/nativeWakeWatcher— blocking registry wait (no native callbacks, no polling)libnucleus_proxy.dylib(arm64 + x86_64)nativeGetProxyConfig()→SCDynamicStoreCopyProxiesas the same 4-string layoutnativeResolveProxyForUrl(url, pacUrl)→ PAC via CFNetworknativeWaitForConfigChange/nativeWakeWatcher—SCDynamicStoreon the current CFRunLooplibnucleus_proxy.so(x64 + aarch64), GIO resolved withdlopen(no hard libgio link)kioslaverc+http_proxy/no_proxy/… env fallback in KotlinThe 4-string config array is shared across platforms so Kotlin feeds the same
ProxyRules/ProxyBypassRulesparsers:http=…;https=…;socks=…);-joined; macOS appends<local>when ExcludeSimpleHostnames is set)"1"/"0")API
install()keeps the previous default selector as a fallback, so the JDKhttp.proxyHostproperties keep working for URIs the OS has no opinion on.Resolution order per URL: bypass list → PAC script → static rules (the
latter also being the fallback when the script cannot be evaluated). PAC
results are cached per origin and dropped on every configuration change.
Platform caveats
without embedding a JS engine) — only static rules and bypass lists.
autoDetectbut not evaluated: when DHCP WPAD succeeds, Apple embeds the discovered PAC
URL into the system settings, so an empty
pacUrlalmost always means thereis nothing to run.
Verification
:native-proxy:checkgreen (detekt + ktlint + unit tests for the parsers,bypass matcher, env/KDE helpers, and per-platform load/read smoke tests)
localhost→ DIRECT, registry write detected by the watcher,nativeWakeWatcherreleases the parked thread immediately
scutil --proxy:HTTP/HTTPS/SOCKS hosts match, loopback stays DIRECT,
install()wires theJVM selector
.sobuilds on x64/aarch64; GSettings/KDE/env unit tests +optional E2E via
NUCLEUS_PROXY_E2E=trueFollow-ups (not in this PR)
native-http/native-http-okhttp/native-http-ktor