Browse Source

fix #996

tags/v2.1.0-rc1
Shivaram Lingamneni 4 years ago
parent
commit
0f7d58b1c5
3 changed files with 40 additions and 27 deletions
  1. 3
    6
      irc/client.go
  2. 34
    21
      irc/listeners.go
  3. 3
    0
      irc/utils/proxy.go

+ 3
- 6
irc/client.go View File

@@ -329,22 +329,19 @@ func (server *Server) RunClient(conn IRCConn) {
329 329
 	for _, defaultMode := range config.Accounts.defaultUserModes {
330 330
 		client.SetMode(defaultMode, true)
331 331
 	}
332
+	if proxiedConn.Secure {
333
+		client.SetMode(modes.TLS, true)
334
+	}
332 335
 
333 336
 	if proxiedConn.Config.TLSConfig != nil {
334
-		client.SetMode(modes.TLS, true)
335 337
 		// error is not useful to us here anyways so we can ignore it
336 338
 		session.certfp, _ = utils.GetCertFP(proxiedConn.Conn, RegisterTimeout)
337 339
 	}
338 340
 
339 341
 	if session.isTor {
340
-		client.SetMode(modes.TLS, true)
341 342
 		session.rawHostname = config.Server.TorListeners.Vhost
342 343
 		client.rawHostname = session.rawHostname
343 344
 	} else {
344
-		if realIP.IsLoopback() || utils.IPInNets(realIP, config.Server.secureNets) {
345
-			// treat local connections as secure (may be overridden later by WEBIRC)
346
-			client.SetMode(modes.TLS, true)
347
-		}
348 345
 		if config.Server.CheckIdent {
349 346
 			client.doIdentLookup(proxiedConn.Conn)
350 347
 		}

+ 34
- 21
irc/listeners.go View File

@@ -88,13 +88,6 @@ func (nl *NetListener) Stop() error {
88 88
 	return nl.listener.Close()
89 89
 }
90 90
 
91
-// ensure that any IP we got from the PROXY line is trustworthy (otherwise, clear it)
92
-func validateProxiedIP(conn *utils.WrappedConn, config *Config) {
93
-	if !utils.IPInNets(utils.AddrToIP(conn.RemoteAddr()), config.Server.proxyAllowedFromNets) {
94
-		conn.ProxiedIP = nil
95
-	}
96
-}
97
-
98 91
 func (nl *NetListener) serve() {
99 92
 	for {
100 93
 		conn, err := nl.listener.Accept()
@@ -103,9 +96,7 @@ func (nl *NetListener) serve() {
103 96
 			// hand off the connection
104 97
 			wConn, ok := conn.(*utils.WrappedConn)
105 98
 			if ok {
106
-				if wConn.ProxiedIP != nil {
107
-					validateProxiedIP(wConn, nl.server.Config())
108
-				}
99
+				confirmProxyData(wConn, "", "", "", nl.server.Config())
109 100
 				go nl.server.RunClient(NewIRCStreamConn(wConn))
110 101
 			} else {
111 102
 				nl.server.logger.Error("internal", "invalid connection type", nl.addr)
@@ -159,8 +150,9 @@ func (wl *WSListener) Stop() error {
159 150
 
160 151
 func (wl *WSListener) handle(w http.ResponseWriter, r *http.Request) {
161 152
 	config := wl.server.Config()
162
-	proxyAllowedFrom := config.Server.proxyAllowedFromNets
163
-	proxiedIP := utils.HandleXForwardedFor(r.RemoteAddr, r.Header.Get("X-Forwarded-For"), proxyAllowedFrom)
153
+	remoteAddr := r.RemoteAddr
154
+	xff := r.Header.Get("X-Forwarded-For")
155
+	xfp := r.Header.Get("X-Forwarded-Proto")
164 156
 
165 157
 	wsUpgrader := websocket.Upgrader{
166 158
 		CheckOrigin: func(r *http.Request) bool {
@@ -192,18 +184,39 @@ func (wl *WSListener) handle(w http.ResponseWriter, r *http.Request) {
192 184
 		conn.Close()
193 185
 		return
194 186
 	}
195
-	if wConn.ProxiedIP != nil {
196
-		validateProxiedIP(wConn, config)
197
-	} else {
198
-		// if there was no PROXY protocol IP, use the validated X-Forwarded-For IP instead,
199
-		// unless it is redundant
200
-		if proxiedIP != nil && !proxiedIP.Equal(utils.AddrToIP(wConn.RemoteAddr())) {
201
-			wConn.ProxiedIP = proxiedIP
202
-		}
203
-	}
187
+
188
+	confirmProxyData(wConn, remoteAddr, xff, xfp, config)
204 189
 
205 190
 	// avoid a DoS attack from buffering excessively large messages:
206 191
 	conn.SetReadLimit(maxReadQBytes)
207 192
 
208 193
 	go wl.server.RunClient(NewIRCWSConn(conn))
209 194
 }
195
+
196
+// validate conn.ProxiedIP and conn.Secure against config, HTTP headers, etc.
197
+func confirmProxyData(conn *utils.WrappedConn, remoteAddr, xForwardedFor, xForwardedProto string, config *Config) {
198
+	if conn.ProxiedIP != nil {
199
+		if !utils.IPInNets(utils.AddrToIP(conn.RemoteAddr()), config.Server.proxyAllowedFromNets) {
200
+			conn.ProxiedIP = nil
201
+		}
202
+	} else if xForwardedFor != "" {
203
+		proxiedIP := utils.HandleXForwardedFor(remoteAddr, xForwardedFor, config.Server.proxyAllowedFromNets)
204
+		// don't set proxied IP if it is redundant with the actual IP
205
+		if proxiedIP != nil && !proxiedIP.Equal(utils.AddrToIP(conn.RemoteAddr())) {
206
+			conn.ProxiedIP = proxiedIP
207
+		}
208
+	}
209
+
210
+	if conn.Config.TLSConfig != nil || conn.Config.Tor {
211
+		// we terminated our own encryption:
212
+		conn.Secure = true
213
+	} else if !conn.Config.WebSocket {
214
+		// plaintext normal connection: loopback and secureNets are secure
215
+		realIP := utils.AddrToIP(conn.RemoteAddr())
216
+		conn.Secure = realIP.IsLoopback() || utils.IPInNets(realIP, config.Server.secureNets)
217
+	} else {
218
+		// plaintext websocket: trust X-Forwarded-Proto from a trusted source
219
+		conn.Secure = utils.IPInNets(utils.AddrToIP(conn.RemoteAddr()), config.Server.proxyAllowedFromNets) &&
220
+			xForwardedProto == "https"
221
+	}
222
+}

+ 3
- 0
irc/utils/proxy.go View File

@@ -93,6 +93,9 @@ type WrappedConn struct {
93 93
 	net.Conn
94 94
 	ProxiedIP net.IP
95 95
 	Config    ListenerConfig
96
+	// Secure indicates whether we believe the connection between us and the client
97
+	// was secure against interception and modification (including all proxies):
98
+	Secure bool
96 99
 }
97 100
 
98 101
 // ReloadableListener is a wrapper for net.Listener that allows reloading

Loading…
Cancel
Save