Exemplo n.º 1
0
        /// <returns>null if no neighbors found for routing</returns>
        public ConnectionToNeighbor RouteInviteRequest(LocalDrpPeer localDrpPeer, RoutedRequest routedRequest)
        {
            var req    = routedRequest.InviteReq;
            var logger = routedRequest.Logger;
            ConnectionToNeighbor   r           = null;
            RegistrationIdDistance minDistance = null;
            var connectedNeighborsForRouting   = localDrpPeer.GetConnectedNeighborsForRouting(routedRequest).ToList();

            foreach (var connectedPeer in connectedNeighborsForRouting)
            {
                var distanceToConnectedPeer = req.ResponderRegistrationId.GetDistanceTo(_cryptoLibrary, connectedPeer.RemoteRegistrationId, NumberOfDimensions);
                logger.WriteToLog_routing_detail($"distanceToConnectedPeer={distanceToConnectedPeer} from {req} to {connectedPeer}");
                if (minDistance == null || minDistance.IsGreaterThan(distanceToConnectedPeer))
                {
                    minDistance = distanceToConnectedPeer;
                    r           = connectedPeer;
                }
            }
            if (r == null)
            {
                logger.WriteToLog_routing_detail($"no neighbors found for routing");
            }

            return(r);
        }
Exemplo n.º 2
0
        public IEnumerable <ConnectionToNeighbor> GetConnectedNeighborsForRouting(RoutedRequest routedRequest)
        {
            foreach (var connectedPeer in ConnectedNeighborsCanBeUsedForNewRequests)
            {
                if (routedRequest.ReceivedFromNeighborNullable != null && connectedPeer == routedRequest.ReceivedFromNeighborNullable)
                {
                    if (routedRequest.Logger.WriteToLog_deepDetail_enabled)
                    {
                        routedRequest.Logger.WriteToLog_deepDetail($"skipping routing back to source peer {connectedPeer}");
                    }
                    continue;
                }
                if (routedRequest.TriedNeighbors.Contains(connectedPeer))
                {
                    if (routedRequest.Logger.WriteToLog_deepDetail_enabled)
                    {
                        routedRequest.Logger.WriteToLog_deepDetail($"skipping routing to previously tried peer {connectedPeer}");
                    }
                    continue;
                }

                if (routedRequest.RequesterRegistrationId.Equals(connectedPeer.RemoteRegistrationId))
                {
                    if (routedRequest.Logger.WriteToLog_deepDetail_enabled)
                    {
                        routedRequest.Logger.WriteToLog_deepDetail($"skipping routing to peer with same regID {connectedPeer}");
                    }
                    continue;
                }

                yield return(connectedPeer);
            }
        }
Exemplo n.º 3
0
        async Task ProcessRegisterReqAtoEpPacket2Async(IPEndPoint requesterEndpoint, RegisterRequestPacket req, Stopwatch reqReceivedSW)
        {
            var firstLocalPeer = LocalPeers.Values.FirstOrDefault();

            if (firstLocalPeer != null)
            {
                var logger        = new Logger(this, firstLocalPeer, req, VisionChannelModuleName_reg);
                var routedRequest = new RoutedRequest(logger, null, requesterEndpoint, reqReceivedSW, null, req);
                await ProcessRegisterRequestAsync(null, routedRequest);
            }
            else
            {
                WriteToLog_reg_responderSide_higherLevelDetail($"no local peers to accept {req}");
            }
        }
Exemplo n.º 4
0
        public RoutedRequest(Logger logger, ConnectionToNeighbor receivedFromNeighborNullable, IPEndPoint receivedFromEndpoint,
                             Stopwatch reqReceivedSwNullable, InviteRequestPacket inviteReqNullable,
                             RegisterRequestPacket registerReqNullable, RoutedRequest previousTrialRoutedRequestNullable = null)
        {
            InviteReq   = inviteReqNullable;
            RegisterReq = registerReqNullable;
            if (InviteReq == null && RegisterReq == null)
            {
                throw new ArgumentException();
            }
            if (InviteReq != null && RegisterReq != null)
            {
                throw new ArgumentException();
            }

            ReceivedFromNeighborNullable = receivedFromNeighborNullable;
            ReceivedFromEndpoint         = receivedFromEndpoint;
            Logger  = logger;
            _engine = logger.Engine;
            ReqReceivedSwNullable = reqReceivedSwNullable;

            if (InviteReq != null)
            {
                ReqP2pSeq16 = InviteReq.ReqP2pSeq16;
            }
            else
            {
                ReqP2pSeq16 = RegisterReq.ReqP2pSeq16;
            }

            if (previousTrialRoutedRequestNullable != null)
            {
                _repliedWithNPA = previousTrialRoutedRequestNullable._repliedWithNPA;
                TriedNeighbors  = previousTrialRoutedRequestNullable.TriedNeighbors;
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// main register responder proc for both A-EP and P2P modes
        /// in P2P mode Timestamp32S, NeighborToken32 and NeighborHMAC are verified at this time
        /// </summary>
        /// <param name="receivedFromInP2pMode">
        /// is null in A-EP mode
        /// </param>
        internal async Task AcceptRegisterRequestAsync(LocalDrpPeer acceptAt, RoutedRequest routedRequest) // engine thread
        {
            var logger = routedRequest.Logger;

            logger.ModuleName = VisionChannelModuleName_reg_responderSide;
            var req = routedRequest.RegisterReq;

            if (req.RequesterRegistrationId.Equals(acceptAt.Configuration.LocalPeerRegistrationId))
            {
                throw new InvalidOperationException();
            }

            // check  signature of requester (A)
            if (!req.RequesterSignature.Verify(_cryptoLibrary,
                                               w => req.GetSharedSignedFields(w, false),
                                               req.RequesterRegistrationId
                                               )
                )
            {
                throw new BadSignatureException("invalid REGISTER REQ RequesterSignature 2396");
            }

            if (routedRequest.ReceivedFromNeighborNullable == null)
            { // A-EP mode
                if (req.EpEndpoint.Address.Equals(acceptAt.PublicIpApiProviderResponse) == false)
                {
                    throw new PossibleAttackException();
                }
            }

            if (PendingRegisterRequestExists(req.RequesterRegistrationId))
            {
                // received duplicate REGISTER REQ packet
                logger.WriteToLog_needsAttention($"ignoring duplicate registration request {req.RequesterRegistrationId} from {routedRequest.ReceivedFromEndpoint}");
                return;
            }

            if (!RecentUniqueAcceptedRegistrationRequests.Filter(req.GetUniqueRequestIdFields))
            {
                logger.WriteToLog_needsAttention($"ignoring registration request {req.RequesterRegistrationId} ts={req.ReqTimestamp64} from {routedRequest.ReceivedFromEndpoint} with non-unique request ID fields");
                return;
            }

            logger.WriteToLog_higherLevelDetail($"accepting registration from {routedRequest.ReceivedFromEndpoint}: ReqP2pSeq16={req.ReqP2pSeq16}, NumberOfHopsRemaining={req.NumberOfHopsRemaining}, epEndpoint={req.EpEndpoint}, sourcePeer={routedRequest.ReceivedFromNeighborNullable}, ts={req.ReqTimestamp64}");

            if (!RecentUniquePublicEcdhKeys.Filter(req.RequesterEcdhePublicKey.Ecdh25519PublicKey))
            {
                logger.WriteToLog_needsAttention($"ignoring registration request {req.RequesterRegistrationId} from {routedRequest.ReceivedFromEndpoint} with non-unique RequesterEcdhePublicKey");
                return;
            }

            _pendingRegisterRequests.Add(req.RequesterRegistrationId);
            try
            {
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"sending NPACK to REQ to {routedRequest.ReceivedFromEndpoint} (delay={routedRequest.ReqReceivedSw_ms}ms)");
                }
                routedRequest.SendNeighborPeerAck_accepted_IfNotAlreadyReplied();

                var newConnectionToNeighbor = new ConnectionToNeighbor(this, acceptAt, ConnectedDrpPeerInitiatedBy.remotePeer, req.RequesterRegistrationId)
                {
                    LocalEndpoint = routedRequest.ReceivedFromNeighborNullable?.LocalEndpoint ?? req.EpEndpoint,
                };
                byte[] ack1UdpData;
                try
                {
                    var ack1 = new RegisterAck1Packet
                    {
                        RequesterRegistrationId = req.RequesterRegistrationId,
                        ReqTimestamp64          = req.ReqTimestamp64,
                        ResponderEcdhePublicKey = new EcdhPublicKey(newConnectionToNeighbor.LocalEcdhe25519PublicKey),
                        ResponderRegistrationId = acceptAt.Configuration.LocalPeerRegistrationId,
                        ReqP2pSeq16             = GetNewNpaSeq16_AtoEP(),
                    };
                    RecentUniquePublicEcdhKeys.AssertIsUnique(ack1.ResponderEcdhePublicKey.Ecdh25519PublicKey, $"ack1.ResponderEcdhePublicKey");
                    ack1.ToResponderTxParametersEncrypted = newConnectionToNeighbor.Encrypt_ack1_ToResponderTxParametersEncrypted_AtResponder_DeriveSharedDhSecret(logger, req, ack1, routedRequest.ReceivedFromNeighborNullable);
                    ack1.ResponderSignature = RegistrationSignature.Sign(_cryptoLibrary,
                                                                         (w2) =>
                    {
                        req.GetSharedSignedFields(w2, true);
                        ack1.GetSharedSignedFields(w2, false, true);
                    },
                                                                         acceptAt.Configuration.LocalPeerRegistrationPrivateKey);
                    if (routedRequest.ReceivedFromNeighborNullable == null)
                    {
                        ack1.RequesterEndpoint = routedRequest.ReceivedFromEndpoint;
                    }
                    ack1UdpData = ack1.Encode_OpionallySignNeighborHMAC(routedRequest.ReceivedFromNeighborNullable);

                    var    ack2Scanner = RegisterAck2Packet.GetScanner(logger, routedRequest.ReceivedFromNeighborNullable, req);
                    var    requesterVisibleDescription = routedRequest.ReceivedFromNeighborNullable?.ToString() ?? routedRequest.ReceivedFromEndpoint.ToString();
                    byte[] ack2UdpData;
                    if (routedRequest.ReceivedFromNeighborNullable == null)
                    {   // wait for ACK2, retransmitting ACK1
                        if (logger.WriteToLog_detail_enabled)
                        {
                            logger.WriteToLog_detail($"sending ACK1, waiting for ACK2");
                        }
                        ack2UdpData = await OptionallySendUdpRequestAsync_Retransmit_WaitForResponse("ack2 33469", requesterVisibleDescription, ack1UdpData, routedRequest.ReceivedFromEndpoint, ack2Scanner);
                    }
                    else
                    {   // retransmit ACK1 until NPACK (via P2P); at same time wait for ACK
                        if (logger.WriteToLog_detail_enabled)
                        {
                            logger.WriteToLog_detail($"sending ACK1, awaiting for NPACK");
                        }
                        _ = OptionallySendUdpRequestAsync_Retransmit_WaitForNeighborPeerAck("ack1 423087", ack1UdpData, routedRequest.ReceivedFromEndpoint,
                                                                                            ack1.ReqP2pSeq16, routedRequest.ReceivedFromNeighborNullable, ack1.GetSignedFieldsForNeighborHMAC);
                        // not waiting for NPACK, wait for ACK
                        if (logger.WriteToLog_detail_enabled)
                        {
                            logger.WriteToLog_detail($"waiting for ACK2");
                        }
                        ack2UdpData = await OptionallySendUdpRequestAsync_Retransmit_WaitForResponse("ack2 46051", requesterVisibleDescription, null, routedRequest.ReceivedFromEndpoint, ack2Scanner);
                    }

                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"received ACK2");
                    }
                    var ack2 = RegisterAck2Packet.Decode_OptionallyVerify_InitializeP2pStreamAtResponder(logger, ack2UdpData, req, ack1, newConnectionToNeighbor);
                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"verified ACK2");
                    }

                    acceptAt.AddToConnectedNeighbors(newConnectionToNeighbor, req);                                                                  // added to list here in order to respond to ping requests from A

                    SendNeighborPeerAckResponseToRegisterAck2(ack2, routedRequest.ReceivedFromEndpoint, routedRequest.ReceivedFromNeighborNullable); // send NPACK to ACK

                    _ = WaitForRegistrationConfirmationRequestAsync(requesterVisibleDescription, logger, routedRequest.ReceivedFromEndpoint, req, newConnectionToNeighbor, routedRequest.ReceivedFromNeighborNullable);

                    #region send ping, verify pong
                    var ping = newConnectionToNeighbor.CreatePing(true, false, acceptAt.ConnectedNeighborsBusySectorIds, acceptAt.AnotherNeighborToSameSectorExists(newConnectionToNeighbor));

                    var pendingPingRequest = new PendingLowLevelUdpRequest("pendingPingRequest 693", newConnectionToNeighbor.RemoteEndpoint,
                                                                           PongPacket.GetScanner(newConnectionToNeighbor.LocalNeighborToken32, ping.PingRequestId32), DateTimeNowUtc,
                                                                           Configuration.InitialPingRequests_ExpirationTimeoutS,
                                                                           ping.Encode(),
                                                                           Configuration.InitialPingRequests_InitialRetransmissionTimeoutS,
                                                                           Configuration.InitialPingRequests_RetransmissionTimeoutIncrement
                                                                           );

                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"sent PING");
                    }
                    var pongPacketData = await SendUdpRequestAsync_Retransmit(pendingPingRequest); // wait for pong from A

                    if (pongPacketData == null)
                    {
                        throw new DrpTimeoutException($"reg. responder initial PING request to {newConnectionToNeighbor} (timeout={Configuration.InitialPingRequests_ExpirationTimeoutS}s)");
                    }
                    var pong = PongPacket.DecodeAndVerify(_cryptoLibrary,
                                                          pongPacketData, ping, newConnectionToNeighbor,
                                                          true);
                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"verified PONG");
                    }
                    newConnectionToNeighbor.OnReceivedVerifiedPong(pong, pendingPingRequest.ResponseReceivedAtUtc.Value,
                                                                   pendingPingRequest.ResponseReceivedAtUtc.Value - pendingPingRequest.InitialTxTimeUTC.Value);
                    #endregion
                }
                catch (Exception exc)
                {
                    newConnectionToNeighbor.Dispose();
                    throw exc;
                }
            }
            catch (DrpTimeoutException exc)
            {
                logger.WriteToLog_needsAttention($"could not accept REGISTER request: {exc}");
            }
            catch (Exception exc)
            {
                logger.WriteToLog_mediumPain($"could not accept REGISTER request: {exc}");
            }
            finally
            {
                _pendingRegisterRequests.Remove(req.RequesterRegistrationId);
            }
        }
