Add automated client connection limiting

This commit is contained in:
Daniel Oaks
2016-10-23 23:05:00 +10:00
parent 1092caa190
commit a404bf83d1
6 changed files with 202 additions and 10 deletions
+47 -1
View File
@@ -25,6 +25,12 @@ import (
"github.com/tidwall/buntdb"
)
var (
// cached because this may be used lots
tooManyClientsMsg = ircmsg.MakeMessage(nil, "", "ERROR", "Too many clients from your IP or network")
tooManyClientsBytes, _ = tooManyClientsMsg.Line()
)
// Limits holds the maximum limits for various things such as topic lengths
type Limits struct {
AwayLen int
@@ -67,6 +73,8 @@ type Server struct {
clients *ClientLookupSet
commands chan Command
configFilename string
connectionLimits *ConnectionLimits
connectionLimitsMutex sync.Mutex // used when affecting the connection limiter, to make sure rehashing doesn't make things go out-of-whack
ctime time.Time
currentOpers map[*Client]bool
idle chan *Client
@@ -135,6 +143,11 @@ func NewServer(configFilename string, config *Config) *Server {
log.Fatal("Error loading operators:", err.Error())
}
connectionLimits, err := NewConnectionLimits(config.Server.ConnectionLimits)
if err != nil {
log.Fatal("Error loading connection limits:", err.Error())
}
server := &Server{
accounts: make(map[string]*ClientAccount),
authenticationEnabled: config.AuthenticationEnabled,
@@ -142,6 +155,7 @@ func NewServer(configFilename string, config *Config) *Server {
clients: NewClientLookupSet(),
commands: make(chan Command),
configFilename: configFilename,
connectionLimits: connectionLimits,
ctime: time.Now(),
currentOpers: make(map[*Client]bool),
idle: make(chan *Client),
@@ -318,7 +332,21 @@ func (server *Server) Run() {
}
case conn := <-server.newConns:
go NewClient(server, conn.Conn, conn.IsTLS)
// check connection limits
ipaddr := net.ParseIP(IPString(conn.Conn.RemoteAddr()))
if ipaddr != nil {
server.connectionLimitsMutex.Lock()
err := server.connectionLimits.AddClient(ipaddr, false)
server.connectionLimitsMutex.Unlock()
if err == nil {
go NewClient(server, conn.Conn, conn.IsTLS)
continue
}
}
// too many connections from one client, tell the client and close the connection
// this might not show up properly on some clients, but our objective here is just to close it out before it has a load impact on us
conn.Conn.Write([]byte(tooManyClientsBytes))
conn.Conn.Close()
case client := <-server.idle:
client.Idle()
@@ -946,6 +974,12 @@ func (server *Server) rehash() error {
return fmt.Errorf("Error rehashing config file: %s", err.Error())
}
// confirm connectionLimits are fine
connectionLimits, err := NewConnectionLimits(config.Server.ConnectionLimits)
if err != nil {
return fmt.Errorf("Error rehashing config file: %s", err.Error())
}
// confirm operator stuff all exists and is fine
operclasses, err := config.OperatorClasses()
if err != nil {
@@ -962,6 +996,18 @@ func (server *Server) rehash() error {
}
}
// apply new connectionlimits
server.connectionLimitsMutex.Lock()
server.connectionLimits = connectionLimits
for _, client := range server.clients.ByNick {
ipaddr := net.ParseIP(IPString(client.socket.conn.RemoteAddr()))
if ipaddr != nil {
server.connectionLimits.AddClient(ipaddr, true)
}
}
server.connectionLimitsMutex.Unlock()
// setup new and removed caps
addedCaps := make(CapabilitySet)
removedCaps := make(CapabilitySet)