add in basic address dial filtering
License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com>
Jeromy committed
Jun 16, 2015 at 11:06 UTC
e01f8e4f22a929b69daaaadeda730dc6f3d05d5d
8 files changed
+115
-6
Godeps/Godeps.json
+4
@@ -239,6 +239,10 @@
239
"ImportPath": "github.com/whyrusleeping/iptb",
240
"Rev": "3970c95a864f1a40037f796ff596607ce8ae43be"
241
},
242
+ {
243
+ "ImportPath": "github.com/whyrusleeping/multiaddr-filter",
244
+ "Rev": "15837fcc356fddef27c634b0f6379b3b7f259114"
245
+ },
246
{
247
"ImportPath": "golang.org/x/crypto/blowfish",
248
"Rev": "c84e1f8e3a7e322d497cd16c0e8a13c7e127baf3"
Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/mask.go
new
+19
@@ -0,0 +1,19 @@
1
+package mask
2
+
3
+import (
4
+ "errors"
5
+ "net"
6
+ "strings"
7
+)
8
+
9
+func NewMask(a string) (*net.IPNet, error) {
10
+ parts := strings.Split(a, "/")
11
+ if len(parts) == 5 && parts[1] == "ip4" && parts[3] == "ipcidr" {
12
+ _, ipn, err := net.ParseCIDR(parts[2] + "/" + parts[4])
13
+ if err != nil {
14
+ return nil, err
15
+ }
16
+ return ipn, nil
17
+ }
18
+ return nil, errors.New("invalid format")
19
+}
Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/mask_test.go
new
+36
@@ -0,0 +1,36 @@
1
+package mask
2
+
3
+import (
4
+ "net"
5
+ "testing"
6
+)
7
+
8
+func TestFiltered(t *testing.T) {
9
+ var tests = map[string]map[string]bool{
10
+ "/ip4/10.0.0.0/ipcidr/8": map[string]bool{
11
+ "10.3.3.4": true,
12
+ "10.3.4.4": true,
13
+ "10.4.4.4": true,
14
+ "15.52.34.3": false,
15
+ },
16
+ "/ip4/192.168.0.0/ipcidr/16": map[string]bool{
17
+ "192.168.0.0": true,
18
+ "192.168.1.0": true,
19
+ "192.1.0.0": false,
20
+ "10.4.4.4": false,
21
+ },
22
+ }
23
+
24
+ for mask, set := range tests {
25
+ m, err := NewMask(mask)
26
+ if err != nil {
27
+ t.Fatal(err)
28
+ }
29
+ for addr, val := range set {
30
+ ip := net.ParseIP(addr)
31
+ if m.Contains(ip) != val {
32
+ t.Fatalf("expected contains(%s, %s) == %s", mask, addr, val)
33
+ }
34
+ }
35
+ }
36
+}
core/core.go
+18
-6
@@ -13,17 +13,17 @@ import (
13
"errors"
14
"fmt"
15
"io"
16
+ "net"
17
"time"
18
19
b58 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
20
ctxgroup "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-ctxgroup"
21
ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
22
ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
23
+ mamask "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter"
24
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
23
- metrics "github.com/ipfs/go-ipfs/metrics"
24
- eventlog "github.com/ipfs/go-ipfs/thirdparty/eventlog"
25
-
25
diag "github.com/ipfs/go-ipfs/diagnostics"
26
+ metrics "github.com/ipfs/go-ipfs/metrics"
27
ic "github.com/ipfs/go-ipfs/p2p/crypto"
28
discovery "github.com/ipfs/go-ipfs/p2p/discovery"
29
p2phost "github.com/ipfs/go-ipfs/p2p/host"
@@ -32,6 +32,7 @@ import (
32
swarm "github.com/ipfs/go-ipfs/p2p/net/swarm"
33
addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr"
34
peer "github.com/ipfs/go-ipfs/p2p/peer"
35
+ eventlog "github.com/ipfs/go-ipfs/thirdparty/eventlog"
36
37
routing "github.com/ipfs/go-ipfs/routing"
38
dht "github.com/ipfs/go-ipfs/routing/dht"
@@ -254,7 +255,18 @@ func (n *IpfsNode) startOnlineServices(ctx context.Context, routingOption Routin
255
// Set reporter
256
n.Reporter = metrics.NewBandwidthCounter()
257
257
- peerhost, err := hostOption(ctx, n.Identity, n.Peerstore, n.Reporter)
258
+ // get undialable addrs from config
259
+ cfg := n.Repo.Config()
260
+ var addrfilter []*net.IPNet
261
+ for _, s := range cfg.DialBlocklist {
262
+ f, err := mamask.NewMask(s)
263
+ if err != nil {
264
+ return fmt.Errorf("incorrectly formatter address filter in config: %s", s)
265
+ }
266
+ addrfilter = append(addrfilter, f)
267
+ }
268
+
269
+ peerhost, err := hostOption(ctx, n.Identity, n.Peerstore, n.Reporter, addrfilter)
270
if err != nil {
271
return err
272
}
@@ -508,12 +520,12 @@ func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) {
520
return listen, nil
521
}
522
511
-type HostOption func(ctx context.Context, id peer.ID, ps peer.Peerstore, bwr metrics.Reporter) (p2phost.Host, error)
523
+type HostOption func(ctx context.Context, id peer.ID, ps peer.Peerstore, bwr metrics.Reporter, fs []*net.IPNet) (p2phost.Host, error)
524
525
var DefaultHostOption HostOption = constructPeerHost
526
527
// isolates the complex initialization steps
516
-func constructPeerHost(ctx context.Context, id peer.ID, ps peer.Peerstore, bwr metrics.Reporter) (p2phost.Host, error) {
528
+func constructPeerHost(ctx context.Context, id peer.ID, ps peer.Peerstore, bwr metrics.Reporter, fs []*net.IPNet) (p2phost.Host, error) {
529
530
// no addresses to begin with. we'll start later.
531
network, err := swarm.NewNetwork(ctx, nil, id, ps, bwr)
p2p/net/swarm/swarm.go
+8
@@ -4,6 +4,7 @@ package swarm
4
5
import (
6
"fmt"
7
+ "net"
8
"sync"
9
"time"
10
@@ -50,6 +51,9 @@ type Swarm struct {
51
notifmu sync.RWMutex
52
notifs map[inet.Notifiee]ps.Notifiee
53
54
+ // filters for addresses that shouldnt be dialed
55
+ filters []*net.IPNet
56
+
57
cg ctxgroup.ContextGroup
58
bwc metrics.Reporter
59
}
@@ -84,6 +88,10 @@ func (s *Swarm) teardown() error {
88
return s.swarm.Close()
89
}
90
91
+func (s *Swarm) AddDialFilter(f *net.IPNet) {
92
+ s.filters = append(s.filters, f)
93
+}
94
+
95
// CtxGroup returns the Context Group of the swarm
96
func filterAddrs(listenAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) {
97
if len(listenAddrs) > 0 {
p2p/net/swarm/swarm_dial.go
+28
@@ -303,6 +303,8 @@ func (s *Swarm) dial(ctx context.Context, p peer.ID) (*Conn, error) {
303
ila, _ := s.InterfaceListenAddresses()
304
remoteAddrs = addrutil.Subtract(remoteAddrs, ila)
305
remoteAddrs = addrutil.Subtract(remoteAddrs, s.peers.Addrs(s.local))
306
+ remoteAddrs = s.filterAddrs(remoteAddrs)
307
+
308
log.Debugf("%s swarm dialing %s -- local:%s remote:%s", s.local, p, s.ListenAddresses(), remoteAddrs)
309
if len(remoteAddrs) == 0 {
310
err := errors.New("peer has no addresses")
@@ -454,6 +456,32 @@ func (s *Swarm) dialAddr(ctx context.Context, d *conn.Dialer, p peer.ID, addr ma
456
return connC, nil
457
}
458
459
+func (s *Swarm) filterAddrs(addrs []ma.Multiaddr) []ma.Multiaddr {
460
+ var out []ma.Multiaddr
461
+ for _, a := range addrs {
462
+ if !s.addrBlocked(a) {
463
+ out = append(out, a)
464
+ }
465
+ }
466
+ return out
467
+}
468
+
469
+func (s *Swarm) addrBlocked(a ma.Multiaddr) bool {
470
+ _, addr, err := manet.DialArgs(a)
471
+ if err != nil {
472
+ // if we cant parse it, its probably not blocked
473
+ return false
474
+ }
475
+
476
+ ip := net.ParseIP(addr)
477
+ for _, f := range s.filters {
478
+ if f.Contains(ip) {
479
+ return true
480
+ }
481
+ }
482
+ return false
483
+}
484
+
485
// dialConnSetup is the setup logic for a connection from the dial side. it
486
// needs to add the Conn to the StreamSwarm, then run newConnSetup
487
func dialConnSetup(ctx context.Context, s *Swarm, connC conn.Conn) (*Conn, error) {
repo/config/config.go
+1
@@ -26,6 +26,7 @@ type Config struct {
26
Tour Tour // local node's tour position
27
Gateway Gateway // local node's gateway server options
28
SupernodeRouting SupernodeClientConfig // local node's routing servers (if SupernodeRouting enabled)
29
+ DialBlocklist []string
30
Log Log
31
}
32
util/sadhack/godep.go
+1
@@ -6,4 +6,5 @@ import _ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/go-hum
6
7
// similar to the above, only used in the tests makefile
8
import _ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/iptb"
9
+
10
import _ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/chriscool/go-sleep"