mirror of
https://github.com/ergochat/ergo.git
synced 2024-12-23 03:02:48 +01:00
commit
0f03b323d7
@ -282,7 +282,7 @@ func (server *Server) RunClient(conn IRCConn) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
server.logger.Info("connect-ip", fmt.Sprintf("Client connecting from %v", realIP))
|
server.logger.Info("connect-ip", fmt.Sprintf("Client connecting: real IP %v, proxied IP %v", realIP, proxiedIP))
|
||||||
|
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
config := server.Config()
|
config := server.Config()
|
||||||
@ -327,22 +327,19 @@ func (server *Server) RunClient(conn IRCConn) {
|
|||||||
session.resetFakelag()
|
session.resetFakelag()
|
||||||
|
|
||||||
ApplyUserModeChanges(client, config.Accounts.defaultUserModes, false, nil)
|
ApplyUserModeChanges(client, config.Accounts.defaultUserModes, false, nil)
|
||||||
|
if proxiedConn.Secure {
|
||||||
|
client.SetMode(modes.TLS, true)
|
||||||
|
}
|
||||||
|
|
||||||
if proxiedConn.Config.TLSConfig != nil {
|
if proxiedConn.Config.TLSConfig != nil {
|
||||||
client.SetMode(modes.TLS, true)
|
|
||||||
// error is not useful to us here anyways so we can ignore it
|
// error is not useful to us here anyways so we can ignore it
|
||||||
session.certfp, _ = utils.GetCertFP(proxiedConn.Conn, RegisterTimeout)
|
session.certfp, _ = utils.GetCertFP(proxiedConn.Conn, RegisterTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
if session.isTor {
|
if session.isTor {
|
||||||
client.SetMode(modes.TLS, true)
|
|
||||||
session.rawHostname = config.Server.TorListeners.Vhost
|
session.rawHostname = config.Server.TorListeners.Vhost
|
||||||
client.rawHostname = session.rawHostname
|
client.rawHostname = session.rawHostname
|
||||||
} else {
|
} 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 {
|
if config.Server.CheckIdent {
|
||||||
client.doIdentLookup(proxiedConn.Conn)
|
client.doIdentLookup(proxiedConn.Conn)
|
||||||
}
|
}
|
||||||
|
@ -57,8 +57,9 @@ func (wc *webircConfig) Populate() (err error) {
|
|||||||
// ApplyProxiedIP applies the given IP to the client.
|
// ApplyProxiedIP applies the given IP to the client.
|
||||||
func (client *Client) ApplyProxiedIP(session *Session, proxiedIP net.IP, tls bool) (err error, quitMsg string) {
|
func (client *Client) ApplyProxiedIP(session *Session, proxiedIP net.IP, tls bool) (err error, quitMsg string) {
|
||||||
// PROXY and WEBIRC are never accepted from a Tor listener, even if the address itself
|
// PROXY and WEBIRC are never accepted from a Tor listener, even if the address itself
|
||||||
// is whitelisted:
|
// is whitelisted. Furthermore, don't accept PROXY or WEBIRC if we already accepted
|
||||||
if session.isTor {
|
// a proxied IP from any source (PROXY, WEBIRC, or X-Forwarded-For):
|
||||||
|
if session.isTor || session.proxiedIP != nil {
|
||||||
return errBadProxyLine, ""
|
return errBadProxyLine, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,13 +88,6 @@ func (nl *NetListener) Stop() error {
|
|||||||
return nl.listener.Close()
|
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() {
|
func (nl *NetListener) serve() {
|
||||||
for {
|
for {
|
||||||
conn, err := nl.listener.Accept()
|
conn, err := nl.listener.Accept()
|
||||||
@ -103,9 +96,7 @@ func (nl *NetListener) serve() {
|
|||||||
// hand off the connection
|
// hand off the connection
|
||||||
wConn, ok := conn.(*utils.WrappedConn)
|
wConn, ok := conn.(*utils.WrappedConn)
|
||||||
if ok {
|
if ok {
|
||||||
if wConn.ProxiedIP != nil {
|
confirmProxyData(wConn, "", "", "", nl.server.Config())
|
||||||
validateProxiedIP(wConn, nl.server.Config())
|
|
||||||
}
|
|
||||||
go nl.server.RunClient(NewIRCStreamConn(wConn))
|
go nl.server.RunClient(NewIRCStreamConn(wConn))
|
||||||
} else {
|
} else {
|
||||||
nl.server.logger.Error("internal", "invalid connection type", nl.addr)
|
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) {
|
func (wl *WSListener) handle(w http.ResponseWriter, r *http.Request) {
|
||||||
config := wl.server.Config()
|
config := wl.server.Config()
|
||||||
proxyAllowedFrom := config.Server.proxyAllowedFromNets
|
remoteAddr := r.RemoteAddr
|
||||||
proxiedIP := utils.HandleXForwardedFor(r.RemoteAddr, r.Header.Get("X-Forwarded-For"), proxyAllowedFrom)
|
xff := r.Header.Get("X-Forwarded-For")
|
||||||
|
xfp := r.Header.Get("X-Forwarded-Proto")
|
||||||
|
|
||||||
wsUpgrader := websocket.Upgrader{
|
wsUpgrader := websocket.Upgrader{
|
||||||
CheckOrigin: func(r *http.Request) bool {
|
CheckOrigin: func(r *http.Request) bool {
|
||||||
@ -192,18 +184,39 @@ func (wl *WSListener) handle(w http.ResponseWriter, r *http.Request) {
|
|||||||
conn.Close()
|
conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if wConn.ProxiedIP != nil {
|
|
||||||
validateProxiedIP(wConn, config)
|
confirmProxyData(wConn, remoteAddr, xff, xfp, 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// avoid a DoS attack from buffering excessively large messages:
|
// avoid a DoS attack from buffering excessively large messages:
|
||||||
conn.SetReadLimit(maxReadQBytes)
|
conn.SetReadLimit(maxReadQBytes)
|
||||||
|
|
||||||
go wl.server.RunClient(NewIRCWSConn(conn))
|
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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -93,6 +93,9 @@ type WrappedConn struct {
|
|||||||
net.Conn
|
net.Conn
|
||||||
ProxiedIP net.IP
|
ProxiedIP net.IP
|
||||||
Config ListenerConfig
|
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
|
// ReloadableListener is a wrapper for net.Listener that allows reloading
|
||||||
|
Loading…
Reference in New Issue
Block a user