Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
8eb4e8a
Add MAC address include/exclude filtering for nftables auto-redirect
nekohasekai Mar 3, 2026
c406dd1
draft: windows auto redirect
nekohasekai Mar 11, 2026
29f3a52
Fix windows redirect driver: unique GUIDs, config locking, paged pool
nekohasekai Mar 26, 2026
9a64b3d
Add VS project files for winredirect driver
nekohasekai Mar 26, 2026
0747b28
Disable Spectre mitigation for driver build
nekohasekai Mar 26, 2026
fae30d8
Fix: move SpectreMitigation to PropertyGroup level
nekohasekai Mar 26, 2026
55ca672
Fix driver: downgrade to WFP v1 APIs for older WDK compatibility
nekohasekai Mar 26, 2026
d66a9a8
Fix FwpsPendClassify0 signature, suppress deprecation warnings
nekohasekai Mar 26, 2026
b3d27a4
Fix linker: add initguid.h, wdmsec.lib, uuid.lib; disable InfVerif
nekohasekai Mar 26, 2026
4592a8c
Remove uuid.lib, override InfVerif/Inf2Cat targets
nekohasekai Mar 26, 2026
035a441
Fix BSOD: add FWPS_RIGHT_ACTION_WRITE check, NULL pointer guards for …
nekohasekai Mar 27, 2026
db80806
Fix Windows auto-redirect async redirect flow
nekohasekai Mar 27, 2026
fde0bea
Add Windows auto-redirect soak harness
nekohasekai Mar 27, 2026
50f2f37
Gate Windows auto-redirect by best route
nekohasekai Mar 27, 2026
804fef4
Update .gitignore
nekohasekai Mar 27, 2026
33d32a4
Use GUID route gating for Windows auto-redirect
nekohasekai Mar 27, 2026
3982524
Fix Windows driver route status check
nekohasekai Mar 27, 2026
f3de8ca
Fix Windows driver warnings
nekohasekai Mar 27, 2026
fa93cb0
Fix Windows auto-redirect test harness
nekohasekai Mar 27, 2026
d728fea
Update embedded Windows redirect drivers
nekohasekai Mar 27, 2026
a97a179
windows: fail fast on redirect runtime errors
nekohasekai Mar 27, 2026
4337150
windows: pass context through auto redirect
nekohasekai Mar 27, 2026
80f9f8c
windows: fix GetBestRoute2 NULL param, add fatal error context
nekohasekai Mar 27, 2026
4aea1b6
windows: simplify auto-redirect startup and TUN GUID resolution
nekohasekai Mar 27, 2026
b211d06
windows: clean up dead code, comments, and fix goroutine leak
nekohasekai Mar 27, 2026
8a062ad
Clarify Windows route lookup fallback
nekohasekai Mar 27, 2026
7bcf9d1
Clarify Windows ErrReset bypass semantics
nekohasekai Mar 27, 2026
1b2f80f
windows: fail-fast on stuck pending entries instead of auto-bypass
nekohasekai Mar 27, 2026
aff1ecf
windows: remove dead code and fix struct packing
nekohasekai Mar 27, 2026
e432565
windows: fix review issues in auto-redirect
nekohasekai Mar 27, 2026
85dc2d5
windows: fail open timed-out redirect verdicts
nekohasekai Mar 27, 2026
9b306c0
windows: modernize driver API usage and simplify GUID handling
nekohasekai Mar 27, 2026
255b479
ci: sync bundled winredirect drivers
nekohasekai Mar 28, 2026
259fc61
ci: capture arm64 driver diagnostics
nekohasekai Mar 28, 2026
88d3474
ci: print visual studio catalog version
nekohasekai Mar 28, 2026
3a3849d
ci: print arm64 library hashes
nekohasekai Mar 28, 2026
5d4df52
winredirect: simplify Windows verdict handling
nekohasekai Mar 28, 2026
3d4d916
winredirect: Add CI build
nekohasekai Mar 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions .github/docker/msvc-wine.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Cross-compiles Windows kernel drivers using msvc-wine.
# Toolchain: MSVC 17.13 + SDK/WDK 10.0.22621
# Architectures: x86, x64, ARM, ARM64
FROM alpine:3.21 AS msvc-wine
RUN apk add --no-cache git
RUN git clone https://github.com/mcha-forks/msvc-wine.git /msvc-wine \
&& cd /msvc-wine && git checkout 2d5f5a3

