Exemplo n.º 1
0
        void IConnectedPeerStreamExtension.OnReceivedSignalingPacket(BinaryReader reader) // manager thread
        {
            var subtPacketType = (SubtPacketType)reader.ReadByte();

            switch (subtPacketType)
            {
            case SubtPacketType.RemoteStatus:
                var p = new SubtRemoteStatusPacket(reader);
                //   SubtLocalPeer.WriteToLog($"received from peer {SubtConnectedPeer.RemotePeerId}: SUBT status packet: {p}");
                LatestRemoteStatus = p;
                _stream.MarkAsActiveByExtension();

                if (_rxBwBeforeJB.OutputPerUnit > p.RecentTxBandwidth * 5)
                {
                    EmitPainToDeveloper($"_rxBwBeforeJB.OutputPerUnit={_rxBwBeforeJB.OutputPerUnit} > p.RecentTxBandwidth={p.RecentTxBandwidth}");
                }
                break;

            case SubtPacketType.AdjustmentRequest:
                var adj = new AdjustmentRequestPacket(reader);
                SubtLocalPeer.WriteToLog($"{this} received adjustment request: {adj}");
                if (adj.TxTargetBandwidth > this.TargetTxBandwidth)
                {     // increase
                    if (SubtLocalPeer.ImHealthyAndReadyFor100kbpsU2uSymbiosis)
                    {
                        // check requested BW
                        this.TargetTxBandwidth = Math.Min(adj.TxTargetBandwidth, MaxTxBandwidthToAcceptFromRemoteSide);
                        SubtLocalPeer.WriteToLog($"{this} bandwidth increased to {MiscProcedures.BandwidthToString(this.TargetTxBandwidth)}");
                    }
                    else
                    {
                        SubtLocalPeer.WriteToLog($"{this} is not healthy to increase bandwidth");
                    }
                }
                else     // decrease
                {
                    this.TargetTxBandwidth = adj.TxTargetBandwidth;
                    SubtLocalPeer.WriteToLog($"{this} bandwidth decreased to {MiscProcedures.BandwidthToString(this.TargetTxBandwidth)}");
                }

                // respond
                var resp     = new AdjustmentResponsePacket(this.TargetTxBandwidth);
                var respData = resp.Encode(this);
                _stream.SendPacket(respData, respData.Length);
                _lastTimeReceivedAdjustmentRequestUTC = SubtLocalPeer.LocalPeer.DateTimeNowUtc;
                break;

            case SubtPacketType.AdjustmentResponse:
                var adjResp = new AdjustmentResponsePacket(reader);
                if (PendingAdjustmentRequestPacket != null)
                {     // we got response from remote peer
                    SubtLocalPeer.WriteToLog($"{this} received adjustment response: {adjResp}");
                    //  adjust local tx BW, according to remote BW. check what is responded
                    this.TargetTxBandwidth             = Math.Min(adjResp.TxTargetBandwidth, PendingAdjustmentRequestPacket.TxTargetBandwidth);
                    PendingAdjustmentRequestPacket     = null;
                    PendingAdjustmentRequestPacketData = null;
                }
                break;
            }
        }
Exemplo n.º 2
0
        void PlaybackFromJitter(uint timeNow32)
        {
          //  if (_stream.Stream.Debug) _subtLocalPeer.WriteToLog($">> PlaybackFromJitter count={_jitterBuffer.Count}");
            if (_jitterBuffer.Count != 0)
            {
                // simulate playback from JB		
                var newestTimestampInSimulatedJitterBuffer = _jitterBuffer.Last.Value.timestamp32;

                // determine TS value of currently played frame
                var maxAllowedTimestampInSimulatedJitterBuffer = unchecked(newestTimestampInSimulatedJitterBuffer - SubtLogicConfiguration.JitterBufferLengthTicks);

               // if (_stream.Stream.Debug) Debugger.Break();

                // remove oldest frames which are being played
                for (;;)
                {
                    var oldestItem = _jitterBuffer.First;
                    if (oldestItem == null)
                        break;
                    if (MiscProcedures.TimeStamp1IsLess(oldestItem.Value.timestamp32, maxAllowedTimestampInSimulatedJitterBuffer) == false)
                    {
                  //      if (_stream.Stream.Debug) _subtLocalPeer.WriteToLog(
                  //          $"<< PlaybackFromJitter count={_jitterBuffer.Count} oldestTS={oldestItem.Value.timestamp32}, maxAllowedTimestampInSimulatedJitterBuffer={maxAllowedTimestampInSimulatedJitterBuffer}, newestTimestamp={newestTimestampInSimulatedJitterBuffer}");
                        break;
                    }

                    OnPlayed(oldestItem.Value, timeNow32);
                    _jitterBuffer.RemoveFirst();
                }
            }
        }
