From e0e4791f72227d78b79c22e8cde871244095da89 Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Sat, 18 Sep 2021 21:28:16 -0400 Subject: [PATCH] factor out some shared code --- irc/client.go | 37 ++++++++----------------------------- irc/histserv.go | 8 +------- irc/panic.go | 19 +++++++++++++++++++ irc/server.go | 20 ++++---------------- irc/utils/net.go | 34 ++++++++++++++++++++++++++++++++++ 5 files changed, 66 insertions(+), 52 deletions(-) create mode 100644 irc/panic.go diff --git a/irc/client.go b/irc/client.go index a344c671..dda36a4e 100644 --- a/irc/client.go +++ b/irc/client.go @@ -488,40 +488,19 @@ func (client *Client) lookupHostname(session *Session, overwrite bool) { if session.proxiedIP != nil { ip = session.proxiedIP } - ipString := ip.String() - var hostname, candidate string + var hostname string + lookupSuccessful := false if config.Server.lookupHostnames { session.Notice("*** Looking up your hostname...") - - names, err := net.LookupAddr(ipString) - if err == nil && 0 < len(names) { - candidate = strings.TrimSuffix(names[0], ".") - } - if utils.IsHostname(candidate) { - if config.Server.ForwardConfirmHostnames { - addrs, err := net.LookupHost(candidate) - if err == nil { - for _, addr := range addrs { - if addr == ipString { - hostname = candidate // successful forward confirmation - break - } - } - } - } else { - hostname = candidate - } - } - } - - if hostname != "" { - session.Notice("*** Found your hostname") - } else { - if config.Server.lookupHostnames { + hostname, lookupSuccessful = utils.LookupHostname(ip, config.Server.ForwardConfirmHostnames) + if lookupSuccessful { + session.Notice("*** Found your hostname") + } else { session.Notice("*** Couldn't look up your hostname") } - hostname = utils.IPStringToHostname(ipString) + } else { + hostname = utils.IPStringToHostname(ip.String()) } session.rawHostname = hostname diff --git a/irc/histserv.go b/irc/histserv.go index c9228809..59149fa4 100644 --- a/irc/histserv.go +++ b/irc/histserv.go @@ -7,7 +7,6 @@ import ( "bufio" "fmt" "os" - "runtime/debug" "strconv" "time" @@ -156,12 +155,7 @@ func histservExportHandler(service *ircService, server *Server, client *Client, } func histservExportAndNotify(service *ircService, server *Server, cfAccount string, outfile *os.File, filename, alertNick string) { - defer func() { - if r := recover(); r != nil { - server.logger.Error("history", - fmt.Sprintf("Panic in history export routine: %v\n%s", r, debug.Stack())) - } - }() + defer server.HandlePanic() defer outfile.Close() writer := bufio.NewWriter(outfile) diff --git a/irc/panic.go b/irc/panic.go new file mode 100644 index 00000000..ae0b92f4 --- /dev/null +++ b/irc/panic.go @@ -0,0 +1,19 @@ +// Copyright (c) 2021 Shivaram Lingamneni +// released under the MIT license + +package irc + +import ( + "fmt" + "runtime/debug" +) + +// HandlePanic is a general-purpose panic handler for ad-hoc goroutines. +// Because of the semantics of `recover`, it must be called directly +// from the routine on whose call stack the panic would occur, with `defer`, +// e.g. `defer server.HandlePanic()` +func (server *Server) HandlePanic() { + if r := recover(); r != nil { + server.logger.Error("internal", fmt.Sprintf("Panic encountered: %v\n%s", r, debug.Stack())) + } +} diff --git a/irc/server.go b/irc/server.go index 6f4ad349..15070990 100644 --- a/irc/server.go +++ b/irc/server.go @@ -12,7 +12,6 @@ import ( _ "net/http/pprof" "os" "os/signal" - "runtime/debug" "strconv" "strings" "sync" @@ -245,14 +244,12 @@ func (server *Server) checkTorLimits() (banned bool, message string) { func (server *Server) handleAlwaysOnExpirations() { defer func() { - if r := recover(); r != nil { - server.logger.Error("internal", - fmt.Sprintf("Panic in always-on cleanup: %v\n%s", r, debug.Stack())) - } - // either way, reschedule + // reschedule whether or not there was a panic time.AfterFunc(alwaysOnExpirationPollPeriod, server.handleAlwaysOnExpirations) }() + defer server.HandlePanic() + config := server.Config() deadline := time.Duration(config.Accounts.Multiclient.AlwaysOnExpiration) if deadline == 0 { @@ -514,16 +511,7 @@ func (client *Client) getWhoisOf(target *Client, hasPrivs bool, rb *ResponseBuff // rehash reloads the config and applies the changes from the config file. func (server *Server) rehash() error { // #1570; this needs its own panic handling because it can be invoked via SIGHUP - defer func() { - if r := recover(); r != nil { - if server.Config().Debug.recoverFromErrors { - server.logger.Error("internal", - fmt.Sprintf("Panic during rehash: %v\n%s", r, debug.Stack())) - } else { - panic(r) - } - } - }() + defer server.HandlePanic() server.logger.Info("server", "Attempting rehash") diff --git a/irc/utils/net.go b/irc/utils/net.go index 451c56a0..081e067d 100644 --- a/irc/utils/net.go +++ b/irc/utils/net.go @@ -193,3 +193,37 @@ func HandleXForwardedFor(remoteAddr string, xForwardedFor string, whitelist []ne // or nil: return } + +// LookupHostname does an (optionally reverse-confirmed) hostname lookup +// suitable for use as an IRC hostname. It falls back to a string +// representation of the IP address (again suitable for use as an IRC +// hostname). +func LookupHostname(ip net.IP, forwardConfirm bool) (hostname string, lookupSuccessful bool) { + ipString := ip.String() + var candidate string + names, err := net.LookupAddr(ipString) + if err == nil && 0 < len(names) { + candidate = strings.TrimSuffix(names[0], ".") + } + if IsHostname(candidate) { + if forwardConfirm { + addrs, err := net.LookupHost(candidate) + if err == nil { + for _, addr := range addrs { + if forwardIP := net.ParseIP(addr); ip.Equal(forwardIP) { + hostname = candidate // successful forward confirmation + break + } + } + } + } else { + hostname = candidate + } + } + + if hostname != "" { + return hostname, true + } else { + return IPStringToHostname(ipString), false + } +}