relay_manager.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  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. useRelays atomic.Bool
  19. }
  20. func NewRelayManager(ctx context.Context, l *slog.Logger, hostmap *HostMap, c *config.C) *relayManager {
  21. rm := &relayManager{
  22. l: l,
  23. hostmap: hostmap,
  24. }
  25. rm.reload(c, true)
  26. c.RegisterReloadCallback(func(c *config.C) {
  27. err := rm.reload(c, false)
  28. if err != nil {
  29. rm.l.Error("Failed to reload relay_manager", "error", err)
  30. }
  31. })
  32. return rm
  33. }
  34. func (rm *relayManager) reload(c *config.C, initial bool) error {
  35. if initial || c.HasChanged("relay.am_relay") || c.HasChanged("relay.use_relays") {
  36. amRelay := c.GetBool("relay.am_relay", false)
  37. rm.amRelay.Store(amRelay)
  38. rm.useRelays.Store(c.GetBool("relay.use_relays", true) && !amRelay)
  39. }
  40. return nil
  41. }
  42. func (rm *relayManager) GetAmRelay() bool {
  43. return rm.amRelay.Load()
  44. }
  45. func (rm *relayManager) GetUseRelays() bool {
  46. return rm.useRelays.Load()
  47. }
  48. // StartRelays drives the relay-establishment side of an outbound handshake attempt.
  49. // For each candidate relay it either kicks off a handshake to the relay, sends a CreateRelayRequest, retransmits
  50. // one that may have been lost, or, once the relay is Established, forwards the in-progress
  51. // stage 0 handshake packet for vpnIp through it.
  52. func (rm *relayManager) StartRelays(f *Interface, vpnIp netip.Addr, hostinfo *HostInfo, stage0 []byte) {
  53. if !rm.GetUseRelays() || len(hostinfo.remotes.relays) == 0 {
  54. return
  55. }
  56. hostinfo.logger(rm.l).Info("Attempt to relay through hosts", "relays", hostinfo.remotes.relays)
  57. // One WireBuffer for the whole relay-fanout loop.
  58. buf := f.bufAlloc.Acquire()
  59. defer f.bufAlloc.Release(buf)
  60. // Send a RelayRequest to all known Relay IP's
  61. for _, relay := range hostinfo.remotes.relays {
  62. // Don't relay through the host I'm trying to connect to
  63. if relay == vpnIp {
  64. continue
  65. }
  66. // Don't relay to myself
  67. if f.myVpnAddrsTable.Contains(relay) {
  68. continue
  69. }
  70. relayHostInfo := rm.hostmap.QueryVpnAddr(relay)
  71. if relayHostInfo == nil || !relayHostInfo.remote.IsValid() {
  72. hostinfo.logger(rm.l).Info("Establish tunnel to relay target", "relay", relay.String())
  73. f.Handshake(relay)
  74. continue
  75. }
  76. // Check the relay HostInfo to see if we already established a relay through
  77. existingRelay, ok := relayHostInfo.relayState.QueryRelayForByIp(vpnIp)
  78. if !ok {
  79. // No relays exist or requested yet.
  80. if relayHostInfo.remote.IsValid() {
  81. idx, err := AddRelay(rm.l, relayHostInfo, rm.hostmap, vpnIp, nil, TerminalType, Requested)
  82. if err != nil {
  83. hostinfo.logger(rm.l).Info("Failed to add relay to hostmap", "relay", relay.String(), "error", err)
  84. }
  85. m := NebulaControl{
  86. Type: NebulaControl_CreateRelayRequest,
  87. InitiatorRelayIndex: idx,
  88. }
  89. switch relayHostInfo.GetCert().Certificate.Version() {
  90. case cert.Version1:
  91. if !f.myVpnAddrs[0].Is4() {
  92. hostinfo.logger(rm.l).Error("can not establish v1 relay with a v6 network because the relay is not running a current nebula version")
  93. continue
  94. }
  95. if !vpnIp.Is4() {
  96. hostinfo.logger(rm.l).Error("can not establish v1 relay with a v6 remote network because the relay is not running a current nebula version")
  97. continue
  98. }
  99. b := f.myVpnAddrs[0].As4()
  100. m.OldRelayFromAddr = binary.BigEndian.Uint32(b[:])
  101. b = vpnIp.As4()
  102. m.OldRelayToAddr = binary.BigEndian.Uint32(b[:])
  103. case cert.Version2:
  104. m.RelayFromAddr = netAddrToProtoAddr(f.myVpnAddrs[0])
  105. m.RelayToAddr = netAddrToProtoAddr(vpnIp)
  106. default:
  107. hostinfo.logger(rm.l).Error("Unknown certificate version found while creating relay")
  108. continue
  109. }
  110. msg, err := m.Marshal()
  111. if err != nil {
  112. hostinfo.logger(rm.l).Error("Failed to marshal Control message to create relay", "error", err)
  113. } else {
  114. f.SendMessageToHostInfo(header.Control, 0, relayHostInfo, msg, buf)
  115. rm.l.Info("send CreateRelayRequest",
  116. "relayFrom", f.myVpnAddrs[0],
  117. "relayTo", vpnIp,
  118. "initiatorRelayIndex", idx,
  119. "relay", relay,
  120. )
  121. }
  122. }
  123. continue
  124. }
  125. switch existingRelay.State {
  126. case Established:
  127. hostinfo.logger(rm.l).Info("Send handshake via relay", "relay", relay.String())
  128. f.SendVia(relayHostInfo, existingRelay, stage0, buf)
  129. case Disestablished:
  130. // Mark this relay as 'requested'
  131. relayHostInfo.relayState.UpdateRelayForByIpState(vpnIp, Requested)
  132. fallthrough
  133. case Requested:
  134. hostinfo.logger(rm.l).Info("Re-send CreateRelay request", "relay", relay.String())
  135. // Re-send the CreateRelay request, in case the previous one was lost.
  136. m := NebulaControl{
  137. Type: NebulaControl_CreateRelayRequest,
  138. InitiatorRelayIndex: existingRelay.LocalIndex,
  139. }
  140. switch relayHostInfo.GetCert().Certificate.Version() {
  141. case cert.Version1:
  142. if !f.myVpnAddrs[0].Is4() {
  143. hostinfo.logger(rm.l).Error("can not establish v1 relay with a v6 network because the relay is not running a current nebula version")
  144. continue
  145. }
  146. if !vpnIp.Is4() {
  147. hostinfo.logger(rm.l).Error("can not establish v1 relay with a v6 remote network because the relay is not running a current nebula version")
  148. continue
  149. }
  150. b := f.myVpnAddrs[0].As4()
  151. m.OldRelayFromAddr = binary.BigEndian.Uint32(b[:])
  152. b = vpnIp.As4()
  153. m.OldRelayToAddr = binary.BigEndian.Uint32(b[:])
  154. case cert.Version2:
  155. m.RelayFromAddr = netAddrToProtoAddr(f.myVpnAddrs[0])
  156. m.RelayToAddr = netAddrToProtoAddr(vpnIp)
  157. default:
  158. hostinfo.logger(rm.l).Error("Unknown certificate version found while creating relay")
  159. continue
  160. }
  161. msg, err := m.Marshal()
  162. if err != nil {
  163. hostinfo.logger(rm.l).Error("Failed to marshal Control message to create relay", "error", err)
  164. } else {
  165. // This must send over the hostinfo, not over hm.Hosts[ip]
  166. f.SendMessageToHostInfo(header.Control, 0, relayHostInfo, msg, buf)
  167. rm.l.Info("send CreateRelayRequest",
  168. "relayFrom", f.myVpnAddrs[0],
  169. "relayTo", vpnIp,
  170. "initiatorRelayIndex", existingRelay.LocalIndex,
  171. "relay", relay,
  172. )
  173. }
  174. case PeerRequested:
  175. // PeerRequested only occurs in Forwarding relays, not Terminal relays, and this is a Terminal relay case.
  176. fallthrough
  177. default:
  178. hostinfo.logger(rm.l).Error("Relay unexpected state",
  179. "vpnIp", vpnIp,
  180. "state", existingRelay.State,
  181. "relay", relay,
  182. )
  183. }
  184. }
  185. }
  186. // AddRelay finds an available relay index on the hostmap, and associates the relay info with it.
  187. // relayHostInfo is the Nebula peer which can be used as a relay to access the target vpnIp.
  188. func AddRelay(l *slog.Logger, relayHostInfo *HostInfo, hm *HostMap, vpnIp netip.Addr, remoteIdx *uint32, relayType int, state int) (uint32, error) {
  189. hm.Lock()
  190. defer hm.Unlock()
  191. for range 32 {
  192. index, err := generateIndex(l)
  193. if err != nil {
  194. return 0, err
  195. }
  196. _, inRelays := hm.Relays[index]
  197. if !inRelays {
  198. // Avoid standing up a relay that can't be used since only the primary hostinfo
  199. // will be pointed to by the relay logic
  200. //TODO: if there was an existing primary and it had relay state, should we merge?
  201. hm.unlockedMakePrimary(relayHostInfo)
  202. hm.Relays[index] = relayHostInfo
  203. newRelay := Relay{
  204. Type: relayType,
  205. State: state,
  206. LocalIndex: index,
  207. PeerAddr: vpnIp,
  208. }
  209. if remoteIdx != nil {
  210. newRelay.RemoteIndex = *remoteIdx
  211. }
  212. relayHostInfo.relayState.InsertRelay(vpnIp, index, &newRelay)
  213. return index, nil
  214. }
  215. }
  216. return 0, errors.New("failed to generate unique localIndexId")
  217. }
  218. // EstablishRelay updates a Requested Relay to become an Established Relay, which can pass traffic.
  219. func (rm *relayManager) EstablishRelay(relayHostInfo *HostInfo, m *NebulaControl) (*Relay, error) {
  220. relay, ok := relayHostInfo.relayState.CompleteRelayByIdx(m.InitiatorRelayIndex, m.ResponderRelayIndex)
  221. if !ok {
  222. var relayFrom, relayTo any
  223. if m.RelayFromAddr == nil {
  224. relayFrom = m.OldRelayFromAddr
  225. } else {
  226. relayFrom = m.RelayFromAddr
  227. }
  228. if m.RelayToAddr == nil {
  229. relayTo = m.OldRelayToAddr
  230. } else {
  231. relayTo = m.RelayToAddr
  232. }
  233. rm.l.Info("relayManager failed to update relay",
  234. "relay", relayHostInfo.vpnAddrs[0],
  235. "initiatorRelayIndex", m.InitiatorRelayIndex,
  236. "relayFrom", relayFrom,
  237. "relayTo", relayTo,
  238. )
  239. return nil, fmt.Errorf("unknown relay")
  240. }
  241. return relay, nil
  242. }
  243. func (rm *relayManager) HandleControlMsg(h *HostInfo, d []byte, f *Interface) {
  244. msg := &NebulaControl{}
  245. err := msg.Unmarshal(d)
  246. if err != nil {
  247. h.logger(f.l).Error("Failed to unmarshal control message", "error", err)
  248. return
  249. }
  250. var v cert.Version
  251. if msg.OldRelayFromAddr > 0 || msg.OldRelayToAddr > 0 {
  252. v = cert.Version1
  253. b := [4]byte{}
  254. binary.BigEndian.PutUint32(b[:], msg.OldRelayFromAddr)
  255. msg.RelayFromAddr = netAddrToProtoAddr(netip.AddrFrom4(b))
  256. binary.BigEndian.PutUint32(b[:], msg.OldRelayToAddr)
  257. msg.RelayToAddr = netAddrToProtoAddr(netip.AddrFrom4(b))
  258. } else {
  259. v = cert.Version2
  260. }
  261. switch msg.Type {
  262. case NebulaControl_CreateRelayRequest:
  263. rm.handleCreateRelayRequest(v, h, f, msg)
  264. case NebulaControl_CreateRelayResponse:
  265. rm.handleCreateRelayResponse(v, h, f, msg)
  266. }
  267. }
  268. func (rm *relayManager) handleCreateRelayResponse(v cert.Version, h *HostInfo, f *Interface, m *NebulaControl) {
  269. rm.l.Info("handleCreateRelayResponse",
  270. "relayFrom", protoAddrToNetAddr(m.RelayFromAddr),
  271. "relayTo", protoAddrToNetAddr(m.RelayToAddr),
  272. "initiatorRelayIndex", m.InitiatorRelayIndex,
  273. "responderRelayIndex", m.ResponderRelayIndex,
  274. "vpnAddrs", h.vpnAddrs,
  275. )
  276. target := m.RelayToAddr
  277. targetAddr := protoAddrToNetAddr(target)
  278. relay, err := rm.EstablishRelay(h, m)
  279. if err != nil {
  280. rm.l.Error("Failed to update relay for relayTo", "error", err)
  281. return
  282. }
  283. // Do I need to complete the relays now?
  284. if relay.Type == TerminalType {
  285. return
  286. }
  287. // I'm the middle man. Let the initiator know that the I've established the relay they requested.
  288. peerHostInfo := rm.hostmap.QueryVpnAddr(relay.PeerAddr)
  289. if peerHostInfo == nil {
  290. rm.l.Error("Can't find a HostInfo for peer", "relayTo", relay.PeerAddr)
  291. return
  292. }
  293. peerRelay, ok := peerHostInfo.relayState.QueryRelayForByIp(targetAddr)
  294. if !ok {
  295. rm.l.Error("peerRelay does not have Relay state for relayTo", "relayTo", peerHostInfo.vpnAddrs[0])
  296. return
  297. }
  298. switch peerRelay.State {
  299. case Requested:
  300. // I initiated the request to this peer, but haven't heard back from the peer yet. I must wait for this peer
  301. // to respond to complete the connection.
  302. case PeerRequested, Disestablished, Established:
  303. peerHostInfo.relayState.UpdateRelayForByIpState(targetAddr, Established)
  304. resp := NebulaControl{
  305. Type: NebulaControl_CreateRelayResponse,
  306. ResponderRelayIndex: peerRelay.LocalIndex,
  307. InitiatorRelayIndex: peerRelay.RemoteIndex,
  308. }
  309. if v == cert.Version1 {
  310. peer := peerHostInfo.vpnAddrs[0]
  311. if !peer.Is4() {
  312. rm.l.Error("Refusing to CreateRelayResponse for a v1 relay with an ipv6 address",
  313. "relayFrom", peer,
  314. "relayTo", target,
  315. "initiatorRelayIndex", resp.InitiatorRelayIndex,
  316. "responderRelayIndex", resp.ResponderRelayIndex,
  317. "vpnAddrs", peerHostInfo.vpnAddrs,
  318. )
  319. return
  320. }
  321. b := peer.As4()
  322. resp.OldRelayFromAddr = binary.BigEndian.Uint32(b[:])
  323. b = targetAddr.As4()
  324. resp.OldRelayToAddr = binary.BigEndian.Uint32(b[:])
  325. } else {
  326. resp.RelayFromAddr = netAddrToProtoAddr(peerHostInfo.vpnAddrs[0])
  327. resp.RelayToAddr = target
  328. }
  329. msg, err := resp.Marshal()
  330. if err != nil {
  331. rm.l.Error("relayManager Failed to marshal Control CreateRelayResponse message to create relay", "error", err)
  332. } else {
  333. buf := f.bufAlloc.Acquire()
  334. f.SendMessageToHostInfo(header.Control, 0, peerHostInfo, msg, buf)
  335. f.bufAlloc.Release(buf)
  336. rm.l.Info("send CreateRelayResponse",
  337. "relayFrom", resp.RelayFromAddr,
  338. "relayTo", resp.RelayToAddr,
  339. "initiatorRelayIndex", resp.InitiatorRelayIndex,
  340. "responderRelayIndex", resp.ResponderRelayIndex,
  341. "vpnAddrs", peerHostInfo.vpnAddrs,
  342. )
  343. }
  344. }
  345. }
  346. func (rm *relayManager) handleCreateRelayRequest(v cert.Version, h *HostInfo, f *Interface, m *NebulaControl) {
  347. from := protoAddrToNetAddr(m.RelayFromAddr)
  348. target := protoAddrToNetAddr(m.RelayToAddr)
  349. logMsg := rm.l.With(
  350. "relayFrom", from,
  351. "relayTo", target,
  352. "initiatorRelayIndex", m.InitiatorRelayIndex,
  353. "vpnAddrs", h.vpnAddrs,
  354. )
  355. logMsg.Info("handleCreateRelayRequest")
  356. // Is the source of the relay me? This should never happen, but did happen due to
  357. // an issue migrating relays over to newly re-handshaked host info objects.
  358. if f.myVpnAddrsTable.Contains(from) {
  359. logMsg.Error("Discarding relay request from myself", "myIP", from)
  360. return
  361. }
  362. // Is the target of the relay me?
  363. if f.myVpnAddrsTable.Contains(target) {
  364. existingRelay, ok := h.relayState.QueryRelayForByIp(from)
  365. if ok {
  366. switch existingRelay.State {
  367. case Requested:
  368. ok = h.relayState.CompleteRelayByIP(from, m.InitiatorRelayIndex)
  369. if !ok {
  370. logMsg.Error("Relay State not found")
  371. return
  372. }
  373. case Established:
  374. if existingRelay.RemoteIndex != m.InitiatorRelayIndex {
  375. // We got a brand new Relay request, because its index is different than what we saw before.
  376. // This should never happen. The peer should never change an index, once created.
  377. logMsg.Error("Existing relay mismatch with CreateRelayRequest",
  378. "existingRemoteIndex", existingRelay.RemoteIndex)
  379. return
  380. }
  381. case Disestablished:
  382. if existingRelay.RemoteIndex != m.InitiatorRelayIndex {
  383. // We got a brand new Relay request, because its index is different than what we saw before.
  384. // This should never happen. The peer should never change an index, once created.
  385. logMsg.Error("Existing relay mismatch with CreateRelayRequest",
  386. "existingRemoteIndex", existingRelay.RemoteIndex)
  387. return
  388. }
  389. // Mark the relay as 'Established' because it's safe to use again
  390. h.relayState.UpdateRelayForByIpState(from, Established)
  391. case PeerRequested:
  392. // I should never be in this state, because I am terminal, not forwarding.
  393. logMsg.Error("Unexpected Relay State found",
  394. "existingRemoteIndex", existingRelay.RemoteIndex,
  395. "state", existingRelay.State)
  396. }
  397. } else {
  398. _, err := AddRelay(rm.l, h, f.hostMap, from, &m.InitiatorRelayIndex, TerminalType, Established)
  399. if err != nil {
  400. logMsg.Error("Failed to add relay", "error", err)
  401. return
  402. }
  403. }
  404. relay, ok := h.relayState.QueryRelayForByIp(from)
  405. if !ok {
  406. logMsg.Error("Relay State not found", "from", from)
  407. return
  408. }
  409. resp := NebulaControl{
  410. Type: NebulaControl_CreateRelayResponse,
  411. ResponderRelayIndex: relay.LocalIndex,
  412. InitiatorRelayIndex: relay.RemoteIndex,
  413. }
  414. if v == cert.Version1 {
  415. b := from.As4()
  416. resp.OldRelayFromAddr = binary.BigEndian.Uint32(b[:])
  417. b = target.As4()
  418. resp.OldRelayToAddr = binary.BigEndian.Uint32(b[:])
  419. } else {
  420. resp.RelayFromAddr = netAddrToProtoAddr(from)
  421. resp.RelayToAddr = netAddrToProtoAddr(target)
  422. }
  423. msg, err := resp.Marshal()
  424. if err != nil {
  425. logMsg.Error("relayManager Failed to marshal Control CreateRelayResponse message to create relay", "error", err)
  426. } else {
  427. buf := f.bufAlloc.Acquire()
  428. f.SendMessageToHostInfo(header.Control, 0, h, msg, buf)
  429. f.bufAlloc.Release(buf)
  430. rm.l.Info("send CreateRelayResponse",
  431. "relayFrom", from,
  432. "relayTo", target,
  433. "initiatorRelayIndex", resp.InitiatorRelayIndex,
  434. "responderRelayIndex", resp.ResponderRelayIndex,
  435. "vpnAddrs", h.vpnAddrs,
  436. )
  437. }
  438. return
  439. } else {
  440. // the target is not me. Create a relay to the target, from me.
  441. if !rm.GetAmRelay() {
  442. return
  443. }
  444. peer := rm.hostmap.QueryVpnAddr(target)
  445. if peer == nil {
  446. // Try to establish a connection to this host. If we get a future relay request,
  447. // we'll be ready!
  448. f.Handshake(target)
  449. return
  450. }
  451. if !peer.remote.IsValid() {
  452. // Only create relays to peers for whom I have a direct connection
  453. return
  454. }
  455. var index uint32
  456. var err error
  457. targetRelay, ok := peer.relayState.QueryRelayForByIp(from)
  458. if ok {
  459. index = targetRelay.LocalIndex
  460. } else {
  461. // Allocate an index in the hostMap for this relay peer
  462. index, err = AddRelay(rm.l, peer, f.hostMap, from, nil, ForwardingType, Requested)
  463. if err != nil {
  464. return
  465. }
  466. }
  467. peer.relayState.UpdateRelayForByIpState(from, Requested)
  468. // Send a CreateRelayRequest to the peer.
  469. req := NebulaControl{
  470. Type: NebulaControl_CreateRelayRequest,
  471. InitiatorRelayIndex: index,
  472. }
  473. if v == cert.Version1 {
  474. if !h.vpnAddrs[0].Is4() {
  475. rm.l.Error("Refusing to CreateRelayRequest for a v1 relay with an ipv6 address",
  476. "relayFrom", h.vpnAddrs[0],
  477. "relayTo", target,
  478. "initiatorRelayIndex", req.InitiatorRelayIndex,
  479. "responderRelayIndex", req.ResponderRelayIndex,
  480. "vpnAddr", target,
  481. )
  482. return
  483. }
  484. b := h.vpnAddrs[0].As4()
  485. req.OldRelayFromAddr = binary.BigEndian.Uint32(b[:])
  486. b = target.As4()
  487. req.OldRelayToAddr = binary.BigEndian.Uint32(b[:])
  488. } else {
  489. req.RelayFromAddr = netAddrToProtoAddr(h.vpnAddrs[0])
  490. req.RelayToAddr = netAddrToProtoAddr(target)
  491. }
  492. msg, err := req.Marshal()
  493. if err != nil {
  494. logMsg.Error("relayManager Failed to marshal Control message to create relay", "error", err)
  495. } else {
  496. buf := f.bufAlloc.Acquire()
  497. f.SendMessageToHostInfo(header.Control, 0, peer, msg, buf)
  498. f.bufAlloc.Release(buf)
  499. rm.l.Info("send CreateRelayRequest",
  500. "relayFrom", h.vpnAddrs[0],
  501. "relayTo", target,
  502. "initiatorRelayIndex", req.InitiatorRelayIndex,
  503. "responderRelayIndex", req.ResponderRelayIndex,
  504. "vpnAddr", target,
  505. )
  506. }
  507. // Also track the half-created Relay state just received
  508. _, ok = h.relayState.QueryRelayForByIp(target)
  509. if !ok {
  510. _, err := AddRelay(rm.l, h, f.hostMap, target, &m.InitiatorRelayIndex, ForwardingType, PeerRequested)
  511. if err != nil {
  512. logMsg.Error("relayManager Failed to allocate a local index for relay", "error", err)
  513. return
  514. }
  515. }
  516. }
  517. }