Exemplo n.º 3
0
        void ProcessReceivedAcceptedHello_UpdateHelloLevelFields(ConnectedPeer connectedPeer, ConnectedPeerStream stream, PeerHelloPacket helloResponsePacket, uint responseReceivedTime32)
        {
            var rtt = TimeSpan.FromTicks(unchecked (responseReceivedTime32 - helloResponsePacket.RequestTime32)) - TimeSpan.FromMilliseconds(helloResponsePacket.ResponseCpuDelayMs ?? 0);

            if (rtt < TimeSpan.Zero)
            {
                rtt = TimeSpan.Zero;                      // avoid abnormal measurements
            }
            stream.LatestHelloRtt           = rtt;
            stream.LocalPeerPublicIp        = helloResponsePacket.RequestedFromIp;
            stream.LastTimeReceivedAccepted = _localPeer.DateTimeNowUtc;
            connectedPeer.ProtocolVersion   = helloResponsePacket.ProtocolVersion;
            connectedPeer.LibraryVersion    = MiscProcedures.Uint32secondsToDateTime(helloResponsePacket.LibraryVersion);
            connectedPeer.TotalHelloAcceptedPacketsReceived++;
            stream.TotalHelloAcceptedPacketsReceived++;
            stream.RemotePeerRoleIsUser = helloResponsePacket.RoleFlagIsUser;

            if (helloResponsePacket.IpLocationData != null && connectedPeer.RemoteIpLocationData == null)
            {
                _localPeer.WriteToLog_higherLevelDetail(LogModules.Hello, $"got IP location from peer {connectedPeer}: {helloResponsePacket.IpLocationData}");
                connectedPeer.RemoteIpLocationData = helloResponsePacket.IpLocationData;
            }

            if (helloResponsePacket.ExtensionIds != null && helloResponsePacket.ExtensionIds.Length != 0)
            {
                connectedPeer.LatestReceivedRemoteExtensionIds = new HashSet <string>(helloResponsePacket.ExtensionIds.Distinct());
            }
        }
Exemplo n.º 4
0
        internal byte[] DecryptAndVerify(byte[] encryptedNullable, byte[] hmacNullable, int id, EncryptedFieldIds fieldId)
        {
            if (encryptedNullable == null || hmacNullable == null)
            {
                return(null);
            }

            GetIVandKeys(id, fieldId, out var iv, out var aesKey, out var hmacKey);

            var hmac = _cryptoLibrary.GetSha256HMAC(hmacKey, encryptedNullable);

            if (!MiscProcedures.EqualByteArrays(hmacNullable, hmac))
            {
                throw new BadSignatureException();
            }

            var decrypted = new byte[encryptedNullable.Length];

            _cryptoLibrary.ProcessAesCbcBlocks(false, aesKey, iv, encryptedNullable, decrypted);

            using var reader = BinaryProcedures.CreateBinaryReader(decrypted, 0);
            var dataLength = reader.ReadUInt16();

            return(reader.ReadBytes(dataLength));
        }