FROM registry.fedoraproject.org/fedora-minimal:44 AS wine

COPY <<-'EOF' /etc/yum.repos.d/_copr:copr.fedorainfracloud.org:mochaa:wine.repo
[copr:copr.fedorainfracloud.org:mochaa:wine]
name=Copr repo for wine owned by mochaa
baseurl=https://download.copr.fedorainfracloud.org/results/mochaa/wine/fedora-$releasever-$basearch/
type=rpm-md
skip_if_unavailable=True
gpgcheck=1
gpgkey=https://download.copr.fedorainfracloud.org/results/mochaa/wine/pubkey.gpg
repo_gpgcheck=0
enabled=1
enabled_metadata=1

[copr:copr.fedorainfracloud.org:mochaa:wine:ml]
name=Copr repo for wine owned by mochaa (i386)
baseurl=https://download.copr.fedorainfracloud.org/results/mochaa/wine/fedora-$releasever-i386/
type=rpm-md
skip_if_unavailable=True
gpgcheck=1
gpgkey=https://download.copr.fedorainfracloud.org/results/mochaa/wine/pubkey.gpg
repo_gpgcheck=0
cost=1100
enabled=1
enabled_metadata=1
EOF

RUN <<-EOF
set -xeu
microdnf install -y wine-core wine-core.i686 wine-mono
microdnf clean all
EOF

RUN <<-EOF
set -xeu
wine wineboot -u
wine reg.exe add HKCU\\Software\\Wine\\Drivers /v Graphics /t REG_SZ /d null
wineserver -w
EOF

WORKDIR /builddir

FROM wine AS fetch-wdk
COPY --from=msvc-wine /msvc-wine/wdk-download.sh ./
RUN WINEDEBUG=1 bash -x ./wdk-download.sh --cache wdk https://go.microsoft.com/fwlink/?linkid=2330411

FROM python:3.14-slim AS fetch-msvc
WORKDIR /builddir
COPY --from=msvc-wine /msvc-wine/vsdownload.py ./
RUN PYTHONUNBUFFERED=1 ./vsdownload.py --accept-license --only-download --cache cache \
--major=17 --msvc-version=17.13 --sdk-version=10.0.22621 --with-wdk-installer wdk/Installers \
Microsoft.Component.MSBuild

FROM wine AS builder
RUN <<-EOF
microdnf install -y git msitools perl
microdnf clean all
EOF
COPY --from=fetch-msvc /builddir/cache/ ./cache/
COPY --from=fetch-wdk /builddir/wdk/Installers/ ./wdk/Installers/
COPY --from=msvc-wine /msvc-wine/vsdownload.py ./
COPY --from=msvc-wine /msvc-wine/patches/ ./patches/
RUN PYTHONUNBUFFERED=1 python3 ./vsdownload.py --accept-license --cache cache --dest /opt/msvc \
--major=17 --msvc-version=17.13 --sdk-version=10.0.22621 --with-wdk-installer wdk/Installers \
Microsoft.Component.MSBuild
COPY --from=msvc-wine /msvc-wine/lowercase /msvc-wine/fixinclude /msvc-wine/install.sh /msvc-wine/msvctricks.cpp ./
COPY --from=msvc-wine /msvc-wine/wrappers/ ./wrappers/
RUN bash -x ./install.sh /opt/msvc
# WDK 22621 MSBuild targets reject Win32/ARM for km drivers (removed in Windows 11).
# The km libraries for these arches are present; only the validation blocks them.
RUN find -L /opt/msvc -iname 'windowsdriver.common.targets' \
-exec sed -i '/not a valid architecture for Kernel mode/s/<Error/<Message/' {} +

