diff --git a/irc/client.go b/irc/client.go index 8d4f7827..4f4f4cb0 100644 --- a/irc/client.go +++ b/irc/client.go @@ -111,6 +111,8 @@ type Session struct { capState caps.State capVersion caps.Version + registrationMessages int + resumeID string resumeDetails *ResumeDetails zncPlaybackTimes *zncPlaybackTimes @@ -396,6 +398,15 @@ func (client *Client) run(session *Session) { } } + // DoS hardening, #505 + if !client.registered { + session.registrationMessages++ + if client.server.Config().Limits.RegistrationMessages < session.registrationMessages { + client.Send(nil, client.server.name, ERR_UNKNOWNERROR, "*", client.t("You have sent too many registration messages")) + break + } + } + msg, err := ircmsg.ParseLineStrict(line, true, maxlenRest) if err == ircmsg.ErrorLineIsEmpty { continue diff --git a/irc/config.go b/irc/config.go index 965aa9d5..5750276f 100644 --- a/irc/config.go +++ b/irc/config.go @@ -214,16 +214,17 @@ type LineLenLimits struct { // Various server-enforced limits on data size. type Limits struct { - AwayLen int `yaml:"awaylen"` - ChanListModes int `yaml:"chan-list-modes"` - ChannelLen int `yaml:"channellen"` - IdentLen int `yaml:"identlen"` - KickLen int `yaml:"kicklen"` - LineLen LineLenLimits `yaml:"linelen"` - MonitorEntries int `yaml:"monitor-entries"` - NickLen int `yaml:"nicklen"` - TopicLen int `yaml:"topiclen"` - WhowasEntries int `yaml:"whowas-entries"` + AwayLen int `yaml:"awaylen"` + ChanListModes int `yaml:"chan-list-modes"` + ChannelLen int `yaml:"channellen"` + IdentLen int `yaml:"identlen"` + KickLen int `yaml:"kicklen"` + LineLen LineLenLimits `yaml:"linelen"` + MonitorEntries int `yaml:"monitor-entries"` + NickLen int `yaml:"nicklen"` + TopicLen int `yaml:"topiclen"` + WhowasEntries int `yaml:"whowas-entries"` + RegistrationMessages int `yaml:"registration-messages"` } // STSConfig controls the STS configuration/ @@ -532,6 +533,9 @@ 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, ErrLimitsAreInsane } + if config.Limits.RegistrationMessages == 0 { + config.Limits.RegistrationMessages = 1024 + } if config.Server.STS.Enabled { config.Server.STS.Duration, err = custime.ParseDuration(config.Server.STS.DurationString) if err != nil { diff --git a/oragono.yaml b/oragono.yaml index 9c965b23..35754dea 100644 --- a/oragono.yaml +++ b/oragono.yaml @@ -557,6 +557,10 @@ limits: # configurable length for the rest of the message: rest: 2048 + # maximum number of messages to accept during registration (prevents + # DoS / resource exhaustion attacks): + registration-messages: 1024 + # fakelag: prevents clients from spamming commands too rapidly fakelag: # whether to enforce fakelag