Exemplo n.º 5
0
        void SendStatusIfNeeded(uint timestamp32)
        {
            if (_lastTimeSentStatus == null ||
                MiscProcedures.TimeStamp1IsLess(_lastTimeSentStatus.Value + SubtLogicConfiguration.RxMeasurementsTransmissionIntervalTicks, timestamp32)
                )
            {
                _lastTimeSentStatus = timestamp32;
                var remotePeerId = SubtConnectedPeer.RemotePeerId;
                if (remotePeerId != null)
                {
                    bool iwantToIncreaseBandwidthUntilHighPacketLoss = false;
                    if (SubtLocalPeer.LocalPeer.Configuration.RoleAsUser)
                    { // initially this signal comes from user
                        iwantToIncreaseBandwidthUntilHighPacketLoss = SubtLocalPeer.Configuration.BandwidthTargetMbps == null;
                    }
                    else if (SubtLocalPeer.LocalPeer.Configuration.RoleAsSharedPassive)
                    { // and then gets reflected from sharedPassive peers
                        iwantToIncreaseBandwidthUntilHighPacketLoss = LatestRemoteStatus?.IwantToIncreaseBandwidthUntilHighPacketLoss == true;
                    }

                    var data = new SubtRemoteStatusPacket(_rxMeasurement.RecentBandwidth, _rxMeasurement.RecentPacketLoss,
                                                          this.RecentTxBandwidth,
                                                          iwantToIncreaseBandwidthUntilHighPacketLoss,
                                                          SubtLocalPeer.LocalPeer.Configuration.RoleAsSharedPassive)
                               .Encode(this);
                    _stream.SendPacket(data, data.Length);
                }
            }
        }
Exemplo n.º 6
0
        public override bool Equals(object obj)
        {
            var obj2 = (HMAC)obj;

            if (obj2.Flags != this.Flags)
            {
                return(false);
            }
            return(MiscProcedures.EqualByteArrays(obj2.hmacSha256, this.hmacSha256));
        }
Exemplo n.º 7
0
        void RetransmitBandwidthAdjustmentRequestIfNeeded(uint timestamp32) // sender thread
        {
            var p = PendingAdjustmentRequestPacketData;                     // save it to this (sender) thread

            if (p != null && _lastTimeSentBandwidthAdjustmentRequest != null &&
                MiscProcedures.TimeStamp1IsLess(_lastTimeSentBandwidthAdjustmentRequest.Value + SubtLogicConfiguration.SubtAdjustmentRequestTransmissionIntervalTicks, timestamp32)
                )
            {
                _lastTimeSentBandwidthAdjustmentRequest = timestamp32;
                _stream.SendPacket(p, p.Length);
            }
        }
Exemplo n.º 8
0
        bool TryInsertIntoJitterBuffer(JitterBufferElement jbe)
        {
            // _subtLocalPeer.WriteToLog($">> TryInsertIntoJitterBuffer strm{_stream.StreamId} count={_jitterBuffer.Count} ts={jbe.timestamp32} seq={jbe.sequence} last (newest) TS={_jitterBuffer.Last?.Value?.timestamp32}");

            if (IsNewElementOutOfSequence(jbe)) return false;

            LinkedListNode<JitterBufferElement> insertAfter = null;
            for (var item = _jitterBuffer.Last; ;)
            {
                if (item == null) break;
                var enumeratedSequence = item.Value.sequence;
                if (enumeratedSequence == jbe.sequence) return false; // duplicate packet
                if (Sequence1IsLess(enumeratedSequence, jbe.sequence))
                {
                    insertAfter = item;
                    break;
                }
                item = item.Previous;
            }

            if (insertAfter == null)
            {
                //if (_jitterBuffer.First != null)
                //{
                //    if (TimeStamp1IsLess(_jitterBuffer.First.Value.timestamp32, jbe.timestamp32))
                //    {
                //        // throw new Exception();
                //        _subtLocalPeer.WriteToLog($"strm{_stream.StreamId} count={_jitterBuffer.Count}. bad item put into JB: ts={jbe.timestamp32} seq={jbe.sequence} firstTS={_jitterBuffer.First.Value.timestamp32}  firstSeq={_jitterBuffer.First.Value.sequence} ");
                //        foreach (var item in _jitterBuffer)
                //            _subtLocalPeer.WriteToLog($"strm{_stream.StreamId} item: TS={item.timestamp32}  seq={item.sequence} ");                        
                //        return false;
                //    }
                //}
                _jitterBuffer.AddFirst(jbe);
            }
            else
            {
                if (MiscProcedures.TimeStamp1IsLess(jbe.timestamp32, insertAfter.Value.timestamp32))
                {
                    _subtLocalPeer.WriteToLog_lightPain($"JB corruption check: received {jbe}; first: {_jitterBuffer.First?.Value}; last: {_jitterBuffer.Last?.Value}");
                    return false;
                    //throw new Exception();
                }
                _jitterBuffer.AddAfter(insertAfter, jbe);
            }

          //  if (_stream.Stream.Debug)
        //        CheckJitterBuffer();

            return true;
        }
