VPN Tunnel Interface vs Full Tunnel Routing: A Technical Guide
Choose tunnel interface routing if you need simultaneous access to local resources (printers, NAS, Docker networks) and VPN-protected resources – it routes only specific subnets through the VPN while keeping everything else on your direct connection. Choose full tunnel routing if your organization mandates all traffic through the VPN for compliance, or if you need complete protection on untrusted networks like public WiFi. The core difference is control granularity: tunnel interface gives you precise per-subnet routing decisions, while full tunnel encrypts everything at the cost of added latency and lost local network access.
What Is a Tunnel Interface?
A tunnel interface represents a virtual network interface created by the VPN software. Instead of routing all traffic through the VPN, you can treat the tunnel as a specific network route—similar to how you might have multiple network adapters on a single machine. The tunnel interface gets its own IP address from the VPN’s address space, and you decide which traffic flows through it.
On Linux, you can view tunnel interfaces after connecting to a VPN:
ip addr show | grep -i tun
# Output typically shows tun0, tun1, etc. With VPN-assigned IPs
The tunnel interface becomes another pathway into your routing table. You control what goes through it explicitly using routing policies.
Full Tunnel Routing Explained
Full tunnel routing sends every single packet from your device through the VPN tunnel. Nothing goes directly to your local network or ISP. When you connect to a corporate VPN from a coffee shop, full tunnel ensures all your traffic—browsing, email, background updates—appears to originate from the corporate network.
The routing table in full tunnel mode looks something like this:
# Default route points through tunnel (0.0.0.0/0)
ip route show
# 0.0.0.0/0 via 10.8.0.1 dev tun0
Your ISP sees only encrypted traffic heading to the VPN server. Local network resources become inaccessible unless the VPN configuration specifically allows split tunneling—or unless you accept the performance cost of routing everything through the tunnel and back.
Key Differences Between Tunnel Interface and Full Tunnel
The primary distinction involves control granularity. Tunnel interface routing gives you precise control: you can route specific subnets, individual hosts, or even single ports through the VPN while keeping everything else on your direct connection. Full tunnel routing gives you simplicity: one configuration covers all traffic, but you lose the ability to access local resources without going through the VPN first.
Consider a practical scenario. You work remotely and need to access both company resources (which require the VPN) and local network printers or file shares. With tunnel interface routing, you add specific routes:
# Route only corporate subnet through VPN
ip route add 10.0.0.0/8 via 10.8.0.1 dev tun0
# All other traffic uses default gateway
With full tunnel, your local printer becomes unreachable unless you reconfigure the VPN to allow split tunneling or unless you accept that every print job travels through your corporate network.
Performance implications differ significantly. Full tunnel adds latency for every connection since traffic must reach the VPN server before heading to its final destination. A packet to a nearby website might take 50ms directly but 150ms through a VPN server on the other coast. Tunnel interface routing lets you optimize: local traffic stays local, while only VPN-required traffic incurs the tunnel penalty.
Use Cases for Each Approach
When to Use Tunnel Interface Routing
Developers often prefer tunnel interface routing when working with multiple environments. You might need production database access through the VPN while keeping development servers on your direct connection. Container environments benefit particularly from this approach, since Docker networks and Kubernetes clusters need to remain accessible without VPN interference.
Security researchers conducting network analysis sometimes use tunnel interfaces to route only suspicious traffic through an additional layer of protection while maintaining clean access to standard services. The ability to selectively apply VPN protection provides flexibility that full tunnel cannot match.
Network debugging becomes more straightforward with tunnel interfaces. You can route specific traffic through the VPN while capturing local traffic with tools like tcpdump or Wireshark on your primary interface.
When to Use Full Tunnel Routing
Corporate environments frequently mandate full tunnel routing for security compliance. When employees access sensitive systems, organizations need assurance that no traffic escapes the protected path. Regulatory requirements sometimes explicitly require all traffic to flow through approved network inspection points.
Public WiFi protection represents another full tunnel scenario. When connecting from airports, hotels, or coffee shops, full tunnel ensures your traffic never touches the untrusted local network directly. Even seemingly innocuous DNS queries could leak information about your activities.
Threat models involving sophisticated adversaries who might perform traffic analysis benefit from full tunnel. By encrypting everything, you prevent observers from determining which services you access based on packet timing and size patterns.
Implementation Examples
WireGuard Configuration
WireGuard configurations demonstrate tunnel interface routing clearly. The AllowedIPs directive controls what gets routed through the tunnel:
# Full tunnel - route everything
[Peer]
PublicKey = SERVER_PUBLIC_KEY
AllowedIPs = 0.0.0.0/0, ::/0
# Tunnel interface - route only specific subnets
[Peer]
PublicKey = SERVER_PUBLIC_KEY
AllowedIPs = 10.0.0.0/8, 192.168.100.0/24
OpenVPN Split Tunnel
OpenVPN achieves the same with routing directives:
# Full tunnel (default behavior when no special config)
# All traffic encrypted through VPN
# Split tunnel - corporate network only
route 10.0.0.0 255.0.0.0
# Redirect gateway would enable full tunnel instead
macOS Network Extension
For macOS developers building VPN clients, Network Extension frameworks provide programmatic control:
// Creating a tunnel network settings object
let tunnelSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "vpn.example.com")
// Configure DNS - for full tunnel, use VPN DNS
// For split tunnel, keep local DNS or specify different servers
tunnelSettings.dnsSettings = NEDNSSettings(servers: ["10.8.0.1"])
// Configure IPv4 settings with routing
let ipv4Settings = NEIPv4Settings(addresses: ["10.8.0.2"], subnetMasks: ["255.255.255.0"])
// Full tunnel: include 0.0.0.0/0
ipv4Settings.includedRoutes = [NEIPv4Route.default()]
// Split tunnel: include only required subnets
ipv4Settings.includedRoutes = [
NEIPv4Route(destinationAddress: "10.0.0.0", subnetMask: "255.0.0.0"),
NEIPv4Route(destinationAddress: "192.168.100.0", subnetMask: "255.255.255.0")
]
Security Considerations
Tunnel interface routing introduces potential information leakage. DNS queries for non-VPN domains might still go through your ISP’s DNS servers, revealing your browsing destinations. Always configure tunnel DNS settings to match your routing:
# Ensure DNS queries for VPN-routed domains go through VPN
resolvectl tun0 dns 10.8.0.1
Full tunnel simplifies this concern but creates a single point of failure. If the VPN connection drops, applications might silently fall back to direct connections. Always use kill switches with full tunnel configurations:
# WireGuard kill switch using iptables
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -o wg0 -j ACCEPT
iptables -A OUTPUT -j DROP
Choosing the Right Approach
Your specific requirements determine the best choice. Consider these questions:
Do you need simultaneous access to local network resources and VPN-protected resources? Tunnel interface routing becomes necessary. Local printers, smart home devices, or network-attached storage all require direct local access.
Does your organization mandate all traffic through the VPN for compliance? Full tunnel satisfies security requirements without exception.
Are you primarily concerned about public WiFi eavesdropping while wanting minimal performance impact? Tunnel interface routing lets you protect sensitive traffic while maintaining reasonable speeds for everything else.
Do you run services that need to be accessible from your local network while the VPN runs? Full tunnel blocks incoming connections unless explicitly port-forwarded through the VPN.
Understanding these tradeoffs enables informed decisions rather than one-size-fits-all configurations. Most modern VPN clients support both approaches, giving you the flexibility to choose based on your current task.
Advanced Routing Policy Management
For complex network scenarios, policy-based routing provides granular control:
# Linux: Advanced policy routing beyond basic tunnel/full tunnel
# Add multiple routing tables for different traffic classes
# Define routing tables
echo "200 corporate" >> /etc/iproute2/rt_tables
echo "201 personal" >> /etc/iproute2/rt_tables
# Create rules for VPN routing
ip rule add from 192.168.1.100 lookup corporate
ip rule add from 192.168.1.101 lookup personal
# Configure corporate table (through VPN)
ip route add 10.0.0.0/8 via 10.8.0.1 dev tun0 table corporate
ip route add 0.0.0.0/0 via 10.8.0.1 dev tun0 table corporate
# Configure personal table (direct connection)
ip route add 0.0.0.0/0 via 192.168.1.1 dev eth0 table personal
# Verify routing
ip route show table corporate
ip route show table personal
This enables per-source routing where different devices on your network use different tunnel configurations.
DNS Configuration for Split Routing
DNS remains the critical leak vector in tunnel interface configurations:
# Systemd-resolved with per-interface DNS
cat > /etc/systemd/resolved.conf.d/vpn-dns.conf <<EOF
[Resolve]
# VPN tunnel interface gets VPN DNS
DNS=10.8.0.1
Domains=corporate.internal
# Local interface gets local DNS
FallbackDNS=8.8.8.8
EOF
# Verify DNS routing by interface
resolvectl status
# Test DNS leak for specific domain
nslookup corporate.internal
# Should use 10.8.0.1 (VPN)
nslookup google.com
# Should use ISP DNS (if split tunnel is configured)
Incorrect DNS configuration undermines tunnel interface security, allowing local observers to determine which services you access.
Linux iptables Rules for Tunnel Interface Enforcement
For systems requiring no DNS leaks regardless of application misconfiguration:
#!/bin/bash
# Strict tunnel interface firewall rules
# Default: drop all traffic
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
# Allow loopback
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# Allow established connections
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow VPN interface traffic
iptables -A OUTPUT -o tun0 -j ACCEPT
iptables -A INPUT -i tun0 -j ACCEPT
# Allow VPN tunnel creation traffic to specific server
iptables -A OUTPUT -d YOUR_VPN_SERVER -p tcp --dport 1194 -j ACCEPT
iptables -A OUTPUT -d YOUR_VPN_SERVER -p udp --dport 1194 -j ACCEPT
# Allow specific local traffic (e.g., printer)
iptables -A OUTPUT -d 192.168.1.100 -j ACCEPT
# DNS over VPN only
iptables -A OUTPUT -p udp --dport 53 -o tun0 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -o tun0 -j ACCEPT
# Save rules
iptables-save > /etc/iptables/rules.v4
This enforcement ensures no application can bypass the tunnel interface through misconfiguration.
macOS Packet Tunnel Implementation
macOS developers building VPN extensions need to implement packet filtering:
// Implementing split tunnel in Network Extension
class SplitTunnelPacketHandler {
let allowedDomains = ["corporate.com", "internal.example.com"]
func shouldRouteThroughTunnel(for address: String) -> Bool {
// Check if address matches allowed domains
for domain in allowedDomains {
if address.hasSuffix(domain) {
return true
}
}
return false
}
func setupSplitTunnelRoutes() {
let tunnelSettings = NEPacketTunnelNetworkSettings(
tunnelRemoteAddress: "vpn.example.com"
)
// Configure DNS for corporate domain only
let dnsSettings = NEDNSSettings(servers: ["10.8.0.1"])
dnsSettings.matchDomains = ["corporate.com", "internal.example.com"]
tunnelSettings.dnsSettings = dnsSettings
// IPv4 routing: split tunnel approach
let ipv4Settings = NEIPv4Settings(
addresses: ["10.8.0.2"],
subnetMasks: ["255.255.255.0"]
)
// Only route corporate networks through VPN
ipv4Settings.includedRoutes = [
NEIPv4Route(destinationAddress: "10.0.0.0", subnetMask: "255.0.0.0"),
NEIPv4Route(destinationAddress: "172.16.0.0", subnetMask: "255.240.0.0")
]
tunnelSettings.ipv4Settings = ipv4Settings
}
}
Windows Network Extension (Wintun)
Windows users can achieve tunnel interface control through Wintun:
// Wintun packet filtering example
#include <wintun.h>
VOID FilterPackets(WINTUN_ADAPTER* Adapter) {
WINTUN_SESSION* Session = WintunStartSession(Adapter, 0x100000);
for (;;) {
WINTUN_PACKET* Packets[256];
DWORD PacketsRead = WintunReceivePackets(Session, Packets, 256);
for (DWORD i = 0; i < PacketsRead; ++i) {
WINTUN_PACKET* Packet = Packets[i];
// Inspect packet destination
// Route corporate traffic through VPN
// Route local traffic direct
if (IsDestinationCorporate(Packet->Data)) {
RouteToVPN(Packet);
} else {
SendDirect(Packet);
}
}
}
}
Bandwidth and Latency Monitoring
Quantify the performance difference between approaches:
#!/bin/bash
# Compare tunnel interface vs full tunnel performance
test_configuration() {
local config_name=$1
local test_duration=60
# Bandwidth test (download)
echo "Testing: $config_name"
iperf3 -c test-server.com -t $test_duration -R 2>&1 | grep "sender"
# Latency test
ping -c 10 test-server.com | grep "avg"
# DNS resolution speed
time nslookup test-domain.com
}
# Test tunnel interface (selective routing)
echo "Tunnel Interface Results:"
test_configuration "tunnel"
# Test full tunnel (all traffic)
echo "Full Tunnel Results:"
test_configuration "full-tunnel"
# Test direct connection (baseline)
echo "Direct Connection Baseline:"
test_configuration "direct"
VPN Connection Recovery and Failover
Handling VPN disconnections gracefully:
#!/bin/bash
# Auto-reconnect and failover for tunnel interface
VPN_INTERFACE="tun0"
VPN_PROCESS="openvpn"
FAILOVER_TIMEOUT=30
monitor_vpn() {
while true; do
if ! Ip link show $VPN_INTERFACE > /dev/null 2>&1; then
echo "VPN interface down, attempting reconnect..."
# Kill hanging process
pkill -f $VPN_PROCESS
sleep 2
# Restart VPN
systemctl start openvpn@myconfig
# Wait for interface
for i in $(seq 1 $FAILOVER_TIMEOUT); do
if ip link show $VPN_INTERFACE > /dev/null 2>&1; then
echo "VPN reconnected"
break
fi
sleep 1
done
fi
sleep 10
done
}
# Run as systemd service
monitor_vpn
Practical Testing Framework
Verify your tunnel configuration works correctly:
#!/usr/bin/env python3
# Test tunnel interface configuration
import subprocess
import requests
import socket
def test_tunnel_configuration():
"""Verify tunnel interface routes correctly"""
tests = {
"vpn_connected": check_vpn_connected,
"dns_routed": check_dns_routing,
"local_access": check_local_access,
"vpn_access": check_vpn_access,
}
results = {}
for test_name, test_func in tests.items():
try:
result = test_func()
results[test_name] = "PASS" if result else "FAIL"
except Exception as e:
results[test_name] = f"ERROR: {e}"
return results
def check_vpn_connected():
"""Verify VPN interface is up"""
result = subprocess.run(
["ip", "link", "show", "tun0"],
capture_output=True
)
return result.returncode == 0
def check_dns_routing():
"""Verify DNS queries route correctly"""
try:
ip = socket.gethostbyname("corporate.com")
return True
except socket.gaierror:
return False
def check_local_access():
"""Verify local resources are still accessible"""
try:
requests.get("http://192.168.1.1", timeout=2)
return True
except:
return False
def check_vpn_access():
"""Verify VPN-protected resources are accessible"""
try:
requests.get("http://10.0.0.1", timeout=5)
return True
except:
return False
if __name__ == "__main__":
results = test_tunnel_configuration()
for test, result in results.items():
print(f"{test}: {result}")
These technical tools enable precise control over network routing, essential for complex environments requiring simultaneous VPN and direct access.
Related Articles
- Vpn Tunnel Interface Vs Full Tunnel Routing Difference.
- How to Configure DNS over HTTPS Inside a VPN Tunnel
- IOS Privacy Settings: Complete Walkthrough
- How To Use Wireguard Tunnel For Encrypted Peer To Peer Commu
- Openvpn Tls Auth Vs Tls Crypt Difference Security Comparison
Built by theluckystrike — More at zovo.one