From 7c5a8f201368f822c9ad72768c85d405d51f80b4 Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Mon, 24 May 2021 00:38:47 -0400 Subject: [PATCH] make MaxLineLen configurable --- default.yaml | 5 +++++ irc/client.go | 8 ++++++-- irc/config.go | 4 ++++ irc/ircconn.go | 8 ++++++-- irc/listeners.go | 2 +- irc/server.go | 3 +++ traditional.yaml | 5 +++++ 7 files changed, 30 insertions(+), 5 deletions(-) diff --git a/default.yaml b/default.yaml index c5b74706..032403d4 100644 --- a/default.yaml +++ b/default.yaml @@ -360,6 +360,11 @@ server: # e.g., `NickServ!NickServ@localhost`. uncomment this to override: #override-services-hostname: "example.network" + # in a "closed-loop" system where you control the server and all the clients, + # you may want to increase the maximum (non-tag) length of an IRC line from + # the default value of 512. do not do this on a public server: + # max-line-len: 512 + # account options accounts: # is account authentication enabled, i.e., can users log into existing accounts? diff --git a/irc/client.go b/irc/client.go index e4669888..f432c259 100644 --- a/irc/client.go +++ b/irc/client.go @@ -31,8 +31,8 @@ import ( ) const ( - // maximum line length not including tags; don't change this for a public server - MaxLineLen = 512 + // maximum IRC line length, not including tags + DefaultMaxLineLen = 512 // IdentTimeout is how long before our ident (username) check times out. IdentTimeout = time.Second + 500*time.Millisecond @@ -61,6 +61,10 @@ const ( PingCoalesceThreshold = time.Second ) +var ( + MaxLineLen = DefaultMaxLineLen +) + // Client is an IRC client. type Client struct { account string diff --git a/irc/config.go b/irc/config.go index bbe5de16..02f562cf 100644 --- a/irc/config.go +++ b/irc/config.go @@ -590,6 +590,7 @@ type Config struct { OutputPath string `yaml:"output-path"` IPCheckScript ScriptConfig `yaml:"ip-check-script"` OverrideServicesHostname string `yaml:"override-services-hostname"` + MaxLineLen int `yaml:"max-line-len"` } Roleplay struct { @@ -1132,6 +1133,9 @@ func LoadConfig(filename string) (config *Config, err error) { if config.Limits.RegistrationMessages == 0 { config.Limits.RegistrationMessages = 1024 } + if config.Server.MaxLineLen < DefaultMaxLineLen { + config.Server.MaxLineLen = DefaultMaxLineLen + } if config.Datastore.MySQL.Enabled { if config.Limits.NickLen > mysql.MaxTargetLength || config.Limits.ChannelLen > mysql.MaxTargetLength { return nil, fmt.Errorf("to use MySQL, nick and channel length limits must be %d or lower", mysql.MaxTargetLength) diff --git a/irc/ircconn.go b/irc/ircconn.go index 29c706ec..328b65ad 100644 --- a/irc/ircconn.go +++ b/irc/ircconn.go @@ -16,7 +16,6 @@ import ( ) const ( - maxReadQBytes = ircmsg.MaxlenTagsFromClient + MaxLineLen + 1024 initialBufferSize = 1024 ) @@ -24,6 +23,11 @@ var ( crlf = []byte{'\r', '\n'} ) +// maximum total length, in bytes, of a single IRC message: +func maxReadQBytes() int { + return ircmsg.MaxlenTagsFromClient + MaxLineLen + 1024 +} + // IRCConn abstracts away the distinction between a regular // net.Conn (which includes both raw TCP and TLS) and a websocket. // it doesn't expose the net.Conn, io.Reader, or io.Writer interfaces @@ -51,7 +55,7 @@ type IRCStreamConn struct { func NewIRCStreamConn(conn *utils.WrappedConn) *IRCStreamConn { var c IRCStreamConn c.conn = conn - c.reader.Initialize(conn.Conn, initialBufferSize, maxReadQBytes) + c.reader.Initialize(conn.Conn, initialBufferSize, maxReadQBytes()) return &c } diff --git a/irc/listeners.go b/irc/listeners.go index 72f99a5f..336afed2 100644 --- a/irc/listeners.go +++ b/irc/listeners.go @@ -185,7 +185,7 @@ func (wl *WSListener) handle(w http.ResponseWriter, r *http.Request) { confirmProxyData(wConn, remoteAddr, xff, xfp, config) // avoid a DoS attack from buffering excessively large messages: - conn.SetReadLimit(maxReadQBytes) + conn.SetReadLimit(int64(maxReadQBytes())) go wl.server.RunClient(NewIRCWSConn(conn)) } diff --git a/irc/server.go b/irc/server.go index 280e7557..269fd88c 100644 --- a/irc/server.go +++ b/irc/server.go @@ -554,6 +554,7 @@ func (server *Server) applyConfig(config *Config) (err error) { server.nameCasefolded = config.Server.nameCasefolded globalCasemappingSetting = config.Server.Casemapping globalUtf8EnforcementSetting = config.Server.EnforceUtf8 + MaxLineLen = config.Server.MaxLineLen } else { // enforce configs that can't be changed after launch: if server.name != config.Server.Name { @@ -577,6 +578,8 @@ func (server *Server) applyConfig(config *Config) (err error) { return fmt.Errorf("Cannot change override-services-hostname after launching the server, rehash aborted") } else if !oldConfig.Datastore.MySQL.Enabled && config.Datastore.MySQL.Enabled { return fmt.Errorf("Cannot enable MySQL after launching the server, rehash aborted") + } else if oldConfig.Server.MaxLineLen != config.Server.MaxLineLen { + return fmt.Errorf("Cannot change max-line-len after launching the server, rehash aborted") } } diff --git a/traditional.yaml b/traditional.yaml index 1efc5af0..26f1e2da 100644 --- a/traditional.yaml +++ b/traditional.yaml @@ -332,6 +332,11 @@ server: # e.g., `NickServ!NickServ@localhost`. uncomment this to override: #override-services-hostname: "example.network" + # in a "closed-loop" system where you control the server and all the clients, + # you may want to increase the maximum (non-tag) length of an IRC line from + # the default value of 512. do not do this on a public server: + # max-line-len: 512 + # account options accounts: # is account authentication enabled, i.e., can users log into existing accounts?