github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/dns/handler_whitelist_test.go (about) 1 /* 2 * Copyright (C) 2020 The "MysteriumNetwork/node" Authors. 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 package dns 19 20 import ( 21 "net" 22 "testing" 23 24 "github.com/mysteriumnetwork/node/core/policy/localcopy" 25 26 "github.com/miekg/dns" 27 "github.com/mysteriumnetwork/node/firewall" 28 "github.com/mysteriumnetwork/node/market" 29 "github.com/stretchr/testify/assert" 30 ) 31 32 var ( 33 policyDNSZone = market.AccessPolicy{ID: "wildcard-domain"} 34 policyDNSZoneRules = market.AccessPolicyRuleSet{ 35 ID: "wildcard-domain", 36 Allow: []market.AccessRule{ 37 {Type: market.AccessPolicyTypeDNSZone, Value: "wildcard.com"}, 38 }, 39 } 40 41 policyDNSHostname = market.AccessPolicy{ID: "domain"} 42 policyDNSHostnameRules = market.AccessPolicyRuleSet{ 43 ID: "domain", 44 Allow: []market.AccessRule{ 45 {Type: market.AccessPolicyTypeDNSHostname, Value: "single.com"}, 46 }, 47 } 48 ) 49 50 func Test_WhitelistAnswers(t *testing.T) { 51 tests := []struct { 52 name string 53 response *dns.Msg 54 whitelistedIPs map[string]int 55 }{ 56 { 57 "should not allow failed responses", 58 &dns.Msg{ 59 MsgHdr: dns.MsgHdr{Rcode: dns.RcodeNameError}, 60 }, 61 map[string]int{}, 62 }, 63 { 64 "should allow whitelisted hostname", 65 &dns.Msg{ 66 Answer: []dns.RR{ 67 &dns.A{ 68 Hdr: dns.RR_Header{Name: "single.com.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}, 69 A: net.ParseIP("0.0.0.3"), 70 }, 71 &dns.A{ 72 Hdr: dns.RR_Header{Name: "single.com.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}, 73 A: net.ParseIP("0.0.0.4"), 74 }, 75 }, 76 }, 77 map[string]int{ 78 "0.0.0.3": 1, 79 "0.0.0.4": 1, 80 }, 81 }, 82 { 83 "should not allow zone of whitelisted hostname", 84 &dns.Msg{ 85 Answer: []dns.RR{ 86 &dns.A{ 87 Hdr: dns.RR_Header{Name: "cdn.single.com.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}, 88 A: net.ParseIP("0.0.0.2"), 89 }, 90 }, 91 }, 92 map[string]int{}, 93 }, 94 { 95 "should not allow unknown hostname", 96 &dns.Msg{ 97 Answer: []dns.RR{ 98 &dns.A{ 99 Hdr: dns.RR_Header{Name: "belekas.com.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}, 100 A: net.ParseIP("0.0.0.1"), 101 }, 102 }, 103 }, 104 map[string]int{}, 105 }, 106 107 { 108 "should allow whitelisted wildcard hostname", 109 &dns.Msg{ 110 Answer: []dns.RR{ 111 &dns.A{ 112 Hdr: dns.RR_Header{Name: "wildcard.com.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}, 113 A: net.ParseIP("0.0.0.8"), 114 }, 115 &dns.A{ 116 Hdr: dns.RR_Header{Name: "wildcard.com.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}, 117 A: net.ParseIP("0.0.0.9"), 118 }, 119 }, 120 }, 121 map[string]int{ 122 "0.0.0.8": 1, 123 "0.0.0.9": 1, 124 }, 125 }, 126 { 127 "should allow zone of whitelisted wildcard hostname", 128 &dns.Msg{ 129 Answer: []dns.RR{ 130 &dns.A{ 131 Hdr: dns.RR_Header{Name: "cdn.wildcard.com.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}, 132 A: net.ParseIP("0.0.0.6"), 133 }, 134 &dns.A{ 135 Hdr: dns.RR_Header{Name: "cdn.wildcard.com.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}, 136 A: net.ParseIP("0.0.0.7"), 137 }, 138 }, 139 }, 140 map[string]int{ 141 "0.0.0.6": 1, 142 "0.0.0.7": 1, 143 }, 144 }, 145 } 146 147 for _, tt := range tests { 148 t.Run(tt.name, func(t *testing.T) { 149 mockedBlocker := &trafficBlockerMock{ 150 allowIPCalls: map[string]int{}, 151 } 152 writer := &recordingWriter{} 153 handler := WhitelistAnswers( 154 dns.HandlerFunc(func(writer dns.ResponseWriter, req *dns.Msg) { 155 writer.WriteMsg(tt.response) 156 }), 157 mockedBlocker, 158 createPolicies(), 159 ) 160 161 handler.ServeDNS(writer, &dns.Msg{}) 162 assert.Equal(t, tt.whitelistedIPs, mockedBlocker.allowIPCalls, tt.name) 163 assert.Equal(t, tt.response, writer.responseMsg) 164 }) 165 } 166 } 167 168 func createPolicies() *localcopy.Repository { 169 repo := localcopy.NewRepository() 170 repo.SetPolicyRules(policyDNSZone, policyDNSZoneRules) 171 repo.SetPolicyRules(policyDNSHostname, policyDNSHostnameRules) 172 return repo 173 } 174 175 type trafficBlockerMock struct { 176 allowIPCalls map[string]int 177 } 178 179 func (tbn *trafficBlockerMock) Setup() error { return nil } 180 181 func (tbn *trafficBlockerMock) Teardown() {} 182 183 func (tbn *trafficBlockerMock) BlockIncomingTraffic(net.IPNet) (firewall.IncomingRuleRemove, error) { 184 return nil, nil 185 } 186 187 func (tbn *trafficBlockerMock) AllowURLAccess(rawURLs ...string) (firewall.IncomingRuleRemove, error) { 188 return nil, nil 189 } 190 191 func (tbn *trafficBlockerMock) AllowIPAccess(ip net.IP) (firewall.IncomingRuleRemove, error) { 192 ipString := ip.String() 193 if _, called := tbn.allowIPCalls[ipString]; !called { 194 tbn.allowIPCalls[ipString] = 0 195 } 196 tbn.allowIPCalls[ipString]++ 197 198 return func() error { 199 return nil 200 }, nil 201 }