Exemplo n.º 9
0
        void ThreadEntry()
        {
            var        sw           = Stopwatch.StartNew();
            var        previousTs32 = _localPeer.LocalPeer.Time32;
            const uint period32     = (uint)TimeSpan.TicksPerMillisecond * 10;
            int        counter      = 0;

            while (!_disposing)
            {
                try
                {
                    _actionsQueue.ExecuteQueued();

                    var timeNow32 = _localPeer.LocalPeer.Time32;

                    while (MiscProcedures.TimeStamp1IsLess(previousTs32, timeNow32) && !_disposing)
                    {
                        if (_debug)
                        {
                            Debugger.Break();
                        }

                        previousTs32 = unchecked (previousTs32 + period32);
                        foreach (var stream in _streams.Values)
                        {
                            stream.SendPacketsIfNeeded_10ms();
                        }
                        counter++;
                        if (counter % 10 == 0)
                        {
                            foreach (var stream in _streams.Values)
                            {
                                stream.SendPayloadPacketsIfNeeded_100ms();
                            }
                        }
                        if (counter % 100 == 0)
                        {
                            foreach (var stream in _streams.Values)
                            {
                                stream.SendPayloadPacketsIfNeeded_1s();
                            }
                        }
                    }
                }
                catch (Exception exc)
                {
                    _localPeer.HandleException(exc);
                }
                Thread.Sleep(10);
            }
        }
Exemplo n.º 10
0
        void CheckJitterBuffer()
        {
            ushort? previousSeq = null;
            uint? previousTs32 = null;
            foreach (var jbe in _jitterBuffer)
            {
                if (previousSeq.HasValue && Sequence1IsLess(jbe.sequence, previousSeq.Value))
                    throw new Exception();
                if (previousTs32.HasValue && MiscProcedures.TimeStamp1IsLess(jbe.timestamp32, previousTs32.Value))
                    throw new Exception();

                previousSeq = jbe.sequence;
                previousTs32 = jbe.timestamp32;
            }
        } 
        public override string ToString()
        {
            var r = $"[responderEP={ResponderEndpoint}";

            if (RequestPacketDataNullable != null)
            {
                r += $", req={(PacketTypes)RequestPacketDataNullable[0]} (hash={MiscProcedures.GetArrayHashCodeString(RequestPacketDataNullable)})";
            }
            if (ResponseScanner != null && ResponseScanner.ResponseFirstBytes != null)
            {
                r += $", resp={(PacketTypes)ResponseScanner.ResponseFirstBytes[0]}";
            }
            r += $", timeout={_expirationTimeoutS}s, compl.Action={CompletionActionVisibleId}]";
            return(r);
        }
Exemplo n.º 12
0
        /// <summary>
        /// if this procedure is used - "OnTimePassed" must not be called externally
        /// </summary>
        public void OnTimeObserved(uint timeNow32)
        {
            if (_latestTimeObserved.HasValue)
            {
                if (MiscProcedures.TimeStamp1IsLess(timeNow32, _latestTimeObserved.Value))
                {
                    // can happen if 2 threads use this class instance in parallel, and each thread calls this procedure.  it is normal situation, when "timeNow32" is a 'little bit' less than "_latestTimeObserved"
                    //  todo event for developer  in case of "high" jumps?
                    return;
                }

                OnTimePassed(unchecked (timeNow32 - _latestTimeObserved.Value));
            }
            _latestTimeObserved = timeNow32;
        }
