maddy

Fork https://github.com/foxcpp/maddy

git clone git://git.lin.moe/go/maddy.git

  1/*
  2Maddy Mail Server - Composable all-in-one email server.
  3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors
  4
  5This program is free software: you can redistribute it and/or modify
  6it under the terms of the GNU General Public License as published by
  7the Free Software Foundation, either version 3 of the License, or
  8(at your option) any later version.
  9
 10This program is distributed in the hope that it will be useful,
 11but WITHOUT ANY WARRANTY; without even the implied warranty of
 12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13GNU General Public License for more details.
 14
 15You should have received a copy of the GNU General Public License
 16along with this program.  If not, see <https://www.gnu.org/licenses/>.
 17*/
 18
 19package dns
 20
 21import (
 22	"net"
 23	"testing"
 24
 25	"github.com/foxcpp/go-mockdns"
 26	"github.com/foxcpp/maddy/framework/future"
 27	"github.com/foxcpp/maddy/framework/module"
 28	"github.com/foxcpp/maddy/internal/check"
 29	"github.com/foxcpp/maddy/internal/testutils"
 30)
 31
 32func TestRequireMatchingRDNS(t *testing.T) {
 33	test := func(rdns, srcHost string, fail bool) {
 34		rdnsFut := future.New()
 35		var ptr []string
 36		if rdns != "" {
 37			rdnsFut.Set(rdns, nil)
 38			ptr = []string{rdns}
 39		} else {
 40			rdnsFut.Set(nil, nil)
 41		}
 42
 43		res := requireMatchingRDNS(check.StatelessCheckContext{
 44			Resolver: &mockdns.Resolver{
 45				Zones: map[string]mockdns.Zone{
 46					"4.3.2.1.in-addr.arpa.": {
 47						PTR: ptr,
 48					},
 49				},
 50			},
 51			MsgMeta: &module.MsgMetadata{
 52				Conn: &module.ConnState{
 53					RemoteAddr: &net.TCPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 55555},
 54					Hostname:   srcHost,
 55					RDNSName:   rdnsFut,
 56				},
 57			},
 58			Logger: testutils.Logger(t, "require_matching_rdns"),
 59		})
 60
 61		actualFail := res.Reason != nil
 62		if fail && !actualFail {
 63			t.Errorf("%v, %s: expected failure but check succeeded", rdns, srcHost)
 64		}
 65		if !fail && actualFail {
 66			t.Errorf("%v, %s: unexpected failure", rdns, srcHost)
 67		}
 68	}
 69
 70	test("", "example.org", true)
 71	test("example.org", "[1.2.3.4]", true)
 72	test("example.org", "[IPv6:beef::1]", true)
 73	test("example.org", "example.org", false)
 74	test("example.org.", "example.org", false)
 75	test("example.org", "example.org.", false)
 76	test("example.org.", "example.org.", false)
 77	test("example.com.", "example.org.", true)
 78}
 79
 80func TestRequireMXRecord(t *testing.T) {
 81	test := func(mailFrom, mxDomain string, mx []net.MX, fail bool) {
 82		res := requireMXRecord(check.StatelessCheckContext{
 83			Resolver: &mockdns.Resolver{
 84				Zones: map[string]mockdns.Zone{
 85					mxDomain + ".": {
 86						MX: mx,
 87					},
 88				},
 89			},
 90			MsgMeta: &module.MsgMetadata{
 91				Conn: &module.ConnState{
 92					RemoteAddr: &net.TCPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 55555},
 93				},
 94			},
 95			Logger: testutils.Logger(t, "require_mx_record"),
 96		}, mailFrom)
 97
 98		actualFail := res.Reason != nil
 99		if fail && !actualFail {
100			t.Errorf("%v, %v: expected failure but check succeeded", mailFrom, mx)
101		}
102		if !fail && actualFail {
103			t.Errorf("%v, %v: unexpected failure", mailFrom, mx)
104		}
105	}
106
107	test("foo@example.org", "example.org", nil, true)
108	test("foo@example.com", "", nil, true) // NXDOMAIN
109	test("foo@[1.2.3.4]", "", nil, true)
110	test("[IPv6:beef::1]", "", nil, true)
111	test("[IPv6:beef::1]", "", nil, true)
112	test("foo@example.org", "example.org", []net.MX{{Host: "a.com"}}, false)
113	test("foo@", "", nil, true)
114	test("", "", nil, false) // Permit <> for bounces.
115	test("foo@example.org", "example.org", []net.MX{{Host: "."}}, true)
116}