Commit 2d6b787c authored by Juan Batiz-Benet's avatar Juan Batiz-Benet

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

Swarm Addrs, Disable secio opt, + tests
parents c9edbf35 59d6a9a1
......@@ -6,6 +6,7 @@ import (
"net/http"
_ "net/http/pprof"
"os"
"sort"
"strings"
"sync"
......@@ -18,6 +19,7 @@ import (
commands "github.com/ipfs/go-ipfs/core/commands"
corehttp "github.com/ipfs/go-ipfs/core/corehttp"
"github.com/ipfs/go-ipfs/core/corerouting"
conn "github.com/ipfs/go-ipfs/p2p/net/conn"
peer "github.com/ipfs/go-ipfs/p2p/peer"
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
util "github.com/ipfs/go-ipfs/util"
......@@ -31,7 +33,8 @@ const (
writableKwd = "writable"
ipfsMountKwd = "mount-ipfs"
ipnsMountKwd = "mount-ipns"
unrestrictedApiAccess = "unrestricted-api"
unrestrictedApiAccessKwd = "unrestricted-api"
unencryptTransportKwd = "disable-transport-encryption"
// apiAddrKwd = "address-api"
// swarmAddrKwd = "address-swarm"
)
......@@ -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.StringOption(ipfsMountKwd, "Path to the mountpoint for IPFS (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.
// cmds.StringOption(apiAddrKwd, "Address for the daemon rpc API (overrides config)"),
......@@ -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
// running in an uninitialized state.
initialize, _, err := req.Option(initOptionKwd).Bool()
......@@ -179,6 +191,8 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
return
}
printSwarmAddrs(node)
defer func() {
// 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.
......@@ -256,9 +270,9 @@ func serveHTTPApi(req cmds.Request) (error, <-chan error) {
apiMaddr = apiLis.Multiaddr()
fmt.Printf("API server listening on %s\n", apiMaddr)
unrestricted, _, err := req.Option(unrestrictedApiAccess).Bool()
unrestricted, _, err := req.Option(unrestrictedApiAccessKwd).Bool()
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{
......@@ -305,6 +319,19 @@ func serveHTTPApi(req cmds.Request) (error, <-chan error) {
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
func serveHTTPGateway(req cmds.Request) (error, <-chan error) {
cfg, err := req.Context().GetConfig()
......
......@@ -46,6 +46,7 @@ ipfs id supports the format option for output with the following keys:
<aver>: agent version
<pver>: protocol version
<pubkey>: public key
<addrs>: addresses (newline delimited)
`,
},
Arguments: []cmds.Argument{
......@@ -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, "<pver>", val.ProtocolVersion, -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
} else {
......
......@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"io"
"path"
"sort"
cmds "github.com/ipfs/go-ipfs/commands"
......@@ -91,6 +92,9 @@ var swarmAddrsCmd = &cmds.Command{
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) {
n, err := req.Context().GetNode()
......@@ -144,6 +148,50 @@ ipfs swarm addrs lists all addresses this node is aware of.
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{
Helptext: cmds.HelpText{
Tagline: "Open connection to a given address",
......
......@@ -60,7 +60,7 @@ func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (
return
}
if d.PrivateKey == nil {
if d.PrivateKey == nil || EncryptConnections == false {
log.Warning("dialer %s dialing INSECURELY %s at %s!", d, remote, raddr)
connOut = c
return
......
......@@ -93,3 +93,11 @@ type Listener interface {
// Any blocked Accept operations will be unblocked and return errors.
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) {
return nil, err
}
if l.privk == nil {
if l.privk == nil || EncryptConnections == false {
log.Warning("listener %s listening INSECURELY!", l)
return c, nil
}
......
......@@ -43,24 +43,30 @@ func TestNotifications(t *testing.T) {
for i, s := range nets {
n := notifiees[i]
for _, s2 := range nets {
cos := s.ConnsToPeer(s2.LocalPeer())
func() {
for i := 0; i < len(cos); i++ {
var c inet.Conn
select {
case c = <-n.connected:
case <-time.After(timeout):
t.Fatal("timeout")
}
for _, c2 := range cos {
if c == c2 {
t.Log("got notif for conn")
return
}
var actual []inet.Conn
for len(s.ConnsToPeer(s2.LocalPeer())) != len(actual) {
select {
case c := <-n.connected:
actual = append(actual, c)
case <-time.After(timeout):
t.Fatal("timeout")
}
}
expect := s.ConnsToPeer(s2.LocalPeer())
for _, c1 := range actual {
found := false
for _, c2 := range expect {
if c1 == c2 {
found = true
break
}
}
if !found {
t.Error("connection not found")
}
}()
}
}
}
......
......@@ -11,8 +11,6 @@ import (
)
func TestNotifications(t *testing.T) {
t.Parallel()
ctx := context.Background()
swarms := makeSwarms(ctx, t, 5)
defer func() {
......@@ -44,24 +42,30 @@ func TestNotifications(t *testing.T) {
continue
}
cos := s.ConnectionsToPeer(s2.LocalPeer())
func() {
for i := 0; i < len(cos); i++ {
var c inet.Conn
select {
case c = <-n.connected:
case <-time.After(timeout):
t.Fatal("timeout")
}
for _, c2 := range cos {
if c == c2 {
t.Log("got notif for conn", c)
return
}
var actual []inet.Conn
for len(s.ConnectionsToPeer(s2.LocalPeer())) != len(actual) {
select {
case c := <-n.connected:
actual = append(actual, c)
case <-time.After(timeout):
t.Fatal("timeout")
}
}
expect := s.ConnectionsToPeer(s2.LocalPeer())
for _, c1 := range actual {
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) {
case <-time.After(time.Second):
t.Fatal("should have gotten connection")
case <-conns:
fmt.Println("got connect")
t.Log("got connect")
}
}
......@@ -193,8 +193,10 @@ test_config_ipfs_gateway_writable() {
test_launch_ipfs_daemon() {
args=$1
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.
......
......@@ -8,6 +8,8 @@ test_description="Test daemon command"
. 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
test_expect_success "setup IPFS_PATH" '
IPFS_PATH="$(pwd)/.ipfs" &&
......@@ -17,7 +19,7 @@ test_expect_success "setup IPFS_PATH" '
# NOTE: this should remove bootstrap peers (needs a flag)
# 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
# - 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" '
ipfs daemon --init >actual_daemon 2>daemon_err &
'
......@@ -34,6 +36,11 @@ test_expect_success "'ipfs config Identity.PeerID' works" '
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
test_expect_success "ipfs peer id looks good" '
PEERID=$(cat config_peerId) &&
......@@ -58,6 +65,7 @@ test_expect_success "ipfs daemon output looks good" '
echo "peer identity: $PEERID" >>expected_daemon &&
echo "to get started, enter:" >>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 "Gateway (readonly) server listening on /ip4/127.0.0.1/tcp/8080" >>expected_daemon &&
test_cmp expected_daemon actual_daemon
......@@ -91,6 +99,15 @@ test_expect_success "ipfs help output looks good" '
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
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" '
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" '
mkdir dir &&
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 is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment