1
0
mirror of https://github.com/golang/go synced 2024-11-17 18:04:48 -07:00

crypto/tls: failed tls.Conn.Write returns a permanent error

Fixes #29971

Change-Id: I2f1653640c88fafe0ec17a75dcf41d5896c4cb8e
Reviewed-on: https://go-review.googlesource.com/c/go/+/227840
Run-TryBot: Katie Hockman <katie@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Katie Hockman 2020-04-10 10:06:29 -04:00
parent bd0623b4e7
commit 614a713be5
3 changed files with 88 additions and 3 deletions

View File

@ -162,9 +162,22 @@ type halfConn struct {
trafficSecret []byte // current TLS 1.3 traffic secret
}
type permamentError struct {
err net.Error
}
func (e *permamentError) Error() string { return e.err.Error() }
func (e *permamentError) Unwrap() error { return e.err }
func (e *permamentError) Timeout() bool { return e.err.Timeout() }
func (e *permamentError) Temporary() bool { return false }
func (hc *halfConn) setErrorLocked(err error) error {
if e, ok := err.(net.Error); ok {
hc.err = &permamentError{err: e}
} else {
hc.err = err
return err
}
return hc.err
}
// prepareCipherSpec sets the encryption and MAC states

View File

@ -355,7 +355,8 @@ func TestAlertForwarding(t *testing.T) {
err := Server(s, testConfig).Handshake()
s.Close()
if e, ok := err.(*net.OpError); !ok || e.Err != error(alertUnknownCA) {
var opErr *net.OpError
if !errors.As(err, &opErr) || opErr.Err != error(alertUnknownCA) {
t.Errorf("Got error: %s; expected: %s", err, error(alertUnknownCA))
}
}

View File

@ -201,6 +201,77 @@ func TestDialTimeout(t *testing.T) {
}
}
func TestDeadlineOnWrite(t *testing.T) {
if testing.Short() {
t.Skip("skipping in short mode")
}
ln := newLocalListener(t)
defer ln.Close()
srvCh := make(chan *Conn, 1)
go func() {
sconn, err := ln.Accept()
if err != nil {
srvCh <- nil
return
}
srv := Server(sconn, testConfig.Clone())
if err := srv.Handshake(); err != nil {
srvCh <- nil
return
}
srvCh <- srv
}()
clientConfig := testConfig.Clone()
clientConfig.MaxVersion = VersionTLS12
conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
if err != nil {
t.Fatal(err)
}
defer conn.Close()
srv := <-srvCh
if srv == nil {
t.Error(err)
}
// Make sure the client/server is setup correctly and is able to do a typical Write/Read
buf := make([]byte, 6)
if _, err := srv.Write([]byte("foobar")); err != nil {
t.Errorf("Write err: %v", err)
}
if n, err := conn.Read(buf); n != 6 || err != nil || string(buf) != "foobar" {
t.Errorf("Read = %d, %v, data %q; want 6, nil, foobar", n, err, buf)
}
// Set a deadline which should cause Write to timeout
if err = srv.SetDeadline(time.Now()); err != nil {
t.Fatalf("SetDeadline(time.Now()) err: %v", err)
}
if _, err = srv.Write([]byte("should fail")); err == nil {
t.Fatal("Write should have timed out")
}
// Clear deadline and make sure it still times out
if err = srv.SetDeadline(time.Time{}); err != nil {
t.Fatalf("SetDeadline(time.Time{}) err: %v", err)
}
if _, err = srv.Write([]byte("This connection is permanently broken")); err == nil {
t.Fatal("Write which previously failed should still time out")
}
// Verify the error
if ne := err.(net.Error); ne.Temporary() != false {
t.Error("Write timed out but incorrectly classified the error as Temporary")
}
if !isTimeoutError(err) {
t.Error("Write timed out but did not classify the error as a Timeout")
}
}
func isTimeoutError(err error) bool {
if ne, ok := err.(net.Error); ok {
return ne.Timeout()