mirror of
https://github.com/ipfs/kubo.git
synced 2026-03-10 18:57:57 +08:00
add command to manipulate address filters and a sharness test for them
License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com>
This commit is contained in:
parent
e7fd57f69a
commit
7cc73f7b86
2
Godeps/Godeps.json
generated
2
Godeps/Godeps.json
generated
@ -282,7 +282,7 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/whyrusleeping/multiaddr-filter",
|
||||
"Rev": "15837fcc356fddef27c634b0f6379b3b7f259114"
|
||||
"Rev": "9e26222151125ecd3fc1fd190179b6bdd55f5608"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/blowfish",
|
||||
|
||||
21
Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/LICENSE
generated
vendored
Normal file
21
Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Jeromy Johnson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
15
Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/README.md
generated
vendored
Normal file
15
Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/README.md
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
# go-multiaddr-filter -- CIDR netmasks with multiaddr
|
||||
|
||||
This module creates very simple [multiaddr](https://github.com/jbenet/go-multiaddr) formatted cidr netmasks.
|
||||
|
||||
It doesn't do full multiaddr parsing to save on vendoring things and perf. The `net` package will take care of verifying the validity of the network part anyway.
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
|
||||
import filter "github.com/whyrusleeping/multiaddr-filter"
|
||||
|
||||
filter.NewMask("/ip4/192.168.0.0/24") // ipv4
|
||||
filter.NewMask("/ip6/fe80::/64") // ipv6
|
||||
```
|
||||
42
Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/mask.go
generated
vendored
42
Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/mask.go
generated
vendored
@ -2,18 +2,46 @@ package mask
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
|
||||
)
|
||||
|
||||
var ErrInvalidFormat = errors.New("invalid multiaddr-filter format")
|
||||
|
||||
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
|
||||
|
||||
if parts[0] != "" {
|
||||
return nil, ErrInvalidFormat
|
||||
}
|
||||
return nil, errors.New("invalid format")
|
||||
|
||||
if len(parts) != 5 {
|
||||
return nil, ErrInvalidFormat
|
||||
}
|
||||
|
||||
// check it's a valid filter address. ip + cidr
|
||||
isip := parts[1] == "ip4" || parts[1] == "ip6"
|
||||
iscidr := parts[3] == "ipcidr"
|
||||
if !isip || !iscidr {
|
||||
return nil, ErrInvalidFormat
|
||||
}
|
||||
|
||||
_, ipn, err := net.ParseCIDR(parts[2] + "/" + parts[4])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ipn, nil
|
||||
}
|
||||
|
||||
func ConvertIPNet(n *net.IPNet) (string, error) {
|
||||
addr, err := manet.FromIP(n.IP)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
b, _ := n.Mask.Size()
|
||||
return fmt.Sprintf("%s/ipcidr/%d", addr, b), nil
|
||||
}
|
||||
|
||||
96
Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/mask_test.go
generated
vendored
96
Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/mask_test.go
generated
vendored
@ -5,6 +5,74 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidMasks(t *testing.T) {
|
||||
|
||||
cidrOrFatal := func(s string) *net.IPNet {
|
||||
_, ipn, err := net.ParseCIDR(s)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return ipn
|
||||
}
|
||||
|
||||
testCases := map[string]*net.IPNet{
|
||||
"/ip4/1.2.3.4/ipcidr/0": cidrOrFatal("1.2.3.4/0"),
|
||||
"/ip4/1.2.3.4/ipcidr/32": cidrOrFatal("1.2.3.4/32"),
|
||||
"/ip4/1.2.3.4/ipcidr/24": cidrOrFatal("1.2.3.4/24"),
|
||||
"/ip4/192.168.0.0/ipcidr/28": cidrOrFatal("192.168.0.0/28"),
|
||||
"/ip6/fe80::/ipcidr/0": cidrOrFatal("fe80::/0"),
|
||||
"/ip6/fe80::/ipcidr/64": cidrOrFatal("fe80::/64"),
|
||||
"/ip6/fe80::/ipcidr/128": cidrOrFatal("fe80::/128"),
|
||||
}
|
||||
|
||||
for s, m1 := range testCases {
|
||||
m2, err := NewMask(s)
|
||||
if err != nil {
|
||||
t.Error("should be invalid:", s)
|
||||
continue
|
||||
}
|
||||
|
||||
if m1.String() != m2.String() {
|
||||
t.Error("masks not equal:", m1, m2)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestInvalidMasks(t *testing.T) {
|
||||
|
||||
testCases := []string{
|
||||
"/",
|
||||
"/ip4/10.1.2.3",
|
||||
"/ip6/::",
|
||||
"/ip4/1.2.3.4/cidr/24",
|
||||
"/ip6/fe80::/cidr/24",
|
||||
"/eth/aa:aa:aa:aa:aa/ipcidr/24",
|
||||
"foobar/ip4/1.2.3.4/ipcidr/32",
|
||||
}
|
||||
|
||||
for _, s := range testCases {
|
||||
_, err := NewMask(s)
|
||||
if err != ErrInvalidFormat {
|
||||
t.Error("should be invalid:", s)
|
||||
}
|
||||
}
|
||||
|
||||
testCases2 := []string{
|
||||
"/ip4/1.2.3.4/ipcidr/33",
|
||||
"/ip4/192.168.0.0/ipcidr/-1",
|
||||
"/ip6/fe80::/ipcidr/129",
|
||||
}
|
||||
|
||||
for _, s := range testCases2 {
|
||||
_, err := NewMask(s)
|
||||
if err == nil {
|
||||
t.Error("should be invalid:", s)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestFiltered(t *testing.T) {
|
||||
var tests = map[string]map[string]bool{
|
||||
"/ip4/10.0.0.0/ipcidr/8": map[string]bool{
|
||||
@ -34,3 +102,31 @@ func TestFiltered(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsing(t *testing.T) {
|
||||
var addrs = map[string]string{
|
||||
"/ip4/192.168.0.0/ipcidr/16": "192.168.0.0/16",
|
||||
"/ip4/192.0.0.0/ipcidr/8": "192.0.0.0/8",
|
||||
"/ip6/2001:db8::/ipcidr/32": "2001:db8::/32",
|
||||
}
|
||||
|
||||
for k, v := range addrs {
|
||||
m, err := NewMask(k)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if m.String() != v {
|
||||
t.Fatalf("mask is wrong: ", m, v)
|
||||
}
|
||||
|
||||
orig, err := ConvertIPNet(m)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if orig != k {
|
||||
t.Fatal("backwards conversion failed: ", orig, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,10 +9,12 @@ import (
|
||||
"sort"
|
||||
|
||||
cmds "github.com/ipfs/go-ipfs/commands"
|
||||
swarm "github.com/ipfs/go-ipfs/p2p/net/swarm"
|
||||
peer "github.com/ipfs/go-ipfs/p2p/peer"
|
||||
iaddr "github.com/ipfs/go-ipfs/util/ipfsaddr"
|
||||
|
||||
ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
|
||||
mafilter "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"
|
||||
)
|
||||
|
||||
@ -32,6 +34,7 @@ ipfs swarm peers - List peers with open connections
|
||||
ipfs swarm addrs - List known addresses. Useful to debug.
|
||||
ipfs swarm connect <address> - Open connection to a given address
|
||||
ipfs swarm disconnect <address> - Close connection to a given address
|
||||
ipfs swarm filters - Manipulate filters addresses
|
||||
`,
|
||||
ShortDescription: `
|
||||
ipfs swarm is a tool to manipulate the network swarm. The swarm is the
|
||||
@ -44,6 +47,7 @@ ipfs peers in the internet.
|
||||
"addrs": swarmAddrsCmd,
|
||||
"connect": swarmConnectCmd,
|
||||
"disconnect": swarmDisconnectCmd,
|
||||
"filters": swarmFiltersCmd,
|
||||
},
|
||||
}
|
||||
|
||||
@ -358,3 +362,142 @@ func peersWithAddresses(addrs []string) (pis []peer.PeerInfo, err error) {
|
||||
}
|
||||
return pis, nil
|
||||
}
|
||||
|
||||
var swarmFiltersCmd = &cmds.Command{
|
||||
Helptext: cmds.HelpText{
|
||||
Tagline: "Manipulate address filters",
|
||||
ShortDescription: `
|
||||
'ipfs swarm filters' will list out currently applied filters. Its subcommands can be used
|
||||
to add or remove said filters. Filters are specified using the multiaddr-filter format:
|
||||
|
||||
example:
|
||||
|
||||
/ip4/192.168.0.0/ipcidr/16
|
||||
|
||||
Where the above is equivalent to the standard CIDR:
|
||||
|
||||
192.168.0.0/16
|
||||
|
||||
Filters default to those specified under the "DialBlocklist" config key.
|
||||
`,
|
||||
},
|
||||
Subcommands: map[string]*cmds.Command{
|
||||
"add": swarmFiltersAddCmd,
|
||||
"rm": swarmFiltersRmCmd,
|
||||
},
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
snet, ok := n.PeerHost.Network().(*swarm.Network)
|
||||
if !ok {
|
||||
res.SetError(errors.New("failed to cast network to swarm network"), cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
var output []string
|
||||
for _, f := range snet.Filters.Filters() {
|
||||
s, err := mafilter.ConvertIPNet(f)
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
output = append(output, s)
|
||||
}
|
||||
res.SetOutput(&stringList{output})
|
||||
},
|
||||
Marshalers: cmds.MarshalerMap{
|
||||
cmds.Text: stringListMarshaler,
|
||||
},
|
||||
Type: stringList{},
|
||||
}
|
||||
|
||||
var swarmFiltersAddCmd = &cmds.Command{
|
||||
Helptext: cmds.HelpText{
|
||||
Tagline: "add an address filter",
|
||||
ShortDescription: `
|
||||
'ipfs swarm filters add' will add an address filter to the daemons swarm.
|
||||
Filters applied this way will not persist daemon reboots, to acheive that,
|
||||
add your filters to the ipfs config file.
|
||||
`,
|
||||
},
|
||||
Arguments: []cmds.Argument{
|
||||
cmds.StringArg("address", true, true, "multiaddr to filter").EnableStdin(),
|
||||
},
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
snet, ok := n.PeerHost.Network().(*swarm.Network)
|
||||
if !ok {
|
||||
res.SetError(errors.New("failed to cast network to swarm network"), cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
for _, arg := range req.Arguments() {
|
||||
mask, err := mafilter.NewMask(arg)
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
snet.Filters.AddDialFilter(mask)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var swarmFiltersRmCmd = &cmds.Command{
|
||||
Helptext: cmds.HelpText{
|
||||
Tagline: "remove an address filter",
|
||||
ShortDescription: `
|
||||
'ipfs swarm filters rm' will remove an address filter from the daemons swarm.
|
||||
Filters removed this way will not persist daemon reboots, to acheive that,
|
||||
remove your filters from the ipfs config file.
|
||||
`,
|
||||
},
|
||||
Arguments: []cmds.Argument{
|
||||
cmds.StringArg("address", true, true, "multiaddr filter to remove").EnableStdin(),
|
||||
},
|
||||
Run: func(req cmds.Request, res cmds.Response) {
|
||||
n, err := req.Context().GetNode()
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
if n.PeerHost == nil {
|
||||
res.SetError(errNotOnline, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
snet, ok := n.PeerHost.Network().(*swarm.Network)
|
||||
if !ok {
|
||||
res.SetError(errors.New("failed to cast network to swarm network"), cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Arguments()[0] == "all" || req.Arguments()[0] == "*" {
|
||||
fs := snet.Filters.Filters()
|
||||
for _, f := range fs {
|
||||
snet.Filters.Remove(f)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for _, arg := range req.Arguments() {
|
||||
mask, err := mafilter.NewMask(arg)
|
||||
if err != nil {
|
||||
res.SetError(err, cmds.ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
snet.Filters.Remove(mask)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@ -9,11 +9,17 @@ import (
|
||||
)
|
||||
|
||||
type Filters struct {
|
||||
filters []*net.IPNet
|
||||
filters map[string]*net.IPNet
|
||||
}
|
||||
|
||||
func NewFilters() *Filters {
|
||||
return &Filters{
|
||||
filters: make(map[string]*net.IPNet),
|
||||
}
|
||||
}
|
||||
|
||||
func (fs *Filters) AddDialFilter(f *net.IPNet) {
|
||||
fs.filters = append(fs.filters, f)
|
||||
fs.filters[f.String()] = f
|
||||
}
|
||||
|
||||
func (f *Filters) AddrBlocked(a ma.Multiaddr) bool {
|
||||
@ -32,3 +38,15 @@ func (f *Filters) AddrBlocked(a ma.Multiaddr) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *Filters) Filters() []*net.IPNet {
|
||||
var out []*net.IPNet
|
||||
for _, ff := range f.filters {
|
||||
out = append(out, ff)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (f *Filters) Remove(ff *net.IPNet) {
|
||||
delete(f.filters, ff.String())
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ func NewSwarm(ctx context.Context, listenAddrs []ma.Multiaddr,
|
||||
dialT: DialTimeout,
|
||||
notifs: make(map[inet.Notifiee]ps.Notifiee),
|
||||
bwc: bwc,
|
||||
Filters: new(filter.Filters),
|
||||
Filters: filter.NewFilters(),
|
||||
}
|
||||
|
||||
// configure Swarm
|
||||
|
||||
71
test/sharness/t0141-addfilter.sh
Executable file
71
test/sharness/t0141-addfilter.sh
Executable file
@ -0,0 +1,71 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2014 Jeromy Johnson
|
||||
# MIT Licensed; see the LICENSE file in this repository.
|
||||
#
|
||||
|
||||
test_description="Test ipfs swarm command"
|
||||
|
||||
AF1="/ip4/192.168.0.0/ipcidr/16"
|
||||
AF2="/ip4/127.0.0.0/ipcidr/8"
|
||||
AF3="/ip6/2008:bcd::/ipcidr/32"
|
||||
AF4="/ip4/172.16.0.0/ipcidr/12"
|
||||
|
||||
. lib/test-lib.sh
|
||||
|
||||
test_init_ipfs
|
||||
|
||||
test_swarm_filter_cmd() {
|
||||
printf "" > list_expected
|
||||
for AF in "$@"
|
||||
do
|
||||
echo "$AF" >>list_expected
|
||||
done
|
||||
|
||||
test_expect_success "'ipfs swarm filters' succeeds" '
|
||||
ipfs swarm filters > list_actual
|
||||
'
|
||||
|
||||
test_expect_success "'ipfs swarm filters' output looks good" '
|
||||
test_sort_cmp list_actual list_expected
|
||||
'
|
||||
}
|
||||
|
||||
test_swarm_filters() {
|
||||
|
||||
ipfs swarm filters rm all
|
||||
|
||||
test_swarm_filter_cmd
|
||||
|
||||
test_expect_success "'ipfs swarm filter add' succeeds" '
|
||||
ipfs swarm filters add $AF1 $AF2 $AF3
|
||||
'
|
||||
|
||||
test_swarm_filter_cmd $AF1 $AF2 $AF3
|
||||
|
||||
test_expect_success "'ipfs swarm filter rm' succeeds" '
|
||||
ipfs swarm filters rm $AF2 $AF3
|
||||
'
|
||||
|
||||
test_swarm_filter_cmd $AF1
|
||||
|
||||
test_expect_success "'ipfs swarm filter add' succeeds" '
|
||||
ipfs swarm filters add $AF4 $AF2
|
||||
'
|
||||
|
||||
test_swarm_filter_cmd $AF1 $AF2 $AF4
|
||||
|
||||
test_expect_success "'ipfs swarm filter rm' succeeds" '
|
||||
ipfs swarm filters rm $AF1 $AF2 $AF4
|
||||
'
|
||||
|
||||
test_swarm_filter_cmd
|
||||
}
|
||||
|
||||
test_launch_ipfs_daemon
|
||||
|
||||
test_swarm_filters
|
||||
|
||||
test_kill_ipfs_daemon
|
||||
|
||||
test_done
|
||||
Loading…
Reference in New Issue
Block a user