github.com/elfadel/cilium@v1.6.12/pkg/fqdn/dnsproxy/proxy_test.go (about)

     1  // Copyright 2018 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // +build privileged_tests
    16  
    17  package dnsproxy
    18  
    19  import (
    20  	"context"
    21  	"net"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/cilium/cilium/pkg/completion"
    26  	"github.com/cilium/cilium/pkg/datapath"
    27  	"github.com/cilium/cilium/pkg/endpoint"
    28  	"github.com/cilium/cilium/pkg/endpoint/regeneration"
    29  	"github.com/cilium/cilium/pkg/identity"
    30  	"github.com/cilium/cilium/pkg/identity/cache"
    31  	"github.com/cilium/cilium/pkg/ipcache"
    32  	"github.com/cilium/cilium/pkg/labels"
    33  	"github.com/cilium/cilium/pkg/lock"
    34  	monitorAPI "github.com/cilium/cilium/pkg/monitor/api"
    35  	"github.com/cilium/cilium/pkg/option"
    36  	"github.com/cilium/cilium/pkg/policy"
    37  	"github.com/cilium/cilium/pkg/policy/api"
    38  	"github.com/cilium/cilium/pkg/revert"
    39  	"github.com/cilium/cilium/pkg/source"
    40  
    41  	"github.com/miekg/dns"
    42  	. "gopkg.in/check.v1"
    43  )
    44  
    45  // Hook up gocheck into the "go test" runner.
    46  func Test(t *testing.T) {
    47  	TestingT(t)
    48  }
    49  
    50  type DNSProxyTestSuite struct {
    51  	repo         *policy.Repository
    52  	dnsTCPClient *dns.Client
    53  	dnsServer    *dns.Server
    54  	proxy        *DNSProxy
    55  }
    56  
    57  func (s *DNSProxyTestSuite) GetPolicyRepository() *policy.Repository {
    58  	return s.repo
    59  }
    60  
    61  func (s *DNSProxyTestSuite) GetProxyPort(l7Type policy.L7ParserType, ingress bool) (uint16, string, error) {
    62  	return 0, "", nil
    63  }
    64  
    65  func (s *DNSProxyTestSuite) UpdateProxyRedirect(e regeneration.EndpointUpdater, l4 *policy.L4Filter, wg *completion.WaitGroup) (uint16, error, revert.FinalizeFunc, revert.RevertFunc) {
    66  	return 0, nil, nil, nil
    67  }
    68  
    69  func (s *DNSProxyTestSuite) RemoveProxyRedirect(e regeneration.EndpointInfoSource, id string, wg *completion.WaitGroup) (error, revert.FinalizeFunc, revert.RevertFunc) {
    70  	return nil, nil, nil
    71  }
    72  
    73  func (s *DNSProxyTestSuite) UpdateNetworkPolicy(e regeneration.EndpointUpdater, policy *policy.L4Policy,
    74  	proxyWaitGroup *completion.WaitGroup) (error, revert.RevertFunc) {
    75  	return nil, nil
    76  }
    77  
    78  func (s *DNSProxyTestSuite) RemoveNetworkPolicy(e regeneration.EndpointInfoSource) {}
    79  
    80  func (s *DNSProxyTestSuite) QueueEndpointBuild(ctx context.Context, epID uint64) (func(), error) {
    81  	return nil, nil
    82  }
    83  
    84  func (s *DNSProxyTestSuite) RemoveFromEndpointQueue(epID uint64) {}
    85  
    86  func (s *DNSProxyTestSuite) GetCompilationLock() *lock.RWMutex {
    87  	return nil
    88  }
    89  
    90  func (s *DNSProxyTestSuite) SendNotification(typ monitorAPI.AgentNotification, text string) error {
    91  	return nil
    92  }
    93  
    94  func (s *DNSProxyTestSuite) Datapath() datapath.Datapath {
    95  	return nil
    96  }
    97  
    98  func (s *DNSProxyTestSuite) GetNodeSuffix() string {
    99  	return ""
   100  }
   101  
   102  func (s *DNSProxyTestSuite) UpdateIdentities(added, deleted cache.IdentityCache) {}
   103  
   104  var _ = Suite(&DNSProxyTestSuite{})
   105  
   106  func setupServer(c *C) (dnsServer *dns.Server) {
   107  	waitOnListen := make(chan struct{})
   108  	dnsServer = &dns.Server{Addr: ":0", Net: "tcp", NotifyStartedFunc: func() { close(waitOnListen) }}
   109  	go dnsServer.ListenAndServe()
   110  	dns.HandleFunc(".", serveDNS)
   111  
   112  	select {
   113  	case <-waitOnListen:
   114  		return dnsServer
   115  
   116  	case <-time.After(10 * time.Second):
   117  		c.Error("DNS server did not start listening")
   118  	}
   119  
   120  	return nil
   121  }
   122  
   123  func teardown(dnsServer *dns.Server) {
   124  	dnsServer.Listener.Close()
   125  }
   126  
   127  func serveDNS(w dns.ResponseWriter, r *dns.Msg) {
   128  	m := new(dns.Msg)
   129  	m.SetReply(r)
   130  
   131  	retARR, err := dns.NewRR(m.Question[0].Name + " 60 IN A 1.1.1.1")
   132  	if err != nil {
   133  		panic(err)
   134  	}
   135  	m.Answer = append(m.Answer, retARR)
   136  
   137  	w.WriteMsg(m)
   138  }
   139  
   140  type DummySelectorCacheUser struct{}
   141  
   142  func (d *DummySelectorCacheUser) IdentitySelectionUpdated(selector policy.CachedSelector, selections, added, deleted []identity.NumericIdentity) {
   143  }
   144  
   145  // Setup identities, ports and endpoint IDs we will need
   146  var (
   147  	testSelectorCache       = policy.NewSelectorCache(cache.GetIdentityCache())
   148  	dummySelectorCacheUser  = &DummySelectorCacheUser{}
   149  	DstID1Selector          = api.NewESFromLabels(labels.ParseSelectLabel("k8s:Dst1=test"))
   150  	cachedDstID1Selector, _ = testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, DstID1Selector)
   151  	DstID2Selector          = api.NewESFromLabels(labels.ParseSelectLabel("k8s:Dst2=test"))
   152  	cachedDstID2Selector, _ = testSelectorCache.AddIdentitySelector(dummySelectorCacheUser, DstID2Selector)
   153  
   154  	epID1   = uint64(111)
   155  	epID2   = uint64(222)
   156  	epID3   = uint64(333)
   157  	dstID1  = identity.NumericIdentity(1001)
   158  	dstID2  = identity.NumericIdentity(2002)
   159  	dstPort = uint16(53) // Set below when we setup the server!
   160  )
   161  
   162  func (s *DNSProxyTestSuite) SetUpSuite(c *C) {
   163  	// Add these identities
   164  	testSelectorCache.UpdateIdentities(cache.IdentityCache{
   165  		dstID1: labels.Labels{"Dst1": labels.NewLabel("Dst1", "test", labels.LabelSourceK8s)}.LabelArray(),
   166  		dstID2: labels.Labels{"Dst2": labels.NewLabel("Dst2", "test", labels.LabelSourceK8s)}.LabelArray(),
   167  	}, nil)
   168  
   169  	s.repo = policy.NewPolicyRepository()
   170  	s.dnsTCPClient = &dns.Client{Net: "tcp", Timeout: 100 * time.Millisecond, SingleInflight: true}
   171  	s.dnsServer = setupServer(c)
   172  	c.Assert(s.dnsServer, Not(IsNil), Commentf("unable to setup DNS server"))
   173  
   174  	proxy, err := StartDNSProxy("", 0,
   175  		// LookupEPByIP
   176  		func(ip net.IP) (*endpoint.Endpoint, error) {
   177  			return endpoint.NewEndpointWithState(s, uint16(epID1), endpoint.StateReady), nil
   178  		},
   179  		// LookupSecIDByIP
   180  		func(ip net.IP) (ipcache.Identity, bool, error) {
   181  			DNSServerListenerAddr := (s.dnsServer.Listener.Addr()).(*net.TCPAddr)
   182  			switch {
   183  			case ip.String() == DNSServerListenerAddr.IP.String():
   184  				ident := ipcache.Identity{
   185  					ID:     dstID1,
   186  					Source: source.Unspec}
   187  				return ident, true, nil
   188  			default:
   189  				ident := ipcache.Identity{
   190  					ID:     dstID2,
   191  					Source: source.Unspec}
   192  				return ident, true, nil
   193  			}
   194  		},
   195  		// NotifyOnDNSMsg
   196  		func(lookupTime time.Time, ep *endpoint.Endpoint, epIPPort string, dstAddr string, msg *dns.Msg, protocol string, allowed bool, stat ProxyRequestContext) error {
   197  			return nil
   198  		})
   199  	c.Assert(err, IsNil, Commentf("error starting DNS Proxy"))
   200  	s.proxy = proxy
   201  
   202  	// This is here because Listener or Listeer.Addr() was nil. The
   203  	// lookupTargetDNSServer function doesn't need to change the target.
   204  	c.Assert(s.dnsServer.Listener, Not(IsNil), Commentf("DNS server missing a Listener"))
   205  	DNSServerListenerAddr := (s.dnsServer.Listener.Addr()).(*net.TCPAddr)
   206  	c.Assert(DNSServerListenerAddr, Not(IsNil), Commentf("DNS server missing a Listener address"))
   207  	s.proxy.lookupTargetDNSServer = func(w dns.ResponseWriter) (serverIP net.IP, serverPort uint16, addrStr string, err error) {
   208  		return DNSServerListenerAddr.IP, uint16(DNSServerListenerAddr.Port), DNSServerListenerAddr.String(), nil
   209  	}
   210  	dstPort = uint16(DNSServerListenerAddr.Port)
   211  }
   212  
   213  func (s *DNSProxyTestSuite) TearDownTest(c *C) {
   214  	s.proxy.allowed = make(perEPAllow)
   215  	s.proxy.SetRejectReply(option.FQDNProxyDenyWithRefused)
   216  }
   217  
   218  func (s *DNSProxyTestSuite) TearDownSuite(c *C) {
   219  	s.dnsServer.Listener.Close()
   220  	s.proxy.UDPServer.Shutdown()
   221  	s.proxy.TCPServer.Shutdown()
   222  }
   223  
   224  func (s *DNSProxyTestSuite) TestRejectFromDifferentEndpoint(c *C) {
   225  	name := "cilium.io."
   226  	l7map := policy.L7DataMap{
   227  		cachedDstID1Selector: api.L7Rules{
   228  			DNS: []api.PortRuleDNS{{MatchName: name}},
   229  		},
   230  	}
   231  	query := name
   232  
   233  	// Reject a query from not endpoint 1
   234  	err := s.proxy.UpdateAllowed(epID1, dstPort, l7map)
   235  	c.Assert(err, Equals, nil, Commentf("Could not update with rules"))
   236  	allowed := s.proxy.CheckAllowed(epID2, dstPort, dstID1, query)
   237  	c.Assert(allowed, Equals, false, Commentf("request was not rejected when it should be blocked"))
   238  }
   239  
   240  func (s *DNSProxyTestSuite) TestAcceptFromMatchingEndpoint(c *C) {
   241  	name := "cilium.io."
   242  	l7map := policy.L7DataMap{
   243  		cachedDstID1Selector: api.L7Rules{
   244  			DNS: []api.PortRuleDNS{{MatchName: name}},
   245  		},
   246  	}
   247  	query := name
   248  
   249  	// accept a query that matches from endpoint1
   250  	err := s.proxy.UpdateAllowed(epID1, dstPort, l7map)
   251  	c.Assert(err, Equals, nil, Commentf("Could not update with rules"))
   252  	allowed := s.proxy.CheckAllowed(epID1, dstPort, dstID1, query)
   253  	c.Assert(allowed, Equals, true, Commentf("request was rejected when it should be allowed"))
   254  }
   255  
   256  func (s *DNSProxyTestSuite) TestAcceptNonRegex(c *C) {
   257  	name := "simple.io."
   258  	l7map := policy.L7DataMap{
   259  		cachedDstID1Selector: api.L7Rules{
   260  			DNS: []api.PortRuleDNS{{MatchName: name}},
   261  		},
   262  	}
   263  	query := name
   264  
   265  	// accept a query that matches from endpoint1
   266  	err := s.proxy.UpdateAllowed(epID1, dstPort, l7map)
   267  	c.Assert(err, Equals, nil, Commentf("Could not update with rules"))
   268  	allowed := s.proxy.CheckAllowed(epID1, dstPort, dstID1, query)
   269  	c.Assert(allowed, Equals, true, Commentf("request was rejected when it should be allowed"))
   270  }
   271  
   272  func (s *DNSProxyTestSuite) TestRejectNonRegex(c *C) {
   273  	name := "cilium.io."
   274  	l7map := policy.L7DataMap{
   275  		cachedDstID1Selector: api.L7Rules{
   276  			DNS: []api.PortRuleDNS{{MatchName: name}},
   277  		},
   278  	}
   279  	query := "ciliumXio."
   280  
   281  	// reject a query for a non-regex where a . is different (i.e. ensure simple FQDNs treat . as .)
   282  	err := s.proxy.UpdateAllowed(epID1, dstPort, l7map)
   283  	c.Assert(err, Equals, nil, Commentf("Could not update with rules"))
   284  	allowed := s.proxy.CheckAllowed(epID1, dstPort, dstID1, query)
   285  	c.Assert(allowed, Equals, false, Commentf("request was not rejected when it should be blocked"))
   286  }
   287  
   288  func (s *DNSProxyTestSuite) TestRejectNonMatchingRefusedResponse(c *C) {
   289  	name := "cilium.io."
   290  	l7map := policy.L7DataMap{
   291  		cachedDstID1Selector: api.L7Rules{
   292  			DNS: []api.PortRuleDNS{{MatchName: name}},
   293  		},
   294  	}
   295  	query := "notcilium.io."
   296  
   297  	err := s.proxy.UpdateAllowed(epID1, dstPort, l7map)
   298  	c.Assert(err, Equals, nil, Commentf("Could not update with rules"))
   299  	allowed := s.proxy.CheckAllowed(epID1, dstPort, dstID1, query)
   300  	c.Assert(allowed, Equals, false, Commentf("request was not rejected when it should be blocked"))
   301  
   302  	request := new(dns.Msg)
   303  	request.SetQuestion(query, dns.TypeA)
   304  
   305  	// reject a query with NXDomain
   306  	s.proxy.SetRejectReply(option.FQDNProxyDenyWithNameError)
   307  	response, _, _ := s.dnsTCPClient.Exchange(request, s.proxy.TCPServer.Listener.Addr().String())
   308  	c.Assert(response.Rcode, Equals, dns.RcodeNameError, Commentf("DNS request from test client was not rejected when it should be blocked"))
   309  
   310  	// reject a query with Refused
   311  	s.proxy.SetRejectReply(option.FQDNProxyDenyWithRefused)
   312  	response, _, _ = s.dnsTCPClient.Exchange(request, s.proxy.TCPServer.Listener.Addr().String())
   313  	c.Assert(response.Rcode, Equals, dns.RcodeRefused, Commentf("DNS request from test client was not rejected when it should be blocked"))
   314  
   315  }
   316  
   317  func (s *DNSProxyTestSuite) TestRespondViaCorrectProtocol(c *C) {
   318  	// Respond with an actual answer for the query. This also tests that the
   319  	// connection was forwarded via the correct protocol (tcp/udp) because we
   320  	// connet with TCP, and the server only listens on TCP.
   321  
   322  	name := "cilium.io."
   323  	l7map := policy.L7DataMap{
   324  		cachedDstID1Selector: api.L7Rules{
   325  			DNS: []api.PortRuleDNS{{MatchName: name}},
   326  		},
   327  	}
   328  	query := name
   329  
   330  	err := s.proxy.UpdateAllowed(epID1, dstPort, l7map)
   331  	c.Assert(err, Equals, nil, Commentf("Could not update with rules"))
   332  	allowed := s.proxy.CheckAllowed(epID1, dstPort, dstID1, query)
   333  	c.Assert(allowed, Equals, true, Commentf("request was rejected when it should be allowed"))
   334  
   335  	request := new(dns.Msg)
   336  	request.SetQuestion(query, dns.TypeA)
   337  	response, _, err := s.dnsTCPClient.Exchange(request, s.proxy.TCPServer.Listener.Addr().String())
   338  	c.Assert(err, IsNil, Commentf("DNS request from test client failed when it should succeed"))
   339  	c.Assert(len(response.Answer), Equals, 1, Commentf("Proxy returned incorrect number of answer RRs %s", response))
   340  	c.Assert(response.Answer[0].String(), Equals, "cilium.io.\t60\tIN\tA\t1.1.1.1", Commentf("Proxy returned incorrect RRs"))
   341  
   342  }
   343  
   344  func (s *DNSProxyTestSuite) TestRespondMixedCaseInRequestResponse(c *C) {
   345  	// Test that mixed case query is allowed out and then back in to support
   346  	// high-order-bit query uniqueing schemes (and a data exfiltration
   347  	// vector :( )
   348  	name := "cilium.io."
   349  	l7map := policy.L7DataMap{
   350  		cachedDstID1Selector: api.L7Rules{
   351  			DNS: []api.PortRuleDNS{{MatchName: name}},
   352  		},
   353  	}
   354  	query := "CILIUM.io."
   355  
   356  	err := s.proxy.UpdateAllowed(epID1, dstPort, l7map)
   357  	c.Assert(err, Equals, nil, Commentf("Could not update with rules"))
   358  	allowed := s.proxy.CheckAllowed(epID1, dstPort, dstID1, query)
   359  	c.Assert(allowed, Equals, true, Commentf("request was rejected when it should be allowed"))
   360  
   361  	request := new(dns.Msg)
   362  	request.SetQuestion(query, dns.TypeA)
   363  	response, _, err := s.dnsTCPClient.Exchange(request, s.proxy.TCPServer.Listener.Addr().String())
   364  	c.Assert(err, IsNil, Commentf("DNS request from test client failed when it should succeed"))
   365  	c.Assert(len(response.Answer), Equals, 1, Commentf("Proxy returned incorrect number of answer RRs %s", response))
   366  	c.Assert(response.Answer[0].String(), Equals, "CILIUM.io.\t60\tIN\tA\t1.1.1.1", Commentf("Proxy returned incorrect RRs"))
   367  
   368  	request.SetQuestion("ciliuM.io.", dns.TypeA)
   369  	response, _, err = s.dnsTCPClient.Exchange(request, s.proxy.TCPServer.Listener.Addr().String())
   370  	c.Assert(err, IsNil, Commentf("DNS request from test client failed when it should succeed"))
   371  	c.Assert(len(response.Answer), Equals, 1, Commentf("Proxy returned incorrect number of answer RRs %+v", response.Answer))
   372  	c.Assert(response.Answer[0].String(), Equals, "ciliuM.io.\t60\tIN\tA\t1.1.1.1", Commentf("Proxy returned incorrect RRs"))
   373  }
   374  
   375  func (s *DNSProxyTestSuite) TestCheckAllowedTwiceRemovedOnce(c *C) {
   376  	name := "cilium.io."
   377  	l7map := policy.L7DataMap{
   378  		cachedDstID1Selector: api.L7Rules{
   379  			DNS: []api.PortRuleDNS{{MatchName: name}},
   380  		},
   381  	}
   382  	query := name
   383  
   384  	// Add the rule twice
   385  	err := s.proxy.UpdateAllowed(epID1, dstPort, l7map)
   386  	c.Assert(err, Equals, nil, Commentf("Could not update with rules"))
   387  	err = s.proxy.UpdateAllowed(epID1, dstPort, l7map)
   388  	c.Assert(err, Equals, nil, Commentf("Could not update with rules"))
   389  	allowed := s.proxy.CheckAllowed(epID1, dstPort, dstID1, query)
   390  	c.Assert(allowed, Equals, true, Commentf("request was rejected when it should be allowed"))
   391  
   392  	// Delete once, it should reject
   393  	err = s.proxy.UpdateAllowed(epID1, dstPort, nil)
   394  	c.Assert(err, Equals, nil, Commentf("Could not update with rules"))
   395  	allowed = s.proxy.CheckAllowed(epID1, dstPort, dstID1, query)
   396  	c.Assert(allowed, Equals, false, Commentf("request was allowed when it should be rejected"))
   397  
   398  	// Delete once, it should reject and not crash
   399  	err = s.proxy.UpdateAllowed(epID1, dstPort, nil)
   400  	c.Assert(err, Equals, nil, Commentf("Could not update with rules"))
   401  	allowed = s.proxy.CheckAllowed(epID1, dstPort, dstID1, query)
   402  	c.Assert(allowed, Equals, false, Commentf("request was allowed when it should be rejected"))
   403  }
   404  
   405  func (s *DNSProxyTestSuite) TestFullPathDependence(c *C) {
   406  	// Test that we consider each of endpoint ID, destination SecID (via the
   407  	// selector in L7DataMap), destination port (set in the redirect itself) and
   408  	// the DNS name.
   409  	// The rules approximate:
   410  	// +------+--------+---------+----------------+
   411  	// | From |   To   | DstPort |    DNSNames    |
   412  	// +======+========+=========+================+
   413  	// | EP1  | DstID1 |      53 | *.ubuntu.com   |
   414  	// | EP1  | DstID1 |      53 | aws.amazon.com |
   415  	// | EP1  | DstID2 |      53 | cilium.io      |
   416  	// | EP1  | DstID1 |      54 | example.com    |
   417  	// | EP3  | DstID1 |      53 | example.com    |
   418  	// +------+--------+---------+----------------+
   419  	//
   420  	// Cases:
   421  	// +------+-------+--------+------+----------------+----------+----------------------------------------------------------------+
   422  	// | Case | From  |   To   | Port |     Query      | Outcome  |                             Reason                             |
   423  	// +------+-------+--------+------+----------------+----------+----------------------------------------------------------------+
   424  	// |    1 | EPID1 | DstID1 |   53 | www.ubuntu.com | Allowed  |                                                                |
   425  	// |    2 | EPID1 | DstID1 |   54 | cilium.io      | Rejected | Port 54 only allows example.com                                |
   426  	// |    3 | EPID1 | DstID2 |   53 | cilium.io      | Allowed  |                                                                |
   427  	// |    4 | EPID1 | DstID2 |   53 | aws.amazon.com | Rejected | Only cilium.io is allowed with DstID2                          |
   428  	// |    5 | EPID1 | DstID1 |   54 | example.com    | Allowed  |                                                                |
   429  	// |    6 | EPID2 | DstID1 |   53 | cilium.io      | Rejected | EPID2 is not allowed as a source by any policy                 |
   430  	// |    7 | EPID3 | DstID1 |   53 | example.com    | Allowed  |                                                                |
   431  	// |    8 | EPID3 | DstID1 |   53 | aws.amazon.com | Rejected | EPID3 is only allowed to ask DstID1 on Port 53 for example.com |
   432  	// |    8 | EPID3 | DstID1 |   54 | example.com    | Rejected | EPID3 is only allowed to ask DstID1 on Port 53 for example.com |
   433  	// |    9 | EPID3 | DstID2 |   53 | example.com    | Rejected | EPID3 is only allowed to ask DstID1 on Port 53 for example.com |
   434  	// +------+-------+--------+------+----------------+----------+----------------------------------------------------------------+
   435  
   436  	// Setup rules
   437  	//	| EP1  | DstID1 |      53 | *.ubuntu.com   |
   438  	//	| EP1  | DstID1 |      53 | aws.amazon.com |
   439  	//	| EP1  | DstID2 |      53 | cilium.io      |
   440  	err := s.proxy.UpdateAllowed(epID1, 53, policy.L7DataMap{
   441  		cachedDstID1Selector: api.L7Rules{
   442  			DNS: []api.PortRuleDNS{
   443  				{MatchPattern: "*.ubuntu.com."},
   444  				{MatchPattern: "aws.amazon.com."},
   445  			},
   446  		},
   447  		cachedDstID2Selector: api.L7Rules{
   448  			DNS: []api.PortRuleDNS{
   449  				{MatchPattern: "cilium.io."},
   450  			},
   451  		},
   452  	})
   453  	c.Assert(err, Equals, nil, Commentf("Could not update with port 53 rules"))
   454  
   455  	//	| EP1  | DstID1 |      54 | example.com    |
   456  	err = s.proxy.UpdateAllowed(epID1, 54, policy.L7DataMap{
   457  		cachedDstID1Selector: api.L7Rules{
   458  			DNS: []api.PortRuleDNS{
   459  				{MatchPattern: "example.com."},
   460  			},
   461  		},
   462  	})
   463  	c.Assert(err, Equals, nil, Commentf("Could not update with rules"))
   464  
   465  	// | EP3  | DstID1 |      53 | example.com    |
   466  	err = s.proxy.UpdateAllowed(epID3, 53, policy.L7DataMap{
   467  		cachedDstID1Selector: api.L7Rules{
   468  			DNS: []api.PortRuleDNS{
   469  				{MatchPattern: "example.com."},
   470  			},
   471  		},
   472  	})
   473  	c.Assert(err, Equals, nil, Commentf("Could not update with rules"))
   474  
   475  	// Test cases
   476  	// Case 1 | EPID1 | DstID1 |   53 | www.ubuntu.com | Allowed
   477  	allowed := s.proxy.CheckAllowed(epID1, 53, dstID1, "www.ubuntu.com")
   478  	c.Assert(allowed, Equals, true, Commentf("request was rejected when it should be allowed"))
   479  
   480  	// Case 2 | EPID1 | DstID1 |   54 | cilium.io      | Rejected | Port 54 only allows example.com
   481  	allowed = s.proxy.CheckAllowed(epID1, 54, dstID1, "cilium.io")
   482  	c.Assert(allowed, Equals, false, Commentf("request was allowed when it should be rejected"))
   483  
   484  	// Case 3 | EPID1 | DstID2 |   53 | cilium.io      | Allowed
   485  	allowed = s.proxy.CheckAllowed(epID1, 53, dstID2, "cilium.io")
   486  	c.Assert(allowed, Equals, true, Commentf("request was rejected when it should be allowed"))
   487  
   488  	// Case 4 | EPID1 | DstID2 |   53 | aws.amazon.com | Rejected | Only cilium.io is allowed with DstID2
   489  	allowed = s.proxy.CheckAllowed(epID1, 53, dstID2, "aws.amazon.com")
   490  	c.Assert(allowed, Equals, false, Commentf("request was allowed when it should be rejected"))
   491  
   492  	// Case 5 | EPID1 | DstID1 |   54 | example.com    | Allowed
   493  	allowed = s.proxy.CheckAllowed(epID1, 54, dstID1, "example.com")
   494  	c.Assert(allowed, Equals, true, Commentf("request was rejected when it should be allowed"))
   495  
   496  	// Case 6 | EPID2 | DstID1 |   53 | cilium.io      | Rejected | EPID2 is not allowed as a source by any policy
   497  	allowed = s.proxy.CheckAllowed(epID2, 53, dstID1, "cilium.io")
   498  	c.Assert(allowed, Equals, false, Commentf("request was allowed when it should be rejected"))
   499  
   500  	// Case 7 | EPID3 | DstID1 |   53 | example.com    | Allowed
   501  	allowed = s.proxy.CheckAllowed(epID3, 53, dstID1, "example.com")
   502  	c.Assert(allowed, Equals, true, Commentf("request was rejected when it should be allowed"))
   503  
   504  	// Case 8 | EPID3 | DstID1 |   53 | aws.amazon.com | Rejected | EPID3 is only allowed to ask DstID1 on Port 53 for example.com
   505  	allowed = s.proxy.CheckAllowed(epID3, 53, dstID1, "aws.amazon.io")
   506  	c.Assert(allowed, Equals, false, Commentf("request was allowed when it should be rejected"))
   507  
   508  	// Case 8 | EPID3 | DstID1 |   54 | example.com    | Rejected | EPID3 is only allowed to ask DstID1 on Port 53 for example.com
   509  	allowed = s.proxy.CheckAllowed(epID3, 54, dstID1, "example.com")
   510  	c.Assert(allowed, Equals, false, Commentf("request was allowed when it should be rejected"))
   511  
   512  	// Case 9 | EPID3 | DstID2 |   53 | example.com    | Rejected | EPID3 is only allowed to ask DstID1 on Port 53 for example.com
   513  	allowed = s.proxy.CheckAllowed(epID3, 53, dstID2, "example.com")
   514  	c.Assert(allowed, Equals, false, Commentf("request was allowed when it should be rejected"))
   515  }