lib/connections: Do not leak FDs, fix address copy (fixes #5767) (#5768)

* lib/connections: Do not leak FDs, fix address copy (fixes #5767)

* build

* Update quic_listen.go

* Update quic_listen.go
This commit is contained in:
Audrius Butkevicius 2019-06-09 22:14:00 +01:00 committed by GitHub
parent 41ff4b323e
commit ee746263fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 23 additions and 10 deletions

View File

@ -45,23 +45,26 @@ func (d *quicDialer) Dial(id protocol.DeviceID, uri *url.URL) (internalConn, err
} }
var conn net.PacketConn var conn net.PacketConn
closeConn := false // We need to track who created the conn.
// Given we always pass the connection to quic, it assumes it's a remote connection it never closes it,
// So our wrapper around it needs to close it, but it only needs to close it if it's not the listening connection.
var createdConn net.PacketConn
if listenConn := registry.Get(uri.Scheme, packetConnLess); listenConn != nil { if listenConn := registry.Get(uri.Scheme, packetConnLess); listenConn != nil {
conn = listenConn.(net.PacketConn) conn = listenConn.(net.PacketConn)
} else { } else {
if packetConn, err := net.ListenPacket("udp", ":0"); err != nil { if packetConn, err := net.ListenPacket("udp", ":0"); err != nil {
return internalConn{}, err return internalConn{}, err
} else { } else {
closeConn = true
conn = packetConn conn = packetConn
createdConn = packetConn
} }
} }
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
session, err := quic.DialContext(ctx, conn, addr, uri.Host, d.tlsCfg, quicConfig) session, err := quic.DialContext(ctx, conn, addr, uri.Host, d.tlsCfg, quicConfig)
if err != nil { if err != nil {
if closeConn { if createdConn != nil {
_ = conn.Close() _ = createdConn.Close()
} }
return internalConn{}, err return internalConn{}, err
} }
@ -85,13 +88,13 @@ func (d *quicDialer) Dial(id protocol.DeviceID, uri *url.URL) (internalConn, err
if err != nil { if err != nil {
// It's ok to close these, this does not close the underlying packetConn. // It's ok to close these, this does not close the underlying packetConn.
_ = session.Close() _ = session.Close()
if closeConn { if createdConn != nil {
_ = conn.Close() _ = createdConn.Close()
} }
return internalConn{}, err return internalConn{}, err
} }
return internalConn{&quicTlsConn{session, stream}, connTypeQUICClient, quicPriority}, nil return internalConn{&quicTlsConn{session, stream, createdConn}, connTypeQUICClient, quicPriority}, nil
} }
func (d *quicDialer) RedialFrequency() time.Duration { func (d *quicDialer) RedialFrequency() time.Duration {

View File

@ -59,7 +59,8 @@ func (t *quicListener) OnNATTypeChanged(natType stun.NATType) {
func (t *quicListener) OnExternalAddressChanged(address *stun.Host, via string) { func (t *quicListener) OnExternalAddressChanged(address *stun.Host, via string) {
var uri *url.URL var uri *url.URL
if address != nil { if address != nil {
uri = &(*t.uri) copy := *t.uri
uri = &copy
uri.Host = address.TransportAddr() uri.Host = address.TransportAddr()
} }
@ -165,7 +166,7 @@ func (t *quicListener) Serve() {
continue continue
} }
t.conns <- internalConn{&quicTlsConn{session, stream}, connTypeQUICServer, quicPriority} t.conns <- internalConn{&quicTlsConn{session, stream, nil}, connTypeQUICServer, quicPriority}
} }
} }

View File

@ -24,15 +24,24 @@ var (
type quicTlsConn struct { type quicTlsConn struct {
quic.Session quic.Session
quic.Stream quic.Stream
// If we created this connection, we should be the ones closing it.
createdConn net.PacketConn
} }
func (q *quicTlsConn) Close() error { func (q *quicTlsConn) Close() error {
sterr := q.Stream.Close() sterr := q.Stream.Close()
seerr := q.Session.Close() seerr := q.Session.Close()
var pcerr error
if q.createdConn != nil {
pcerr = q.createdConn.Close()
}
if sterr != nil { if sterr != nil {
return sterr return sterr
} }
return seerr if seerr != nil {
return seerr
}
return pcerr
} }
// Sort available packet connections by ip address, preferring unspecified local address. // Sort available packet connections by ip address, preferring unspecified local address.