relay_manager.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. package nebula
  2. import (
  3. "context"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "net/netip"
  8. "sync/atomic"
  9. "github.com/sirupsen/logrus"
  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 *logrus.Logger
  16. hostmap *HostMap
  17. amRelay atomic.Bool
  18. }
  19. func NewRelayManager(ctx context.Context, l *logrus.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. l.WithError(err).Error("Failed to reload relay_manager")
  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 *logrus.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 i := 0; i < 32; i++ {
  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. fields := logrus.Fields{
  82. "relay": relayHostInfo.vpnAddrs[0],
  83. "initiatorRelayIndex": m.InitiatorRelayIndex,
  84. }
  85. if m.RelayFromAddr == nil {
  86. fields["relayFrom"] = m.OldRelayFromAddr
  87. } else {
  88. fields["relayFrom"] = m.RelayFromAddr
  89. }
  90. if m.RelayToAddr == nil {
  91. fields["relayTo"] = m.OldRelayToAddr
  92. } else {
  93. fields["relayTo"] = m.RelayToAddr
  94. }
  95. rm.l.WithFields(fields).Info("relayManager failed to update relay")
  96. return nil, fmt.Errorf("unknown relay")
  97. }
  98. return relay, nil
  99. }
  100. func (rm *relayManager) HandleControlMsg(h *HostInfo, d []byte, f *Interface) {
  101. msg := &NebulaControl{}
  102. err := msg.Unmarshal(d)
  103. if err != nil {
  104. h.logger(f.l).WithError(err).Error("Failed to unmarshal control message")
  105. return
  106. }
  107. var v cert.Version
  108. if msg.OldRelayFromAddr > 0 || msg.OldRelayToAddr > 0 {
  109. v = cert.Version1
  110. b := [4]byte{}
  111. binary.BigEndian.PutUint32(b[:], msg.OldRelayFromAddr)
  112. msg.RelayFromAddr = netAddrToProtoAddr(netip.AddrFrom4(b))
  113. binary.BigEndian.PutUint32(b[:], msg.OldRelayToAddr)
  114. msg.RelayToAddr = netAddrToProtoAddr(netip.AddrFrom4(b))
  115. } else {
  116. v = cert.Version2
  117. }
  118. switch msg.Type {
  119. case NebulaControl_CreateRelayRequest:
  120. rm.handleCreateRelayRequest(v, h, f, msg)
  121. case NebulaControl_CreateRelayResponse:
  122. rm.handleCreateRelayResponse(v, h, f, msg)
  123. }
  124. }
  125. func (rm *relayManager) handleCreateRelayResponse(v cert.Version, h *HostInfo, f *Interface, m *NebulaControl) {
  126. rm.l.WithFields(logrus.Fields{
  127. "relayFrom": protoAddrToNetAddr(m.RelayFromAddr),
  128. "relayTo": protoAddrToNetAddr(m.RelayToAddr),
  129. "initiatorRelayIndex": m.InitiatorRelayIndex,
  130. "responderRelayIndex": m.ResponderRelayIndex,
  131. "vpnAddrs": h.vpnAddrs}).
  132. Info("handleCreateRelayResponse")
  133. target := m.RelayToAddr
  134. targetAddr := protoAddrToNetAddr(target)
  135. relay, err := rm.EstablishRelay(h, m)
  136. if err != nil {
  137. rm.l.WithError(err).Error("Failed to update relay for relayTo")
  138. return
  139. }
  140. // Do I need to complete the relays now?
  141. if relay.Type == TerminalType {
  142. return
  143. }
  144. // I'm the middle man. Let the initiator know that the I've established the relay they requested.
  145. peerHostInfo := rm.hostmap.QueryVpnAddr(relay.PeerAddr)
  146. if peerHostInfo == nil {
  147. rm.l.WithField("relayTo", relay.PeerAddr).Error("Can't find a HostInfo for peer")
  148. return
  149. }
  150. peerRelay, ok := peerHostInfo.relayState.QueryRelayForByIp(targetAddr)
  151. if !ok {
  152. rm.l.WithField("relayTo", peerHostInfo.vpnAddrs[0]).Error("peerRelay does not have Relay state for relayTo")
  153. return
  154. }
  155. switch peerRelay.State {
  156. case Requested:
  157. // I initiated the request to this peer, but haven't heard back from the peer yet. I must wait for this peer
  158. // to respond to complete the connection.
  159. case PeerRequested, Disestablished, Established:
  160. peerHostInfo.relayState.UpdateRelayForByIpState(targetAddr, Established)
  161. resp := NebulaControl{
  162. Type: NebulaControl_CreateRelayResponse,
  163. ResponderRelayIndex: peerRelay.LocalIndex,
  164. InitiatorRelayIndex: peerRelay.RemoteIndex,
  165. }
  166. relayFrom := h.vpnAddrs[0]
  167. if v == cert.Version1 {
  168. peer := peerHostInfo.vpnAddrs[0]
  169. if !peer.Is4() {
  170. rm.l.WithField("relayFrom", peer).
  171. WithField("relayTo", target).
  172. WithField("initiatorRelayIndex", resp.InitiatorRelayIndex).
  173. WithField("responderRelayIndex", resp.ResponderRelayIndex).
  174. WithField("vpnAddrs", peerHostInfo.vpnAddrs).
  175. Error("Refusing to CreateRelayResponse for a v1 relay with an ipv6 address")
  176. return
  177. }
  178. b := peer.As4()
  179. resp.OldRelayFromAddr = binary.BigEndian.Uint32(b[:])
  180. b = targetAddr.As4()
  181. resp.OldRelayToAddr = binary.BigEndian.Uint32(b[:])
  182. } else {
  183. if targetAddr.Is4() {
  184. relayFrom = h.vpnAddrs[0]
  185. } else {
  186. //todo do this smarter
  187. relayFrom = h.vpnAddrs[len(h.vpnAddrs)-1]
  188. }
  189. resp.RelayFromAddr = netAddrToProtoAddr(relayFrom)
  190. resp.RelayToAddr = target
  191. }
  192. msg, err := resp.Marshal()
  193. if err != nil {
  194. rm.l.WithError(err).
  195. Error("relayManager Failed to marshal Control CreateRelayResponse message to create relay")
  196. } else {
  197. f.SendMessageToHostInfo(header.Control, 0, peerHostInfo, msg, make([]byte, 12), make([]byte, mtu))
  198. rm.l.WithFields(logrus.Fields{
  199. "relayFrom": resp.RelayFromAddr,
  200. "relayTo": resp.RelayToAddr,
  201. "initiatorRelayIndex": resp.InitiatorRelayIndex,
  202. "responderRelayIndex": resp.ResponderRelayIndex,
  203. "vpnAddrs": peerHostInfo.vpnAddrs}).
  204. Info("send CreateRelayResponse")
  205. }
  206. }
  207. }
  208. func (rm *relayManager) handleCreateRelayRequest(v cert.Version, h *HostInfo, f *Interface, m *NebulaControl) {
  209. from := protoAddrToNetAddr(m.RelayFromAddr)
  210. target := protoAddrToNetAddr(m.RelayToAddr)
  211. logMsg := rm.l.WithFields(logrus.Fields{
  212. "relayFrom": from,
  213. "relayTo": target,
  214. "initiatorRelayIndex": m.InitiatorRelayIndex,
  215. "vpnAddrs": h.vpnAddrs})
  216. logMsg.Info("handleCreateRelayRequest")
  217. // Is the source of the relay me? This should never happen, but did happen due to
  218. // an issue migrating relays over to newly re-handshaked host info objects.
  219. if f.myVpnAddrsTable.Contains(from) {
  220. logMsg.WithField("myIP", from).Error("Discarding relay request from myself")
  221. return
  222. }
  223. // Is the target of the relay me?
  224. if f.myVpnAddrsTable.Contains(target) {
  225. existingRelay, ok := h.relayState.QueryRelayForByIp(from)
  226. if ok {
  227. switch existingRelay.State {
  228. case Requested:
  229. ok = h.relayState.CompleteRelayByIP(from, m.InitiatorRelayIndex)
  230. if !ok {
  231. logMsg.Error("Relay State not found")
  232. return
  233. }
  234. case Established:
  235. if existingRelay.RemoteIndex != m.InitiatorRelayIndex {
  236. // We got a brand new Relay request, because its index is different than what we saw before.
  237. // This should never happen. The peer should never change an index, once created.
  238. logMsg.WithFields(logrus.Fields{
  239. "existingRemoteIndex": existingRelay.RemoteIndex}).Error("Existing relay mismatch with CreateRelayRequest")
  240. return
  241. }
  242. case Disestablished:
  243. if existingRelay.RemoteIndex != m.InitiatorRelayIndex {
  244. // We got a brand new Relay request, because its index is different than what we saw before.
  245. // This should never happen. The peer should never change an index, once created.
  246. logMsg.WithFields(logrus.Fields{
  247. "existingRemoteIndex": existingRelay.RemoteIndex}).Error("Existing relay mismatch with CreateRelayRequest")
  248. return
  249. }
  250. // Mark the relay as 'Established' because it's safe to use again
  251. h.relayState.UpdateRelayForByIpState(from, Established)
  252. case PeerRequested:
  253. // I should never be in this state, because I am terminal, not forwarding.
  254. logMsg.WithFields(logrus.Fields{
  255. "existingRemoteIndex": existingRelay.RemoteIndex,
  256. "state": existingRelay.State}).Error("Unexpected Relay State found")
  257. }
  258. } else {
  259. _, err := AddRelay(rm.l, h, f.hostMap, from, &m.InitiatorRelayIndex, TerminalType, Established)
  260. if err != nil {
  261. logMsg.WithError(err).Error("Failed to add relay")
  262. return
  263. }
  264. }
  265. relay, ok := h.relayState.QueryRelayForByIp(from)
  266. if !ok {
  267. logMsg.WithField("from", from).Error("Relay State not found")
  268. return
  269. }
  270. resp := NebulaControl{
  271. Type: NebulaControl_CreateRelayResponse,
  272. ResponderRelayIndex: relay.LocalIndex,
  273. InitiatorRelayIndex: relay.RemoteIndex,
  274. }
  275. if v == cert.Version1 {
  276. b := from.As4()
  277. resp.OldRelayFromAddr = binary.BigEndian.Uint32(b[:])
  278. b = target.As4()
  279. resp.OldRelayToAddr = binary.BigEndian.Uint32(b[:])
  280. } else {
  281. resp.RelayFromAddr = netAddrToProtoAddr(from)
  282. resp.RelayToAddr = netAddrToProtoAddr(target)
  283. }
  284. msg, err := resp.Marshal()
  285. if err != nil {
  286. logMsg.
  287. WithError(err).Error("relayManager Failed to marshal Control CreateRelayResponse message to create relay")
  288. } else {
  289. f.SendMessageToHostInfo(header.Control, 0, h, msg, make([]byte, 12), make([]byte, mtu))
  290. rm.l.WithFields(logrus.Fields{
  291. "relayFrom": from,
  292. "relayTo": target,
  293. "initiatorRelayIndex": resp.InitiatorRelayIndex,
  294. "responderRelayIndex": resp.ResponderRelayIndex,
  295. "vpnAddrs": h.vpnAddrs}).
  296. Info("send CreateRelayResponse")
  297. }
  298. return
  299. } else {
  300. // the target is not me. Create a relay to the target, from me.
  301. if !rm.GetAmRelay() {
  302. return
  303. }
  304. peer := rm.hostmap.QueryVpnAddr(target)
  305. if peer == nil {
  306. // Try to establish a connection to this host. If we get a future relay request,
  307. // we'll be ready!
  308. f.Handshake(target)
  309. return
  310. }
  311. if !peer.remote.IsValid() {
  312. // Only create relays to peers for whom I have a direct connection
  313. return
  314. }
  315. var index uint32
  316. var err error
  317. targetRelay, ok := peer.relayState.QueryRelayForByIp(from)
  318. if ok {
  319. index = targetRelay.LocalIndex
  320. } else {
  321. // Allocate an index in the hostMap for this relay peer
  322. index, err = AddRelay(rm.l, peer, f.hostMap, from, nil, ForwardingType, Requested)
  323. if err != nil {
  324. return
  325. }
  326. }
  327. peer.relayState.UpdateRelayForByIpState(from, Requested)
  328. // Send a CreateRelayRequest to the peer.
  329. req := NebulaControl{
  330. Type: NebulaControl_CreateRelayRequest,
  331. InitiatorRelayIndex: index,
  332. }
  333. relayFrom := h.vpnAddrs[0]
  334. if v == cert.Version1 {
  335. if !h.vpnAddrs[0].Is4() {
  336. rm.l.WithField("relayFrom", h.vpnAddrs[0]).
  337. WithField("relayTo", target).
  338. WithField("initiatorRelayIndex", req.InitiatorRelayIndex).
  339. WithField("responderRelayIndex", req.ResponderRelayIndex).
  340. WithField("vpnAddr", target).
  341. Error("Refusing to CreateRelayRequest for a v1 relay with an ipv6 address")
  342. return
  343. }
  344. b := h.vpnAddrs[0].As4()
  345. req.OldRelayFromAddr = binary.BigEndian.Uint32(b[:])
  346. b = target.As4()
  347. req.OldRelayToAddr = binary.BigEndian.Uint32(b[:])
  348. } else {
  349. if target.Is4() {
  350. relayFrom = h.vpnAddrs[0]
  351. } else {
  352. //todo do this smarter
  353. relayFrom = h.vpnAddrs[len(h.vpnAddrs)-1]
  354. }
  355. req.RelayFromAddr = netAddrToProtoAddr(relayFrom)
  356. req.RelayToAddr = netAddrToProtoAddr(target)
  357. }
  358. msg, err := req.Marshal()
  359. if err != nil {
  360. logMsg.
  361. WithError(err).Error("relayManager Failed to marshal Control message to create relay")
  362. } else {
  363. f.SendMessageToHostInfo(header.Control, 0, peer, msg, make([]byte, 12), make([]byte, mtu))
  364. rm.l.WithFields(logrus.Fields{
  365. "relayFrom": relayFrom,
  366. "relayTo": target,
  367. "initiatorRelayIndex": req.InitiatorRelayIndex,
  368. "responderRelayIndex": req.ResponderRelayIndex,
  369. "vpnAddr": target}).
  370. Info("send CreateRelayRequest")
  371. }
  372. // Also track the half-created Relay state just received
  373. _, ok = h.relayState.QueryRelayForByIp(target)
  374. if !ok {
  375. _, err := AddRelay(rm.l, h, f.hostMap, target, &m.InitiatorRelayIndex, ForwardingType, PeerRequested)
  376. if err != nil {
  377. logMsg.
  378. WithError(err).Error("relayManager Failed to allocate a local index for relay")
  379. return
  380. }
  381. }
  382. }
  383. }