Exemplo n.º 13
0
        /// <summary>
        /// creates a scanner that finds ACK1 that matches to REQ
        /// </summary>
        /// <param name="connectionToNeighborNullable">
        /// peer that responds to REQ with ACK1
        /// if not null - the scanner will verify ACK1.NeighborHMAC
        /// </param>
        public static LowLevelUdpResponseScanner GetScanner(Logger logger, RequestP2pSequenceNumber16 reqP2pSeq16, ConnectionToNeighbor connectionToNeighborNullable = null)
        {
            if (logger.WriteToLog_detail_enabled)
            {
                logger.WriteToLog_detail($">> FailurePacket.GetScanner() reqP2pSeq16={reqP2pSeq16}");
            }
            BinaryProcedures.CreateBinaryWriter(out var ms, out var w);
            w.Write((byte)PacketTypes.Failure);
            w.Write((byte)0);
            if (connectionToNeighborNullable != null)
            {
                connectionToNeighborNullable.LocalNeighborToken32.Encode(w);
            }

            reqP2pSeq16.Encode(w);

            var r = new LowLevelUdpResponseScanner
            {
                ResponseFirstBytes   = ms.ToArray(),
                IgnoredByteAtOffset1 = 1 // ignore flags
            };

            if (connectionToNeighborNullable != null)
            {
                r.OptionalFilter = (responseData) =>
                {
                    if (logger.WriteToLog_detail_enabled)
                    {
                        logger.WriteToLog_detail($"filtering FAILURE @scanner: hash={MiscProcedures.GetArrayHashCodeString(responseData)}");
                    }
                    if (connectionToNeighborNullable.IsDisposed)
                    {
                        logger.WriteToLog_needsAttention("ignoring FAILURE: connection is disposed");
                        return(false);
                    }
                    var failure = DecodeAndOptionallyVerify(responseData, reqP2pSeq16);
                    if (failure.NeighborHMAC.Equals(connectionToNeighborNullable.GetNeighborHMAC(failure.GetSignedFieldsForNeighborHMAC)) == false)
                    {
                        logger.WriteToLog_attacks("ignoring FAILURE: received HMAC is invalid");
                        return(false);
                    }
                    return(true);
                };
            }
            return(r);
        }
        /// <param name="waitNhaFromNeighborNullable">is used to verify NPACK.NeighborHMAC</param>
        internal async Task <NeighborPeerAckPacket> OptionallySendUdpRequestAsync_Retransmit_WaitForNeighborPeerAck(string completionActionVisibleId, byte[] requestPacketDataNullable, IPEndPoint responderEndpoint,
                                                                                                                    RequestP2pSequenceNumber16 reqP2pSeq16, ConnectionToNeighbor waitNhaFromNeighborNullable = null, Action <BinaryWriter> npaRequestFieldsForNeighborHmacNullable = null)
        {
            var npaScanner = NeighborPeerAckPacket.GetScanner(reqP2pSeq16, waitNhaFromNeighborNullable, npaRequestFieldsForNeighborHmacNullable);

            if (WriteToLog_udp_deepDetail_enabled)
            {
                WriteToLog_udp_deepDetail($"waiting for NPACK, scanner: {MiscProcedures.ByteArrayToString(npaScanner.ResponseFirstBytes)} npaSeq={reqP2pSeq16}");
            }
            var nextHopResponsePacketData = await SendUdpRequestAsync_Retransmit(
                new PendingLowLevelUdpRequest(completionActionVisibleId, responderEndpoint,
                                              npaScanner,
                                              DateTimeNowUtc, Configuration.UdpLowLevelRequests_ExpirationTimeoutS,
                                              requestPacketDataNullable,
                                              Configuration.UdpLowLevelRequests_InitialRetransmissionTimeoutS, Configuration.UdpLowLevelRequests_RetransmissionTimeoutIncrement
                                              ));

            if (nextHopResponsePacketData == null)
            {
                string desc = "no NPACK response to DRP request '";
                if (requestPacketDataNullable != null)
                {
                    desc += (PacketTypes)requestPacketDataNullable[0];
                }
                desc += $"' - timeout expired ({Configuration.UdpLowLevelRequests_ExpirationTimeoutS}s) completionAction={completionActionVisibleId}";
                if (waitNhaFromNeighborNullable != null)
                {
                    desc += $", neighbor={waitNhaFromNeighborNullable}";
                }
                throw new DrpTimeoutException(desc);
            }

            var nextHopResponsePacket = new NeighborPeerAckPacket(nextHopResponsePacketData);

            if (nextHopResponsePacket.ResponseCode != ResponseOrFailureCode.accepted)
            {
                if (WriteToLog_udp_deepDetail_enabled)
                {
                    WriteToLog_udp_deepDetail($"got NPACK with {nextHopResponsePacket.ResponseCode} throwing exception");
                }
                throw new RequestRejectedException(nextHopResponsePacket.ResponseCode);
            }
            return(nextHopResponsePacket);
        }
        /// <summary>
        /// is executed by engine thread
        /// </summary>
        /// <returns>
        /// true if the response is linked to request, and the packet is processed
        /// </returns>
        bool PendingUdpRequests_ProcessPacket(IPEndPoint responderEndpoint, byte[] udpData, DateTime receivedAtUtc)
        {
            using var tracker = CreateTracker("PendingUdpRequests_ProcessPacket");
            tracker.Details   = $"count={_pendingLowLevelUdpRequests.Count}";

            // todo optimize this by storing pending requests indexed
            for (var item = _pendingLowLevelUdpRequests.First; item != null; item = item.Next)
            {
                var request = item.Value;

                if (WriteToLog_udp_deepDetail_enabled)
                {
                    WriteToLog_udp_deepDetail($"matching to pending request... responderEndpoint={responderEndpoint}, " +
                                              $"udpData={MiscProcedures.ByteArrayToString(udpData)} ({(PacketTypes)udpData[0]}) " +
                                              $"hash={MiscProcedures.GetArrayHashCodeString(udpData)}, " +
                                              $"request={request}"
                                              // + $" ResponseScanner.ResponseFirstBytes={MiscProcedures.ByteArrayToString(request.ResponseScanner.ResponseFirstBytes)}"
                                              );
                }

                try
                {
                    if (request.ResponderEndpoint.Equals(responderEndpoint) && request.ResponseScanner.Scan(this, udpData))
                    {
                        tracker.Details += $"; completed {request.CompletionActionVisibleId}";
                        _pendingLowLevelUdpRequests.Remove(item);
                        request.ResponseReceivedAtUtc = receivedAtUtc;
                        tracker.Dispose();
                        using (var tr2 = CreateTracker(request.CompletionActionVisibleId))
                            request.TaskCompletionSource.SetResult(udpData);
                        return(true);
                    }
                }
                catch (Exception exc)
                {
                    HandleExceptionInEngineThread(exc);
                }
            }

            //  WriteToLog_udp_detail($"match to pending request was not found for packet from {responderEndpoint}, udpData={MiscProcedures.ByteArrayToString(udpData)}");

            return(false);
        }
