提交 2d6b787c 作者: Juan Batiz-Benet

Merge pull request #1399 from ipfs/disable-secio-option

Swarm Addrs, Disable secio opt, + tests
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
"net/http" "net/http"
_ "net/http/pprof" _ "net/http/pprof"
"os" "os"
"sort"
"strings" "strings"
"sync" "sync"
...@@ -18,6 +19,7 @@ import ( ...@@ -18,6 +19,7 @@ import (
commands "github.com/ipfs/go-ipfs/core/commands" commands "github.com/ipfs/go-ipfs/core/commands"
corehttp "github.com/ipfs/go-ipfs/core/corehttp" corehttp "github.com/ipfs/go-ipfs/core/corehttp"
"github.com/ipfs/go-ipfs/core/corerouting" "github.com/ipfs/go-ipfs/core/corerouting"
conn "github.com/ipfs/go-ipfs/p2p/net/conn"
peer "github.com/ipfs/go-ipfs/p2p/peer" peer "github.com/ipfs/go-ipfs/p2p/peer"
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
util "github.com/ipfs/go-ipfs/util" util "github.com/ipfs/go-ipfs/util"
...@@ -31,7 +33,8 @@ const ( ...@@ -31,7 +33,8 @@ const (
writableKwd = "writable" writableKwd = "writable"
ipfsMountKwd = "mount-ipfs" ipfsMountKwd = "mount-ipfs"
ipnsMountKwd = "mount-ipns" ipnsMountKwd = "mount-ipns"
unrestrictedApiAccess = "unrestricted-api" unrestrictedApiAccessKwd = "unrestricted-api"
unencryptTransportKwd = "disable-transport-encryption"
// apiAddrKwd = "address-api" // apiAddrKwd = "address-api"
// swarmAddrKwd = "address-swarm" // swarmAddrKwd = "address-swarm"
) )
...@@ -75,7 +78,8 @@ the port as you would other services or database (firewall, authenticated proxy, ...@@ -75,7 +78,8 @@ the port as you would other services or database (firewall, authenticated proxy,
cmds.BoolOption(writableKwd, "Enable writing objects (with POST, PUT and DELETE)"), cmds.BoolOption(writableKwd, "Enable writing objects (with POST, PUT and DELETE)"),
cmds.StringOption(ipfsMountKwd, "Path to the mountpoint for IPFS (if using --mount)"), cmds.StringOption(ipfsMountKwd, "Path to the mountpoint for IPFS (if using --mount)"),
cmds.StringOption(ipnsMountKwd, "Path to the mountpoint for IPNS (if using --mount)"), cmds.StringOption(ipnsMountKwd, "Path to the mountpoint for IPNS (if using --mount)"),
cmds.BoolOption(unrestrictedApiAccess, "Allow API access to unlisted hashes"), cmds.BoolOption(unrestrictedApiAccessKwd, "Allow API access to unlisted hashes"),
cmds.BoolOption(unencryptTransportKwd, "Disable transport encryption (for debugging protocols)"),
// TODO: add way to override addresses. tricky part: updating the config if also --init. // TODO: add way to override addresses. tricky part: updating the config if also --init.
// cmds.StringOption(apiAddrKwd, "Address for the daemon rpc API (overrides config)"), // cmds.StringOption(apiAddrKwd, "Address for the daemon rpc API (overrides config)"),
...@@ -109,6 +113,14 @@ func daemonFunc(req cmds.Request, res cmds.Response) { ...@@ -109,6 +113,14 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
} }
}() }()
// check transport encryption flag.
unencrypted, _, _ := req.Option(unencryptTransportKwd).Bool()
if unencrypted {
log.Warningf(`Running with --%s: All connections are UNENCRYPTED.
You will not be able to connect to regular encrypted networks.`, unencryptTransportKwd)
conn.EncryptConnections = false
}
// first, whether user has provided the initialization flag. we may be // first, whether user has provided the initialization flag. we may be
// running in an uninitialized state. // running in an uninitialized state.
initialize, _, err := req.Option(initOptionKwd).Bool() initialize, _, err := req.Option(initOptionKwd).Bool()
...@@ -179,6 +191,8 @@ func daemonFunc(req cmds.Request, res cmds.Response) { ...@@ -179,6 +191,8 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
return return
} }
printSwarmAddrs(node)
defer func() { defer func() {
// We wait for the node to close first, as the node has children // We wait for the node to close first, as the node has children
// that it will wait for before closing, such as the API server. // that it will wait for before closing, such as the API server.
...@@ -256,9 +270,9 @@ func serveHTTPApi(req cmds.Request) (error, <-chan error) { ...@@ -256,9 +270,9 @@ func serveHTTPApi(req cmds.Request) (error, <-chan error) {
apiMaddr = apiLis.Multiaddr() apiMaddr = apiLis.Multiaddr()
fmt.Printf("API server listening on %s\n", apiMaddr) fmt.Printf("API server listening on %s\n", apiMaddr)
unrestricted, _, err := req.Option(unrestrictedApiAccess).Bool() unrestricted, _, err := req.Option(unrestrictedApiAccessKwd).Bool()
if err != nil { if err != nil {
return fmt.Errorf("serveHTTPApi: Option(%s) failed: %s", unrestrictedApiAccess, err), nil return fmt.Errorf("serveHTTPApi: Option(%s) failed: %s", unrestrictedApiAccessKwd, err), nil
} }
apiGw := corehttp.NewGateway(corehttp.GatewayConfig{ apiGw := corehttp.NewGateway(corehttp.GatewayConfig{
...@@ -305,6 +319,19 @@ func serveHTTPApi(req cmds.Request) (error, <-chan error) { ...@@ -305,6 +319,19 @@ func serveHTTPApi(req cmds.Request) (error, <-chan error) {
return nil, errc return nil, errc
} }
// printSwarmAddrs prints the addresses of the host
func printSwarmAddrs(node *core.IpfsNode) {
var addrs []string
for _, addr := range node.PeerHost.Addrs() {
addrs = append(addrs, addr.String())
}
sort.Sort(sort.StringSlice(addrs))
for _, addr := range addrs {
fmt.Printf("Swarm listening on %s\n", addr)
}
}
// serveHTTPGateway collects options, creates listener, prints status message and starts serving requests // serveHTTPGateway collects options, creates listener, prints status message and starts serving requests
func serveHTTPGateway(req cmds.Request) (error, <-chan error) { func serveHTTPGateway(req cmds.Request) (error, <-chan error) {
cfg, err := req.Context().GetConfig() cfg, err := req.Context().GetConfig()
......
...@@ -46,6 +46,7 @@ ipfs id supports the format option for output with the following keys: ...@@ -46,6 +46,7 @@ ipfs id supports the format option for output with the following keys:
<aver>: agent version <aver>: agent version
<pver>: protocol version <pver>: protocol version
<pubkey>: public key <pubkey>: public key
<addrs>: addresses (newline delimited)
`, `,
}, },
Arguments: []cmds.Argument{ Arguments: []cmds.Argument{
...@@ -119,6 +120,9 @@ ipfs id supports the format option for output with the following keys: ...@@ -119,6 +120,9 @@ ipfs id supports the format option for output with the following keys:
output = strings.Replace(output, "<aver>", val.AgentVersion, -1) output = strings.Replace(output, "<aver>", val.AgentVersion, -1)
output = strings.Replace(output, "<pver>", val.ProtocolVersion, -1) output = strings.Replace(output, "<pver>", val.ProtocolVersion, -1)
output = strings.Replace(output, "<pubkey>", val.PublicKey, -1) output = strings.Replace(output, "<pubkey>", val.PublicKey, -1)
output = strings.Replace(output, "<addrs>", strings.Join(val.Addresses, "\n"), -1)
output = strings.Replace(output, "\\n", "\n", -1)
output = strings.Replace(output, "\\t", "\t", -1)
return strings.NewReader(output), nil return strings.NewReader(output), nil
} else { } else {
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"path"
"sort" "sort"
cmds "github.com/ipfs/go-ipfs/commands" cmds "github.com/ipfs/go-ipfs/commands"
...@@ -91,6 +92,9 @@ var swarmAddrsCmd = &cmds.Command{ ...@@ -91,6 +92,9 @@ var swarmAddrsCmd = &cmds.Command{
ipfs swarm addrs lists all addresses this node is aware of. ipfs swarm addrs lists all addresses this node is aware of.
`, `,
}, },
Subcommands: map[string]*cmds.Command{
"local": swarmAddrsLocalCmd,
},
Run: func(req cmds.Request, res cmds.Response) { Run: func(req cmds.Request, res cmds.Response) {
n, err := req.Context().GetNode() n, err := req.Context().GetNode()
...@@ -144,6 +148,50 @@ ipfs swarm addrs lists all addresses this node is aware of. ...@@ -144,6 +148,50 @@ ipfs swarm addrs lists all addresses this node is aware of.
Type: addrMap{}, Type: addrMap{},
} }
var swarmAddrsLocalCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "List local addresses.",
ShortDescription: `
ipfs swarm addrs local lists all local addresses the node is listening on.
`,
},
Options: []cmds.Option{
cmds.BoolOption("id", "Show peer ID in addresses"),
},
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.ErrClient)
return
}
showid, _, _ := req.Option("id").Bool()
id := n.Identity.Pretty()
var addrs []string
for _, addr := range n.PeerHost.Addrs() {
saddr := addr.String()
if showid {
saddr = path.Join(saddr, "ipfs", id)
}
addrs = append(addrs, saddr)
}
sort.Sort(sort.StringSlice(addrs))
res.SetOutput(&stringList{addrs})
},
Type: stringList{},
Marshalers: cmds.MarshalerMap{
cmds.Text: stringListMarshaler,
},
}
var swarmConnectCmd = &cmds.Command{ var swarmConnectCmd = &cmds.Command{
Helptext: cmds.HelpText{ Helptext: cmds.HelpText{
Tagline: "Open connection to a given address", Tagline: "Open connection to a given address",
......
...@@ -60,7 +60,7 @@ func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) ( ...@@ -60,7 +60,7 @@ func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (
return return
} }
if d.PrivateKey == nil { if d.PrivateKey == nil || EncryptConnections == false {
log.Warning("dialer %s dialing INSECURELY %s at %s!", d, remote, raddr) log.Warning("dialer %s dialing INSECURELY %s at %s!", d, remote, raddr)
connOut = c connOut = c
return return
......
...@@ -93,3 +93,11 @@ type Listener interface { ...@@ -93,3 +93,11 @@ type Listener interface {
// Any blocked Accept operations will be unblocked and return errors. // Any blocked Accept operations will be unblocked and return errors.
Close() error Close() error
} }
// EncryptConnections is a global parameter because it should either be
// enabled or _completely disabled_. I.e. a node should only be able to talk
// to proper (encrypted) networks if it is encrypting all its transports.
// Running a node with disabled transport encryption is useful to debug the
// protocols, achieve implementation interop, or for private networks which
// -- for whatever reason -- _must_ run unencrypted.
var EncryptConnections = true
...@@ -107,7 +107,7 @@ func (l *listener) Accept() (net.Conn, error) { ...@@ -107,7 +107,7 @@ func (l *listener) Accept() (net.Conn, error) {
return nil, err return nil, err
} }
if l.privk == nil { if l.privk == nil || EncryptConnections == false {
log.Warning("listener %s listening INSECURELY!", l) log.Warning("listener %s listening INSECURELY!", l)
return c, nil return c, nil
} }
......
...@@ -43,24 +43,30 @@ func TestNotifications(t *testing.T) { ...@@ -43,24 +43,30 @@ func TestNotifications(t *testing.T) {
for i, s := range nets { for i, s := range nets {
n := notifiees[i] n := notifiees[i]
for _, s2 := range nets { for _, s2 := range nets {
cos := s.ConnsToPeer(s2.LocalPeer()) var actual []inet.Conn
func() { for len(s.ConnsToPeer(s2.LocalPeer())) != len(actual) {
for i := 0; i < len(cos); i++ { select {
var c inet.Conn case c := <-n.connected:
select { actual = append(actual, c)
case c = <-n.connected: case <-time.After(timeout):
case <-time.After(timeout): t.Fatal("timeout")
t.Fatal("timeout") }
} }
for _, c2 := range cos {
if c == c2 { expect := s.ConnsToPeer(s2.LocalPeer())
t.Log("got notif for conn") for _, c1 := range actual {
return found := false
} for _, c2 := range expect {
if c1 == c2 {
found = true
break
} }
}
if !found {
t.Error("connection not found") t.Error("connection not found")
} }
}() }
} }
} }
......
...@@ -11,8 +11,6 @@ import ( ...@@ -11,8 +11,6 @@ import (
) )
func TestNotifications(t *testing.T) { func TestNotifications(t *testing.T) {
t.Parallel()
ctx := context.Background() ctx := context.Background()
swarms := makeSwarms(ctx, t, 5) swarms := makeSwarms(ctx, t, 5)
defer func() { defer func() {
...@@ -44,24 +42,30 @@ func TestNotifications(t *testing.T) { ...@@ -44,24 +42,30 @@ func TestNotifications(t *testing.T) {
continue continue
} }
cos := s.ConnectionsToPeer(s2.LocalPeer()) var actual []inet.Conn
func() { for len(s.ConnectionsToPeer(s2.LocalPeer())) != len(actual) {
for i := 0; i < len(cos); i++ { select {
var c inet.Conn case c := <-n.connected:
select { actual = append(actual, c)
case c = <-n.connected: case <-time.After(timeout):
case <-time.After(timeout): t.Fatal("timeout")
t.Fatal("timeout") }
} }
for _, c2 := range cos {
if c == c2 { expect := s.ConnectionsToPeer(s2.LocalPeer())
t.Log("got notif for conn", c) for _, c1 := range actual {
return found := false
} for _, c2 := range expect {
if c1 == c2 {
found = true
break
} }
t.Error("connection not found", c)
} }
}() if !found {
t.Error("connection not found")
}
}
} }
} }
......
...@@ -325,6 +325,6 @@ func TestFilterBounds(t *testing.T) { ...@@ -325,6 +325,6 @@ func TestFilterBounds(t *testing.T) {
case <-time.After(time.Second): case <-time.After(time.Second):
t.Fatal("should have gotten connection") t.Fatal("should have gotten connection")
case <-conns: case <-conns:
fmt.Println("got connect") t.Log("got connect")
} }
} }
...@@ -193,8 +193,10 @@ test_config_ipfs_gateway_writable() { ...@@ -193,8 +193,10 @@ test_config_ipfs_gateway_writable() {
test_launch_ipfs_daemon() { test_launch_ipfs_daemon() {
args=$1
test_expect_success "'ipfs daemon' succeeds" ' test_expect_success "'ipfs daemon' succeeds" '
ipfs daemon >actual_daemon 2>daemon_err & ipfs daemon $args >actual_daemon 2>daemon_err &
' '
# we say the daemon is ready when the API server is ready. # we say the daemon is ready when the API server is ready.
......
...@@ -8,6 +8,8 @@ test_description="Test daemon command" ...@@ -8,6 +8,8 @@ test_description="Test daemon command"
. lib/test-lib.sh . lib/test-lib.sh
# TODO: randomize ports here once we add --config to ipfs daemon
# this needs to be in a different test than "ipfs daemon --init" below # this needs to be in a different test than "ipfs daemon --init" below
test_expect_success "setup IPFS_PATH" ' test_expect_success "setup IPFS_PATH" '
IPFS_PATH="$(pwd)/.ipfs" && IPFS_PATH="$(pwd)/.ipfs" &&
...@@ -17,7 +19,7 @@ test_expect_success "setup IPFS_PATH" ' ...@@ -17,7 +19,7 @@ test_expect_success "setup IPFS_PATH" '
# NOTE: this should remove bootstrap peers (needs a flag) # NOTE: this should remove bootstrap peers (needs a flag)
# TODO(cryptix): # TODO(cryptix):
# - we won't see daemon startup failure because we put the daemon in the background - fix: fork with exit code after api listen # - we won't see daemon startup failure because we put the daemon in the background - fix: fork with exit code after api listen
# - also default ports: might clash with local clients. Failure in that case isn't clear as well because pollEndpoint just uses the already running node # - also default ports: might clash with local clients. Failure in that case isn't clear as well because pollEndpoint just uses the already running node
test_expect_success "ipfs daemon --init launches" ' test_expect_success "ipfs daemon --init launches" '
ipfs daemon --init >actual_daemon 2>daemon_err & ipfs daemon --init >actual_daemon 2>daemon_err &
' '
...@@ -34,6 +36,11 @@ test_expect_success "'ipfs config Identity.PeerID' works" ' ...@@ -34,6 +36,11 @@ test_expect_success "'ipfs config Identity.PeerID' works" '
ipfs config Identity.PeerID >config_peerId ipfs config Identity.PeerID >config_peerId
' '
test_expect_success "'ipfs swarm addrs local' works" '
ipfs swarm addrs local >local_addrs
'
# this is lifted straight from t0020-init.sh # this is lifted straight from t0020-init.sh
test_expect_success "ipfs peer id looks good" ' test_expect_success "ipfs peer id looks good" '
PEERID=$(cat config_peerId) && PEERID=$(cat config_peerId) &&
...@@ -58,6 +65,7 @@ test_expect_success "ipfs daemon output looks good" ' ...@@ -58,6 +65,7 @@ test_expect_success "ipfs daemon output looks good" '
echo "peer identity: $PEERID" >>expected_daemon && echo "peer identity: $PEERID" >>expected_daemon &&
echo "to get started, enter:" >>expected_daemon && echo "to get started, enter:" >>expected_daemon &&
printf "\\n\\t$STARTFILE\\n\\n" >>expected_daemon && printf "\\n\\t$STARTFILE\\n\\n" >>expected_daemon &&
cat local_addrs | sed "s/^/Swarm listening on /" >>expected_daemon &&
echo "API server listening on /ip4/127.0.0.1/tcp/5001" >>expected_daemon && echo "API server listening on /ip4/127.0.0.1/tcp/5001" >>expected_daemon &&
echo "Gateway (readonly) server listening on /ip4/127.0.0.1/tcp/8080" >>expected_daemon && echo "Gateway (readonly) server listening on /ip4/127.0.0.1/tcp/8080" >>expected_daemon &&
test_cmp expected_daemon actual_daemon test_cmp expected_daemon actual_daemon
...@@ -91,6 +99,15 @@ test_expect_success "ipfs help output looks good" ' ...@@ -91,6 +99,15 @@ test_expect_success "ipfs help output looks good" '
test_fsh cat help.txt test_fsh cat help.txt
' '
# check transport is encrypted
test_expect_success 'transport should be encrypted' '
nc -w 5 localhost 4001 >swarmnc &&
grep -q "AES-256,AES-128" swarmnc &&
test_must_fail grep -q "/ipfs/identify" swarmnc ||
test_fsh cat swarmnc
'
# end same as in t0010 # end same as in t0010
test_expect_success "daemon is still running" ' test_expect_success "daemon is still running" '
......
#!/bin/sh
#
# Copyright (c) 2014 Juan Batiz-Benet
# MIT Licensed; see the LICENSE file in this repository.
#
test_description="Test daemon command"
. lib/test-lib.sh
test_init_ipfs
test_launch_ipfs_daemon '--unrestricted-api --disable-transport-encryption'
gwyport=$PORT_GWAY
apiport=$PORT_API
test_expect_success 'api gateway should be unrestricted' '
echo "hello mars :$gwyport :$apiport" >expected &&
HASH=$(ipfs add -q expected) &&
curl -sfo actual1 "http://127.0.0.1:$gwyport/ipfs/$HASH" &&
curl -sfo actual2 "http://127.0.0.1:$apiport/ipfs/$HASH" &&
test_cmp expected actual1 &&
test_cmp expected actual2
'
# Odd. this fails here, but the inverse works on t0060-daemon.
test_expect_success 'transport should be unencrypted' '
go-sleep 0.5s | nc localhost "$PORT_SWARM" >swarmnc &&
test_must_fail grep -q "AES-256,AES-128" swarmnc &&
grep -q "/ipfs/identify" swarmnc ||
test_fsh cat swarmnc
'
test_kill_ipfs_daemon
test_done
...@@ -33,6 +33,10 @@ test_expect_success "GET IPFS path output looks good" ' ...@@ -33,6 +33,10 @@ test_expect_success "GET IPFS path output looks good" '
rm actual rm actual
' '
test_expect_success "GET IPFS path on API forbidden" '
test_curl_resp_http_code "http://127.0.0.1:$apiport/ipfs/$HASH" "HTTP/1.1 403 Forbidden"
'
test_expect_success "GET IPFS directory path succeeds" ' test_expect_success "GET IPFS directory path succeeds" '
mkdir dir && mkdir dir &&
echo "12345" >dir/test && echo "12345" >dir/test &&
......
#!/bin/sh
#
# Copyright (c) 2014 Jeromy Johnson
# MIT Licensed; see the LICENSE file in this repository.
#
test_description="Test ipfs swarm command"
. lib/test-lib.sh
test_init_ipfs
test_launch_ipfs_daemon
test_expect_success 'disconnected: peers is empty' '
ipfs swarm peers >actual &&
test_must_be_empty actual
'
test_expect_success 'disconnected: addrs local has localhost' '
ipfs swarm addrs local >actual &&
grep "/ip4/127.0.0.1" actual
'
test_expect_success 'disconnected: addrs local matches ipfs id' '
ipfs id -f="<addrs>\\n" | sort >expected &&
ipfs swarm addrs local --id | sort >actual &&
test_cmp expected actual
'
test_kill_ipfs_daemon
test_done
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论