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  }