|
@@ -2,14 +2,12 @@ package nebula
|
|
|
|
|
|
import (
|
|
import (
|
|
"bytes"
|
|
"bytes"
|
|
- "encoding/binary"
|
|
|
|
"errors"
|
|
"errors"
|
|
"math"
|
|
"math"
|
|
"net"
|
|
"net"
|
|
"testing"
|
|
"testing"
|
|
"time"
|
|
"time"
|
|
|
|
|
|
- "github.com/rcrowley/go-metrics"
|
|
|
|
"github.com/slackhq/nebula/cert"
|
|
"github.com/slackhq/nebula/cert"
|
|
"github.com/slackhq/nebula/config"
|
|
"github.com/slackhq/nebula/config"
|
|
"github.com/slackhq/nebula/firewall"
|
|
"github.com/slackhq/nebula/firewall"
|
|
@@ -163,44 +161,44 @@ func TestFirewall_Drop(t *testing.T) {
|
|
cp := cert.NewCAPool()
|
|
cp := cert.NewCAPool()
|
|
|
|
|
|
// Drop outbound
|
|
// Drop outbound
|
|
- assert.Equal(t, fw.Drop([]byte{}, p, false, &h, cp, nil), ErrNoMatchingRule)
|
|
|
|
|
|
+ assert.Equal(t, fw.Drop(p, false, &h, cp, nil), ErrNoMatchingRule)
|
|
// Allow inbound
|
|
// Allow inbound
|
|
resetConntrack(fw)
|
|
resetConntrack(fw)
|
|
- assert.NoError(t, fw.Drop([]byte{}, p, true, &h, cp, nil))
|
|
|
|
|
|
+ assert.NoError(t, fw.Drop(p, true, &h, cp, nil))
|
|
// Allow outbound because conntrack
|
|
// Allow outbound because conntrack
|
|
- assert.NoError(t, fw.Drop([]byte{}, p, false, &h, cp, nil))
|
|
|
|
|
|
+ assert.NoError(t, fw.Drop(p, false, &h, cp, nil))
|
|
|
|
|
|
// test remote mismatch
|
|
// test remote mismatch
|
|
oldRemote := p.RemoteIP
|
|
oldRemote := p.RemoteIP
|
|
p.RemoteIP = iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 10))
|
|
p.RemoteIP = iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 10))
|
|
- assert.Equal(t, fw.Drop([]byte{}, p, false, &h, cp, nil), ErrInvalidRemoteIP)
|
|
|
|
|
|
+ assert.Equal(t, fw.Drop(p, false, &h, cp, nil), ErrInvalidRemoteIP)
|
|
p.RemoteIP = oldRemote
|
|
p.RemoteIP = oldRemote
|
|
|
|
|
|
// ensure signer doesn't get in the way of group checks
|
|
// ensure signer doesn't get in the way of group checks
|
|
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
|
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
|
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"nope"}, "", nil, nil, "", "signer-shasum"))
|
|
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"nope"}, "", nil, nil, "", "signer-shasum"))
|
|
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"default-group"}, "", nil, nil, "", "signer-shasum-bad"))
|
|
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"default-group"}, "", nil, nil, "", "signer-shasum-bad"))
|
|
- assert.Equal(t, fw.Drop([]byte{}, p, true, &h, cp, nil), ErrNoMatchingRule)
|
|
|
|
|
|
+ assert.Equal(t, fw.Drop(p, true, &h, cp, nil), ErrNoMatchingRule)
|
|
|
|
|
|
// test caSha doesn't drop on match
|
|
// test caSha doesn't drop on match
|
|
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
|
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
|
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"nope"}, "", nil, nil, "", "signer-shasum-bad"))
|
|
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"nope"}, "", nil, nil, "", "signer-shasum-bad"))
|
|
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"default-group"}, "", nil, nil, "", "signer-shasum"))
|
|
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"default-group"}, "", nil, nil, "", "signer-shasum"))
|
|
- assert.NoError(t, fw.Drop([]byte{}, p, true, &h, cp, nil))
|
|
|
|
|
|
+ assert.NoError(t, fw.Drop(p, true, &h, cp, nil))
|
|
|
|
|
|
// ensure ca name doesn't get in the way of group checks
|
|
// ensure ca name doesn't get in the way of group checks
|
|
cp.CAs["signer-shasum"] = &cert.NebulaCertificate{Details: cert.NebulaCertificateDetails{Name: "ca-good"}}
|
|
cp.CAs["signer-shasum"] = &cert.NebulaCertificate{Details: cert.NebulaCertificateDetails{Name: "ca-good"}}
|
|
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
|
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
|
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"nope"}, "", nil, nil, "ca-good", ""))
|
|
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"nope"}, "", nil, nil, "ca-good", ""))
|
|
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"default-group"}, "", nil, nil, "ca-good-bad", ""))
|
|
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"default-group"}, "", nil, nil, "ca-good-bad", ""))
|
|
- assert.Equal(t, fw.Drop([]byte{}, p, true, &h, cp, nil), ErrNoMatchingRule)
|
|
|
|
|
|
+ assert.Equal(t, fw.Drop(p, true, &h, cp, nil), ErrNoMatchingRule)
|
|
|
|
|
|
// test caName doesn't drop on match
|
|
// test caName doesn't drop on match
|
|
cp.CAs["signer-shasum"] = &cert.NebulaCertificate{Details: cert.NebulaCertificateDetails{Name: "ca-good"}}
|
|
cp.CAs["signer-shasum"] = &cert.NebulaCertificate{Details: cert.NebulaCertificateDetails{Name: "ca-good"}}
|
|
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
|
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
|
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"nope"}, "", nil, nil, "ca-good-bad", ""))
|
|
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"nope"}, "", nil, nil, "ca-good-bad", ""))
|
|
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"default-group"}, "", nil, nil, "ca-good", ""))
|
|
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"default-group"}, "", nil, nil, "ca-good", ""))
|
|
- assert.NoError(t, fw.Drop([]byte{}, p, true, &h, cp, nil))
|
|
|
|
|
|
+ assert.NoError(t, fw.Drop(p, true, &h, cp, nil))
|
|
}
|
|
}
|
|
|
|
|
|
func BenchmarkFirewallTable_match(b *testing.B) {
|
|
func BenchmarkFirewallTable_match(b *testing.B) {
|
|
@@ -412,10 +410,10 @@ func TestFirewall_Drop2(t *testing.T) {
|
|
cp := cert.NewCAPool()
|
|
cp := cert.NewCAPool()
|
|
|
|
|
|
// h1/c1 lacks the proper groups
|
|
// h1/c1 lacks the proper groups
|
|
- assert.Error(t, fw.Drop([]byte{}, p, true, &h1, cp, nil), ErrNoMatchingRule)
|
|
|
|
|
|
+ assert.Error(t, fw.Drop(p, true, &h1, cp, nil), ErrNoMatchingRule)
|
|
// c has the proper groups
|
|
// c has the proper groups
|
|
resetConntrack(fw)
|
|
resetConntrack(fw)
|
|
- assert.NoError(t, fw.Drop([]byte{}, p, true, &h, cp, nil))
|
|
|
|
|
|
+ assert.NoError(t, fw.Drop(p, true, &h, cp, nil))
|
|
}
|
|
}
|
|
|
|
|
|
func TestFirewall_Drop3(t *testing.T) {
|
|
func TestFirewall_Drop3(t *testing.T) {
|
|
@@ -495,13 +493,13 @@ func TestFirewall_Drop3(t *testing.T) {
|
|
cp := cert.NewCAPool()
|
|
cp := cert.NewCAPool()
|
|
|
|
|
|
// c1 should pass because host match
|
|
// c1 should pass because host match
|
|
- assert.NoError(t, fw.Drop([]byte{}, p, true, &h1, cp, nil))
|
|
|
|
|
|
+ assert.NoError(t, fw.Drop(p, true, &h1, cp, nil))
|
|
// c2 should pass because ca sha match
|
|
// c2 should pass because ca sha match
|
|
resetConntrack(fw)
|
|
resetConntrack(fw)
|
|
- assert.NoError(t, fw.Drop([]byte{}, p, true, &h2, cp, nil))
|
|
|
|
|
|
+ assert.NoError(t, fw.Drop(p, true, &h2, cp, nil))
|
|
// c3 should fail because no match
|
|
// c3 should fail because no match
|
|
resetConntrack(fw)
|
|
resetConntrack(fw)
|
|
- assert.Equal(t, fw.Drop([]byte{}, p, true, &h3, cp, nil), ErrNoMatchingRule)
|
|
|
|
|
|
+ assert.Equal(t, fw.Drop(p, true, &h3, cp, nil), ErrNoMatchingRule)
|
|
}
|
|
}
|
|
|
|
|
|
func TestFirewall_DropConntrackReload(t *testing.T) {
|
|
func TestFirewall_DropConntrackReload(t *testing.T) {
|
|
@@ -545,12 +543,12 @@ func TestFirewall_DropConntrackReload(t *testing.T) {
|
|
cp := cert.NewCAPool()
|
|
cp := cert.NewCAPool()
|
|
|
|
|
|
// Drop outbound
|
|
// Drop outbound
|
|
- assert.Equal(t, fw.Drop([]byte{}, p, false, &h, cp, nil), ErrNoMatchingRule)
|
|
|
|
|
|
+ assert.Equal(t, fw.Drop(p, false, &h, cp, nil), ErrNoMatchingRule)
|
|
// Allow inbound
|
|
// Allow inbound
|
|
resetConntrack(fw)
|
|
resetConntrack(fw)
|
|
- assert.NoError(t, fw.Drop([]byte{}, p, true, &h, cp, nil))
|
|
|
|
|
|
+ assert.NoError(t, fw.Drop(p, true, &h, cp, nil))
|
|
// Allow outbound because conntrack
|
|
// Allow outbound because conntrack
|
|
- assert.NoError(t, fw.Drop([]byte{}, p, false, &h, cp, nil))
|
|
|
|
|
|
+ assert.NoError(t, fw.Drop(p, false, &h, cp, nil))
|
|
|
|
|
|
oldFw := fw
|
|
oldFw := fw
|
|
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
|
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
|
@@ -559,7 +557,7 @@ func TestFirewall_DropConntrackReload(t *testing.T) {
|
|
fw.rulesVersion = oldFw.rulesVersion + 1
|
|
fw.rulesVersion = oldFw.rulesVersion + 1
|
|
|
|
|
|
// Allow outbound because conntrack and new rules allow port 10
|
|
// Allow outbound because conntrack and new rules allow port 10
|
|
- assert.NoError(t, fw.Drop([]byte{}, p, false, &h, cp, nil))
|
|
|
|
|
|
+ assert.NoError(t, fw.Drop(p, false, &h, cp, nil))
|
|
|
|
|
|
oldFw = fw
|
|
oldFw = fw
|
|
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
|
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
|
@@ -568,7 +566,7 @@ func TestFirewall_DropConntrackReload(t *testing.T) {
|
|
fw.rulesVersion = oldFw.rulesVersion + 1
|
|
fw.rulesVersion = oldFw.rulesVersion + 1
|
|
|
|
|
|
// Drop outbound because conntrack doesn't match new ruleset
|
|
// Drop outbound because conntrack doesn't match new ruleset
|
|
- assert.Equal(t, fw.Drop([]byte{}, p, false, &h, cp, nil), ErrNoMatchingRule)
|
|
|
|
|
|
+ assert.Equal(t, fw.Drop(p, false, &h, cp, nil), ErrNoMatchingRule)
|
|
}
|
|
}
|
|
|
|
|
|
func BenchmarkLookup(b *testing.B) {
|
|
func BenchmarkLookup(b *testing.B) {
|
|
@@ -830,97 +828,6 @@ func TestAddFirewallRulesFromConfig(t *testing.T) {
|
|
assert.EqualError(t, AddFirewallRulesFromConfig(l, true, conf, mf), "firewall.inbound rule #0; `test error`")
|
|
assert.EqualError(t, AddFirewallRulesFromConfig(l, true, conf, mf), "firewall.inbound rule #0; `test error`")
|
|
}
|
|
}
|
|
|
|
|
|
-func TestTCPRTTTracking(t *testing.T) {
|
|
|
|
- b := make([]byte, 200)
|
|
|
|
-
|
|
|
|
- // Max ip IHL (60 bytes) and tcp IHL (60 bytes)
|
|
|
|
- b[0] = 15
|
|
|
|
- b[60+12] = 15 << 4
|
|
|
|
- f := Firewall{
|
|
|
|
- metricTCPRTT: metrics.GetOrRegisterHistogram("nope", nil, metrics.NewExpDecaySample(1028, 0.015)),
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Set SEQ to 1
|
|
|
|
- binary.BigEndian.PutUint32(b[60+4:60+8], 1)
|
|
|
|
-
|
|
|
|
- c := &conn{}
|
|
|
|
- setTCPRTTTracking(c, b)
|
|
|
|
- assert.Equal(t, uint32(1), c.Seq)
|
|
|
|
-
|
|
|
|
- // Bad ack - no ack flag
|
|
|
|
- binary.BigEndian.PutUint32(b[60+8:60+12], 80)
|
|
|
|
- assert.False(t, f.checkTCPRTT(c, b))
|
|
|
|
-
|
|
|
|
- // Bad ack, number is too low
|
|
|
|
- binary.BigEndian.PutUint32(b[60+8:60+12], 0)
|
|
|
|
- b[60+13] = uint8(0x10)
|
|
|
|
- assert.False(t, f.checkTCPRTT(c, b))
|
|
|
|
-
|
|
|
|
- // Good ack
|
|
|
|
- binary.BigEndian.PutUint32(b[60+8:60+12], 80)
|
|
|
|
- assert.True(t, f.checkTCPRTT(c, b))
|
|
|
|
- assert.Equal(t, uint32(0), c.Seq)
|
|
|
|
-
|
|
|
|
- // Set SEQ to 1
|
|
|
|
- binary.BigEndian.PutUint32(b[60+4:60+8], 1)
|
|
|
|
- c = &conn{}
|
|
|
|
- setTCPRTTTracking(c, b)
|
|
|
|
- assert.Equal(t, uint32(1), c.Seq)
|
|
|
|
-
|
|
|
|
- // Good acks
|
|
|
|
- binary.BigEndian.PutUint32(b[60+8:60+12], 81)
|
|
|
|
- assert.True(t, f.checkTCPRTT(c, b))
|
|
|
|
- assert.Equal(t, uint32(0), c.Seq)
|
|
|
|
-
|
|
|
|
- // Set SEQ to max uint32 - 20
|
|
|
|
- binary.BigEndian.PutUint32(b[60+4:60+8], ^uint32(0)-20)
|
|
|
|
- c = &conn{}
|
|
|
|
- setTCPRTTTracking(c, b)
|
|
|
|
- assert.Equal(t, ^uint32(0)-20, c.Seq)
|
|
|
|
-
|
|
|
|
- // Good acks
|
|
|
|
- binary.BigEndian.PutUint32(b[60+8:60+12], 81)
|
|
|
|
- assert.True(t, f.checkTCPRTT(c, b))
|
|
|
|
- assert.Equal(t, uint32(0), c.Seq)
|
|
|
|
-
|
|
|
|
- // Set SEQ to max uint32 / 2
|
|
|
|
- binary.BigEndian.PutUint32(b[60+4:60+8], ^uint32(0)/2)
|
|
|
|
- c = &conn{}
|
|
|
|
- setTCPRTTTracking(c, b)
|
|
|
|
- assert.Equal(t, ^uint32(0)/2, c.Seq)
|
|
|
|
-
|
|
|
|
- // Below
|
|
|
|
- binary.BigEndian.PutUint32(b[60+8:60+12], ^uint32(0)/2-1)
|
|
|
|
- assert.False(t, f.checkTCPRTT(c, b))
|
|
|
|
- assert.Equal(t, ^uint32(0)/2, c.Seq)
|
|
|
|
-
|
|
|
|
- // Halfway below
|
|
|
|
- binary.BigEndian.PutUint32(b[60+8:60+12], uint32(0))
|
|
|
|
- assert.False(t, f.checkTCPRTT(c, b))
|
|
|
|
- assert.Equal(t, ^uint32(0)/2, c.Seq)
|
|
|
|
-
|
|
|
|
- // Halfway above is ok
|
|
|
|
- binary.BigEndian.PutUint32(b[60+8:60+12], ^uint32(0))
|
|
|
|
- assert.True(t, f.checkTCPRTT(c, b))
|
|
|
|
- assert.Equal(t, uint32(0), c.Seq)
|
|
|
|
-
|
|
|
|
- // Set SEQ to max uint32
|
|
|
|
- binary.BigEndian.PutUint32(b[60+4:60+8], ^uint32(0))
|
|
|
|
- c = &conn{}
|
|
|
|
- setTCPRTTTracking(c, b)
|
|
|
|
- assert.Equal(t, ^uint32(0), c.Seq)
|
|
|
|
-
|
|
|
|
- // Halfway + 1 above
|
|
|
|
- binary.BigEndian.PutUint32(b[60+8:60+12], ^uint32(0)/2+1)
|
|
|
|
- assert.False(t, f.checkTCPRTT(c, b))
|
|
|
|
- assert.Equal(t, ^uint32(0), c.Seq)
|
|
|
|
-
|
|
|
|
- // Halfway above
|
|
|
|
- binary.BigEndian.PutUint32(b[60+8:60+12], ^uint32(0)/2)
|
|
|
|
- assert.True(t, f.checkTCPRTT(c, b))
|
|
|
|
- assert.Equal(t, uint32(0), c.Seq)
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
func TestFirewall_convertRule(t *testing.T) {
|
|
func TestFirewall_convertRule(t *testing.T) {
|
|
l := test.NewLogger()
|
|
l := test.NewLogger()
|
|
ob := &bytes.Buffer{}
|
|
ob := &bytes.Buffer{}
|