From: Matt Joiner Date: Thu, 14 Aug 2025 02:30:34 +0000 (+1000) Subject: Don't close webseed peers for bad data X-Git-Tag: v1.59.0~2^2~9 X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=4031ab24b007c36944d1b24016147e4ac3d2619d;p=btrtrc.git Don't close webseed peers for bad data --- diff --git a/peer-impl.go b/peer-impl.go index 27be7b06..25fe5a72 100644 --- a/peer-impl.go +++ b/peer-impl.go @@ -31,7 +31,7 @@ type legacyPeerImpl interface { // Drop connection. This may be a no-op if there is no connection. drop() // Rebuke the peer - ban() + providedBadData() String() string // Per peer-impl lines for WriteStatus. peerImplStatusLines() []string diff --git a/peerconn.go b/peerconn.go index 9758cbd2..573ae30e 100644 --- a/peerconn.go +++ b/peerconn.go @@ -1165,7 +1165,7 @@ func (cn *PeerConn) drop() { cn.t.dropConnection(cn) } -func (cn *PeerConn) ban() { +func (cn *PeerConn) providedBadData() { cn.t.cl.banPeerIP(cn.remoteIp()) } diff --git a/smartban.go b/smartban.go index 857ca291..dd7d6662 100644 --- a/smartban.go +++ b/smartban.go @@ -11,6 +11,7 @@ import ( type bannableAddr = netip.Addr +// TODO: Should be keyed on weak[Peer]. type smartBanCache = smartban.Cache[bannableAddr, RequestIndex, uint64] type blockCheckingWriter struct { diff --git a/torrent.go b/torrent.go index 2f6b7b98..d66d51da 100644 --- a/torrent.go +++ b/torrent.go @@ -1232,7 +1232,8 @@ func (t *Torrent) countBytesHashed(n int64) { func (t *Torrent) hashPiece(piece pieceIndex) ( correct bool, - // These are peers that sent us blocks that differ from what we hash here. + // These are peers that sent us blocks that differ from what we hash here. TODO: Track Peer not + // bannable addr for peer types that are rebuked differently. differingPeers map[bannableAddr]struct{}, err error, ) { @@ -2625,7 +2626,7 @@ func (t *Torrent) pieceHashed(piece pieceIndex, passed bool, hashIoErr error) { "piece failed hash. banning peer", "piece", piece, "peer", c) - c.ban() + c.providedBadData() // TODO: Check if we now have no available peers for pieces we want. } } diff --git a/webseed-peer.go b/webseed-peer.go index 19ace314..2ebfd66c 100644 --- a/webseed-peer.go +++ b/webseed-peer.go @@ -23,15 +23,30 @@ import ( type webseedPeer struct { // First field for stats alignment. - peer Peer - logger *slog.Logger - client webseed.Client - activeRequests map[*webseedRequest]struct{} - locker sync.Locker - lastUnhandledErr time.Time - hostKey webseedHostKeyHandle + peer Peer + logger *slog.Logger + client webseed.Client + activeRequests map[*webseedRequest]struct{} + locker sync.Locker + hostKey webseedHostKeyHandle // We need this to look ourselves up in the Client.activeWebseedRequests map. url webseedUrlKey + + // When requests are allowed to resume. If Zero, then anytime. + penanceComplete time.Time + lastCrime error +} + +func (me *webseedPeer) suspended() bool { + return me.lastCrime != nil && time.Now().Before(me.penanceComplete) +} + +func (me *webseedPeer) convict(err error, term time.Duration) { + if me.suspended() { + return + } + me.lastCrime = err + me.penanceComplete = time.Now().Add(term) } func (*webseedPeer) allConnStatsImplField(stats *AllConnStats) *ConnStats { @@ -78,7 +93,12 @@ var _ legacyPeerImpl = (*webseedPeer)(nil) func (me *webseedPeer) peerImplStatusLines() []string { lines := []string{ me.client.Url, - fmt.Sprintf("last unhandled error: %v", eventAgeString(me.lastUnhandledErr)), + } + if me.lastCrime != nil { + lines = append(lines, fmt.Sprintf("last crime: %v", me.lastCrime)) + } + if me.suspended() { + lines = append(lines, fmt.Sprintf("suspended for %v more", time.Until(me.penanceComplete))) } if len(me.activeRequests) > 0 { elems := make([]string, 0, len(me.activeRequests)) @@ -238,8 +258,8 @@ func (ws *webseedPeer) connectionFlags() string { // Maybe this should drop all existing connections, or something like that. func (ws *webseedPeer) drop() {} -func (cn *webseedPeer) ban() { - cn.peer.close() +func (cn *webseedPeer) providedBadData() { + cn.convict(errors.New("provided bad data"), time.Minute) } func (ws *webseedPeer) onClose() { diff --git a/webseed-requesting.go b/webseed-requesting.go index 3bd95f50..4cc9ccb4 100644 --- a/webseed-requesting.go +++ b/webseed-requesting.go @@ -384,6 +384,9 @@ func (cl *Client) iterPossibleWebseedRequests() iter.Seq2[webseedUniqueRequestKe panicif.GreaterThanOrEqual(firstRequest, t.maxEndRequest()) webseedSliceIndex := t.requestIndexToWebseedSliceIndex(firstRequest) for url, ws := range t.webSeeds { + if ws.suspended() { + continue + } // Return value from this function (RequestPieceFunc) doesn't terminate // iteration, so propagate that to not handling the yield return value. if !yield(