feature/conn25: send TSMP message to client for no IP mapping on connector

When a connector receives a packet from a client on a transit IP that it
can't find a real IP mapping for, it drops the packet. This commit
starts notifying the client of this dropping over TSMP, so the client
can tell the connector to re-establish the transit IP-real IP binding.

Updates tailscale/corp#34256.

Signed-off-by: Naman Sood <mail@nsood.in>
This commit is contained in:
Naman Sood
2026-06-01 14:46:27 -04:00
parent 4f07a071e7
commit da51072b98
4 changed files with 100 additions and 9 deletions
+8 -1
View File
@@ -29,7 +29,7 @@ const minTSMPSize = 7 // the rejected body is 7 bytes
// On the wire, after the IP header, it's currently 7 or 8 bytes:
// - '!'
// - IPProto byte (IANA protocol number: TCP or UDP)
// - 'A' or 'S' (RejectedDueToACLs, RejectedDueToShieldsUp)
// - byte stating rejection reason (see [TailscaleRejectReason] for valid values)
// - srcPort big endian uint16
// - dstPort big endian uint16
// - [optional] byte of flag bits:
@@ -101,6 +101,11 @@ const (
// RejectedDueToHostFirewall means that the target host's
// firewall is blocking the traffic.
RejectedDueToHostFirewall TailscaleRejectReason = 'W'
// RejectedDueToUnknownAppConnectorTransitIP means that the connector host has no real IP
// mapping that matches the provided transit IP for this client, so the
// connector has no destination to forward the connection to.
RejectedDueToUnknownAppConnectorTransitIP TailscaleRejectReason = 'T'
)
func (r TailscaleRejectReason) String() string {
@@ -113,6 +118,8 @@ func (r TailscaleRejectReason) String() string {
return "host-ip-forwarding-unavailable"
case RejectedDueToHostFirewall:
return "host-firewall"
case RejectedDueToUnknownAppConnectorTransitIP:
return "app-connector-transit-ip-unknown"
}
return fmt.Sprintf("0x%02x", byte(r))
}