Browse Source

fix #328 (implement DEFCON)

tags/v2.2.0-rc1
Shivaram Lingamneni 4 years ago
parent
commit
6ea2eb367d
11 changed files with 70 additions and 7 deletions
  1. 1
    0
      conventional.yaml
  2. 1
    0
      default.yaml
  3. 7
    2
      irc/accounts.go
  4. 2
    1
      irc/channel.go
  5. 4
    0
      irc/channelmanager.go
  6. 3
    2
      irc/client.go
  7. 4
    0
      irc/commands.go
  8. 8
    0
      irc/getters.go
  9. 15
    0
      irc/handlers.go
  10. 14
    0
      irc/help.go
  11. 11
    2
      irc/server.go

+ 1
- 0
conventional.yaml View File

@@ -553,6 +553,7 @@ oper-classes:
553 553
             - "vhosts"
554 554
             - "chanreg"
555 555
             - "history"
556
+            - "defcon"
556 557
 
557 558
 # ircd operators
558 559
 opers:

+ 1
- 0
default.yaml View File

@@ -579,6 +579,7 @@ oper-classes:
579 579
             - "vhosts"
580 580
             - "chanreg"
581 581
             - "history"
582
+            - "defcon"
582 583
 
583 584
 # ircd operators
584 585
 opers:

+ 7
- 2
irc/accounts.go View File

@@ -380,8 +380,8 @@ func (am *AccountManager) Register(client *Client, account string, callbackNames
380 380
 
381 381
 	config := am.server.Config()
382 382
 
383
-	// final "is registration allowed" check, probably redundant:
384
-	if !(config.Accounts.Registration.Enabled || callbackNamespace == "admin") {
383
+	// final "is registration allowed" check:
384
+	if !(config.Accounts.Registration.Enabled || callbackNamespace == "admin") || am.server.Defcon() <= 4 {
385 385
 		return errFeatureDisabled
386 386
 	}
387 387
 
@@ -1642,6 +1642,11 @@ func (am *AccountManager) performVHostChange(account string, munger vhostMunger)
1642 1642
 		return
1643 1643
 	}
1644 1644
 
1645
+	if am.server.Defcon() <= 3 {
1646
+		err = errFeatureDisabled
1647
+		return
1648
+	}
1649
+
1645 1650
 	am.vHostUpdateMutex.Lock()
1646 1651
 	defer am.vHostUpdateMutex.Unlock()
1647 1652
 

+ 2
- 1
irc/channel.go View File

@@ -706,7 +706,8 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
706 706
 			return errBanned
707 707
 		}
708 708
 
709
-		if channel.flags.HasMode(modes.RegisteredOnly) && details.account == "" {
709
+		if details.account == "" &&
710
+			(channel.flags.HasMode(modes.RegisteredOnly) || channel.server.Defcon() <= 3) {
710 711
 			return errRegisteredOnly
711 712
 		}
712 713
 	}

+ 4
- 0
irc/channelmanager.go View File

@@ -187,6 +187,10 @@ func (cm *ChannelManager) Cleanup(channel *Channel) {
187 187
 }
188 188
 
