relay_manager.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. package nebula
  2. import (
  3. "context"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "log/slog"
  8. "net/netip"
  9. "sync/atomic"
  10. "github.com/slackhq/nebula/cert"
  11. "github.com/slackhq/nebula/config"
  12. "github.com/slackhq/nebula/header"
  13. )
  14. type relayManager struct {
  15. l *slog.Logger
  16. hostmap *HostMap
  17. amRelay atomic.Bool
  18. }
  19. func NewRelayManager(ctx context.Context, l *slog.Logger, hostmap *HostMap, c *config.C) *relayManager {
  20. rm := &relayManager{
  21. l: l,
  22. hostmap: hostmap,
  23. }
  24. rm.reload(c, true)
  25. c.RegisterReloadCallback(func(c *config.C) {
  26. err := rm.reload(c, false)
  27. if err != nil {
  28. rm.l.Error("Failed to reload relay_manager", "error", err)
  29. }
  30. })
  31. return rm
  32. }
  33. func (rm *relayManager) reload(c *config.C, initial bool) error {
  34. if initial || c.HasChanged("relay.am_relay") {
  35. rm.setAmRelay(c.GetBool("relay.am_relay", false))
  36. }
  37. return nil
  38. }
  39. func (rm *relayManager) GetAmRelay() bool {
  40. return rm.amRelay.Load()
  41. }
  42. func (rm *relayManager) setAmRelay(v bool) {
  43. rm.amRelay.Store(v)
  44. }
  45. // AddRelay finds an available relay index on the hostmap, and associates the relay info with it.
  46. // relayHostInfo is the Nebula peer which can be used as a relay to access the target vpnIp.
  47. func AddRelay(l *slog.Logger, relayHostInfo *HostInfo, hm *HostMap, vpnIp netip.Addr, remoteIdx *uint32, relayType int, state int) (uint32, error) {
  48. hm.Lock()
  49. defer hm.Unlock()
  50. for range 32 {
  51. index, err := generateIndex(l)
  52. if err != nil {
  53. return 0, err
  54. }
  55. _, inRelays := hm.Relays[index]
  56. if !inRelays {
  57. // Avoid standing up a relay that can't be used since only the primary hostinfo
  58. // will be pointed to by the relay logic
  59. //TODO: if there was an existing primary and it had relay state, should we merge?
  60. hm.unlockedMakePrimary(relayHostInfo)
  61. hm.Relays[index] = relayHostInfo
  62. newRelay := Relay{
  63. Type: relayType,
  64. State: state,
  65. LocalIndex: index,
  66. PeerAddr: vpnIp,
  67. }
  68. if remoteIdx != nil {
  69. newRelay.RemoteIndex = *remoteIdx
  70. }
  71. relayHostInfo.relayState.InsertRelay(vpnIp, index, &newRelay)
  72. return index, nil
  73. }
  74. }
  75. return 0, errors.New("failed to generate unique localIndexId")
  76. }
  77. // EstablishRelay updates a Requested Relay to become an Established Relay, which can pass traffic.
  78. func (rm *relayManager) EstablishRelay(relayHostInfo *HostInfo, m *NebulaControl) (*Relay, error) {
  79. relay, ok := relayHostInfo.relayState.CompleteRelayByIdx(m.InitiatorRelayIndex, m.ResponderRelayIndex)
  80. if !ok {
  81. var relayFrom, relayTo any
  82. if m.RelayFromAddr == nil {
  83. relayFrom = m.OldRelayFromAddr
  84. } else {
  85. relayFrom = m.RelayFromAddr
  86. }
  87. if m.RelayToAddr == nil {
  88. relayTo = m.OldRelayToAddr
  89. } else {
  90. relayTo = m.RelayToAddr
  91. }
  92. rm.l.Info("relayManager failed to update relay",
  93. "relay", relayHostInfo.vpnAddrs[0],
  94. "initiatorRelayIndex", m.InitiatorRelayIndex,
  95. "relayFrom", relayFrom,
  96. "relayTo", relayTo,
  97. )
  98. return nil, fmt.Errorf("unknown relay")
  99. }
  100. return relay, nil
  101. }
  102. func (rm *relayManager) HandleControlMsg(h *HostInfo, d []byte, f *Interface) {
  103. msg := &NebulaControl{}
  104. err := msg.Unmarshal(d)
  105. if err != nil {
  106. h.logger(f.l).Error("Failed to unmarshal control message", "error", err)
  107. return
  108. }
  109. var v cert.Version
  110. if msg.OldRelayFromAddr > 0 || msg.OldRelayToAddr > 0 {
  111. v = cert.Version1
  112. b := [4]byte{}
  113. binary.BigEndian.PutUint32(b[:], msg.OldRelayFromAddr)
  114. msg.RelayFromAddr = netAddrToProtoAddr(netip.AddrFrom4(b))
  115. binary.BigEndian.PutUint32(b[:], msg.OldRelayToAddr)
  116. msg.RelayToAddr = netAddrToProtoAddr(netip.AddrFrom4(b))
  117. } else {
  118. v = cert.Version2
  119. }
  120. switch msg.Type {
  121. case NebulaControl_CreateRelayRequest:
  122. rm.handleCreateRelayRequest(v, h, f, msg)
  123. case NebulaControl_CreateRelayResponse:
  124. rm.handleCreateRelayResponse(v, h, f, msg)
  125. }
  126. }
  127. func (rm *relayManager) handleCreateRelayResponse(v cert.Version, h *HostInfo, f *Interface, m *NebulaControl) {
  128. rm.l.Info("handleCreateRelayResponse",
  129. "relayFrom", protoAddrToNetAddr(m.RelayFromAddr),
  130. "relayTo", protoAddrToNetAddr(m.RelayToAddr),
  131. "initiatorRelayIndex", m.InitiatorRelayIndex,
  132. "responderRelayIndex", m.ResponderRelayIndex,
  133. "vpnAddrs", h.vpnAddrs,
  134. )
  135. target := m.RelayToAddr
  136. targetAddr := protoAddrToNetAddr(target)
  137. relay, err := rm.EstablishRelay(h, m)
  138. if err != nil {
  139. rm.l.Error("Failed to update relay for relayTo", "error", err)
  140. return
  141. }
  142. // Do I need to complete the relays now?
  143. if relay.Type == TerminalType {
  144. return
  145. }
  146. // I'm the middle man. Let the initiator know that the I've established the relay they requested.
  147. peerHostInfo := rm.hostmap.QueryVpnAddr(relay.PeerAddr)
  148. if peerHostInfo == nil {
  149. rm.l.Error("Can't find a HostInfo for peer", "relayTo", relay.PeerAddr)
  150. return
  151. }
  152. peerRelay, ok := peerHostInfo.relayState.QueryRelayForByIp(targetAddr)
  153. if !ok {
  154. rm.l.Error("peerRelay does not have Relay state for relayTo", "relayTo", peerHostInfo.vpnAddrs[0])
  155. return
  156. }
  157. switch peerRelay.State {
  158. case Requested:
  159. // I initiated the request to this peer, but haven't heard back from the peer yet. I must wait for this peer
  160. // to respond to complete the connection.
  161. case PeerRequested, Disestablished, Established:
  162. peerHostInfo.relayState.UpdateRelayForByIpState(targetAddr, Established)
  163. resp := NebulaControl{
  164. Type: NebulaControl_CreateRelayResponse,
  165. ResponderRelayIndex: peerRelay.LocalIndex,
  166. InitiatorRelayIndex: peerRelay.RemoteIndex,
  167. }
  168. if v == cert.Version1 {
  169. peer := peerHostInfo.vpnAddrs[0]
  170. if !peer.Is4() {
  171. rm.l.Error("Refusing to CreateRelayResponse for a v1 relay with an ipv6 address",
  172. "relayFrom", peer,
  173. "relayTo", target,
  174. "initiatorRelayIndex", resp.InitiatorRelayIndex,
  175. "responderRelayIndex", resp.ResponderRelayIndex,
  176. "vpnAddrs", peerHostInfo.vpnAddrs,
  177. )
  178. return
  179. }
  180. b := peer.As4()
  181. resp.OldRelayFromAddr = binary.BigEndian.Uint32(b[:])
  182. b = targetAddr.As4()
  183. resp.OldRelayToAddr = binary.BigEndian.Uint32(b[:])
  184. } else {
  185. resp.RelayFromAddr = netAddrToProtoAddr(peerHostInfo.vpnAddrs[0])
  186. resp.RelayToAddr = target
  187. }
  188. msg, err := resp.Marshal()
  189. if err != nil {
  190. rm.l.Error("relayManager Failed to marshal Control CreateRelayResponse message to create relay", "error", err)
  191. } else {
  192. f.SendMessageToHostInfo(header.Control, 0, peerHostInfo, msg, make([]byte, 12), make([]byte, mtu))
  193. rm.l.Info("send CreateRelayResponse",
  194. "relayFrom", resp.RelayFromAddr,
  195. "relayTo", resp.RelayToAddr,
  196. "initiatorRelayIndex", resp.InitiatorRelayIndex,
  197. "responderRelayIndex", resp.ResponderRelayIndex,
  198. "vpnAddrs", peerHostInfo.vpnAddrs,
  199. )
  200. }
  201. }
  202. }
  203. func (rm *relayManager) handleCreateRelayRequest(v cert.Version, h *HostInfo, f *Interface, m *NebulaControl) {
  204. from := protoAddrToNetAddr(m.RelayFromAddr)
  205. target := protoAddrToNetAddr(m.RelayToAddr)
  206. logMsg := rm.l.With(
  207. "relayFrom", from,
  208. "relayTo", target,
  209. "initiatorRelayIndex", m.InitiatorRelayIndex,
  210. "vpnAddrs", h.vpnAddrs,
  211. )
  212. logMsg.Info("handleCreateRelayRequest")
  213. // Is the source of the relay me? This should never happen, but did happen due to
  214. // an issue migrating relays over to newly re-handshaked host info objects.
  215. if f.myVpnAddrsTable.Contains(from) {
  216. logMsg.Error("Discarding relay request from myself", "myIP", from)
  217. return
  218. }
  219. // Is the target of the relay me?
  220. if f.myVpnAddrsTable.Contains(target) {
  221. existingRelay, ok := h.relayState.QueryRelayForByIp(from)
  222. if ok {
  223. switch existingRelay.State {
  224. case Requested:
  225. ok = h.relayState.CompleteRelayByIP(from, m.InitiatorRelayIndex)
  226. if !ok {
  227. logMsg.Error("Relay State not found")
  228. return
  229. }
  230. case Established:
  231. if existingRelay.RemoteIndex != m.InitiatorRelayIndex {
  232. // We got a brand new Relay request, because its index is different than what we saw before.
  233. // This should never happen. The peer should never change an index, once created.
  234. logMsg.Error("Existing relay mismatch with CreateRelayRequest",
  235. "existingRemoteIndex", existingRelay.RemoteIndex)
  236. return
  237. }
  238. case Disestablished:
  239. if existingRelay.RemoteIndex != m.InitiatorRelayIndex {
  240. // We got a brand new Relay request, because its index is different than what we saw before.
  241. // This should never happen. The peer should never change an index, once created.
  242. logMsg.Error("Existing relay mismatch with CreateRelayRequest",
  243. "existingRemoteIndex", existingRelay.RemoteIndex)
  244. return
  245. }
  246. // Mark the relay as 'Established' because it's safe to use again
  247. h.relayState.UpdateRelayForByIpState(from, Established)
  248. case PeerRequested:
  249. // I should never be in this state, because I am terminal, not forwarding.
  250. logMsg.Error("Unexpected Relay State found",
  251. "existingRemoteIndex", existingRelay.RemoteIndex,
  252. "state", existingRelay.State)
  253. }
  254. } else {
  255. _, err := AddRelay(rm.l, h, f.hostMap, from, &m.InitiatorRelayIndex, TerminalType, Established)
  256. if err != nil {
  257. logMsg.Error("Failed to add relay", "error", err)
  258. return
  259. }
  260. }
  261. relay, ok := h.relayState.QueryRelayForByIp(from)
  262. if !ok {
  263. logMsg.Error("Relay State not found", "from", from)
  264. return
  265. }
  266. resp := NebulaControl{
  267. Type: NebulaControl_CreateRelayResponse,
  268. ResponderRelayIndex: relay.LocalIndex,
  269. InitiatorRelayIndex: relay.RemoteIndex,
  270. }
  271. if v == cert.Version1 {
  272. b := from.As4()
  273. resp.OldRelayFromAddr = binary.BigEndian.Uint32(b[:])
  274. b = target.As4()
  275. resp.OldRelayToAddr = binary.BigEndian.Uint32(b[:])
  276. } else {
  277. resp.RelayFromAddr = netAddrToProtoAddr(from)
  278. resp.RelayToAddr = netAddrToProtoAddr(target)
  279. }
  280. msg, err := resp.Marshal()
  281. if err != nil {
  282. logMsg.Error("relayManager Failed to marshal Control CreateRelayResponse message to create relay", "error", err)
  283. } else {
  284. f.SendMessageToHostInfo(header.Control, 0, h, msg, make([]byte, 12), make([]byte, mtu))
  285. rm.l.Info("send CreateRelayResponse",
  286. "relayFrom", from,
  287. "relayTo", target,
  288. "initiatorRelayIndex", resp.InitiatorRelayIndex,
  289. "responderRelayIndex", resp.ResponderRelayIndex,
  290. "vpnAddrs", h.vpnAddrs,
  291. )
  292. }
  293. return
  294. } else {
  295. // the target is not me. Create a relay to the target, from me.
  296. if !rm.GetAmRelay() {
  297. return
  298. }
  299. peer := rm.hostmap.QueryVpnAddr(target)
  300. if peer == nil {
  301. // Try to establish a connection to this host. If we get a future relay request,
  302. // we'll be ready!
  303. f.Handshake(target)
  304. return
  305. }
  306. if !peer.remote.IsValid() {
  307. // Only create relays to peers for whom I have a direct connection
  308. return
  309. }
  310. var index uint32
  311. var err error
  312. targetRelay, ok := peer.relayState.QueryRelayForByIp(from)
  313. if ok {
  314. index = targetRelay.LocalIndex
  315. } else {
  316. // Allocate an index in the hostMap for this relay peer
  317. index, err = AddRelay(rm.l, peer, f.hostMap, from, nil, ForwardingType, Requested)
  318. if err != nil {
  319. return
  320. }
  321. }
  322. peer.relayState.UpdateRelayForByIpState(from, Requested)
  323. // Send a CreateRelayRequest to the peer.
  324. req := NebulaControl{
  325. Type: NebulaControl_CreateRelayRequest,
  326. InitiatorRelayIndex: index,
  327. }
  328. if v == cert.Version1 {
  329. if !h.vpnAddrs[0].Is4() {
  330. rm.l.Error("Refusing to CreateRelayRequest for a v1 relay with an ipv6 address",
  331. "relayFrom", h.vpnAddrs[0],
  332. "relayTo", target,
  333. "initiatorRelayIndex", req.InitiatorRelayIndex,
  334. "responderRelayIndex", req.ResponderRelayIndex,
  335. "vpnAddr", target,
  336. )
  337. return
  338. }
  339. b := h.vpnAddrs[0].As4()
  340. req.OldRelayFromAddr = binary.BigEndian.Uint32(b[:])
  341. b = target.As4()
  342. req.OldRelayToAddr = binary.BigEndian.Uint32(b[:])
  343. } else {
  344. req.RelayFromAddr = netAddrToProtoAddr(h.vpnAddrs[0])
  345. req.RelayToAddr = netAddrToProtoAddr(target)
  346. }
  347. msg, err := req.Marshal()
  348. if err != nil {
  349. logMsg.Error("relayManager Failed to marshal Control message to create relay", "error", err)
  350. } else {
  351. f.SendMessageToHostInfo(header.Control, 0, peer, msg, make([]byte, 12), make([]byte, mtu))
  352. rm.l.Info("send CreateRelayRequest",
  353. "relayFrom", h.vpnAddrs[0],
  354. "relayTo", target,
  355. "initiatorRelayIndex", req.InitiatorRelayIndex,
  356. "responderRelayIndex", req.ResponderRelayIndex,
  357. "vpnAddr", target,
  358. )
  359. }
  360. // Also track the half-created Relay state just received
  361. _, ok = h.relayState.QueryRelayForByIp(target)
  362. if !ok {
  363. _, err := AddRelay(rm.l, h, f.hostMap, target, &m.InitiatorRelayIndex, ForwardingType, PeerRequested)
  364. if err != nil {
  365. logMsg.Error("relayManager Failed to allocate a local index for relay", "error", err)
  366. return
  367. }
  368. }
  369. }
  370. }