Browse Source

enum types simplifying sort, config fails on wrong action types

devel+dnsbl
moocow 6 years ago
parent
commit
6a9fa35d35
5 changed files with 151 additions and 63 deletions
  1. 31
    9
      irc/config.go
  2. 55
    46
      irc/dnsbl.go
  3. 0
    3
      irc/handlers.go
  4. 6
    5
      irc/server.go
  5. 59
    0
      oragono.yaml

+ 31
- 9
irc/config.go View File

@@ -97,16 +97,33 @@ type DnsblConfig struct {
97 97
 }
98 98
 
99 99
 type DnsblListEntry struct {
100
-	Host   string
101
-	Types  []string
102
-	Reply  map[string]DnsblListReply
103
-	Action string
104
-	Reason string
100
+	Host       string
101
+	Types      []string
102
+	Reply      map[string]DnsblListReply
103
+	Action     string
104
+	ActionType uint
105
+	Reason     string
105 106
 }
106 107
 
107 108
 type DnsblListReply struct {
108
-	Action string
109
-	Reason string
109
+	Action     string
110
+	ActionType uint
111
+	Reason     string
112
+}
113
+
114
+func (conf *Config) DnsblTypes(action string) (uint, error) {
115
+	actions := map[string]uint{
116
+		"require-sasl": DnsblRequireSaslReply,
117
+		"allow":        DnsblAllowReply,
118
+		"block":        DnsblBlockReply,
119
+		"notify":       DnsblNotifyReply,
120
+	}
121
+
122
+	if value, exists := actions[action]; exists {
123
+		return value, nil
124
+	}
125
+
126
+	return DnsblUnknownReply, errors.New(fmt.Sprintf("Unknown DNSBL action type: %s", action))
110 127
 }
111 128
 
112 129
 type NickReservationMethod int