189 189
 func (cm *ChannelManager) SetRegistered(channelName string, account string) (err error) {
190
+	if cm.server.Defcon() <= 4 {
191
+		return errFeatureDisabled
192
+	}
193
+
190 194
 	var channel *Channel
191 195
 	cfname, err := CasefoldChannel(channelName)
192 196
 	if err != nil {

+ 3
- 2
irc/client.go View File

@@ -529,7 +529,7 @@ const (
529 529
 	authFailSaslRequired
530 530
 )
531 531
 
532
-func (client *Client) isAuthorized(config *Config, session *Session) AuthOutcome {
532
+func (client *Client) isAuthorized(server *Server, config *Config, session *Session) AuthOutcome {
533 533
 	saslSent := client.account != ""
534 534
 	// PASS requirement
535 535
 	if (config.Server.passwordBytes != nil) && session.passStatus != serverPassSuccessful && !(config.Accounts.SkipServerPassword && saslSent) {
@@ -540,7 +540,8 @@ func (client *Client) isAuthorized(config *Config, session *Session) AuthOutcome
540 540
 		return authFailTorSaslRequired
541 541
 	}
542 542
 	// finally, enforce require-sasl
543
-	if config.Accounts.RequireSasl.Enabled && !saslSent && !utils.IPInNets(session.IP(), config.Accounts.RequireSasl.exemptedNets) {
543
+	if !saslSent && (config.Accounts.RequireSasl.Enabled || server.Defcon() <= 2) &&
544
+		!utils.IPInNets(session.IP(), config.Accounts.RequireSasl.exemptedNets) {
544 545
 		return authFailSaslRequired
545 546
 	}
546 547
 	return authSuccess

+ 4
- 0
irc/commands.go View File

@@ -124,6 +124,10 @@ func init() {
124 124
 			minParams: 1,
125 125
 			oper:      true,
126 126
 		},
127
+		"DEFCON": {
128
+			handler: defconHandler,
129
+			capabs:  []string{"defcon"},
130
+		},
127 131
 		"DEOPER": {
128 132
 			handler:   deoperHandler,
129 133
 			minParams: 0,

+ 8
- 0
irc/getters.go View File

@@ -37,6 +37,14 @@ func (server *Server) Languages() (lm *languages.Manager) {
37 37
 	return server.Config().languageManager
38 38
 }
39 39
 
40
+func (server *Server) Defcon() uint32 {
41
+	return atomic.LoadUint32(&server.defcon)
42
+}
43
+
44
+func (server *Server) SetDefcon(defcon uint32) {
45
+	atomic.StoreUint32(&server.defcon, defcon)
46
+}
47
+
40 48
 func (client *Client) Sessions() (sessions []*Session) {
41 49
 	client.stateMutex.RLock()
42 50
 	sessions = client.sessions

+ 15
- 0
irc/handlers.go View File

@@ -759,6 +759,21 @@ func debugHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
759 759
 	return false
760 760
 }
761 761
 
762
+func defconHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
763
+	if len(msg.Params) > 0 {
764
+		level, err := strconv.Atoi(msg.Params[0])
765
+		if err == nil && 1 <= level && level <= 5 {
766
+			server.SetDefcon(uint32(level))
767
+			server.snomasks.Send(sno.LocalAnnouncements, fmt.Sprintf("%s [%s] set DEFCON level to %d", client.Nick(), client.Oper().Name, level))
768
+		} else {
769
+			rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), msg.Command, client.t("Invalid DEFCON parameter"))
770
+			return false
771
+		}
772
+	}
773
+	rb.Notice(fmt.Sprintf(client.t("Current DEFCON level is %d"), server.Defcon()))
774
+	return false
775
+}
776
+
762 777
 // helper for parsing the reason args to DLINE and KLINE
763 778
 func getReasonsFromParams(params []string, currentArg int) (reason, operReason string) {
764 779
 	reason = "No reason given"

+ 14
- 0
irc/help.go View File

@@ -164,6 +164,20 @@ Provides various debugging commands for the IRCd. <option> can be one of:
164 164
 * STOPCPUPROFILE: Stops the CPU profiler.
165 165
 * PROFILEHEAP: Writes a memory profile.
166 166
 * CRASHSERVER: Crashes the server (for use in failover testing)`,
167
+	},
168
+	"defcon": {
169
+		oper: true,
170
+		text: `DEFCON [level]
171
+
172
+The DEFCON system can disable server features at runtime, to mitigate
173
+spam or other hostile activity. It has five levels, which are cumulative
174
+(i.e., level 3 includes all restrictions from level 4 and so on):
175
+
176
+5: Normal operation
177
+4: No new account or channel registrations
178
+3: All channels are +R; no changes to vhosts
179
+2: No new unauthenticated connections
180
+1: No new connections except from localhost or other trusted IPs`,
167 181
 	},
168 182
 	"deoper": {
169 183
 		oper: true,

+ 11
- 2
irc/server.go View File

@@ -80,6 +80,7 @@ type Server struct {
80 80
 	whoWas            WhoWasList
81 81
 	stats             Stats
82 82
 	semaphores        ServerSemaphores
83
+	defcon            uint32
83 84
 }
84 85
 
85 86
 // NewServer returns a new Oragono server.
@@ -91,6 +92,7 @@ func NewServer(config *Config, logger *logger.Manager) (*Server, error) {
91 92
 		logger:       logger,
92 93
 		rehashSignal: make(chan os.Signal, 1),
93 94
 		signals:      make(chan os.Signal, len(ServerExitSignals)),
95
+		defcon:       5,
94 96
 	}
95 97
 
96 98
 	server.clients.Initialize()
@@ -149,6 +151,12 @@ func (server *Server) Run() {
149 151
 }
150 152
 
151 153
 func (server *Server) checkBans(ipaddr net.IP) (banned bool, message string) {
154
+	if server.Defcon() == 1 {
155
+		if !(ipaddr.IsLoopback() || utils.IPInNets(ipaddr, server.Config().Server.secureNets)) {
156
+			return true, "New connections to this server are temporarily restricted"
157
+		}
158
+	}
159
+
152 160
 	// check DLINEs
153 161
 	isBanned, info := server.dlines.CheckIP(ipaddr)
154 162
 	if isBanned {
@@ -220,7 +228,8 @@ func (server *Server) tryRegister(c *Client, session *Session) (exiting bool) {
220 228
 
221 229
 	// client MUST send PASS if necessary, or authenticate with SASL if necessary,
222 230
 	// before completing the other registration commands
223
-	authOutcome := c.isAuthorized(server.Config(), session)
231
+	config := server.Config()
232
+	authOutcome := c.isAuthorized(server, config, session)
224 233
 	var quitMessage string
225 234
 	switch authOutcome {
226 235
 	case authFailPass:
@@ -270,7 +279,7 @@ func (server *Server) tryRegister(c *Client, session *Session) (exiting bool) {
270 279
 	// Apply default user modes (without updating the invisible counter)
271 280
 	// The number of invisible users will be updated by server.stats.Register
272 281
 	// if we're using default user mode +i.
273
-	for _, defaultMode := range server.Config().Accounts.defaultUserModes {
282
+	for _, defaultMode := range config.Accounts.defaultUserModes {
274 283
 		c.SetMode(defaultMode, true)
275 284
 	}
276 285
 

Loading…
Cancel
Save