Exemplo n.º 6
0
        internal async Task ProcessRegisterRequestAsync(LocalDrpPeer receivedAtLocalDrpPeerNullable, RoutedRequest routedRequest)
        {
            var req = routedRequest.RegisterReq;

            if (!ValidateReceivedReqTimestamp64(req.ReqTimestamp64))
            {
                throw new BadSignatureException($"invalid REGISTER REQ 265 ReqTimestamp64={MiscProcedures.Int64ticksToDateTime(req.ReqTimestamp64)}");
            }

            if (PendingRegisterRequestExists(req.RequesterRegistrationId))
            {
                routedRequest.Logger.WriteToLog_higherLevelDetail($"rejecting {req}: another request is already pending");
                await routedRequest.SendErrorResponse(ResponseOrFailureCode.failure_routeIsUnavailable);

                return;
            }


_retry:
            routedRequest.ReceivedFromNeighborNullable?.AssertIsNotDisposed();
            if (!RouteRegistrationRequest(receivedAtLocalDrpPeerNullable, routedRequest, out var proxyToDestinationPeer, out var acceptAt)) // routing
            {                                                                                                                               // no route found
                await routedRequest.SendErrorResponse(ResponseOrFailureCode.failure_routeIsUnavailable);

                return;
            }

            if (acceptAt != null)
            {   // accept the registration request here at this.LocalDrpPeer
                routedRequest.ReceivedFromNeighborNullable?.AssertIsNotDisposed();
                _ = AcceptRegisterRequestAsync(acceptAt, routedRequest);
            }
            else if (proxyToDestinationPeer != null)
            {  // proxy the registration request to another peer
                routedRequest.ReceivedFromNeighborNullable?.AssertIsNotDisposed();
                var needToRerouteToAnotherNeighbor = await ProxyRegisterRequestAsync(routedRequest, proxyToDestinationPeer);

                if (needToRerouteToAnotherNeighbor && routedRequest.ReceivedFromNeighborNullable?.IsDisposed != true)
                {
                    routedRequest.TriedNeighbors.Add(proxyToDestinationPeer);
                    routedRequest.Logger.WriteToLog_detail($"retrying to proxy registration to another neighbor on error. already tried {routedRequest.TriedNeighbors.Count}");
                    routedRequest.ReceivedFromNeighborNullable?.AssertIsNotDisposed();
                    goto _retry;
                }
            }
            else
            {
                routedRequest.Logger.WriteToLog_detail($"rejecting request: routing failed");
                await routedRequest.SendErrorResponse(ResponseOrFailureCode.failure_routeIsUnavailable);
            }
        }
        /// <summary>
        /// Timestamp32S, NeighborToken32 and NeighborHMAC are verified at this time
        /// </summary>
        internal async Task AcceptInviteRequestAsync(RoutedRequest routedRequest)
        {
            if (routedRequest.ReceivedFromNeighborNullable == null)
            {
                throw new ArgumentException();
            }
            var req = routedRequest.InviteReq;

            if (!req.ResponderRegistrationId.Equals(this.Configuration.LocalPeerRegistrationId))
            {
                throw new ArgumentException();
            }
            var logger = routedRequest.Logger;

            logger.ModuleName = DrpPeerEngine.VisionChannelModuleName_inv_responderSide;

            if (logger.WriteToLog_detail_enabled)
            {
                logger.WriteToLog_detail($"accepting {req} from sourcePeer={routedRequest.ReceivedFromNeighborNullable}");
            }

            // check if regID exists in contact book, get userID from the local contact book
            // ignore the REQ packet if no such user in contacts
            this._drpPeerApp.OnReceivedInvite(req.RequesterRegistrationId, req.ContactInvitationTokenNullable, out var remoteRequesterUserIdFromLocalContactBookNullable, out var localUserCertificateWithPrivateKey, out var autoReply);
            if (autoReply == false)
            {
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_needsAttention($"ignored invite: autoReply = false");
                }
                return;
            }
            localUserCertificateWithPrivateKey?.AssertHasPrivateKey();

            if (remoteRequesterUserIdFromLocalContactBookNullable != null)
            {
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"resolved user {remoteRequesterUserIdFromLocalContactBookNullable} by requester regID={req.RequesterRegistrationId}");
                }
            }

            if (!Engine.RecentUniquePublicEcdhKeys.Filter(req.RequesterEcdhePublicKey.Ecdh25519PublicKey))
            {
                logger.WriteToLog_mediumPain($"RequesterEcdhePublicKey {req.RequesterEcdhePublicKey} is not unique, it has been recently processed");
                return;
            }
            if (!Engine.RecentUniqueInviteRequests.Filter(req.GetUniqueRequestIdFields))
            {
                logger.WriteToLog_mediumPain($"{req} fields are not unique, the request has been recently processed");
                return;
            }

            // verify requester reg. signature
            if (!req.RequesterRegistrationSignature.Verify(Engine.CryptoLibrary, req.GetSharedSignedFields, req.RequesterRegistrationId))
            {
                throw new BadSignatureException("invalid INVITE REQ RequesterRegistrationSignature 2349");
            }

            _pendingInviteRequests.Add(req.RequesterRegistrationId);

            try
            {
                // send NPACK to REQ
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"sending NPACK to REQ source peer");
                }
                routedRequest.SendNeighborPeerAck_accepted_IfNotAlreadyReplied();

                var session = new InviteSession(this)
                {
                    Logger = logger
                };
                try
                {
                    session.DeriveSharedInviteAckDhSecret(Engine.CryptoLibrary, req.RequesterEcdhePublicKey.Ecdh25519PublicKey);

                    session.LocalSessionDescription = new InviteSessionDescription
                    {
                        DirectChannelEndPoint = routedRequest.ReceivedFromNeighborNullable.LocalEndpoint,
                        NatBehaviour          = Engine.LocalNatBehaviour,
                        DirectChannelToken32  = session.LocalDirectChannelToken32
                    };
                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"responding with local session {session.LocalSessionDescription}");
                    }

                    session.LocalSessionDescription.UserCertificate = localUserCertificateWithPrivateKey;

                    #region send ACK1. sign local SD by local user
                    var ack1 = new InviteAck1Packet
                    {
                        ReqTimestamp32S         = req.ReqTimestamp32S,
                        RequesterRegistrationId = req.RequesterRegistrationId,
                        ResponderRegistrationId = req.ResponderRegistrationId,
                        ResponderEcdhePublicKey = new EcdhPublicKey(session.LocalInviteAckEcdhePublicKey),
                    };
                    session.LocalSessionDescription.UserCertificateSignature = UserCertificateSignature.Sign(Engine.CryptoLibrary,
                                                                                                             w =>
                    {
                        req.GetSharedSignedFields(w);
                        ack1.GetSharedSignedFields(w, false);
                        session.LocalSessionDescription.WriteSignedFields(w);
                    },
                                                                                                             localUserCertificateWithPrivateKey);

                    ack1.ToResponderSessionDescriptionEncrypted = session.LocalSessionDescription.Encrypt(Engine.CryptoLibrary,
                                                                                                          req, ack1, session, false);
                    ack1.ResponderRegistrationSignature = RegistrationSignature.Sign(Engine.CryptoLibrary, w =>
                    {
                        req.GetSharedSignedFields(w);
                        ack1.GetSharedSignedFields(w, true);
                    },
                                                                                     this.Configuration.LocalPeerRegistrationPrivateKey
                                                                                     );

                    var ack1UdpData = ack1.Encode_SetP2pFields(routedRequest.ReceivedFromNeighborNullable);
                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"sending ACK1 to source peer, awaiting for NPACK");
                    }
                    _ = routedRequest.ReceivedFromNeighborNullable.SendUdpRequestAsync_Retransmit_WaitForNPACK("ack1 1450", ack1UdpData, ack1.ReqP2pSeq16, ack1.GetSignedFieldsForNeighborHMAC);
                    // not waiting for NPACK, wait for ACK2
                    #endregion

                    // wait for ACK2
                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"waiting for ACK2");
                    }
                    var ack2UdpData = await Engine.OptionallySendUdpRequestAsync_Retransmit_WaitForResponse("ack2 23467789", routedRequest.ReceivedFromNeighborNullable.ToString(), null, routedRequest.ReceivedFromNeighborNullable.RemoteEndpoint,
                                                                                                            InviteAck2Packet.GetScanner(logger, req, routedRequest.ReceivedFromNeighborNullable));

                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"received ACK2");
                    }
                    var ack2 = InviteAck2Packet.Decode(ack2UdpData);
                    if (!ack2.RequesterRegistrationSignature.Verify(Engine.CryptoLibrary, w =>
                    {
                        req.GetSharedSignedFields(w);
                        ack1.GetSharedSignedFields(w, true);
                        ack2.GetSharedSignedFields(w);
                    }, req.RequesterRegistrationId))
                    {
                        throw new BadSignatureException("invalid INVITE ACK2 RequesterRegistrationSignature 2348");
                    }
                    // decrypt, verify SD remote user's certificate and signature
                    session.RemoteSessionDescription = InviteSessionDescription.Decrypt_Verify(Engine.CryptoLibrary,
                                                                                               ack2.ToRequesterSessionDescriptionEncrypted,
                                                                                               req, ack1, true, session, remoteRequesterUserIdFromLocalContactBookNullable, Engine.DateTimeNowUtc);
                    session.LocalSessionDescription.SessionType = session.RemoteSessionDescription.SessionType;

                    switch (session.RemoteSessionDescription.SessionType)
                    {
                    case SessionType.asyncShortSingleMessage: break;

                    case SessionType.ike1:
                        if (_drpPeerApp.OnReceivedInvite_GetLocalIke1Data(req.ContactInvitationTokenNullable) == null)
                        {
                            throw new BadSignatureException("bad ContactInvitationToken 21379");
                        }
                        break;

                    default: throw new NotImplementedException();
                    }

                    // send NPACK to ACK2
                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"sending NPACK to ACK2 to source peer");
                    }
                    SendNeighborPeerAckResponseToAck2(ack2, routedRequest.ReceivedFromNeighborNullable);

                    // send CFM with signature
                    var cfm = new InviteConfirmationPacket
                    {
                        ReqTimestamp32S         = req.ReqTimestamp32S,
                        RequesterRegistrationId = req.RequesterRegistrationId,
                        ResponderRegistrationId = req.ResponderRegistrationId,
                    };
                    cfm.ResponderRegistrationSignature = RegistrationSignature.Sign(Engine.CryptoLibrary, w =>
                    {
                        req.GetSharedSignedFields(w);
                        ack1.GetSharedSignedFields(w, true);
                        ack2.GetSharedSignedFields(w);
                    }, this.Configuration.LocalPeerRegistrationPrivateKey);
                    var cfmUdpData = cfm.Encode_SetP2pFields(routedRequest.ReceivedFromNeighborNullable);

                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"sending CFM to source peer, waiting for NPACK");
                    }
                    await routedRequest.ReceivedFromNeighborNullable.SendUdpRequestAsync_Retransmit_WaitForNPACK("cfm 49146", cfmUdpData, cfm.ReqP2pSeq16, cfm.GetSignedFieldsForNeighborHMAC);

                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"received NPACK to CFM");
                    }

                    session.DeriveSharedPingPongHmacKey(req, ack1, ack2, cfm);

                    await session.SetupAEkeysAsync();
                }
                catch
                {
                    session.Dispose();
                    throw;
                }

                if (autoReply)
                {
                    switch (session.RemoteSessionDescription.SessionType)
                    {
                    case SessionType.asyncShortSingleMessage:
                        if (logger.WriteToLog_detail_enabled)
                        {
                            logger.WriteToLog_detail($"autoReply=true: receiving message");
                        }
                        _ = ReceiveShortSingleMessageAsync(session, req);
                        break;

                    case SessionType.ike1:
                        if (logger.WriteToLog_detail_enabled)
                        {
                            logger.WriteToLog_detail($"autoReply=true: starting IKE1");
                        }
                        _ = Ike1Async_AtInviteResponder(session, req);
                        break;

                    default: throw new NotImplementedException();
                    }
                }
                else
                {
                    session.Dispose(); // todo implement other cases
                }
            }
            catch (DrpTimeoutException exc)
            {
                logger.WriteToLog_lightPain($"could not accept INVITE request: {exc}");
            }
            catch (Exception exc)
            {
                logger.WriteToLog_mediumPain($"could not accept INVITE request: {exc}");
            }
            finally
            {
                _pendingInviteRequests.Remove(req.RequesterRegistrationId);
            }
        }
