netcheck,portmapper,magicsock: ignore some UDP write errors on Linux

Treat UDP send EPERM errors as a lost UDP packet, not something super
fatal. That's just the Linux firewall preventing it from going out.

And add a leaf package net/neterror for that (and future) policy that
all three packages can share, with tests.

Updates #3619

Change-Id: Ibdb838c43ee9efe70f4f25f7fc7fdf4607ba9c1d
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2021-12-30 11:11:50 -08:00
committed by Brad Fitzpatrick
parent 2c94e3c4ad
commit 7d9b1de3aa
7 changed files with 115 additions and 4 deletions

View File

@@ -39,6 +39,7 @@ import (
"tailscale.com/net/dnscache"
"tailscale.com/net/interfaces"
"tailscale.com/net/netcheck"
"tailscale.com/net/neterror"
"tailscale.com/net/netns"
"tailscale.com/net/portmapper"
"tailscale.com/net/stun"
@@ -1212,7 +1213,7 @@ func (c *Conn) sendUDPStd(addr *net.UDPAddr, b []byte) (sent bool, err error) {
switch {
case addr.IP.To4() != nil:
_, err = c.pconn4.WriteTo(b, addr)
if err != nil && c.noV4.Get() {
if err != nil && (c.noV4.Get() || neterror.TreatAsLostUDP(err)) {
return false, nil
}
case len(addr.IP) == net.IPv6len:
@@ -1221,7 +1222,7 @@ func (c *Conn) sendUDPStd(addr *net.UDPAddr, b []byte) (sent bool, err error) {
return false, nil
}
_, err = c.pconn6.WriteTo(b, addr)
if err != nil && c.noV6.Get() {
if err != nil && (c.noV6.Get() || neterror.TreatAsLostUDP(err)) {
return false, nil
}
default: