fix: nil HTTP recorder ref in WebSocket goroutines, add tunnel loop detection
- handler/http/websocket, forwarder/sniffer_ws, sniffing/sniffer_ws: nil ro2.HTTP in WebSocket copy goroutines to avoid data races on the shared HTTP recorder object - handler/tunnel/bind: remove ingress rule check that incorrectly overrode the endpoint host for non-matching ingress rules - handler/tunnel/entrypoint: add forwarding loop detection by checking Gost-Forwarded-Node header for the entrypoint's own node ID
This commit is contained in:
@@ -51,6 +51,7 @@ func (h *httpHandler) copyWebsocketDirection(ctx context.Context, r io.Reader, w
|
|||||||
}
|
}
|
||||||
ro2 := &xrecorder.HandlerRecorderObject{}
|
ro2 := &xrecorder.HandlerRecorderObject{}
|
||||||
*ro2 = *ro
|
*ro2 = *ro
|
||||||
|
ro2.HTTP = nil
|
||||||
r2 := ro2
|
r2 := ro2
|
||||||
|
|
||||||
limiter := rate.NewLimiter(rate.Limit(sampleRate), int(sampleRate))
|
limiter := rate.NewLimiter(rate.Limit(sampleRate), int(sampleRate))
|
||||||
|
|||||||
@@ -41,10 +41,8 @@ func (h *tunnelHandler) handleBind(ctx context.Context, conn net.Conn, network,
|
|||||||
if host == "" || h.md.ingress == nil {
|
if host == "" || h.md.ingress == nil {
|
||||||
host = endpoint
|
host = endpoint
|
||||||
} else if host != endpoint {
|
} else if host != endpoint {
|
||||||
if rule := h.md.ingress.GetRule(ctx, host, ingress.WithService(h.options.Service)); rule != nil && rule.Endpoint != tunnelID.String() {
|
|
||||||
host = endpoint
|
host = endpoint
|
||||||
}
|
}
|
||||||
}
|
|
||||||
addr := net.JoinHostPort(host, port)
|
addr := net.JoinHostPort(host, port)
|
||||||
|
|
||||||
af := &relay.AddrFeature{}
|
af := &relay.AddrFeature{}
|
||||||
|
|||||||
@@ -278,6 +278,24 @@ func (ep *entrypoint) httpRoundTrip(ctx context.Context, rw io.ReadWriteCloser,
|
|||||||
} else {
|
} else {
|
||||||
req.Header.Set(httpHeaderSID, ro.SID)
|
req.Header.Set(httpHeaderSID, ro.SID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Loop detection: if Gost-Forwarded-Node contains our own node ID,
|
||||||
|
// the request has already passed through this entrypoint and is looping.
|
||||||
|
for _, node := range strings.Split(req.Header.Get(httpHeaderForwardedNode), ",") {
|
||||||
|
if strings.TrimSpace(node) == ep.node {
|
||||||
|
log.Warn("forwarding loop detected, rejecting request")
|
||||||
|
res := &http.Response{
|
||||||
|
ProtoMajor: req.ProtoMajor,
|
||||||
|
ProtoMinor: req.ProtoMinor,
|
||||||
|
Header: http.Header{},
|
||||||
|
StatusCode: http.StatusServiceUnavailable,
|
||||||
|
}
|
||||||
|
ro.HTTP.StatusCode = res.StatusCode
|
||||||
|
res.Write(rw)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
req.Header.Set(httpHeaderForwardedNode, ro.Node)
|
req.Header.Set(httpHeaderForwardedNode, ro.Node)
|
||||||
|
|
||||||
host := req.Host
|
host := req.Host
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ func (h *Sniffer) sniffingWebsocketFrame(ctx context.Context, rw, cc io.ReadWrit
|
|||||||
go func() {
|
go func() {
|
||||||
ro2 := &xrecorder.HandlerRecorderObject{}
|
ro2 := &xrecorder.HandlerRecorderObject{}
|
||||||
*ro2 = *ro
|
*ro2 = *ro
|
||||||
|
ro2.HTTP = nil
|
||||||
ro := ro2
|
ro := ro2
|
||||||
|
|
||||||
limiter := rate.NewLimiter(rate.Limit(sampleRate), int(sampleRate))
|
limiter := rate.NewLimiter(rate.Limit(sampleRate), int(sampleRate))
|
||||||
@@ -57,6 +58,7 @@ func (h *Sniffer) sniffingWebsocketFrame(ctx context.Context, rw, cc io.ReadWrit
|
|||||||
go func() {
|
go func() {
|
||||||
ro2 := &xrecorder.HandlerRecorderObject{}
|
ro2 := &xrecorder.HandlerRecorderObject{}
|
||||||
*ro2 = *ro
|
*ro2 = *ro
|
||||||
|
ro2.HTTP = nil
|
||||||
ro := ro2
|
ro := ro2
|
||||||
|
|
||||||
limiter := rate.NewLimiter(rate.Limit(sampleRate), int(sampleRate))
|
limiter := rate.NewLimiter(rate.Limit(sampleRate), int(sampleRate))
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ func (h *Sniffer) sniffingWebsocketFrame(ctx context.Context, rw, cc io.ReadWrit
|
|||||||
go func() {
|
go func() {
|
||||||
ro2 := &xrecorder.HandlerRecorderObject{}
|
ro2 := &xrecorder.HandlerRecorderObject{}
|
||||||
*ro2 = *ro
|
*ro2 = *ro
|
||||||
|
ro2.HTTP = nil
|
||||||
ro := ro2
|
ro := ro2
|
||||||
|
|
||||||
limiter := rate.NewLimiter(rate.Limit(sampleRate), int(sampleRate))
|
limiter := rate.NewLimiter(rate.Limit(sampleRate), int(sampleRate))
|
||||||
@@ -56,6 +57,7 @@ func (h *Sniffer) sniffingWebsocketFrame(ctx context.Context, rw, cc io.ReadWrit
|
|||||||
go func() {
|
go func() {
|
||||||
ro2 := &xrecorder.HandlerRecorderObject{}
|
ro2 := &xrecorder.HandlerRecorderObject{}
|
||||||
*ro2 = *ro
|
*ro2 = *ro
|
||||||
|
ro2.HTTP = nil
|
||||||
ro := ro2
|
ro := ro2
|
||||||
|
|
||||||
limiter := rate.NewLimiter(rate.Limit(sampleRate), int(sampleRate))
|
limiter := rate.NewLimiter(rate.Limit(sampleRate), int(sampleRate))
|
||||||
|
|||||||
Reference in New Issue
Block a user