Bladeren bron

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.
tags/v2.12.0-rc1
Shivaram Lingamneni 1 jaar geleden
bovenliggende
commit
3ceff6a8b1
3 gewijzigde bestanden met toevoegingen van 29 en 27 verwijderingen
  1. 5
    5
      irc/client.go
  2. 2
    2
      irc/listeners.go
  3. 22
    20
      irc/utils/proxy.go

+ 5
- 5
irc/client.go Bestand weergeven

295
 	var banMsg string
295
 	var banMsg string
296
 	realIP := utils.AddrToIP(wConn.RemoteAddr())
296
 	realIP := utils.AddrToIP(wConn.RemoteAddr())
297
 	var proxiedIP net.IP
297
 	var proxiedIP net.IP
298
-	if wConn.Config.Tor {
298
+	if wConn.Tor {
299
 		// cover up details of the tor proxying infrastructure (not a user privacy concern,
299
 		// cover up details of the tor proxying infrastructure (not a user privacy concern,
300
 		// but a hardening measure):
300
 		// but a hardening measure):
301
 		proxiedIP = utils.IPv4LoopbackAddress
301
 		proxiedIP = utils.IPv4LoopbackAddress
329
 		lastActive: now,
329
 		lastActive: now,
330
 		channels:   make(ChannelSet),
330
 		channels:   make(ChannelSet),
331
 		ctime:      now,
331
 		ctime:      now,
332
-		isSTSOnly:  wConn.Config.STSOnly,
332
+		isSTSOnly:  wConn.STSOnly,
333
 		languages:  server.Languages().Default(),
333
 		languages:  server.Languages().Default(),
334
 		loginThrottle: connection_limits.GenericThrottle{
334
 		loginThrottle: connection_limits.GenericThrottle{
335
 			Duration: config.Accounts.LoginThrottling.Duration,
335
 			Duration: config.Accounts.LoginThrottling.Duration,
358
 		lastActive: now,
358
 		lastActive: now,
359
 		realIP:     realIP,
359
 		realIP:     realIP,
360
 		proxiedIP:  proxiedIP,
360
 		proxiedIP:  proxiedIP,
361
-		isTor:      wConn.Config.Tor,
362
-		hideSTS:    wConn.Config.Tor || wConn.Config.HideSTS,
361
+		isTor:      wConn.Tor,
362
+		hideSTS:    wConn.Tor || wConn.HideSTS,
363
 	}
363
 	}
364
 	client.sessions = []*Session{session}
364
 	client.sessions = []*Session{session}
365
 
365
 
369
 		client.SetMode(modes.TLS, true)
369
 		client.SetMode(modes.TLS, true)
370
 	}
370
 	}
371
 
371
 
372
-	if wConn.Config.TLSConfig != nil {
372
+	if wConn.TLS {
373
 		// error is not useful to us here anyways so we can ignore it
373
 		// error is not useful to us here anyways so we can ignore it
374
 		session.certfp, session.peerCerts, _ = utils.GetCertFP(wConn.Conn, RegisterTimeout)
374
 		session.certfp, session.peerCerts, _ = utils.GetCertFP(wConn.Conn, RegisterTimeout)
375
 	}
375
 	}

+ 2
- 2
irc/listeners.go Bestand weergeven

204
 		}
204
 		}
205
 	}
205
 	}
206
 
206
 
207
-	if conn.Config.TLSConfig != nil || conn.Config.Tor {
207
+	if conn.TLS || conn.Tor {
208
 		// we terminated our own encryption:
208
 		// we terminated our own encryption:
209
 		conn.Secure = true
209
 		conn.Secure = true
210
-	} else if !conn.Config.WebSocket {
210
+	} else if !conn.WebSocket {
211
 		// plaintext normal connection: loopback and secureNets are secure
211
 		// plaintext normal connection: loopback and secureNets are secure
212
 		realIP := utils.AddrToIP(conn.RemoteAddr())
212
 		realIP := utils.AddrToIP(conn.RemoteAddr())
213
 		conn.Secure = realIP.IsLoopback() || utils.IPInNets(realIP, config.Server.secureNets)
213
 		conn.Secure = realIP.IsLoopback() || utils.IPInNets(realIP, config.Server.secureNets)

+ 22
- 20
irc/utils/proxy.go Bestand weergeven

9
 	"io"
9
 	"io"
10
 	"net"
10
 	"net"
11
 	"strings"
11
 	"strings"
12
-	"sync"
12
+	"sync/atomic"
13
 	"time"
13
 	"time"
14
 )
14
 )
