diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
index 4ee07c958e3ed531ac2154a6cecafff71bd1069c..426cabafd5cf278cfbb51555214a4438614e4f6c 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -239,6 +239,10 @@
 			"ImportPath": "github.com/whyrusleeping/iptb",
 			"Rev": "3970c95a864f1a40037f796ff596607ce8ae43be"
 		},
+		{
+			"ImportPath": "github.com/whyrusleeping/multiaddr-filter",
+			"Rev": "15837fcc356fddef27c634b0f6379b3b7f259114"
+		},
 		{
 			"ImportPath": "golang.org/x/crypto/blowfish",
 			"Rev": "c84e1f8e3a7e322d497cd16c0e8a13c7e127baf3"
diff --git a/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/mask.go b/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/mask.go
new file mode 100644
index 0000000000000000000000000000000000000000..91208fe048d3f4df3ee6305a5ea7bef58a9e02c3
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/mask.go
@@ -0,0 +1,19 @@
+package mask
+
+import (
+	"errors"
+	"net"
+	"strings"
+)
+
+func NewMask(a string) (*net.IPNet, error) {
+	parts := strings.Split(a, "/")
+	if len(parts) == 5 && parts[1] == "ip4" && parts[3] == "ipcidr" {
+		_, ipn, err := net.ParseCIDR(parts[2] + "/" + parts[4])
+		if err != nil {
+			return nil, err
+		}
+		return ipn, nil
+	}
+	return nil, errors.New("invalid format")
+}
diff --git a/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/mask_test.go b/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/mask_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..4507dca68f8cc6fb1dc648755f620d0f92349928
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/mask_test.go
@@ -0,0 +1,36 @@
+package mask
+
+import (
+	"net"
+	"testing"
+)
+
+func TestFiltered(t *testing.T) {
+	var tests = map[string]map[string]bool{
+		"/ip4/10.0.0.0/ipcidr/8": map[string]bool{
+			"10.3.3.4":   true,
+			"10.3.4.4":   true,
+			"10.4.4.4":   true,
+			"15.52.34.3": false,
+		},
+		"/ip4/192.168.0.0/ipcidr/16": map[string]bool{
+			"192.168.0.0": true,
+			"192.168.1.0": true,
+			"192.1.0.0":   false,
+			"10.4.4.4":    false,
+		},
+	}
+
+	for mask, set := range tests {
+		m, err := NewMask(mask)
+		if err != nil {
+			t.Fatal(err)
+		}
+		for addr, val := range set {
+			ip := net.ParseIP(addr)
+			if m.Contains(ip) != val {
+				t.Fatalf("expected contains(%s, %s) == %s", mask, addr, val)
+			}
+		}
+	}
+}
diff --git a/core/core.go b/core/core.go
index 877ffe9c0f7b4f0d7a42f7b16eb1e2844c1cc868..e3111a172748f025298c58fb5d0d9374546c1937 100644
--- a/core/core.go
+++ b/core/core.go
@@ -13,17 +13,17 @@ import (
 	"errors"
 	"fmt"
 	"io"
+	"net"
 	"time"
 
 	b58 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
 	ctxgroup "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-ctxgroup"
 	ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
 	ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
+	mamask "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter"
 	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
-	metrics "github.com/ipfs/go-ipfs/metrics"
-	eventlog "github.com/ipfs/go-ipfs/thirdparty/eventlog"
-
 	diag "github.com/ipfs/go-ipfs/diagnostics"
+	metrics "github.com/ipfs/go-ipfs/metrics"
 	ic "github.com/ipfs/go-ipfs/p2p/crypto"
 	discovery "github.com/ipfs/go-ipfs/p2p/discovery"
 	p2phost "github.com/ipfs/go-ipfs/p2p/host"
@@ -32,6 +32,7 @@ import (
 	swarm "github.com/ipfs/go-ipfs/p2p/net/swarm"
 	addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr"
 	peer "github.com/ipfs/go-ipfs/p2p/peer"
+	eventlog "github.com/ipfs/go-ipfs/thirdparty/eventlog"
 
 	routing "github.com/ipfs/go-ipfs/routing"
 	dht "github.com/ipfs/go-ipfs/routing/dht"
@@ -254,7 +255,18 @@ func (n *IpfsNode) startOnlineServices(ctx context.Context, routingOption Routin
 	// Set reporter
 	n.Reporter = metrics.NewBandwidthCounter()
 
-	peerhost, err := hostOption(ctx, n.Identity, n.Peerstore, n.Reporter)
+	// get undialable addrs from config
+	cfg := n.Repo.Config()
+	var addrfilter []*net.IPNet
+	for _, s := range cfg.DialBlocklist {
+		f, err := mamask.NewMask(s)
+		if err != nil {
+			return fmt.Errorf("incorrectly formatter address filter in config: %s", s)
+		}
+		addrfilter = append(addrfilter, f)
+	}
+
+	peerhost, err := hostOption(ctx, n.Identity, n.Peerstore, n.Reporter, addrfilter)
 	if err != nil {
 		return err
 	}
@@ -508,12 +520,12 @@ func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) {
 	return listen, nil
 }
 
-type HostOption func(ctx context.Context, id peer.ID, ps peer.Peerstore, bwr metrics.Reporter) (p2phost.Host, error)
+type HostOption func(ctx context.Context, id peer.ID, ps peer.Peerstore, bwr metrics.Reporter, fs []*net.IPNet) (p2phost.Host, error)
 
 var DefaultHostOption HostOption = constructPeerHost
 
 // isolates the complex initialization steps
-func constructPeerHost(ctx context.Context, id peer.ID, ps peer.Peerstore, bwr metrics.Reporter) (p2phost.Host, error) {
+func constructPeerHost(ctx context.Context, id peer.ID, ps peer.Peerstore, bwr metrics.Reporter, fs []*net.IPNet) (p2phost.Host, error) {
 
 	// no addresses to begin with. we'll start later.
 	network, err := swarm.NewNetwork(ctx, nil, id, ps, bwr)
diff --git a/p2p/net/conn/interface.go b/p2p/net/conn/interface.go
index 7d2c95af102c3aef260b5f236de017a0c253c64e..3a61911af82250e2dceb4f7b58af522d5d10a0f2 100644
--- a/p2p/net/conn/interface.go
+++ b/p2p/net/conn/interface.go
@@ -7,6 +7,7 @@ import (
 
 	key "github.com/ipfs/go-ipfs/blocks/key"
 	ic "github.com/ipfs/go-ipfs/p2p/crypto"
+	filter "github.com/ipfs/go-ipfs/p2p/net/filter"
 	peer "github.com/ipfs/go-ipfs/p2p/peer"
 
 	msgio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
@@ -86,6 +87,8 @@ type Listener interface {
 	// LocalPeer is the identity of the local Peer.
 	LocalPeer() peer.ID
 
+	SetAddrFilters(*filter.Filters)
+
 	// Close closes the listener.
 	// Any blocked Accept operations will be unblocked and return errors.
 	Close() error
diff --git a/p2p/net/conn/listen.go b/p2p/net/conn/listen.go
index d60c0ba3ad0acf8b60cab83b2e5ad28b98e5ad27..ea91e5a56d4ccfaf2abc606bdb9ece3876c1a43b 100644
--- a/p2p/net/conn/listen.go
+++ b/p2p/net/conn/listen.go
@@ -13,6 +13,7 @@ import (
 	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
 
 	ic "github.com/ipfs/go-ipfs/p2p/crypto"
+	filter "github.com/ipfs/go-ipfs/p2p/net/filter"
 	peer "github.com/ipfs/go-ipfs/p2p/peer"
 )
 
@@ -26,6 +27,8 @@ type listener struct {
 	local peer.ID    // LocalPeer is the identity of the local Peer
 	privk ic.PrivKey // private key to use to initialize secure conns
 
+	filters *filter.Filters
+
 	wrapper ConnWrapper
 
 	cg ctxgroup.ContextGroup
@@ -45,6 +48,10 @@ func (l *listener) String() string {
 	return fmt.Sprintf("<Listener %s %s>", l.local, l.Multiaddr())
 }
 
+func (l *listener) SetAddrFilters(fs *filter.Filters) {
+	l.filters = fs
+}
+
 // Accept waits for and returns the next connection to the listener.
 // Note that unfortunately this
 func (l *listener) Accept() (net.Conn, error) {
@@ -81,6 +88,12 @@ func (l *listener) Accept() (net.Conn, error) {
 		}
 
 		log.Debugf("listener %s got connection: %s <---> %s", l, maconn.LocalMultiaddr(), maconn.RemoteMultiaddr())
+
+		if l.filters != nil && l.filters.AddrBlocked(maconn.RemoteMultiaddr()) {
+			log.Debugf("blocked connection from %s", maconn.RemoteMultiaddr())
+			maconn.Close()
+			continue
+		}
 		// If we have a wrapper func, wrap this conn
 		if l.wrapper != nil {
 			maconn = l.wrapper(maconn)
diff --git a/p2p/net/filter/filter.go b/p2p/net/filter/filter.go
new file mode 100644
index 0000000000000000000000000000000000000000..1642a8b77c7c17b071b09ab7ae2fab75483b0661
--- /dev/null
+++ b/p2p/net/filter/filter.go
@@ -0,0 +1,34 @@
+package filter
+
+import (
+	"net"
+	"strings"
+
+	ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
+	manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
+)
+
+type Filters struct {
+	filters []*net.IPNet
+}
+
+func (fs *Filters) AddDialFilter(f *net.IPNet) {
+	fs.filters = append(fs.filters, f)
+}
+
+func (f *Filters) AddrBlocked(a ma.Multiaddr) bool {
+	_, addr, err := manet.DialArgs(a)
+	if err != nil {
+		// if we cant parse it, its probably not blocked
+		return false
+	}
+
+	ipstr := strings.Split(addr, ":")[0]
+	ip := net.ParseIP(ipstr)
+	for _, ft := range f.filters {
+		if ft.Contains(ip) {
+			return true
+		}
+	}
+	return false
+}
diff --git a/p2p/net/swarm/swarm.go b/p2p/net/swarm/swarm.go
index 15a5bbddbdf453b729597af55c30af5d1501c3e7..4fe45df8549f4acc5061957bffe7cb1c6050e611 100644
--- a/p2p/net/swarm/swarm.go
+++ b/p2p/net/swarm/swarm.go
@@ -9,6 +9,7 @@ import (
 
 	metrics "github.com/ipfs/go-ipfs/metrics"
 	inet "github.com/ipfs/go-ipfs/p2p/net"
+	filter "github.com/ipfs/go-ipfs/p2p/net/filter"
 	addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr"
 	peer "github.com/ipfs/go-ipfs/p2p/peer"
 	eventlog "github.com/ipfs/go-ipfs/thirdparty/eventlog"
@@ -50,6 +51,9 @@ type Swarm struct {
 	notifmu sync.RWMutex
 	notifs  map[inet.Notifiee]ps.Notifiee
 
+	// filters for addresses that shouldnt be dialed
+	Filters *filter.Filters
+
 	cg  ctxgroup.ContextGroup
 	bwc metrics.Reporter
 }
@@ -64,13 +68,14 @@ func NewSwarm(ctx context.Context, listenAddrs []ma.Multiaddr,
 	}
 
 	s := &Swarm{
-		swarm:  ps.NewSwarm(PSTransport),
-		local:  local,
-		peers:  peers,
-		cg:     ctxgroup.WithContext(ctx),
-		dialT:  DialTimeout,
-		notifs: make(map[inet.Notifiee]ps.Notifiee),
-		bwc:    bwc,
+		swarm:   ps.NewSwarm(PSTransport),
+		local:   local,
+		peers:   peers,
+		cg:      ctxgroup.WithContext(ctx),
+		dialT:   DialTimeout,
+		notifs:  make(map[inet.Notifiee]ps.Notifiee),
+		bwc:     bwc,
+		Filters: new(filter.Filters),
 	}
 
 	// configure Swarm
diff --git a/p2p/net/swarm/swarm_dial.go b/p2p/net/swarm/swarm_dial.go
index aacee6ec4405f7ea2c0920948706c93b18dae364..c969ca570181bdfd5f3cf65f6aaf35e37227fb90 100644
--- a/p2p/net/swarm/swarm_dial.go
+++ b/p2p/net/swarm/swarm_dial.go
@@ -303,6 +303,7 @@ func (s *Swarm) dial(ctx context.Context, p peer.ID) (*Conn, error) {
 	ila, _ := s.InterfaceListenAddresses()
 	remoteAddrs = addrutil.Subtract(remoteAddrs, ila)
 	remoteAddrs = addrutil.Subtract(remoteAddrs, s.peers.Addrs(s.local))
+
 	log.Debugf("%s swarm dialing %s -- local:%s remote:%s", s.local, p, s.ListenAddresses(), remoteAddrs)
 	if len(remoteAddrs) == 0 {
 		err := errors.New("peer has no addresses")
@@ -310,6 +311,13 @@ func (s *Swarm) dial(ctx context.Context, p peer.ID) (*Conn, error) {
 		return nil, err
 	}
 
+	remoteAddrs = s.filterAddrs(remoteAddrs)
+	if len(remoteAddrs) == 0 {
+		err := errors.New("all adresses for peer have been filtered out")
+		logdial["error"] = err
+		return nil, err
+	}
+
 	// open connection to peer
 	d := &conn.Dialer{
 		Dialer: manet.Dialer{
@@ -454,6 +462,16 @@ func (s *Swarm) dialAddr(ctx context.Context, d *conn.Dialer, p peer.ID, addr ma
 	return connC, nil
 }
 
+func (s *Swarm) filterAddrs(addrs []ma.Multiaddr) []ma.Multiaddr {
+	var out []ma.Multiaddr
+	for _, a := range addrs {
+		if !s.Filters.AddrBlocked(a) {
+			out = append(out, a)
+		}
+	}
+	return out
+}
+
 // dialConnSetup is the setup logic for a connection from the dial side. it
 // needs to add the Conn to the StreamSwarm, then run newConnSetup
 func dialConnSetup(ctx context.Context, s *Swarm, connC conn.Conn) (*Conn, error) {
diff --git a/p2p/net/swarm/swarm_listen.go b/p2p/net/swarm/swarm_listen.go
index 2a985763f1b7731ef6b32e09dc0351b71fdee131..4a8f4dd4d9e390444d4be2b9bf2bd7aaf7f0f763 100644
--- a/p2p/net/swarm/swarm_listen.go
+++ b/p2p/net/swarm/swarm_listen.go
@@ -69,6 +69,8 @@ func (s *Swarm) setupListener(maddr ma.Multiaddr) error {
 		return err
 	}
 
+	list.SetAddrFilters(s.Filters)
+
 	if cw, ok := list.(conn.ListenerConnWrapper); ok {
 		cw.SetConnWrapper(func(c manet.Conn) manet.Conn {
 			return mconn.WrapConn(s.bwc, c)
diff --git a/p2p/net/swarm/swarm_test.go b/p2p/net/swarm/swarm_test.go
index 9aa825320ab0d709d6b9fa67580789401ecafca2..4c12a1b5d3b4ac42950164babc8ca02ee0e85732 100644
--- a/p2p/net/swarm/swarm_test.go
+++ b/p2p/net/swarm/swarm_test.go
@@ -4,6 +4,7 @@ import (
 	"bytes"
 	"fmt"
 	"io"
+	"net"
 	"sync"
 	"testing"
 	"time"
@@ -270,3 +271,60 @@ func TestConnHandler(t *testing.T) {
 	default:
 	}
 }
+
+func TestAddrBlocking(t *testing.T) {
+	ctx := context.Background()
+	swarms := makeSwarms(ctx, t, 2)
+
+	swarms[0].SetConnHandler(func(conn *Conn) {
+		t.Fatal("no connections should happen!")
+	})
+
+	_, block, err := net.ParseCIDR("127.0.0.1/8")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	swarms[1].Filters.AddDialFilter(block)
+
+	swarms[1].peers.AddAddr(swarms[0].LocalPeer(), swarms[0].ListenAddresses()[0], peer.PermanentAddrTTL)
+	_, err = swarms[1].Dial(context.TODO(), swarms[0].LocalPeer())
+	if err == nil {
+		t.Fatal("dial should have failed")
+	}
+
+	swarms[0].peers.AddAddr(swarms[1].LocalPeer(), swarms[1].ListenAddresses()[0], peer.PermanentAddrTTL)
+	_, err = swarms[0].Dial(context.TODO(), swarms[1].LocalPeer())
+	if err == nil {
+		t.Fatal("dial should have failed")
+	}
+}
+
+func TestFilterBounds(t *testing.T) {
+	ctx := context.Background()
+	swarms := makeSwarms(ctx, t, 2)
+
+	conns := make(chan struct{}, 8)
+	swarms[0].SetConnHandler(func(conn *Conn) {
+		conns <- struct{}{}
+	})
+
+	// Address that we wont be dialing from
+	_, block, err := net.ParseCIDR("192.0.0.1/8")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// set filter on both sides, shouldnt matter
+	swarms[1].Filters.AddDialFilter(block)
+	swarms[0].Filters.AddDialFilter(block)
+
+	connectSwarms(t, ctx, swarms)
+
+	select {
+	case <-time.After(time.Second):
+		t.Fatal("should have gotten connection")
+	case <-conns:
+		fmt.Println("got connect")
+	}
+}
diff --git a/repo/config/config.go b/repo/config/config.go
index c9a8aabec6844dabbbefeb48dfd86b12ad4ff020..e7474cf7e090c97dc820bb435bef0e71053863c1 100644
--- a/repo/config/config.go
+++ b/repo/config/config.go
@@ -26,6 +26,7 @@ type Config struct {
 	Tour             Tour                  // local node's tour position
 	Gateway          Gateway               // local node's gateway server options
 	SupernodeRouting SupernodeClientConfig // local node's routing servers (if SupernodeRouting enabled)
+	DialBlocklist    []string
 	Log              Log
 }
 
diff --git a/util/sadhack/godep.go b/util/sadhack/godep.go
index c38bbb1e4a0853a29c53408b00e2cdb872e1d8fb..47a2350bb907b8211f82c419c36f7e0400a78911 100644
--- a/util/sadhack/godep.go
+++ b/util/sadhack/godep.go
@@ -6,4 +6,5 @@ import _ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/go-hum
 
 // similar to the above, only used in the tests makefile
 import _ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/iptb"
+
 import _ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/chriscool/go-sleep"