This commit is contained in:
Shivaram Lingamneni 2020-05-10 06:17:11 -04:00
parent 93f1e5b5b8
commit 0f7d58b1c5
3 changed files with 40 additions and 27 deletions

View File

@ -329,22 +329,19 @@ func (server *Server) RunClient(conn IRCConn) {
for _, defaultMode := range config.Accounts.defaultUserModes {
client.SetMode(defaultMode, true)
}
if proxiedConn.Secure {
client.SetMode(modes.TLS, true)
}
if proxiedConn.Config.TLSConfig != nil {
client.SetMode(modes.TLS, true)
// error is not useful to us here anyways so we can ignore it
session.certfp, _ = utils.GetCertFP(proxiedConn.Conn, RegisterTimeout)
}
if session.isTor {
client.SetMode(modes.TLS, true)
session.rawHostname = config.Server.TorListeners.Vhost
client.rawHostname = session.rawHostname
} else {
if realIP.IsLoopback() || utils.IPInNets(realIP, config.Server.secureNets) {
// treat local connections as secure (may be overridden later by WEBIRC)
client.SetMode(modes.TLS, true)
}
if config.Server.CheckIdent {
client.doIdentLookup(proxiedConn.Conn)
}

View File

@ -88,13 +88,6 @@ func (nl *NetListener) Stop() error {
return nl.listener.Close()
}
// ensure that any IP we got from the PROXY line is trustworthy (otherwise, clear it)
func validateProxiedIP(conn *utils.WrappedConn, config *Config) {
if !utils.IPInNets(utils.AddrToIP(conn.RemoteAddr()), config.Server.proxyAllowedFromNets) {
conn.ProxiedIP = nil
}
}
func (nl *NetListener) serve() {
for {
conn, err := nl.listener.Accept()
@ -103,9 +96,7 @@ func (nl *NetListener) serve() {
// hand off the connection
wConn, ok := conn.(*utils.WrappedConn)
if ok {
if wConn.ProxiedIP != nil {
validateProxiedIP(wConn, nl.server.Config())
}
confirmProxyData(wConn, "", "", "", nl.server.Config())
go nl.server.RunClient(NewIRCStreamConn(wConn))
} else {
nl.server.logger.Error("internal", "invalid connection type", nl.addr)
@ -159,8 +150,9 @@ func (wl *WSListener) Stop() error {
func (wl *WSListener) handle(w http.ResponseWriter, r *http.Request) {
config := wl.server.Config()
proxyAllowedFrom := config.Server.proxyAllowedFromNets
proxiedIP := utils.HandleXForwardedFor(r.RemoteAddr, r.Header.Get("X-Forwarded-For"), proxyAllowedFrom)
remoteAddr := r.RemoteAddr
xff := r.Header.Get("X-Forwarded-For")
xfp := r.Header.Get("X-Forwarded-Proto")
wsUpgrader := websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
@ -192,18 +184,39 @@ func (wl *WSListener) handle(w http.ResponseWriter, r *http.Request) {
conn.Close()
return
}
if wConn.ProxiedIP != nil {
validateProxiedIP(wConn, config)
} else {
// if there was no PROXY protocol IP, use the validated X-Forwarded-For IP instead,
// unless it is redundant
if proxiedIP != nil && !proxiedIP.Equal(utils.AddrToIP(wConn.RemoteAddr())) {
wConn.ProxiedIP = proxiedIP
}
}
confirmProxyData(wConn, remoteAddr, xff, xfp, config)
// avoid a DoS attack from buffering excessively large messages:
conn.SetReadLimit(maxReadQBytes)
go wl.server.RunClient(NewIRCWSConn(conn))
}
// validate conn.ProxiedIP and conn.Secure against config, HTTP headers, etc.
func confirmProxyData(conn *utils.WrappedConn, remoteAddr, xForwardedFor, xForwardedProto string, config *Config) {
if conn.ProxiedIP != nil {
if !utils.IPInNets(utils.AddrToIP(conn.RemoteAddr()), config.Server.proxyAllowedFromNets) {
conn.ProxiedIP = nil
}
} else if xForwardedFor != "" {
proxiedIP := utils.HandleXForwardedFor(remoteAddr, xForwardedFor, config.Server.proxyAllowedFromNets)
// don't set proxied IP if it is redundant with the actual IP
if proxiedIP != nil && !proxiedIP.Equal(utils.AddrToIP(conn.RemoteAddr())) {
conn.ProxiedIP = proxiedIP
}
}
if conn.Config.TLSConfig != nil || conn.Config.Tor {
// we terminated our own encryption:
conn.Secure = true
} else if !conn.Config.WebSocket {
// plaintext normal connection: loopback and secureNets are secure
realIP := utils.AddrToIP(conn.RemoteAddr())
conn.Secure = realIP.IsLoopback() || utils.IPInNets(realIP, config.Server.secureNets)
} else {
// plaintext websocket: trust X-Forwarded-Proto from a trusted source
conn.Secure = utils.IPInNets(utils.AddrToIP(conn.RemoteAddr()), config.Server.proxyAllowedFromNets) &&
xForwardedProto == "https"
}
}

View File

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