Skip to content

Commit

Permalink
Merge pull request #442 from jbenet/io-spipe
Browse files Browse the repository at this point in the history
secio, spipe replacement
  • Loading branch information
jbenet committed Dec 12, 2014
2 parents a62b239 + 881f5c9 commit 4a5a742
Show file tree
Hide file tree
Showing 18 changed files with 1,154 additions and 35 deletions.
2 changes: 1 addition & 1 deletion Godeps/Godeps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 13 additions & 4 deletions Godeps/_workspace/src/github.com/jbenet/go-msgio/msgio.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions cmd/ipfs/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import (
"syscall"
"time"

// TODO rm direct reference to go-logging
logging "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-logging"
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"

Expand Down Expand Up @@ -147,7 +145,7 @@ func (i *cmdInvocation) Run(ctx context.Context) (output io.Reader, err error) {
}
if debug || u.GetenvBool("DEBUG") || os.Getenv("IPFS_LOGGING") == "debug" {
u.Debug = true
u.SetAllLoggers(logging.DEBUG)
u.SetDebugLogging()
}

// if debugging, let's profile.
Expand Down
1 change: 1 addition & 0 deletions cmd/seccat/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
seccat
240 changes: 240 additions & 0 deletions cmd/seccat/seccat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
// package main provides an implementation of netcat using the secio package.
// This means the channel is encrypted (and MACed).
// It is meant to exercise the spipe package.
// Usage:
// seccat [<local address>] <remote address>
// seccat -l <local address>
//
// Address format is: [host]:port
package main

import (
"errors"
"flag"
"fmt"
"io"
"net"
"os"
"os/signal"
"syscall"

ci "github.com/jbenet/go-ipfs/crypto"
secio "github.com/jbenet/go-ipfs/crypto/secio"
peer "github.com/jbenet/go-ipfs/peer"
u "github.com/jbenet/go-ipfs/util"
)

var verbose = false

// Usage prints out the usage of this module.
// Assumes flags use go stdlib flag pacakage.
var Usage = func() {
text := `seccat - secure netcat in Go
Usage:
listen: %s [<local address>] <remote address>
dial: %s -l <local address>
Address format is Go's: [host]:port
`

fmt.Fprintf(os.Stderr, text, os.Args[0], os.Args[0])
flag.PrintDefaults()
}

type args struct {
listen bool
verbose bool
debug bool
localAddr string
remoteAddr string
// keyfile string
keybits int
}

func parseArgs() args {
var a args

// setup + parse flags
flag.BoolVar(&a.listen, "listen", false, "listen for connections")
flag.BoolVar(&a.listen, "l", false, "listen for connections (short)")
flag.BoolVar(&a.verbose, "v", true, "verbose")
flag.BoolVar(&a.debug, "debug", false, "debugging")
// flag.StringVar(&a.keyfile, "key", "", "private key file")
flag.IntVar(&a.keybits, "keybits", 2048, "num bits for generating private key")
flag.Usage = Usage
flag.Parse()
osArgs := flag.Args()

if len(osArgs) < 1 {
exit("")
}

if a.verbose {
out("verbose on")
}

if a.listen {
a.localAddr = osArgs[0]
} else {
if len(osArgs) > 1 {
a.localAddr = osArgs[0]
a.remoteAddr = osArgs[1]
} else {
a.remoteAddr = osArgs[0]
}
}

return a
}

func main() {
args := parseArgs()
verbose = args.verbose
if args.debug {
u.SetDebugLogging()
}

go func() {
// wait until we exit.
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, syscall.SIGABRT)
<-sigc
panic("ABORT! ABORT! ABORT!")
}()

if err := connect(args); err != nil {
exit("%s", err)
}
}

func setupPeer(a args) (peer.Peer, peer.Peerstore, error) {
if a.keybits < 1024 {
return nil, nil, errors.New("Bitsize less than 1024 is considered unsafe.")
}

out("generating key pair...")
sk, pk, err := ci.GenerateKeyPair(ci.RSA, a.keybits)
if err != nil {
return nil, nil, err
}

ps := peer.NewPeerstore()
peer, err := ps.WithKeyPair(sk, pk)
if err != nil {
return nil, nil, err
}
out("local peer id: %s", peer.ID())
return peer, ps, nil
}

