/// <summary> /// generates new snonce0 object /// resets state when necessary /// </summary> public Snonce0State GenerateOrGetExistingSnonce0(uint timeSec32UTC, ICcpRemoteEndpoint clientEndpoint) { if (timeSec32UTC > _nextPeriodSwitchTimeSec32UTC || _currentPeriodStates.Count > _config.Snonce0TableMaxSize) { // switch tables _previousPeriodStates = _currentPeriodStates; _currentPeriodStates = new Dictionary <ICcpRemoteEndpoint, Snonce0State>(); _nextPeriodSwitchTimeSec32UTC = timeSec32UTC + _config.Snonce0TablePeriodSec; } var existingSnonce0 = TryGetSnonce0(clientEndpoint); if (existingSnonce0 != null) { return(existingSnonce0); } var r = new Snonce0State { Snonce0 = new byte[ServerHelloPacket0.Snonce0SupportedSize] }; _rnd.NextBytes(r.Snonce0); _currentPeriodStates.Add(clientEndpoint, r); return(r); }
void RespondToHello0(ICcpRemoteEndpoint clientEndpoint, ServerHello0Status status, byte[] cnonce0) { var response = new ServerHelloPacket0 { Status = status, Cnonce0 = cnonce0 }; var responseBytes = response.Encode(); _ccpTransport.SendPacket(clientEndpoint, responseBytes); }
public Snonce0State TryGetSnonce0(ICcpRemoteEndpoint clientEndpoint) { if (_currentPeriodStates.TryGetValue(clientEndpoint, out var r)) { return(r); } if (_previousPeriodStates.TryGetValue(clientEndpoint, out r)) { return(r); } return(null); }
void ICcpTransportUser.ProcessPacket(ICcpRemoteEndpoint remoteEndpoint, byte[] data) // receiver thread(s) { lock (_packetsToProcess) { if (_packetsToProcess.Count > _config.PacketProcessingQueueMaxCount) { OnPacketProcessingQueueOverloaded(); return; } _packetsToProcess.Enqueue(new ReceivedPacket { ClientEndpoint = remoteEndpoint, Data = data }); } }
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 ProcessClientHello0(ICcpRemoteEndpoint clientEndpoint, BinaryReader reader, byte[] payloadData) // packets processor thread { var packet = new ClientHelloPacket0(reader, payloadData); if (!PassStatelessPoWfilter(clientEndpoint, packet)) { return; } // create snonce0 state var snonce0 = _snonce0Table.GenerateOrGetExistingSnonce0(TimeSec32UTC, clientEndpoint); var response = new ServerHelloPacket0 { Cnonce0 = packet.Cnonce0, Snonce0 = snonce0.Snonce0, Status = ServerHello0Status.OK, StatefulProofOfWorkType = StatefulProofOfWorkType._2019_06 }; var responseBytes = response.Encode(); _ccpTransport.SendPacket(clientEndpoint, responseBytes); }
bool PassStatelessPoWfilter(ICcpRemoteEndpoint clientEndpoint, ClientHelloPacket0 packet)// packets processor thread // sends responses { switch (packet.StatelessProofOfWorkType) { case StatelessProofOfWorkType._2019_06: // verify size of PoW data if (packet.StatelessProofOfWorkData.Length < 12 || packet.StatelessProofOfWorkData.Length > 64) { throw new CcpBadPacketException(); } // verify datetime ("period") // return err code if time is wrong, with correct server's UTC time uint receivedTimeSec32; unsafe { fixed(byte *statelessProofOfWorkDataPtr = packet.StatelessProofOfWorkData) { fixed(byte *addressBytesPtr = clientEndpoint.AddressBytes) { receivedTimeSec32 = *((uint *)statelessProofOfWorkDataPtr); if (addressBytesPtr[0] != statelessProofOfWorkDataPtr[4] || addressBytesPtr[1] != statelessProofOfWorkDataPtr[5] || addressBytesPtr[2] != statelessProofOfWorkDataPtr[6] || addressBytesPtr[3] != statelessProofOfWorkDataPtr[7] ) { if (_config.RespondErrors) { RespondToHello0(clientEndpoint, ServerHello0Status.ErrorBadStatelessProofOfWork_BadSourceIp, packet.Cnonce0); } return(false); } } } } var localTimeSec32 = TimeSec32UTC; var diffSec = Math.Abs((int)unchecked (localTimeSec32 - receivedTimeSec32)); if (diffSec > _config.StatelessPoW_MaxClockDifferenceS) { // respond with error "try again with valid clock" - legitimate user has to get valid clock from some time server and synchronize itself with the server if (_config.RespondErrors) { RespondToHello0(clientEndpoint, ServerHello0Status.ErrorBadStatelessProofOfWork_BadClock, packet.Cnonce0); } return(false); } var hash = _cryptoLibrary.GetHashSHA256(packet.OriginalPacketPayload); // calculate hash, considering entire packet data (including stateless PoW result) // verify hash result if (!StatelessPowHashIsOK(hash)) { HandleBadStatelessPowPacket(clientEndpoint); // no response return(false); } // check if hash is unique var dataIsUnique = _recentUniquePowData.TryInputData(hash, localTimeSec32); if (dataIsUnique) { return(true); } else { // respond with error "try again with unique PoW data" if (_config.RespondErrors) { RespondToHello0(clientEndpoint, ServerHello0Status.ErrorTryAgainRightNowWithThisServer, packet.Cnonce0); } return(false); } default: throw new CcpBadPacketException(); } }
void HandleBadStatefulPowPacket(ICcpRemoteEndpoint remoteEndpoint) { //todo }
void HandleBadSnonce0(ICcpRemoteEndpoint remoteEndpoint) {//todo }
/// <summary> /// possibly but not neccessarily malformed, because it created an exception /// </summary> void HandleMalformedPacket(ICcpRemoteEndpoint remoteEndpoint) { //todo }
void ICcpTransport.SendPacket(ICcpRemoteEndpoint remoteEndpoint, byte[] data) { var ep = (CcpUdpRemoteEndpoint)remoteEndpoint; _socket.Send(data, data.Length, ep.Endpoint); }