mirror of
				https://github.com/ergochat/ergo.git
				synced 2025-11-03 23:37:22 +01:00 
			
		
		
		
	Add initial automated connection throttling
This commit is contained in:
		
							parent
							
								
									ddba5af265
								
							
						
					
					
						commit
						91d59575ce
					
				@ -11,15 +11,17 @@ New release of Oragono!
 | 
			
		||||
 | 
			
		||||
### Added
 | 
			
		||||
* Added ARM build (for Raspberry PIs and similar).
 | 
			
		||||
* Added `KLINE` and `UNDLINE` commands. Complementing `KLINE`, this lets you ban masks from the server.
 | 
			
		||||
* Added automated connection throttling! To enable this, copy the `connection-throttling` section from the config.
 | 
			
		||||
* Added `KLINE` and `UNDLINE` commands. Complementing `DLINE`'s per-IP and per-network bans, this lets you ban masks from the server.
 | 
			
		||||
 | 
			
		||||
### Changed
 | 
			
		||||
* Connection limits can now be freely enabled or disabled. To enable automated limit handling, see the new `enabled` flag in the config, under `connection-limits`.
 | 
			
		||||
 | 
			
		||||
### Removed
 | 
			
		||||
 | 
			
		||||
### Fixed
 | 
			
		||||
* Fixed an issue where `UNDLINE` didn't save across server launches.
 | 
			
		||||
* Removed several race conditions and made the server more resiliant to these bugs.
 | 
			
		||||
* Removed several race conditions which could result in server panics.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## [0.5.0] - 2016-12-10
 | 
			
		||||
 | 
			
		||||
@ -12,6 +12,7 @@ import (
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"log"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"gopkg.in/yaml.v2"
 | 
			
		||||
)
 | 
			
		||||
