1/*2Maddy Mail Server - Composable all-in-one email server.3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors45This program is free software: you can redistribute it and/or modify6it under the terms of the GNU General Public License as published by7the Free Software Foundation, either version 3 of the License, or8(at your option) any later version.910This program is distributed in the hope that it will be useful,11but WITHOUT ANY WARRANTY; without even the implied warranty of12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13GNU General Public License for more details.1415You should have received a copy of the GNU General Public License16along with this program. If not, see <https://www.gnu.org/licenses/>.17*/1819package dnsbl2021import (22 "context"23 "errors"24 "net"25 "testing"2627 "github.com/foxcpp/go-mockdns"28 "github.com/foxcpp/maddy/internal/testutils"29)3031func TestCheckList(t *testing.T) {32 test := func(zones map[string]mockdns.Zone, cfg List, ip net.IP, ehlo, mailFrom string, expectedErr error) {33 mod := &DNSBL{34 resolver: &mockdns.Resolver{Zones: zones},35 log: testutils.Logger(t, "dnsbl"),36 }37 err := mod.checkList(context.Background(), cfg, ip, ehlo, mailFrom)38 if !errors.Is(err, expectedErr) {39 t.Errorf("expected err to be '%#v', got '%#v'", expectedErr, err)40 }41 }4243 test(nil, List{Zone: "example.org"}, net.IPv4(1, 2, 3, 4),44 "example.com", "foo@example.com", nil)45 test(map[string]mockdns.Zone{46 "4.3.2.1.example.org.": {47 A: []string{"127.0.0.1"},48 },49 }, List{Zone: "example.org", ClientIPv4: true}, net.IPv4(1, 2, 3, 4),50 "mx.example.com", "foo@example.com", ListedErr{51 Identity: "1.2.3.4",52 List: "example.org",53 Reason: "127.0.0.1",54 },55 )56 test(map[string]mockdns.Zone{57 "mx.example.com.example.org.": {58 A: []string{"127.0.0.1"},59 },60 }, List{Zone: "example.org"}, net.IPv4(1, 2, 3, 4),61 "mx.example.com", "foo@example.com", nil,62 )63 test(map[string]mockdns.Zone{64 "mx.example.com.example.org.": {65 A: []string{"127.0.0.1"},66 },67 }, List{Zone: "example.org", EHLO: true}, net.IPv4(1, 2, 3, 4),68 "mx.example.com", "foo@example.com", ListedErr{69 Identity: "mx.example.com",70 List: "example.org",71 Reason: "127.0.0.1",72 },73 )74 test(map[string]mockdns.Zone{75 "[1.2.3.4].example.org.": {76 A: []string{"127.0.0.1"},77 },78 }, List{Zone: "example.org", EHLO: true}, net.IPv4(1, 2, 3, 4),79 "[1.2.3.4]", "foo@example.com", nil,80 )81 test(map[string]mockdns.Zone{82 "[IPv6:beef::1].example.org.": {83 A: []string{"127.0.0.1"},84 },85 }, List{Zone: "example.org", EHLO: true}, net.IPv4(1, 2, 3, 4),86 "[IPv6:beef::1]", "foo@example.com", nil,87 )88 test(map[string]mockdns.Zone{89 "example.com.example.org.": {90 A: []string{"127.0.0.1"},91 },92 }, List{Zone: "example.org"}, net.IPv4(1, 2, 3, 4),93 "mx.example.com", "foo@example.com", nil,94 )95 test(map[string]mockdns.Zone{96 "postmaster.example.org.": {97 A: []string{"127.0.0.1"},98 },99 }, List{Zone: "example.org", MAILFROM: true}, net.IPv4(1, 2, 3, 4),100 "mx.example.com", "postmaster", nil,101 )102 test(map[string]mockdns.Zone{103 ".example.org.": {104 A: []string{"127.0.0.1"},105 },106 }, List{Zone: "example.org", MAILFROM: true}, net.IPv4(1, 2, 3, 4),107 "mx.example.com", "", nil,108 )109 test(map[string]mockdns.Zone{110 "example.com.example.org.": {111 A: []string{"127.0.0.1"},112 },113 }, List{Zone: "example.org", MAILFROM: true}, net.IPv4(1, 2, 3, 4),114 "mx.example.com", "foo@example.com", ListedErr{115 Identity: "example.com",116 List: "example.org",117 Reason: "127.0.0.1",118 },119 )120}121122func TestCheckLists(t *testing.T) {123 test := func(zones map[string]mockdns.Zone, bls []List, ip net.IP, ehlo, mailFrom string, reject, quarantine bool) {124 mod := &DNSBL{125 bls: bls,126 resolver: &mockdns.Resolver{Zones: zones},127 log: testutils.Logger(t, "dnsbl"),128 quarantineThres: 1,129 rejectThres: 2,130 }131 result := mod.checkLists(context.Background(), ip, ehlo, mailFrom)132133 if result.Reject && !reject {134 t.Errorf("Expected message to not be rejected")135 }136 if !result.Reject && reject {137 t.Errorf("Expected message to be rejected")138 }139 if result.Quarantine && !quarantine {140 t.Errorf("Expected message to not be quarantined")141 }142 if !result.Quarantine && quarantine {143 t.Errorf("Expected message to be quarantined")144 }145 }146147 // Score 2 >= 2, reject148 test(map[string]mockdns.Zone{149 "4.3.2.1.example.org.": {150 A: []string{"127.0.0.1"},151 },152 }, []List{153 {154 Zone: "example.org",155 ClientIPv4: true,156 ScoreAdj: 2,157 },158 }, net.IPv4(1, 2, 3, 4),159 "mx.example.com", "foo@example.com", true, false,160 )161162 // Score 1 >= 1, quarantine163 test(map[string]mockdns.Zone{164 "4.3.2.1.example.org.": {165 A: []string{"127.0.0.1"},166 },167 }, []List{168 {169 Zone: "example.org",170 ClientIPv4: true,171 ScoreAdj: 1,172 },173 }, net.IPv4(1, 2, 3, 4),174 "mx.example.com", "foo@example.com", false, true,175 )176177 // Score 0, no action178 test(map[string]mockdns.Zone{179 "4.3.2.1.example.org.": {180 A: []string{"127.0.0.1"},181 },182 "4.3.2.1.example.net.": {183 A: []string{"127.0.0.1"},184 },185 },186 []List{187 {Zone: "example.org", ClientIPv4: true, ScoreAdj: 1},188 {Zone: "example.net", ClientIPv4: true, ScoreAdj: -1},189 },190 net.IPv4(1, 2, 3, 4),191 "mx.example.com", "foo@example.com",192 false, false,193 )194195 // DNS error, hard-fail (reject)196 test(map[string]mockdns.Zone{197 "4.3.2.2.example.org.": {198 Err: &net.DNSError{199 Err: "i/o timeout",200 IsTimeout: true,201 IsTemporary: true,202 },203 },204 },205 []List{206 {Zone: "example.org", ClientIPv4: true, ScoreAdj: 1},207 {Zone: "example.net", ClientIPv4: true, ScoreAdj: 2},208 },209 net.IPv4(2, 2, 3, 4),210 "mx.example.com", "foo@example.com",211 true, false,212 )213}