mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-10 22:19:31 +01:00
Initial DLINE changes
This commit is contained in:
parent
6beaeff9c7
commit
8c797d0f76
@ -10,6 +10,7 @@ New release of Oragono!
|
|||||||
### Security
|
### Security
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
* Added ability to `DLINE` IP addresses ad networks, to allow for fast blocking.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@ -76,6 +76,11 @@ var Commands = map[string]Command{
|
|||||||
handler: debugHandler,
|
handler: debugHandler,
|
||||||
minParams: 1,
|
minParams: 1,
|
||||||
},
|
},
|
||||||
|
"DLINE": {
|
||||||
|
handler: dlineHandler,
|
||||||
|
minParams: 1,
|
||||||
|
oper: true,
|
||||||
|
},
|
||||||
"HELP": {
|
"HELP": {
|
||||||
handler: helpHandler,
|
handler: helpHandler,
|
||||||
minParams: 0,
|
minParams: 0,
|
||||||
@ -200,6 +205,11 @@ var Commands = map[string]Command{
|
|||||||
handler: topicHandler,
|
handler: topicHandler,
|
||||||
minParams: 1,
|
minParams: 1,
|
||||||
},
|
},
|
||||||
|
"UNDLINE": {
|
||||||
|
handler: undlineHandler,
|
||||||
|
minParams: 1,
|
||||||
|
oper: true,
|
||||||
|
},
|
||||||
"USER": {
|
"USER": {
|
||||||
handler: userHandler,
|
handler: userHandler,
|
||||||
usablePreReg: true,
|
usablePreReg: true,
|
||||||
|
151
irc/dline.go
Normal file
151
irc/dline.go
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
// Copyright (c) 2016- Daniel Oaks <daniel@danieloaks.net>
|
||||||
|
// released under the MIT license
|
||||||
|
|
||||||
|
package irc
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// IPRestrictTime contains the expiration info about the given IP.
|
||||||
|
type IPRestrictTime struct {
|
||||||
|
// Expires is when this block expires.
|
||||||
|
Expires time.Time
|
||||||
|
// Length is how long this block lasts for.
|
||||||
|
Length time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExpired returns true if the time has expired.
|
||||||
|
func (iptime *IPRestrictTime) IsExpired() bool {
|
||||||
|
return iptime.Expires.Before(time.Now())
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPBanInfo holds info about an IP/net ban.
|
||||||
|
type IPBanInfo struct {
|
||||||
|
// Reason is the ban reason.
|
||||||
|
Reason string
|
||||||
|
// OperReason is an oper ban reason.
|
||||||
|
OperReason string
|
||||||
|
// Time holds details about the duration, if it exists.
|
||||||
|
Time *IPRestrictTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// dLineAddr contains the address itself and expiration time for a given network.
|
||||||
|
type dLineAddr struct {
|
||||||
|
// Address is the address that is blocked.
|
||||||
|
Address net.IP
|
||||||
|
// Info contains information on the ban.
|
||||||
|
Info IPBanInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// dLineNet contains the net itself and expiration time for a given network.
|
||||||
|
type dLineNet struct {
|
||||||
|
// Network is the network that is blocked.
|
||||||
|
Network net.IPNet
|
||||||
|
// Info contains information on the ban.
|
||||||
|
Info IPBanInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// DLineManager manages and dlines.
|
||||||
|
type DLineManager struct {
|
||||||
|
// addresses that are dlined
|
||||||
|
addresses map[string]*dLineAddr
|
||||||
|
// networks that are dlined
|
||||||
|
networks map[string]*dLineNet
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDLineManager returns a new DLineManager.
|
||||||
|
func NewDLineManager() *DLineManager {
|
||||||
|
dm := DLineManager{
|
||||||
|
addresses: make(map[string]*dLineAddr),
|
||||||
|
networks: make(map[string]*dLineNet),
|
||||||
|
}
|
||||||
|
return &dm
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddNetwork adds a network to the blocked list.
|
||||||
|
func (dm *DLineManager) AddNetwork(network net.IPNet, length *IPRestrictTime) {
|
||||||
|
netString := network.String()
|
||||||
|
dln := dLineNet{
|
||||||
|
Network: network,
|
||||||
|
Info: IPBanInfo{
|
||||||
|
Time: length,
|
||||||
|
Reason: "",
|
||||||
|
OperReason: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
dm.networks[netString] = &dln
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveNetwork removes a network from the blocked list.
|
||||||
|
func (dm *DLineManager) RemoveNetwork(network net.IPNet) {
|
||||||
|
netString := network.String()
|
||||||
|
delete(dm.networks, netString)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddIP adds an IP address to the blocked list.
|
||||||
|
func (dm *DLineManager) AddIP(addr net.IP, length *IPRestrictTime) {
|
||||||
|
addrString := addr.String()
|
||||||
|
dla := dLineAddr{
|
||||||
|
Address: addr,
|
||||||
|
Info: IPBanInfo{
|
||||||
|
Time: length,
|
||||||
|
Reason: "",
|
||||||
|
OperReason: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
dm.addresses[addrString] = &dla
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveIP removes an IP from the blocked list.
|
||||||
|
func (dm *DLineManager) RemoveIP(addr net.IP) {
|
||||||
|
addrString := addr.String()
|
||||||
|
delete(dm.addresses, addrString)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckIP returns whether or not an IP address was banned, and how long it is banned for.
|
||||||
|
func (dm *DLineManager) CheckIP(addr net.IP) (isBanned bool, info *IPBanInfo) {
|
||||||
|
// check IP addr
|
||||||
|
addrString := addr.String()
|
||||||
|
|
||||||
|
addrInfo := dm.addresses[addrString]
|
||||||
|
if addrInfo != nil {
|
||||||
|
if addrInfo.Info.Time != nil {
|
||||||
|
if addrInfo.Info.Time.IsExpired() {
|
||||||
|
// ban on IP has expired, remove it from our blocked list
|
||||||
|
dm.RemoveIP(addr)
|
||||||
|
} else {
|
||||||
|
return true, &addrInfo.Info
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check networks
|
||||||
|
var netsToRemove []net.IPNet
|
||||||
|
|
||||||
|
for _, netInfo := range dm.networks {
|
||||||
|
if !netInfo.Network.Contains(addr) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if netInfo.Info.Time != nil {
|
||||||
|
if netInfo.Info.Time.IsExpired() {
|
||||||
|
// ban on network has expired, remove it from our blocked list
|
||||||
|
netsToRemove = append(netsToRemove, netInfo.Network)
|
||||||
|
} else {
|
||||||
|
return true, &addrInfo.Info
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove expired networks
|
||||||
|
for _, expiredNet := range netsToRemove {
|
||||||
|
dm.RemoveNetwork(expiredNet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// no matches!
|
||||||
|
return false, nil
|
||||||
|
}
|
38
irc/help.go
38
irc/help.go
@ -36,7 +36,8 @@ Oragono supports the following channel modes:
|
|||||||
|
|
||||||
+i | Invite-only mode, only invited clients can join the channel.
|
+i | Invite-only mode, only invited clients can join the channel.
|
||||||
+m | Moderated mode, only privileged clients can talk on the channel.
|
+m | Moderated mode, only privileged clients can talk on the channel.
|
||||||
+n | No-outside-messages mode, only users that are on the channel can send the channel messages.
|
+n | No-outside-messages mode, only users that are on the channel can send
|
||||||
|
| messages to it.
|
||||||
+t | Only channel opers can modify the topic.
|
+t | Only channel opers can modify the topic.
|
||||||
+s | Secret mode, channel won't show up in /LIST or whois replies.
|
+s | Secret mode, channel won't show up in /LIST or whois replies.
|
||||||
|
|
||||||
@ -95,6 +96,26 @@ Prints debug information about the IRCd. <option> can be one of:
|
|||||||
* STARTCPUPROFILE: Starts the CPU profiler.
|
* STARTCPUPROFILE: Starts the CPU profiler.
|
||||||
* STOPCPUPROFILE: Stops the CPU profiler.
|
* STOPCPUPROFILE: Stops the CPU profiler.
|
||||||
* PROFILEHEAP: Writes out the CPU profiler info.`,
|
* PROFILEHEAP: Writes out the CPU profiler info.`,
|
||||||
|
},
|
||||||
|
"dline": {
|
||||||
|
oper: true,
|
||||||
|
text: `DLINE [duration] <ip>/<net> [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
|
||||||
|
everyone else will see a standard message. The oper reason is shown to
|
||||||
|
operators getting info about the DLINEs that exist.
|
||||||
|
|
||||||
|
Bans are saved across subsequent launches of the server.
|
||||||
|
|
||||||
|
[duration] can be of the following forms:
|
||||||
|
10h 8m 13s
|
||||||
|
|
||||||
|
<net> is specified in typical CIDR notation. For example:
|
||||||
|
127.0.0.1/8
|
||||||
|
8.8.8.8/24
|
||||||
|
|
||||||
|
[reason] and [oper reason], if they exist, are separated by a vertical bar (|).`,
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
text: `HELP <argument>
|
text: `HELP <argument>
|
||||||
@ -250,7 +271,7 @@ Indicates that you're leaving the server, and shows everyone the given reason.`,
|
|||||||
REG VERIFY <accountname> <auth_code>
|
REG VERIFY <accountname> <auth_code>
|
||||||
|
|
||||||
Used in account registration. See the relevant specs for more info:
|
Used in account registration. See the relevant specs for more info:
|
||||||
https://github.com/DanielOaks/ircv3-specifications/blob/register-and-verify/extensions/reg-core-3.3.md`,
|
http://oragono.io/specs.html`,
|
||||||
},
|
},
|
||||||
"rehash": {
|
"rehash": {
|
||||||
oper: true,
|
oper: true,
|
||||||
@ -268,6 +289,16 @@ Shows the time of the current, or the given, server.`,
|
|||||||
|
|
||||||
If [topic] is given, sets the topic in the channel to that. If [topic] is not
|
If [topic] is given, sets the topic in the channel to that. If [topic] is not
|
||||||
given, views the current topic on the channel.`,
|
given, views the current topic on the channel.`,
|
||||||
|
},
|
||||||
|
"undline": {
|
||||||
|
oper: true,
|
||||||
|
text: `UNDLINE <ip>/<net>
|
||||||
|
|
||||||
|
Removes an existing ban on an IP address or a network.
|
||||||
|
|
||||||
|
<net> is specified in typical CIDR notation. For example:
|
||||||
|
127.0.0.1/8
|
||||||
|
8.8.8.8/24`,
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
text: `USER <username> 0 * <realname>
|
text: `USER <username> 0 * <realname>
|
||||||
@ -316,8 +347,7 @@ Returns historical information on the last user with the given nickname.`,
|
|||||||
|
|
||||||
Oragono supports an experimental unicode casemapping designed for extended
|
Oragono supports an experimental unicode casemapping designed for extended
|
||||||
Unicode support. This casemapping is based off RFC 7700 and the draft rfc7700
|
Unicode support. This casemapping is based off RFC 7700 and the draft rfc7700
|
||||||
casemapping spec here:
|
casemapping spec here: http://oragono.io/specs.html`,
|
||||||
https://github.com/DanielOaks/ircv3-specifications/blob/master%2Brfc7700/documentation/rfc7700.md`,
|
|
||||||
},
|
},
|
||||||
"prefix": {
|
"prefix": {
|
||||||
text: `RPL_ISUPPORT PREFIX
|
text: `RPL_ISUPPORT PREFIX
|
||||||
|
@ -29,6 +29,9 @@ var (
|
|||||||
// cached because this may be used lots
|
// 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 IP or network")
|
||||||
tooManyClientsBytes, _ = tooManyClientsMsg.Line()
|
tooManyClientsBytes, _ = tooManyClientsMsg.Line()
|
||||||
|
|
||||||
|
bannedFromServerMsg = ircmsg.MakeMessage(nil, "", "ERROR", "You are banned from this server (%s)")
|
||||||
|
bannedFromServerBytes, _ = bannedFromServerMsg.Line()
|
||||||
)
|
)
|
||||||
|
|
||||||
// Limits holds the maximum limits for various things such as topic lengths
|
// Limits holds the maximum limits for various things such as topic lengths
|
||||||
@ -78,6 +81,7 @@ type Server struct {
|
|||||||
connectionLimitsMutex sync.Mutex // used when affecting the connection limiter, to make sure rehashing doesn't make things go out-of-whack
|
connectionLimitsMutex sync.Mutex // used when affecting the connection limiter, to make sure rehashing doesn't make things go out-of-whack
|
||||||
ctime time.Time
|
ctime time.Time
|
||||||
currentOpers map[*Client]bool
|
currentOpers map[*Client]bool
|
||||||
|
dlines *DLineManager
|
||||||
idle chan *Client
|
idle chan *Client
|
||||||
isupport *ISupportList
|
isupport *ISupportList
|
||||||
limits Limits
|
limits Limits
|
||||||
@ -190,6 +194,9 @@ func NewServer(configFilename string, config *Config) *Server {
|
|||||||
}
|
}
|
||||||
server.store = *db
|
server.store = *db
|
||||||
|
|
||||||
|
// load dlines
|
||||||
|
server.loadDLines()
|
||||||
|
|
||||||
// load password manager
|
// load password manager
|
||||||
err = server.store.View(func(tx *buntdb.Tx) error {
|
err = server.store.View(func(tx *buntdb.Tx) error {
|
||||||
saltString, err := tx.Get(keySalt)
|
saltString, err := tx.Get(keySalt)
|
||||||
@ -342,18 +349,33 @@ func (server *Server) Run() {
|
|||||||
// check connection limits
|
// check connection limits
|
||||||
ipaddr := net.ParseIP(IPString(conn.Conn.RemoteAddr()))
|
ipaddr := net.ParseIP(IPString(conn.Conn.RemoteAddr()))
|
||||||
if ipaddr != nil {
|
if ipaddr != nil {
|
||||||
|
// check DLINEs
|
||||||
|
isBanned, info := server.dlines.CheckIP(ipaddr)
|
||||||
|
if isBanned {
|
||||||
|
banMessage := fmt.Sprintf(bannedFromServerBytes, info.Reason)
|
||||||
|
if info.Time != nil {
|
||||||
|
banMessage += fmt.Sprintf(" [%s]", info.Time.Length.String())
|
||||||
|
}
|
||||||
|
conn.Conn.Write([]byte(banMessage))
|
||||||
|
conn.Conn.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// check connection limits
|
||||||
server.connectionLimitsMutex.Lock()
|
server.connectionLimitsMutex.Lock()
|
||||||
err := server.connectionLimits.AddClient(ipaddr, false)
|
err := server.connectionLimits.AddClient(ipaddr, false)
|
||||||
server.connectionLimitsMutex.Unlock()
|
server.connectionLimitsMutex.Unlock()
|
||||||
if err == nil {
|
if err != nil {
|
||||||
go NewClient(server, conn.Conn, conn.IsTLS)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// too many connections from one client, tell the client and close the connection
|
// too many connections from one client, tell the client and close the connection
|
||||||
// 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
|
// 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(tooManyClientsBytes))
|
conn.Conn.Write([]byte(tooManyClientsBytes))
|
||||||
conn.Conn.Close()
|
conn.Conn.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
go NewClient(server, conn.Conn, conn.IsTLS)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
case client := <-server.idle:
|
case client := <-server.idle:
|
||||||
client.Idle()
|
client.Idle()
|
||||||
|
Loading…
Reference in New Issue
Block a user