Exemplo n.º 8
0
        /// <summary>
        /// Timestamp32S, NeighborToken32 and NeighborHMAC are verified at this time
        /// </summary>
        /// <returns>
        /// true to retry the request with another neighbor (if the request needs to be "rerouted")
        /// </returns>
        internal async Task <bool> ProxyInviteRequestAsync(RoutedRequest routedRequest, ConnectionToNeighbor destinationPeer)
        {
            var req    = routedRequest.InviteReq;
            var logger = routedRequest.Logger;

            logger.ModuleName = DrpPeerEngine.VisionChannelModuleName_inv_proxySide;
            if (logger.WriteToLog_detail_enabled)
            {
                logger.WriteToLog_detail($"proxying {req} to {destinationPeer}");
            }

            if (!routedRequest.CheckedRecentUniqueProxiedRequests)
            {
                if (!Engine.RecentUniqueInviteRequests.Filter(req.GetUniqueRequestIdFields))
                {
                    logger.WriteToLog_higherLevelDetail($"rejecting non-unique {req}: requesterEndpoint={routedRequest.ReceivedFromEndpoint}");
                    await routedRequest.SendErrorResponse(ResponseOrFailureCode.failure_routeIsUnavailable);

                    return(false);
                }
                routedRequest.CheckedRecentUniqueProxiedRequests = true;
            }

            if (req.NumberOfHopsRemaining > InviteRequestPacket.MaxNumberOfHopsRemaining)
            {
                await routedRequest.SendErrorResponse(ResponseOrFailureCode.failure_routeIsUnavailable);

                return(false);
            }
            if (req.NumberOfHopsRemaining <= 1)
            {
                await routedRequest.SendErrorResponse(ResponseOrFailureCode.failure_numberOfHopsRemainingReachedZero);

                return(false);
            }

            _pendingInviteRequests.Add(req.RequesterRegistrationId);
            try
            {
                // send NPACK to REQ
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"sending NPACK to REQ source peer");
                }
                routedRequest.SendNeighborPeerAck_accepted_IfNotAlreadyReplied();

                req.NumberOfHopsRemaining--;
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"decremented number of hops in {req}: NumberOfHopsRemaining={req.NumberOfHopsRemaining}");
                }

                // send (proxy) REQ to responder. wait for NPACK, verify NPACK.senderHMAC, retransmit REQ
                var reqUdpData = req.Encode_SetP2pFields(destinationPeer);

                #region wait for ACK1 from responder  verify NeighborHMAC

                byte[] ack1UdpData;
                try
                {
                    var sentRequest = new SentRequest(Engine, logger, destinationPeer.RemoteEndpoint, destinationPeer, reqUdpData,
                                                      req.ReqP2pSeq16, InviteAck1Packet.GetScanner(logger, req, destinationPeer));
                    ack1UdpData = await sentRequest.SendRequestAsync("inv proxy ack1 3457");
                }
                catch (RequestRejectedException reqExc)
                {
                    logger.WriteToLog_higherLevelDetail($"got response={reqExc.ResponseCode} from destination {destinationPeer}. will try another neighbor..");

                    if (reqExc.ResponseCode == ResponseOrFailureCode.failure_numberOfHopsRemainingReachedZero)
                    {
                        await routedRequest.SendErrorResponse(ResponseOrFailureCode.failure_numberOfHopsRemainingReachedZero);

                        return(false);
                    }

                    if (routedRequest.ReceivedFromNeighborNullable?.IsDisposed == true)
                    {
                        logger.WriteToLog_needsAttention($"sourcePeer={routedRequest.ReceivedFromNeighborNullable} is disposed during proxying 75675");
                        return(false);
                    }
                    if (reqExc.ResponseCode == ResponseOrFailureCode.failure_routeIsUnavailable)
                    {
                        req.NumberOfHopsRemaining++; // roll back previous decrement for a new trial
                    }
                    return(true);                    // will retry
                }
                catch (DrpTimeoutException exc)
                {
                    logger.WriteToLog_higherLevelDetail($"got timeout error when requesting {destinationPeer}: {exc.Message}");
                    req.NumberOfHopsRemaining++; // roll back previous decrement for a new trial
                    return(true);                // will retry
                }
                catch (Exception reqExc)
                {
                    logger.WriteToLog_mediumPain($"could not proxy INVITE request: {reqExc}");
                    if (routedRequest.ReceivedFromNeighborNullable?.IsDisposed == true)
                    {
                        logger.WriteToLog_needsAttention($"sourcePeer={routedRequest.ReceivedFromNeighborNullable} is disposed during proxying 76897805");
                        return(false);
                    }
                    return(true); // will retry
                }


                var ack1 = InviteAck1Packet.Decode(ack1UdpData);
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"verified ACK1 from responder");
                }
                // respond with NPACK to ACk1
                SendNeighborPeerAckResponseToAck1(ack1, destinationPeer);
                #endregion

                #region send ACK1 to requester, wait for NPACK and ACK2
                var ack1UdpDataTx = ack1.Encode_SetP2pFields(routedRequest.ReceivedFromNeighborNullable);

                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"sending ACK1, awaiting for NPACK");
                }
                _ = Engine.OptionallySendUdpRequestAsync_Retransmit_WaitForNeighborPeerAck("ack1 13536", ack1UdpDataTx, routedRequest.ReceivedFromEndpoint,
                                                                                           ack1.ReqP2pSeq16, routedRequest.ReceivedFromNeighborNullable, ack1.GetSignedFieldsForNeighborHMAC);
                // not waiting for NPACK, wait for ACK1
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"waiting for ACK2");
                }

                var ack2UdpData = await Engine.OptionallySendUdpRequestAsync_Retransmit_WaitForResponse("ack2 2346892",
                                                                                                        routedRequest.ReceivedFromNeighborNullable?.ToString() ?? routedRequest.ReceivedFromEndpoint.ToString(),
                                                                                                        null, routedRequest.ReceivedFromEndpoint,
                                                                                                        InviteAck2Packet.GetScanner(logger, req, routedRequest.ReceivedFromNeighborNullable));

                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"received ACK2");
                }
                var ack2 = InviteAck2Packet.Decode(ack2UdpData);
                #endregion

                // send NPACK to ACK2
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"sending NPACK to ACK2 to source peer");
                }
                SendNeighborPeerAckResponseToAck2(ack2, routedRequest.ReceivedFromNeighborNullable);

                // send ACK2 to responder
                // put ACK2.ReqP2pSeq16, sendertoken32, senderHMAC
                // wait for NPACK
                var ack2UdpDataTx = ack2.Encode_SetP2pFields(destinationPeer);
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"sending ACK2 to responder");
                }
                await destinationPeer.SendUdpRequestAsync_Retransmit_WaitForNPACK("ack2 5344530", ack2UdpDataTx,
                                                                                  ack2.ReqP2pSeq16, ack2.GetSignedFieldsForNeighborHMAC);

                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"received NPACK to ACK2 from destination peer");
                }

                // wait for CFM from responder
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"waiting for CFM from responder");
                }
                var cfmUdpData = await Engine.WaitForUdpResponseAsync(new PendingLowLevelUdpRequest("cfm 12358", destinationPeer.RemoteEndpoint,
                                                                                                    InviteConfirmationPacket.GetScanner(logger, req, destinationPeer),
                                                                                                    Engine.DateTimeNowUtc, Engine.Configuration.CfmTimoutS
                                                                                                    ));

                if (cfmUdpData == null)
                {
                    throw new DrpTimeoutException($"inv. proxy CFM response from destination peer {destinationPeer} (timeout={Engine.Configuration.CfmTimoutS}s)");
                }
                var cfm = InviteConfirmationPacket.Decode(cfmUdpData);
                // todo verify signature, update RDRs and QoS
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"verified CFM from responder");
                }

                // respond NPACK to CFM to destination peer
                SendNeighborPeerAckResponseToCfm(cfm, destinationPeer);

                // send CFM to requester
                var cfmUdpDataTx = cfm.Encode_SetP2pFields(routedRequest.ReceivedFromNeighborNullable);

                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"sending CFM to requester, waiting for NPACK");
                }
                await Engine.OptionallySendUdpRequestAsync_Retransmit_WaitForNeighborPeerAck("cfm 23468", cfmUdpDataTx, routedRequest.ReceivedFromEndpoint,
                                                                                             cfm.ReqP2pSeq16, routedRequest.ReceivedFromNeighborNullable, cfm.GetSignedFieldsForNeighborHMAC);

                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"received NPACK to CFM from source peer");
                }
            }
            catch (DrpTimeoutException exc)
            {
                logger.WriteToLog_lightPain($"could not proxy INVITE: {exc.Message}");
            }
            catch (Exception exc)
            {
                logger.WriteToLog_mediumPain($"could not proxy INVITE request: {exc}");
            }
            finally
            {
                _pendingInviteRequests.Remove(req.RequesterRegistrationId);
            }
            return(false);
        }
