tailcfg: add DNS address list for IsWireGuardOnly nodes

Tailscale exit nodes provide DNS service over the peer API, however
IsWireGuardOnly nodes do not have a peer API, and instead need client
DNS parameters passed in their node description.

For Mullvad nodes this will contain the in network 10.64.0.1 address.

Updates #9377

Signed-off-by: James Tucker <james@tailscale.com>
This commit is contained in:
James Tucker
2023-09-14 10:04:31 -07:00
committed by James Tucker
parent 335a5aaf9a
commit e7727db553
9 changed files with 160 additions and 2 deletions

View File

@@ -336,6 +336,10 @@ type Node struct {
// is not expected to speak Disco or DERP, and it must have Endpoints in
// order to be reachable.
IsWireGuardOnly bool `json:",omitempty"`
// ExitNodeDNSResolvers is the list of DNS servers that should be used when this
// node is marked IsWireGuardOnly and being used as an exit node.
ExitNodeDNSResolvers []*dnstype.Resolver `json:",omitempty"`
}
// DisplayName returns the user-facing name for a node which should

View File

@@ -65,6 +65,12 @@ func (src *Node) Clone() *Node {
if dst.SelfNodeV4MasqAddrForThisPeer != nil {
dst.SelfNodeV4MasqAddrForThisPeer = ptr.To(*src.SelfNodeV4MasqAddrForThisPeer)
}
if src.ExitNodeDNSResolvers != nil {
dst.ExitNodeDNSResolvers = make([]*dnstype.Resolver, len(src.ExitNodeDNSResolvers))
for i := range dst.ExitNodeDNSResolvers {
dst.ExitNodeDNSResolvers[i] = src.ExitNodeDNSResolvers[i].Clone()
}
}
return dst
}
@@ -101,6 +107,7 @@ var _NodeCloneNeedsRegeneration = Node(struct {
Expired bool
SelfNodeV4MasqAddrForThisPeer *netip.Addr
IsWireGuardOnly bool
ExitNodeDNSResolvers []*dnstype.Resolver
}{})
// Clone makes a deep copy of Hostinfo.

View File

@@ -350,7 +350,7 @@ func TestNodeEqual(t *testing.T) {
"UnsignedPeerAPIOnly",
"ComputedName", "computedHostIfDifferent", "ComputedNameWithHost",
"DataPlaneAuditLogID", "Expired", "SelfNodeV4MasqAddrForThisPeer",
"IsWireGuardOnly",
"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",

View File

@@ -180,7 +180,10 @@ func (v NodeView) SelfNodeV4MasqAddrForThisPeer() *netip.Addr {
return &x
}
func (v NodeView) IsWireGuardOnly() bool { return v.ж.IsWireGuardOnly }
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)
}
func (v NodeView) Equal(v2 NodeView) bool { return v.ж.Equal(v2.ж) }
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
@@ -216,6 +219,7 @@ var _NodeViewNeedsRegeneration = Node(struct {
Expired bool
SelfNodeV4MasqAddrForThisPeer *netip.Addr
IsWireGuardOnly bool
ExitNodeDNSResolvers []*dnstype.Resolver
}{})
// View returns a readonly view of Hostinfo.