github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/core/network/firewall/rule_test.go (about) 1 // Copyright 2020 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package firewall 5 6 import ( 7 "github.com/juju/testing" 8 jc "github.com/juju/testing/checkers" 9 gc "gopkg.in/check.v1" 10 11 "github.com/juju/juju/core/network" 12 ) 13 14 var _ = gc.Suite(&IngressRuleSuite{}) 15 16 type IngressRuleSuite struct { 17 testing.IsolationSuite 18 } 19 20 func (IngressRuleSuite) TestRuleFormatting(c *gc.C) { 21 pr := network.MustParsePortRange("8080-9090/tcp") 22 r1 := NewIngressRule(pr) 23 c.Assert(r1.PortRange, gc.Equals, pr) 24 c.Assert(r1.SourceCIDRs, gc.HasLen, 0) 25 c.Assert(r1.String(), gc.Equals, "8080-9090/tcp") 26 27 r2 := NewIngressRule(pr, "10.0.0.0/24", "0.0.0.0/0", "0.0.0.0/0") 28 c.Assert(r2.PortRange, gc.Equals, pr) 29 c.Assert(r2.SourceCIDRs, gc.HasLen, 2, gc.Commentf("expected ingress rule not to contain duplicate CIDRs")) 30 c.Assert(r2.String(), gc.Equals, "8080-9090/tcp from 0.0.0.0/0,10.0.0.0/24") 31 } 32 33 func (IngressRuleSuite) TestRuleValidation(c *gc.C) { 34 bogus := network.PortRange{ 35 Protocol: "gopher", 36 FromPort: 1, 37 ToPort: 1, 38 } 39 r1 := NewIngressRule(bogus) 40 c.Assert(r1.Validate(), gc.ErrorMatches, `.*invalid protocol "gopher", expected "tcp", "udp", or "icmp"`) 41 42 pr := network.MustParsePortRange("8080-9090/tcp") 43 r2 := NewIngressRule(pr, "bogus") 44 c.Assert(r2.Validate(), gc.ErrorMatches, ".*invalid CIDR address: bogus") 45 46 r3 := NewIngressRule(pr, "100.0.0.0/8") 47 c.Assert(r3.Validate(), jc.ErrorIsNil) 48 } 49 50 func (IngressRuleSuite) TestRuleEquality(c *gc.C) { 51 specs := []struct { 52 descr string 53 ruleA, ruleB IngressRule 54 exp bool 55 }{ 56 { 57 descr: "same port and CIDRs", 58 ruleA: NewIngressRule(network.MustParsePortRange("80/tcp"), "10.0.0.0/24", "192.168.0.0/24"), 59 ruleB: NewIngressRule(network.MustParsePortRange("80/tcp"), "192.168.0.0/24", "10.0.0.0/24"), 60 exp: true, 61 }, 62 { 63 descr: "same port different CIDRs", 64 ruleA: NewIngressRule(network.MustParsePortRange("80/tcp"), "10.0.0.0/24", "192.168.42.0/24"), 65 ruleB: NewIngressRule(network.MustParsePortRange("80/tcp"), "192.168.0.0/24", "10.0.0.0/24"), 66 exp: false, 67 }, 68 { 69 descr: "different port same CIDRs", 70 ruleA: NewIngressRule(network.MustParsePortRange("90/tcp"), "10.0.0.0/24", "192.168.0.0/24"), 71 ruleB: NewIngressRule(network.MustParsePortRange("80/tcp"), "192.168.0.0/24", "10.0.0.0/24"), 72 exp: false, 73 }, 74 } 75 76 for specIndex, spec := range specs { 77 c.Logf("%d) %s", specIndex, spec.descr) 78 got := spec.ruleA.EqualTo(spec.ruleB) 79 c.Assert(got, gc.Equals, spec.exp) 80 81 got = spec.ruleB.EqualTo(spec.ruleA) 82 c.Assert(got, gc.Equals, spec.exp) 83 } 84 } 85 86 func (IngressRuleSuite) TestRuleSorting(c *gc.C) { 87 rules := IngressRules{ 88 NewIngressRule(network.MustParsePortRange("10-100/udp"), "0.0.0.0/0", "192.168.1.0/24"), 89 NewIngressRule(network.MustParsePortRange("80-90/tcp"), "0.0.0.0/0", "192.168.1.0/24"), 90 NewIngressRule(network.MustParsePortRange("80-90/udp"), "0.0.0.0/0", "192.168.1.0/24"), 91 NewIngressRule(network.MustParsePortRange("80/tcp"), "0.0.0.0/0", "192.168.1.0/24"), 92 NewIngressRule(network.MustParsePortRange("80/tcp"), "0.0.0.0/0"), 93 } 94 rules.Sort() 95 96 exp := IngressRules{ 97 NewIngressRule(network.MustParsePortRange("80/tcp"), "0.0.0.0/0"), 98 NewIngressRule(network.MustParsePortRange("80/tcp"), "0.0.0.0/0", "192.168.1.0/24"), 99 NewIngressRule(network.MustParsePortRange("80-90/tcp"), "0.0.0.0/0", "192.168.1.0/24"), 100 NewIngressRule(network.MustParsePortRange("10-100/udp"), "0.0.0.0/0", "192.168.1.0/24"), 101 NewIngressRule(network.MustParsePortRange("80-90/udp"), "0.0.0.0/0", "192.168.1.0/24"), 102 } 103 104 c.Assert(rules, gc.DeepEquals, exp) 105 } 106 107 func (IngressRuleSuite) TestRulesEquality(c *gc.C) { 108 setA := IngressRules{ 109 NewIngressRule(network.MustParsePortRange("80/tcp"), "10.0.0.0/24", "192.168.0.0/24"), 110 NewIngressRule(network.MustParsePortRange("80/tcp"), "192.168.0.0/24", "10.0.0.0/24"), 111 } 112 setB := IngressRules{ 113 NewIngressRule(network.MustParsePortRange("80/tcp"), "192.168.0.0/24", "10.0.0.0/24"), 114 NewIngressRule(network.MustParsePortRange("80/tcp"), "10.0.0.0/24", "192.168.0.0/24"), 115 } 116 setC := IngressRules{ 117 NewIngressRule(network.MustParsePortRange("80/tcp"), "192.168.0.0/24", "10.0.0.0/24"), 118 NewIngressRule(network.MustParsePortRange("90/tcp"), "10.0.0.0/24", "192.168.0.0/24"), 119 } 120 121 c.Assert(setA.EqualTo(setB), jc.IsTrue) 122 c.Assert(setA.EqualTo(setC), jc.IsFalse) 123 c.Assert(setB.EqualTo(setC), jc.IsFalse) 124 } 125 126 func (IngressRuleSuite) TestUniqueRules(c *gc.C) { 127 in := IngressRules{ 128 NewIngressRule(network.MustParsePortRange("80/tcp"), "10.0.0.0/24", "192.168.0.0/24"), 129 NewIngressRule(network.MustParsePortRange("123/tcp"), "192.168.0.0/24", "10.0.0.0/24"), 130 NewIngressRule(network.MustParsePortRange("80/tcp"), "10.0.0.0/24", "192.168.0.0/24"), 131 } 132 133 exp := IngressRules{ 134 NewIngressRule(network.MustParsePortRange("80/tcp"), "10.0.0.0/24", "192.168.0.0/24"), 135 NewIngressRule(network.MustParsePortRange("123/tcp"), "192.168.0.0/24", "10.0.0.0/24"), 136 } 137 138 c.Assert(in.UniqueRules(), gc.DeepEquals, exp) 139 } 140 141 func (IngressRuleSuite) TestDiffOpenAll(c *gc.C) { 142 wanted := IngressRules{ 143 NewIngressRule(network.MustParsePortRange("80-90/tcp"), "0.0.0.0/0"), 144 NewIngressRule(network.MustParsePortRange("443/tcp"), "10.0.0.0/24", "192.168.1.0/24"), 145 NewIngressRule(network.MustParsePortRange("80-90/udp"), "0.0.0.0/0"), 146 } 147 wanted.Sort() 148 149 toOpen, toClose := IngressRules{}.Diff(wanted) 150 c.Assert(toClose, gc.HasLen, 0) 151 c.Assert(toOpen, jc.DeepEquals, wanted) 152 } 153 154 func (IngressRuleSuite) TestDiffCloseAll(c *gc.C) { 155 current := IngressRules{ 156 NewIngressRule(network.MustParsePortRange("80-90/tcp"), "0.0.0.0/0"), 157 NewIngressRule(network.MustParsePortRange("443/tcp"), "10.0.0.0/24", "192.168.1.0/24"), 158 NewIngressRule(network.MustParsePortRange("80-90/udp"), "0.0.0.0/0"), 159 } 160 current.Sort() 161 162 toOpen, toClose := current.Diff(nil) 163 c.Assert(toOpen, gc.HasLen, 0) 164 c.Assert(toClose, jc.DeepEquals, current) 165 } 166 167 func (IngressRuleSuite) TestDiffNoPortRangeOverlap(c *gc.C) { 168 current := IngressRules{ 169 NewIngressRule(network.MustParsePortRange("80-90/tcp"), "0.0.0.0/0"), 170 NewIngressRule(network.MustParsePortRange("443/tcp"), "10.0.0.0/24", "192.168.1.0/24"), 171 NewIngressRule(network.MustParsePortRange("80-90/udp"), "0.0.0.0/0"), 172 } 173 extra := IngressRules{ 174 NewIngressRule(network.MustParsePortRange("100-110/tcp"), "0.0.0.0/0"), 175 NewIngressRule(network.MustParsePortRange("8080/tcp"), "10.0.0.0/24", "192.168.1.0/24"), 176 NewIngressRule(network.MustParsePortRange("67/udp"), "0.0.0.0/0"), 177 } 178 179 wanted := append(current, extra...) 180 toOpen, toClose := current.Diff(wanted) 181 c.Assert(toClose, gc.HasLen, 0) 182 183 extra.Sort() 184 c.Assert(toOpen, jc.DeepEquals, extra) 185 } 186 187 func (IngressRuleSuite) TestPortRangeOverlapToOpen(c *gc.C) { 188 current := IngressRules{ 189 NewIngressRule(network.MustParsePortRange("80-90/tcp"), "10.0.0.0/24"), 190 NewIngressRule(network.MustParsePortRange("443/tcp"), "10.0.0.0/24", "192.168.1.0/24"), 191 NewIngressRule(network.MustParsePortRange("80-90/udp"), "0.0.0.0/0"), 192 } 193 extra := IngressRules{ 194 NewIngressRule(network.MustParsePortRange("80-90/tcp"), "192.168.1.0/24", "10.0.0.0/24"), 195 NewIngressRule(network.MustParsePortRange("8080/tcp"), "10.0.0.0/24", "192.168.1.0/24"), 196 NewIngressRule(network.MustParsePortRange("67/udp"), "0.0.0.0/0"), 197 } 198 wanted := append(current, extra...) 199 toOpen, toClose := current.Diff(wanted) 200 c.Assert(toClose, gc.HasLen, 0) 201 202 c.Assert(toOpen, jc.DeepEquals, IngressRules{ 203 NewIngressRule(network.MustParsePortRange("80-90/tcp"), "192.168.1.0/24"), 204 NewIngressRule(network.MustParsePortRange("8080/tcp"), "10.0.0.0/24", "192.168.1.0/24"), 205 NewIngressRule(network.MustParsePortRange("67/udp"), "0.0.0.0/0"), 206 }) 207 } 208 209 func (IngressRuleSuite) TestPortRangeOverlapToClose(c *gc.C) { 210 current := IngressRules{ 211 NewIngressRule(network.MustParsePortRange("80-90/tcp"), "10.0.0.0/24", "192.168.1.0/24"), 212 NewIngressRule(network.MustParsePortRange("443/tcp"), "10.0.0.0/24", "192.168.1.0/24"), 213 NewIngressRule(network.MustParsePortRange("80-90/udp"), "0.0.0.0/0"), 214 } 215 wanted := IngressRules{ 216 NewIngressRule(network.MustParsePortRange("80-90/tcp"), "10.0.0.0/24"), 217 NewIngressRule(network.MustParsePortRange("443/tcp"), "10.0.0.0/24", "192.168.1.0/24"), 218 NewIngressRule(network.MustParsePortRange("80-90/udp"), "0.0.0.0/0"), 219 } 220 221 toOpen, toClose := current.Diff(wanted) 222 c.Assert(toOpen, gc.HasLen, 0) 223 224 c.Assert(toClose, jc.DeepEquals, IngressRules{ 225 NewIngressRule(network.MustParsePortRange("80-90/tcp"), "192.168.1.0/24"), 226 }) 227 } 228 229 func (IngressRuleSuite) TestPortRangeOverlap(c *gc.C) { 230 current := IngressRules{ 231 NewIngressRule(network.MustParsePortRange("80-90/tcp"), "10.0.0.0/24", "192.168.1.0/24"), 232 NewIngressRule(network.MustParsePortRange("443/tcp"), "10.0.0.0/24", "192.168.1.0/24"), 233 } 234 wanted := IngressRules{ 235 NewIngressRule(network.MustParsePortRange("80-90/tcp"), "10.0.0.0/24"), 236 NewIngressRule(network.MustParsePortRange("443/tcp"), "10.0.0.0/24", "192.168.1.0/24"), 237 NewIngressRule(network.MustParsePortRange("80-90/udp"), "0.0.0.0/0"), 238 } 239 240 toOpen, toClose := current.Diff(wanted) 241 c.Assert(toOpen, jc.DeepEquals, IngressRules{ 242 NewIngressRule(network.MustParsePortRange("80-90/udp"), "0.0.0.0/0"), 243 }) 244 c.Assert(toClose, jc.DeepEquals, IngressRules{ 245 NewIngressRule(network.MustParsePortRange("80-90/tcp"), "192.168.1.0/24"), 246 }) 247 } 248 249 func (IngressRuleSuite) TestDiffRangesClosesPortsIfRulesAreDisjoint(c *gc.C) { 250 current := IngressRules{ 251 NewIngressRule(network.MustParsePortRange("3306/tcp"), "35.187.158.35/32"), 252 } 253 wanted := IngressRules{ 254 NewIngressRule(network.MustParsePortRange("3306/tcp"), "35.187.152.241/32"), 255 } 256 257 toOpen, toClose := current.Diff(wanted) 258 c.Assert(toOpen, gc.DeepEquals, wanted) 259 c.Assert(toClose, gc.DeepEquals, current) 260 } 261 262 func (IngressRuleSuite) TestRemoveCIDRsMatchingAddressType(c *gc.C) { 263 in := IngressRules{ 264 NewIngressRule(network.MustParsePortRange("80/tcp"), "35.187.158.35/32"), 265 // We expect these rules to be de-dupped once the IPV6 CIDRs get removed 266 NewIngressRule(network.MustParsePortRange("81/tcp"), "35.187.1.35/32", "::/0"), 267 NewIngressRule(network.MustParsePortRange("81/tcp"), "35.187.1.35/32", "2002::1234:abcd:ffff:c0a8:101/64"), 268 } 269 270 out := in.RemoveCIDRsMatchingAddressType(network.IPv6Address) 271 c.Assert(out, gc.DeepEquals, IngressRules{ 272 NewIngressRule(network.MustParsePortRange("80/tcp"), "35.187.158.35/32"), 273 NewIngressRule(network.MustParsePortRange("81/tcp"), "35.187.1.35/32"), 274 }) 275 }