Exemplo n.º 9
0
        /// <summary>
        /// main register responder proc for both A-EP and P2P modes
        /// in P2P mode NeighborToken32 and NeighborHMAC are verified at this time
        /// </summary>
        /// <param name="receivedFromInP2pMode">
        /// is null in A-EP mode
        /// </param>
        /// <returns>
        /// true to retry the request with another neighbor (if the request needs to be "rerouted")
        /// </returns>
        internal async Task <bool> ProxyRegisterRequestAsync(RoutedRequest routedRequest, ConnectionToNeighbor destinationPeer) // engine thread
        {
            routedRequest.ReceivedFromNeighborNullable?.AssertIsNotDisposed();
            var req    = routedRequest.RegisterReq;
            var logger = routedRequest.Logger;

            logger.ModuleName = VisionChannelModuleName_reg_proxySide;

            if (!ValidateReceivedReqTimestamp64(req.ReqTimestamp64))
            {
                logger.WriteToLog_needsAttention($"rejecting REGISTER request {req.RequesterRegistrationId}: invalid REGISTER REQ 457 ReqTimestamp64={MiscProcedures.Int64ticksToDateTime(req.ReqTimestamp64)}");
                //   await routedRequest.SendErrorResponse(ResponseOrFailureCode.failure_numberOfHopsRemainingReachedZero);
                return(false);
            }

            if (PendingRegisterRequestExists(req.RequesterRegistrationId))
            {
                logger.WriteToLog_higherLevelDetail($"rejecting duplicate request {req}: requesterEndpoint={routedRequest.ReceivedFromEndpoint}");
                await routedRequest.SendErrorResponse(ResponseOrFailureCode.failure_routeIsUnavailable);

                return(false);
            }

            if (req.NumberOfHopsRemaining > RegisterRequestPacket.MaxNumberOfHopsRemaining || req.NumberOfRandomHopsRemaining > RegisterRequestPacket.MaxNumberOfHopsRemaining)
            {
                logger.WriteToLog_needsAttention($"rejecting {req}: invalid number of hops remaining");
                await routedRequest.SendErrorResponse(ResponseOrFailureCode.failure_routeIsUnavailable);

                return(false);
            }

            if (!routedRequest.CheckedRecentUniqueProxiedRequests)
            {
                var recentUniqueProxiedRegistrationRequests = req.RandomModeAtThisHop ? RecentUniqueProxiedRegistrationRequests_RandomHop : RecentUniqueProxiedRegistrationRequests_NonRandomHop;
                if (!recentUniqueProxiedRegistrationRequests.Filter(req.GetUniqueRequestIdFields))
                {
                    logger.WriteToLog_higherLevelDetail($"rejecting non-unique request {req}: requesterEndpoint={routedRequest.ReceivedFromEndpoint}");
                    await routedRequest.SendErrorResponse(ResponseOrFailureCode.failure_routeIsUnavailable);

                    return(false);
                }
                routedRequest.CheckedRecentUniqueProxiedRequests = true;
            }

            logger.WriteToLog_higherLevelDetail($"proxying {req}: requesterEndpoint={routedRequest.ReceivedFromEndpoint}, NumberOfHopsRemaining={req.NumberOfHopsRemaining}, ReqP2pSeq16={req.ReqP2pSeq16}, destinationPeer={destinationPeer}, sourcePeer={routedRequest.ReceivedFromNeighborNullable}");

            if (!ValidateReceivedReqTimestamp64(req.ReqTimestamp64))
            {
                throw new BadSignatureException($"invalid REGISTER REQ ReqTimestamp64={MiscProcedures.Int64ticksToDateTime(req.ReqTimestamp64)} 3507");
            }

            req.NumberOfHopsRemaining--;
            if (req.NumberOfHopsRemaining == 0)
            {
                logger.WriteToLog_needsAttention($"rejecting REGISTER request {req.RequesterRegistrationId}: max hops reached");
                await routedRequest.SendErrorResponse(ResponseOrFailureCode.failure_numberOfHopsRemainingReachedZero);

                return(false);
            }

            _pendingRegisterRequests.Add(req.RequesterRegistrationId);
            try
            {
                // send NPACK to source peer
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"sending NPACK to REQ source peer (delay={routedRequest.ReqReceivedSw_ms}ms)");
                }
                routedRequest.SendNeighborPeerAck_accepted_IfNotAlreadyReplied();

                if (req.NumberOfRandomHopsRemaining >= 1)
                {
                    req.NumberOfRandomHopsRemaining--;
                }
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"decremented number of hops in {req}: NumberOfHopsRemaining={req.NumberOfHopsRemaining}, NumberOfRandomHopsRemaining={req.NumberOfRandomHopsRemaining}");
                }

                req.ReqP2pSeq16 = destinationPeer.GetNewRequestP2pSeq16_P2P();
                byte[] ack1UdpData;
                try
                {
                    var sentRequest = new SentRequest(this, logger, destinationPeer.RemoteEndpoint, destinationPeer, req.Encode_OptionallySignNeighborHMAC(destinationPeer),
                                                      req.ReqP2pSeq16, RegisterAck1Packet.GetScanner(logger, req, destinationPeer));

                    // send (proxy) REQ to responder. wait for NPACK, verify NPACK.senderHMAC, retransmit REQ
                    // wait for ACK1 from destination peer
                    // verify NeighborHMAC
                    // var ack1R = await sentRequest.SendRequestAsync_NoExc("ack1 34601"); ////////////////////////////////// new method
                    ack1UdpData = await sentRequest.SendRequestAsync("ack1 34601");

                    //  if (logger.WriteToLog_detail2_enabled) logger.WriteToLog_detail("got ACK1 result");

                    if (routedRequest.ReceivedFromNeighborNullable?.IsDisposed == true)
                    {
                        logger.WriteToLog_needsAttention($"sourcePeer={routedRequest.ReceivedFromNeighborNullable} is disposed during proxying 52460");
                        return(false);
                    }
                    if (destinationPeer?.IsDisposed == true)
                    {
                        logger.WriteToLog_needsAttention($"destinationPeer={destinationPeer} is disposed during proxying 52460");
                        return(false);
                    }

                    //if (ack1R.ResponseCode != ResponseOrFailureCode.accepted)
                    //{
                    //    logger.WriteToLog_higherLevelDetail($"got response={ack1R.ResponseCode} from destination {destinationPeer}");
                    //    if (ack1R.ResponseCode == ResponseOrFailureCode.failure_routeIsUnavailable)
                    //        req.NumberOfHopsRemaining++; // roll back previous decrement for a new trial
                    //    return true; // will retry
                    //}
                    //ack1UdpData = ack1R.UdpData;
                }
                catch (RequestRejectedException reqExc)
                {
                    logger.WriteToLog_higherLevelDetail($"got exception: response={reqExc.ResponseCode} from destination {destinationPeer}");
                    if (reqExc.ResponseCode == ResponseOrFailureCode.failure_numberOfHopsRemainingReachedZero)
                    {
                        await routedRequest.SendErrorResponse(ResponseOrFailureCode.failure_numberOfHopsRemainingReachedZero);

                        return(false);
                    }

                    if (routedRequest.ReceivedFromNeighborNullable?.IsDisposed == true)
                    {
                        logger.WriteToLog_needsAttention($"sourcePeer={routedRequest.ReceivedFromNeighborNullable} is disposed during proxying 35346232");
                        return(false);
                    }
                    if (reqExc.ResponseCode == ResponseOrFailureCode.failure_routeIsUnavailable)
                    {
                        req.NumberOfHopsRemaining++; // roll back previous decrement for a new trial
                    }

                    return(true); // will retry
                }
                catch (DrpTimeoutException exc)
                {
                    logger.WriteToLog_higherLevelDetail($"got timeout error when requesting {destinationPeer}: {exc.Message}");
                    req.NumberOfHopsRemaining++; // roll back previous decrement for a new trial
                    return(true);                // will retry
                }
                catch (Exception reqExc)
                {
                    logger.WriteToLog_mediumPain($"could not proxy REGISTER request: {reqExc}");
                    if (routedRequest.ReceivedFromNeighborNullable?.IsDisposed == true)
                    {
                        logger.WriteToLog_needsAttention($"sourcePeer={routedRequest.ReceivedFromNeighborNullable} is disposed during proxying 76897805");
                        return(false);
                    }
                    return(true); // will retry
                }

                var tr1  = CreateTracker("ack1 34601 2");
                var ack1 = RegisterAck1Packet.DecodeAndOptionallyVerify(logger, ack1UdpData, req, null);
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"verified ACK1 from destination");
                }

                // respond with NPACK
                SendNeighborPeerAckResponseToRegisterAck1(ack1, destinationPeer);

                // send ACK1 to source peer
                // wait for ACK / NPACK
                if (routedRequest.ReceivedFromNeighborNullable != null)
                {   // P2P mode
                    routedRequest.ReceivedFromNeighborNullable.AssertIsNotDisposed();
                    ack1.ReqP2pSeq16 = routedRequest.ReceivedFromNeighborNullable.GetNewRequestP2pSeq16_P2P();
                }
                else
                {   // A-EP mode
                    ack1.RequesterEndpoint = routedRequest.ReceivedFromEndpoint;
                }
                var ack1UdpDataTx = ack1.Encode_OpionallySignNeighborHMAC(routedRequest.ReceivedFromNeighborNullable);

                var sourcePeerVisibleDescription = routedRequest.ReceivedFromNeighborNullable?.ToString() ?? routedRequest.ReceivedFromEndpoint.ToString();
                var ack2Scanner = RegisterAck2Packet.GetScanner(logger, routedRequest.ReceivedFromNeighborNullable, req);
                tr1.Dispose();
                byte[] ack2UdpData;
                if (routedRequest.ReceivedFromNeighborNullable == null)
                {   // A-EP mode: wait for ACK2, retransmitting ACK1
                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"sending ACK1, waiting for ACK2");
                    }
                    ack2UdpData = await OptionallySendUdpRequestAsync_Retransmit_WaitForResponse("ack2 12368", sourcePeerVisibleDescription,
                                                                                                 ack1UdpDataTx, routedRequest.ReceivedFromEndpoint, ack2Scanner);
                }
                else
                {   // P2P mode: retransmit ACK1 until NPACK (via P2P); at same time wait for ACK2
                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"sending ACK1, awaiting for NPACK");
                    }
                    _ = OptionallySendUdpRequestAsync_Retransmit_WaitForNeighborPeerAck("ack1 3686", ack1UdpDataTx, routedRequest.ReceivedFromEndpoint,
                                                                                        ack1.ReqP2pSeq16, routedRequest.ReceivedFromNeighborNullable, ack1.GetSignedFieldsForNeighborHMAC);
                    // not waiting for NPACK, wait for ACK2
                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"waiting for ACK2");
                    }
                    ack2UdpData = await OptionallySendUdpRequestAsync_Retransmit_WaitForResponse("ack2 345209", sourcePeerVisibleDescription,
                                                                                                 null, routedRequest.ReceivedFromEndpoint, ack2Scanner);
                }

                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"received ACK2");
                }
                if (routedRequest.ReceivedFromNeighborNullable?.IsDisposed == true)
                {
                    logger.WriteToLog_needsAttention($"sourcePeer={routedRequest.ReceivedFromNeighborNullable} is disposed during proxying 2345135");
                    return(false);
                }
                if (destinationPeer?.IsDisposed == true)
                {
                    logger.WriteToLog_needsAttention($"destinationPeer={destinationPeer} is disposed during proxying 2345135");
                    return(false);
                }
                var ack2 = RegisterAck2Packet.Decode_OptionallyVerify_InitializeP2pStreamAtResponder(logger, ack2UdpData, null, null, null);

                // send NPACK to source peer
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"sending NPACK to ACK2 to source peer");
                }
                SendNeighborPeerAckResponseToRegisterAck2(ack2, routedRequest.ReceivedFromEndpoint, routedRequest.ReceivedFromNeighborNullable);

                // send ACK2 to destination peer
                // put ACK2.ReqP2pSeq16, sendertoken32, senderHMAC
                // wait for NPACK
                if (destinationPeer.IsDisposed == true)
                {
                    logger.WriteToLog_needsAttention($"destinationPeer={destinationPeer} is disposed during proxying 345784567");
                    return(false);
                }
                if (routedRequest.ReceivedFromNeighborNullable?.IsDisposed == true)
                {
                    logger.WriteToLog_needsAttention($"sourcePeer={routedRequest.ReceivedFromNeighborNullable} is disposed during proxying 345784567");
                    return(false);
                }
                ack2.ReqP2pSeq16 = destinationPeer.GetNewRequestP2pSeq16_P2P();
                await destinationPeer.SendUdpRequestAsync_Retransmit_WaitForNPACK("ack2 41937", ack2.Encode_OptionallySignNeighborHMAC(destinationPeer),
                                                                                  ack2.ReqP2pSeq16, ack2.GetSignedFieldsForNeighborHMAC);

                if (routedRequest.ReceivedFromNeighborNullable?.IsDisposed == true)
                {
                    logger.WriteToLog_needsAttention($"sourcePeer={routedRequest.ReceivedFromNeighborNullable} is disposed during proxying 234646");
                    return(false);
                }
                if (destinationPeer?.IsDisposed == true)
                {
                    logger.WriteToLog_needsAttention($"destinationPeer={destinationPeer} is disposed during proxying 234646");
                    return(false);
                }

                // wait for CFM from source peer
                var cfmUdpData = await OptionallySendUdpRequestAsync_Retransmit_WaitForResponse("cfm 234789", sourcePeerVisibleDescription, null,
                                                                                                routedRequest.ReceivedFromEndpoint,
                                                                                                RegisterConfirmationPacket.GetScanner(logger, routedRequest.ReceivedFromNeighborNullable, req)
                                                                                                );

                var cfm = RegisterConfirmationPacket.DecodeAndOptionallyVerify(cfmUdpData, null, null);
                if (routedRequest.ReceivedFromNeighborNullable?.IsDisposed == true)
                {
                    logger.WriteToLog_needsAttention($"sourcePeer={routedRequest.ReceivedFromNeighborNullable} is disposed during proxying 3452326");
                    return(false);
                }
                if (destinationPeer?.IsDisposed == true)
                {
                    logger.WriteToLog_needsAttention($"destinationPeer={destinationPeer} is disposed during proxying 3452326");
                    return(false);
                }

                // TODO verify signatures and update QoS

                // send NPACK to source peer
                SendNeighborPeerAckResponseToRegisterCfm(cfm, routedRequest.ReceivedFromEndpoint, routedRequest.ReceivedFromNeighborNullable);

                // send CFM to responder
                // wait for NPACK from destination peer, retransmit
                if (destinationPeer.IsDisposed == true)
                {
                    logger.WriteToLog_needsAttention($"destinationPeer={destinationPeer} is disposed during proxying 123678");
                    return(false);
                }
                if (routedRequest.ReceivedFromNeighborNullable?.IsDisposed == true)
                {
                    logger.WriteToLog_needsAttention($"sourcePeer={routedRequest.ReceivedFromNeighborNullable} is disposed during proxying 123678");
                    return(false);
                }
                cfm.ReqP2pSeq16 = destinationPeer.GetNewRequestP2pSeq16_P2P();
                await destinationPeer.SendUdpRequestAsync_Retransmit_WaitForNPACK("cfm 1357", cfm.Encode_OptionallySignNeighborHMAC(destinationPeer),
                                                                                  cfm.ReqP2pSeq16, cfm.GetSignedFieldsForNeighborHMAC);


                logger.WriteToLog_higherLevelDetail($"proxying {req} is successfully complete");
            }
            catch (DrpTimeoutException exc)
            {
                logger.WriteToLog_lightPain($"could not proxy REGISTER: request timeout: {exc.Message}");
            }
            catch (Exception exc)
            {
                logger.WriteToLog_mediumPain($"could not proxy REGISTER request: {exc}");
            }
            finally
            {
                _pendingRegisterRequests.Remove(req.RequesterRegistrationId);
            }

            return(false);
        }
