xline: Add ANDKILL param to kill all matching clients

This commit is contained in:
Daniel Oaks 2017-05-24 00:58:36 -06:00
parent 3101f16478
commit ebb9d629d7
5 changed files with 88 additions and 10 deletions

View File

@ -137,6 +137,11 @@ func NewClient(server *Server, conn net.Conn, isTLS bool) *Client {
return client
}
// IP returns the IP address of this client.
func (client *Client) IP() net.IP {
return net.ParseIP(IPString(client.socket.conn.RemoteAddr()))
}
//
// command goroutine
//
@ -475,7 +480,7 @@ func (client *Client) destroy() {
friends.Remove(client)
// remove from connection limits
ipaddr := net.ParseIP(IPString(client.socket.conn.RemoteAddr()))
ipaddr := client.IP()
// this check shouldn't be required but eh
if ipaddr != nil {
client.server.connectionLimitsMutex.Lock()

View File

@ -183,7 +183,7 @@ func (dm *DLineManager) CheckIP(addr net.IP) (isBanned bool, info *IPBanInfo) {
return false, nil
}
// DLINE [MYSELF] [duration] <ip>/<net> [ON <server>] [reason [| oper reason]]
// DLINE [ANDKILL] [MYSELF] [duration] <ip>/<net> [ON <server>] [reason [| oper reason]]
func dlineHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
// check oper permissions
if !client.class.Capabilities["oper:local_ban"] {
@ -193,6 +193,13 @@ func dlineHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
currentArg := 0
// when setting a ban, if they say "ANDKILL" we should also kill all users who match it
var andKill bool
if len(msg.Params) > currentArg+1 && strings.ToLower(msg.Params[currentArg]) == "andkill" {
andKill = true
currentArg++
}
// when setting a ban that covers the oper's current connection, we require them to say
// "DLINE MYSELF" so that we're sure they really mean it.
var dlineMyself bool
@ -232,13 +239,13 @@ func dlineHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
if hostNet == nil {
hostString = hostAddr.String()
if !dlineMyself && hostAddr.Equal(net.ParseIP(IPString(client.socket.conn.RemoteAddr()))) {
if !dlineMyself && hostAddr.Equal(client.IP()) {
client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, msg.Command, "This ban matches you. To DLINE yourself, you must use the command: /DLINE MYSELF <arguments>")
return false
}
} else {
hostString = hostNet.String()
if !dlineMyself && hostNet.Contains(net.ParseIP(IPString(client.socket.conn.RemoteAddr()))) {
if !dlineMyself && hostNet.Contains(client.IP()) {
client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, msg.Command, "This ban matches you. To DLINE yourself, you must use the command: /DLINE MYSELF <arguments>")
return false
}
@ -315,7 +322,37 @@ func dlineHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
client.Notice(fmt.Sprintf("Added D-Line for %s", hostString))
}
return false
var killClient bool
if andKill {
var clientsToKill []*Client
var toKill bool
server.clients.ByNickMutex.RLock()
for _, mcl := range server.clients.ByNick {
if hostNet == nil {
toKill = hostAddr.Equal(mcl.IP())
} else {
toKill = hostNet.Contains(mcl.IP())
}
if toKill {
clientsToKill = append(clientsToKill, mcl)
}
}
server.clients.ByNickMutex.RUnlock()
for _, mcl := range clientsToKill {
mcl.Quit(fmt.Sprintf("You have been banned from this server (%s)", reason))
if mcl == client {
killClient = true
} else {
// if mcl == client, we kill them below
mcl.destroy()
}
}
}
return killClient
}
func unDLineHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {

View File

@ -145,7 +145,7 @@ Prints debug information about the IRCd. <option> can be one of:
},
"dline": {
oper: true,
text: `DLINE [MYSELF] [duration] <ip>/<net> [ON <server>] [reason [| oper reason]]
text: `DLINE [ANDKILL] [MYSELF] [duration] <ip>/<net> [ON <server>] [reason [| oper reason]]
Bans an IP address or network from connecting to the server. If the duration is
given then only for that long. The reason is shown to the user themselves, but
@ -154,6 +154,8 @@ operators getting info about the DLINEs that exist.
Bans are saved across subsequent launches of the server.
"ANDKILL" means that all matching clients are also removed from the server.
"MYSELF" is required when the DLINE matches the address the person applying it is connected
from. If "MYSELF" is not given, trying to DLINE yourself will result in an error.
@ -211,7 +213,7 @@ supplied.`,
},
"kline": {
oper: true,
text: `KLINE [MYSELF] [duration] <mask> [ON <server>] [reason [| oper reason]]
text: `KLINE [ANDKILL] [MYSELF] [duration] <mask> [ON <server>] [reason [| oper reason]]
Bans a mask from connecting to the server. If the duration is given then only for that
long. The reason is shown to the user themselves, but everyone else will see a standard
@ -219,6 +221,8 @@ message. The oper reason is shown to operators getting info about the KLINEs tha
Bans are saved across subsequent launches of the server.
"ANDKILL" means that all matching clients are also removed from the server.
"MYSELF" is required when the KLINE matches the address the person applying it is connected
from. If "MYSELF" is not given, trying to KLINE yourself will result in an error.

View File

@ -110,7 +110,7 @@ func (km *KLineManager) CheckMasks(masks ...string) (isBanned bool, info *IPBanI
return false, nil
}
// KLINE [MYSELF] [duration] <mask> [ON <server>] [reason [| oper reason]]
// KLINE [ANDKILL] [MYSELF] [duration] <mask> [ON <server>] [reason [| oper reason]]
func klineHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
// check oper permissions
if !client.class.Capabilities["oper:local_ban"] {
@ -120,6 +120,13 @@ func klineHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
currentArg := 0
// when setting a ban, if they say "ANDKILL" we should also kill all users who match it
var andKill bool
if len(msg.Params) > currentArg+1 && strings.ToLower(msg.Params[currentArg]) == "andkill" {
andKill = true
currentArg++
}
// when setting a ban that covers the oper's current connection, we require them to say
// "KLINE MYSELF" so that we're sure they really mean it.
var klineMyself bool
@ -226,7 +233,32 @@ func klineHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
client.Notice(fmt.Sprintf("Added K-Line for %s", mask))
}
return false
var killClient bool
if andKill {
var clientsToKill []*Client
server.clients.ByNickMutex.RLock()
for _, mcl := range server.clients.ByNick {
for _, clientMask := range mcl.AllNickmasks() {
if matcher.Match(clientMask) {
clientsToKill = append(clientsToKill, mcl)
}
}
}
server.clients.ByNickMutex.RUnlock()
for _, mcl := range clientsToKill {
mcl.Quit(fmt.Sprintf("You have been banned from this server (%s)", reason))
if mcl == client {
killClient = true
} else {
// if mcl == client, we kill them below
mcl.destroy()
}
}
}
return killClient
}
func unKLineHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {

View File

@ -1358,7 +1358,7 @@ func (server *Server) rehash() error {
server.clients.ByNickMutex.RLock()
for _, client := range server.clients.ByNick {
ipaddr := net.ParseIP(IPString(client.socket.conn.RemoteAddr()))
ipaddr := client.IP()
if ipaddr != nil {
server.connectionLimits.AddClient(ipaddr, true)
}