public float GetTrustValue() { // update if last calcualtion is too old, will assert if this entry is not supposed to have a trustvalue if (Environment.TickCount - dwLastTrustValueCalc > Opcodes.MIN2MS(10)) { RecalcualteTrustValue(); } return(m_fTrustValue); }
protected bool InTrackListIsAllowedPacket(uint uIP, byte byOpcode, bool bValidSenderkey) { // this tracklist tacks _incoming_ request packets and acts as a general flood protection by dropping // too frequent requests from a single IP, avoiding response floods, processing time DOS attacks and slowing down // other possible attacks/behavior (scanning indexed files, fake publish floods, etc) // first figure out if this is a request packet to be tracked and its timelimits // timelimits are choosed by estimating the max. frequency of such packets on normal operation (+ buffer) // (those limits are not meant be fine to be used by normal usage, but only supposed to be a flood detection) uint iAllowedPacketsPerMinute; byte byDbgOrgOpcode = byOpcode; switch (byOpcode) { case Opcodes.KADEMLIA2_BOOTSTRAP_REQ: iAllowedPacketsPerMinute = 2; break; case Opcodes.KADEMLIA2_HELLO_REQ: iAllowedPacketsPerMinute = 3; break; case Opcodes.KADEMLIA2_REQ: iAllowedPacketsPerMinute = 10; break; case Opcodes.KADEMLIA2_SEARCH_NOTES_REQ: iAllowedPacketsPerMinute = 3; break; case Opcodes.KADEMLIA2_SEARCH_KEY_REQ: iAllowedPacketsPerMinute = 3; break; case Opcodes.KADEMLIA2_SEARCH_SOURCE_REQ: iAllowedPacketsPerMinute = 3; break; case Opcodes.KADEMLIA2_PUBLISH_KEY_REQ: iAllowedPacketsPerMinute = 3; break; case Opcodes.KADEMLIA2_PUBLISH_SOURCE_REQ: iAllowedPacketsPerMinute = 2; break; case Opcodes.KADEMLIA2_PUBLISH_NOTES_REQ: iAllowedPacketsPerMinute = 2; break; case Opcodes.KADEMLIA_FIREWALLED2_REQ: byOpcode = Opcodes.KADEMLIA_FIREWALLED_REQ; iAllowedPacketsPerMinute = 2; break; case Opcodes.KADEMLIA_FIREWALLED_REQ: iAllowedPacketsPerMinute = 2; break; case Opcodes.KADEMLIA_FINDBUDDY_REQ: iAllowedPacketsPerMinute = 2; break; case Opcodes.KADEMLIA_CALLBACK_REQ: iAllowedPacketsPerMinute = 1; break; case Opcodes.KADEMLIA2_PING: iAllowedPacketsPerMinute = 2; break; default: // not any request packets, so its a response packet - no further checks on this point return(true); } uint iSecondsPerPacket = 60 / iAllowedPacketsPerMinute; uint dwCurrentTick = (uint)Environment.TickCount; // time for cleaning up? if (dwCurrentTick - dwLastTrackInCleanup > Opcodes.MIN2MS(12)) { InTrackListCleanup(); } // check for existing entries TrackPacketsIn_Struct pTrackEntry; if (!m_mapTrackPacketsIn.ContainsKey(uIP)) { pTrackEntry = new TrackPacketsIn_Struct(); pTrackEntry.m_uIP = uIP; m_mapTrackPacketsIn[uIP] = pTrackEntry; m_liTrackPacketsIn.Insert(0, pTrackEntry); } else { pTrackEntry = m_mapTrackPacketsIn[uIP]; } // search specific request tracks for (int i = 0; i < pTrackEntry.m_aTrackedRequests.Count; i++) { if (pTrackEntry.m_aTrackedRequests[i].m_byOpcode == byOpcode) { // already tracked requests with theis opcode, remove already expired request counts TrackPacketsIn_Struct.TrackedRequestIn_Struct rCurTrackedRequest = pTrackEntry.m_aTrackedRequests[i]; if (rCurTrackedRequest.m_nCount > 0 && dwCurrentTick - rCurTrackedRequest.m_dwFirstAdded > Opcodes.SEC2MS(iSecondsPerPacket)) { uint nRemoveCount = (dwCurrentTick - rCurTrackedRequest.m_dwFirstAdded) / Opcodes.SEC2MS(iSecondsPerPacket); if (nRemoveCount > rCurTrackedRequest.m_nCount) { rCurTrackedRequest.m_nCount = 0; rCurTrackedRequest.m_dwFirstAdded = dwCurrentTick; // for the packet we just process } else { rCurTrackedRequest.m_nCount -= nRemoveCount; rCurTrackedRequest.m_dwFirstAdded += Opcodes.SEC2MS(iSecondsPerPacket) * nRemoveCount; } } // we increase the counter in any case, even if we drop the packet later rCurTrackedRequest.m_nCount++; // remember only for easier cleanup pTrackEntry.m_dwLastExpire = Math.Max(pTrackEntry.m_dwLastExpire, rCurTrackedRequest.m_dwFirstAdded + Opcodes.SEC2MS(iSecondsPerPacket) * rCurTrackedRequest.m_nCount); if (Kademlia.IsRunningInLANMode() && OtherFunctions.IsLANIP((uint)IPAddress.NetworkToHostOrder(uIP))) // no flood detection in LanMode { return(true); } // now the actualy check if this request is allowed if (rCurTrackedRequest.m_nCount > iAllowedPacketsPerMinute * 5) { // this is so far above the limit that it has to be an intentional flood / misuse in any case // so we take the next higher punishment and ban the IP //DebugLogWarning("Kad: Massive request flood detected for opcode 0x%X (0x%X) from IP %s - Banning IP", byOpcode, byDbgOrgOpcode, ipstr(ntohl(uIP))); //theApp.clientlist.AddBannedClient(IPAddress.NetworkToHostOrder(uIP)); return(false); // drop packet } else if (rCurTrackedRequest.m_nCount > iAllowedPacketsPerMinute) { // over the limit, drop the packet but do nothing else if (!rCurTrackedRequest.m_bDbgLogged) { rCurTrackedRequest.m_bDbgLogged = true; //DebugLog("Kad: Request flood detected for opcode 0x%X (0x%X) from IP %s - Droping packets with this opcode", byOpcode, byDbgOrgOpcode, ipstr(ntohl(uIP))); } return(false); // drop packet } else { rCurTrackedRequest.m_bDbgLogged = false; } return(true); } } // add a new entry for this request, no checks needed since 1 is always ok TrackPacketsIn_Struct.TrackedRequestIn_Struct curTrackedRequest; curTrackedRequest.m_byOpcode = byOpcode; curTrackedRequest.m_bDbgLogged = false; curTrackedRequest.m_dwFirstAdded = dwCurrentTick; curTrackedRequest.m_nCount = 1; // remember only for easier cleanup pTrackEntry.m_dwLastExpire = Math.Max(pTrackEntry.m_dwLastExpire, dwCurrentTick + Opcodes.SEC2MS(iSecondsPerPacket)); pTrackEntry.m_aTrackedRequests.Add(curTrackedRequest); return(true); }