@@ -493,12 +510,16 @@ func LoadConfig(filename string) (config *Config, err error) {
493 510
 	config.Server.WebIRC = newWebIRC
494 511
 
495 512
 	for id, list := range config.Dnsbl.Lists {
496
-		var action, reason = list.Action, list.Reason
513
+		actionType, err := config.DnsblTypes(list.Action)
514
+		if err != nil {
515
+			return nil, err
516
+		}
517
+		reason := list.Reason
497 518
 
498 519
 		var newDnsblListReply = make(map[string]DnsblListReply)
499 520
 		for key, reply := range list.Reply {
500 521
 			if reply.Action == "" {
501
-				reply.Action = action
522
+				reply.ActionType = actionType
502 523
 			}
503 524
 			if reply.Reason == "" {
504 525
 				reply.Reason = reason
@@ -508,6 +529,7 @@ func LoadConfig(filename string) (config *Config, err error) {
508 529
 				newDnsblListReply[newKey] = reply
509 530
 			}
510 531
 		}
532
+		config.Dnsbl.Lists[id].ActionType = actionType
511 533
 		config.Dnsbl.Lists[id].Reply = newDnsblListReply
512 534
 	}
513 535
 

+ 55
- 46
irc/dnsbl.go View File

@@ -9,6 +9,16 @@ import (
9 9
 	"github.com/oragono/oragono/irc/sno"
10 10
 )
11 11
 
12
+// Constants
13
+const (
14
+	DnsblRequireSaslReply uint = iota
15
+	DnsblAllowReply
16
+	DnsblBlockReply
17
+	DnsblNotifyReply
18
+	DnsblUnknownReply
19
+)
20
+
21
+// ReverseAddress returns IPv4 addresses reversed
12 22
 func ReverseAddress(ip net.IP) string {
13 23
 	// This is a IPv4 address
14 24
 	if ip.To4() != nil {
@@ -25,12 +35,7 @@ func ReverseAddress(ip net.IP) string {
25 35
 	return ip.String()
26 36
 }
27 37
 
28
-func LastIpOctet(addr string) string {
29
-	address := strings.Split(addr, ".")
30
-
31
-	return address[len(address)-1]
32
-}
33
-
38
+// LookupBlacklistEntry performs a lookup on the dnsbl on the client IP
34 39
 func (server *Server) LookupBlacklistEntry(list *DnsblListEntry, client *Client) []string {
35 40
 	res, err := net.LookupHost(fmt.Sprintf("%s.%s", ReverseAddress(client.IP()), list.Host))
36 41
 
@@ -42,23 +47,16 @@ func (server *Server) LookupBlacklistEntry(list *DnsblListEntry, client *Client)
42 47
 
43 48
 	if len(res) > 0 {
44 49
 		for _, addr := range res {
45
-			entries = append(entries, LastIpOctet(addr))
50
+			octet := strings.Split(addr, ".")
51
+			if len(octet) > 0 {
52
+				entries = append(entries, octet[len(octet)-1])
53
+			}
46 54
 		}
47 55
 	}
48 56
 
49 57
 	return entries
50 58
 }
51 59
 
52
-func sendDnsblMessage(client *Client, message string) {
53
-	/*fmt.Printf(client.server.DnsblConfig().Channel)
54
-	if channel := client.server.DnsblConfig().Channel; channel != "" {
55
-		fmt.Printf(channel)
56
-		client.Send(nil, client.server.name, "PRIVMSG", channel, message)
57
-	}
58
-	*/
59
-	client.server.snomasks.Send(sno.Dnsbl, message)
60
-}
61
-
62 60
 // ProcessBlacklist does
63 61
 func (server *Server) ProcessBlacklist(client *Client) {
64 62
 
@@ -67,56 +65,51 @@ func (server *Server) ProcessBlacklist(client *Client) {
67 65
 		return
68 66
 	}
69 67
 
68
+	channel := server.DnsblConfig().Channel
69
+	lists := server.DnsblConfig().Lists
70
+
70 71
 	type DnsblTypeResponse struct {
71
-		Host   string
72
-		Action string
73
-		Reason string
72
+		Host       string
73
+		ActionType uint
74
+		Reason     string
74 75
 	}
75 76
 	var items = []DnsblTypeResponse{}
76
-	for _, list := range server.DnsblConfig().Lists {
77
+	for _, list := range lists {
77 78
 		response := DnsblTypeResponse{
78
-			Host:   list.Host,
79
-			Action: list.Action,
80
-			Reason: list.Reason,
79
+			Host:       list.Host,
80
+			ActionType: list.ActionType,
81
+			Reason:     list.Reason,
81 82
 		}
82 83
 		// update action/reason if matched with new ...
83 84
 		for _, entry := range server.LookupBlacklistEntry(&list, client) {
84 85
 			if reply, exists := list.Reply[entry]; exists {
85
-				response.Action, response.Reason = reply.Action, reply.Reason
86
+				response.ActionType, response.Reason = list.ActionType, reply.Reason
86 87
 			}
87 88
 			items = append(items, response)
88 89
 		}
89 90
 	}
90 91
 
91
-	// Sort responses so that require-sasl blocks come first. Otherwise A>B (allow>block, allow>notify, block>notify)
92
-	// so that responses come in this order:
93
-	// - require-sasl
94
-	// - allow
95
-	// - block
96
-	// - notify
92
+	// Sorts in the following order: require-sasl, allow, block, notify
97 93
 	sort.Slice(items, func(i, j int) bool {
98
-		if items[i].Action == "require-sasl" {
99
-			return true
100
-		}
101
-		return items[i].Action > items[j].Action
94
+		return items[i].ActionType > items[j].ActionType
102 95
 	})
103 96
 
104 97
 	if len(items) > 0 {
105 98
 		item := items[0]
106
-		switch item.Action {
107
-		case "require-sasl":
108
-			sendDnsblMessage(client, fmt.Sprintf("Connecting client %s matched %s, requiring SASL to proceed", client.IP(), item.Host))
99
+		switch item.ActionType {
100
+		case DnsblRequireSaslReply:
101
+			client.sendServerMessage("", channel, sno.Dnsbl, fmt.Sprintf("Connecting client %s matched %s, requiring SASL to proceed", client.IP(), item.Host))
109 102
 			client.SetRequireSasl(true, item.Reason)
110 103
 
111
-		case "block":
112
-			sendDnsblMessage(client, fmt.Sprintf("Connecting client %s matched %s - killing", client.IP(), item.Host))
104
+		case DnsblBlockReply:
105
+			client.sendServerMessage("", channel, sno.Dnsbl, fmt.Sprintf("Connecting client %s matched %s - killing", client.IP(), item.Host))
113 106
 			client.Quit(strings.Replace(item.Reason, "{ip}", client.IPString(), -1))
114 107
 
115
-		case "notify":
116
-			sendDnsblMessage(client, fmt.Sprintf("Connecting client %s matched %s", client.IP(), item.Host))
108
+		case DnsblNotifyReply:
109
+			client.sendServerMessage("", channel, sno.Dnsbl, fmt.Sprintf("Connecting client %s matched %s", client.IP(), item.Host))
117 110
 
118
-		case "allow":
119
-			sendDnsblMessage(client, fmt.Sprintf("Allowing host %s [%s]", client.IP(), item.Host))
111
+		case DnsblAllowReply:
112
+			client.sendServerMessage("", channel, sno.Dnsbl, fmt.Sprintf("Allowing host %s [%s]", client.IP(), item.Host))
120 113
 		}
121 114
 	}
122 115
 
@@ -130,13 +123,29 @@ func connectionRequiresSasl(client *Client) bool {
130 123
 		return false
131 124
 	}
132 125
 
126
+	channel := client.server.DnsblConfig().Channel
127
+
133 128
 	if client.Account() == "" {
134
-		sendDnsblMessage(client, fmt.Sprintf("Connecting client %s and did not authenticate through SASL - blocking connection", client.IP()))
129
+		//client.sendServerMessage("", channel, sno.Dnsbl, fmt.Sprintf("Connecting client %s and did not authenticate through SASL - blocking connection", client.IP()))
135 130
 		client.Quit(strings.Replace(reason, "{ip}", client.IPString(), -1))
136 131
 		return true
137 132
 	}
138 133
 
139
-	sendDnsblMessage(client, fmt.Sprintf("Connecting client %s authenticated through SASL - allowing", client.IP()))
134
+	client.sendServerMessage("", channel, sno.Dnsbl, fmt.Sprintf("Connecting client %s authenticated through SASL - allowing", client.IP()))
140 135
 
141 136
 	return false
142 137
 }
138
+
139
+func (client *Client) sendServerMessage(pseudo string, channel string, mask sno.Mask, message string) {
140
+	/*
141
+	   This causes an out of bounds error - possibly in client.Send() - investigate further
142
+	   	if pseudo == "" {
143
+	   		pseudo = client.server.name
144
+	   	}
145
+
146
+	   	if channel != "" {
147
+	   		client.Send(nil, pseudo, "PRIVMSG", channel, message)
148
+	   	}
149
+	*/
150
+	client.server.snomasks.Send(mask, message)
151
+}

+ 0
- 3
irc/handlers.go View File

@@ -1784,9 +1784,6 @@ func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
1784 1784
 
1785 1785
 	server.snomasks.Send(sno.LocalOpers, fmt.Sprintf(ircfmt.Unescape("Client opered up $c[grey][$r%s$c[grey], $r%s$c[grey]]"), client.nickMaskString, client.operName))
1786 1786
 
1787
-	// increase oper count
1788
-	//server.stats.ChangeOperators(1)
1789
-
1790 1787
 	// client may now be unthrottled by the fakelag system
1791 1788
 	client.resetFakelag()
1792 1789
 

+ 6
- 5
irc/server.go View File

@@ -446,11 +446,6 @@ func (server *Server) tryRegister(c *Client) {
446 446
 		return
447 447
 	}
448 448
 
449
-	if connectionRequiresSasl(c) {
450
-		c.destroy(false)
451
-		return
452
-	}
453
-
454 449
 	// client MUST send PASS (or AUTHENTICATE, if skip-server-password is set)
455 450
 	// before completing the other registration commands
456 451
 	if !c.Authorized() {
@@ -467,6 +462,12 @@ func (server *Server) tryRegister(c *Client) {
467 462
 		return
468 463
 	}
469 464
 
465
+	// Check if connection requires SASL
466
+	if connectionRequiresSasl(c) {
467
+		c.destroy(false)
468
+		return
469
+	}
470
+
470 471
 	// check KLINEs
471 472
 	isBanned, info := server.klines.CheckMasks(c.AllNickmasks()...)
472 473
 	if isBanned {

+ 59
- 0
oragono.yaml View File

@@ -407,3 +407,62 @@ fakelag:
407 407
     # client status resets to the default state if they go this long without
408 408
     # sending any commands:
409 409
     cooldown: 2s
410
+# dnsbls are DNS block lists. they're used to automatically deny or restrict clients who
411
+# have been deemed bad
412
+dnsbl:
413
+    # whether to check DNS block lists
414
+    enabled: false
415
+
416
+    # optional channel to send rejections to if the 'notify' action is specified in any lists
417
+    #channel: "#dnsbl"
418
+
419
+    # the specific dnsbls to check for every client entering the network
420
+    lists:
421
+        -
422
+            # host - specific hostname to use
423
+            host: "dnsbl.dronebl.org"
424
+
425
+            # which types of hosts to look up on this dnsbl. we support:
426
+            # - ipv4: D.C.B.A.hostname
427
+            # - ipv6: n.i.b.b.l.e.s.hostname (see explanation here: https://www.dan.me.uk/dnsbl )
428
+            types:
429
+                - ipv4
430
+                - ipv6
431
+
432
+            # action to take if the client matches this dnsbl:
433
+            # - allow - let the client access the network
434
+            # - block - block the client from accessing the network, with the given message
435
+            # - notify - send a notification to opers in-channel (if configured) and via the 'S' snomask
436
+            # - require-sasl - require the client to login with SASL, kill them if they don't
437
+            action: block
438
+
439
+            # reason that's shown if they're unable to access the network because of this rbl.
440
+            # we support the following variables:
441
+            # - "{ip}" - their IP address
442
+            reason: "Your IP ({ip}) is listed in DroneBL. For assistance, see http://dronebl.org/lookup?ip={ip}"
443
+
444
+            # specific replies to take action on. these are based on the last octet of the return IP.
445
+            # for example, "24" or "13,54,24" would both match a result of "127.0.0.24" from the rbl.
446
+            reply:
447
+                # 8/9/10/11 are all proxies
448
+                "8,9,10,11":
449
+                    action: require-sasl
450
+                    reason: "You need to enable SASL to access this network. For assistance, see http://dronebl.org/lookup?ip={ip}"
451
+                # 98 is an example reply type that's not real
452
+                98:
453
+                    action: allow
454
+
455
+        -
456
+            host: "rbl.efnetrbl.org"
457
+            types:
458
+                - ipv4
459
+            action: block
460
+            reason: "Your IP ({ip}) is listed in the EFnet RBL. For assistance, see http://efnetrbl.org/?i={ip}"
461
+
462
+        -
463
+            host: "torexit.dan.me.uk"
464
+            types:
465
+                - ipv4
466
+                - ipv6
467
+            action: require-sasl
468
+            reason: "You need to enable SASL to access this network while using TOR"

Loading…
Cancel
Save