func connect(args args) error {
p, ps, err := setupPeer(args)
if err != nil {
return err
}

var conn net.Conn
if args.listen {
conn, err = Listen(args.localAddr)
} else {
conn, err = Dial(args.localAddr, args.remoteAddr)
}
if err != nil {
return err
}

// log everything that goes through conn
rwc := &logRW{n: "conn", rw: conn}

// OK, let's setup the channel.
sg := secio.SessionGenerator{Local: p, Peerstore: ps}
sess, err := sg.NewSession(nil, rwc)
if err != nil {
return err
}
out("remote peer id: %s", sess.RemotePeer().ID())
netcat(sess.ReadWriter().(io.ReadWriteCloser))
return nil
}

// Listen listens and accepts one incoming UDT connection on a given port,
// and pipes all incoming data to os.Stdout.
func Listen(localAddr string) (net.Conn, error) {
l, err := net.Listen("tcp", localAddr)
if err != nil {
return nil, err
}
out("listening at %s", l.Addr())

c, err := l.Accept()
if err != nil {
return nil, err
}
out("accepted connection from %s", c.RemoteAddr())

// done with listener
l.Close()

return c, nil
}

// Dial connects to a remote address and pipes all os.Stdin to the remote end.
// If localAddr is set, uses it to Dial from.
func Dial(localAddr, remoteAddr string) (net.Conn, error) {

var laddr net.Addr
var err error
if localAddr != "" {
laddr, err = net.ResolveTCPAddr("tcp", localAddr)
if err != nil {
return nil, fmt.Errorf("failed to resolve address %s", localAddr)
}
}

if laddr != nil {
out("dialing %s from %s", remoteAddr, laddr)
} else {
out("dialing %s", remoteAddr)
}

d := net.Dialer{LocalAddr: laddr}
c, err := d.Dial("tcp", remoteAddr)
if err != nil {
return nil, err
}
out("connected to %s", c.RemoteAddr())

return c, nil
}

func netcat(c io.ReadWriteCloser) {
out("piping stdio to connection")

done := make(chan struct{}, 2)

go func() {
n, _ := io.Copy(c, os.Stdin)
out("sent %d bytes", n)
done <- struct{}{}
}()
go func() {
n, _ := io.Copy(os.Stdout, c)
out("received %d bytes", n)
done <- struct{}{}
}()

// wait until we exit.
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, syscall.SIGHUP, syscall.SIGINT,
syscall.SIGTERM, syscall.SIGQUIT)

select {
case <-done:
case <-sigc:
return
}

c.Close()
}
51 changes: 51 additions & 0 deletions cmd/seccat/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package main

import (
"fmt"
"io"
"os"

eventlog "github.com/jbenet/go-ipfs/util/eventlog"
)

var log = eventlog.Logger("seccat")

func exit(format string, vals ...interface{}) {
if format != "" {
fmt.Fprintf(os.Stderr, "seccat: error: "+format+"\n", vals...)
}
Usage()
os.Exit(1)
}

func out(format string, vals ...interface{}) {
if verbose {
fmt.Fprintf(os.Stderr, "seccat: "+format+"\n", vals...)
}
}

type logRW struct {
n string
rw io.ReadWriter
}

func (r *logRW) Read(buf []byte) (int, error) {
n, err := r.rw.Read(buf)
if err == nil {
log.Debugf("%s read: %v", r.n, buf)
}
return n, err
}

func (r *logRW) Write(buf []byte) (int, error) {
log.Debugf("%s write: %v", r.n, buf)
return r.rw.Write(buf)
}

func (r *logRW) Close() error {
c, ok := r.rw.(io.Closer)
if ok {
return c.Close()
}
return nil
}
Loading

0 comments on commit 4a5a742

Please sign in to comment.