inside_filter_test.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. package nebula
  2. import (
  3. "net/netip"
  4. "testing"
  5. "time"
  6. "github.com/gaissmai/bart"
  7. "github.com/slackhq/nebula/cert"
  8. "github.com/slackhq/nebula/firewall"
  9. "github.com/slackhq/nebula/header"
  10. "github.com/slackhq/nebula/overlay/batch"
  11. "github.com/slackhq/nebula/overlay/overlaytest"
  12. "github.com/slackhq/nebula/overlay/tio"
  13. "github.com/slackhq/nebula/udp"
  14. "github.com/stretchr/testify/assert"
  15. "github.com/stretchr/testify/require"
  16. )
  17. func newInsideFilterTestInterface(t *testing.T, allow bool) (*Interface, *HostInfo, *capturingTun) {
  18. t.Helper()
  19. local := netip.MustParseAddr("192.0.2.1")
  20. remote := netip.MustParseAddr("192.0.2.2")
  21. f, tun := newSelfForwardInterface(local)
  22. f.inside = overlaytest.NoopTun{}
  23. f.myVpnNetworksTable = &bart.Lite{}
  24. f.myVpnNetworksTable.Insert(netip.MustParsePrefix("192.0.2.0/24"))
  25. f.myBroadcastAddrsTable.Insert(netip.MustParsePrefix("192.0.2.255/32"))
  26. f.dropLocalBroadcast, f.dropMulticast = true, true
  27. localCert := &dummyCert{version: cert.Version1, networks: []netip.Prefix{netip.PrefixFrom(local, 24)}}
  28. peerCert := &dummyCert{version: cert.Version1, networks: []netip.Prefix{netip.PrefixFrom(remote, 24)}}
  29. f.firewall = NewFirewall(f.l, time.Minute, time.Minute, time.Minute, localCert)
  30. if allow {
  31. require.NoError(t, f.firewall.AddRule(false, firewall.ProtoAny, 0, 0, []string{"any"}, "", "", "", "", ""))
  32. }
  33. f.pki = &PKI{}
  34. f.pki.caPool.Store(cert.NewCAPool())
  35. f.hostMap = newHostMap(f.l)
  36. f.lightHouse = newTestLighthouse()
  37. f.lightHouse.amLighthouse = true // Keep destination lookup from probing other remotes.
  38. f.handshakeManager = NewHandshakeManager(f.l, f.hostMap, f.lightHouse, udp.NoopConn{}, defaultHandshakeConfig)
  39. f.handshakeManager.f = f
  40. f.connectionManager = &connectionManager{intf: f}
  41. h := &HostInfo{
  42. vpnAddrs: []netip.Addr{remote},
  43. ConnectionState: &ConnectionState{
  44. peerCert: &cert.CachedCertificate{Certificate: peerCert},
  45. },
  46. }
  47. f.hostMap.Hosts[remote] = h
  48. return f, h, tun
  49. }
  50. func TestFilterInsidePacket(t *testing.T) {
  51. local := netip.MustParseAddr("192.0.2.1")
  52. remote := netip.MustParseAddr("192.0.2.2")
  53. for _, tt := range []struct {
  54. name string
  55. packet []byte
  56. allow bool
  57. reject bool
  58. ready bool
  59. writes int
  60. }{
  61. {name: "allowed", packet: buildIPv4(local, remote, tcpSyn), allow: true, ready: true},
  62. {name: "malformed", packet: []byte{0x45}, allow: true},
  63. {name: "broadcast", packet: buildIPv4(local, netip.MustParseAddr("192.0.2.255"), udpDatagram), allow: true},
  64. {name: "multicast", packet: buildIPv4(local, netip.MustParseAddr("224.0.0.1"), udpDatagram), allow: true},
  65. {name: "firewall drop", packet: buildIPv4(local, remote, tcpSyn)},
  66. {name: "firewall reject", packet: buildIPv4(local, remote, tcpSyn), reject: true, writes: 1},
  67. {name: "unroutable drop", packet: buildIPv4(local, netip.MustParseAddr("198.51.100.1"), tcpSyn), allow: true},
  68. {name: "unroutable reject", packet: buildIPv4(local, netip.MustParseAddr("198.51.100.1"), tcpSyn), allow: true, reject: true, writes: 1},
  69. } {
  70. t.Run(tt.name, func(t *testing.T) {
  71. f, h, tun := newInsideFilterTestInterface(t, tt.allow)
  72. f.firewall.OutboundSendReject = tt.reject
  73. fp := &firewall.ParsedPacket{}
  74. got := f.filterInsidePacket(tio.Packet{Bytes: tt.packet}, fp, make([]byte, mtu), 0, nil)
  75. if tt.ready {
  76. require.Same(t, h, got)
  77. assert.Equal(t, local, fp.LocalAddr)
  78. assert.Equal(t, remote, fp.RemoteAddr)
  79. } else {
  80. require.Nil(t, got)
  81. }
  82. assert.Zero(t, h.ConnectionState.messageCounter.Load(), "filtering must not allocate encryption counters")
  83. assert.False(t, h.sentSinceCheck(), "filtering must not mark outbound traffic")
  84. require.Len(t, tun.writes, tt.writes)
  85. if tt.writes > 0 {
  86. require.GreaterOrEqual(t, len(tun.writes[0]), 40)
  87. assert.Equal(t, tt.packet[16:20], tun.writes[0][12:16])
  88. assert.Equal(t, tt.packet[12:16], tun.writes[0][16:20])
  89. assert.NotZero(t, tun.writes[0][33]&0x04, "reject must carry a TCP reset")
  90. }
  91. })
  92. }
  93. }
  94. func TestFilterInsidePacketSelf(t *testing.T) {
  95. local := netip.MustParseAddr("192.0.2.1")
  96. f, _, tun := newInsideFilterTestInterface(t, true)
  97. pkt := buildIPv4(local, local, tcpSyn)
  98. require.Nil(t, f.filterInsidePacket(tio.Packet{Bytes: pkt}, &firewall.ParsedPacket{}, nil, 0, nil))
  99. if immediatelyForwardToSelf {
  100. require.Len(t, tun.writes, 1)
  101. assert.Equal(t, pkt, tun.writes[0])
  102. } else {
  103. assert.Empty(t, tun.writes)
  104. }
  105. }
  106. func TestFilterInsidePacketPendingHandshake(t *testing.T) {
  107. f, h, tun := newInsideFilterTestInterface(t, true)
  108. remote := h.vpnAddrs[0]
  109. delete(f.hostMap.Hosts, remote)
  110. hh := &HandshakeHostInfo{hostinfo: h}
  111. f.handshakeManager.vpnIps[remote] = hh
  112. pkt := buildIPv4(netip.MustParseAddr("192.0.2.1"), remote, udpDatagram)
  113. want := append([]byte(nil), pkt...)
  114. require.Nil(t, f.filterInsidePacket(tio.Packet{Bytes: pkt}, &firewall.ParsedPacket{}, nil, 0, nil))
  115. require.Len(t, hh.packetStore, 1)
  116. clear(pkt)
  117. assert.Equal(t, want, hh.packetStore[0].packet, "the handshake cache must own its packet")
  118. assert.Equal(t, header.Message, hh.packetStore[0].messageType)
  119. assert.Empty(t, tun.writes)
  120. assert.Zero(t, h.ConnectionState.messageCounter.Load())
  121. }
  122. type insideFilterConn struct {
  123. udp.NoopConn
  124. packets [][]byte
  125. }
  126. func (c *insideFilterConn) WriteBatch(bufs [][]byte, _ []netip.AddrPort) (int, error) {
  127. for _, b := range bufs {
  128. c.packets = append(c.packets, append([]byte(nil), b...))
  129. }
  130. return len(bufs), nil
  131. }
  132. func TestConsumeInsidePacketFilterAndSend(t *testing.T) {
  133. for _, allow := range []bool{false, true} {
  134. t.Run(map[bool]string{false: "denied", true: "allowed"}[allow], func(t *testing.T) {
  135. f, h, _ := newInsideFilterTestInterface(t, allow)
  136. initR, respR := runTestHandshake(t)
  137. ci, err := newConnectionStateFromResult(initR)
  138. require.NoError(t, err)
  139. rci, err := newConnectionStateFromResult(respR)
  140. require.NoError(t, err)
  141. ci.peerCert = h.ConnectionState.peerCert
  142. h.ConnectionState = ci
  143. h.remoteIndexId = 100
  144. remote := netip.MustParseAddrPort("198.51.100.2:4242")
  145. h.remote.Store(&remote)
  146. conn := &insideFilterConn{}
  147. sb := batch.NewSendBatch(conn, 1, mtu)
  148. pkt := buildIPv4(netip.MustParseAddr("192.0.2.1"), h.vpnAddrs[0], udpDatagram)
  149. before := ci.messageCounter.Load()
  150. f.consumeInsidePacket(tio.Packet{Bytes: pkt}, &firewall.ParsedPacket{}, make([]byte, 12), sb, nil, 0, nil)
  151. _, err = sb.Flush()
  152. require.NoError(t, err)
  153. if !allow {
  154. assert.Empty(t, conn.packets)
  155. assert.Equal(t, before, ci.messageCounter.Load())
  156. assert.False(t, h.sentSinceCheck())
  157. return
  158. }
  159. require.Len(t, conn.packets, 1)
  160. assert.True(t, h.sentSinceCheck())
  161. hdr := &header.H{}
  162. require.NoError(t, hdr.Parse(conn.packets[0]))
  163. assert.Equal(t, header.Message, hdr.Type)
  164. assert.Equal(t, h.remoteIndexId, hdr.RemoteIndex)
  165. assert.Equal(t, before+1, hdr.MessageCounter)
  166. plain, err := rci.Decrypt(f.l, hdr.MessageCounter, conn.packets[0], make([]byte, 12))
  167. require.NoError(t, err)
  168. assert.Equal(t, pkt, plain)
  169. })
  170. }
  171. }