@ -95,12 +96,26 @@ type RestAPIConfig struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ConnectionLimitsConfig struct {
 | 
			
		||||
	Enabled     bool
 | 
			
		||||
	CidrLenIPv4 int `yaml:"cidr-len-ipv4"`
 | 
			
		||||
	CidrLenIPv6 int `yaml:"cidr-len-ipv6"`
 | 
			
		||||
	IPsPerCidr  int `yaml:"ips-per-subnet"`
 | 
			
		||||
	Exempted    []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ConnectionThrottleConfig struct {
 | 
			
		||||
	Enabled            bool
 | 
			
		||||
	CidrLenIPv4        int           `yaml:"cidr-len-ipv4"`
 | 
			
		||||
	CidrLenIPv6        int           `yaml:"cidr-len-ipv6"`
 | 
			
		||||
	ConnectionsPerCidr int           `yaml:"max-connections"`
 | 
			
		||||
	DurationString     string        `yaml:"duration"`
 | 
			
		||||
	Duration           time.Duration `yaml:"duration-time"`
 | 
			
		||||
	BanDurationString  string        `yaml:"ban-duration"`
 | 
			
		||||
	BanDuration        time.Duration
 | 
			
		||||
	BanMessage         string `yaml:"ban-message"`
 | 
			
		||||
	Exempted           []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Config struct {
 | 
			
		||||
	Network struct {
 | 
			
		||||
		Name string
 | 
			
		||||
@ -108,16 +123,17 @@ type Config struct {
 | 
			
		||||
 | 
			
		||||
	Server struct {
 | 
			
		||||
		PassConfig
 | 
			
		||||
		Password         string
 | 
			
		||||
		Name             string
 | 
			
		||||
		Listen           []string
 | 
			
		||||
		Wslisten         string                      `yaml:"ws-listen"`
 | 
			
		||||
		TLSListeners     map[string]*TLSListenConfig `yaml:"tls-listeners"`
 | 
			
		||||
		RestAPI          RestAPIConfig               `yaml:"rest-api"`
 | 
			
		||||
		CheckIdent       bool                        `yaml:"check-ident"`
 | 
			
		||||
		Log              string
 | 
			
		||||
		MOTD             string
 | 
			
		||||
		ConnectionLimits ConnectionLimitsConfig `yaml:"connection-limits"`
 | 
			
		||||
		Password           string
 | 
			
		||||
		Name               string
 | 
			
		||||
		Listen             []string
 | 
			
		||||
		Wslisten           string                      `yaml:"ws-listen"`
 | 
			
		||||
		TLSListeners       map[string]*TLSListenConfig `yaml:"tls-listeners"`
 | 
			
		||||
		RestAPI            RestAPIConfig               `yaml:"rest-api"`
 | 
			
		||||
		CheckIdent         bool                        `yaml:"check-ident"`
 | 
			
		||||
		Log                string
 | 
			
		||||
		MOTD               string
 | 
			
		||||
		ConnectionLimits   ConnectionLimitsConfig   `yaml:"connection-limits"`
 | 
			
		||||
		ConnectionThrottle ConnectionThrottleConfig `yaml:"connection-throttling"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Datastore struct {
 | 
			
		||||
@ -309,6 +325,16 @@ func LoadConfig(filename string) (config *Config, err error) {
 | 
			
		||||
	if config.Limits.NickLen < 1 || config.Limits.ChannelLen < 2 || config.Limits.AwayLen < 1 || config.Limits.KickLen < 1 || config.Limits.TopicLen < 1 {
 | 
			
		||||
		return nil, errors.New("Limits aren't setup properly, check them and make them sane")
 | 
			
		||||
	}
 | 
			
		||||
	if config.Server.ConnectionThrottle.Enabled {
 | 
			
		||||
		config.Server.ConnectionThrottle.Duration, err = time.ParseDuration(config.Server.ConnectionThrottle.DurationString)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("Could not parse connection-throttle duration: %s", err.Error())
 | 
			
		||||
		}
 | 
			
		||||
		config.Server.ConnectionThrottle.BanDuration, err = time.ParseDuration(config.Server.ConnectionThrottle.BanDurationString)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("Could not parse connection-throttle ban-duration: %s", err.Error())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return config, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -15,6 +15,7 @@ var (
 | 
			
		||||
 | 
			
		||||
// ConnectionLimits manages the automated client connection limits.
 | 
			
		||||
type ConnectionLimits struct {
 | 
			
		||||
	enabled  bool
 | 
			
		||||
	ipv4Mask net.IPMask
 | 
			
		||||
	ipv6Mask net.IPMask
 | 
			
		||||
	// subnetLimit is the maximum number of clients per subnet
 | 
			
		||||
@ -44,6 +45,10 @@ func (cl *ConnectionLimits) maskAddr(addr net.IP) net.IP {
 | 
			
		||||
// AddClient adds a client to our population if possible. If we can't, throws an error instead.
 | 
			
		||||
// 'force' is used to add already-existing clients (i.e. ones that are already on the network).
 | 
			
		||||
func (cl *ConnectionLimits) AddClient(addr net.IP, force bool) error {
 | 
			
		||||
	if !cl.enabled {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// check exempted lists
 | 
			
		||||
	// we don't track populations for exempted addresses or nets - this is by design
 | 
			
		||||
	if cl.exemptedIPs[addr.String()] {
 | 
			
		||||
@ -70,6 +75,10 @@ func (cl *ConnectionLimits) AddClient(addr net.IP, force bool) error {
 | 
			
		||||
 | 
			
		||||
// RemoveClient removes the given address from our population
 | 
			
		||||
func (cl *ConnectionLimits) RemoveClient(addr net.IP) {
 | 
			
		||||
	if !cl.enabled {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	addrString := addr.String()
 | 
			
		||||
	cl.population[addrString] = cl.population[addrString] - 1
 | 
			
		||||
 | 
			
		||||
@ -82,6 +91,8 @@ func (cl *ConnectionLimits) RemoveClient(addr net.IP) {
 | 
			
		||||
// NewConnectionLimits returns a new connection limit handler.
 | 
			
		||||
func NewConnectionLimits(config ConnectionLimitsConfig) (*ConnectionLimits, error) {
 | 
			
		||||
	var cl ConnectionLimits
 | 
			
		||||
	cl.enabled = config.Enabled
 | 
			
		||||
 | 
			
		||||
	cl.population = make(map[string]int)
 | 
			
		||||
	cl.exemptedIPs = make(map[string]bool)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										142
									
								
								irc/connection_throttling.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								irc/connection_throttling.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,142 @@
 | 
			
		||||
// Copyright (c) 2016- Daniel Oaks <daniel@danieloaks.net>
 | 
			
		||||
// released under the MIT license
 | 
			
		||||
 | 
			
		||||
package irc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/DanielOaks/girc-go/ircmsg"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ThrottleDetails holds the connection-throttling details for a subnet/IP.
 | 
			
		||||
type ThrottleDetails struct {
 | 
			
		||||
	Start       time.Time
 | 
			
		||||
	ClientCount int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ConnectionThrottle manages automated client connection throttling.
 | 
			
		||||
type ConnectionThrottle struct {
 | 
			
		||||
	enabled     bool
 | 
			
		||||
	ipv4Mask    net.IPMask
 | 
			
		||||
	ipv6Mask    net.IPMask
 | 
			
		||||
	subnetLimit int
 | 
			
		||||
	duration    time.Duration
 | 
			
		||||
	population  map[string]ThrottleDetails
 | 
			
		||||
 | 
			
		||||
	// used by the server to ban clients that go over this limit
 | 
			
		||||
	BanDuration     time.Duration
 | 
			
		||||
	BanMessage      string
 | 
			
		||||
	BanMessageBytes []byte
 | 
			
		||||
 | 
			
		||||
	// exemptedIPs holds IPs that are exempt from limits
 | 
			
		||||
	exemptedIPs map[string]bool
 | 
			
		||||
	// exemptedNets holds networks that are exempt from limits
 | 
			
		||||
	exemptedNets []net.IPNet
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// maskAddr masks the given IPv4/6 address with our cidr limit masks.
 | 
			
		||||
func (ct *ConnectionThrottle) maskAddr(addr net.IP) net.IP {
 | 
			
		||||
	if addr.To4() == nil {
 | 
			
		||||
		// IPv6 addr
 | 
			
		||||
		addr = addr.Mask(ct.ipv6Mask)
 | 
			
		||||
	} else {
 | 
			
		||||
		// IPv4 addr
 | 
			
		||||
		addr = addr.Mask(ct.ipv4Mask)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return addr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ResetFor removes any existing count for the given address.
 | 
			
		||||
func (ct *ConnectionThrottle) ResetFor(addr net.IP) {
 | 
			
		||||
	if !ct.enabled {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// remove
 | 
			
		||||
	ct.maskAddr(addr)
 | 
			
		||||
	addrString := addr.String()
 | 
			
		||||
	delete(ct.population, addrString)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddClient introduces a new client connection if possible. If we can't, throws an error instead.
 | 
			
		||||
func (ct *ConnectionThrottle) AddClient(addr net.IP) error {
 | 
			
		||||
	if !ct.enabled {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// check exempted lists
 | 
			
		||||
	if ct.exemptedIPs[addr.String()] {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	for _, ex := range ct.exemptedNets {
 | 
			
		||||
		if ex.Contains(addr) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// check throttle
 | 
			
		||||
	ct.maskAddr(addr)
 | 
			
		||||
	addrString := addr.String()
 | 
			
		||||
 | 
			
		||||
	details, exists := ct.population[addrString]
 | 
			
		||||
	if !exists || details.Start.Add(ct.duration).Before(time.Now()) {
 | 
			
		||||
		details = ThrottleDetails{
 | 
			
		||||
			Start: time.Now(),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if details.ClientCount+1 > ct.subnetLimit {
 | 
			
		||||
		return errTooManyClients
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	details.ClientCount++
 | 
			
		||||
	ct.population[addrString] = details
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewConnectionThrottle returns a new client connection throttler.
 | 
			
		||||
func NewConnectionThrottle(config ConnectionThrottleConfig) (*ConnectionThrottle, error) {
 | 
			
		||||
	var ct ConnectionThrottle
 | 
			
		||||
	ct.enabled = config.Enabled
 | 
			
		||||
 | 
			
		||||
	ct.population = make(map[string]ThrottleDetails)
 | 
			
		||||
	ct.exemptedIPs = make(map[string]bool)
 | 
			
		||||
 | 
			
		||||
	ct.ipv4Mask = net.CIDRMask(config.CidrLenIPv4, 32)
 | 
			
		||||
	ct.ipv6Mask = net.CIDRMask(config.CidrLenIPv6, 128)
 | 
			
		||||
	ct.subnetLimit = config.ConnectionsPerCidr
 | 
			
		||||
 | 
			
		||||
	ct.duration = config.Duration
 | 
			
		||||
 | 
			
		||||
	ct.BanDuration = config.BanDuration
 | 
			
		||||
	ct.BanMessage = config.BanMessage
 | 
			
		||||
	ircmsgOutput := ircmsg.MakeMessage(nil, "", "ERROR", ct.BanMessage)
 | 
			
		||||
	msg, err := ircmsgOutput.Line()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("Could not make error message: %s", err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	ct.BanMessageBytes = []byte(msg)
 | 
			
		||||
 | 
			
		||||
	// assemble exempted nets
 | 
			
		||||
	for _, cidr := range config.Exempted {
 | 
			
		||||
		ipaddr := net.ParseIP(cidr)
 | 
			
		||||
		_, netaddr, err := net.ParseCIDR(cidr)
 | 
			
		||||
 | 
			
		||||
		if ipaddr == nil && err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("Could not parse exempted IP/network [%s]", cidr)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ipaddr != nil {
 | 
			
		||||
			ct.exemptedIPs[ipaddr.String()] = true
 | 
			
		||||
		} else {
 | 
			
		||||
			ct.exemptedNets = append(ct.exemptedNets, *netaddr)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &ct, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										118
									
								
								irc/server.go
									
									
									
									
									
								
							
							
						
						
									
										118
									
								
								irc/server.go
									
									
									
									
									
								
							@ -28,7 +28,7 @@ import (
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// cached because this may be used lots
 | 
			
		||||
	tooManyClientsMsg      = ircmsg.MakeMessage(nil, "", "ERROR", "Too many clients from your IP or network")
 | 
			
		||||
	tooManyClientsMsg      = ircmsg.MakeMessage(nil, "", "ERROR", "Too many clients from your network")
 | 
			
		||||
	tooManyClientsBytes, _ = tooManyClientsMsg.Line()
 | 
			
		||||
 | 
			
		||||
	bannedFromServerMsg      = ircmsg.MakeMessage(nil, "", "ERROR", "You are banned from this server (%s)")
 | 
			
		||||
@ -72,42 +72,44 @@ type ListenerEvent struct {
 | 
			
		||||
 | 
			
		||||
// Server is the main Oragono server.
 | 
			
		||||
type Server struct {
 | 
			
		||||
	accountRegistration   *AccountRegistration
 | 
			
		||||
	accounts              map[string]*ClientAccount
 | 
			
		||||
	authenticationEnabled bool
 | 
			
		||||
	channels              ChannelNameMap
 | 
			
		||||
	checkIdent            bool
 | 
			
		||||
	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
 | 
			
		||||
	dlines                *DLineManager
 | 
			
		||||
	idle                  chan *Client
 | 
			
		||||
	isupport              *ISupportList
 | 
			
		||||
	klines                *KLineManager
 | 
			
		||||
	limits                Limits
 | 
			
		||||
	listenerEventActMutex sync.Mutex
 | 
			
		||||
	listeners             map[string]ListenerInterface
 | 
			
		||||
	listenerUpdateMutex   sync.Mutex
 | 
			
		||||
	monitoring            map[string][]Client
 | 
			
		||||
	motdLines             []string
 | 
			
		||||
	name                  string
 | 
			
		||||
	nameCasefolded        string
 | 
			
		||||
	networkName           string
 | 
			
		||||
	newConns              chan clientConn
 | 
			
		||||
	operators             map[string]Oper
 | 
			
		||||
	operclasses           map[string]OperClass
 | 
			
		||||
	password              []byte
 | 
			
		||||
	passwords             *PasswordManager
 | 
			
		||||
	rehashMutex           sync.Mutex
 | 
			
		||||
	rehashSignal          chan os.Signal
 | 
			
		||||
	restAPI               *RestAPIConfig
 | 
			
		||||
	signals               chan os.Signal
 | 
			
		||||
	store                 *buntdb.DB
 | 
			
		||||
	whoWas                *WhoWasList
 | 
			
		||||
	accountRegistration     *AccountRegistration
 | 
			
		||||
	accounts                map[string]*ClientAccount
 | 
			
		||||
	authenticationEnabled   bool
 | 
			
		||||
	channels                ChannelNameMap
 | 
			
		||||
	checkIdent              bool
 | 
			
		||||
	clients                 *ClientLookupSet
 | 
			
		||||
	commands                chan Command
 | 
			
		||||
	configFilename          string
 | 
			
		||||
	connectionThrottle      *ConnectionThrottle
 | 
			
		||||
	connectionThrottleMutex sync.Mutex // used when affecting the connection limiter, to make sure rehashing doesn't make things go out-of-whack
 | 
			
		||||
	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
 | 
			
		||||
	dlines                  *DLineManager
 | 
			
		||||
	idle                    chan *Client
 | 
			
		||||
	isupport                *ISupportList
 | 
			
		||||
	klines                  *KLineManager
 | 
			
		||||
	limits                  Limits
 | 
			
		||||
	listenerEventActMutex   sync.Mutex
 | 
			
		||||
	listeners               map[string]ListenerInterface
 | 
			
		||||
	listenerUpdateMutex     sync.Mutex
 | 
			
		||||
	monitoring              map[string][]Client
 | 
			
		||||
	motdLines               []string
 | 
			
		||||
	name                    string
 | 
			
		||||
	nameCasefolded          string
 | 
			
		||||
	networkName             string
 | 
			
		||||
	newConns                chan clientConn
 | 
			
		||||
	operators               map[string]Oper
 | 
			
		||||
	operclasses             map[string]OperClass
 | 
			
		||||
	password                []byte
 | 
			
		||||
	passwords               *PasswordManager
 | 
			
		||||
	rehashMutex             sync.Mutex
 | 
			
		||||
	rehashSignal            chan os.Signal
 | 
			
		||||
	restAPI                 *RestAPIConfig
 | 
			
		||||
	signals                 chan os.Signal
 | 
			
		||||
	store                   *buntdb.DB
 | 
			
		||||
	whoWas                  *WhoWasList
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
@ -157,6 +159,10 @@ func NewServer(configFilename string, config *Config) *Server {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal("Error loading connection limits:", err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	connectionThrottle, err := NewConnectionThrottle(config.Server.ConnectionThrottle)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal("Error loading connection throttler:", err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	server := &Server{
 | 
			
		||||
		accounts:              make(map[string]*ClientAccount),
 | 
			
		||||
@ -166,6 +172,7 @@ func NewServer(configFilename string, config *Config) *Server {
 | 
			
		||||
		commands:              make(chan Command),
 | 
			
		||||
		configFilename:        configFilename,
 | 
			
		||||
		connectionLimits:      connectionLimits,
 | 
			
		||||
		connectionThrottle:    connectionThrottle,
 | 
			
		||||
		ctime:                 time.Now(),
 | 
			
		||||
		currentOpers:          make(map[*Client]bool),
 | 
			
		||||
		idle:                  make(chan *Client),
 | 
			
		||||
@ -403,6 +410,27 @@ func (server *Server) Run() {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// check connection throttle
 | 
			
		||||
				server.connectionThrottleMutex.Lock()
 | 
			
		||||
				err = server.connectionThrottle.AddClient(ipaddr)
 | 
			
		||||
				server.connectionThrottleMutex.Unlock()
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					// too many connections too quickly from client, tell them and close the connection
 | 
			
		||||
					length := &IPRestrictTime{
 | 
			
		||||
						Duration: server.connectionThrottle.BanDuration,
 | 
			
		||||
						Expires:  time.Now().Add(server.connectionThrottle.BanDuration),
 | 
			
		||||
					}
 | 
			
		||||
					server.dlines.AddIP(ipaddr, length, server.connectionThrottle.BanMessage, "Exceeded automated connection throttle")
 | 
			
		||||
 | 
			
		||||
					// reset ban on connectionThrottle
 | 
			
		||||
					server.connectionThrottle.ResetFor(ipaddr)
 | 
			
		||||
 | 
			
		||||
					// 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(server.connectionThrottle.BanMessageBytes))
 | 
			
		||||
					conn.Conn.Close()
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				go NewClient(server, conn.Conn, conn.IsTLS)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
@ -1066,23 +1094,29 @@ func (server *Server) rehash() error {
 | 
			
		||||
	config, err := LoadConfig(server.configFilename)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("Error rehashing config file: %s", err.Error())
 | 
			
		||||
		return fmt.Errorf("Error rehashing config file config: %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())
 | 
			
		||||
		return fmt.Errorf("Error rehashing config file connection-limits: %s", err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// confirm connectionThrottler is fine
 | 
			
		||||
	connectionThrottle, err := NewConnectionThrottle(config.Server.ConnectionThrottle)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("Error rehashing config file connection-throttle: %s", err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// confirm operator stuff all exists and is fine
 | 
			
		||||
	operclasses, err := config.OperatorClasses()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("Error rehashing config file: %s", err.Error())
 | 
			
		||||
		return fmt.Errorf("Error rehashing config file operclasses: %s", err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	opers, err := config.Operators(operclasses)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("Error rehashing config file: %s", err.Error())
 | 
			
		||||
		return fmt.Errorf("Error rehashing config file opers: %s", err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	for client := range server.currentOpers {
 | 
			
		||||
		_, exists := opers[client.operName]
 | 
			
		||||
@ -1094,6 +1128,8 @@ func (server *Server) rehash() error {
 | 
			
		||||
	// apply new connectionlimits
 | 
			
		||||
	server.connectionLimitsMutex.Lock()
 | 
			
		||||
	server.connectionLimits = connectionLimits
 | 
			
		||||
	server.connectionThrottleMutex.Lock()
 | 
			
		||||
	server.connectionThrottle = connectionThrottle
 | 
			
		||||
 | 
			
		||||
	server.clients.ByNickMutex.RLock()
 | 
			
		||||
	for _, client := range server.clients.ByNick {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										31
									
								
								oragono.yaml
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								oragono.yaml
									
									
									
									
									
								
							@ -51,6 +51,9 @@ server:
 | 
			
		||||
 | 
			
		||||
    # maximum number of connections per subnet
 | 
			
		||||
    connection-limits:
 | 
			
		||||
        # whether to throttle limits or not
 | 
			
		||||
        enabled: true
 | 
			
		||||
 | 
			
		||||
        # how wide the cidr should be for IPv4 
 | 
			
		||||
        cidr-len-ipv4: 24
 | 
			
		||||
 | 
			
		||||
@ -66,6 +69,34 @@ server:
 | 
			
		||||
            - "127.0.0.1/8"
 | 
			
		||||
            - "::1/128"
 | 
			
		||||
 | 
			
		||||
    # automated connection throttling
 | 
			
		||||
    connection-throttling:
 | 
			
		||||
        # whether to throttle connections or not
 | 
			
		||||
        enabled: true
 | 
			
		||||
 | 
			
		||||
        # how wide the cidr should be for IPv4 
 | 
			
		||||
        cidr-len-ipv4: 32
 | 
			
		||||
 | 
			
		||||
        # how wide the cidr should be for IPv6
 | 
			
		||||
        cidr-len-ipv6: 128
 | 
			
		||||
 | 
			
		||||
        # how long to keep track of connections for
 | 
			
		||||
        duration: 10m
 | 
			
		||||
 | 
			
		||||
        # maximum number of connections, per subnet, within the given duration
 | 
			
		||||
        max-connections: 12
 | 
			
		||||
 | 
			
		||||
        # how long to ban offenders for, and the message to use
 | 
			
		||||
        # after banning them, the number of connections is reset (which lets you use UNDLINE to unban people)
 | 
			
		||||
        ban-duration: 10m
 | 
			
		||||
        ban-message: You have attempted to connect too many times within a short duration. Wait a while, and you will be able to connect.
 | 
			
		||||
 | 
			
		||||
        # IPs/networks which are exempted from connection limits
 | 
			
		||||
        exempted:
 | 
			
		||||
            - "127.0.0.1"
 | 
			
		||||
            - "127.0.0.1/8"
 | 
			
		||||
            - "::1/128"
 | 
			
		||||
 | 
			
		||||
# account/channel registration
 | 
			
		||||
registration:
 | 
			
		||||
    # account registration
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user