Merge pull request #2146 from slingamn/webirc.1

add a config switch to accept hostnames from WEBIRC
This commit is contained in:
Shivaram Lingamneni 2024-04-14 20:46:01 +02:00 committed by GitHub
commit 15d686c593
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 62 additions and 36 deletions

View File

@ -218,6 +218,10 @@ server:
# - "192.168.1.1"
# - "192.168.10.1/24"
# whether to accept the hostname parameter on the WEBIRC line as the IRC hostname
# (the default/recommended Ergo configuration will use cloaks instead)
accept-hostname: false
# maximum length of clients' sendQ in bytes
# this should be big enough to hold bursts of channel/direct messages
max-sendq: 96k

View File

@ -160,13 +160,14 @@ type Session struct {
idleTimer *time.Timer
pingSent bool // we sent PING to a putatively idle connection and we're waiting for PONG
sessionID int64
socket *Socket
realIP net.IP
proxiedIP net.IP
rawHostname string
isTor bool
hideSTS bool
sessionID int64
socket *Socket
realIP net.IP
proxiedIP net.IP
rawHostname string
hostnameFinalized bool
isTor bool
hideSTS bool
fakelag Fakelag
deferredFakelagCount int
@ -488,12 +489,21 @@ func (client *Client) resizeHistory(config *Config) {
}
}
// resolve an IP to an IRC-ready hostname, using reverse DNS, forward-confirming if necessary,
// and sending appropriate notices to the client
func (client *Client) lookupHostname(session *Session, overwrite bool) {
// once we have the final IP address (from the connection itself or from proxy data),
// compute the various possibilities for the hostname:
// * In the default/recommended configuration, via the cloak algorithm
// * If hostname lookup is enabled, via (forward-confirmed) reverse DNS
// * If WEBIRC was used, possibly via the hostname passed on the WEBIRC line
func (client *Client) finalizeHostname(session *Session) {
// only allow this once, since registration can fail (e.g. if the nickname is in use)
if session.hostnameFinalized {
return
}
session.hostnameFinalized = true
if session.isTor {
return
} // else: even if cloaking is enabled, look up the real hostname to show to operators
}
config := client.server.Config()
ip := session.realIP
@ -501,30 +511,27 @@ func (client *Client) lookupHostname(session *Session, overwrite bool) {
ip = session.proxiedIP
}
var hostname string
lookupSuccessful := false
if config.Server.lookupHostnames {
session.Notice("*** Looking up your hostname...")
hostname, lookupSuccessful = utils.LookupHostname(ip, config.Server.ForwardConfirmHostnames)
if lookupSuccessful {
session.Notice("*** Found your hostname")
// even if cloaking is enabled, we may want to look up the real hostname to show to operators:
if session.rawHostname == "" {
var hostname string
lookupSuccessful := false
if config.Server.lookupHostnames {
session.Notice("*** Looking up your hostname...")
hostname, lookupSuccessful = utils.LookupHostname(ip, config.Server.ForwardConfirmHostnames)
if lookupSuccessful {
session.Notice("*** Found your hostname")
} else {
session.Notice("*** Couldn't look up your hostname")
}
} else {
session.Notice("*** Couldn't look up your hostname")
hostname = utils.IPStringToHostname(ip.String())
}
} else {
hostname = utils.IPStringToHostname(ip.String())
session.rawHostname = hostname
}
session.rawHostname = hostname
cloakedHostname := config.Server.Cloaks.ComputeCloak(ip)
client.stateMutex.Lock()
defer client.stateMutex.Unlock()
// update the hostname if this is a new connection, but not if it's a reattach
if overwrite || client.rawHostname == "" {
client.rawHostname = hostname
client.cloakedHostname = cloakedHostname
client.updateNickMaskNoMutex()
}
// these will be discarded if this is actually a reattach:
client.rawHostname = session.rawHostname
client.cloakedHostname = config.Server.Cloaks.ComputeCloak(ip)
}
func (client *Client) doIdentLookup(conn net.Conn) {

View File

@ -32,6 +32,7 @@ type webircConfig struct {
Fingerprint *string // legacy name for certfp, #1050
Certfp string
Hosts []string
AcceptHostname bool `yaml:"accept-hostname"`
allowedNets []net.IPNet
}

View File

@ -3512,8 +3512,9 @@ func webircHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respo
}
}
config := server.Config()
givenPassword := []byte(msg.Params[0])
for _, info := range server.Config().Server.WebIRC {
for _, info := range config.Server.WebIRC {
if utils.IPInNets(client.realIP, info.allowedNets) {
// confirm password and/or fingerprint
if 0 < len(info.Password) && bcrypt.CompareHashAndPassword(info.Password, givenPassword) != nil {
@ -3523,11 +3524,23 @@ func webircHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respo
continue
}
err, quitMsg := client.ApplyProxiedIP(rb.session, net.ParseIP(msg.Params[3]), secure)
candidateIP := msg.Params[3]
err, quitMsg := client.ApplyProxiedIP(rb.session, net.ParseIP(candidateIP), secure)
if err != nil {
client.Quit(quitMsg, rb.session)
return true
} else {
if info.AcceptHostname {
candidateHostname := msg.Params[2]
if candidateHostname != candidateIP {
if utils.IsHostname(candidateHostname) {
rb.session.rawHostname = candidateHostname
} else {
// log this at debug level since it may be spammy
server.logger.Debug("internal", "invalid hostname from WEBIRC", candidateHostname)
}
}
}
return false
}
}

View File

@ -314,9 +314,7 @@ func (server *Server) checkBanScriptExemptSASL(config *Config, session *Session)
func (server *Server) tryRegister(c *Client, session *Session) (exiting bool) {
// XXX PROXY or WEBIRC MUST be sent as the first line of the session;
// if we are here at all that means we have the final value of the IP
if session.rawHostname == "" {
session.client.lookupHostname(session, false)
}
c.finalizeHostname(session)
// try to complete registration normally
// XXX(#1057) username can be filled in by an ident query without the client

View File

@ -192,6 +192,9 @@ server:
# - "192.168.1.1"
# - "192.168.10.1/24"
# whether to accept the hostname parameter on the WEBIRC line as the IRC hostname
accept-hostname: true
# maximum length of clients' sendQ in bytes
# this should be big enough to hold bursts of channel/direct messages
max-sendq: 96k