filter incoming connections and add a test of functionality
- add extra check to dialblock test - move filter to separate package - also improved tests - sunk filters down into p2p/net/conn/listener License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com> Signed-off-by: Juan Batiz-Benet <juan@benet.ai>
Jeromy committed
Jun 17, 2015 at 16:26 UTC
0bf6b39cafda5fb243f8ae3c909650077c6ecab3
7 files changed
+120
-29
p2p/net/conn/interface.go
+3
@@ -7,6 +7,7 @@ import (
7
8
key "github.com/ipfs/go-ipfs/blocks/key"
9
ic "github.com/ipfs/go-ipfs/p2p/crypto"
10
+ filter "github.com/ipfs/go-ipfs/p2p/net/filter"
11
peer "github.com/ipfs/go-ipfs/p2p/peer"
12
13
msgio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
@@ -86,6 +87,8 @@ type Listener interface {
87
// LocalPeer is the identity of the local Peer.
88
LocalPeer() peer.ID
89
90
+ SetAddrFilters(*filter.Filters)
91
+
92
// Close closes the listener.
93
// Any blocked Accept operations will be unblocked and return errors.
94
Close() error
p2p/net/conn/listen.go
+13
@@ -13,6 +13,7 @@ import (
13
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
14
15
ic "github.com/ipfs/go-ipfs/p2p/crypto"
16
+ filter "github.com/ipfs/go-ipfs/p2p/net/filter"
17
peer "github.com/ipfs/go-ipfs/p2p/peer"
18
)
19
@@ -26,6 +27,8 @@ type listener struct {
27
local peer.ID // LocalPeer is the identity of the local Peer
28
privk ic.PrivKey // private key to use to initialize secure conns
29
30
+ filters *filter.Filters
31
+
32
wrapper ConnWrapper
33
34
cg ctxgroup.ContextGroup
@@ -45,6 +48,10 @@ func (l *listener) String() string {
48
return fmt.Sprintf("<Listener %s %s>", l.local, l.Multiaddr())
49
}
50
51
+func (l *listener) SetAddrFilters(fs *filter.Filters) {
52
+ l.filters = fs
53
+}
54
+
55
// Accept waits for and returns the next connection to the listener.
56
// Note that unfortunately this
57
func (l *listener) Accept() (net.Conn, error) {
@@ -81,6 +88,12 @@ func (l *listener) Accept() (net.Conn, error) {
88
}
89
90
log.Debugf("listener %s got connection: %s <---> %s", l, maconn.LocalMultiaddr(), maconn.RemoteMultiaddr())
91
+
92
+ if l.filters != nil && l.filters.AddrBlocked(maconn.RemoteMultiaddr()) {
93
+ log.Debugf("blocked connection from %s", maconn.RemoteMultiaddr())
94
+ maconn.Close()
95
+ continue
96
+ }
97
// If we have a wrapper func, wrap this conn
98
if l.wrapper != nil {
99
maconn = l.wrapper(maconn)
p2p/net/filter/filter.go
new
+34
@@ -0,0 +1,34 @@
1
+package filter
2
+
3
+import (
4
+ "net"
5
+ "strings"
6
+
7
+ ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8
+ manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
9
+)
10
+
11
+type Filters struct {
12
+ filters []*net.IPNet
13
+}
14
+
15
+func (fs *Filters) AddDialFilter(f *net.IPNet) {
16
+ fs.filters = append(fs.filters, f)
17
+}
18
+
19
+func (f *Filters) AddrBlocked(a ma.Multiaddr) bool {
20
+ _, addr, err := manet.DialArgs(a)
21
+ if err != nil {
22
+ // if we cant parse it, its probably not blocked
23
+ return false
24
+ }
25
+
26
+ ipstr := strings.Split(addr, ":")[0]
27
+ ip := net.ParseIP(ipstr)
28
+ for _, ft := range f.filters {
29
+ if ft.Contains(ip) {
30
+ return true
31
+ }
32
+ }
33
+ return false
34
+}
p2p/net/swarm/swarm.go
+3
-28
@@ -4,19 +4,18 @@ package swarm
4
5
import (
6
"fmt"
7
- "net"
7
"sync"
8
"time"
9
10
metrics "github.com/ipfs/go-ipfs/metrics"
11
inet "github.com/ipfs/go-ipfs/p2p/net"
12
+ filter "github.com/ipfs/go-ipfs/p2p/net/filter"
13
addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr"
14
peer "github.com/ipfs/go-ipfs/p2p/peer"
15
eventlog "github.com/ipfs/go-ipfs/thirdparty/eventlog"
16
17
ctxgroup "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-ctxgroup"
18
ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
19
- manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
19
ps "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream"
20
pst "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream/transport"
21
psy "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream/transport/yamux"
@@ -53,7 +52,7 @@ type Swarm struct {
52
notifs map[inet.Notifiee]ps.Notifiee
53
54
// filters for addresses that shouldnt be dialed
56
- Filters *Filters
55
+ Filters *filter.Filters
56
57
cg ctxgroup.ContextGroup
58
bwc metrics.Reporter
@@ -76,7 +75,7 @@ func NewSwarm(ctx context.Context, listenAddrs []ma.Multiaddr,
75
dialT: DialTimeout,
76
notifs: make(map[inet.Notifiee]ps.Notifiee),
77
bwc: bwc,
79
- Filters: new(Filters),
78
+ Filters: new(filter.Filters),
79
}
80
81
// configure Swarm
@@ -90,30 +89,6 @@ func (s *Swarm) teardown() error {
89
return s.swarm.Close()
90
}
91
93
-type Filters struct {
94
- filters []*net.IPNet
95
-}
96
-
97
-func (fs *Filters) AddDialFilter(f *net.IPNet) {
98
- fs.filters = append(fs.filters, f)
99
-}
100
-
101
-func (f *Filters) AddrBlocked(a ma.Multiaddr) bool {
102
- _, addr, err := manet.DialArgs(a)
103
- if err != nil {
104
- // if we cant parse it, its probably not blocked
105
- return false
106
- }
107
-
108
- ip := net.ParseIP(addr)
109
- for _, ft := range f.filters {
110
- if ft.Contains(ip) {
111
- return true
112
- }
113
- }
114
- return false
115
-}
116
-
92
// CtxGroup returns the Context Group of the swarm
93
func filterAddrs(listenAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) {
94
if len(listenAddrs) > 0 {
p2p/net/swarm/swarm_dial.go
+7
-1
@@ -303,7 +303,6 @@ 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)
306
307
log.Debugf("%s swarm dialing %s -- local:%s remote:%s", s.local, p, s.ListenAddresses(), remoteAddrs)
308
if len(remoteAddrs) == 0 {
@@ -312,6 +311,13 @@ func (s *Swarm) dial(ctx context.Context, p peer.ID) (*Conn, error) {
311
return nil, err
312
}
313
314
+ remoteAddrs = s.filterAddrs(remoteAddrs)
315
+ if len(remoteAddrs) == 0 {
316
+ err := errors.New("all adresses for peer have been filtered out")
317
+ logdial["error"] = err
318
+ return nil, err
319
+ }
320
+
321
// open connection to peer
322
d := &conn.Dialer{
323
Dialer: manet.Dialer{
p2p/net/swarm/swarm_listen.go
+2
@@ -69,6 +69,8 @@ func (s *Swarm) setupListener(maddr ma.Multiaddr) error {
69
return err
70
}
71
72
+ list.SetAddrFilters(s.Filters)
73
+
74
if cw, ok := list.(conn.ListenerConnWrapper); ok {
75
cw.SetConnWrapper(func(c manet.Conn) manet.Conn {
76
return mconn.WrapConn(s.bwc, c)
p2p/net/swarm/swarm_test.go
+58
@@ -4,6 +4,7 @@ import (
4
"bytes"
5
"fmt"
6
"io"
7
+ "net"
8
"sync"
9
"testing"
10
"time"
@@ -270,3 +271,60 @@ func TestConnHandler(t *testing.T) {
271
default:
272
}
273
}
274
+
275
+func TestAddrBlocking(t *testing.T) {
276
+ ctx := context.Background()
277
+ swarms := makeSwarms(ctx, t, 2)
278
+
279
+ swarms[0].SetConnHandler(func(conn *Conn) {
280
+ t.Fatal("no connections should happen!")
281
+ })
282
+
283
+ _, block, err := net.ParseCIDR("127.0.0.1/8")
284
+ if err != nil {
285
+ t.Fatal(err)
286
+ }
287
+
288
+ swarms[1].Filters.AddDialFilter(block)
289
+
290
+ swarms[1].peers.AddAddr(swarms[0].LocalPeer(), swarms[0].ListenAddresses()[0], peer.PermanentAddrTTL)
291
+ _, err = swarms[1].Dial(context.TODO(), swarms[0].LocalPeer())
292
+ if err == nil {
293
+ t.Fatal("dial should have failed")
294
+ }
295
+
296
+ swarms[0].peers.AddAddr(swarms[1].LocalPeer(), swarms[1].ListenAddresses()[0], peer.PermanentAddrTTL)
297
+ _, err = swarms[0].Dial(context.TODO(), swarms[1].LocalPeer())
298
+ if err == nil {
299
+ t.Fatal("dial should have failed")
300
+ }
301
+}
302
+
303
+func TestFilterBounds(t *testing.T) {
304
+ ctx := context.Background()
305
+ swarms := makeSwarms(ctx, t, 2)
306
+
307
+ conns := make(chan struct{}, 8)
308
+ swarms[0].SetConnHandler(func(conn *Conn) {
309
+ conns <- struct{}{}
310
+ })
311
+
312
+ // Address that we wont be dialing from
313
+ _, block, err := net.ParseCIDR("192.0.0.1/8")
314
+ if err != nil {
315
+ t.Fatal(err)
316
+ }
317
+
318
+ // set filter on both sides, shouldnt matter
319
+ swarms[1].Filters.AddDialFilter(block)
320
+ swarms[0].Filters.AddDialFilter(block)
321
+
322
+ connectSwarms(t, ctx, swarms)
323
+
324
+ select {
325
+ case <-time.After(time.Second):
326
+ t.Fatal("should have gotten connection")
327
+ case <-conns:
328
+ fmt.Println("got connect")
329
+ }
330
+}