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
|
||||
|
||||
### Added
|
||||
* Added ability to `DLINE` IP addresses ad networks, to allow for fast blocking.
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -76,6 +76,11 @@ var Commands = map[string]Command{
|
||||
handler: debugHandler,
|
||||
minParams: 1,
|
||||
},
|
||||
"DLINE": {
|
||||
handler: dlineHandler,
|
||||
minParams: 1,
|
||||
oper: true,
|
||||
},
|
||||
"HELP": {
|
||||
handler: helpHandler,
|
||||
minParams: 0,
|
||||
@ -200,6 +205,11 @@ var Commands = map[string]Command{
|
||||
handler: topicHandler,
|
||||
minParams: 1,
|
||||
},
|
||||
"UNDLINE": {
|
||||
handler: undlineHandler,
|
||||
minParams: 1,
|
||||
oper: true,
|
||||
},
|
||||
"USER": {
|
||||
handler: userHandler,
|
||||
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.
|
||||
+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.
|
||||
+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.
|
||||
* STOPCPUPROFILE: Stops the CPU profiler.
|
||||
* 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": {
|
||||
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>
|
||||
|
||||
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": {
|
||||
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
|
||||
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": {
|
||||
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
|
||||
Unicode support. This casemapping is based off RFC 7700 and the draft rfc7700
|
||||
casemapping spec here:
|
||||
https://github.com/DanielOaks/ircv3-specifications/blob/master%2Brfc7700/documentation/rfc7700.md`,
|
||||
casemapping spec here: http://oragono.io/specs.html`,
|
||||
},
|
||||
"prefix": {
|
||||
text: `RPL_ISUPPORT PREFIX
|
||||
|
@ -29,6 +29,9 @@ var (
|
||||
// cached because this may be used lots
|
||||
tooManyClientsMsg = ircmsg.MakeMessage(nil, "", "ERROR", "Too many clients from your IP or network")
|
||||
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
|
||||
@ -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
|
||||
ctime time.Time
|
||||
currentOpers map[*Client]bool
|
||||
dlines *DLineManager
|
||||
idle chan *Client
|
||||
isupport *ISupportList
|
||||
limits Limits
|
||||
@ -190,6 +194,9 @@ func NewServer(configFilename string, config *Config) *Server {
|
||||
}
|
||||
server.store = *db
|
||||
|
||||
// load dlines
|
||||
server.loadDLines()
|
||||
|
||||
// load password manager
|
||||
err = server.store.View(func(tx *buntdb.Tx) error {
|
||||
saltString, err := tx.Get(keySalt)
|
||||
@ -342,18 +349,33 @@ func (server *Server) Run() {
|
||||
// check connection limits
|
||||
ipaddr := net.ParseIP(IPString(conn.Conn.RemoteAddr()))
|
||||
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()
|
||||
err := server.connectionLimits.AddClient(ipaddr, false)
|
||||
server.connectionLimitsMutex.Unlock()
|
||||
if err == nil {
|
||||
go NewClient(server, conn.Conn, conn.IsTLS)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
// 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
|
||||
conn.Conn.Write([]byte(tooManyClientsBytes))
|
||||
conn.Conn.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
go NewClient(server, conn.Conn, conn.IsTLS)
|
||||
continue
|
||||
}
|
||||
|
||||
case client := <-server.idle:
|
||||
client.Idle()
|
||||
|
Loading…
Reference in New Issue
Block a user