2018-04-23 13:16:20 +02:00
|
|
|
package irc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/oragono/oragono/irc/sno"
|
2018-04-24 20:51:20 +02:00
|
|
|
"github.com/oragono/oragono/irc/utils"
|
2018-04-23 13:16:20 +02:00
|
|
|
)
|
|
|
|
|
2018-04-24 13:47:35 +02:00
|
|
|
// Constants
|
2018-04-24 20:51:20 +02:00
|
|
|
type DnsblActionType uint
|
|
|
|
|
2018-04-24 13:47:35 +02:00
|
|
|
const (
|
2018-04-24 20:51:20 +02:00
|
|
|
DnsblRequireSaslReply DnsblActionType = iota
|
2018-04-24 13:47:35 +02:00
|
|
|
DnsblAllowReply
|
|
|
|
DnsblBlockReply
|
|
|
|
DnsblNotifyReply
|
|
|
|
DnsblUnknownReply
|
|
|
|
)
|
|
|
|
|
|
|
|
// LookupBlacklistEntry performs a lookup on the dnsbl on the client IP
|
2018-04-23 13:16:20 +02:00
|
|
|
func (server *Server) LookupBlacklistEntry(list *DnsblListEntry, client *Client) []string {
|
2018-04-24 20:51:20 +02:00
|
|
|
res, err := net.LookupHost(fmt.Sprintf("%s.%s", utils.ReverseAddress(client.IP()), list.Host))
|
2018-04-23 13:16:20 +02:00
|
|
|
|
|
|
|
var entries []string
|
|
|
|
if err != nil {
|
2018-04-24 20:51:20 +02:00
|
|
|
// An error may indicate that the A record was not found
|
2018-04-23 13:16:20 +02:00
|
|
|
return entries
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(res) > 0 {
|
|
|
|
for _, addr := range res {
|
2018-04-24 13:47:35 +02:00
|
|
|
octet := strings.Split(addr, ".")
|
|
|
|
if len(octet) > 0 {
|
|
|
|
entries = append(entries, octet[len(octet)-1])
|
|
|
|
}
|
2018-04-23 13:16:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return entries
|
|
|
|
}
|
|
|
|
|
|
|
|
// ProcessBlacklist does
|
|
|
|
func (server *Server) ProcessBlacklist(client *Client) {
|
|
|
|
|
|
|
|
if !server.DnsblConfig().Enabled || len(server.DnsblConfig().Lists) == 0 {
|
|
|
|
// do nothing if dnsbl is disabled, empty lists is treated as if dnsbl was disabled
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-04-24 13:47:35 +02:00
|
|
|
lists := server.DnsblConfig().Lists
|
|
|
|
|
2018-04-23 13:16:20 +02:00
|
|
|
type DnsblTypeResponse struct {
|
2018-04-24 13:47:35 +02:00
|
|
|
Host string
|
2018-04-24 20:51:20 +02:00
|
|
|
ActionType DnsblActionType
|
2018-04-24 13:47:35 +02:00
|
|
|
Reason string
|
2018-04-23 13:16:20 +02:00
|
|
|
}
|
|
|
|
var items = []DnsblTypeResponse{}
|
2018-04-24 13:47:35 +02:00
|
|
|
for _, list := range lists {
|
2018-04-23 13:16:20 +02:00
|
|
|
response := DnsblTypeResponse{
|
2018-04-24 13:47:35 +02:00
|
|
|
Host: list.Host,
|
|
|
|
ActionType: list.ActionType,
|
|
|
|
Reason: list.Reason,
|
2018-04-23 13:16:20 +02:00
|
|
|
}
|
|
|
|
// update action/reason if matched with new ...
|
|
|
|
for _, entry := range server.LookupBlacklistEntry(&list, client) {
|
|
|
|
if reply, exists := list.Reply[entry]; exists {
|
2018-04-24 13:47:35 +02:00
|
|
|
response.ActionType, response.Reason = list.ActionType, reply.Reason
|
2018-04-23 13:16:20 +02:00
|
|
|
}
|
|
|
|
items = append(items, response)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-24 13:47:35 +02:00
|
|
|
// Sorts in the following order: require-sasl, allow, block, notify
|
2018-04-23 13:16:20 +02:00
|
|
|
sort.Slice(items, func(i, j int) bool {
|
2018-04-24 13:47:35 +02:00
|
|
|
return items[i].ActionType > items[j].ActionType
|
2018-04-23 13:16:20 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
if len(items) > 0 {
|
|
|
|
item := items[0]
|
2018-04-24 13:47:35 +02:00
|
|
|
switch item.ActionType {
|
|
|
|
case DnsblRequireSaslReply:
|
2018-04-24 20:51:20 +02:00
|
|
|
dnsblSendServiceMessage(server, fmt.Sprintf("Connecting client %s matched %s, requiring SASL to proceed", client.IP(), item.Host))
|
2018-04-23 13:16:20 +02:00
|
|
|
client.SetRequireSasl(true, item.Reason)
|
|
|
|
|
2018-04-24 13:47:35 +02:00
|
|
|
case DnsblBlockReply:
|
2018-04-24 20:51:20 +02:00
|
|
|
dnsblSendServiceMessage(server, fmt.Sprintf("Connecting client %s matched %s - killing", client.IP(), item.Host))
|
2018-04-23 13:16:20 +02:00
|
|
|
client.Quit(strings.Replace(item.Reason, "{ip}", client.IPString(), -1))
|
|
|
|
|
2018-04-24 13:47:35 +02:00
|
|
|
case DnsblNotifyReply:
|
2018-04-24 20:51:20 +02:00
|
|
|
dnsblSendServiceMessage(server, fmt.Sprintf("Connecting client %s matched %s", client.IP(), item.Host))
|
2018-04-23 13:16:20 +02:00
|
|
|
|
2018-04-24 13:47:35 +02:00
|
|
|
case DnsblAllowReply:
|
2018-04-24 20:51:20 +02:00
|
|
|
dnsblSendServiceMessage(server, fmt.Sprintf("Allowing host %s [%s]", client.IP(), item.Host))
|
2018-04-23 13:16:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-04-24 20:51:20 +02:00
|
|
|
func ConnectionRequiresSasl(client *Client) bool {
|
2018-04-23 13:16:20 +02:00
|
|
|
sasl, reason := client.RequireSasl()
|
|
|
|
|
|
|
|
if !sasl {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if client.Account() == "" {
|
2018-04-24 20:51:20 +02:00
|
|
|
dnsblSendServiceMessage(client.server, fmt.Sprintf("Connecting client %s and did not authenticate through SASL - blocking connection", client.IP()))
|
2018-04-23 13:16:20 +02:00
|
|
|
client.Quit(strings.Replace(reason, "{ip}", client.IPString(), -1))
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2018-04-24 20:51:20 +02:00
|
|
|
dnsblSendServiceMessage(client.server, fmt.Sprintf("Connecting client %s authenticated through SASL - allowing", client.IP()))
|
2018-04-23 13:16:20 +02:00
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
2018-04-24 13:47:35 +02:00
|
|
|
|
2018-04-24 20:51:20 +02:00
|
|
|
func dnsblSendServiceMessage(server *Server, message string) {
|
|
|
|
channel := server.DnsblConfig().Channel
|
|
|
|
if channel != "" {
|
|
|
|
server.serviceNotifyChannel(server.name, channel, message)
|
|
|
|
}
|
|
|
|
server.snomasks.Send(sno.Dnsbl, message)
|
2018-04-24 13:47:35 +02:00
|
|
|
}
|