Exemplo n.º 16
0
        void ProcessClientHello1(ICcpRemoteEndpoint clientEndpoint, BinaryReader reader, byte[] payloadData) // packets processor thread
        {
            var snonce0 = _snonce0Table.TryGetSnonce0(clientEndpoint);

            if (snonce0 == null)
            {
                HandleBadSnonce0(clientEndpoint);
                return;
            }

            var packet = new ClientHelloPacket1(reader, payloadData);

            // check snonce0
            if (!MiscProcedures.EqualByteArrays(packet.Snonce0, snonce0.Snonce0))
            {
                HandleBadSnonce0(clientEndpoint);
                return;
            }

            ///check stateful PoW result
            var hash = _cryptoLibrary.GetHashSHA256(packet.OriginalPacketPayload);

            // calculate hash, considering entire packet data (including stateful PoW result)
            // verify hash result
            if (!StatefulPowHashIsOK(hash))
            {
                HandleBadStatefulPowPacket(clientEndpoint);
                // no response
                return;
            }

            // questionable:    hello1IPlimit table:  limit number of requests  per 1 minute from every IPv4 block: max 100? requests per 1 minute from 1 block
            //   ------------ possible attack on hello1IPlimit  table???


            var response = new ServerHelloPacket1 {
                Status = ServerHello1Status.OKready, Cnonce1 = packet.StatefulProofOfWorkResponseData
            };
            var responseBytes = response.Encode();

            _ccpTransport.SendPacket(clientEndpoint, responseBytes);
        }
