mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-11 21:27:31 +00:00
all: declare & plumb IPv6 masquerade address for peer
This PR plumbs through awareness of an IPv6 SNAT/masquerade address from the wire protocol through to the low-level (tstun / wgengine). This PR is the first in two PRs for implementing IPv6 NAT support to/from peers. A subsequent PR will implement the data-plane changes to implement IPv6 NAT - this is just plumbing. Signed-off-by: Tom DNetto <tom@tailscale.com> Updates ENG-991
This commit is contained in:
@@ -374,6 +374,21 @@ type Node struct {
|
||||
// not be masqueraded (e.g. in case of --snat-subnet-routes).
|
||||
SelfNodeV4MasqAddrForThisPeer *netip.Addr `json:",omitempty"`
|
||||
|
||||
// SelfNodeV6MasqAddrForThisPeer is the IPv6 that this peer knows the current node as.
|
||||
// It may be empty if the peer knows the current node by its native
|
||||
// IPv6 address.
|
||||
// This field is only populated in a MapResponse for peers and not
|
||||
// for the current node.
|
||||
//
|
||||
// If set, it should be used to masquerade traffic originating from the
|
||||
// current node to this peer. The masquerade address is only relevant
|
||||
// for this peer and not for other peers.
|
||||
//
|
||||
// This only applies to traffic originating from the current node to the
|
||||
// peer or any of its subnets. Traffic originating from subnet routes will
|
||||
// not be masqueraded (e.g. in case of --snat-subnet-routes).
|
||||
SelfNodeV6MasqAddrForThisPeer *netip.Addr `json:",omitempty"`
|
||||
|
||||
// IsWireGuardOnly indicates that this is a non-Tailscale WireGuard peer, it
|
||||
// is not expected to speak Disco or DERP, and it must have Endpoints in
|
||||
// order to be reachable.
|
||||
@@ -1940,6 +1955,7 @@ func (n *Node) Equal(n2 *Node) bool {
|
||||
eqStrings(n.Tags, n2.Tags) &&
|
||||
n.Expired == n2.Expired &&
|
||||
eqPtr(n.SelfNodeV4MasqAddrForThisPeer, n2.SelfNodeV4MasqAddrForThisPeer) &&
|
||||
eqPtr(n.SelfNodeV6MasqAddrForThisPeer, n2.SelfNodeV6MasqAddrForThisPeer) &&
|
||||
n.IsWireGuardOnly == n2.IsWireGuardOnly
|
||||
}
|
||||
|
||||
|
@@ -71,6 +71,9 @@ func (src *Node) Clone() *Node {
|
||||
if dst.SelfNodeV4MasqAddrForThisPeer != nil {
|
||||
dst.SelfNodeV4MasqAddrForThisPeer = ptr.To(*src.SelfNodeV4MasqAddrForThisPeer)
|
||||
}
|
||||
if dst.SelfNodeV6MasqAddrForThisPeer != nil {
|
||||
dst.SelfNodeV6MasqAddrForThisPeer = ptr.To(*src.SelfNodeV6MasqAddrForThisPeer)
|
||||
}
|
||||
if src.ExitNodeDNSResolvers != nil {
|
||||
dst.ExitNodeDNSResolvers = make([]*dnstype.Resolver, len(src.ExitNodeDNSResolvers))
|
||||
for i := range dst.ExitNodeDNSResolvers {
|
||||
@@ -113,6 +116,7 @@ var _NodeCloneNeedsRegeneration = Node(struct {
|
||||
DataPlaneAuditLogID string
|
||||
Expired bool
|
||||
SelfNodeV4MasqAddrForThisPeer *netip.Addr
|
||||
SelfNodeV6MasqAddrForThisPeer *netip.Addr
|
||||
IsWireGuardOnly bool
|
||||
ExitNodeDNSResolvers []*dnstype.Resolver
|
||||
}{})
|
||||
|
@@ -350,7 +350,7 @@ func TestNodeEqual(t *testing.T) {
|
||||
"UnsignedPeerAPIOnly",
|
||||
"ComputedName", "computedHostIfDifferent", "ComputedNameWithHost",
|
||||
"DataPlaneAuditLogID", "Expired", "SelfNodeV4MasqAddrForThisPeer",
|
||||
"IsWireGuardOnly", "ExitNodeDNSResolvers",
|
||||
"SelfNodeV6MasqAddrForThisPeer", "IsWireGuardOnly", "ExitNodeDNSResolvers",
|
||||
}
|
||||
if have := fieldsOf(reflect.TypeOf(Node{})); !reflect.DeepEqual(have, nodeHandles) {
|
||||
t.Errorf("Node.Equal check might be out of sync\nfields: %q\nhandled: %q\n",
|
||||
@@ -545,6 +545,16 @@ func TestNodeEqual(t *testing.T) {
|
||||
&Node{SelfNodeV4MasqAddrForThisPeer: ptr.To(netip.MustParseAddr("100.64.0.1"))},
|
||||
true,
|
||||
},
|
||||
{
|
||||
&Node{},
|
||||
&Node{SelfNodeV6MasqAddrForThisPeer: ptr.To(netip.MustParseAddr("2001::3456"))},
|
||||
false,
|
||||
},
|
||||
{
|
||||
&Node{SelfNodeV6MasqAddrForThisPeer: ptr.To(netip.MustParseAddr("2001::3456"))},
|
||||
&Node{SelfNodeV6MasqAddrForThisPeer: ptr.To(netip.MustParseAddr("2001::3456"))},
|
||||
true,
|
||||
},
|
||||
{
|
||||
&Node{
|
||||
CapMap: NodeCapMap{
|
||||
|
@@ -186,6 +186,14 @@ func (v NodeView) SelfNodeV4MasqAddrForThisPeer() *netip.Addr {
|
||||
return &x
|
||||
}
|
||||
|
||||
func (v NodeView) SelfNodeV6MasqAddrForThisPeer() *netip.Addr {
|
||||
if v.ж.SelfNodeV6MasqAddrForThisPeer == nil {
|
||||
return nil
|
||||
}
|
||||
x := *v.ж.SelfNodeV6MasqAddrForThisPeer
|
||||
return &x
|
||||
}
|
||||
|
||||
func (v NodeView) IsWireGuardOnly() bool { return v.ж.IsWireGuardOnly }
|
||||
func (v NodeView) ExitNodeDNSResolvers() views.SliceView[*dnstype.Resolver, dnstype.ResolverView] {
|
||||
return views.SliceOfViews[*dnstype.Resolver, dnstype.ResolverView](v.ж.ExitNodeDNSResolvers)
|
||||
@@ -225,6 +233,7 @@ var _NodeViewNeedsRegeneration = Node(struct {
|
||||
DataPlaneAuditLogID string
|
||||
Expired bool
|
||||
SelfNodeV4MasqAddrForThisPeer *netip.Addr
|
||||
SelfNodeV6MasqAddrForThisPeer *netip.Addr
|
||||
IsWireGuardOnly bool
|
||||
ExitNodeDNSResolvers []*dnstype.Resolver
|
||||
}{})
|
||||
|
Reference in New Issue
Block a user