Hi All,
I am working on a macOS System Extension using Apple’s Network Extension Framework, designed to observe and log network activity at multiple layers. The system extension is currently stable and working as expected for HTTP and DNS traffic with 3 providers, getting Socket, HTTP, and DNS logs.
Current Architecture Overview
The project consists of two Xcode targets:
1. Main App Process
-
Responsible for:
- Managing system extension lifecycle (activation, configuration)
- Establishing IPC (XPC) communication with extensions
- Receiving structured logs from extensions
- Writing logs efficiently to disk using a persistent file handle
-
Uses:
OSSystemExtensionManagerNEFilterManager,NETransparentProxyManager,NEDNSProxyManagerNWPathMonitorfor network availability handling- Persistent logging mechanism (
FileHandle)
2. System Extension Process
Contains three providers, all running within a single system extension process:
a) Content Filter (NEFilterDataProvider)
-
Captures socket-level metadata
-
Extracts:
- PID via audit token
- Local/remote endpoints
- Protocol (TCP/UDP, IPv4/IPv6)
- Direction (inbound/outbound)
-
Sends structured JSON logs via shared IPC
b) Transparent Proxy (NETransparentProxyProvider)
- Intercepts TCP flows
- Creates a corresponding
NWConnectionto the destination - Captures both HTTP and HTTPS traffic, sends it to HTTPFlowLogger file which bypasses if it's not HTTP traffic.
- Uses a custom
HTTPFlowLogger:- Built using SwiftNIO library (NIO HTTP1)
- Parses up to HTTP/1.1 traffic
- Handles streaming, headers, and partial body capture (with size limits)
- Maintains per-flow state and lifecycle management
- Logs structured HTTP data via shared IPC
c) DNS Proxy (NEDNSProxyProvider)
- Intercepts UDP DNS traffic
- Forwards queries to upstream resolver (system DNS or fallback)
- Maintains shared UDP connection
- Tracks pending requests using DNS IDs
- Parses DNS packets (queries + responses) using a custom parser
- Logs structured DNS metadata via shared IPC
Shared Component: IPCConnection
-
Single bidirectional XPC channel used by all providers
-
Handles:
- App → Extension registration
- Extension → App logging
-
Uses Mach service defined in system extension entitlements
Project Structure
NetworkExtension (Project)
│
├── NetworkExtension (Target 1: Main App)
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── Info.plist
│ ├── NetworkExtension.entitlements
│ ├── Main.storyboard
│ └──ViewController.swift
│
├── SystemExtensions (Target 2: Extension Process)
│ ├── common/
│ │ ├── IPCConnection.swift
│ │ └── main.swift
│ │
│ ├── DNSProxyProvider/
│ │ ├──DNSDataParser.swift
│ │ └──DNSProxyProvider.swift (DNS Proxy)
│ │
│ ├── FilterDataProvider/
│ │ └── FilterDataProvider.swift
│ │
│ ├── TransparentProxyProvider/
│ │ ├── HTTPLogParser.swift
│ │ ├── LogDataModel.swift
│ │ └──TransparentProxyProvider.swift
│ │
│ ├── Info.plist
│ └── SystemExtensions.entitlements
│
Current Capabilities
-
Unified logging pipeline across:
- Socket-level metadata
- HTTP traffic (HTTP/1.1)
- DNS queries/responses
-
Efficient log handling using persistent file descriptors
-
Stable IPC communication between app and extensions
-
Flow-level tracking and lifecycle management
-
Selective filtering (e.g., bypass rules for specific IPs)
What's the best approach to add TLS Inspection with MITM proxy setup?
Some context and constraints:
- Existing implementation handles HTTP parsing and should remain unchanged (Swift-based).
- I’m okay with bypassing apps/sites that use certificate pinning (e.g., banking apps) and legitimate sites.
- Performance is important — I want to avoid high CPU utilization.
- I’m relatively new to TLS inspection and MITM proxy design.
Questions
- Is it a good idea to implement TLS inspection within a system extension, or does that typically introduce significant complexity and performance overhead?
- As
NETransparentProxyProvideralready intercepting HTTPS traffic, can we redirect it to a separate processing pipeline (e.g., another file/module), while keeping the existing HTTP parser(HTTPFlowLogger - HTTP only parser) intact? - What are the recommended architectural approaches for adding HTTPS parsing via MITM in a performant way?
- Are there best practices for selectively bypassing pinned or sensitive domains while still inspecting other traffic?
- Any guidance on avoiding common pitfalls (e.g., certificate handling, connection reuse, latency issues)?
I’m looking for a clean, maintainable approach to integrate HTTPS inspection into my existing system without unnecessary complexity or performance degradation.
Please let me know if any additional details from my side would help in suggesting the most appropriate approach.
Thanks in advance for your time and insights—I really appreciate it.