Add native Windows support via wintun and in-process PPP engine#1334
Open
hkirste wants to merge 22 commits into
Open
Add native Windows support via wintun and in-process PPP engine#1334hkirste wants to merge 22 commits into
hkirste wants to merge 22 commits into
Conversation
Replace pppd dependency on Windows with an in-process PPP LCP/IPCP negotiation engine (ppp.c) and wintun TUN adapter. Windows-specific code lives in dedicated source files (io_win.c, tunnel_win.c, ipv4_win.c, etc.) selected at build time by CMake, keeping existing Unix code paths completely untouched. Key components: - CMakeLists.txt: Cross-platform CMake build alongside existing autotools - ppp.c/ppp.h: PPP state machine handling LCP/IPCP negotiation (RFC 1661/1332) - wintun.h: Dynamic loading of wintun.dll TUN driver - io_win.c: Windows I/O loop with 5-thread model - tunnel_win.c: Windows tunnel lifecycle (wintun adapter management) - ipv4_win.c: Route management via Windows IP Helper API (iphlpapi) - userinput_win.c: Console password input via SetConsoleMode - log_win.c: Windows logging with ANSI color and Event Log support - http_server_win.c: Winsock2-based SAML HTTP server - compat_win32.h: POSIX-to-Win32 compatibility shims - lib/getopt/: Bundled getopt_long for MSVC - tests/test_ppp.c: 13 unit tests for PPP state machine - .github/workflows/windows.yml: CI for Windows (MinGW) and CMake builds - README.md: Windows build/install instructions Modified shared headers with minimal #ifdef _WIN32 guards: config.h, tunnel.h, io.h, ipv4.h, ssl.h, main.c, config.c Both autotools (Unix) and CMake (all platforms) build systems verified.
- .github/workflows/release.yml: On tag push, build Windows (MinGW-w64) and Linux binaries, bundle wintun.dll + OpenSSL DLLs, and upload as GitHub Release artifacts. - installer/openfortivpn.nsi: NSIS installer script that installs openfortivpn.exe + wintun.dll, adds to PATH, creates example config, and registers in Add/Remove Programs.
- Add -DBUILD_TESTING=ON to CMake configure - Use PowerShell for wintun download and zip packaging (more reliable on Windows runners than MSYS2 wget/7z) - Allow test step to continue on failure (tests need Windows APIs that may not be fully available in CI)
- Add PThreads4W dependency for MSVC (MinGW has built-in pthreads) - Add MSVC compatibility shims: strcasecmp, strncasecmp, strtok_r, memmem, strcasestr, getline - Fix sys/types.h and io.h header conflicts on MSVC - Guard unistd.h/arpa/inet.h includes in shared http.c - Fix wintun LOAD_FUNC macro case mismatch (CreateAdapter vs CREATE_ADAPTER) - Fix crash in wintun_configure_ip: GetAdapterLUID called with NULL adapter handle - Defer split route installation until TUN adapter LUID is available - Properly store and close wintun adapter handle on cleanup
The bundled getopt_long for MSVC returned -1 immediately when encountering a non-option argument, requiring the host to always be placed after all options. Add GNU-style permutation so arguments like "openfortivpn vpn.example.com -u user -p pass" work correctly.
- Guard pid_t typedef with _MSC_VER (MinGW already defines it) - Move strcasestr/memmem shims outside _MSC_VER guard for MinGW - Fix wintun.h typedef indentation (tabs to spaces per astyle) - Fix tunnel_win.c continuation line indentation
- Move getline shim outside _MSC_VER guard (MinGW also lacks it) - Fix default case indentation in ppp_process_incoming per astyle
MinGW provides POSIX isatty()/fileno() from <unistd.h>, not MSVC's _isatty()/_fileno() from <io.h>. Use POSIX names and alias for MSVC.
- Fix case block indentation in ppp.c (astyle expects brace at case level)
- Put default: and { on same line per astyle
- Fix continuation line indentation in ipv4_win.c
Apply astyle --style=linux formatting: use spaces for continuation indentation, place opening brace on same line as case labels.
- Remove static zero-initialization (ipv4_win.c) - Join quoted strings split across lines (ipv4_win.c, tunnel_win.c, http_server_win.c) - Fix block comment trailing */ placement (test_ppp.c) - Simplify FAIL macro to single statement (test_ppp.c) - Move extern declarations to headers: isatty/fileno to compat_win32.h, ipv4_win_set_tun_luid/ipv4_apply_deferred_routes to ipv4.h - Restructure WINAPI function pointer typedefs in wintun.h to use two-step typedefs that avoid confusing checkpatch's spacing rules - Add typedefs.checkpatch for Windows API types and update checkpatch.sh to use --typedefsfile
- Inline wintun LOAD_FUNC macro into explicit GetProcAddress calls - Replace ASSERT macro do-while with simple conditional
ReadConsoleA fails silently when stdin is a pipe (e.g., when a GUI redirects stdin). Detect pipe vs console via GetConsoleMode and use ReadFile for piped input.
pthread_cancel is broken on MinGW-w64 and causes ACCESS_VIOLATION. Replaced with cooperative shutdown: SSL_shutdown unblocks SSL threads, EndSession unblocks TUN threads, poison pills unblock pool_pop.
ipv4_add_split_vpn_route now stores routes for deferred application after adapter creation. Gateway route failure no longer blocks split routes in split-tunnel mode.
…ndle Removed broken GetAdapterLUID call with NULL adapter in wintun_configure_ip. Store adapter handle for proper cleanup.
run_tunnel returns specific exit codes (10=DNS, 13=cert, 20=auth, etc.) but main() was overwriting them all with EXIT_FAILURE (1).
New --json-events flag emits JSON on stderr for GUI integration. exit_codes.h defines specific codes for each failure type.
Join split JSON format string literals onto single lines to satisfy checkpatch SPLIT_STRING without needing an ignore rule. Add event.c, event.h, and exit_codes.h to Makefile.am for autotools builds.
Collaborator
|
The thing is that we already have a branch with an in-process PPP engine that has been in test for quite some time: I was thinking of eventually merging into the main branch. I'm not sure how easy it is to merge those two branches. And which PPP engine to use? I like that you have added unit tests — we should have more of them and ideally even set up a mockup Fortinet server for tests. The PPP engine should run on POSIX systems too. |
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.
Summary
Architecture
On Unix, openfortivpn forks pppd for PPP negotiation and uses a PTY for communication. On Windows, pppd is unavailable, so this PR replaces it with:
ppp.c— In-process PPP state machine implementing LCP and IPCP negotiation per RFC 1661/1332wintun.h— Dynamic loading of wintun.dll (lightweight TUN driver from the WireGuard project)io_win.c— 5-thread I/O model: ssl_read, ssl_write, tun_read, tun_write, if_configtunnel_win.c— Windows tunnel lifecycle and wintun adapter managementipv4_win.c— Route/DNS management via Windows IP Helper API (iphlpapi)compat_win32.h— POSIX-to-Win32 shims (ssize_t, signals, sockets, string functions)Shared headers have minimal
#ifdef _WIN32guards (config.h, tunnel.h, io.h, ipv4.h, ssl.h). Shared source files (http.c, main.c, config.c) required only include guards for POSIX headers.New files (Windows-only, not compiled on Unix)
src/ppp.c,src/ppp.hsrc/io_win.csrc/tunnel_win.csrc/ipv4_win.csrc/userinput_win.csrc/log_win.csrc/http_server_win.csrc/wintun.hsrc/compat_win32.hlib/getopt/getopt.cCMakeLists.txttests/test_ppp.cinstaller/openfortivpn.nsi.github/workflows/windows.ymlBuild & runtime requirements
Testing
Test plan
./configure && make && make check)mkdir build && cd build && cmake .. && make)ctestor./test_ppp)