WIP: rebase fork onto upstream/main (v1.103.0) #15

Closed
codinget wants to merge 670 commits from webnet into save/webnet-2026-07-29
2 changed files with 54 additions and 7 deletions
Showing only changes of commit 477d5a43df - Show all commits
+22
View File
@@ -81,6 +81,7 @@ func init() {
}, nil
})
ipnlocal.RegisterPeerAPIHandler("/v0/connector/transit-ip", handleConnectorTransitIP)
ipnlocal.HookReplyToDNSQueries.Add(handleHookReplyToDNSQueries)
}
func handleConnectorTransitIP(h ipnlocal.PeerAPIHandler, w http.ResponseWriter, r *http.Request) {
@@ -97,6 +98,18 @@ func handleConnectorTransitIP(h ipnlocal.PeerAPIHandler, w http.ResponseWriter,
e.handleConnectorTransitIP(h, w, r)
}
func handleHookReplyToDNSQueries(h ipnlocal.PeerAPIHandler) bool {
// TODO(tailscale/corp#39033): Remove for alpha release.
if !envknob.UseWIPCode() && !testenv.InTest() {
return false
}
e, ok := ipnlocal.GetExt[*extension](h.LocalBackend())
if !ok {
return false
}
return e.handleHookReplyToDNSQueries(h)
}
// extension is an [ipnext.Extension] managing the connector on platforms
// that import this package.
type extension struct {
@@ -343,6 +356,15 @@ func (e *extension) handleConnectorTransitIP(h ipnlocal.PeerAPIHandler, w http.R
w.Write(bs)
}
func (e *extension) handleHookReplyToDNSQueries(h ipnlocal.PeerAPIHandler) bool {
if !e.conn25.isConfigured() {
return false
}
// TODO(tailscale/corp#40076): verify the peer has access to the query's
// app (if any) domain.
return true
}
// onSelfChange implements the [ipnext.Hooks.OnSelfChange] hook.
func (e *extension) onSelfChange(selfNode tailcfg.NodeView) {
cfg, err := configFromNodeView(selfNode)
+32 -7
View File
@@ -674,6 +674,12 @@ func (h *peerAPIHandler) handleServeDNSFwd(w http.ResponseWriter, r *http.Reques
dh.ServeHTTP(w, r)
}
// HookReplyToDNSQueries allows extensions to register a willingness to allow
// handling PeerAPI DNS queries for the peer making this request.
var HookReplyToDNSQueries = feature.Hooks[func(PeerAPIHandler) bool]{
offersExitNodeOrAppConnectorAndPeerHasAutogroupInternet,
}
func (h *peerAPIHandler) replyToDNSQueries() bool {
if !buildfeatures.HasDNS {
return false
@@ -683,17 +689,36 @@ func (h *peerAPIHandler) replyToDNSQueries() bool {
// without further checks.
return true
}
b := h.ps.b
if !b.OfferingExitNode() && !b.OfferingAppConnector() {
// If we're not an exit node or app connector, there's
// no point to being a DNS server for somebody.
return false
}
if !h.remoteAddr.IsValid() {
// This should never be the case if the peerAPIHandler
// was wired up correctly, but just in case.
return false
}
for _, hook := range HookReplyToDNSQueries {
if hook(h) {
return true
}
}
return false
}
// offersExitNodeOrAppConnectorAndPeerHasAutogroupInternet is run as part of
// [HookReplyToDNSQueries] and handles our legacy PeerAPI DNS acceptance
// criteria:
// - When a node is advertising an exit node it will accept DNS queries
// from peers that have access to autogroup:internet.
// - When a node is advertising an app connector, it will accept DNS queries
// to peers that have access to a relevant app.
//
// Further details about how these are accomplished are in inline comments.
func offersExitNodeOrAppConnectorAndPeerHasAutogroupInternet(h PeerAPIHandler) bool {
b := h.LocalBackend()
if !b.OfferingExitNode() && !b.OfferingAppConnector() {
// If we're not an exit node or app connector, this hook
// doesn't apply.
return false
}
// Otherwise, we're an exit node but the peer is not us, so
// we need to check if they're allowed access to the internet.
// As peerapi bypasses wgengine/filter checks, we need to check
@@ -716,7 +741,7 @@ func (h *peerAPIHandler) replyToDNSQueries() bool {
// arbitrary. DNS runs over TCP and UDP, so sure... we check
// TCP.
dstIP := netaddr.IPv4(0, 0, 0, 0)
remoteIP := h.remoteAddr.Addr()
remoteIP := h.RemoteAddr().Addr()
if remoteIP.Is6() {
// autogroup:internet for IPv6 is defined to start with 2000::/3,
// so use 2000::0 as the probe "the internet" address.