mirror of
https://github.com/tailscale/tailscale.git
synced 2025-10-24 01:31:55 +00:00
ipn/ipnlocal, tailcfg: wire up ingress peerapi
Updates tailscale/corp#7515 Co-authored-by: Shayne Sweeney <shayne@tailscale.com> Change-Id: I7eac7b4ac37fd8e8a9e0469594c1e9e7dd0da666 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
65f3dab4c6
commit
9dfb0916c2
@@ -34,6 +34,7 @@ import (
|
||||
"github.com/kortschak/wol"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
"tailscale.com/client/tailscale/apitype"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/hostinfo"
|
||||
"tailscale.com/ipn"
|
||||
@@ -572,6 +573,9 @@ func (h *peerAPIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
case "/v0/interfaces":
|
||||
h.handleServeInterfaces(w, r)
|
||||
return
|
||||
case "/v0/ingress":
|
||||
h.handleServeIngress(w, r)
|
||||
return
|
||||
}
|
||||
who := h.peerUser.DisplayName
|
||||
fmt.Fprintf(w, `<html>
|
||||
@@ -586,6 +590,63 @@ This is my Tailscale device. Your device is %v.
|
||||
}
|
||||
}
|
||||
|
||||
func (h *peerAPIHandler) handleServeIngress(w http.ResponseWriter, r *http.Request) {
|
||||
// http.Errors only useful if hitting endpoint manually
|
||||
// otherwise rely on log lines when debugging ingress connections
|
||||
// as connection is hijacked for bidi and is encrypted tls
|
||||
if !h.canIngress() {
|
||||
h.logf("ingress: denied; no ingress cap from %v", h.remoteAddr)
|
||||
http.Error(w, "denied; no ingress cap", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
logAndError := func(code int, publicMsg string) {
|
||||
h.logf("ingress: bad request from %v: %s", h.remoteAddr, publicMsg)
|
||||
http.Error(w, publicMsg, http.StatusMethodNotAllowed)
|
||||
}
|
||||
bad := func(publicMsg string) {
|
||||
logAndError(http.StatusBadRequest, publicMsg)
|
||||
}
|
||||
if r.Method != "POST" {
|
||||
logAndError(http.StatusMethodNotAllowed, "only POST allowed")
|
||||
return
|
||||
}
|
||||
srcAddrStr := r.Header.Get("Tailscale-Ingress-Src")
|
||||
if srcAddrStr == "" {
|
||||
bad("Tailscale-Ingress-Src header not set")
|
||||
return
|
||||
}
|
||||
srcAddr, err := netip.ParseAddrPort(srcAddrStr)
|
||||
if err != nil {
|
||||
bad("Tailscale-Ingress-Src header invalid; want ip:port")
|
||||
return
|
||||
}
|
||||
target := r.Header.Get("Tailscale-Ingress-Target")
|
||||
if target == "" {
|
||||
bad("Tailscale-Target-Target header not set")
|
||||
return
|
||||
}
|
||||
if _, _, err := net.SplitHostPort(target); err != nil {
|
||||
bad("Tailscale-Target-Target header invalid; want host:port")
|
||||
return
|
||||
}
|
||||
|
||||
getConn := func() (net.Conn, bool) {
|
||||
conn, _, err := w.(http.Hijacker).Hijack()
|
||||
if err != nil {
|
||||
h.logf("ingress: failed hijacking conn")
|
||||
http.Error(w, "failed hijacking conn", http.StatusInternalServerError)
|
||||
return nil, false
|
||||
}
|
||||
io.WriteString(conn, "HTTP/1.1 101 Switching Protocols\r\n\r\n")
|
||||
return conn, true
|
||||
}
|
||||
sendRST := func() {
|
||||
http.Error(w, "denied", http.StatusForbidden)
|
||||
}
|
||||
|
||||
h.ps.b.HandleIngressTCPConn(h.peerNode, ipn.HostPort(target), srcAddr, getConn, sendRST)
|
||||
}
|
||||
|
||||
func (h *peerAPIHandler) handleServeInterfaces(w http.ResponseWriter, r *http.Request) {
|
||||
if !h.canDebug() {
|
||||
http.Error(w, "denied; no debug access", http.StatusForbidden)
|
||||
@@ -694,6 +755,13 @@ func (h *peerAPIHandler) canWakeOnLAN() bool {
|
||||
return h.isSelf || h.peerHasCap(tailcfg.CapabilityWakeOnLAN)
|
||||
}
|
||||
|
||||
var allowSelfIngress = envknob.RegisterBool("TS_ALLOW_SELF_INGRESS")
|
||||
|
||||
// canIngress reports whether h can send ingress requests to this node.
|
||||
func (h *peerAPIHandler) canIngress() bool {
|
||||
return h.peerHasCap(tailcfg.CapabilityIngress) || (allowSelfIngress() && h.isSelf)
|
||||
}
|
||||
|
||||
func (h *peerAPIHandler) peerHasCap(wantCap string) bool {
|
||||
for _, hasCap := range h.ps.b.PeerCaps(h.remoteAddr.Addr()) {
|
||||
if hasCap == wantCap {
|
||||
|
||||
Reference in New Issue
Block a user