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; } }
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(); } } }
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()); } }
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)); }
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); } } }
public override bool Equals(object obj) { var obj2 = (HMAC)obj; if (obj2.Flags != this.Flags) { return(false); } return(MiscProcedures.EqualByteArrays(obj2.hmacSha256, this.hmacSha256)); }
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); } }
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; }
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); } }
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); }
/// <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; }
/// <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); }
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); }
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); }
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; } } } }
public override string ToString() => MiscProcedures.ByteArrayToString(Ed25519publicKey);
public override int GetHashCode() { return(MiscProcedures.GetArrayHashCode(Ed25519publicKey)); }
public override bool Equals(object obj) { var obj2 = (RegistrationId)obj; return(MiscProcedures.EqualByteArrays(obj2.Ed25519publicKey, this.Ed25519publicKey)); }
public override string ToString() => MiscProcedures.ByteArrayToString(hmacSha256);
Contact GetUnconfirmedContactByToken(byte[] contactInvitationToken) { return(Contacts.Values.FirstOrDefault(x => x.LocallyInitiatedIke1Invitation != null && MiscProcedures.EqualByteArrays(x.LocallyInitiatedIke1Invitation.ContactInvitationToken, contactInvitationToken) == true)); }
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); } }
bool RemoteVersionIsAcceptableForNewConnection(PeerHelloPacket remoteHello) { return(MiscProcedures.Uint32secondsToDateTime(remoteHello.LibraryVersion) > MiscProcedures.MinPeerCompilationDateTimeUtcExclusive); }
/// <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; } }
/// <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); }
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); } }
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); } }