Pull up `adb shell ip rule` on an Android 13 handset with any commercial VPN client running and the output is unambiguous. Rule 10000 points every non-loopback packet into the tun interface. Rule 10500 handles the UID-scoped exceptions the VPN whitelists for itself. Local subnets — 192.168.0.0/16, 10.0.0.0/8, and crucially the multicast range 224.0.0.0/4 — are not in that whitelist by default. That is the receipt. The camera does not fail because the VPN encrypted something it shouldn't have. It fails because the mDNS discovery packet that the camera app sends to find a networked sensor or an IP cam gets routed into a tunnel exit node in Zurich, and comes back as nothing.
The Receipt: What Actually Happens When the Camera Call Fails
Here is the pattern we see over and over again in bug reports. The user opens a third-party camera app — a baby monitor viewer, a networked DSLR tether, a security-camera client, a video-conferencing tool that enumerates virtual camera sources — and the app returns one of three error states. "No camera found." "Camera failed to connect." A spinning loader that never resolves. The user disconnects the VPN. The app immediately finds the hardware. That cause-and-effect is clean, and it is also almost always misdiagnosed.
The misdiagnosis sits in a predictable place. Users assume the VPN "blocks the camera" in some permission sense. That assumption is wrong. There is no camera permission a VPN client holds or revokes on Android. The VPN cannot see what the camera app is doing with the camera hardware itself. What the VPN can do — what it does, every single session — is own the routing table for the whole user space. And camera apps on modern Android are not just talking to a hardware sensor. They are discovering endpoints. They are negotiating RTSP streams. They are querying mDNS. They are reaching across the LAN or the loopback interface to a companion service.
The failure, in other words, is almost never at the camera-API layer. It is at the transport layer. The packet the app sends never arrives, or the response is routed through a datacenter in another country, or multicast simply dissolves. The error UI the app shows is a lie — not a deliberate one, but the camera library returns `null`, and `null` becomes "Camera failed to connect" because the library author never wrote a code path for "my mDNS probe hit a VPN tunnel". Every mobile VPN support ticket on this topic starts with the user describing a symptom one hop downstream of the actual fault.
The VPN Routing Table Nobody Reads Before Blaming the App
Android's networking stack uses `ip rule` priority tables. When a VPN client calls `VpnService.Builder.establish()`, the framework installs a set of rules that redirects effectively all user-space traffic through a tun0 interface. The default behavior — I want to say this flatly, because the vendor marketing almost never does — is that *everything* goes through the tunnel unless the VPN explicitly carves out an exception.
Carving out an exception is non-trivial. The VPN would need to insert additional `ip rule` entries at a higher priority than 10000, matching on destination CIDR, before the catch-all tunnel rule. For RFC1918 private ranges, that is mechanically straightforward. For multicast — 224.0.0.0/4, where mDNS (RFC 6762) lives at 224.0.0.251 — it is slightly less so, because multicast is a transmit-side problem as much as a receive-side one. The handset needs to not just send the probe to the local segment, it needs to be joined to the multicast group on the correct interface. When tun0 is up and claiming the default route, Android's `MulticastSocket.joinGroup()` call will, in the absence of a `NetworkInterface` argument, bind to the wrong interface.
I'll concede the strongest version of the opposing argument early. Yes — several of the major clients do install an "allow LAN" or "local network access" toggle, and when that toggle is on, RFC1918 destinations do bypass the tunnel. That is real, and it is useful. Shared drives work. Printers work. Chromecast discovery works for most users most of the time. The toggle solves the easy half of the problem.
But the camera pipeline is the hard half. Camera apps on Android 11 and later increasingly chain through a loopback or a service running on the device itself — a HAL shim, a USB-ethernet bridge, a locally-hosted RTSP mux. The traffic never leaves 127.0.0.0/8. And here is the specific gotcha: Android's `ip rule` priority 15000 handles loopback for the UID that owns the socket, but a camera app whose UID differs from the service it's trying to reach via localhost sits in a gray zone that the VPN's rule set was never designed to accommodate.
Loopback, mDNS, and the Multicast Problem Android Introduced in 11
Android 11 (API 30) shipped a change to how multicast and loopback traffic are reconciled with VPN state. Before 11, a VPN that did not touch the LOOPBACK scope would, in practice, leave localhost traffic alone — your packets to 127.0.0.1 were handled by the kernel before the tun redirect even saw them. From 11 onward, the networking stack became stricter about UID attribution. If App A sends to 127.0.0.1:8080 and App B is listening on 127.0.0.1:8080, the kernel will refuse the connection unless both UIDs are considered to be on the same "network" from the VPN's perspective. If App B is a system service and App A is a user-space camera client, their network contexts can diverge the moment the VPN installs its UID-scoped rules.
This is not a conspiracy. The change was deliberate, and from a security-model perspective it is defensible — it was tightened in part to prevent exactly the kind of cross-UID loopback leaks that privacy auditors had been flagging since the Android 7 era. But the collateral damage is that any camera architecture that depends on a mediator service bound to localhost — and a surprisingly large number do, especially those that virtualize a USB camera or a remote IP stream as a local v4l2 node — breaks the instant a VPN is up.
The mDNS failure mode is simpler and uglier. A camera discovery call sends a UDP packet to 224.0.0.251:5353. In the clear, that packet goes out on the wifi interface, every mDNS-aware device on the subnet (including the camera, including the camera's companion hub) sees it, and responds. With the tunnel up and the multicast range not in the carve-out, that packet goes into tun0. Which does not forward multicast. The packet is dropped. No camera on the subnet ever hears the probe. The app, after a 2–5 second timeout, declares no cameras available. The user curses the app. The app did nothing wrong.
Why "Allow LAN" Toggles Fix Printers But Not Camera Pipelines
Here is the asymmetry I want to pull apart, because it is the single most common support-ticket confusion. The "allow LAN" toggle in a mobile VPN client installs — behind the scenes — a routing exception for RFC1918 unicast destinations. Printer at 192.168.1.100. NAS at 192.168.0.42. Chromecast at 192.168.1.230 for Chromecast's unicast fallback path. All three work.
What the toggle typically does NOT do:
Multicast forwarding. Multicast groups require explicit interface binding, and the toggle rarely rewrites the socket options of apps the VPN doesn't own. mDNS probes continue to vanish into tun0.
Loopback UID reconciliation. The toggle is a routing-table change, not a UID-group change. The kernel still enforces the Android 11+ rules on cross-UID localhost. Camera apps whose architecture relies on a local mediator service remain broken.
IPv6 ULA. If your camera uses a link-local IPv6 address (fe80::/10) and the VPN client doesn't carve out the IPv6 link-local scope — which several do not — the discovery path over IPv6 also dies, silently.
Reverse-direction connections. "Allow LAN" is often implemented as an outbound exception. If the camera needs to initiate a connection back to the phone — for an RTSP pull architecture or a WebRTC fallback — the inbound side is still blocked by the VPN's firewall policy.
That is why users report that the printer works, the shared drive works, and yet the camera still times out. The toggle solves outbound unicast to RFC1918. It does not solve multicast, loopback-with-UID-divergence, IPv6 link-local, or reverse-connect flows. The camera pipeline uses at least one and often three of those.
What the Four Major Clients Do Differently — NordVPN, ExpressVPN, Surfshark, ProtonVPN
The behavior is not uniform across vendors, and the user-visible delta matters. We'll stay vendor-neutral on recommendations here; what follows is a description of posture, not a ranking.
NordVPN on Android installs a routing exception for RFC1918 ranges when the "Invisibility on LAN" toggle is OFF (the inverse of what the name suggests — the toggle hides the device from the LAN; disabling it allows LAN discovery). Multicast is not carved out by default. Loopback traffic is left to the kernel's post-Android-11 UID enforcement.
ExpressVPN's Android client uses the Lightway protocol on tun0 and installs its own split-tunnel infrastructure. It exposes a per-app bypass — the user can mark the camera app as excluded from the tunnel entirely. That is a crude but effective fix for the discovery failure, with the obvious threat-model cost we'll discuss in the next section.
Surfshark exposes a "Bypasser" feature that allows URL-level and app-level exclusion. Multicast is handled similarly to NordVPN — not carved out of the tunnel by default. Users have reported that enabling LAN access via the client's "Local network discovery" setting restores some but not all camera-discovery flows.
ProtonVPN's Android client (open source, auditable, scope published by Securitum in their public reports) does install a LAN-access toggle, and the client's handling of IPv6 is the most explicit of the four — it allows the user to disable IPv6 inside the tunnel entirely, which indirectly resolves the IPv6-link-local discovery failure for some camera apps by forcing them to fall back to IPv4 mDNS. ProtonVPN also uses WireGuard as a default option on Android, and the WireGuard whitepaper (Donenfeld, 2017) is explicit that the protocol does not natively handle multicast forwarding — that is a client-side routing concern.
None of these clients fully solves the loopback-UID problem introduced in Android 11. The kernel enforces it, not the VPN.
The Split-Tunnel Workaround and Its Threat-Model Cost
The practical workaround users converge on is split-tunneling: mark the camera app (and often its companion app, if there is one) as excluded from the VPN tunnel entirely. The app's traffic goes over the raw wifi interface, discovery works, the pipeline connects. Problem solved.
Except: the camera app is now not on the VPN. Whatever threat model justified the VPN in the first place — ISP-level traffic observation, hostile wifi network, geographic unblocking — no longer applies to the camera app's traffic. That matters more than most tutorials admit.
Consider the threat model honestly. If the adversary is a passive ISP collecting Netflix-level metadata, excluding the camera app from the tunnel is low-cost. The ISP sees you using a baby monitor viewer. Fine. If the adversary is a hostile network — the airport wifi, the coworking space, the hotel — excluding the camera app from the tunnel is substantially worse. Any passive observer on that network now sees the camera app's unencrypted discovery traffic, including the mDNS announcements that leak device names and manufacturer information. Camera firmware fingerprinting from mDNS strings is a well-documented reconnaissance technique.
If the adversary is anyone with ARP-spoofing or router-level control over the local network, split-tunneling the camera app is not a workaround — it is a surrender. The reason you brought the VPN was to not trust that network. You just told the camera app to trust it.
There is a cleaner compromise: run the camera app over the VPN while connected to a network you fully control (home wifi), and only enable split-tunneling as a session-level override when you specifically need the discovery to resolve on a trusted LAN. Any time you are on a network you don't own, the exclusion should be off. That requires the user to actively manage the toggle. In practice, almost nobody does.
If You Only Remember One Thing
The Android camera failure is a routing failure, not a camera failure. The VPN did not encrypt your sensor. It redirected the mDNS probe into a datacenter, broke the loopback UID reconciliation your camera pipeline depends on, and did not carve out multicast.
The right question is not "how do I make my camera work with a VPN." The right question is "what is my threat model, which of my apps need to see the LAN to function, and is split-tunneling those specific apps an acceptable cost given who my adversary is." That answer is yours to work out. The routing table does not care how you answer. It just does what it was configured to do.
FAQ
Does disabling the VPN permanently fix camera apps that fail over the tunnel?
Disabling the VPN restores camera discovery immediately, yes — because the tun interface is torn down and the default route reverts to wifi. But "permanently fix" is the wrong framing. The VPN was presumably running for a reason. If that reason was anything stronger than casual geo-unblocking, turning it off every time the camera app opens leaves the rest of your traffic exposed. Prefer per-app exclusion, applied only on networks you trust.
Why does the "allow LAN" setting fix my printer but not my camera?
Allow-LAN toggles install routing exceptions for RFC1918 private unicast ranges — 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12. Printers are typically reachable on a unicast IP in those ranges, so the exception works. Camera apps often depend on multicast mDNS discovery (224.0.0.0/4), IPv6 link-local, or cross-UID loopback — none of which are covered by a standard allow-LAN toggle. Same symptom name, different routing problem.
Does switching from OpenVPN to WireGuard inside the client help?
Not for discovery failures. The underlying problem is at the Android routing-rule layer, not the tunnel protocol layer. WireGuard, OpenVPN, IKEv2 and Lightway all install the same type of `ip rule` redirect to tun0. The WireGuard whitepaper is explicit that multicast handling is a client-side concern. Switching protocols can shift reconnection behavior and performance, but the camera discovery path dies the same way under all four.
Will using a dedicated IP from the VPN provider resolve this?
No. A dedicated IP changes the exit-node identity of your tunneled traffic — it does not change how the Android handset routes multicast or loopback locally. The camera app's discovery packet still gets redirected into tun0 and dropped before it ever reaches the exit node, dedicated or otherwise. Dedicated IPs solve CAPTCHA fatigue and reputation issues; they do not solve LAN discovery.
Is this behavior different on Android 14 and 15 compared to Android 11?
The underlying UID-scoped loopback enforcement introduced in Android 11 persists through Android 15, with incremental tightening in each release. Android 13 added further restrictions on background multicast socket operations. Android 14 formalized network stack permission grants. The direction of travel is clear — more isolation between UIDs over VPN, not less. Camera pipelines that work on Android 10 often degrade on 13 and later with the same VPN client installed.
Does using a VPN that advertises "no logs" matter for this specific issue?
No-logs policy is a privacy posture claim about what the provider retains server-side. It has no bearing on how the Android client manages the local routing table. A no-logs provider with a poorly designed Android client will still break your camera. A log-keeping provider with careful multicast and LAN handling may not. Audit the client's technical behavior separately from the policy claims — these are two independent questions.
If I exclude the camera app from the VPN, does the rest of my traffic stay protected?
Yes, under the specific split-tunnel semantics the client implements. Other apps continue to route through tun0 and remain within the tunnel's protection envelope. The excluded app, however, operates on the raw interface and is visible to any party with network-adjacent position — your ISP, the local wifi operator, anyone with ARP-level access to the segment. The protection of the other apps is not weakened; the excluded app is simply not protected at all.