Exemplo n.º 10
0
        /// <summary>
        /// main routing procedure for register REQ requests
        /// </summary>
        /// <param name="receivedAtLocalDrpPeerNullable">
        /// is set when routing REQ packets that are received via P2P connection from neighbor to the LocalDrpPeer
        /// is null in A-EP mode
        /// </param>
        internal bool RouteRegistrationRequest(LocalDrpPeer receivedAtLocalDrpPeerNullable, RoutedRequest routedRequest, out ConnectionToNeighbor proxyToDestinationPeer, out LocalDrpPeer acceptAt)
        {
            proxyToDestinationPeer = null;
            acceptAt = null;

            var req    = routedRequest.RegisterReq;
            var logger = routedRequest.Logger;

            if (req.NumberOfHopsRemaining <= 1)
            {
                var possibleAcceptAt = receivedAtLocalDrpPeerNullable ?? routedRequest.ReceivedFromNeighborNullable?.LocalDrpPeer;
                if (possibleAcceptAt == null)
                {
                    possibleAcceptAt = LocalPeers.Values.Where(x => x.Configuration.LocalPeerRegistrationId.Equals(req.RequesterRegistrationId) == false).FirstOrDefault();
                }

                if (possibleAcceptAt != null)
                {
                    if (!possibleAcceptAt.ConnectedNeighbors.Any(x => x.RemoteRegistrationId.Equals(req.RequesterRegistrationId)))
                    {
                        logger.WriteToLog_routing_higherLevelDetail($"accepting registration request {req.RequesterRegistrationId} at local DRP peer {acceptAt}: low number of hops remaining");
                        acceptAt = possibleAcceptAt;
                        return(true);
                    }
                    else
                    {
                        logger.WriteToLog_routing_higherLevelDetail($"not accepting registration at local DRP peer" +
                                                                    $" {acceptAt} when low number of hops remaining: already connected");
                    }
                }
            }

            if (req.RandomModeAtThisHop)
            { // random mode
                var itemsForRouting = new List <object>();
                if (routedRequest.ReceivedFromNeighborNullable == null)
                {
                    foreach (var localDrpPeer in LocalPeers.Values)
                    {
                        itemsForRouting.AddRange(localDrpPeer.GetConnectedNeighborsForRouting(routedRequest));
                        if (!localDrpPeer.Configuration.LocalPeerRegistrationId.Equals(req.RequesterRegistrationId))
                        {
                            itemsForRouting.Add(localDrpPeer);
                        }
                    }
                }
                else
                {
                    itemsForRouting.AddRange(routedRequest.ReceivedFromNeighborNullable.LocalDrpPeer.GetConnectedNeighborsForRouting(routedRequest));
                    if (!routedRequest.ReceivedFromNeighborNullable.LocalDrpPeer.Configuration.LocalPeerRegistrationId.Equals(req.RequesterRegistrationId))
                    {
                        itemsForRouting.Add(routedRequest.ReceivedFromNeighborNullable.LocalDrpPeer);
                    }
                }

                if (itemsForRouting.Count != 0)
                {
                    var itemForRouting = itemsForRouting[_insecureRandom.Next(itemsForRouting.Count - 1)];
                    logger.WriteToLog_routing_higherLevelDetail($"routing registration in random mode to one of {itemsForRouting.Count} destinations: {proxyToDestinationPeer}");
                    if (itemForRouting is ConnectionToNeighbor)
                    {
                        proxyToDestinationPeer = (ConnectionToNeighbor)itemForRouting;
                    }
                    else
                    {
                        acceptAt = (LocalDrpPeer)itemForRouting;
                    }
                }
                else
                {
                    logger.WriteToLog_routing_needsAttention($"can not route registration in random mode: no destinations available including local peers");
                }
            }
            else
            {
                double?maxP2pConnectionValue = null;
                if (receivedAtLocalDrpPeerNullable != null)
                {
                    RouteRegistrationRequest_LocalDrpPeerIteration(receivedAtLocalDrpPeerNullable, routedRequest, ref maxP2pConnectionValue, ref proxyToDestinationPeer, ref acceptAt);
                }
                else
                {
                    foreach (var localDrpPeer in LocalPeers.Values)
                    {
                        RouteRegistrationRequest_LocalDrpPeerIteration(localDrpPeer, routedRequest, ref maxP2pConnectionValue, ref proxyToDestinationPeer, ref acceptAt);
                    }
                }
            }

            if (proxyToDestinationPeer != null)
            {
                logger.WriteToLog_routing_higherLevelDetail($"proxying registration to {proxyToDestinationPeer}");
                return(true);
            }
            else if (acceptAt != null)
            {
                logger.WriteToLog_routing_higherLevelDetail($"accepting registration at local DRP peer {acceptAt}");
                return(true);
            }
            else
            {
                logger.WriteToLog_routing_higherLevelDetail($"no route found for REGISTER request to {req.RequesterRegistrationId}");
                return(false);
            }
        }