FROM wine
COPY --from=builder /opt/msvc /opt/msvc
89 changes: 89 additions & 0 deletions .github/scripts/compare_signed_pe.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/usr/bin/env python3

from __future__ import annotations

import argparse
import hashlib
import sys
from pathlib import Path


class PEFormatError(ValueError):
pass


def read_u16(data: bytes, offset: int) -> int:
return int.from_bytes(data[offset:offset + 2], "little")


def read_u32(data: bytes, offset: int) -> int:
return int.from_bytes(data[offset:offset + 4], "little")


def canonicalize_signed_pe(path: Path) -> bytes:
data = bytearray(path.read_bytes())
if len(data) < 0x40 or data[:2] != b"MZ":
raise PEFormatError(f"{path}: missing DOS header")

pe_offset = read_u32(data, 0x3C)
if pe_offset + 24 > len(data) or data[pe_offset:pe_offset + 4] != b"PE\x00\x00":
raise PEFormatError(f"{path}: missing PE header")

optional_offset = pe_offset + 24
magic = read_u16(data, optional_offset)
if magic == 0x10B:
data_directory_offset = optional_offset + 96
elif magic == 0x20B:
data_directory_offset = optional_offset + 112
else:
raise PEFormatError(f"{path}: unsupported optional header magic 0x{magic:04x}")

checksum_offset = optional_offset + 64
if checksum_offset + 4 > len(data):
raise PEFormatError(f"{path}: truncated optional header")
data[checksum_offset:checksum_offset + 4] = b"\x00" * 4

security_directory_offset = data_directory_offset + 8 * 4
if security_directory_offset + 8 > len(data):
raise PEFormatError(f"{path}: truncated data directories")

certificate_offset = read_u32(data, security_directory_offset)
certificate_size = read_u32(data, security_directory_offset + 4)
data[security_directory_offset:security_directory_offset + 8] = b"\x00" * 8

if certificate_offset == 0 or certificate_size == 0:
return bytes(data)

certificate_end = certificate_offset + certificate_size
if certificate_end > len(data):
raise PEFormatError(f"{path}: certificate table exceeds file size")

return bytes(data[:certificate_offset] + data[certificate_end:])


def canonical_sha256(path: Path) -> str:
return hashlib.sha256(canonicalize_signed_pe(path)).hexdigest()


def main() -> int:
parser = argparse.ArgumentParser(
description="Compare two PE files after stripping Authenticode-only differences.",
)
parser.add_argument("left", type=Path)
parser.add_argument("right", type=Path)
args = parser.parse_args()

try:
left_hash = canonical_sha256(args.left)
right_hash = canonical_sha256(args.right)
except (OSError, PEFormatError) as exc:
print(exc, file=sys.stderr)
return 2

print(f"{args.left}: {left_hash}")
print(f"{args.right}: {right_hash}")
return 0 if left_hash == right_hash else 1


if __name__ == "__main__":
raise SystemExit(main())
160 changes: 160 additions & 0 deletions .github/workflows/winredirect-driver-sync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
name: sync winredirect driver

on:
pull_request:
branches:
- main
- dev
paths:
- '.github/docker/msvc-wine.dockerfile'
- '.github/scripts/compare_signed_pe.py'
- '.github/workflows/winredirect-driver-sync.yml'
- 'internal/winredirect/driver/**'

permissions:
contents: write

concurrency:
group: winredirect-driver-${{ github.event.pull_request.head.repo.full_name }}-${{ github.event.pull_request.head.ref }}
cancel-in-progress: true

jobs:
sync:
name: Refresh bundled drivers
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- name: Checkout PR head
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.ref }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build msvc-wine image
uses: docker/build-push-action@v6
with:
file: .github/docker/msvc-wine.dockerfile
load: true
tags: msvc-wine:local
cache-from: type=gha,scope=msvc-wine
cache-to: type=gha,mode=max,scope=msvc-wine

