diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 0cefb70d7..f35e10977 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -1753,15 +1753,25 @@ func (b *LocalBackend) getPeerAPIPortForTSMPPing(ip netaddr.IP) (port uint16, ok func (b *LocalBackend) peerAPIServicesLocked() (ret []tailcfg.Service) { for _, pln := range b.peerAPIListeners { - proto := tailcfg.ServiceProto("peerapi4") + proto := tailcfg.PeerAPI4 if pln.ip.Is6() { - proto = "peerapi6" + proto = tailcfg.PeerAPI6 } ret = append(ret, tailcfg.Service{ Proto: proto, Port: uint16(pln.port), }) } + switch runtime.GOOS { + case "linux", "freebsd", "openbsd", "illumos", "darwin": + // These are the platforms currently supported by + // net/dns/resolver/tsdns.go:Resolver.HandleExitNodeDNSQuery. + // TODO(bradfitz): add windows once it's done there. + ret = append(ret, tailcfg.Service{ + Proto: tailcfg.PeerAPIDNS, + Port: 1, // version + }) + } return ret } @@ -2880,9 +2890,9 @@ func peerAPIBase(nm *netmap.NetworkMap, peer *tailcfg.Node) string { var p4, p6 uint16 for _, s := range peer.Hostinfo.Services { switch s.Proto { - case "peerapi4": + case tailcfg.PeerAPI4: p4 = s.Port - case "peerapi6": + case tailcfg.PeerAPI6: p6 = s.Port } } diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go index 3dc0dbc1c..2404b6bb8 100644 --- a/tailcfg/tailcfg.go +++ b/tailcfg/tailcfg.go @@ -379,18 +379,49 @@ func (h *Hostinfo) CheckRequestTags() error { return nil } +// ServiceProto is a service type. It's usually +// TCP ("tcp") or UDP ("udp"), but it can also have +// meta service values as defined in Service.Proto. type ServiceProto string const ( - TCP = ServiceProto("tcp") - UDP = ServiceProto("udp") + TCP = ServiceProto("tcp") + UDP = ServiceProto("udp") + PeerAPI4 = ServiceProto("peerapi4") + PeerAPI6 = ServiceProto("peerapi6") + PeerAPIDNS = ServiceProto("peerapi-dns-proxy") ) +// Service represents a service running on a node. type Service struct { - _ structs.Incomparable - Proto ServiceProto // TCP or UDP - Port uint16 // port number service is listening on - Description string `json:",omitempty"` // text description of service + _ structs.Incomparable + + // Proto is the type of service. It's usually the constant TCP + // or UDP ("tcp" or "udp"), but it can also be one of the + // following meta service values: + // + // * "peerapi4": peerapi is available on IPv4; Port is the + // port number that the peerapi is running on the + // node's Tailscale IPv4 address. + // * "peerapi6": peerapi is available on IPv6; Port is the + // port number that the peerapi is running on the + // node's Tailscale IPv6 address. + // * "peerapi-dns": the local peerapi service supports + // being a DNS proxy (when the node is an exit + // node). For this service, the Port number is really + // the version number of the service. + Proto ServiceProto + + // Port is the port number. + // + // For Proto "peerapi-dns", it's the version number of the DNS proxy, + // currently 1. + Port uint16 + + // Description is the textual description of the service, + // usually the process name that's running. + Description string `json:",omitempty"` + // TODO(apenwarr): allow advertising services on subnet IPs? // TODO(apenwarr): add "tags" here for each service? }