Exemplo n.º 11
0
        void RouteRegistrationRequest_LocalDrpPeerIteration(LocalDrpPeer localDrpPeer, RoutedRequest routedRequest,
                                                            ref double?maxP2pConnectionValue,
                                                            ref ConnectionToNeighbor proxyToDestinationPeer, ref LocalDrpPeer acceptAt)
        {
            var req = routedRequest.RegisterReq;
            var connectedNeighborsForRouting = localDrpPeer.GetConnectedNeighborsForRouting(routedRequest).ToList();
            var logger = routedRequest.Logger;

            var distancesToNeighbors         = new List <RegistrationIdDistance>();
            var requestedDirectionMulResults = new List <double>();
            int connectedNeighborsCountThatMatchReqFilters = 0;

            foreach (var neighbor in connectedNeighborsForRouting)
            {
                if (req.MinimalDistanceToNeighbor != 0)
                {
                    var distanceToNeighbor = req.RequesterRegistrationId.GetDistanceTo(_cryptoLibrary, neighbor.RemoteRegistrationId, NumberOfDimensions);
                    distancesToNeighbors.Add(distanceToNeighbor);
                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"distanceToNeighbor={distanceToNeighbor} from REGISTER REQ {req.RequesterRegistrationId} to {neighbor} (req.min={req.MinimalDistanceToNeighbor})");
                    }
                    if (distanceToNeighbor.IsLessThan(req.MinimalDistanceToNeighbor))
                    {
                        // skip: this is too close than requested
                        if (logger.WriteToLog_detail_enabled)
                        {
                            logger.WriteToLog_detail($"skipping connection to {neighbor}: distance={distanceToNeighbor} is less than requested={req.MinimalDistanceToNeighbor}");
                        }
                        continue;
                    }
                }
                if (req.DirectionVectorNullable != null)
                {
                    var    requestedDirectionVector = req.DirectionVectorNullableD;
                    var    vectorFromThisToNeighbor = RegistrationId.GetDifferenceVector(req.RequesterRegistrationId, neighbor.RemoteRegistrationId, CryptoLibrary, Configuration.SandboxModeOnly_NumberOfDimensions);
                    double mulResult = 0;
                    for (int i = 0; i < requestedDirectionVector.Length; i++)
                    {
                        mulResult += requestedDirectionVector[i] * requestedDirectionVector[i];
                    }
                    requestedDirectionMulResults.Add(mulResult);
                    if (mulResult < 0)
                    {
                        if (logger.WriteToLog_detail_enabled)
                        {
                            logger.WriteToLog_detail($"skipping connection to {neighbor}: direction from requester to neighbor does not match requested vector");
                        }
                        continue;
                    }
                }
                connectedNeighborsCountThatMatchReqFilters++;

                var p2pConnectionValue_withNeighbor = P2pConnectionValueCalculator.GetMutualP2pConnectionValue(CryptoLibrary, req.RequesterRegistrationId, req.RequesterNeighborsBusySectorIds,
                                                                                                               neighbor.RemoteRegistrationId, neighbor.RemoteNeighborsBusySectorIds ?? 0, NumberOfDimensions, false, false, false);

                if (logger.WriteToLog_deepDetail_enabled)
                {
                    logger.WriteToLog_deepDetail($"p2pConnectionValue_withNeighbor={p2pConnectionValue_withNeighbor} from REGISTER REQ {req.RequesterRegistrationId} to {neighbor}");
                }

                if (maxP2pConnectionValue == null || maxP2pConnectionValue < p2pConnectionValue_withNeighbor)
                {
                    maxP2pConnectionValue  = p2pConnectionValue_withNeighbor;
                    proxyToDestinationPeer = neighbor;
                    acceptAt = null;
                }
            }

            if (connectedNeighborsCountThatMatchReqFilters == 0 && connectedNeighborsForRouting.Count != 0)
            {
                if (req.MinimalDistanceToNeighbor != 0)
                {
                    // special case: we are inside the "minDistance" hypersphere: move away from the requester, proxy to most distant neighbor
                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"special case: move away from the requester, proxy to most distant neighbor");
                    }
                    RegistrationIdDistance maxDistance = null;
                    for (int i = 0; i < connectedNeighborsForRouting.Count; i++)
                    {
                        var neighbor           = connectedNeighborsForRouting[i];
                        var distanceToNeighbor = distancesToNeighbors[i];
                        if (logger.WriteToLog_detail_enabled)
                        {
                            logger.WriteToLog_detail($"distanceToConnectedPeer={distanceToNeighbor} from REGISTER REQ {req.RequesterRegistrationId} to {neighbor} (req.min={req.MinimalDistanceToNeighbor})");
                        }
                        if (maxDistance == null || distanceToNeighbor.IsGreaterThan(maxDistance))
                        {
                            maxDistance            = distanceToNeighbor;
                            proxyToDestinationPeer = neighbor;
                            acceptAt = null;
                        }
                    }
                }
                if (req.DirectionVectorNullable != null)
                {
                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"special case: move towards the specified direction");
                    }
                    double?maxMulResult = null;
                    for (int i = 0; i < connectedNeighborsForRouting.Count; i++)
                    {
                        var neighbor  = connectedNeighborsForRouting[i];
                        var mulResult = requestedDirectionMulResults[i];
                        if (logger.WriteToLog_detail_enabled)
                        {
                            logger.WriteToLog_detail($"mulResult={mulResult} for {neighbor}");
                        }
                        if (maxMulResult == null || mulResult > maxMulResult)
                        {
                            maxMulResult           = mulResult;
                            proxyToDestinationPeer = neighbor;
                            acceptAt = null;
                        }
                    }
                }
            }

            // dont connect to local peer if already connected
            if (localDrpPeer.Configuration.LocalPeerRegistrationId.Equals(req.RequesterRegistrationId) == true)
            {
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"not accepting request at local peer: it has same regID {req.RequesterRegistrationId}");
                }
            }
            else if (localDrpPeer.ConnectedNeighbors.Any(x => x.RemoteRegistrationId.Equals(req.RequesterRegistrationId)) == true)
            {
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"not accepting request at local peer: already connected to {req.RequesterRegistrationId}");
                }
            }
            else if (localDrpPeer.ConnectedNeighbors.Count > localDrpPeer.Configuration.AbsoluteMaxNumberOfNeighbors)
            {
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"not accepting request at local peer: already too many neighbors ({localDrpPeer.ConnectedNeighbors.Count})");
                }
            }
            else
            {
                var p2pConnectionValue_withLocalPeer = P2pConnectionValueCalculator.GetMutualP2pConnectionValue(CryptoLibrary, req.RequesterRegistrationId, req.RequesterNeighborsBusySectorIds,
                                                                                                                localDrpPeer.Configuration.LocalPeerRegistrationId, localDrpPeer.ConnectedNeighborsBusySectorIds, NumberOfDimensions, false, false, false);
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"p2pConnectionValue_withLocalPeer={p2pConnectionValue_withLocalPeer} from REGISTER REQ {req.RequesterRegistrationId} to {localDrpPeer.Configuration.LocalPeerRegistrationId}");
                }
                if (maxP2pConnectionValue == null || p2pConnectionValue_withLocalPeer > maxP2pConnectionValue)
                {
                    maxP2pConnectionValue  = p2pConnectionValue_withLocalPeer;
                    proxyToDestinationPeer = null;
                    acceptAt = localDrpPeer;
                }
            }

            if (logger.WriteToLog_detail_enabled)
            {
                logger.WriteToLog_detail($"<< RouteRegistrationRequest_LocalDrpPeerIteration() proxyTo={proxyToDestinationPeer}, acceptAt={acceptAt}");
            }
        }
