diff --git a/CHANGELOG.md b/CHANGELOG.md index 0eec877a..f3f65602 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ New release of Oragono! ### Removed ### Fixed +* Fixed crash when using STATUSMSG-like messaging. +* Fixed crash with gIRC-Go ircmsg library we depend on. ## [0.4.0] - 2016-11-03 diff --git a/DEVELOPING.md b/DEVELOPING.md new file mode 100644 index 00000000..2fabf9f6 --- /dev/null +++ b/DEVELOPING.md @@ -0,0 +1,10 @@ +# Developing Oragono + +Most development happens on the `develop` branch, which is occasionally rebased + merged into `master` when it's not incredibly broken. + +The intent is to keep `master` relatively stable. + + +## Fuzzing + +Fuzzing can be useful. We don't have testing done inside the IRCd itself, but this fuzzer I've written works alright and has helped shake out various bugs: [irc_fuzz.py](https://gist.github.com/DanielOaks/63ae611039cdf591dfa4) diff --git a/irc/client.go b/irc/client.go index c0d019f7..7f1a5386 100644 --- a/irc/client.go +++ b/irc/client.go @@ -20,7 +20,7 @@ import ( const ( IDLE_TIMEOUT = time.Minute + time.Second*30 // how long before a client is considered idle QUIT_TIMEOUT = time.Minute // how long after idle before a client is kicked - IdentTimeoutSeconds = 8 + IdentTimeoutSeconds = 5 ) var ( @@ -157,7 +157,11 @@ func (client *Client) run() { cmd, exists := Commands[msg.Command] if !exists { - client.Send(nil, client.server.name, ERR_UNKNOWNCOMMAND, client.nick, msg.Command, "Unknown command") + if len(msg.Command) > 0 { + client.Send(nil, client.server.name, ERR_UNKNOWNCOMMAND, client.nick, msg.Command, "Unknown command") + } else { + client.Send(nil, client.server.name, ERR_UNKNOWNCOMMAND, client.nick, "lastcmd", "No command given") + } continue } @@ -463,6 +467,8 @@ func (client *Client) Send(tags *map[string]ircmsg.TagValue, prefix string, comm // try not to fail quietly - especially useful when running tests, as a note to dig deeper // log.Println("Error assembling message:") // spew.Dump(message) + // debug.PrintStack() + message = ircmsg.MakeMessage(nil, client.server.name, ERR_UNKNOWNERROR, "*", "Error assembling message for sending") line, _ := message.Line() client.socket.Write(line) diff --git a/irc/modes.go b/irc/modes.go index 246e0c84..88d7bc09 100644 --- a/irc/modes.go +++ b/irc/modes.go @@ -207,7 +207,7 @@ var ( func SplitChannelMembershipPrefixes(target string) (prefixes string, name string) { name = target for { - if len(name) == 0 || strings.Contains("~&@%+", string(name[0])) { + if len(name) > 0 && strings.Contains("~&@%+", string(name[0])) { prefixes += string(name[0]) name = name[1:] } else { @@ -257,7 +257,9 @@ func umodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { target := server.clients.Get(nickname) if err != nil || target == nil { - client.Send(nil, server.name, ERR_NOSUCHNICK, client.nick, msg.Params[0], "No such nick") + if len(msg.Params[0]) > 0 { + client.Send(nil, server.name, ERR_NOSUCHNICK, client.nick, msg.Params[0], "No such nick") + } return false } diff --git a/irc/server.go b/irc/server.go index 644395a1..c0f544c8 100644 --- a/irc/server.go +++ b/irc/server.go @@ -354,7 +354,7 @@ func (server *Server) Run() { if isBanned { banMessage := fmt.Sprintf(bannedFromServerBytes, info.Reason) if info.Time != nil { - banMessage += fmt.Sprintf(" [%s]", info.Time.Length.String()) + banMessage += fmt.Sprintf(" [%s]", info.Time.Duration.String()) } conn.Conn.Write([]byte(banMessage)) conn.Conn.Close() @@ -698,7 +698,9 @@ func joinHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { for i, name := range channels { casefoldedName, err := CasefoldChannel(name) if err != nil { - client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, name, "No such channel") + if len(name) > 0 { + client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, name, "No such channel") + } continue } @@ -734,7 +736,9 @@ func partHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { channel := server.channels.Get(casefoldedChannelName) if err != nil || channel == nil { - client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, "No such channel") + if len(chname) > 0 { + client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, "No such channel") + } continue } @@ -748,7 +752,9 @@ func topicHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { name, err := CasefoldChannel(msg.Params[0]) channel := server.channels.Get(name) if err != nil || channel == nil { - client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, msg.Params[0], "No such channel") + if len(msg.Params[0]) > 0 { + client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, msg.Params[0], "No such channel") + } return false } @@ -774,6 +780,11 @@ func privmsgHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool prefixes, targetString := SplitChannelMembershipPrefixes(targetString) lowestPrefix := GetLowestChannelModePrefix(prefixes) + // eh, no need to notify them + if len(targetString) < 1 { + continue + } + target, err := CasefoldChannel(targetString) if err == nil { channel := server.channels.Get(target) @@ -786,7 +797,9 @@ func privmsgHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool target, err = CasefoldName(targetString) user := server.clients.Get(target) if err != nil || user == nil { - client.Send(nil, server.name, ERR_NOSUCHNICK, target, "No such nick") + if len(target) > 0 { + client.Send(nil, server.name, ERR_NOSUCHNICK, target, "No such nick") + } continue } if !user.capabilities[MessageTags] { @@ -832,6 +845,11 @@ func whoisHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { masksString = msg.Params[0] } + if len(strings.TrimSpace(masksString)) < 1 { + client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, msg.Command, "No masks given") + return false + } + if client.flags[Operator] { masks := strings.Split(masksString, ",") for _, mask := range masks { @@ -964,7 +982,6 @@ func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { err = ComparePassword(hash, password) if (hash == nil) || (err != nil) { - fmt.Println("2", hash) client.Send(nil, server.name, ERR_PASSWDMISMATCH, client.nick, "Password incorrect") return true } @@ -1392,7 +1409,9 @@ func listHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { casefoldedChname, err := CasefoldChannel(chname) channel := server.channels.Get(casefoldedChname) if err != nil || channel == nil || (!client.flags[Operator] && channel.flags[Secret]) { - client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, "No such channel") + if len(chname) > 0 { + client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, "No such channel") + } continue } client.RplList(channel) @@ -1445,7 +1464,9 @@ func namesHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { casefoldedChname, err := CasefoldChannel(chname) channel := server.channels.Get(casefoldedChname) if err != nil || channel == nil { - client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, "No such channel") + if len(chname) > 0 { + client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, "No such channel") + } continue } channel.Names(client) @@ -1545,13 +1566,17 @@ func whowasHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { for _, nickname := range nicknames { results := server.whoWas.Find(nickname, count) if len(results) == 0 { - client.Send(nil, server.name, ERR_WASNOSUCHNICK, client.nick, nickname, "There was no such nickname") + if len(nickname) > 0 { + client.Send(nil, server.name, ERR_WASNOSUCHNICK, client.nick, nickname, "There was no such nickname") + } } else { for _, whoWas := range results { client.Send(nil, server.name, RPL_WHOWASUSER, client.nick, whoWas.nickname, whoWas.username, whoWas.hostname, "*", whoWas.realname) } } - client.Send(nil, server.name, RPL_ENDOFWHOWAS, client.nick, nickname, "End of WHOWAS") + if len(nickname) > 0 { + client.Send(nil, server.name, RPL_ENDOFWHOWAS, client.nick, nickname, "End of WHOWAS") + } } return false }