k3s/pkg/daemons/control/proxy/proxy.go
Brad Davidson 11072e2516 Fix occasional "TLS handshake error" in apiserver network proxy.
We should be reading from the hijacked bufio.ReaderWriter instead of
directly from the net.Conn. There is a race condition where the
underlying http handler may consume bytes from the hijacked request
stream, if it comes in the same packet as the CONNECT header. These
bytes are left in the buffered reader, which we were not using. This was
causing us to occasionally drop a few bytes from the start of the
tunneled connection's client data stream.

Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
2022-10-05 21:10:38 -07:00

57 lines
901 B
Go

package proxy
import (
"io"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
type proxy struct {
lconn, rconn io.ReadWriteCloser
done bool
errc chan error
}
func Proxy(lconn, rconn io.ReadWriteCloser) error {
p := &proxy{
lconn: lconn,
rconn: rconn,
errc: make(chan error),
}
defer p.rconn.Close()
defer p.lconn.Close()
go p.pipe(p.lconn, p.rconn)
go p.pipe(p.rconn, p.lconn)
return <-p.errc
}
func (p *proxy) err(err error) {
if p.done {
return
}
if !errors.Is(err, io.EOF) {
logrus.Warnf("Proxy error: %v", err)
}
p.done = true
p.errc <- err
}
func (p *proxy) pipe(src, dst io.ReadWriter) {
buff := make([]byte, 1<<15)
for {
n, err := src.Read(buff)
if err != nil {
p.err(errors.Wrap(err, "read failed"))
return
}
_, err = dst.Write(buff[:n])
if err != nil {
p.err(errors.Wrap(err, "write failed"))
return
}
}
}