Seeing public addresses on eth0 while the tunnel is up feels like proof that something escaped. Usually it is the opposite: the tunnel's own packets have to cross that adapter to reach the server, and they look like ordinary UDP or TCP flows. The inner packet only appears on the tunnel device. Distinguishing the two is a matter of reading the envelope, not of trusting a byte count.

Every tunnel packet still crosses the wire

A tunnel is an interface, not a wire. The client takes an inner packet, wraps it, and sends the result to the server's address and port from the profile. On the physical adapter you see the wrapper; on the tunnel device you see what was wrapped.

In UDP mode the outer flow is one address and port pair in each direction, which is why a healthy tunnel looks almost boring on eth0. That single pair is the thing to look for first.

Capture one interface at a time

Capture one interface at a time when you intend to compare counts. The any pseudo-interface collects every device at once, so a forwarded packet appears on entry and exit and a locally generated one appears twice in two different forms. Equal packet counts with unequal byte counts are normal, because the wrapper is larger than what it carries. ARP, DHCP and IPv6 router advertisements belong on the local link and say nothing about your application.

sudo tcpdump -i eth0 -n host 203.0.113.10 and udp port 1194

Replace the address and port with the profile's own values. If that flow is steady, the tunnel is carrying something.

Ask the kernel which device it picks

Ask the kernel which device it would choose, then confirm on the wire. The route lookup is the decision, and the capture is the evidence that the decision was followed. They answer different questions and you want both.

ip route get 1.1.1.1
ip -6 route get 2606:4700:4700::1111

A split result is the common finding: IPv4 goes to the tunnel and IPv6 goes to the physical adapter because the profile pushed only IPv4 routes. That is a real leak, and it is invisible in an IPv4-only capture. Filter for IPv6 and watch for addresses that are not the server and not link-local.

Run both lookups before and after connecting, so you can see what the client actually changed. The difference between the two runs is the client's real effect.

When the capture really is a leak

Sometimes the capture is telling the truth. A narrower route that sends one prefix around the tunnel, a subnet the client was told to exclude, or a firewall accept that runs before the tunnel policy can all put traffic on the wire in the clear. A rule that matches a process group can be a deliberate exception too. Read its interface and destination scope before you call it a fault.

Fix the route or the exclusion, not the firewall. Then capture again from a fresh connection and check IPv4 and IPv6 separately, since fixing one says nothing about the other. The tcpdump manual covers the interface and direction selectors used above.

Amanqephe ahlobene