Git Product home page Git Product logo

croc's Introduction

croc
Version Coverage Build
Status

This project is supported by Github sponsors.

croc is a tool that allows any two computers to simply and securely transfer files and folders. AFAIK, croc is the only CLI file-transfer tool that does all of the following:

  • allows any two computers to transfer data (using a relay)
  • provides end-to-end encryption (using PAKE)
  • enables easy cross-platform transfers (Windows, Linux, Mac)
  • allows multiple file transfers
  • allows resuming transfers that are interrupted
  • local server or port-forwarding not needed
  • ipv6-first with ipv4 fallback
  • can use proxy, like tor

For more information about croc, see my blog post or read a recent interview I did.

Example

Install

Download the latest release for your system, or install a release from the command-line:

curl https://getcroc.schollz.com | bash

On macOS you can install the latest release with Homebrew:

brew install croc

On macOS you can also install the latest release with MacPorts:

sudo port selfupdate
sudo port install croc

On Windows you can install the latest release with Scoop, Chocolatey, or Winget:

scoop install croc
choco install croc
winget install schollz.croc

On Unix you can install the latest release with Nix:

nix-env -i croc

On Alpine Linux you have to install dependencies first:

apk add bash coreutils
wget -qO- https://getcroc.schollz.com | bash

On Arch Linux you can install the latest release with pacman:

pacman -S croc

On Fedora you can install with dnf:

dnf install croc

On Gentoo you can install with portage:

emerge net-misc/croc

On Termux you can install with pkg:

pkg install croc

On FreeBSD you can install with pkg:

pkg install croc

Or, you can install Go and build from source (requires Go 1.17+):

go install github.com/schollz/croc/v9@latest

On Android there is a 3rd party F-Droid app available to download.

Usage

To send a file, simply do:

$ croc send [file(s)-or-folder]
Sending 'file-or-folder' (X MB)
Code is: code-phrase

Then to receive the file (or folder) on another computer, you can just do

croc code-phrase

The code phrase is used to establish password-authenticated key agreement (PAKE) which generates a secret key for the sender and recipient to use for end-to-end encryption.

There are a number of configurable options (see --help). A set of options (like custom relay, ports, and code phrase) can be set using --remember.

Custom code phrase

You can send with your own code phrase (must be more than 6 characters).

croc send --code [code-phrase] [file(s)-or-folder]

Allow overwriting without prompt

By default, croc will prompt whether to overwrite a file. You can automatically overwrite files by using the --overwrite flag (recipient only). For example, receive a file to automatically overwrite:

croc --yes --overwrite <code>

Use pipes - stdin and stdout

You can pipe to croc:

cat [filename] | croc send

In this case croc will automatically use the stdin data and send and assign a filename like "croc-stdin-123456789". To receive to stdout at you can always just use the --yes will automatically approve the transfer and pipe it out to stdout.

croc --yes [code-phrase] > out

All of the other text printed to the console is going to stderr so it will not interfere with the message going to stdout.

Send text

Sometimes you want to send URLs or short text. In addition to piping, you can easily send text with croc:

croc send --text "hello world"

This will automatically tell the receiver to use stdout when they receive the text so it will be displayed.

Use a proxy

You can use a proxy as your connection to the relay by adding a proxy address with --socks5. For example, you can send via a tor relay:

croc --socks5 "127.0.0.1:9050" send SOMEFILE

Change encryption curve

You can choose from several different elliptic curves to use for encryption by using the --curve flag. Only the recipient can choose the curve. For example, receive a file using the P-521 curve:

croc --curve p521 <codephrase>

Available curves are P-256, P-348, P-521 and SIEC. P-256 is the default curve.

Change hash algorithm

You can choose from several different hash algorithms. The default is the xxhash algorithm which is fast and thorough. If you want to optimize for speed you can use the imohash algorithm which is even faster, but since it samples files (versus reading the whole file) it can mistakenly determine that a file is the same on the two computers transferring - though this is only a problem if you are syncing files versus sending a new file to a computer.

croc send --hash imohash SOMEFILE

Self-host relay

The relay is needed to staple the parallel incoming and outgoing connections. By default, croc uses a public relay but you can also run your own relay:

croc relay

By default it uses TCP ports 9009-9013. Make sure to open those up. You can customize the ports (e.g. croc relay --ports 1111,1112), but you must have a minimum of 2 ports for the relay. The first port is for communication and the subsequent ports are used for the multiplexed data transfer.

You can send files using your relay by entering --relay to change the relay that you are using if you want to custom host your own.

croc --relay "myrelay.example.com:9009" send [filename]

Note, when sending, you only need to include the first port (the communication port). The subsequent ports for data transfer will be transmitted back to the user from the relay.

Self-host relay (docker)

If it's easier you can also run a relay with Docker:

docker run -d -p 9009-9013:9009-9013 -e CROC_PASS='YOURPASSWORD' schollz/croc

Be sure to include the password for the relay otherwise any requests will be rejected.

croc --pass YOURPASSWORD --relay "myreal.example.com:9009" send [filename]

Note: when including --pass YOURPASSWORD you can instead pass a file with the password, e.g. --pass FILEWITHPASSWORD.

License

MIT

Acknowledgements

croc has gone through many iterations, and I am awed by all the great contributions! If you feel like contributing, in any way, by all means you can send an Issue, a PR, or ask a question.

Thanks @warner for the idea, @tscholl2 for the encryption gists, @skorokithakis for code on proxying two connections. Finally thanks for making pull requests @maximbaz, @meyermarcel, @Girbons, @techtide, @heymatthew, @Lunsford94, @lummie, @jesuiscamille, @threefjord, @marcossegovia, @csleong98, @afotescu, @callmefever, @El-JojA, @anatolyyyyyy, @goggle, @smileboywtu, @nicolashardy, @fbartels, @rkuprov, @hreese, @xenrox and Ipar!

croc's People

Contributors

a1lu avatar afotescu avatar baylee4 avatar chtjonas avatar clouedoc avatar dependabot[bot] avatar el-joja avatar fooofei avatar goggle avatar iulius98 avatar jolheiser avatar lpar avatar lummie avatar masterzsh avatar maximbaz avatar nikoksr avatar nkhang avatar qk-santi avatar rain-1 avatar rcl98 avatar schollz avatar sitiom avatar smileboywtu avatar spaceface16518 avatar stefins avatar taigrr avatar thequeasle avatar threefjord avatar v-r-dighe avatar xenrox avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

croc's Issues

Make using one connection the default.

I don't really see a big benefit of having multiple connections open to send/receive a file over the network. The current default of "number of connections" is currently set to 4. I think croc should respect the KISS principle, so it would be good to have the "number of connections" option set to 1 as default. It is nice to have this feature though.

Is it possible to have this changed?

data race

Whenever try receive smt data race pops up