- name: Print toolchain versions
run: |
docker run --rm msvc-wine:local /opt/msvc/bin/x64/cl 2>&1 | head -2 || true
echo "SDK/WDK include versions:"
docker run --rm msvc-wine:local ls /opt/msvc/kits/10/include/
echo "WDK km lib architectures:"
docker run --rm msvc-wine:local sh -c 'ls /opt/msvc/kits/10/lib/*/km/ 2>/dev/null' || true
echo "WindowsDriver.common.targets (arch validation):"
docker run --rm msvc-wine:local sh -c 'find /opt/msvc -name "WindowsDriver.common.targets" -exec grep -n -i "valid architecture\|_SUPPORTED" {} +' 2>/dev/null || true

- name: Build, verify reproducibility, and refresh tracked drivers
id: sync
run: |
set -euo pipefail

arches=(x64 arm64 x86)
platforms=(x64 ARM64 Win32)
tracked=(
internal/winredirect/amd64/winredirect.sys
internal/winredirect/arm64/winredirect.sys
internal/winredirect/x86/winredirect.sys
)

changed=false
artifact_dir="${RUNNER_TEMP}/winredirect-driver-sync"
failure_dir="${artifact_dir}/failure"
mkdir -p "$artifact_dir"

build_driver() {
docker run --rm \
-v "$PWD:/src" -w /src \
-e CL=/Brepro -e LINK=/Brepro \
msvc-wine:local \
/opt/msvc/bin/"$1"/msbuild \
internal/winredirect/driver/winredirect.vcxproj \
/t:Rebuild /p:Configuration=Release /p:SpectreMitigation=false /p:TrackFileAccess=false /v:minimal
}

for i in "${!arches[@]}"; do
arch="${arches[$i]}"
platform="${platforms[$i]}"
tracked_file="${tracked[$i]}"
build_output="internal/winredirect/driver/build/${platform}/Release/winredirect.sys"
run1="${artifact_dir}/${arch}-run1.sys"
run2="${artifact_dir}/${arch}-run2.sys"

echo "::group::Build ${arch} run 1"
build_driver "$arch"
cp "$build_output" "$run1"
echo "::endgroup::"

echo "::group::Build ${arch} run 2"
build_driver "$arch"
cp "$build_output" "$run2"
echo "::endgroup::"

echo "::group::Verify ${arch} reproducibility"
rc=0
python3 .github/scripts/compare_signed_pe.py "$run1" "$run2" || rc=$?
case $rc in
0)
echo "${arch} reproduced after stripping Authenticode data."
;;
1)
mkdir -p "$failure_dir"
cp "$run1" "${failure_dir}/${arch}-run1.sys"
cp "$run2" "${failure_dir}/${arch}-run2.sys"
echo "::error::${arch} build is not reproducible beyond signing metadata."
exit 1
;;
*)
echo "::error::Reproducibility comparison failed for ${arch} with exit code ${rc}"
exit "$rc"
;;
esac
echo "::endgroup::"

echo "::group::Compare ${arch} with tracked driver"
rc=0
python3 .github/scripts/compare_signed_pe.py "$run2" "$tracked_file" || rc=$?
case $rc in
0)
echo "${arch} matches the tracked driver after stripping Authenticode data."
;;
1|2)
echo "${arch} differs beyond signing metadata (rc=${rc}); replacing tracked driver."
cp "$run2" "$tracked_file"
git add -- "$tracked_file"
changed=true
;;
*)
echo "::error::Comparison failed for ${arch} with exit code ${rc}"
exit "$rc"
;;
esac
echo "::endgroup::"
done

echo "changed=${changed}" >> "$GITHUB_OUTPUT"

- name: Upload failed reproducibility artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: winredirect-repro-failure-${{ github.run_id }}-${{ github.run_attempt }}
path: ${{ runner.temp }}/winredirect-driver-sync/failure/*.sys
if-no-files-found: warn

- name: Commit and push refreshed drivers
if: steps.sync.outputs.changed == 'true'
run: |
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git diff --cached --quiet && exit 0
git commit -m 'winredirect: update bundled drivers'
git push origin "HEAD:${{ github.event.pull_request.head.ref }}"
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
.DS_Store
!/README.md
/*.md
/.claude/
/CLAUDE.md
Loading
Loading