github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/internal/enforcer/acls/aclcache_test.go (about)

     1  // +build !windows
     2  
     3  package acls
     4  
     5  import (
     6  	"net"
     7  	"testing"
     8  
     9  	. "github.com/smartystreets/goconvey/convey"
    10  	"go.aporeto.io/enforcerd/trireme-lib/controller/constants"
    11  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/packet"
    12  	"go.aporeto.io/enforcerd/trireme-lib/policy"
    13  )
    14  
    15  var catchAllPolicy = &policy.FlowPolicy{Action: policy.Reject | policy.Log, PolicyID: "default", ServiceID: "default"}
    16  
    17  func TestEmptyACLCacheLookup(t *testing.T) {
    18  
    19  	Convey("Given an empty ACL Cache", t, func() {
    20  		c := NewACLCache()
    21  		Convey("When I lookup for a matching address but failed port, I should get reject", func() {
    22  			ip := net.ParseIP("192.168.100.1")
    23  			port := uint16(600)
    24  			a, p, err := c.GetMatchingAction(ip.To4(), port, packet.IPProtocolTCP, catchAllPolicy)
    25  			So(err, ShouldNotBeNil)
    26  			So(a.Action&policy.Reject, ShouldEqual, policy.Reject)
    27  			So(a.PolicyID, ShouldEqual, "default")
    28  			So(p.Action&policy.Reject, ShouldEqual, policy.Reject)
    29  			So(p.ServiceID, ShouldEqual, "default")
    30  		})
    31  
    32  		Convey("When I lookup for a matching address but failed port, I should get accept", func() {
    33  			ip := net.ParseIP("192.168.100.1")
    34  			port := uint16(600)
    35  			defaultFlowPolcy := &policy.FlowPolicy{Action: policy.Accept | policy.Log, PolicyID: "default", ServiceID: "default"}
    36  			a, p, err := c.GetMatchingAction(ip.To4(), port, packet.IPProtocolTCP, defaultFlowPolcy)
    37  			So(err, ShouldBeNil)
    38  			So(a.Action&policy.Accept, ShouldEqual, policy.Accept)
    39  			So(a.PolicyID, ShouldEqual, "default")
    40  			So(p.Action&policy.Accept, ShouldEqual, policy.Accept)
    41  			So(p.ServiceID, ShouldEqual, "default")
    42  		})
    43  	})
    44  }
    45  
    46  func TestRejectPrioritizedOverAcceptCacheLookup(t *testing.T) {
    47  
    48  	rules = policy.IPRuleList{
    49  		policy.IPRule{
    50  			Addresses: []string{"172.0.0.0/8"},
    51  			Ports:     []string{"1"},
    52  			Protocols: []string{constants.TCPProtoNum},
    53  			Policy: &policy.FlowPolicy{
    54  				Action:   policy.Accept,
    55  				PolicyID: "tcp172/8"},
    56  		},
    57  		policy.IPRule{
    58  			Addresses: []string{"0.0.0.0/0"},
    59  			Ports:     []string{"1"},
    60  			Protocols: []string{constants.TCPProtoNum},
    61  			Policy: &policy.FlowPolicy{
    62  				Action:   policy.Reject,
    63  				PolicyID: "catchAllDrop"},
    64  		},
    65  	}
    66  
    67  	Convey("Given an ACL Cache with accept and reject rules", t, func() {
    68  		c := NewACLCache()
    69  		So(c, ShouldNotBeNil)
    70  		err := c.AddRuleList(rules)
    71  		So(err, ShouldBeNil)
    72  
    73  		Convey("When I lookup for a matching address to both accept and reject rule, I should get reject", func() {
    74  			ip := net.ParseIP("172.1.1.1")
    75  			port := uint16(1)
    76  			a, p, err := c.GetMatchingAction(ip.To4(), port, packet.IPProtocolTCP, catchAllPolicy)
    77  			So(err, ShouldBeNil)
    78  			So(a.Action, ShouldEqual, policy.Reject)
    79  			So(a.PolicyID, ShouldEqual, "catchAllDrop")
    80  			So(p.Action, ShouldEqual, policy.Reject)
    81  			So(p.PolicyID, ShouldEqual, "catchAllDrop")
    82  		})
    83  	})
    84  }
    85  
    86  func TestEmptyACLWithObserveContinueCacheLookup(t *testing.T) {
    87  
    88  	rules = policy.IPRuleList{
    89  		policy.IPRule{
    90  			Addresses: []string{"0.0.0.0/0"},
    91  			Ports:     []string{"1"},
    92  			Protocols: []string{constants.TCPProtoNum},
    93  			Policy: &policy.FlowPolicy{
    94  				Action:        policy.Accept,
    95  				ObserveAction: policy.ObserveContinue,
    96  				PolicyID:      "ObserveAcceptContinue"},
    97  		},
    98  	}
    99  
   100  	Convey("Given an empty ACL Cache", t, func() {
   101  		c := NewACLCache()
   102  		So(c, ShouldNotBeNil)
   103  		err := c.AddRuleList(rules)
   104  		So(err, ShouldBeNil)
   105  
   106  		Convey("When I lookup for a matching address, I should get accept", func() {
   107  			ip := net.ParseIP("192.168.100.1")
   108  			port := uint16(1)
   109  			a, p, err := c.GetMatchingAction(ip.To4(), port, packet.IPProtocolTCP, catchAllPolicy)
   110  			So(err, ShouldNotBeNil)
   111  			So(a.Action, ShouldEqual, policy.Accept)
   112  			So(a.PolicyID, ShouldEqual, "ObserveAcceptContinue")
   113  			So(p.Action&policy.Reject, ShouldEqual, policy.Reject)
   114  			So(p.PolicyID, ShouldEqual, "default")
   115  		})
   116  	})
   117  }
   118  
   119  func TestEmptyACLWithObserveApplyCacheLookup(t *testing.T) {
   120  
   121  	rules = policy.IPRuleList{
   122  		policy.IPRule{
   123  			Addresses: []string{"0.0.0.0/0"},
   124  			Ports:     []string{"1"},
   125  			Protocols: []string{constants.TCPProtoNum},
   126  			Policy: &policy.FlowPolicy{
   127  				Action:        policy.Accept,
   128  				ObserveAction: policy.ObserveApply,
   129  				PolicyID:      "observeAcceptApply"},
   130  		},
   131  	}
   132  
   133  	Convey("Given an empty ACL Cache", t, func() {
   134  		c := NewACLCache()
   135  		So(c, ShouldNotBeNil)
   136  		err := c.AddRuleList(rules)
   137  		So(err, ShouldBeNil)
   138  
   139  		Convey("When I lookup for a matching address, I should get accept", func() {
   140  			ip := net.ParseIP("192.168.100.1")
   141  			port := uint16(1)
   142  			a, p, err := c.GetMatchingAction(ip.To4(), port, packet.IPProtocolTCP, catchAllPolicy)
   143  			So(err, ShouldBeNil)
   144  			So(a.Action, ShouldEqual, policy.Accept)
   145  			So(a.PolicyID, ShouldEqual, "observeAcceptApply")
   146  			So(p.Action, ShouldEqual, policy.Accept)
   147  			So(p.PolicyID, ShouldEqual, "observeAcceptApply")
   148  		})
   149  	})
   150  }
   151  
   152  func TestObserveContinueApplyCacheLookup(t *testing.T) {
   153  
   154  	rules = policy.IPRuleList{
   155  		policy.IPRule{
   156  			Addresses: []string{"172.1.0.0/16"},
   157  			Ports:     []string{"1"},
   158  			Protocols: []string{constants.TCPProtoNum},
   159  			Policy: &policy.FlowPolicy{
   160  				Action:        policy.Reject,
   161  				ObserveAction: policy.ObserveContinue,
   162  				PolicyID:      "observeRejectContinue-172.1/16"},
   163  		},
   164  		policy.IPRule{
   165  			Addresses: []string{"172.0.0.0/8"},
   166  			Ports:     []string{"1"},
   167  			Protocols: []string{constants.TCPProtoNum},
   168  			Policy: &policy.FlowPolicy{
   169  				Action:   policy.Accept,
   170  				PolicyID: "tcp172/8"},
   171  		},
   172  		policy.IPRule{
   173  			Addresses: []string{"172.0.0.0/8"},
   174  			Ports:     []string{"1"},
   175  			Protocols: []string{constants.TCPProtoNum},
   176  			Policy: &policy.FlowPolicy{
   177  				Action:        policy.Accept,
   178  				ObserveAction: policy.ObserveApply,
   179  				PolicyID:      "observeRejectApply"},
   180  		},
   181  		policy.IPRule{
   182  			Addresses: []string{"172.0.0.0/8"},
   183  			Ports:     []string{"1"},
   184  			Protocols: []string{constants.TCPProtoNum},
   185  			Policy: &policy.FlowPolicy{
   186  				Action:        policy.Reject,
   187  				ObserveAction: policy.ObserveContinue,
   188  				PolicyID:      "observeRejectContinue"},
   189  		},
   190  	}
   191  
   192  	Convey("Given an ACL Cache with accept observe-apply and observe-continue rules for same prefix", t, func() {
   193  		c := NewACLCache()
   194  		So(c, ShouldNotBeNil)
   195  		err := c.AddRuleList(rules)
   196  		So(err, ShouldBeNil)
   197  
   198  		Convey("When I lookup for a matching address to /16, I should get report reject and packet accept and ignore observe-apply rule", func() {
   199  			ip := net.ParseIP("172.1.1.1")
   200  			port := uint16(1)
   201  			a, p, err := c.GetMatchingAction(ip.To4(), port, packet.IPProtocolTCP, catchAllPolicy)
   202  			So(err, ShouldBeNil)
   203  			So(a.Action, ShouldEqual, policy.Reject)
   204  			So(a.PolicyID, ShouldEqual, "observeRejectContinue-172.1/16")
   205  			// So(p.Action, ShouldEqual, policy.Accept)
   206  			So(p.PolicyID, ShouldEqual, "tcp172/8")
   207  		})
   208  
   209  		Convey("When I lookup for a matching address to /8, I should get report reject and packet accept and ignore observe-apply rule", func() {
   210  			ip := net.ParseIP("172.2.1.1")
   211  			port := uint16(1)
   212  			a, p, err := c.GetMatchingAction(ip.To4(), port, packet.IPProtocolTCP, catchAllPolicy)
   213  			So(err, ShouldBeNil)
   214  			So(a.Action, ShouldEqual, policy.Reject)
   215  			So(a.PolicyID, ShouldEqual, "observeRejectContinue")
   216  			So(p.Action, ShouldEqual, policy.Accept)
   217  			So(p.PolicyID, ShouldEqual, "tcp172/8")
   218  		})
   219  	})
   220  }
   221  
   222  func TestAcceptWithNomatchCacheLookup(t *testing.T) {
   223  
   224  	rules = policy.IPRuleList{
   225  		policy.IPRule{
   226  			Addresses: []string{"0.0.0.0/1", "!10.10.10.0/24", "128.0.0.0/1", "!10.0.0.0/8", "10.10.0.0/16"},
   227  			Ports:     []string{"0:65535"},
   228  			Protocols: []string{constants.TCPProtoNum},
   229  			Policy: &policy.FlowPolicy{
   230  				Action: policy.Accept,
   231  			},
   232  		},
   233  	}
   234  
   235  	Convey("Given an ACL Cache with accept policy with some nomatch addresses", t, func() {
   236  		c := NewACLCache()
   237  		So(c, ShouldNotBeNil)
   238  		err := c.AddRuleList(rules)
   239  		So(err, ShouldBeNil)
   240  
   241  		Convey("When I lookup address within nomatch outer but also within match inner, I should get accept", func() {
   242  			ip := net.ParseIP("10.10.2.100")
   243  			port := uint16(443)
   244  			a, p, err := c.GetMatchingAction(ip.To4(), port, packet.IPProtocolTCP, catchAllPolicy)
   245  			So(err, ShouldBeNil)
   246  			So(a.Action, ShouldEqual, policy.Accept)
   247  			So(p.Action, ShouldEqual, policy.Accept)
   248  		})
   249  
   250  		Convey("When I lookup address within nomatch, I should get no match", func() {
   251  			ip := net.ParseIP("10.10.10.100")
   252  			port := uint16(443)
   253  			_, _, err := c.GetMatchingAction(ip.To4(), port, packet.IPProtocolTCP, catchAllPolicy)
   254  			So(err, ShouldNotBeNil)
   255  		})
   256  
   257  		Convey("When I lookup address within nomatch outer and not also within match inner, I should get no match", func() {
   258  			ip := net.ParseIP("10.4.10.100")
   259  			port := uint16(443)
   260  			_, _, err := c.GetMatchingAction(ip.To4(), port, packet.IPProtocolTCP, catchAllPolicy)
   261  			So(err, ShouldNotBeNil)
   262  		})
   263  
   264  		Convey("When I lookup address within match outer and not also within match inner, I should get accept", func() {
   265  			ip := net.ParseIP("192.168.10.100")
   266  			port := uint16(443)
   267  			a, p, err := c.GetMatchingAction(ip.To4(), port, packet.IPProtocolTCP, catchAllPolicy)
   268  			So(err, ShouldBeNil)
   269  			So(a.Action, ShouldEqual, policy.Accept)
   270  			So(p.Action, ShouldEqual, policy.Accept)
   271  		})
   272  	})
   273  }
   274  
   275  func TestRemoveRules(t *testing.T) {
   276  
   277  	Convey("Given an ACL Cache with some rules", t, func() {
   278  		ip := net.ParseIP("172.1.0.0")
   279  		So(ip, ShouldNotBeNil)
   280  		c := NewACLCache()
   281  		So(c, ShouldNotBeNil)
   282  		err := c.AddRuleList(policy.IPRuleList{
   283  			policy.IPRule{
   284  				Addresses: []string{"172.1.0.0/16"},
   285  				Ports:     []string{"1"},
   286  				Protocols: []string{constants.TCPProtoNum},
   287  				Policy: &policy.FlowPolicy{
   288  					Action:   policy.Reject,
   289  					PolicyID: "reject",
   290  				},
   291  			},
   292  			policy.IPRule{
   293  				Addresses: []string{"172.1.0.0/16"},
   294  				Ports:     []string{"1"},
   295  				Protocols: []string{constants.TCPProtoNum},
   296  				Policy: &policy.FlowPolicy{
   297  					ObserveAction: policy.ObserveApply,
   298  					PolicyID:      "observeApply",
   299  				},
   300  			},
   301  			policy.IPRule{
   302  				Addresses: []string{"172.1.0.0/16"},
   303  				Ports:     []string{"1"},
   304  				Protocols: []string{constants.TCPProtoNum},
   305  				Policy: &policy.FlowPolicy{
   306  					Action:   policy.Accept,
   307  					PolicyID: "accept",
   308  				},
   309  			},
   310  		})
   311  		So(err, ShouldBeNil)
   312  		val, ok := c.reject.tcpCache.Get(ip, 16)
   313  		So(ok, ShouldBeTrue)
   314  		So(val.(portActionList), ShouldNotBeEmpty)
   315  		val, ok = c.observe.tcpCache.Get(ip, 16)
   316  		So(ok, ShouldBeTrue)
   317  		So(val.(portActionList), ShouldNotBeEmpty)
   318  		val, ok = c.accept.tcpCache.Get(ip, 16)
   319  		So(ok, ShouldBeTrue)
   320  		So(val.(portActionList), ShouldNotBeEmpty)
   321  
   322  		Convey("Then I should error if I pass unparseable rules", func() {
   323  			err := c.RemoveRulesForAddress(
   324  				&Address{IP: ip, Mask: 16, NoMatch: false},
   325  				constants.TCPProtoNum,
   326  				[]string{"invalid"},
   327  				&policy.FlowPolicy{
   328  					Action:   policy.Reject,
   329  					PolicyID: "reject",
   330  				},
   331  			)
   332  			So(err, ShouldNotBeNil)
   333  		})
   334  
   335  		Convey("Then I should be able to remove the rules", func() {
   336  			err := c.RemoveRulesForAddress(
   337  				&Address{IP: ip, Mask: 16, NoMatch: false},
   338  				constants.TCPProtoNum,
   339  				[]string{"1"},
   340  				&policy.FlowPolicy{
   341  					Action:   policy.Reject,
   342  					PolicyID: "reject",
   343  				},
   344  			)
   345  			So(err, ShouldBeNil)
   346  			err = c.RemoveRulesForAddress(
   347  				&Address{IP: ip, Mask: 16, NoMatch: false},
   348  				constants.TCPProtoNum,
   349  				[]string{"1"},
   350  				&policy.FlowPolicy{
   351  					ObserveAction: policy.ObserveApply,
   352  					PolicyID:      "observeApply",
   353  				},
   354  			)
   355  			So(err, ShouldBeNil)
   356  			err = c.RemoveRulesForAddress(
   357  				&Address{IP: ip, Mask: 16, NoMatch: false},
   358  				constants.TCPProtoNum,
   359  				[]string{"1"},
   360  				&policy.FlowPolicy{
   361  					Action:   policy.Accept,
   362  					PolicyID: "accept",
   363  				},
   364  			)
   365  			So(err, ShouldBeNil)
   366  			val, ok := c.reject.tcpCache.Get(ip, 16)
   367  			So(ok, ShouldBeTrue)
   368  			So(val.(portActionList), ShouldBeEmpty)
   369  			val, ok = c.observe.tcpCache.Get(ip, 16)
   370  			So(ok, ShouldBeTrue)
   371  			So(val.(portActionList), ShouldBeEmpty)
   372  			val, ok = c.accept.tcpCache.Get(ip, 16)
   373  			So(ok, ShouldBeTrue)
   374  			So(val.(portActionList), ShouldBeEmpty)
   375  		})
   376  
   377  	})
   378  }