Skip to content

Commit

Permalink
plugin: Add support for content blocking in Kubo
Browse files Browse the repository at this point in the history
Fixes #8492.

This introduces "nopfs" as a preloaded plugin into Kubo.

It automatically make Kubo watch *.deny files found in:

- /etc/ipfs/denylists
- $XDG_CONFIG_HOME/ipfs/denylists
- $IPFS_PATH/denylists

(files need to be present before boot in order to be watched).

Debug logging can be enabled with `GOLOG_LOG_LEVEL="nopfs=debug"`.

All blocks are logged to "nopfs-blocks", so logging requests for blocked
content can be achieved with
`GOLOG_LOG_LEVEL="nopfs-blocks=warn"`:

```
WARN (...) QmRFniDxwxoG2n4AcnGhRdjqDjCM5YeUcBE75K8WXmioH3: blocked (test.deny:9)
```

Interactive/gateway users will also receive errors as responses but with less details:

```
Error: /ipfs/QmQvjk82hPkSaZsyJ8vNER5cmzKW7HyGX5XVusK7EAenCN is blocked and cannot be provided
```

One particularity to keep in mind is that GetMany() will silently drop blocked
blocks from the response (a warnings are logged). AddMany() will act
similarly and avoid adding blocked blocks.

The code implementing all this is actually in nopfs:

- https://github.com/ipfs-shipyard/nopfs (main library)
- https://github.com/ipfs-shipyard/nopfs/tree/master/ipfs (wrappers)

The interpretation of the list rules and block detection is well tested, but a
general review might be in order.
  • Loading branch information
hsanjuan committed Oct 3, 2023
1 parent 9752747 commit d09c1f9
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 0 deletions.
6 changes: 6 additions & 0 deletions docs/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ The above will replace implicit HTTP routers with single one, allowing for
inspection/debug of HTTP requests sent by Kubo via `while true ; do nc -l 7423; done`
or more advanced tools like [mitmproxy](https://docs.mitmproxy.org/stable/#mitmproxy).


## `IPFS_CONTENT_BLOCKING_DISABLE`

Disables the content-blocking subsystem. No denylists will be watched and no
content will be blocked.

## `LIBP2P_TCP_REUSEPORT`

Kubo tries to reuse the same source port for all connections to improve NAT
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ require (
github.com/fsnotify/fsnotify v1.6.0
github.com/google/uuid v1.3.0
github.com/hashicorp/go-multierror v1.1.1
github.com/ipfs-shipyard/nopfs v0.0.11
github.com/ipfs-shipyard/nopfs/ipfs v0.13.1-4
github.com/ipfs/boxo v0.13.2-0.20231002142647-c28c847582f0
github.com/ipfs/go-block-format v0.1.2
github.com/ipfs/go-cid v0.4.1
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,10 @@ github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY=
github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/ipfs-shipyard/nopfs v0.0.11 h1:+JrOqVs4Za0eu4jntdAqxoWolWcmtJnTQXxn2Y/Io2E=
github.com/ipfs-shipyard/nopfs v0.0.11/go.mod h1:zCmxRNQBYwTRYemK6zcKBGLKN9DkDJYNzmNMqw9GtIA=
github.com/ipfs-shipyard/nopfs/ipfs v0.13.1-4 h1:r4bv6eGurmJie8pmmqxcyogYRpajEUPp2p6z9udCl2o=
github.com/ipfs-shipyard/nopfs/ipfs v0.13.1-4/go.mod h1:9IaQXXcza109YjbOJeUCc7Ha9+GWDlBX4wx6BZkNTDE=
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
github.com/ipfs/boxo v0.13.2-0.20231002142647-c28c847582f0 h1:oss04OCg1/QW0h3OfSCZJiUQErpYPOsz7+X4tpgwODs=
Expand Down
2 changes: 2 additions & 0 deletions plugin/loader/preload.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
pluginfxtest "github.com/ipfs/kubo/plugin/plugins/fxtest"
pluginipldgit "github.com/ipfs/kubo/plugin/plugins/git"
pluginlevelds "github.com/ipfs/kubo/plugin/plugins/levelds"
pluginnopfs "github.com/ipfs/kubo/plugin/plugins/nopfs"
pluginpeerlog "github.com/ipfs/kubo/plugin/plugins/peerlog"
)

Expand All @@ -22,4 +23,5 @@ func init() {
Preload(pluginlevelds.Plugins...)
Preload(pluginpeerlog.Plugins...)
Preload(pluginfxtest.Plugins...)
Preload(pluginnopfs.Plugins...)
}
1 change: 1 addition & 0 deletions plugin/loader/preload_list
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ flatfs github.com/ipfs/kubo/plugin/plugins/flatfs *
levelds github.com/ipfs/kubo/plugin/plugins/levelds *
peerlog github.com/ipfs/kubo/plugin/plugins/peerlog *
fxtest github.com/ipfs/kubo/plugin/plugins/fxtest *
nopfs github.com/ipfs/kubo/plugin/plugins/nopfs *
83 changes: 83 additions & 0 deletions plugin/plugins/nopfs/nopfs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package nopfs

import (
"os"
"path/filepath"

"github.com/ipfs-shipyard/nopfs"
"github.com/ipfs-shipyard/nopfs/ipfs"
"github.com/ipfs/kubo/config"
"github.com/ipfs/kubo/core"
"github.com/ipfs/kubo/core/node"
"github.com/ipfs/kubo/plugin"
"go.uber.org/fx"
)

// Plugins sets the list of plugins to be loaded.
var Plugins = []plugin.Plugin{
&nopfsPlugin{},
}

// fxtestPlugin is used for testing the fx plugin.
// It merely adds an fx option that logs a debug statement, so we can verify that it works in tests.
type nopfsPlugin struct{}

var _ plugin.PluginFx = (*nopfsPlugin)(nil)

func (p *nopfsPlugin) Name() string {
return "nopfs"
}

func (p *nopfsPlugin) Version() string {
return "0.0.10"
}

func (p *nopfsPlugin) Init(env *plugin.Environment) error {
return nil
}

// MakeBlocker is a factory for the blocker so that it can be provided with Fx.
func MakeBlocker() (*nopfs.Blocker, error) {
ipfsPath, err := config.PathRoot()
if err != nil {
return nil, err
}

defaultFiles, err := nopfs.GetDenylistFiles()
if err != nil {
return nil, err
}

kuboFiles, err := nopfs.GetDenylistFilesInDir(filepath.Join(ipfsPath, "denylists"))
if err != nil {
return nil, err
}

files := append(defaultFiles, kuboFiles...)

return nopfs.NewBlocker(files)
}

// PathResolvers returns wrapped PathResolvers for Kubo.
func PathResolvers(fetchers node.FetchersIn, blocker *nopfs.Blocker) node.PathResolversOut {
res := node.PathResolverConfig(fetchers)
return node.PathResolversOut{
IPLDPathResolver: ipfs.WrapResolver(res.IPLDPathResolver, blocker),
UnixFSPathResolver: ipfs.WrapResolver(res.UnixFSPathResolver, blocker),
}
}

func (p *nopfsPlugin) Options(info core.FXNodeInfo) ([]fx.Option, error) {
if os.Getenv("IPFS_CONTENT_BLOCKING_DISABLE") != "" {
return info.FXOptions, nil
}

opts := append(
info.FXOptions,
fx.Provide(MakeBlocker),
fx.Decorate(ipfs.WrapBlockService),
fx.Decorate(ipfs.WrapNameSystem),
fx.Decorate(PathResolvers),
)
return opts, nil
}

0 comments on commit d09c1f9

Please sign in to comment.