fix(netxlite): gracefully handle utls panics (#462)

* fix(netxlite): gracefully handle utls panics

See https://github.com/ooni/probe/issues/1770

* fix(netxlite): remove wrong timeout from newly written test
This commit is contained in:
Simone Basso 2021-09-05 21:41:49 +02:00 committed by GitHub
parent b834af83ac
commit 3caf5800a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 5 deletions

View File

@ -3,6 +3,7 @@ package netxlite
import ( import (
"context" "context"
"crypto/tls" "crypto/tls"
"errors"
"net" "net"
utls "gitlab.com/yawning/utls.git" utls "gitlab.com/yawning/utls.git"
@ -43,17 +44,29 @@ func newConnUTLS(clientHello *utls.ClientHelloID) func(conn net.Conn, config *tl
} }
} }
func (c *utlsConn) HandshakeContext(ctx context.Context) error { // ErrUTLSHandshakePanic indicates that there was panic handshaking
// when we were using the yawning/utls library for parroting.
//
// See https://github.com/ooni/probe/issues/1770
var ErrUTLSHandshakePanic = errors.New("utls: handshake panic")
func (c *utlsConn) HandshakeContext(ctx context.Context) (err error) {
errch := make(chan error, 1) errch := make(chan error, 1)
go func() { go func() {
defer func() {
// See https://github.com/ooni/probe/issues/1770
if recover() != nil {
errch <- ErrUTLSHandshakePanic
}
}()
errch <- c.handshakefn()() errch <- c.handshakefn()()
}() }()
select { select {
case err := <-errch: case err = <-errch:
return err
case <-ctx.Done(): case <-ctx.Done():
return ctx.Err() err = ctx.Err()
} }
return
} }
func (c *utlsConn) handshakefn() func() error { func (c *utlsConn) handshakefn() func() error {

View File

@ -49,7 +49,7 @@ func TestNewTLSHandshakerUTLSTypes(t *testing.T) {
} }
} }
func TestUTLSConnHandshakeNotInterrupted(t *testing.T) { func TestUTLSConnHandshakeNotInterruptedSuccess(t *testing.T) {
ctx := context.Background() ctx := context.Background()
conn := &utlsConn{ conn := &utlsConn{
testableHandshake: func() error { testableHandshake: func() error {
@ -62,6 +62,20 @@ func TestUTLSConnHandshakeNotInterrupted(t *testing.T) {
} }
} }
func TestUTLSConnHandshakeNotInterruptedFailure(t *testing.T) {
expected := errors.New("mocked error")
ctx := context.Background()
conn := &utlsConn{
testableHandshake: func() error {
return expected
},
}
err := conn.HandshakeContext(ctx)
if !errors.Is(err, expected) {
t.Fatal("not the error we expected", err)
}
}
func TestUTLSConnHandshakeInterrupted(t *testing.T) { func TestUTLSConnHandshakeInterrupted(t *testing.T) {
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
wg.Add(1) wg.Add(1)
@ -82,3 +96,20 @@ func TestUTLSConnHandshakeInterrupted(t *testing.T) {
close(sigch) close(sigch)
wg.Wait() wg.Wait()
} }
func TestUTLSConnHandshakePanic(t *testing.T) {
wg := sync.WaitGroup{}
wg.Add(1)
ctx := context.Background()
conn := &utlsConn{
testableHandshake: func() error {
defer wg.Done()
panic("mascetti")
},
}
err := conn.HandshakeContext(ctx)
if !errors.Is(err, ErrUTLSHandshakePanic) {
t.Fatal("not the error we expected", err)
}
wg.Wait()
}