15
 
15
 
209
 type WrappedConn struct {
209
 type WrappedConn struct {
210
 	net.Conn
210
 	net.Conn
211
 	ProxiedIP net.IP
211
 	ProxiedIP net.IP
212
-	Config    ListenerConfig
212
+	TLS       bool
213
+	Tor       bool
214
+	STSOnly   bool
215
+	WebSocket bool
216
+	HideSTS   bool
213
 	// Secure indicates whether we believe the connection between us and the client
217
 	// Secure indicates whether we believe the connection between us and the client
214
 	// was secure against interception and modification (including all proxies):
218
 	// was secure against interception and modification (including all proxies):
215
 	Secure bool
219
 	Secure bool
218
 // ReloadableListener is a wrapper for net.Listener that allows reloading
222
 // ReloadableListener is a wrapper for net.Listener that allows reloading
219
 // of config data for postprocessing connections (TLS, PROXY protocol, etc.)
223
 // of config data for postprocessing connections (TLS, PROXY protocol, etc.)
220
 type ReloadableListener struct {
224
 type ReloadableListener struct {
221
-	// TODO: make this lock-free
222
-	sync.Mutex
223
 	realListener net.Listener
225
 	realListener net.Listener
224
-	config       ListenerConfig
225
-	isClosed     bool
226
+	// nil means the listener is closed:
227
+	config atomic.Pointer[ListenerConfig]
226
 }
228
 }
227
 
229
 
228
 func NewReloadableListener(realListener net.Listener, config ListenerConfig) *ReloadableListener {
230
 func NewReloadableListener(realListener net.Listener, config ListenerConfig) *ReloadableListener {
229
-	return &ReloadableListener{
231
+	result := &ReloadableListener{
230
 		realListener: realListener,
232
 		realListener: realListener,
231
-		config:       config,
232
 	}
233
 	}
234
+	result.config.Store(&config) // heap escape
235
+	return result
233
 }
236
 }
234
 
237
 
235
 func (rl *ReloadableListener) Reload(config ListenerConfig) {
238
 func (rl *ReloadableListener) Reload(config ListenerConfig) {
236
-	rl.Lock()
237
-	rl.config = config
238
-	rl.Unlock()
239
+	rl.config.Store(&config)
239
 }
240
 }
240
 
241
 
241
 func (rl *ReloadableListener) Accept() (conn net.Conn, err error) {
242
 func (rl *ReloadableListener) Accept() (conn net.Conn, err error) {
242
 	conn, err = rl.realListener.Accept()
243
 	conn, err = rl.realListener.Accept()
243
 
244
 
244
-	rl.Lock()
245
-	config := rl.config
246
-	isClosed := rl.isClosed
247
-	rl.Unlock()
245
+	config := rl.config.Load()
248
 
246
 
249
-	if isClosed {
247
+	if config == nil {
248
+		// Close() was called
250
 		if err == nil {
249
 		if err == nil {
251
 			conn.Close()
250
 			conn.Close()
252
 		}
251
 		}
279
 	return &WrappedConn{
278
 	return &WrappedConn{
280
 		Conn:      conn,
279
 		Conn:      conn,
281
 		ProxiedIP: proxiedIP,
280
 		ProxiedIP: proxiedIP,
282
-		Config:    config,
281
+		TLS:       config.TLSConfig != nil,
282
+		Tor:       config.Tor,
283
+		STSOnly:   config.STSOnly,
284
+		WebSocket: config.WebSocket,
285
+		HideSTS:   config.HideSTS,
286
+		// Secure will be set later by client code
283
 	}, nil
287
 	}, nil
284
 }
288
 }
285
 
289
 
286
 func (rl *ReloadableListener) Close() error {
290
 func (rl *ReloadableListener) Close() error {
287
-	rl.Lock()
288
-	rl.isClosed = true
289
-	rl.Unlock()
291
+	rl.config.Store(nil)
290
 
292
 
291
 	return rl.realListener.Close()
293
 	return rl.realListener.Close()
292
 }
294
 }

Laden…
Annuleren
Opslaan