make ReloadableListener lock-free

Also stop attaching the *tls.Config to the wrapped connection,
since this forces it to be retained beyond its natural lifetime.
This commit is contained in:
Shivaram Lingamneni 2023-01-05 20:18:14 -05:00
parent bceae9b739
commit 3ceff6a8b1
3 changed files with 29 additions and 27 deletions

View File

@ -295,7 +295,7 @@ func (server *Server) RunClient(conn IRCConn) {
var banMsg string
realIP := utils.AddrToIP(wConn.RemoteAddr())
var proxiedIP net.IP
if wConn.Config.Tor {
if wConn.Tor {
// cover up details of the tor proxying infrastructure (not a user privacy concern,
// but a hardening measure):
proxiedIP = utils.IPv4LoopbackAddress
@ -329,7 +329,7 @@ func (server *Server) RunClient(conn IRCConn) {
lastActive: now,
channels: make(ChannelSet),
ctime: now,
isSTSOnly: wConn.Config.STSOnly,
isSTSOnly: wConn.STSOnly,
languages: server.Languages().Default(),
loginThrottle: connection_limits.GenericThrottle{
Duration: config.Accounts.LoginThrottling.Duration,
@ -358,8 +358,8 @@ func (server *Server) RunClient(conn IRCConn) {
lastActive: now,
realIP: realIP,
proxiedIP: proxiedIP,
isTor: wConn.Config.Tor,
hideSTS: wConn.Config.Tor || wConn.Config.HideSTS,
isTor: wConn.Tor,
hideSTS: wConn.Tor || wConn.HideSTS,
}
client.sessions = []*Session{session}
@ -369,7 +369,7 @@ func (server *Server) RunClient(conn IRCConn) {
client.SetMode(modes.TLS, true)
}
if wConn.Config.TLSConfig != nil {
if wConn.TLS {
// error is not useful to us here anyways so we can ignore it
session.certfp, session.peerCerts, _ = utils.GetCertFP(wConn.Conn, RegisterTimeout)
}

View File

@ -204,10 +204,10 @@ func confirmProxyData(conn *utils.WrappedConn, remoteAddr, xForwardedFor, xForwa
}
}
if conn.Config.TLSConfig != nil || conn.Config.Tor {
if conn.TLS || conn.Tor {
// we terminated our own encryption:
conn.Secure = true
} else if !conn.Config.WebSocket {
} else if !conn.WebSocket {
// plaintext normal connection: loopback and secureNets are secure
realIP := utils.AddrToIP(conn.RemoteAddr())
conn.Secure = realIP.IsLoopback() || utils.IPInNets(realIP, config.Server.secureNets)

View File

@ -9,7 +9,7 @@ import (
"io"
"net"
"strings"
"sync"
"sync/atomic"
"time"
)
@ -209,7 +209,11 @@ func parseProxyLineV2(line []byte) (ip net.IP, err error) {
type WrappedConn struct {
net.Conn
ProxiedIP net.IP
Config ListenerConfig
TLS bool
Tor bool
STSOnly bool
WebSocket bool
HideSTS bool
// Secure indicates whether we believe the connection between us and the client
// was secure against interception and modification (including all proxies):
Secure bool
@ -218,35 +222,30 @@ type WrappedConn struct {
// ReloadableListener is a wrapper for net.Listener that allows reloading
// of config data for postprocessing connections (TLS, PROXY protocol, etc.)
type ReloadableListener struct {
// TODO: make this lock-free
sync.Mutex
realListener net.Listener
config ListenerConfig
isClosed bool
// nil means the listener is closed:
config atomic.Pointer[ListenerConfig]
}
func NewReloadableListener(realListener net.Listener, config ListenerConfig) *ReloadableListener {
return &ReloadableListener{
result := &ReloadableListener{
realListener: realListener,
config: config,
}
result.config.Store(&config) // heap escape
return result
}
func (rl *ReloadableListener) Reload(config ListenerConfig) {
rl.Lock()
rl.config = config
rl.Unlock()
rl.config.Store(&config)
}
func (rl *ReloadableListener) Accept() (conn net.Conn, err error) {
conn, err = rl.realListener.Accept()
rl.Lock()
config := rl.config
isClosed := rl.isClosed
rl.Unlock()
config := rl.config.Load()
if isClosed {
if config == nil {
// Close() was called
if err == nil {
conn.Close()
}
@ -279,14 +278,17 @@ func (rl *ReloadableListener) Accept() (conn net.Conn, err error) {
return &WrappedConn{
Conn: conn,
ProxiedIP: proxiedIP,
Config: config,
TLS: config.TLSConfig != nil,
Tor: config.Tor,
STSOnly: config.STSOnly,
WebSocket: config.WebSocket,
HideSTS: config.HideSTS,
// Secure will be set later by client code
}, nil
}
func (rl *ReloadableListener) Close() error {
rl.Lock()
rl.isClosed = true
rl.Unlock()
rl.config.Store(nil)
return rl.realListener.Close()
}