1
0
Fork 0
forked from External/ergo

add support for tor (#369)

This commit is contained in:
Shivaram Lingamneni 2019-02-25 21:50:43 -05:00
parent d43ce07b66
commit b0f89062fa
10 changed files with 307 additions and 77 deletions

View file

@ -21,7 +21,6 @@ import (
"time"
"github.com/goshuirc/irc-go/ircfmt"
"github.com/goshuirc/irc-go/ircmsg"
"github.com/oragono/oragono/irc/caps"
"github.com/oragono/oragono/irc/connection_limits"
"github.com/oragono/oragono/irc/isupport"
@ -35,10 +34,7 @@ import (
var (
// common error line to sub values into
errorMsg, _ = (&[]ircmsg.IrcMessage{ircmsg.MakeMessage(nil, "", "ERROR", "%s ")}[0]).Line()
// common error responses
couldNotParseIPMsg, _ = (&[]ircmsg.IrcMessage{ircmsg.MakeMessage(nil, "", "ERROR", "Unable to parse your IP address")}[0]).Line()
errorMsg = "ERROR :%s\r\n"
// supportedUserModesString acts as a cache for when we introduce users
supportedUserModesString = modes.SupportedUserModes.String()
@ -58,6 +54,7 @@ var (
type ListenerWrapper struct {
listener net.Listener
tlsConfig *tls.Config
isTor bool
shouldStop bool
// protects atomic update of tlsConfig and shouldStop:
configMutex sync.Mutex // tier 1
@ -92,6 +89,7 @@ type Server struct {
signals chan os.Signal
snomasks *SnoManager
store *buntdb.DB
torLimiter connection_limits.TorLimiter
whoWas *WhoWasList
stats *Stats
semaphores *ServerSemaphores
@ -109,6 +107,7 @@ var (
type clientConn struct {
Conn net.Conn
IsTLS bool
IsTor bool
}
// NewServer returns a new Oragono server.
@ -252,22 +251,27 @@ func (server *Server) Run() {
}
func (server *Server) acceptClient(conn clientConn) {
// check IP address
ipaddr := utils.AddrToIP(conn.Conn.RemoteAddr())
if ipaddr != nil {
isBanned, banMsg := server.checkBans(ipaddr)
if isBanned {
// this might not show up properly on some clients, but our objective here is just to close the connection out before it has a load impact on us
conn.Conn.Write([]byte(fmt.Sprintf(errorMsg, banMsg)))
conn.Conn.Close()
return
}
var isBanned bool
var banMsg string
var ipaddr net.IP
if conn.IsTor {
ipaddr = utils.IPv4LoopbackAddress
isBanned, banMsg = server.checkTorLimits()
} else {
ipaddr = utils.AddrToIP(conn.Conn.RemoteAddr())
isBanned, banMsg = server.checkBans(ipaddr)
}
if isBanned {
// this might not show up properly on some clients, but our objective here is just to close the connection out before it has a load impact on us
conn.Conn.Write([]byte(fmt.Sprintf(errorMsg, banMsg)))
conn.Conn.Close()
return
}
server.logger.Info("localconnect-ip", fmt.Sprintf("Client connecting from %v", ipaddr))
// prolly don't need to alert snomasks on this, only on connection reg
NewClient(server, conn.Conn, conn.IsTLS)
go RunNewClient(server, conn)
}
func (server *Server) checkBans(ipaddr net.IP) (banned bool, message string) {
@ -310,12 +314,23 @@ func (server *Server) checkBans(ipaddr net.IP) (banned bool, message string) {
return false, ""
}
func (server *Server) checkTorLimits() (banned bool, message string) {
switch server.torLimiter.AddClient() {
case connection_limits.ErrLimitExceeded:
return true, "Too many clients from the Tor network"
case connection_limits.ErrThrottleExceeded:
return true, "Exceeded connection throttle for the Tor network"
default:
return false, ""
}
}
//
// IRC protocol listeners
//
// createListener starts a given listener.
func (server *Server) createListener(addr string, tlsConfig *tls.Config, bindMode os.FileMode) (*ListenerWrapper, error) {
func (server *Server) createListener(addr string, tlsConfig *tls.Config, isTor bool, bindMode os.FileMode) (*ListenerWrapper, error) {
// make listener
var listener net.Listener
var err error
@ -338,6 +353,7 @@ func (server *Server) createListener(addr string, tlsConfig *tls.Config, bindMod
wrapper := ListenerWrapper{
listener: listener,
tlsConfig: tlsConfig,
isTor: isTor,
shouldStop: false,
}
@ -349,10 +365,10 @@ func (server *Server) createListener(addr string, tlsConfig *tls.Config, bindMod
conn, err := listener.Accept()
// synchronously access config data:
// whether TLS is enabled and whether we should stop listening
wrapper.configMutex.Lock()
shouldStop = wrapper.shouldStop
tlsConfig = wrapper.tlsConfig
isTor = wrapper.isTor
wrapper.configMutex.Unlock()
if err == nil {
@ -362,6 +378,7 @@ func (server *Server) createListener(addr string, tlsConfig *tls.Config, bindMod
newConn := clientConn{
Conn: conn,
IsTLS: tlsConfig != nil,
IsTor: isTor,
}
// hand off the connection
go server.acceptClient(newConn)
@ -524,7 +541,7 @@ func (client *Client) getWhoisOf(target *Client, rb *ResponseBuffer) {
rb.Add(nil, client.server.name, RPL_WHOISOPERATOR, cnick, tnick, tOper.WhoisLine)
}
if client.HasMode(modes.Operator) || client == target {
rb.Add(nil, client.server.name, RPL_WHOISACTUALLY, cnick, tnick, fmt.Sprintf("%s@%s", target.username, utils.LookupHostname(target.IPString())), target.IPString(), client.t("Actual user@host, Actual IP"))
rb.Add(nil, client.server.name, RPL_WHOISACTUALLY, cnick, tnick, fmt.Sprintf("%s@%s", targetInfo.username, target.RawHostname()), target.IPString(), client.t("Actual user@host, Actual IP"))
}
if target.HasMode(modes.TLS) {
rb.Add(nil, client.server.name, RPL_WHOISSECURE, cnick, tnick, client.t("is using a secure connection"))
@ -639,6 +656,9 @@ func (server *Server) applyConfig(config *Config, initial bool) (err error) {
return err
}
tlConf := &config.Server.TorListeners
server.torLimiter.Configure(tlConf.MaxConnections, tlConf.ThrottleDuration, tlConf.MaxConnectionsPerDuration)
// reload logging config
wasLoggingRawIO := !initial && server.logger.IsLoggingRawIO()
err = server.logger.ApplyConfig(config.Logging)
@ -931,9 +951,9 @@ func (server *Server) loadDatastore(config *Config) error {
}
func (server *Server) setupListeners(config *Config) (err error) {
logListener := func(addr string, tlsconfig *tls.Config) {
logListener := func(addr string, tlsconfig *tls.Config, isTor bool) {
server.logger.Info("listeners",
fmt.Sprintf("now listening on %s, tls=%t.", addr, (tlsconfig != nil)),
fmt.Sprintf("now listening on %s, tls=%t, tor=%t.", addr, (tlsconfig != nil), isTor),
)
}
@ -943,6 +963,15 @@ func (server *Server) setupListeners(config *Config) (err error) {
return
}
isTorListener := func(listener string) bool {
for _, torListener := range config.Server.TorListeners.Listeners {
if listener == torListener {
return true
}
}
return false
}
// update or destroy all existing listeners
for addr := range server.listeners {
currentListener := server.listeners[addr]
@ -958,13 +987,16 @@ func (server *Server) setupListeners(config *Config) (err error) {
// its next Accept(). this is like sending over a buffered channel of
// size 1, but where sending a second item overwrites the buffered item
// instead of blocking.
tlsConfig := tlsListeners[addr]
isTor := isTorListener(addr)
currentListener.configMutex.Lock()
currentListener.shouldStop = !stillConfigured
currentListener.tlsConfig = tlsListeners[addr]
currentListener.tlsConfig = tlsConfig
currentListener.isTor = isTor
currentListener.configMutex.Unlock()
if stillConfigured {
logListener(addr, currentListener.tlsConfig)
logListener(addr, tlsConfig, isTor)
} else {
// tell the listener it should stop by interrupting its Accept() call:
currentListener.listener.Close()
@ -978,15 +1010,16 @@ func (server *Server) setupListeners(config *Config) (err error) {
_, exists := server.listeners[newaddr]
if !exists {
// make new listener
isTor := isTorListener(newaddr)
tlsConfig := tlsListeners[newaddr]
listener, listenerErr := server.createListener(newaddr, tlsConfig, config.Server.UnixBindMode)
listener, listenerErr := server.createListener(newaddr, tlsConfig, isTor, config.Server.UnixBindMode)
if listenerErr != nil {
server.logger.Error("server", "couldn't listen on", newaddr, listenerErr.Error())
err = listenerErr
continue
}
server.listeners[newaddr] = listener
logListener(newaddr, tlsConfig)
logListener(newaddr, tlsConfig, isTor)
}
}