Skip to content

Commit

Permalink
Merge pull request #2146 from slingamn/webirc.1
Browse files Browse the repository at this point in the history
add a config switch to accept hostnames from WEBIRC
  • Loading branch information
slingamn authored Apr 14, 2024
2 parents 1f4b524 + 7726160 commit 15d686c
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 36 deletions.
4 changes: 4 additions & 0 deletions default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
69 changes: 38 additions & 31 deletions irc/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -488,43 +489,49 @@ 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
if session.proxiedIP != nil {
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) {
Expand Down
1 change: 1 addition & 0 deletions irc/gateways.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
17 changes: 15 additions & 2 deletions irc/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
}
}
Expand Down
4 changes: 1 addition & 3 deletions irc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions traditional.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 15d686c

Please sign in to comment.