github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/cmd/seccat/seccat.go (about) 1 // package main provides an implementation of netcat using the secio package. 2 // This means the channel is encrypted (and MACed). 3 // It is meant to exercise the spipe package. 4 // Usage: 5 // seccat [<local address>] <remote address> 6 // seccat -l <local address> 7 // 8 // Address format is: [host]:port 9 package main 10 11 import ( 12 "errors" 13 "flag" 14 "fmt" 15 "io" 16 "net" 17 "os" 18 "os/signal" 19 "syscall" 20 21 ci "github.com/ipfs/go-ipfs/p2p/crypto" 22 secio "github.com/ipfs/go-ipfs/p2p/crypto/secio" 23 peer "github.com/ipfs/go-ipfs/p2p/peer" 24 u "github.com/ipfs/go-ipfs/util" 25 ) 26 27 var verbose = false 28 29 // Usage prints out the usage of this module. 30 // Assumes flags use go stdlib flag pacakage. 31 var Usage = func() { 32 text := `seccat - secure netcat in Go 33 34 Usage: 35 36 listen: %s [<local address>] <remote address> 37 dial: %s -l <local address> 38 39 Address format is Go's: [host]:port 40 ` 41 42 fmt.Fprintf(os.Stderr, text, os.Args[0], os.Args[0]) 43 flag.PrintDefaults() 44 } 45 46 type args struct { 47 listen bool 48 verbose bool 49 debug bool 50 localAddr string 51 remoteAddr string 52 // keyfile string 53 keybits int 54 } 55 56 func parseArgs() args { 57 var a args 58 59 // setup + parse flags 60 flag.BoolVar(&a.listen, "listen", false, "listen for connections") 61 flag.BoolVar(&a.listen, "l", false, "listen for connections (short)") 62 flag.BoolVar(&a.verbose, "v", true, "verbose") 63 flag.BoolVar(&a.debug, "debug", false, "debugging") 64 // flag.StringVar(&a.keyfile, "key", "", "private key file") 65 flag.IntVar(&a.keybits, "keybits", 2048, "num bits for generating private key") 66 flag.Usage = Usage 67 flag.Parse() 68 osArgs := flag.Args() 69 70 if len(osArgs) < 1 { 71 exit("") 72 } 73 74 if a.verbose { 75 out("verbose on") 76 } 77 78 if a.listen { 79 a.localAddr = osArgs[0] 80 } else { 81 if len(osArgs) > 1 { 82 a.localAddr = osArgs[0] 83 a.remoteAddr = osArgs[1] 84 } else { 85 a.remoteAddr = osArgs[0] 86 } 87 } 88 89 return a 90 } 91 92 func main() { 93 args := parseArgs() 94 verbose = args.verbose 95 if args.debug { 96 u.SetDebugLogging() 97 } 98 99 go func() { 100 // wait until we exit. 101 sigc := make(chan os.Signal, 1) 102 signal.Notify(sigc, syscall.SIGABRT) 103 <-sigc 104 panic("ABORT! ABORT! ABORT!") 105 }() 106 107 if err := connect(args); err != nil { 108 exit("%s", err) 109 } 110 } 111 112 func setupPeer(a args) (peer.ID, peer.Peerstore, error) { 113 if a.keybits < 1024 { 114 return "", nil, errors.New("Bitsize less than 1024 is considered unsafe.") 115 } 116 117 out("generating key pair...") 118 sk, pk, err := ci.GenerateKeyPair(ci.RSA, a.keybits) 119 if err != nil { 120 return "", nil, err 121 } 122 123 p, err := peer.IDFromPublicKey(pk) 124 if err != nil { 125 return "", nil, err 126 } 127 128 ps := peer.NewPeerstore() 129 ps.AddPrivKey(p, sk) 130 ps.AddPubKey(p, pk) 131 132 out("local peer id: %s", p) 133 return p, ps, nil 134 } 135 136 func connect(args args) error { 137 p, ps, err := setupPeer(args) 138 if err != nil { 139 return err 140 } 141 142 var conn net.Conn 143 if args.listen { 144 conn, err = Listen(args.localAddr) 145 } else { 146 conn, err = Dial(args.localAddr, args.remoteAddr) 147 } 148 if err != nil { 149 return err 150 } 151 152 // log everything that goes through conn 153 rwc := &logRW{n: "conn", rw: conn} 154 155 // OK, let's setup the channel. 156 sk := ps.PrivKey(p) 157 sg := secio.SessionGenerator{LocalID: p, PrivateKey: sk} 158 sess, err := sg.NewSession(nil, rwc) 159 if err != nil { 160 return err 161 } 162 out("remote peer id: %s", sess.RemotePeer()) 163 netcat(sess.ReadWriter().(io.ReadWriteCloser)) 164 return nil 165 } 166 167 // Listen listens and accepts one incoming UDT connection on a given port, 168 // and pipes all incoming data to os.Stdout. 169 func Listen(localAddr string) (net.Conn, error) { 170 l, err := net.Listen("tcp", localAddr) 171 if err != nil { 172 return nil, err 173 } 174 out("listening at %s", l.Addr()) 175 176 c, err := l.Accept() 177 if err != nil { 178 return nil, err 179 } 180 out("accepted connection from %s", c.RemoteAddr()) 181 182 // done with listener 183 l.Close() 184 185 return c, nil 186 } 187 188 // Dial connects to a remote address and pipes all os.Stdin to the remote end. 189 // If localAddr is set, uses it to Dial from. 190 func Dial(localAddr, remoteAddr string) (net.Conn, error) { 191 192 var laddr net.Addr 193 var err error 194 if localAddr != "" { 195 laddr, err = net.ResolveTCPAddr("tcp", localAddr) 196 if err != nil { 197 return nil, fmt.Errorf("failed to resolve address %s", localAddr) 198 } 199 } 200 201 if laddr != nil { 202 out("dialing %s from %s", remoteAddr, laddr) 203 } else { 204 out("dialing %s", remoteAddr) 205 } 206 207 d := net.Dialer{LocalAddr: laddr} 208 c, err := d.Dial("tcp", remoteAddr) 209 if err != nil { 210 return nil, err 211 } 212 out("connected to %s", c.RemoteAddr()) 213 214 return c, nil 215 } 216 217 func netcat(c io.ReadWriteCloser) { 218 out("piping stdio to connection") 219 220 done := make(chan struct{}, 2) 221 222 go func() { 223 n, _ := io.Copy(c, os.Stdin) 224 out("sent %d bytes", n) 225 done <- struct{}{} 226 }() 227 go func() { 228 n, _ := io.Copy(os.Stdout, c) 229 out("received %d bytes", n) 230 done <- struct{}{} 231 }() 232 233 // wait until we exit. 234 sigc := make(chan os.Signal, 1) 235 signal.Notify(sigc, syscall.SIGHUP, syscall.SIGINT, 236 syscall.SIGTERM, syscall.SIGQUIT) 237 238 select { 239 case <-done: 240 case <-sigc: 241 return 242 } 243 244 c.Close() 245 }