Exemplo n.º 17
0
 void SendStatusIfNeeded(uint timestamp32) // sender thread
 {
     if (_lastTimeSentStatus == null ||
         MiscProcedures.TimeStamp1IsLess(_lastTimeSentStatus.Value + SubtLogicConfiguration.SubtRemoteStatusPacketTransmissionIntervalTicks, timestamp32)
         )
     {
         _lastTimeSentStatus = timestamp32;
         var remotePeerId = SubtConnectedPeer.RemotePeerId;
         if (remotePeerId != null)
         {
             var statusPacket = new SubtRemoteStatusPacket(_rxMeasurement.RecentBandwidth, _rxMeasurement.RecentPacketLoss,
                                                           this.RecentTxBandwidth,
                                                           SubtLocalPeer.LocalPeer.Configuration.RoleAsSharedPassive,
                                                           SubtLocalPeer.ImHealthyAndReadyFor100kbpsU2uSymbiosis
                                                           );
             var data = statusPacket.Encode(this);
             _stream.SendPacket(data, data.Length);
         }
     }
 }
        public Func <byte[], bool> OptionalFilter;             // verifies NPACK.NeighborHMAC, ignores invalid HMACs // returns false to ignore the processed response packet

        public bool Scan(DrpPeerEngine engine, byte[] udpData) // may throw parser exception
        {
            if (!MiscProcedures.EqualByteArrayHeader(ResponseFirstBytes, udpData, IgnoredByteAtOffset1))
            {
                if (engine.WriteToLog_udp_deepDetail_enabled)
                {
                    engine.WriteToLog_udp_deepDetail($"packet does not match to ResponseFirstBytes={MiscProcedures.ByteArrayToString(ResponseFirstBytes)} ({(PacketTypes)ResponseFirstBytes[0]}) udpData={MiscProcedures.ByteArrayToString(udpData)} ({(PacketTypes)udpData[0]})"
                                                     );
                }
                return(false);
            }
            if (OptionalFilter != null)
            {
                if (!OptionalFilter(udpData))
                {
                    //if (engine.WriteToLog_udp_deepDetail_enabled)
                    engine.WriteToLog_udp_lightPain($"packet did not pass OptionalFilter");
                    return(false);
                }
            }
            return(true);
        }
Exemplo n.º 19
0
        void SendStatusIfNeeded(uint timestamp32) // sender thread
        {
            if (_lastTimeSentStatus == null ||
                MiscProcedures.TimeStamp1IsLess(_lastTimeSentStatus.Value + SubtLogicConfiguration.SubtRemoteStatusPacketTransmissionIntervalTicks, timestamp32)
                )
            {
                _lastTimeSentStatus = timestamp32;
                var remotePeerId = SubtConnectedPeer.RemotePeerId;
                if (remotePeerId != null)
                {
                    bool samePacketAlreadySent = false;
                    if (_lastSentSubtStatusPacket != null)
                    {
                        if (_lastSentSubtStatusPacket.ImHealthyAndReadyFor100kbpsU2uSymbiosis == SubtLocalPeer.ImHealthyAndReadyFor100kbpsU2uSymbiosis &&
                            _lastSentSubtStatusPacket.RecentTxBandwidth == this.RecentTxBandwidth &&
                            _lastSentSubtStatusPacket.RecentRxBandwidth == _rxMeasurement.RecentBandwidth)
                        {
                            samePacketAlreadySent = true;
                        }
                    }

                    if (!samePacketAlreadySent)
                    {
                        var statusPacket = new SubtRemoteStatusPacket(_rxMeasurement.RecentBandwidth, _rxMeasurement.RecentPacketLoss,
                                                                      this.RecentTxBandwidth,
                                                                      SubtLocalPeer.LocalPeer.Configuration.RoleAsSharedPassive,
                                                                      SubtLocalPeer.ImHealthyAndReadyFor100kbpsU2uSymbiosis
                                                                      );
                        //  SubtLocalPeer.WriteToLog_deepDetail($"sending SUBT status packet: {statusPacket} to peer {SubtConnectedPeer.RemotePeerId}");
                        var data = statusPacket.Encode(this);
                        _stream.SendPacket(data, data.Length);
                        _lastSentSubtStatusPacket = statusPacket;
                    }
                }
            }
        }
Exemplo n.º 20
0
 public override string ToString() => MiscProcedures.ByteArrayToString(Ed25519publicKey);
Exemplo n.º 21
0
 public override int GetHashCode()
 {
     return(MiscProcedures.GetArrayHashCode(Ed25519publicKey));
 }
