@cryptotaxi247 / kubo / commits / 0bf6b39ca

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 +}