control.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. package nebula
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "net"
  6. "os"
  7. "os/signal"
  8. "syscall"
  9. "github.com/sirupsen/logrus"
  10. "github.com/slackhq/nebula/cert"
  11. "golang.org/x/net/ipv4"
  12. )
  13. // Every interaction here needs to take extra care to copy memory and not return or use arguments "as is" when touching
  14. // core. This means copying IP objects, slices, de-referencing pointers and taking the actual value, etc
  15. type Control struct {
  16. f *Interface
  17. l *logrus.Logger
  18. }
  19. type ControlHostInfo struct {
  20. VpnIP net.IP `json:"vpnIp"`
  21. LocalIndex uint32 `json:"localIndex"`
  22. RemoteIndex uint32 `json:"remoteIndex"`
  23. RemoteAddrs []udpAddr `json:"remoteAddrs"`
  24. CachedPackets int `json:"cachedPackets"`
  25. Cert *cert.NebulaCertificate `json:"cert"`
  26. MessageCounter uint64 `json:"messageCounter"`
  27. CurrentRemote udpAddr `json:"currentRemote"`
  28. }
  29. // Start actually runs nebula, this is a nonblocking call. To block use Control.ShutdownBlock()
  30. func (c *Control) Start() {
  31. c.f.run()
  32. }
  33. // Stop signals nebula to shutdown, returns after the shutdown is complete
  34. func (c *Control) Stop() {
  35. //TODO: stop tun and udp routines, the lock on hostMap effectively does that though
  36. //TODO: this is probably better as a function in ConnectionManager or HostMap directly
  37. c.f.hostMap.Lock()
  38. for _, h := range c.f.hostMap.Hosts {
  39. if h.ConnectionState.ready {
  40. c.f.send(closeTunnel, 0, h.ConnectionState, h, h.remote, []byte{}, make([]byte, 12, 12), make([]byte, mtu))
  41. c.l.WithField("vpnIp", IntIp(h.hostId)).WithField("udpAddr", h.remote).
  42. Debug("Sending close tunnel message")
  43. }
  44. }
  45. c.f.hostMap.Unlock()
  46. c.l.Info("Goodbye")
  47. }
  48. // ShutdownBlock will listen for and block on term and interrupt signals, calling Control.Stop() once signalled
  49. func (c *Control) ShutdownBlock() {
  50. sigChan := make(chan os.Signal)
  51. signal.Notify(sigChan, syscall.SIGTERM)
  52. signal.Notify(sigChan, syscall.SIGINT)
  53. rawSig := <-sigChan
  54. sig := rawSig.String()
  55. c.l.WithField("signal", sig).Info("Caught signal, shutting down")
  56. c.Stop()
  57. }
  58. // RebindUDPServer asks the UDP listener to rebind it's listener. Mainly used on mobile clients when interfaces change
  59. func (c *Control) RebindUDPServer() {
  60. _ = c.f.outside.Rebind()
  61. }
  62. // ListHostmap returns details about the actual or pending (handshaking) hostmap
  63. func (c *Control) ListHostmap(pendingMap bool) []ControlHostInfo {
  64. var hm *HostMap
  65. if pendingMap {
  66. hm = c.f.handshakeManager.pendingHostMap
  67. } else {
  68. hm = c.f.hostMap
  69. }
  70. hm.RLock()
  71. hosts := make([]ControlHostInfo, len(hm.Hosts))
  72. i := 0
  73. for _, v := range hm.Hosts {
  74. hosts[i] = copyHostInfo(v)
  75. i++
  76. }
  77. hm.RUnlock()
  78. return hosts
  79. }
  80. // GetHostInfoByVpnIP returns a single tunnels hostInfo, or nil if not found
  81. func (c *Control) GetHostInfoByVpnIP(vpnIP uint32, pending bool) *ControlHostInfo {
  82. var hm *HostMap
  83. if pending {
  84. hm = c.f.handshakeManager.pendingHostMap
  85. } else {
  86. hm = c.f.hostMap
  87. }
  88. h, err := hm.QueryVpnIP(vpnIP)
  89. if err != nil {
  90. return nil
  91. }
  92. ch := copyHostInfo(h)
  93. return &ch
  94. }
  95. // SetRemoteForTunnel forces a tunnel to use a specific remote
  96. func (c *Control) SetRemoteForTunnel(vpnIP uint32, addr udpAddr) *ControlHostInfo {
  97. hostInfo, err := c.f.hostMap.QueryVpnIP(vpnIP)
  98. if err != nil {
  99. return nil
  100. }
  101. hostInfo.SetRemote(addr.Copy())
  102. ch := copyHostInfo(hostInfo)
  103. return &ch
  104. }
  105. // CloseTunnel closes a fully established tunnel. If localOnly is false it will notify the remote end as well.
  106. func (c *Control) CloseTunnel(vpnIP uint32, localOnly bool) bool {
  107. hostInfo, err := c.f.hostMap.QueryVpnIP(vpnIP)
  108. if err != nil {
  109. return false
  110. }
  111. if !localOnly {
  112. c.f.send(
  113. closeTunnel,
  114. 0,
  115. hostInfo.ConnectionState,
  116. hostInfo,
  117. hostInfo.remote,
  118. []byte{},
  119. make([]byte, 12, 12),
  120. make([]byte, mtu),
  121. )
  122. }
  123. c.f.closeTunnel(hostInfo)
  124. return true
  125. }
  126. func copyHostInfo(h *HostInfo) ControlHostInfo {
  127. addrs := h.RemoteUDPAddrs()
  128. chi := ControlHostInfo{
  129. VpnIP: int2ip(h.hostId),
  130. LocalIndex: h.localIndexId,
  131. RemoteIndex: h.remoteIndexId,
  132. RemoteAddrs: make([]udpAddr, len(addrs), len(addrs)),
  133. CachedPackets: len(h.packetStore),
  134. MessageCounter: *h.ConnectionState.messageCounter,
  135. }
  136. if c := h.GetCert(); c != nil {
  137. chi.Cert = c.Copy()
  138. }
  139. if h.remote != nil {
  140. chi.CurrentRemote = *h.remote
  141. }
  142. for i, addr := range addrs {
  143. chi.RemoteAddrs[i] = addr.Copy()
  144. }
  145. return chi
  146. }
  147. // Hook provides the ability to hook into the network path for a particular
  148. // message sub type. Any received message of that subtype that is allowed by
  149. // the firewall will be written to the provided write func instead of the
  150. // inside interface.
  151. // TODO: make this an io.Writer
  152. func (c *Control) Hook(t NebulaMessageSubType, w func([]byte) error) error {
  153. if t == 0 {
  154. return fmt.Errorf("non-default message subtype must be specified")
  155. }
  156. if _, ok := c.f.handlers[Version][message][t]; ok {
  157. return fmt.Errorf("message subtype %d already hooked", t)
  158. }
  159. c.f.handlers[Version][message][t] = c.f.newHook(w)
  160. return nil
  161. }
  162. // Send provides the ability to send arbitrary message packets to peer nodes.
  163. // The provided payload will be encapsulated in a Nebula Firewall packet
  164. // (IPv4 plus ports) from the node IP to the provided destination nebula IP.
  165. // Any protocol handling above layer 3 (IP) must be managed by the caller.
  166. func (c *Control) Send(ip uint32, port uint16, st NebulaMessageSubType, payload []byte) {
  167. headerLen := ipv4.HeaderLen + minFwPacketLen
  168. length := headerLen + len(payload)
  169. packet := make([]byte, length)
  170. packet[0] = 0x45 // IPv4 HL=20
  171. packet[9] = 114 // Declare as arbitrary 0-hop protocol
  172. binary.BigEndian.PutUint16(packet[2:4], uint16(length))
  173. binary.BigEndian.PutUint32(packet[12:16], ip2int(c.f.inside.CidrNet().IP.To4()))
  174. binary.BigEndian.PutUint32(packet[16:20], ip)
  175. // Set identical values for src and dst port as they're only
  176. // used for nebula firewall rule/conntrack matching.
  177. binary.BigEndian.PutUint16(packet[20:22], port)
  178. binary.BigEndian.PutUint16(packet[22:24], port)
  179. copy(packet[headerLen:], payload)
  180. fp := &FirewallPacket{}
  181. nb := make([]byte, 12)
  182. out := make([]byte, mtu)
  183. c.f.consumeInsidePacket(st, packet, fp, nb, out)
  184. }