Exemplo n.º 22
0
        public override bool Equals(object obj)
        {
            var obj2 = (RegistrationId)obj;

            return(MiscProcedures.EqualByteArrays(obj2.Ed25519publicKey, this.Ed25519publicKey));
        }
Exemplo n.º 23
0
 public override string ToString() => MiscProcedures.ByteArrayToString(hmacSha256);
Exemplo n.º 24
0
 Contact GetUnconfirmedContactByToken(byte[] contactInvitationToken)
 {
     return(Contacts.Values.FirstOrDefault(x => x.LocallyInitiatedIke1Invitation != null && MiscProcedures.EqualByteArrays(x.LocallyInitiatedIke1Invitation.ContactInvitationToken, contactInvitationToken) == true));
 }
Exemplo n.º 25
0
        void IDrpRegisteredPeerApp.OnReceivedInvite(RegistrationId remoteRegistrationId, byte[] contactInvitationToken, out UserId remoteUserIdNullable, out UserCertificate localUserCertificateWithPrivateKey, out bool autoReply)
        {
            remoteUserIdNullable = null;

            var contact = GetUnconfirmedContactByToken(contactInvitationToken);

            if (contact == null)
            {
                _userAppEngine.WriteToLog_needsAtttention($"unconfirmed contact was not found by contactInvitationToken={MiscProcedures.ByteArrayToString(contactInvitationToken)}");
                autoReply = false;
                localUserCertificateWithPrivateKey = null;
            }
            else
            {
                _userAppEngine.WriteToLog_higherLevelDetail($"unconfirmed contact '{contact.UserAliasID}' was found by contactInvitationToken={MiscProcedures.ByteArrayToString(contactInvitationToken)}");
                autoReply = true;
                localUserCertificateWithPrivateKey = User.LocalUserCertificate;
                localUserCertificateWithPrivateKey.AssertHasPrivateKey();
                localUserCertificateWithPrivateKey.AssertIsValidNow(_userAppEngine.Engine.CryptoLibrary, User.UserID, _userAppEngine.Engine.DateTimeNowUtc);
            }
        }
Exemplo n.º 26
0
 bool RemoteVersionIsAcceptableForNewConnection(PeerHelloPacket remoteHello)
 {
     return(MiscProcedures.Uint32secondsToDateTime(remoteHello.LibraryVersion) > MiscProcedures.MinPeerCompilationDateTimeUtcExclusive);
 }
Exemplo n.º 27
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;
            }
        }
Exemplo n.º 28
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.º 29
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);
            }
        }
Exemplo n.º 30
0
        const ushort Magic16_ipv4_requesterToResponder = 0xBFA4; // is used to validate decrypted data

        //   IAuthenticatedEncryptor Encryptor;
        //   IAuthenticatedDecryptor Decryptor;

        /// <summary>
        /// initializes SharedAuthKeyForHMAC
        /// </summary>
        public void InitializeP2pStream(RegisterRequestPacket req, RegisterAck1Packet ack1, RegisterAck2Packet ack2)
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(ToString());
            }

            _req  = req;
            _ack1 = ack1;
            _ack2 = ack2;

            var ms = new MemoryStream();

            using (var writer = new BinaryWriter(ms))
            {
                req.GetSharedSignedFields(writer, true);
                ack1.GetSharedSignedFields(writer, true, true);
                ack2.GetSharedSignedFields(writer, false, true);
                //  var iv = cryptoLibrary.GetHashSHA256(ms.ToArray()); // todo use for p2p  encryption

                ms.Write(SharedDhSecret, 0, SharedDhSecret.Length);

                SharedAuthKeyForNeighborHMAC = _engine.CryptoLibrary.GetHashSHA256(ms.ToArray()); // here SHA256 is used as KDF, together with common fields from packets, including both ECDH public keys and timestamp

                if (_engine.WriteToLog_p2p_detail_enabled)
                {
                    _engine.WriteToLog_p2p_detail2(this, $"initialized P2P stream: SharedAuthKeyForHMAC={MiscProcedures.ByteArrayToString(SharedAuthKeyForNeighborHMAC)}", req);
                }
                //Encryptor = cryptoLibrary.CreateAesEncyptor(iv, aesKey);
                //Decryptor = cryptoLibrary.CreateAesDecyptor(iv, aesKey);
            }
        }