master
go 466 lines 16.5 KB
Raw
1 package config
2
3 import (
4 "fmt"
5 "net"
6 "time"
7 )
8
9 // Transformer is a function which takes configuration and applies some filter to it.
10 type Transformer func(c *Config) error
11
12 // Profile contains the profile transformer the description of the profile.
13 type Profile struct {
14 // Description briefly describes the functionality of the profile.
15 Description string
16
17 // Transform takes ipfs configuration and applies the profile to it.
18 Transform Transformer
19
20 // InitOnly specifies that this profile can only be applied on init.
21 InitOnly bool
22 }
23
24 // defaultServerFilters lists IPv4 and IPv6 prefixes that are private,
25 // local-only, or otherwise not "Globally Reachable" per the IANA
26 // Special-Purpose Address Registries (RFC 6890):
27 //
28 // https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
29 // https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
30 //
31 // The `server` profile appends this list to both `Addresses.NoAnnounce`
32 // (strip from self-announce / identify / DHT self-record) and
33 // `Swarm.AddrFilters` (refuse libp2p dial/accept involving these ranges).
34 // See docs/config.md under "`server` profile" for the rendered table with
35 // per-entry RFC references and guidance on optional entries (for example
36 // loopback or IPv6 outside `2000::/3`) that operators may add manually.
37 //
38 // Keep this list stable; changes here affect every `server`-profile user.
39 var defaultServerFilters = []string{
40 "/ip4/10.0.0.0/ipcidr/8", // RFC 1918: private-use
41 "/ip4/100.64.0.0/ipcidr/10", // RFC 6598: shared address space (CGNAT)
42 "/ip4/127.0.0.0/ipcidr/8", // RFC 1122: IPv4 loopback
43 "/ip4/169.254.0.0/ipcidr/16", // RFC 3927: link-local
44 "/ip4/172.16.0.0/ipcidr/12", // RFC 1918: private-use
45 "/ip4/192.0.0.0/ipcidr/24", // RFC 6890: IETF protocol assignments
46 "/ip4/192.0.2.0/ipcidr/24", // RFC 5737: TEST-NET-1 (documentation)
47 "/ip4/192.168.0.0/ipcidr/16", // RFC 1918: private-use
48 "/ip4/198.18.0.0/ipcidr/15", // RFC 2544: benchmarking
49 "/ip4/198.51.100.0/ipcidr/24", // RFC 5737: TEST-NET-2 (documentation)
50 "/ip4/203.0.113.0/ipcidr/24", // RFC 5737: TEST-NET-3 (documentation)
51 "/ip4/240.0.0.0/ipcidr/4", // RFC 1112: reserved (covers broadcast 255.255.255.255)
52 "/ip6/::/ipcidr/3", // RFC 4291 §2.4: IANA-reserved 0000::/3 block (unspecified, loopback, IPv4-mapped, NAT64, and unallocated space where 1e::/16 leaks)
53 "/ip6/::1/ipcidr/128", // RFC 4291 §2.4: IPv6 loopback (subset of `::/3` above; kept for documentation)
54 "/ip6/100::/ipcidr/64", // RFC 6666: discard-only (subset of `::/3` above; kept for documentation)
55 "/ip6/2001:2::/ipcidr/48", // RFC 5180: BMWG benchmarking
56 "/ip6/2001:db8::/ipcidr/32", // RFC 3849: documentation
57 "/ip6/fc00::/ipcidr/7", // RFC 4193: unique local addresses (ULA)
58 "/ip6/fe80::/ipcidr/10", // RFC 4291: link-local unicast
59 }
60
61 // Profiles is a map holding configuration transformers. Docs are in docs/config.md.
62 var Profiles = map[string]Profile{
63 "server": {
64 Description: `Disables local host discovery, recommended when
65 running IPFS on machines with public IPv4 addresses.`,
66
67 Transform: func(c *Config) error {
68 c.Addresses.NoAnnounce = appendSingle(c.Addresses.NoAnnounce, defaultServerFilters)
69 c.Swarm.AddrFilters = appendSingle(c.Swarm.AddrFilters, defaultServerFilters)
70 c.Discovery.MDNS.Enabled = false
71 c.Swarm.DisableNatPortMap = true
72 return nil
73 },
74 },
75
76 "local-discovery": {
77 Description: `Sets default values to fields affected by the server
78 profile, enables discovery in local networks.`,
79
80 Transform: func(c *Config) error {
81 c.Addresses.NoAnnounce = deleteEntries(c.Addresses.NoAnnounce, defaultServerFilters)
82 c.Swarm.AddrFilters = deleteEntries(c.Swarm.AddrFilters, defaultServerFilters)
83 c.Discovery.MDNS.Enabled = true
84 c.Swarm.DisableNatPortMap = false
85 return nil
86 },
87 },
88 "test": {
89 Description: `Reduces external interference of IPFS daemon, this
90 is useful when using the daemon in test environments.`,
91
92 Transform: func(c *Config) error {
93 c.Addresses.API = Strings{"/ip4/127.0.0.1/tcp/0"}
94 c.Addresses.Gateway = Strings{"/ip4/127.0.0.1/tcp/0"}
95 c.Addresses.Swarm = []string{
96 "/ip4/127.0.0.1/tcp/0",
97 }
98
99 c.Swarm.DisableNatPortMap = true
100 c.Routing.LoopbackAddressesOnLanDHT = True
101
102 c.Bootstrap = []string{}
103 c.Discovery.MDNS.Enabled = false
104 c.AutoTLS.Enabled = False
105 c.AutoConf.Enabled = False
106
107 // Explicitly set autoconf-controlled fields to empty when autoconf is disabled
108 c.DNS.Resolvers = map[string]string{}
109 c.Routing.DelegatedRouters = []string{}
110 c.Ipns.DelegatedPublishers = []string{}
111 return nil
112 },
113 },
114 "default-networking": {
115 Description: `Restores default network settings.
116 Inverse profile of the test profile.`,
117
118 Transform: func(c *Config) error {
119 c.Addresses = addressesConfig()
120
121 // Use AutoConf system for bootstrap peers
122 c.Bootstrap = []string{AutoPlaceholder}
123 c.AutoConf.Enabled = Default
124 c.AutoConf.URL = nil // Clear URL to use implicit default
125
126 c.Swarm.DisableNatPortMap = false
127 c.Discovery.MDNS.Enabled = true
128 c.AutoTLS.Enabled = Default
129 return nil
130 },
131 },
132 "default-datastore": {
133 Description: `Configures the node to use the default datastore (flatfs).
134
135 Read the "flatfs" profile description for more information on this datastore.
136
137 This profile may only be applied when first initializing the node.
138 `,
139
140 InitOnly: true,
141 Transform: func(c *Config) error {
142 c.Datastore.Spec = flatfsSpec()
143 return nil
144 },
145 },
146 "flatfs": {
147 Description: `Configures the node to use the flatfs datastore.
148
149 This is the most battle-tested and reliable datastore.
150 You should use this datastore if:
151
152 * You need a very simple and very reliable datastore, and you trust your
153 filesystem. This datastore stores each block as a separate file in the
154 underlying filesystem so it's unlikely to loose data unless there's an issue
155 with the underlying file system.
156 * You need to run garbage collection in a way that reclaims free space as soon as possible.
157 * You want to minimize memory usage.
158 * You are ok with the default speed of data import, or prefer to use --nocopy.
159
160 See configuration documentation at:
161 https://github.com/ipfs/kubo/blob/master/docs/datastores.md#flatfs
162
163 NOTE: This profile may only be applied when first initializing node at IPFS_PATH
164 via 'ipfs init --profile flatfs'
165 `,
166
167 InitOnly: true,
168 Transform: func(c *Config) error {
169 c.Datastore.Spec = flatfsSpec()
170 return nil
171 },
172 },
173 "flatfs-measure": {
174 Description: `Configures the node to use the flatfs datastore with metrics tracking wrapper.
175 Additional '*_datastore_*' metrics will be exposed on /debug/metrics/prometheus
176
177 NOTE: This profile may only be applied when first initializing node at IPFS_PATH
178 via 'ipfs init --profile flatfs-measure'
179 `,
180
181 InitOnly: true,
182 Transform: func(c *Config) error {
183 c.Datastore.Spec = flatfsSpecMeasure()
184 return nil
185 },
186 },
187 "pebbleds": {
188 Description: `Configures the node to use the pebble high-performance datastore.
189
190 Pebble is a LevelDB/RocksDB inspired key-value store focused on performance
191 and internal usage by CockroachDB.
192 You should use this datastore if:
193
194 - You need a datastore that is focused on performance.
195 - You need reliability by default, but may choose to disable WAL for maximum performance when reliability is not critical.
196 - This datastore is good for multi-terabyte data sets.
197 - May benefit from tuning depending on read/write patterns and throughput.
198 - Performance is helped significantly by running on a system with plenty of memory.
199
200 See configuration documentation at:
201 https://github.com/ipfs/kubo/blob/master/docs/datastores.md#pebbleds
202
203 NOTE: This profile may only be applied when first initializing node at IPFS_PATH
204 via 'ipfs init --profile pebbleds'
205 `,
206
207 InitOnly: true,
208 Transform: func(c *Config) error {
209 c.Datastore.Spec = pebbleSpec()
210 return nil
211 },
212 },
213 "pebbleds-measure": {
214 Description: `Configures the node to use the pebble datastore with metrics tracking wrapper.
215 Additional '*_datastore_*' metrics will be exposed on /debug/metrics/prometheus
216
217 NOTE: This profile may only be applied when first initializing node at IPFS_PATH
218 via 'ipfs init --profile pebbleds-measure'
219 `,
220
221 InitOnly: true,
222 Transform: func(c *Config) error {
223 c.Datastore.Spec = pebbleSpecMeasure()
224 return nil
225 },
226 },
227 "badgerds": {
228 Description: `DEPRECATED: Configures the node to use the legacy badgerv1 datastore.
229 This profile will be removed in a future Kubo release.
230 New deployments should use 'flatfs' or 'pebbleds' instead.
231
232 NOTE: this is badger 1.x, which has known bugs and is no longer supported by the upstream team.
233 It is provided here only for pre-existing users, allowing them to migrate away to more modern datastore.
234
235 Other caveats:
236
237 * This datastore will not properly reclaim space when your datastore is
238 smaller than several gigabytes. If you run IPFS with --enable-gc, you plan
239 on storing very little data in your IPFS node, and disk usage is more
240 critical than performance, consider using flatfs.
241 * This datastore uses up to several gigabytes of memory.
242 * Good for medium-size datastores, but may run into performance issues
243 if your dataset is bigger than a terabyte.
244
245 To migrate: create a new IPFS_PATH with 'ipfs init --profile=flatfs',
246 move pinned data via 'ipfs dag export/import' or 'ipfs pin ls -t recursive|add',
247 and decommission the old badger-based node.
248 When it comes to block storage, use experimental 'pebbleds' only if you are sure
249 modern 'flatfs' does not serve your use case (most users will be perfectly fine
250 with flatfs, it is also possible to keep flatfs for blocks and replace leveldb
251 with pebble if preferred over leveldb).
252
253 See configuration documentation at:
254 https://github.com/ipfs/kubo/blob/master/docs/datastores.md#badgerds
255
256 NOTE: This profile may only be applied when first initializing node at IPFS_PATH
257 via 'ipfs init --profile badgerds'
258 `,
259
260 InitOnly: true,
261 Transform: func(c *Config) error {
262 c.Datastore.Spec = badgerSpec()
263 return nil
264 },
265 },
266 "badgerds-measure": {
267 Description: `DEPRECATED: Configures the node to use the legacy badgerv1 datastore with metrics wrapper.
268 This profile will be removed in a future Kubo release.
269 New deployments should use 'flatfs' or 'pebbleds' instead.
270
271 NOTE: This profile may only be applied when first initializing node at IPFS_PATH
272 via 'ipfs init --profile badgerds-measure'
273 `,
274
275 InitOnly: true,
276 Transform: func(c *Config) error {
277 c.Datastore.Spec = badgerSpecMeasure()
278 return nil
279 },
280 },
281 "lowpower": {
282 Description: `Reduces daemon overhead on the system. May affect node
283 functionality - performance of content discovery and data
284 fetching may be degraded.
285 `,
286 Transform: func(c *Config) error {
287 // Disable "server" services (dht, autonat, limited relay)
288 c.Routing.Type = NewOptionalString("autoclient")
289 c.AutoNAT.ServiceMode = AutoNATServiceDisabled
290 c.Swarm.RelayService.Enabled = False
291
292 // Keep bare minimum connections around
293 lowWater := int64(20)
294 highWater := int64(40)
295 gracePeriod := time.Minute
296 c.Swarm.ConnMgr.Type = NewOptionalString("basic")
297 c.Swarm.ConnMgr.LowWater = &OptionalInteger{value: &lowWater}
298 c.Swarm.ConnMgr.HighWater = &OptionalInteger{value: &highWater}
299 c.Swarm.ConnMgr.GracePeriod = &OptionalDuration{&gracePeriod}
300 return nil
301 },
302 },
303 "announce-off": {
304 Description: `Disables Provide system (announcing to Amino DHT).
305
306 USE WITH CAUTION:
307 The main use case for this is setups with manual Peering.Peers config.
308 Data from this node will not be announced on the DHT. This will make
309 DHT-based routing and data retrieval impossible if this node is the only
310 one hosting it, and other peers are not already connected to it.
311 `,
312 Transform: func(c *Config) error {
313 c.Provide.Enabled = False
314 c.Provide.DHT.Interval = NewOptionalDuration(0) // 0 disables periodic reprovide
315 return nil
316 },
317 },
318 "announce-on": {
319 Description: `Re-enables Provide system (reverts announce-off profile).`,
320 Transform: func(c *Config) error {
321 c.Provide.Enabled = True
322 c.Provide.DHT.Interval = NewOptionalDuration(DefaultProvideDHTInterval) // have to apply explicit default because nil would be ignored
323 return nil
324 },
325 },
326 "randomports": {
327 Description: `Use a random port number for swarm.`,
328
329 Transform: func(c *Config) error {
330 port, err := getAvailablePort()
331 if err != nil {
332 return err
333 }
334 c.Addresses.Swarm = []string{
335 fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", port),
336 fmt.Sprintf("/ip6/::/tcp/%d", port),
337 }
338 return nil
339 },
340 },
341 "unixfs-v0-2015": {
342 Description: `Legacy UnixFS import profile for backward-compatible CID generation.
343 Produces CIDv0 with no raw leaves, sha2-256, 256 KiB chunks, and
344 link-based HAMT size estimation. Use only when legacy CIDs are required.
345 See https://specs.ipfs.tech/ipips/ipip-0499/. Alias: legacy-cid-v0`,
346 Transform: applyUnixFSv02015,
347 },
348 "legacy-cid-v0": {
349 Description: `Alias for unixfs-v0-2015 profile.`,
350 Transform: applyUnixFSv02015,
351 },
352 "unixfs-v1-2025": {
353 Description: `Recommended UnixFS import profile for cross-implementation CID determinism.
354 Uses CIDv1, raw leaves, sha2-256, 1 MiB chunks, 1024 links per file node,
355 256 HAMT fanout, and block-based size estimation for HAMT threshold.
356 See https://specs.ipfs.tech/ipips/ipip-0499/`,
357 Transform: func(c *Config) error {
358 c.Import.CidVersion = *NewOptionalInteger(1)
359 c.Import.UnixFSRawLeaves = True
360 c.Import.UnixFSChunker = *NewOptionalString("size-1048576") // 1 MiB
361 c.Import.HashFunction = *NewOptionalString("sha2-256")
362 c.Import.UnixFSFileMaxLinks = *NewOptionalInteger(1024)
363 c.Import.UnixFSDirectoryMaxLinks = *NewOptionalInteger(0)
364 c.Import.UnixFSHAMTDirectoryMaxFanout = *NewOptionalInteger(256)
365 c.Import.UnixFSHAMTDirectorySizeThreshold = *NewOptionalBytes("256KiB")
366 c.Import.UnixFSHAMTDirectorySizeEstimation = *NewOptionalString(HAMTSizeEstimationBlock)
367 c.Import.UnixFSDAGLayout = *NewOptionalString(DAGLayoutBalanced)
368 return nil
369 },
370 },
371 "autoconf-on": {
372 Description: `Sets configuration to use implicit defaults from remote autoconf service.
373 Bootstrap peers, DNS resolvers, delegated routers, and IPNS delegated publishers are set to "auto".
374 This profile requires AutoConf to be enabled and configured.`,
375
376 Transform: func(c *Config) error {
377 c.Bootstrap = []string{AutoPlaceholder}
378 c.DNS.Resolvers = map[string]string{
379 ".": AutoPlaceholder,
380 }
381 c.Routing.DelegatedRouters = []string{AutoPlaceholder}
382 c.Ipns.DelegatedPublishers = []string{AutoPlaceholder}
383 c.AutoConf.Enabled = True
384 if c.AutoConf.URL == nil {
385 c.AutoConf.URL = NewOptionalString(DefaultAutoConfURL)
386 }
387 return nil
388 },
389 },
390 "autoconf-off": {
391 Description: `Disables AutoConf and sets networking fields to empty for manual configuration.
392 Bootstrap peers, DNS resolvers, delegated routers, and IPNS delegated publishers are set to empty.
393 Use this when you want normal networking but prefer manual control over all endpoints.`,
394
395 Transform: func(c *Config) error {
396 c.Bootstrap = nil
397 c.DNS.Resolvers = nil
398 c.Routing.DelegatedRouters = nil
399 c.Ipns.DelegatedPublishers = nil
400 c.AutoConf.Enabled = False
401 return nil
402 },
403 },
404 }
405
406 func getAvailablePort() (port int, err error) {
407 ln, err := net.Listen("tcp", "[::]:0")
408 if err != nil {
409 return 0, err
410 }
411 defer ln.Close()
412 port = ln.Addr().(*net.TCPAddr).Port
413 return port, nil
414 }
415
416 func appendSingle(a []string, b []string) []string {
417 out := make([]string, 0, len(a)+len(b))
418 m := map[string]bool{}
419 for _, f := range a {
420 if !m[f] {
421 out = append(out, f)
422 }
423 m[f] = true
424 }
425 for _, f := range b {
426 if !m[f] {
427 out = append(out, f)
428 }
429 m[f] = true
430 }
431 return out
432 }
433
434 func deleteEntries(arr []string, del []string) []string {
435 m := map[string]struct{}{}
436 for _, f := range arr {
437 m[f] = struct{}{}
438 }
439 for _, f := range del {
440 delete(m, f)
441 }
442 return mapKeys(m)
443 }
444
445 func mapKeys(m map[string]struct{}) []string {
446 out := make([]string, 0, len(m))
447 for f := range m {
448 out = append(out, f)
449 }
450 return out
451 }
452
453 // applyUnixFSv02015 applies the legacy UnixFS v0 (2015) import settings.
454 func applyUnixFSv02015(c *Config) error {
455 c.Import.CidVersion = *NewOptionalInteger(0)
456 c.Import.UnixFSRawLeaves = False
457 c.Import.UnixFSChunker = *NewOptionalString("size-262144") // 256 KiB
458 c.Import.HashFunction = *NewOptionalString("sha2-256")
459 c.Import.UnixFSFileMaxLinks = *NewOptionalInteger(174)
460 c.Import.UnixFSDirectoryMaxLinks = *NewOptionalInteger(0)
461 c.Import.UnixFSHAMTDirectoryMaxFanout = *NewOptionalInteger(256)
462 c.Import.UnixFSHAMTDirectorySizeThreshold = *NewOptionalBytes("256KiB")
463 c.Import.UnixFSHAMTDirectorySizeEstimation = *NewOptionalString(HAMTSizeEstimationLinks)
464 c.Import.UnixFSDAGLayout = *NewOptionalString(DAGLayoutBalanced)
465 return nil
466 }