CR: IOT_WAN VPN Passthrough — Implementation

Change 1: Enable Default Drop Logging

Justification

IOT_WAN default-action is drop but default-log was not enabled. All dropped packets were silent — no log entries in show log firewall. This is a visibility gap that prevented detection of the VPN issue and any other outbound IoT traffic being silently blocked.

Pre-Verification

# Verify current state — default-log not set
show configuration commands | grep "IOT_WAN default"
Expected output
set firewall ipv4 name IOT_WAN default-action 'drop'
# NO default-log line present
# Confirm no IOT_WAN entries in firewall log
show log firewall | grep "IOT_WAN" | tail -5
Expected output
(empty — no logged drops)

Change Commands

configure
set firewall ipv4 name IOT_WAN default-log
commit
save

Post-Verification

# Verify default-log is set
show configuration commands | grep "IOT_WAN default"
Expected output
set firewall ipv4 name IOT_WAN default-action 'drop'
set firewall ipv4 name IOT_WAN default-log
# Verify drops now appear in log (generate traffic from IoT device if needed)
show log firewall | grep "IOT_WAN" | tail -5

Status

Applied — 2026-04-07 ~11:30 PST

Change 2: Add IPsec VPN Passthrough Rules

Justification

Palo Alto GlobalProtect VPN requires IPsec protocols for data transport after the initial SSL/TLS handshake on TCP 443:

Protocol Port/ID Purpose

ESP

IP Protocol 50

Encapsulated Security Payload — the encrypted data tunnel carrying all user traffic

UDP 4501

Destination port

IPsec NAT Traversal — used when the VPN client is behind NAT (which IoT devices are, via VyOS masquerade rule 140)

UDP 500

Destination port

Internet Key Exchange (IKE) — negotiates encryption keys for the IPsec tunnel

Without these protocols, the VPN handshake completes (TCP 443 allowed) but the data tunnel fails silently. Users see "VPN Connected" but cannot access any resources.

Pre-Verification

# Verify current IOT_WAN rules (should show rules 10-70 only)
show firewall ipv4 name IOT_WAN
# Confirm no ESP/4501/500 rules exist
show configuration commands | grep "IOT_WAN rule 8\|IOT_WAN rule 9"
Expected output
(empty — rules 80/85/90 do not exist yet)

Proof — Firewall Drop Log Evidence (Captured 2026-04-07 12:00 PST)

After enabling default-log on IOT_WAN (Change 1), the user on Domus-IoT (10.50.40.146) attempted to connect GlobalProtect VPN. The following drops were captured:

show log firewall | grep "IOT_WAN" | tail -20
Captured output
# GlobalProtect VPN gateway — TCP 2443 DROPPED
Apr 07 12:00:53 [ipv4-NAM-IOT_WAN-default-D] SRC=10.50.40.146 DST=162.115.35.40 PROTO=TCP SPT=49363 DPT=2443 SYN
Apr 07 12:00:54 [ipv4-NAM-IOT_WAN-default-D] SRC=10.50.40.146 DST=162.115.35.40 PROTO=TCP SPT=49363 DPT=2443 SYN
Apr 07 12:00:55 [ipv4-NAM-IOT_WAN-default-D] SRC=10.50.40.146 DST=162.115.35.40 PROTO=TCP SPT=49363 DPT=2443 SYN
Apr 07 12:00:56 [ipv4-NAM-IOT_WAN-default-D] SRC=10.50.40.146 DST=162.115.35.40 PROTO=TCP SPT=49363 DPT=2443 SYN
# ... repeated SYN retransmits through 12:01:28 — connection never established

# Google push notifications — TCP 5228 DROPPED (separate issue)
Apr 07 11:46:28 [ipv4-NAM-IOT_WAN-default-D] SRC=10.50.40.146 DST=74.125.137.188 PROTO=TCP SPT=65533 DPT=5228 SYN

Analysis of Proof

Drop Destination Port/Proto Impact

162.115.35.40:2443

Palo Alto GlobalProtect VPN gateway

TCP 2443 — alternate GP portal/gateway port

VPN cannot establish tunnel — handshake blocked at SYN

74.125.137.188:5228

Google push notification service

TCP 5228 — Android/Chrome push

Push notifications broken on IoT devices

Key finding: The VPN failure occurred at two stages:

  1. TCP handshake stage: GlobalProtect uses TCP 2443 for portal/gateway, blocked by IOT_WAN (only 80,443 permitted)

  2. IPsec data stage: After rule 75 (TCP 2443) applied, tunnel established but UDP 4501 (IPsec NAT-T) was blocked, preventing data flow

Post-Fix Verification (2026-04-07 12:10 PST)

After applying rules 75, 80, 85, 90:

show firewall ipv4 name IOT_WAN
Result — all rules in place
rule 75 { action accept; destination { port 2443 }; protocol tcp }
rule 80 { action accept; description "Allow IPsec ESP for VPN"; protocol esp }
rule 85 { action accept; description "Allow IPsec NAT-T for VPN"; destination { port 4501 }; protocol udp }
rule 90 { action accept; description "Allow IKE for VPN"; destination { port 500 }; protocol udp }
show log firewall | grep "IOT_WAN" | grep "4501\|2443" | tail -10
Result — only PRE-FIX drops, no post-fix drops
# All drops timestamped 12:00-12:08 — BEFORE rules applied
Apr 07 12:00:53 ... DST=162.115.35.40 DPT=2443 SYN  ← pre-fix
Apr 07 12:01:28 ... DST=162.115.35.40 DPT=2443 SYN  ← pre-fix
Apr 07 12:02:13 ... DST=162.115.28.58 DPT=4501       ← pre-fix
Apr 07 12:08:28 ... DST=162.115.28.58 DPT=4501       ← pre-fix
# NO drops after 12:10 — rules are working
show log firewall | grep "IOT_WAN" | tail -10
Result — remaining drops are non-VPN traffic only
# TCP 5228 — Google push notifications (not in scope)
# TCP 5150 — Application service (not in scope)
# TCP 5223 — Apple push notifications (not in scope)
# TCP 53   — DNS over TCP (rule 50 only allows UDP 53, separate issue)
# NO VPN-related drops (2443, 4501, 500, ESP)

User confirmed: GlobalProtect VPN connected and data flowing. Work resources accessible.

Proof status: VERIFIED — Rules 75, 80, 85, 90 resolved the VPN connectivity failure.

The original hypothesis (IPsec ESP/UDP 4501 blocked after tunnel) is still valid for after the tunnel establishes, but the immediate blocker is TCP 2443.

Proof-of-Concept Test Procedure (Completed)

Step 1: Enabled default-log on IOT_WAN (Change 1, applied 2026-04-07 ~11:30).

Step 2: Monitored firewall log:

tail -f /var/log/messages | grep "IOT_WAN"

Step 3: User on Domus-IoT (10.50.40.146) connected GlobalProtect VPN.

Step 4: Firewall log showed TCP 2443 SYN packets to 162.115.35.40 being dropped by IOT_WAN default action. Repeated SYN retransmits confirm the connection was never established.

Proof status: CONFIRMEDIOT_WAN is blocking the VPN gateway connection on TCP 2443.

[ipv4-NAM-IOT_WAN-default-D] SRC=10.50.40.xxx DST=<vpn-gateway-ip> PROTO=ESP
[ipv4-NAM-IOT_WAN-default-D] SRC=10.50.40.xxx DST=<vpn-gateway-ip> PROTO=UDP DPT=4501

This is the proof — ESP or UDP 4501 from the IoT client dropped by IOT_WAN default action.

Step 4: If drops confirmed, proceed to apply the change.

Change Commands

configure

# Rule 75: Allow GlobalProtect VPN portal (TCP 2443) — CONFIRMED BLOCKED in proof
set firewall ipv4 name IOT_WAN rule 75 action accept
set firewall ipv4 name IOT_WAN rule 75 description 'Allow GlobalProtect VPN portal (TCP 2443)'
set firewall ipv4 name IOT_WAN rule 75 destination port 2443
set firewall ipv4 name IOT_WAN rule 75 protocol tcp

# Rule 80: Allow IPsec ESP (IP protocol 50) — encrypted data tunnel
set firewall ipv4 name IOT_WAN rule 80 action accept
set firewall ipv4 name IOT_WAN rule 80 description 'Allow IPsec ESP for VPN'
set firewall ipv4 name IOT_WAN rule 80 protocol esp

# Rule 85: Allow IPsec NAT-T (UDP 4501) — NAT traversal for IPsec
set firewall ipv4 name IOT_WAN rule 85 action accept
set firewall ipv4 name IOT_WAN rule 85 description 'Allow IPsec NAT-T for VPN'
set firewall ipv4 name IOT_WAN rule 85 destination port 4501
set firewall ipv4 name IOT_WAN rule 85 protocol udp

# Rule 90: Allow IKE (UDP 500) — IPsec key exchange
set firewall ipv4 name IOT_WAN rule 90 action accept
set firewall ipv4 name IOT_WAN rule 90 description 'Allow IKE for VPN'
set firewall ipv4 name IOT_WAN rule 90 destination port 500
set firewall ipv4 name IOT_WAN rule 90 protocol udp

# Review before committing
compare

Review the output of compare. Verify ONLY rules 80, 85, 90 are added. No other changes.

# If compare output is correct:
commit
save

Post-Verification

# 1. Verify rules are in place
show firewall ipv4 name IOT_WAN
Expected — rules 80, 85, 90 present with zero packet counts
Rule 80: accept ESP
Rule 85: accept UDP DPT=4501
Rule 90: accept UDP DPT=500
# 2. Have user reconnect VPN and test
# On user device:
# - Connect GlobalProtect
# - Access work resources
# - Run: ping -c 10 <work-resource>
# - Run: curl -I https://<work-portal>
# 3. Verify rule hit counters incrementing
show firewall ipv4 name IOT_WAN
Expected — packet counts on rules 80/85/90 incrementing
Rule 80: accept ESP — Packets > 0
Rule 85: accept UDP DPT=4501 — Packets > 0
Rule 90: accept UDP DPT=500 — Packets > 0
# 4. Verify no new default drops for VPN traffic
show log firewall | grep "IOT_WAN" | tail -10
Expected — no ESP/4501/500 drops (only unrelated drops if any)
# 5. Confirm IoT security posture unchanged
# IoT devices should NOT be able to reach internal networks
# Test from IoT device:
# ping 10.50.1.1    ← should still be blocked (IOT_LOCAL only allows DHCP/DNS)
# ping 10.50.10.x   ← should still be blocked (IOT_DATA default drop)

Status

Applied — 2026-04-07 ~12:10 PST. Proof verified: no VPN-related drops after commit. User confirmed VPN functional.