croc -send connect.go

                                ,_
                               >' )
   croc version                ( ( \
                                || \
                 /^^^^\         ||
    /^^\________/0     \        ||
   (                    `~+++,,_||__,,++~^^^^^^^
 ...V^V^V^V^V^V^\...............................


Enter receive code: 4-octavia-lecture-india
==================
WARNING: DATA RACE
Write at 0x00c4200b8190 by goroutine 12:
  reflect.Value.SetString()
      /usr/local/Cellar/go/1.9.1/libexec/src/reflect/value.go:1531 +0x64
  encoding/json.(*decodeState).literalStore()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:939 +0x2868
  encoding/json.(*decodeState).literal()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:802 +0x16c
  encoding/json.(*decodeState).value()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:408 +0x186
  encoding/json.(*decodeState).object()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:736 +0x169d
  encoding/json.(*decodeState).value()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:405 +0x149
  encoding/json.(*decodeState).unmarshal()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:187 +0x2db
  encoding/json.Unmarshal()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:107 +0x20e
  main.(*Connection).runClient.func1()
      /Users/callmeanyhow/go/src/croc/connect.go:314 +0x11a9

Previous read at 0x00c4200b8190 by goroutine 10:
  runtime.convT2E()
      /usr/local/Cellar/go/1.9.1/libexec/src/runtime/iface.go:201 +0x0
  main.(*Connection).runClient.func1()
      /Users/callmeanyhow/go/src/croc/connect.go:320 +0x12cd

Goroutine 12 (running) created at:
  main.(*Connection).runClient()
      /Users/callmeanyhow/go/src/croc/connect.go:231 +0x510
  main.(*Connection).Run()
      /Users/callmeanyhow/go/src/croc/connect.go:206 +0x80b
  main.main()
      /Users/callmeanyhow/go/src/croc/main.go:66 +0x573

Goroutine 10 (running) created at:
  main.(*Connection).runClient()
      /Users/callmeanyhow/go/src/croc/connect.go:231 +0x510
  main.(*Connection).Run()
      /Users/callmeanyhow/go/src/croc/connect.go:206 +0x80b
  main.main()
      /Users/callmeanyhow/go/src/croc/main.go:66 +0x573
==================
==================
WARNING: DATA RACE
Write at 0x00c4200b81a0 by goroutine 12:
  reflect.Value.SetInt()
      /usr/local/Cellar/go/1.9.1/libexec/src/reflect/value.go:1425 +0x107
  encoding/json.(*decodeState).literalStore()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:989 +0x213c
  encoding/json.(*decodeState).literal()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:802 +0x16c
  encoding/json.(*decodeState).value()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:408 +0x186
  encoding/json.(*decodeState).object()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:736 +0x169d
  encoding/json.(*decodeState).value()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:405 +0x149
  encoding/json.(*decodeState).unmarshal()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:187 +0x2db
  encoding/json.Unmarshal()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:107 +0x20e
  main.(*Connection).runClient.func1()
      /Users/callmeanyhow/go/src/croc/connect.go:314 +0x11a9

Previous read at 0x00c4200b81a0 by goroutine 10:
  runtime.convT2E()
      /usr/local/Cellar/go/1.9.1/libexec/src/runtime/iface.go:201 +0x0
  main.(*Connection).runClient.func1()
      /Users/callmeanyhow/go/src/croc/connect.go:320 +0x12cd

Goroutine 12 (running) created at:
  main.(*Connection).runClient()
      /Users/callmeanyhow/go/src/croc/connect.go:231 +0x510
  main.(*Connection).Run()
      /Users/callmeanyhow/go/src/croc/connect.go:206 +0x80b
  main.main()
      /Users/callmeanyhow/go/src/croc/main.go:66 +0x573

Goroutine 10 (running) created at:
  main.(*Connection).runClient()
      /Users/callmeanyhow/go/src/croc/connect.go:231 +0x510
  main.(*Connection).Run()
      /Users/callmeanyhow/go/src/croc/connect.go:206 +0x80b
  main.main()
      /Users/callmeanyhow/go/src/croc/main.go:66 +0x573
==================
==================
WARNING: DATA RACE
Write at 0x00c4200b81c8 by goroutine 12:
  reflect.Value.SetBool()
      /usr/local/Cellar/go/1.9.1/libexec/src/reflect/value.go:1364 +0x60
  encoding/json.(*decodeState).literalStore()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:905 +0x10f7
  encoding/json.(*decodeState).literal()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:802 +0x16c
  encoding/json.(*decodeState).value()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:408 +0x186
  encoding/json.(*decodeState).object()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:736 +0x169d
  encoding/json.(*decodeState).value()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:405 +0x149
  encoding/json.(*decodeState).unmarshal()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:187 +0x2db
  encoding/json.Unmarshal()
      /usr/local/Cellar/go/1.9.1/libexec/src/encoding/json/decode.go:107 +0x20e
  main.(*Connection).runClient.func1()
      /Users/callmeanyhow/go/src/croc/connect.go:314 +0x11a9

Previous read at 0x00c4200b81c8 by goroutine 10:
  runtime.convT2E()
      /usr/local/Cellar/go/1.9.1/libexec/src/runtime/iface.go:201 +0x0
  main.(*Connection).runClient.func1()
      /Users/callmeanyhow/go/src/croc/connect.go:320 +0x12cd

Goroutine 12 (running) created at:
  main.(*Connection).runClient()
      /Users/callmeanyhow/go/src/croc/connect.go:231 +0x510
  main.(*Connection).Run()
      /Users/callmeanyhow/go/src/croc/connect.go:206 +0x80b
  main.main()
      /Users/callmeanyhow/go/src/croc/main.go:66 +0x573

Goroutine 10 (running) created at:
  main.(*Connection).runClient()
      /Users/callmeanyhow/go/src/croc/connect.go:231 +0x510
  main.(*Connection).Run()
      /Users/callmeanyhow/go/src/croc/connect.go:206 +0x80b
  main.main()
      /Users/callmeanyhow/go/src/croc/main.go:66 +0x573
==================
Overwriting file connect.go (16 kB)
ok? (y/n): y
==================
WARNING: DATA RACE
Write at 0x00c4200142f9 by goroutine 7:
  main.(*Connection).runClient.func1()
      /Users/callmeanyhow/go/src/croc/connect.go:351 +0x1c49

Previous read at 0x00c4200142f9 by goroutine 12:
  main.(*Connection).runClient.func1()
      /Users/callmeanyhow/go/src/croc/connect.go:355 +0x13ab

Goroutine 7 (running) created at:
  main.(*Connection).runClient()
      /Users/callmeanyhow/go/src/croc/connect.go:231 +0x510
  main.(*Connection).Run()
      /Users/callmeanyhow/go/src/croc/connect.go:206 +0x80b
  main.main()
      /Users/callmeanyhow/go/src/croc/main.go:66 +0x573

Goroutine 12 (running) created at:
  main.(*Connection).runClient()
      /Users/callmeanyhow/go/src/croc/connect.go:231 +0x510
  main.(*Connection).Run()
      /Users/callmeanyhow/go/src/croc/connect.go:206 +0x80b
  main.main()
      /Users/callmeanyhow/go/src/croc/main.go:66 +0x573
==================


Receiving (<-185.9.230.10123671)..
   0s [====================================================================] 100%
   0s [====================================================================] 100%
   0s [====================================================================] 100%
   0s [====================================================================] 100%
   0s [====================================================================] 100%
   0s [====================================================================] 100%
Found 4 data race(s)

Flag to limit bandwidth for sender

This is very simple.

  1. Add a flag
  2. Add a time.Sleep() after each send, which calculates based on the bandwidth and the BUFFER_SIZE

Ask me if you have questions!

Allow receiving directories

First #33 should be done.

After downloading the file (after this line) there should be an if-statement to check whether the c.File.IsDir == true. If so, then it needs to be untarred and decompressed. This will depend on what #33 uses, but again I suggest using mholt/archiver.

Allow sending of directories

When specified -send FILE its possible that FILE is a directory, in which croc should zip the directory and transfer it as a zipped file. This is pretty easy to implement.

First it should check if flags.File is actually a directory, after this line:

if len(flags.File) > 0 {
.

If it is a directory, then it should zipped it into a local temporary .zip file. Then change flags.File to the new .zip file and set a new FileMetaData variable IsDir (which will need to be created here) to true.

For zipping, I recommend using mholt/archiver.

After this, then we can implement receiving the directory #34.

Print out speed of transfer

After sending or receiving file, print out the rate of transfer in MB/s.

Basically, first there needs to be a timer here (e.g. start:= time.Now()) : https://github.com/schollz/croc/blob/master/connect.go#L214

For receiving the file, you should print out the speed here: https://github.com/schollz/croc/blob/master/connect.go#L468

For sending the file, you should print out the speed here: https://github.com/schollz/croc/blob/master/connect.go#L409

In both cases, the speed is the file size (c.File.Size) divided by the duration (e.g. time.Since(start)), preferably in MB/s.

Please feel free to ask me any questions!

Out of memory

croc version 3.0.6
Send a folder from WIndows 10 to Arch Linux

Sending 5.1 GB folder named 'doc-videos'
Code is: silence-voice-bombay
On the other computer, please run:

croc silence-voice-bombay
- waiting for ok... runtime: VirtualAlloc of 2568749056 bytes failed with errno=1455
fatal error: out of memory

runtime stack:
runtime.throw(0x8a445a, 0xd)
        /usr/local/go/src/runtime/panic.go:616 +0x88
runtime.sysMap(0xc042800000, 0x991c0000, 0x1, 0xb2a6f8)
        /usr/local/go/src/runtime/mem_windows.go:122 +0x13b
runtime.(*mheap).sysAlloc(0xb10f60, 0x991c0000, 0xd53df12d01d419e6)
        /usr/local/go/src/runtime/malloc.go:470 +0xdb
runtime.(*mheap).grow(0xb10f60, 0x4c8dc, 0x0)
        /usr/local/go/src/runtime/mheap.go:907 +0x67
runtime.(*mheap).allocSpanLocked(0xb10f60, 0x4c8dc, 0xb2a708, 0x55005c0000005c)
        /usr/local/go/src/runtime/mheap.go:820 +0x308
runtime.(*mheap).alloc_m(0xb10f60, 0x4c8dc, 0xc0424d0101, 0xc0424d1c80)
        /usr/local/go/src/runtime/mheap.go:686 +0x126
runtime.(*mheap).alloc.func1()
        /usr/local/go/src/runtime/mheap.go:753 +0x54
runtime.(*mheap).alloc(0xb10f60, 0x4c8dc, 0x4010101, 0x4140ba)
        /usr/local/go/src/runtime/mheap.go:752 +0x91
runtime.largeAlloc(0x991b6fc5, 0x440101, 0x1906a8)
        /usr/local/go/src/runtime/malloc.go:826 +0x9b
runtime.mallocgc.func1()
        /usr/local/go/src/runtime/malloc.go:721 +0x4d
runtime.systemstack(0x0)
        /usr/local/go/src/runtime/asm_amd64.s:409 +0x7e
runtime.mstart()
        /usr/local/go/src/runtime/proc.go:1175

goroutine 11 [running]:
runtime.systemstack_switch()
        /usr/local/go/src/runtime/asm_amd64.s:363 fp=0xc0424d1d28 sp=0xc0424d1d20 pc=0x4525d0
runtime.mallocgc(0x991b6fc5, 0x7f9f40, 0x1, 0xc042016300)
        /usr/local/go/src/runtime/malloc.go:720 +0x8e1 fp=0xc0424d1dc8 sp=0xc0424d1d28 pc=0x410551
runtime.makeslice(0x7f9f40, 0x991b6fc5, 0x991b6fc5, 0x0, 0x0, 0x66be35)
        /usr/local/go/src/runtime/slice.go:61 +0x7e fp=0xc0424d1df8 sp=0xc0424d1dc8 pc=0x43e2fe
github.com/schollz/croc/src.splitFile(0xc042016300, 0x17, 0x2, 0x0, 0x0)
        /home/zns/work/src/github.com/schollz/croc/src/utils.go:60 +0x14b fp=0xc0424d1e90 sp=0xc0424d1df8 pc=0x76d70b
github.com/schollz/croc/src.(*Croc).getFilesReady(0xc0422fa000, 0x0, 0x0)
        /home/zns/work/src/github.com/schollz/croc/src/files.go:139 +0x379 fp=0xc0424d1fc8 sp=0xc0424d1e90 pc=0x7664a9
runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:2361 +0x1 fp=0xc0424d1fd0 sp=0xc0424d1fc8 pc=0x455031
created by github.com/schollz/croc/src.(*Croc).processState
        /home/zns/work/src/github.com/schollz/croc/src/client.go:282 +0xe1e

goroutine 1 [chan receive, 3 minutes]:
github.com/schollz/croc/src.(*Croc).Send(0xc04215e000, 0xc042060090, 0xf, 0xc04205eb80, 0x14, 0x0, 0x0)
        /home/zns/work/src/github.com/schollz/croc/src/api.go:125 +0x632
main.send(0xc0420c8c60, 0xc04207f740, 0x7acce8)
        /home/zns/work/src/github.com/schollz/croc/main.go:113 +0x1a2
main.main.func1(0xc0420c8c60, 0xc0420c0800, 0xc0420c8c60)
        /home/zns/work/src/github.com/schollz/croc/main.go:44 +0x32
github.com/urfave/cli.HandleAction(0x806e00, 0x8bf018, 0xc0420c8c60, 0x0, 0xc0420c0840)
        /home/zns/work/src/github.com/urfave/cli/app.go:501 +0xcf
github.com/urfave/cli.Command.Run(0x89ed38, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8a3725, 0xb, 0x0, ...)
        /home/zns/work/src/github.com/urfave/cli/command.go:165 +0x484
github.com/urfave/cli.(*App).Run(0xc042158000, 0xc04205c080, 0x3, 0x4, 0x0, 0x0)
        /home/zns/work/src/github.com/urfave/cli/app.go:259 +0x6ef
main.main()
        /home/zns/work/src/github.com/schollz/croc/main.go:91 +0xb51

goroutine 18 [semacquire, 5 minutes]:
sync.runtime_notifyListWait(0xc04205c6d0, 0x0)
        /usr/local/go/src/runtime/sema.go:510 +0x119
sync.(*Cond).Wait(0xc04205c6c0)
        /usr/local/go/src/sync/cond.go:56 +0x87
github.com/cihub/seelog.(*asyncLoopLogger).processItem(0xc0420cc000, 0x0)
        /home/zns/work/src/github.com/cihub/seelog/behavior_asynclooplogger.go:50 +0x98
github.com/cihub/seelog.(*asyncLoopLogger).processQueue(0xc0420cc000)
        /home/zns/work/src/github.com/cihub/seelog/behavior_asynclooplogger.go:63 +0x4b
created by github.com/cihub/seelog.NewAsyncLoopLogger
        /home/zns/work/src/github.com/cihub/seelog/behavior_asynclooplogger.go:40 +0xa4

goroutine 19 [semacquire, 5 minutes]:
sync.runtime_notifyListWait(0xc04205c890, 0x0)
        /usr/local/go/src/runtime/sema.go:510 +0x119
sync.(*Cond).Wait(0xc04205c880)
        /usr/local/go/src/sync/cond.go:56 +0x87
github.com/cihub/seelog.(*asyncLoopLogger).processItem(0xc0420cc120, 0x0)
        /home/zns/work/src/github.com/cihub/seelog/behavior_asynclooplogger.go:50 +0x98
github.com/cihub/seelog.(*asyncLoopLogger).processQueue(0xc0420cc120)
        /home/zns/work/src/github.com/cihub/seelog/behavior_asynclooplogger.go:63 +0x4b
created by github.com/cihub/seelog.NewAsyncLoopLogger
        /home/zns/work/src/github.com/cihub/seelog/behavior_asynclooplogger.go:40 +0xa4

goroutine 20 [syscall, 5 minutes]:
os/signal.signal_recv(0x0)
        /usr/local/go/src/runtime/sigqueue.go:139 +0xad
os/signal.loop()
        /usr/local/go/src/os/signal/signal_unix.go:22 +0x29
created by os/signal.init.0
        /usr/local/go/src/os/signal/signal_unix.go:28 +0x48

goroutine 56 [IO wait]:
internal/poll.runtime_pollWait(0xdb0ea0, 0x72, 0x8f64c0)
        /usr/local/go/src/runtime/netpoll.go:173 +0x5e
internal/poll.(*pollDesc).wait(0xc0420e6cc8, 0x72, 0xaca400, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:85 +0xa2
internal/poll.(*ioSrv).ExecIO(0xb0a8d8, 0xc0420e6b18, 0x8bef58, 0xc0420e6b00, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_windows.go:223 +0x13a
internal/poll.(*FD).Read(0xc0420e6b00, 0xc04236f400, 0x400, 0x400, 0x0, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_windows.go:484 +0x248
net.(*netFD).Read(0xc0420e6b00, 0xc04236f400, 0x400, 0x400, 0x389d56b88f5, 0xb0cc00, 0x0)
        /usr/local/go/src/net/fd_windows.go:151 +0x56
net.(*conn).Read(0xc0422f4160, 0xc04236f400, 0x400, 0x400, 0x0, 0x0, 0x0)
        /usr/local/go/src/net/net.go:176 +0x71
github.com/schollz/croc/src.receiveMessage(0x8fb760, 0xc0422f4160, 0x8fb760, 0xc0422f4160, 0x0, 0x0)
        /home/zns/work/src/github.com/schollz/croc/src/relay.go:151 +0x1b4
github.com/schollz/croc/src.(*Croc).clientCommuncation(0xc04215e0f0, 0x89ef55, 0x5, 0x8fb760, 0xc0422f4160, 0x8bb2c97000, 0x0)
        /home/zns/work/src/github.com/schollz/croc/src/relay.go:60 +0x9d
github.com/schollz/croc/src.(*Croc).listener.func1(0xc04215e0f0, 0x89ef55, 0x5, 0x8fb760, 0xc0422f4160)
        /home/zns/work/src/github.com/schollz/croc/src/relay.go:44 +0x6d
created by github.com/schollz/croc/src.(*Croc).listener
        /home/zns/work/src/github.com/schollz/croc/src/relay.go:43 +0x182

goroutine 22 [semacquire, 5 minutes]:
sync.runtime_notifyListWait(0xc04215b4d0, 0x0)
        /usr/local/go/src/runtime/sema.go:510 +0x119
sync.(*Cond).Wait(0xc04215b4c0)
        /usr/local/go/src/sync/cond.go:56 +0x87
github.com/cihub/seelog.(*asyncLoopLogger).processItem(0xc0420cc480, 0x0)
        /home/zns/work/src/github.com/cihub/seelog/behavior_asynclooplogger.go:50 +0x98
github.com/cihub/seelog.(*asyncLoopLogger).processQueue(0xc0420cc480)
        /home/zns/work/src/github.com/cihub/seelog/behavior_asynclooplogger.go:63 +0x4b
created by github.com/cihub/seelog.NewAsyncLoopLogger
        /home/zns/work/src/github.com/cihub/seelog/behavior_asynclooplogger.go:40 +0xa4

goroutine 26 [IO wait, 3 minutes]:
internal/poll.runtime_pollWait(0xdb08f0, 0x72, 0x8f64c0)
        /usr/local/go/src/runtime/netpoll.go:173 +0x5e
internal/poll.(*pollDesc).wait(0xc0420e6a08, 0x72, 0xaca400, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:85 +0xa2
internal/poll.(*ioSrv).ExecIO(0xb0a8d8, 0xc0420e6858, 0x8bef58, 0xc042469840, 0x697dbb, 0xc04207c000)
        /usr/local/go/src/internal/poll/fd_windows.go:223 +0x13a
internal/poll.(*FD).Read(0xc0420e6840, 0xc04246f000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_windows.go:484 +0x248
net.(*netFD).Read(0xc0420e6840, 0xc04246f000, 0x1000, 0x1000, 0x0, 0x519161, 0xc0422f2961)
        /usr/local/go/src/net/fd_windows.go:151 +0x56
net.(*conn).Read(0xc04218a0b0, 0xc04246f000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
        /usr/local/go/src/net/net.go:176 +0x71
crypto/tls.(*block).readFromUntil(0xc0422ec720, 0xdb1408, 0xc04218a0b0, 0x5, 0xc04218a0b0, 0xc04207c000)
        /usr/local/go/src/crypto/tls/conn.go:493 +0x9d
crypto/tls.(*Conn).readRecord(0xc0420c6380, 0x8bf817, 0xc0420c64a0, 0xc04207e380)
        /usr/local/go/src/crypto/tls/conn.go:595 +0xe7
crypto/tls.(*Conn).Read(0xc0420c6380, 0xc042491000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
        /usr/local/go/src/crypto/tls/conn.go:1156 +0x107
bufio.(*Reader).fill(0xc0420c0660)
        /usr/local/go/src/bufio/bufio.go:100 +0x125
bufio.(*Reader).Peek(0xc0420c0660, 0x2, 0x767f36, 0x0, 0xc0422f2600, 0x363, 0x5ef)
        /usr/local/go/src/bufio/bufio.go:132 +0x41
github.com/gorilla/websocket.(*Conn).read(0xc0420628c0, 0x2, 0x4, 0x3, 0xc042026570, 0xc042026500, 0xc04205cf58)
        /home/zns/work/src/github.com/gorilla/websocket/conn_read.go:12 +0x47
github.com/gorilla/websocket.(*Conn).advanceFrame(0xc0420628c0, 0x0, 0x0, 0x1f0)
        /home/zns/work/src/github.com/gorilla/websocket/conn.go:779 +0x63
github.com/gorilla/websocket.(*Conn).NextReader(0xc0420628c0, 0x8f4f40, 0xc042178f90, 0xc042469d48, 0xc042469d68, 0x4107ff)
        /home/zns/work/src/github.com/gorilla/websocket/conn.go:939 +0xaa
github.com/gorilla/websocket.(*Conn).ReadJSON(0xc0420628c0, 0x816cc0, 0xc042292600, 0x0, 0xc042090900)
        /home/zns/work/src/github.com/gorilla/websocket/json.go:50 +0x36
github.com/schollz/croc/src.(*Croc).client.func1(0xc042486060, 0xc0420628c0, 0xc04215e000)
        /home/zns/work/src/github.com/schollz/croc/src/client.go:74 +0xb2
created by github.com/schollz/croc/src.(*Croc).client
        /home/zns/work/src/github.com/schollz/croc/src/client.go:70 +0x6b3

goroutine 5 [semacquire, 3 minutes]:
sync.runtime_Semacquire(0xc042060e8c)
        /usr/local/go/src/runtime/sema.go:56 +0x40
sync.(*WaitGroup).Wait(0xc042060e80)
        /usr/local/go/src/sync/waitgroup.go:129 +0x79
github.com/schollz/croc/src.(*Croc).client(0xc0422fa000, 0x0, 0xc04205eb80, 0x3, 0x0, 0x0)
        /home/zns/work/src/github.com/schollz/croc/src/client.go:141 +0xa49
github.com/schollz/croc/src.(*Croc).Send.func2(0xc04215e000, 0xc04205eb80, 0x14, 0xc04205eb80, 0x3, 0xc0420dcfc0)
        /home/zns/work/src/github.com/schollz/croc/src/api.go:108 +0x33d
created by github.com/schollz/croc/src.(*Croc).Send
        /home/zns/work/src/github.com/schollz/croc/src/api.go:79 +0x5c1

goroutine 6 [semacquire, 3 minutes]:
sync.runtime_Semacquire(0xc04219a47c)
        /usr/local/go/src/runtime/sema.go:56 +0x40
sync.(*WaitGroup).Wait(0xc04219a470)
        /usr/local/go/src/sync/waitgroup.go:129 +0x79
github.com/schollz/croc/src.(*Croc).client(0xc04215e000, 0x0, 0xc04205eb80, 0x3, 0x0, 0x0)
        /home/zns/work/src/github.com/schollz/croc/src/client.go:141 +0xa49
github.com/schollz/croc/src.(*Croc).Send.func3(0xc04215e000, 0xc04205eb80, 0x3, 0xc0420dcfc0)
        /home/zns/work/src/github.com/schollz/croc/src/api.go:119 +0x65
created by github.com/schollz/croc/src.(*Croc).Send
        /home/zns/work/src/github.com/schollz/croc/src/api.go:114 +0x604

goroutine 50 [semacquire, 3 minutes]:
sync.runtime_Semacquire(0xc0422fc7ac)
        /usr/local/go/src/runtime/sema.go:56 +0x40
sync.(*WaitGroup).Wait(0xc0422fc7a0)
        /usr/local/go/src/sync/waitgroup.go:129 +0x79
github.com/schollz/croc/src.(*Croc).startRelay(0xc04215e0f0)
        /home/zns/work/src/github.com/schollz/croc/src/relay.go:27 +0xe5
created by github.com/schollz/croc/src.(*Croc).Send.func2
        /home/zns/work/src/github.com/schollz/croc/src/api.go:86 +0xfe

goroutine 51 [IO wait]:
internal/poll.runtime_pollWait(0xdb0c30, 0x72, 0x8f64c0)
        /usr/local/go/src/runtime/netpoll.go:173 +0x5e
internal/poll.(*pollDesc).wait(0xc0422c8488, 0x72, 0xaca400, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:85 +0xa2
internal/poll.(*ioSrv).ExecIO(0xb0a8d8, 0xc0422c82d8, 0xc042002ac0, 0x1, 0x0, 0x168)
        /usr/local/go/src/internal/poll/fd_windows.go:223 +0x13a
internal/poll.(*FD).acceptOne(0xc0422c82c0, 0x168, 0xc0421142a0, 0x2, 0x2, 0xc0422c82d8, 0x4761a9, 0xc04222dc60, 0x4107ff, 0x10)
        /usr/local/go/src/internal/poll/fd_windows.go:793 +0xae
internal/poll.(*FD).Accept(0xc0422c82c0, 0xc0420555d0, 0x0, 0x0, 0x0, 0x0, 0xc000000000, 0x0, 0x0, 0x0, ...)
        /usr/local/go/src/internal/poll/fd_windows.go:827 +0x142
net.(*netFD).accept(0xc0422c82c0, 0xc042058f80, 0xc04222ddd0, 0x4022f8)
        /usr/local/go/src/net/fd_windows.go:192 +0x86
net.(*TCPListener).accept(0xc042004028, 0xc04222de00, 0x40119e, 0xc042058f80)
        /usr/local/go/src/net/tcpsock_posix.go:136 +0x35
net.(*TCPListener).AcceptTCP(0xc042004028, 0xc04222de48, 0xc04222de50, 0x18)
        /usr/local/go/src/net/tcpsock.go:246 +0x50
net/http.tcpKeepAliveListener.Accept(0xc042004028, 0x8bf198, 0xc042058f00, 0x8f9840, 0xc04215c300)
        /usr/local/go/src/net/http/server.go:3216 +0x36
net/http.(*Server).Serve(0xc0420649c0, 0x8f9580, 0xc042004028, 0x0, 0x0)
        /usr/local/go/src/net/http/server.go:2770 +0x1ac
net/http.(*Server).ListenAndServe(0xc0420649c0, 0xc0420649c0, 0x5)
        /usr/local/go/src/net/http/server.go:2711 +0xb0
net/http.ListenAndServe(0xc04219a4c6, 0x5, 0x0, 0x0, 0x4, 0xc04219a4c6)
        /usr/local/go/src/net/http/server.go:2969 +0x81
github.com/schollz/croc/src.(*Croc).startServer(0xc04215e0f0, 0x0, 0x0)
        /home/zns/work/src/github.com/schollz/croc/src/server.go:81 +0x1b4
created by github.com/schollz/croc/src.(*Croc).Send.func2
        /home/zns/work/src/github.com/schollz/croc/src/api.go:87 +0x120

goroutine 39 [IO wait]:
internal/poll.runtime_pollWait(0xdb0d00, 0x72, 0x8f64c0)
        /usr/local/go/src/runtime/netpoll.go:173 +0x5e
internal/poll.(*pollDesc).wait(0xc042310488, 0x72, 0xaca400, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:85 +0xa2
internal/poll.(*ioSrv).ExecIO(0xb0a8d8, 0xc0423102d8, 0xc042002aa0, 0x1, 0x0, 0x510)
        /usr/local/go/src/internal/poll/fd_windows.go:223 +0x13a
internal/poll.(*FD).acceptOne(0xc0423102c0, 0x510, 0xc0421141c0, 0x2, 0x2, 0xc0423102d8, 0xc04217a740, 0xc042237d30, 0x4107ff, 0x10)
        /usr/local/go/src/internal/poll/fd_windows.go:793 +0xae
internal/poll.(*FD).Accept(0xc0423102c0, 0xc0420555c0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
        /usr/local/go/src/internal/poll/fd_windows.go:827 +0x142
net.(*netFD).accept(0xc0423102c0, 0xc0420cc480, 0x8bf808, 0x8f4f40)
        /usr/local/go/src/net/fd_windows.go:192 +0x86
net.(*TCPListener).accept(0xc04218a088, 0x451cd0, 0xc042237ee0, 0xc042237ee8)
        /usr/local/go/src/net/tcpsock_posix.go:136 +0x35
net.(*TCPListener).Accept(0xc04218a088, 0x8bee68, 0xc04215e0f0, 0x89ef55, 0x5)
        /usr/local/go/src/net/tcpsock.go:259 +0x50
github.com/schollz/croc/src.(*Croc).listener(0xc04215e0f0, 0x89ef55, 0x5, 0x0, 0x0)
        /home/zns/work/src/github.com/schollz/croc/src/relay.go:38 +0x196
github.com/schollz/croc/src.(*Croc).startRelay.func1(0xc04215e0f0, 0x89ef55, 0x5, 0xc0422fc7a0)
        /home/zns/work/src/github.com/schollz/croc/src/relay.go:21 +0x114
created by github.com/schollz/croc/src.(*Croc).startRelay
        /home/zns/work/src/github.com/schollz/croc/src/relay.go:18 +0xbc

goroutine 40 [IO wait, 3 minutes]:
internal/poll.runtime_pollWait(0xdb0b60, 0x72, 0x8f64c0)
        /usr/local/go/src/runtime/netpoll.go:173 +0x5e
internal/poll.(*pollDesc).wait(0xc0420e61c8, 0x72, 0xaca400, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:85 +0xa2
internal/poll.(*ioSrv).ExecIO(0xb0a8d8, 0xc0420e6018, 0xc042113480, 0x1, 0x0, 0x258)
        /usr/local/go/src/internal/poll/fd_windows.go:223 +0x13a
internal/poll.(*FD).acceptOne(0xc0420e6000, 0x258, 0xc0421140e0, 0x2, 0x2, 0xc0420e6018, 0xc0422f40c0, 0xc042239d30, 0x4107ff, 0x10)
        /usr/local/go/src/internal/poll/fd_windows.go:793 +0xae
internal/poll.(*FD).Accept(0xc0420e6000, 0xc0422c6460, 0x0, 0x0, 0x0, 0x0, 0xc000000000, 0x0, 0x0, 0x0, ...)
        /usr/local/go/src/internal/poll/fd_windows.go:827 +0x142
net.(*netFD).accept(0xc0420e6000, 0x0, 0xc0422c6450, 0x1)
        /usr/local/go/src/net/fd_windows.go:192 +0x86
net.(*TCPListener).accept(0xc0422f40c0, 0x429f90, 0xc0423123a0, 0xc042239ee8)
        /usr/local/go/src/net/tcpsock_posix.go:136 +0x35
net.(*TCPListener).Accept(0xc0422f40c0, 0x8f8fe8, 0xc0422f40c0, 0xd, 0x8f8fc0)
        /usr/local/go/src/net/tcpsock.go:259 +0x50
github.com/schollz/croc/src.(*Croc).listener(0xc04215e0f0, 0x89ef5a, 0x5, 0x0, 0x0)
        /home/zns/work/src/github.com/schollz/croc/src/relay.go:38 +0x196
github.com/schollz/croc/src.(*Croc).startRelay.func1(0xc04215e0f0, 0x89ef5a, 0x5, 0xc0422fc7a0)
        /home/zns/work/src/github.com/schollz/croc/src/relay.go:21 +0x114
created by github.com/schollz/croc/src.(*Croc).startRelay
        /home/zns/work/src/github.com/schollz/croc/src/relay.go:18 +0xbc

goroutine 53 [sleep]:
time.Sleep(0xdf8475800)
        /usr/local/go/src/runtime/time.go:102 +0x17b
github.com/schollz/croc/src.(*Croc).channelCleanup(0xc04215e0f0)
        /home/zns/work/src/github.com/schollz/croc/src/server.go:289 +0x3ad
created by github.com/schollz/croc/src.(*Croc).startServer
        /home/zns/work/src/github.com/schollz/croc/src/server.go:19 +0x4a

goroutine 43 [runnable]:
time.Sleep(0x5f5e100)
        /usr/local/go/src/runtime/time.go:102 +0x17b
github.com/briandowns/spinner.(*Spinner).Start.func1(0xc042458000)
        /home/zns/work/src/github.com/briandowns/spinner/spinner.go:227 +0x61
created by github.com/briandowns/spinner.(*Spinner).Start
        /home/zns/work/src/github.com/briandowns/spinner/spinner.go:211 +0x62

goroutine 25 [select, 3 minutes]:
github.com/schollz/croc/src.(*Croc).client.func2(0xc042294120, 0xc0420c0000, 0xc0422fa000, 0xc042062280, 0xc0422c6680, 0xc042060e80)
        /home/zns/work/src/github.com/schollz/croc/src/client.go:111 +0x103
created by github.com/schollz/croc/src.(*Croc).client
        /home/zns/work/src/github.com/schollz/croc/src/client.go:108 +0xa38

goroutine 55 [IO wait]:
internal/poll.runtime_pollWait(0xdb09c0, 0x72, 0x8f64c0)
        /usr/local/go/src/runtime/netpoll.go:173 +0x5e
internal/poll.(*pollDesc).wait(0xc04246c1c8, 0x72, 0xaca400, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:85 +0xa2
internal/poll.(*ioSrv).ExecIO(0xb0a8d8, 0xc04246c018, 0x8bef58, 0x0, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_windows.go:223 +0x13a
internal/poll.(*FD).Read(0xc04246c000, 0xc04247c000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_windows.go:484 +0x248
net.(*netFD).Read(0xc04246c000, 0xc04247c000, 0x1000, 0x1000, 0xc042292200, 0x0, 0x0)
        /usr/local/go/src/net/fd_windows.go:151 +0x56
net.(*conn).Read(0xc042080088, 0xc04247c000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
        /usr/local/go/src/net/net.go:176 +0x71
bufio.(*Reader).fill(0xc04204a0c0)
        /usr/local/go/src/bufio/bufio.go:100 +0x125
bufio.(*Reader).Peek(0xc04204a0c0, 0x2, 0x14, 0x0, 0x0, 0x0, 0x0)
        /usr/local/go/src/bufio/bufio.go:132 +0x41
github.com/gorilla/websocket.(*Conn).read(0xc042492000, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0)
        /home/zns/work/src/github.com/gorilla/websocket/conn_read.go:12 +0x47
github.com/gorilla/websocket.(*Conn).advanceFrame(0xc042492000, 0x0, 0x0, 0x1f0)
        /home/zns/work/src/github.com/gorilla/websocket/conn.go:779 +0x63
github.com/gorilla/websocket.(*Conn).NextReader(0xc042492000, 0x8f4f60, 0xc042434220, 0xc0424655d8, 0xc0424655f8, 0x4107ff)
        /home/zns/work/src/github.com/gorilla/websocket/conn.go:939 +0xaa
github.com/gorilla/websocket.(*Conn).ReadJSON(0xc042492000, 0x816cc0, 0xc04247aa00, 0xc0422fc040, 0x3)
        /home/zns/work/src/github.com/gorilla/websocket/json.go:50 +0x36
github.com/schollz/croc/src.(*Croc).startServer.func1(0x8f91c0, 0xc0421460e0, 0xc04247e000)
        /home/zns/work/src/github.com/schollz/croc/src/server.go:59 +0x719
net/http.HandlerFunc.ServeHTTP(0xc0422f83e0, 0x8f91c0, 0xc0421460e0, 0xc04247e000)
        /usr/local/go/src/net/http/server.go:1947 +0x4b
net/http.(*ServeMux).ServeHTTP(0xb0c7e0, 0x8f91c0, 0xc0421460e0, 0xc04247e000)
        /usr/local/go/src/net/http/server.go:2337 +0x137
net/http.serverHandler.ServeHTTP(0xc0420649c0, 0x8f91c0, 0xc0421460e0, 0xc04247e000)
        /usr/local/go/src/net/http/server.go:2694 +0xc3
net/http.(*conn).serve(0xc0421760a0, 0x8f9780, 0xc0420da6c0)
        /usr/local/go/src/net/http/server.go:1830 +0x658
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:2795 +0x282

goroutine 42 [semacquire]:
sync.runtime_SemacquireMutex(0xc0422fa0ac, 0x0)
        /usr/local/go/src/runtime/sema.go:71 +0x44
sync.(*Mutex).Lock(0xc0422fa0a8)
        /usr/local/go/src/sync/mutex.go:134 +0x10f
sync.(*RWMutex).Lock(0xc0422fa0a8)
        /usr/local/go/src/sync/rwmutex.go:93 +0x34
github.com/schollz/croc/src.(*Croc).processState(0xc0422fa000, 0x0, 0x0, 0x0, 0xc04246a5a0, 0x0, 0xc0420da400, 0x2, 0x4, 0xc04217294c, ...)
        /home/zns/work/src/github.com/schollz/croc/src/client.go:189 +0x66
github.com/schollz/croc/src.(*Croc).client.func1(0xc042294120, 0xc042062280, 0xc0422fa000)
        /home/zns/work/src/github.com/schollz/croc/src/client.go:80 +0x1d1
created by github.com/schollz/croc/src.(*Croc).client
        /home/zns/work/src/github.com/schollz/croc/src/client.go:70 +0x6b3

goroutine 27 [select, 3 minutes]:
github.com/schollz/croc/src.(*Croc).client.func2(0xc042486060, 0xc0420dd020, 0xc04215e000, 0xc0420628c0, 0xc042338010, 0xc04219a470)
        /home/zns/work/src/github.com/schollz/croc/src/client.go:111 +0x103
created by github.com/schollz/croc/src.(*Croc).client
        /home/zns/work/src/github.com/schollz/croc/src/client.go:108 +0xa38

goroutine 57 [IO wait]:
internal/poll.runtime_pollWait(0xdb0dd0, 0x72, 0x8f64c0)
        /usr/local/go/src/runtime/netpoll.go:173 +0x5e
internal/poll.(*pollDesc).wait(0xc0420e6f88, 0x72, 0xaca400, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:85 +0xa2
internal/poll.(*ioSrv).ExecIO(0xb0a8d8, 0xc0420e6dd8, 0x8bef58, 0x0, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_windows.go:223 +0x13a
internal/poll.(*FD).Read(0xc0420e6dc0, 0xc042370000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_windows.go:484 +0x248
net.(*netFD).Read(0xc0420e6dc0, 0xc042370000, 0x1000, 0x1000, 0xc042292200, 0x0, 0x0)
        /usr/local/go/src/net/fd_windows.go:151 +0x56
net.(*conn).Read(0xc0422f4168, 0xc042370000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
        /usr/local/go/src/net/net.go:176 +0x71
bufio.(*Reader).fill(0xc042152c60)
        /usr/local/go/src/bufio/bufio.go:100 +0x125
bufio.(*Reader).Peek(0xc042152c60, 0x2, 0x14, 0x0, 0x0, 0x0, 0x0)
        /usr/local/go/src/bufio/bufio.go:132 +0x41
github.com/gorilla/websocket.(*Conn).read(0xc042062640, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0)
        /home/zns/work/src/github.com/gorilla/websocket/conn_read.go:12 +0x47
github.com/gorilla/websocket.(*Conn).advanceFrame(0xc042062640, 0x0, 0x0, 0x1f0)
        /home/zns/work/src/github.com/gorilla/websocket/conn.go:779 +0x63
github.com/gorilla/websocket.(*Conn).NextReader(0xc042062640, 0x8f4f60, 0xc042246a40, 0xc0424695d8, 0xc0424695f8, 0x4107ff)
        /home/zns/work/src/github.com/gorilla/websocket/conn.go:939 +0xaa
github.com/gorilla/websocket.(*Conn).ReadJSON(0xc042062640, 0x816cc0, 0xc04245e400, 0xc042172f80, 0x3)
        /home/zns/work/src/github.com/gorilla/websocket/json.go:50 +0x36
github.com/schollz/croc/src.(*Croc).startServer.func1(0x8f91c0, 0xc0421461c0, 0xc04247e100)
        /home/zns/work/src/github.com/schollz/croc/src/server.go:59 +0x719
net/http.HandlerFunc.ServeHTTP(0xc0422f83e0, 0x8f91c0, 0xc0421461c0, 0xc04247e100)
        /usr/local/go/src/net/http/server.go:1947 +0x4b
net/http.(*ServeMux).ServeHTTP(0xb0c7e0, 0x8f91c0, 0xc0421461c0, 0xc04247e100)
        /usr/local/go/src/net/http/server.go:2337 +0x137
net/http.serverHandler.ServeHTTP(0xc0420649c0, 0x8f91c0, 0xc0421461c0, 0xc04247e100)
        /usr/local/go/src/net/http/server.go:2694 +0xc3
net/http.(*conn).serve(0xc042058f00, 0x8f9780, 0xc0420dab80)
        /usr/local/go/src/net/http/server.go:1830 +0x658
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:2795 +0x282

Bug fixes for v2

  • Improve readme
  • Cache the key to a config file (~/.config/croc/key)
  • Mnemicode the key?
  • colors?

Loader on MacOS

  --- [====================================================================] 100%
  --- [==================================================================>-]  98%
  --- [====================================================================] 100%
  --- [==================================================================>-]  98%
  --- [====================================================================] 100%
  --- [==================================================================>-]  98%
  --- [====================================================================] 100%
  --- [==================================================================>-]  98%
  --- [====================================================================] 100%
  --- [==================================================================>-]  98%
  --- [====================================================================] 100%
  --- [==================================================================>-]  98%
  --- [====================================================================] 100%
  --- [==================================================================>-]  98%
  --- [====================================================================] 100%
  --- [==================================================================>-]  98%
  --- [====================================================================] 100%
  --- [==================================================================>-]  98%
  --- [====================================================================] 100%
  --- [==================================================================>-]  98%
  --- [====================================================================] 100%
  --- [==================================================================>-]  98%
  --- [====================================================================] 100%
  --- [==================================================================>-]  98%
  --- [====================================================================] 100%
  --- [==================================================================>-]  98%
  --- [====================================================================] 100%
  --- [==================================================================>-]  98%
  --- [====================================================================] 100%
  --- [===================================================================>]  99%
  --- [====================================================================] 100%
  --- [===================================================================>]  99%
  --- [====================================================================] 100%
  --- [===================================================================>]  99%
  --- [====================================================================] 100%
  --- [===================================================================>]  99%
  --- [====================================================================] 100%
  --- [===================================================================>]  99%
  --- [====================================================================] 100%
  --- [===================================================================>]  99%
  --- [====================================================================] 100%
  --- [===================================================================>]  99%
  --- [====================================================================] 100%
  --- [===================================================================>]  99%
  --- [====================================================================] 100%
  --- [===================================================================>]  99%
  --- [====================================================================] 100%
  --- [===================================================================>]  99%
  --- [====================================================================] 100%
  --- [===================================================================>]  99%
  --- [====================================================================] 100%
  --- [===================================================================>] 100%
  --- [====================================================================] 100%
  --- [===================================================================>] 100%
  --- [====================================================================] 100%
  --- [===================================================================>] 100%
  --- [====================================================================] 100%
  --- [===================================================================>] 100%
  --- [====================================================================] 100%
  --- [===================================================================>] 100%
  --- [====================================================================] 100%
  --- [===================================================================>] 100%
  --- [====================================================================] 100%
  --- [===================================================================>] 100%
  --- [====================================================================] 100%
  --- [====================================================================] 100%
  --- [====================================================================] 100%

While using the send/recieve option in MacOS, I get one loader after each bar has been updated (=).

Relay broken?

Is the relay possibly broken or down? I cannot get a sample file to send.

$ croc -send Rick\ Astley\ -\ Never\ Gonna\ Give\ You\ Up.mp4

                                ,_
                               >' )
   croc version                ( ( \ 
                                || \ 
                 /^^^^\         ||
    /^^\________/0     \        ||
   (                    `~+++,,_||__,,++~^^^^^^^
 ...V^V^V^V^V^V^\...............................
 

Sending 47 MB file named 'Rick Astley - Never Gonna Give You Up.mp4'
Code is: ****************

Transfer file error, chunk size is empty!

croc 0.4.1 Ubuntu 64bit
croc -send t.txt

Sending (->****)..
  36% |██████████████                          | [0s:0s]            ERRO[0011] open t.txt.enc.3: no such file or directory
  26% |██████████                              | [0s:0s]
File sent (9.2 EB/s)

croc

Receiving (<-****)..
ERRO[0009] Problem receiving the file: : chunk size is empty!
 100% |████████████████████████████████████████| [2s:0s]            Error! Please submit the following error to https://github.com/schollz/croc/issues:

'CatFiles open t.txt.enc.3: : open t.txt.enc.3: no such file or directory'

File to transfer, plz unzip.
t.zip

@schollz

NAT

I have many computers all behind NAT.
The relay has to on a public static IP somewhere like in the cloud ?

Clean out old dangling receivers/senders every hour

Basically we need another data type here:

croc/relay.go

Line 16 in 550bd9a

type connectionMap struct {
. Basically a map[string]time.Time where each key is saved with an indicator of whether it is a "sender" or a "receiver" (e.g. "s"+key or "r"+key). Then make a new function that is a for loop that just erases each key in the map that is older than an hour. This function will run a goroutine in the background, forever.

Happy to support contributors, please don't hesitate to ask me questions.

Relay panics sometimes

Output from my logs::

time="2017-10-25T19:38:23Z" level=debug msg="telling sender ok" id=2 ip="x"
time="2017-10-25T19:38:23Z" level=debug msg="preparing pipe" id=2 ip="x"
time="2017-10-25T19:38:23Z" level=debug msg="piping connections" id=2 ip="x"
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x30 pc=0x57da57]

goroutine 332 [running]:
main.chanFromConn.func1(0x0, 0x0, 0xc420057860)
        /root/go/src/github.com/schollz/croc/relay.go:281 +0x77
created by main.chanFromConn
        /root/go/src/github.com/schollz/croc/relay.go:293 +0x71

wormhole protocol and PAKE compatibility

Hi!

I have found with great interest this golang implementation of some of the concepts behind Magic Wormhole. As a user of the latter (and maintainer of the Debian package), I am happy to see other implementations pop up, especially if it means it's easier for others to share files and use those concepts.

Unfortunately, I am concerned with the current implementation of croc, as I explained in #15 (comment)

I see two main issues:

  • compatibility concerns
  • security concerns

Compatibility

While it's great croc reuses some concepts behind magic-wormhole, it doesn't exactly implement the same protocol. This means the problem space is fragmented: a user of croc can't talk with a user of wormhole and vice-versa, which makes it needlessly hard for users to talk to each other.

I understand the idea behind it: a different implementation means more decentralization, for example. But that doesn't mean it has to be a different implementation to be decentralized. Wormhole, out of the box, supports using different relay (e.g. "discovery") and transfer (e.g. "nat trasversal") servers and croc could still implement the wormhole protocol while not being dependent on @warner's infrastructure as a single point of failure (SPOF). In fact, he explicitly said it would be good if other projects would make use of different DNS aliases for those services so they can easily be switched to different backends if traffic would become unmanageable for his services. This is how the debian packages work: the transit server is patched to be tcp:magic-wormhole-transit.debian.net:4001:priority=2.0 instead of the upstream tcp:transit.magic-wormhole.io:4001. Then on Debian's infrastructure, that DNS entry is just a pointer to the normal transit server. The relay server server is the same, however (ws://relay.magic-wormhole.io:4000/v1).

Implementing this would mean adding Wormhole support in croc, specifically the capability of talking with transit and, more importantly, relay servers so that croc would share the same key namespace as Wormhole.

Security

But this would also require reimplementing the key exchange using PAKE instead of the home-grown, SHA256-based key exchanged. As I explained in my previous comments, I am unsure of the security properties of croc as it is done right now. A lot of care was given to the way Wormhole implements the key exchange: it uses a low-entropy ephemeral and weak key to establish a strong session key: that is the PAKE protocol which was published in multiple papers and seems to be solid at the cryptographic layer. I am not sure the SHA256-checksum croc implements has similar properties. For example, does it allow multiple attempts or does it bail on first try? Wouldn't it be possible for an attacker to build a rainbow table of all possible keys and just use that to access the files?

I haven't reviewed croc's security properties in details, so maybe my concerns are misplaced. But as a general principle, rolling out a different cryptosystem for another project seems an idea fraught with dangers that should generally be avoided. In that regard, I also think that PAKE exchange support should be implemented as well as the above network compatibility.

I hope this is useful for you and thanks for working on all of this!

Flag -save for the receiver to specify where to save the file

Current Behaviour
The path from the receiving file is the same as the received file, with no capability of changing the actual path for the current saving

Expected behavior:
When accepting the sending, it should prompt the for a a path where to store the received file (optionally?)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.