v0.42.0
Note
This release was brought to you by the Shipyard team.
What's Changed
Added
namesys: DNSLink lookups now return the DNS TXT record's TTL, and the gateway uses it asCache-Control: max-agefor/ipns/<dnslink-host>responses. Clients cache a DNSLink website for exactly as long as its DNS record allows and fetch updates once it expires, instead of relying on a static default. #329- Requires a resolver that reports TTLs, such as DNS-over-HTTPS via
go-doh-resolverv0.6.0. The OS resolver cannot report TTLs: Go's standard librarynet.Resolverreturns only record values, and libp2p's default DNS wiring (madns.DefaultResolver) wraps it, so domains it serves keep the old behavior. In Kubo, aDNS.Resolversentry for.covers all domains. WithDNSResolverdetects TTL support automatically.NewDNSResolverWithTTL,WithDNSResolverWithTTL, andLookupTXTWithTTLFunctake a TTL-aware lookup directly.NewDNSResolverandLookupTXTFuncare unchanged and report an unknown TTL (0).
- Requires a resolver that reports TTLs, such as DNS-over-HTTPS via
gateway:GET/HEAD /ipfs/bafkqaaa?format=rawnow always returns200with an empty body, so probing clients keep marking the gateway as functional even when its backend cannot serve identity CIDs.bitswap/network/httpnetsends this trustless gateway probe to check providers, and a failed probe drops the provider. Exported asgateway.EmptyIdentityCID. #1179path: addedNewPathFromURI, which accepts native IPFS URIs (ipfs://cid,ipns://name,ipld://cid, and the schemelessipfs:/ipns:/ipld:forms) and rewrites them to canonical content paths, so values copied from browsers and other tools parse as-is.NewPathstays strict and still rejects URI-shaped input, leaving untrusted parsing such as DNSLink records unchanged. #1182blockstore:CachedBlockstorenow returns a value implementing the exportedBloomCacheStatusinterface (Wait/BloomActive/Rebuild) when a Bloom filter is configured, so callers can wait for and observe the result of the asynchronous filter build (previously these methods were unreachable on the unexported cache type), and retry a failed build withRebuild. While a rebuild runs the filter is inactive (lookups fall through to the underlying blockstore, so results stay correct but unaccelerated) and it is activated again only on a complete enumeration. A new optionalAllKeysChanWithErrercapability lets aBlockstorereport an error that truncatesAllKeysChanenumeration. #1184mfs: addedWithFetchTimeout, a time limit on how long MFS waits when it has to fetch part of a tree from the network. MFS can hold a tree whose contents are pulled in on demand, for example a reference made withipfs files cp /ipfs/<cid>. If a needed part is unavailable, MFS would otherwise wait for it forever, freezing every MFS operation and blocking a clean shutdown; with a timeout the wait ends in an error instead. On by default at a generousDefaultFetchTimeout(5 minutes) that only affects unreachable data; passWithFetchTimeout(0)to disable. #1185
Changed
namesys: a name that resolves through several hops (a DNSLink pointing at an IPNS name, or an IPNS chain) now uses the shortest TTL among them, so an update to any link in the chain reaches clients on time. Hops with an unknown TTL (0) are ignored; single-hop results are unchanged. #329namesys: TTLs in results now respect the operator's cap.WithMaxCacheTTL(in Kubo:Ipns.MaxCacheTTL) bounds the reported TTL, soCache-Control: max-agenever promises freshness past it. Cached results report their remaining lifetime instead of the original TTL, so a late cache hit no longer restarts the full caching period on clients. A cap of 0 still means "no local cache" and leaves the reported TTL alone. #329- upgrade to
go-multiaddr-dnsv0.6.0 andgo-doh-resolverv0.6.0, which add DNS TXT TTL reporting and turn on the DNSLinkCache-Controlbehavior above for DoH-backed setups. - 🛠
mfs:File.Opennow takes acontext.Context. Writing to a file whose data has to be fetched from the network (for example, a lazy reference created withipfs files cp) now uses that context, so the write stops when the context is cancelled, such as on a client timeout or when MFS shuts down, instead of waiting forever for a block that never arrives. Callers must add a context argument; pass the request's context to let a timeout cancel the write. #1185 - 🧪
testing: tests now usego-testv0.4.0 andmath/rand/v2.go-test/randomno longer has a global seed or a global sequence, so one test can no longer change the values another test expects to generate deterministically, a class of failure that showed up as an intermittent break in an unrelated test. A generator can also be reused now, instead of being rebuilt for every value. #1187 - 🛠
routing/offline: the offline router now stores value records in the same datastore layout as the go-libp2p-kad-dht value store (v0.42.0+), so a node sharing one datastore between the offline router and a DHT resolves records offline that were published online and vice versa. That interop previously relied on both sides coincidentally using the same key derivation, which the kad-dht v0.42.0 layout change broke. Records written in the old layout (root-level base32 keys) are no longer read;GetValuealso returnsrouting.ErrNotFoundinstead of leakingdatastore.ErrNotFoundfor missing records, and re-validates stored records on read so expired records (e.g. IPNS past its EOL) are no longer returned. By default a stored record is served until it stops being valid (for IPNS, its EOL), unchanged from before; the newWithMaxRecordAgeoption adds an optional store-age cap. Retention also depends on what else uses the datastore: when ago-libp2p-kad-dhtinstance shares it (viadht.ValueDatastore), that DHT's value store drops records older thanamino.DefaultMaxRecordAgeon read and sweeps them in the background, regardless of this router's setting. So a node that also runs a DHT follows the DHT's age cap, while an offline-only node keeps records until their EOL. #1189 - upgrade to
go-libp2p-kad-dhtv0.42.1, which includes a local record validation fix #1189 - upgrade to
go-unixfsnodev1.10.5 - upgrade to
go-cidv0.6.2 - upgrade to
go-libp2pv0.48.1-0.20260709142922-ec408fcc60c9 to get security and other fixes.
Removed
- 🛠
util: removed the deprecatedNewSeededRandandNewTimeSeededRand. Usego-test/randominstead. #1187 - Remove dependency on
whyrusleeping/base32so that boxo only depends on one base32 package,multiformats/go-base32.
Fixed
namesys: a custom sequence number of 0 is now rejected withErrInvalidSequencealso when the name has no existing record, matching the documented behavior that an explicitly supplied sequence must be at least 1.gateway:304 Not Modifiedresponses toIf-None-MatchandIf-Modified-Sincenow carryEtagand theCache-Controltheir200counterpart sends, so a client cache renews its freshness window when it revalidates. A bare 304 left the stored response expired, forcing a revalidation round-trip on every request after the first expiry even when the gateway had just confirmed the content is unchanged. Together with the DNSLink TTL work above, this addresses #329 for web content; CAR and IPNS-record downloads keep their format-specificEtaghandling.gateway: fixed a data race in the remote blockstore, CAR fetcher, and value store. Each picked a gateway URL out of its list using a per-instance*rand.Rand, which is not safe to use from more than one goroutine, so a gateway serving requests in parallel was racing on every request. They now use the top-levelmath/rand/v2functions, which are safe to share. #1187blockstore: the Bloom filter cache no longer activates after an incomplete build. Previously, ifAllKeysChanenumeration was truncated by a mid-iteration datastore error (which was only logged, never propagated) or by a cancelled context, the cache treated the closed channel as a complete build and activated a Bloom filter holding only a subset of the stored CIDs. It then answered "not present" conclusively for blocks that exist but were never indexed, reporting present blocks as missing (Hasreturns false,Get/GetSize/Viewreturn not-found,DeleteBlockbecomes a silent no-op). The build now activates the filter only when enumeration is known to have completed; otherwise it records the error (observable viaBloomCacheStatus.Wait) and the cache degrades to correct pass-through. This also fixes a race where a cancelled build could still mark the filter active. #1183
Security
go-libp2pupdate contains security enhancements for DoS/hardening- 3501 bounds protocols accepted per peer in identify (a peer could plant 1800+ protocol entries in your peerstore via chunked identify)
- 3486 caps unconnected addrs per peer (stops DHT gossip flooding the peerstore with stale addrs; relevant to us)
- 3500 caps webrtc remote addrs per ufrag
- 3487 evicts stale certified addrs when a newer signed peer record drops them (an address a peer once advertised no longer lingers after removal)
Full Changelog: v0.41.0...v0.42.0