Exemplo n.º 12
0
        /// <summary>
        /// sends INVITE, autenticates users, returns Session to be used to create direct cannel
        /// </summary>
        /// <param name="responderUserId">
        /// comes from local contact book
        /// </param>
        /// <param name="responderRegId">
        /// comes from local contact book
        /// </param>
        /// <param name="loggerCb">may be invoked more than one time (in case of retrying)</param>
        public async Task <InviteSession> SendInviteAsync(UserCertificate requesterUserCertificate, RegistrationId responderRegistrationId, UserId responderUserId,
                                                          SessionType sessionType, Action <Logger> loggerCb = null)
        {
            InviteSession session = null;

            try
            {
                var           sw            = Stopwatch.StartNew();
                RoutedRequest routedRequest = null;
                int           trialsCount   = 0;
                Exception     latestTriedNeighborException = null;


_retry:
                trialsCount++;
                session = new InviteSession(this);
                var req = new InviteRequestPacket
                {
                    NumberOfHopsRemaining   = InviteRequestPacket.MaxNumberOfHopsRemaining,
                    RequesterEcdhePublicKey = new EcdhPublicKey(session.LocalInviteAckEcdhePublicKey),
                    RequesterRegistrationId = this.Configuration.LocalPeerRegistrationId,
                    ResponderRegistrationId = responderRegistrationId,
                    ReqTimestamp32S         = Engine.Timestamp32S,
                };
                var logger = new Logger(Engine, this, req, DrpPeerEngine.VisionChannelModuleName_inv_requesterSide);
                if (!Engine.RecentUniqueInviteRequests.Filter(req.GetUniqueRequestIdFields))
                {
                    if (trialsCount > 50)
                    {
                        throw new NonUniquePacketFieldsException($"could not find unique fields to send INVITE request");
                    }
                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"waiting a second to generate ne wunique INVITE request");
                    }
                    await Engine.EngineThreadQueue.WaitAsync(TimeSpan.FromSeconds(1), "inv_wait_1236");

                    goto _retry;
                }


                session.Logger = logger;
                loggerCb?.Invoke(logger);
                Engine.RecentUniquePublicEcdhKeys.AssertIsUnique(req.RequesterEcdhePublicKey.Ecdh25519PublicKey, "req.RequesterEcdhePublicKey");
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"generated unique ECDH key {req.RequesterEcdhePublicKey}");
                }
                req.RequesterRegistrationSignature = RegistrationSignature.Sign(Engine.CryptoLibrary, req.GetSharedSignedFields, this.Configuration.LocalPeerRegistrationPrivateKey);

                this.TestDirection(logger, req.ResponderRegistrationId);
                routedRequest = new RoutedRequest(logger, null, null, null, req, null, routedRequest);

                // find best connected peer to send the request
                var destinationPeer = Engine.RouteInviteRequest(this, routedRequest);
                if (destinationPeer == null)
                {
                    if (latestTriedNeighborException == null)
                    {
                        throw new NoNeighborsToSendInviteException();
                    }
                    else
                    {
                        throw latestTriedNeighborException;
                    }
                }
                InviteAck1Packet ack1;
                try
                {
                    var reqUdpData = req.Encode_SetP2pFields(destinationPeer);
                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"sending {req} (ReqTimestamp32S={MiscProcedures.Uint32secondsToDateTime(req.ReqTimestamp32S)}), waiting for NPACK");
                    }

                    var sentRequest = new SentRequest(Engine, logger, destinationPeer.RemoteEndpoint, destinationPeer, reqUdpData, req.ReqP2pSeq16, InviteAck1Packet.GetScanner(logger, req, destinationPeer));
                    var ack1UdpData = await sentRequest.SendRequestAsync("ack1 4146");

                    #region process ACK1
                    // NeighborHMAC and NeighborToken32 are already verified by scanner
                    ack1 = InviteAck1Packet.Decode(ack1UdpData);
                    Engine.RecentUniquePublicEcdhKeys.AssertIsUnique(ack1.ResponderEcdhePublicKey.Ecdh25519PublicKey, $"ack1.ResponderEcdhePublicKey");
                    if (!ack1.ResponderRegistrationSignature.Verify(Engine.CryptoLibrary, w =>
                    {
                        req.GetSharedSignedFields(w);
                        ack1.GetSharedSignedFields(w, true);
                    },
                                                                    responderRegistrationId))
                    {
                        throw new BadSignatureException("invalid REGISTER ACK1 ResponderRegistrationSignature 2349");
                    }
                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"verified ACK1");
                    }
                    session.DeriveSharedInviteAckDhSecret(Engine.CryptoLibrary, ack1.ResponderEcdhePublicKey.Ecdh25519PublicKey);

                    // send NPACK to ACK1
                    SendNeighborPeerAckResponseToAck1(ack1, destinationPeer);
                    #endregion
                }
                catch (RequestFailedException exc2)
                {
                    latestTriedNeighborException = exc2;
                    if (trialsCount > 50)
                    {
                        throw;
                    }
                    logger.WriteToLog_higherLevelDetail($"trying again on error {exc2.Message}... alreadyTriedProxyingToDestinationPeers.Count={routedRequest.TriedNeighbors.Count}");
                    routedRequest.TriedNeighbors.Add(destinationPeer);
                    goto _retry;
                }

                // decode and verify SD
                session.RemoteSessionDescription = InviteSessionDescription.Decrypt_Verify(Engine.CryptoLibrary,
                                                                                           ack1.ToResponderSessionDescriptionEncrypted,
                                                                                           req, ack1, false, session,
                                                                                           responderUserId, Engine.DateTimeNowUtc);

                // sign and encode local SD
                session.LocalSessionDescription = new InviteSessionDescription
                {
                    DirectChannelEndPoint = destinationPeer.LocalEndpoint,
                    SessionType           = sessionType,
                    DirectChannelToken32  = session.LocalDirectChannelToken32
                };

                session.LocalSessionDescription.UserCertificate = requesterUserCertificate;

                session.LocalSessionDescription.UserCertificateSignature = UserCertificateSignature.Sign(Engine.CryptoLibrary,
                                                                                                         w =>
                {
                    req.GetSharedSignedFields(w);
                    ack1.GetSharedSignedFields(w, true);
                    session.LocalSessionDescription.WriteSignedFields(w);
                },
                                                                                                         requesterUserCertificate
                                                                                                         );

                #region send ack2
                var ack2 = new InviteAck2Packet
                {
                    RequesterRegistrationId = req.RequesterRegistrationId,
                    ResponderRegistrationId = req.ResponderRegistrationId,
                    ReqTimestamp32S         = req.ReqTimestamp32S,
                    ToRequesterSessionDescriptionEncrypted = session.LocalSessionDescription.Encrypt(Engine.CryptoLibrary, req, ack1, session, true)
                };
                ack2.RequesterRegistrationSignature = RegistrationSignature.Sign(Engine.CryptoLibrary, w =>
                {
                    req.GetSharedSignedFields(w);
                    ack1.GetSharedSignedFields(w, true);
                    ack2.GetSharedSignedFields(w);
                }, this.Configuration.LocalPeerRegistrationPrivateKey);
                var ack2UdpData = ack2.Encode_SetP2pFields(destinationPeer);

                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"sending ACK2, waiting for NPACK");
                }
                await destinationPeer.SendUdpRequestAsync_Retransmit_WaitForNPACK("ack2 234575672", ack2UdpData, ack2.ReqP2pSeq16, ack2.GetSignedFieldsForNeighborHMAC);

                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"received NPACK");
                }
                #endregion

                #region wait for CFM
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"waiting for CFM");
                }
                var cfmUdpData = await Engine.WaitForUdpResponseAsync(new PendingLowLevelUdpRequest("cfm 1235695", destinationPeer.RemoteEndpoint,
                                                                                                    InviteConfirmationPacket.GetScanner(logger, req, destinationPeer),
                                                                                                    Engine.DateTimeNowUtc, Engine.Configuration.CfmTimoutS
                                                                                                    ));

                if (cfmUdpData == null)
                {
                    throw new DrpTimeoutException($"did not get CFM at invite requester from destination peer {destinationPeer} (timeout={Engine.Configuration.CfmTimoutS}s)");
                }

                // NeighborHMAC and NeighborToken32 are already verified by scanner
                var cfm = InviteConfirmationPacket.Decode(cfmUdpData);

                if (!cfm.ResponderRegistrationSignature.Verify(Engine.CryptoLibrary, w =>
                {
                    req.GetSharedSignedFields(w);
                    ack1.GetSharedSignedFields(w, true);
                    ack2.GetSharedSignedFields(w);
                },
                                                               responderRegistrationId))
                {
                    throw new BadSignatureException("invalid REGISTER CFM ResponderRegistrationSignature 6398");
                }

                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"verified CFM");
                }

                // send NPACK to CFM
                SendNeighborPeerAckResponseToCfm(cfm, destinationPeer);
                #endregion

                session.DeriveSharedPingPongHmacKey(req, ack1, ack2, cfm);
                return(session);
            }
            catch
            {
                session?.Dispose();
                throw;
            }
        }