Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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