Skip to content

Commit fb879c5

Browse files
lidelguillaumemichelgammazero
authored
fix(routing): defensive nil checks for multiaddr handling (#1081)
* fix(routing): defensive nil checks for multiaddr handling Belt-and-suspenders defense against corrupted address data: - types/ipfs.go: Multiaddr.MarshalJSON returns null for nil - contentrouter: filters nil addresses when building AddrInfo Should help with ipfs/kubo#11116 * refactor(routing): extract filterAddrs helper, extend nil protection - extract filterAddrs() to deduplicate nil-filtering logic - preallocate slice per review feedback - extend nil multiaddr protection to FindPeer and GetClosestPeers - update test to expect empty slices instead of nil addresses review feedback on #1081 * fix(routing): preserve nil semantics in filterAddrs return nil instead of empty slice when input is empty or all entries are filtered out, maintaining original behavior for AddrInfo.Addrs --------- Co-authored-by: Guillaume Michel <[email protected]> Co-authored-by: Andrew Gillis <[email protected]>
1 parent f42859f commit fb879c5

File tree

2 files changed

+33
-22
lines changed

2 files changed

+33
-22
lines changed

routing/http/contentrouter/contentrouter.go

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,25 @@ import (
2121

2222
var logger = logging.Logger("routing/http/contentrouter")
2323

24+
// filterAddrs extracts multiaddrs from types.Multiaddr slice, filtering out nil
25+
// entries as a defensive measure against corrupted data.
26+
// See: https://github.com/ipfs/kubo/issues/11116
27+
func filterAddrs(in []types.Multiaddr) []multiaddr.Multiaddr {
28+
if len(in) == 0 {
29+
return nil
30+
}
31+
out := make([]multiaddr.Multiaddr, 0, len(in))
32+
for _, a := range in {
33+
if a.Multiaddr != nil {
34+
out = append(out, a.Multiaddr)
35+
}
36+
}
37+
if len(out) == 0 {
38+
return nil
39+
}
40+
return out
41+
}
42+
2443
const ttl = 24 * time.Hour
2544

2645
// A Client provides HTTP Delegated Routing methods. See also [server.DelegatedRouter].
@@ -147,17 +166,12 @@ func readProviderResponses(ctx context.Context, iter iter.ResultIter[types.Recor
147166
continue
148167
}
149168

150-
var addrs []multiaddr.Multiaddr
151-
for _, a := range result.Addrs {
152-
addrs = append(addrs, a.Multiaddr)
153-
}
154-
155169
select {
156170
case <-ctx.Done():
157171
return
158172
case ch <- peer.AddrInfo{
159173
ID: *result.ID,
160-
Addrs: addrs,
174+
Addrs: filterAddrs(result.Addrs),
161175
}:
162176
}
163177

@@ -175,17 +189,12 @@ func readProviderResponses(ctx context.Context, iter iter.ResultIter[types.Recor
175189
continue
176190
}
177191

178-
var addrs []multiaddr.Multiaddr
179-
for _, a := range result.Addrs {
180-
addrs = append(addrs, a.Multiaddr)
181-
}
182-
183192
select {
184193
case <-ctx.Done():
185194
return
186195
case ch <- peer.AddrInfo{
187196
ID: *result.ID,
188-
Addrs: addrs,
197+
Addrs: filterAddrs(result.Addrs),
189198
}:
190199
}
191200
}
@@ -224,11 +233,7 @@ func (c *contentRouter) FindPeer(ctx context.Context, pid peer.ID) (peer.AddrInf
224233
continue
225234
}
226235

227-
var addrs []multiaddr.Multiaddr
228-
for _, a := range res.Val.Addrs {
229-
addrs = append(addrs, a.Multiaddr)
230-
}
231-
236+
addrs := filterAddrs(res.Val.Addrs)
232237
// If there are no addresses there's nothing of value to return
233238
if len(addrs) == 0 {
234239
continue
@@ -327,11 +332,7 @@ func (c *contentRouter) GetClosestPeers(ctx context.Context, key cid.Cid) (<-cha
327332
continue
328333
}
329334

330-
var addrs []multiaddr.Multiaddr
331-
for _, a := range res.Val.Addrs {
332-
addrs = append(addrs, a.Multiaddr)
333-
}
334-
335+
addrs := filterAddrs(res.Val.Addrs)
335336
// If there are no addresses there's nothing of value to return
336337
if len(addrs) == 0 {
337338
continue

routing/http/types/ipfs.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ func (c *CID) UnmarshalJSON(b []byte) error {
2727

2828
type Multiaddr struct{ multiaddr.Multiaddr }
2929

30+
// MarshalJSON returns null for nil Multiaddr as a defensive measure.
31+
// This prevents panics if corrupted data contains nil addresses.
32+
// See: https://github.com/ipfs/kubo/issues/11116
33+
func (m Multiaddr) MarshalJSON() ([]byte, error) {
34+
if m.Multiaddr == nil {
35+
return []byte("null"), nil
36+
}
37+
return json.Marshal(m.Multiaddr.String())
38+
}
39+
3040
func (m *Multiaddr) UnmarshalJSON(b []byte) error {
3141
var s string
3242
err := json.Unmarshal(b, &s)

0 commit comments

Comments
 (0)