diff --git a/src/cli/cli.go b/src/cli/cli.go index fa20cb43..4d2a2246 100644 --- a/src/cli/cli.go +++ b/src/cli/cli.go @@ -21,7 +21,7 @@ import ( var Version string func Run() (err error) { -// use all of the processors + // use all of the processors runtime.GOMAXPROCS(runtime.NumCPU()) app := cli.NewApp() @@ -42,6 +42,7 @@ func Run() (err error) { ArgsUsage: "[filename]", Flags: []cli.Flag{ cli.StringFlag{Name: "code, c", Usage: "codephrase used to connect to relay"}, + cli.BoolFlag{Name: "no-local", Usage: "disable local relay when sending"}, cli.StringFlag{Name: "ports", Value: "9009,9010,9011,9012,9013", Usage: "ports of the local relay (optional)"}, }, HelpName: "croc send", @@ -167,6 +168,7 @@ func send(c *cli.Context) (err error) { NoPrompt: c.GlobalBool("yes"), RelayAddress: c.GlobalString("relay"), Stdout: c.GlobalBool("stdout"), + DisableLocal: c.Bool("no-local"), RelayPorts: strings.Split(c.String("ports"), ","), }) if err != nil { diff --git a/src/comm/comm.go b/src/comm/comm.go index a19f5e64..49761268 100644 --- a/src/comm/comm.go +++ b/src/comm/comm.go @@ -16,8 +16,12 @@ type Comm struct { } // NewConnection gets a new comm to a tcp address -func NewConnection(address string) (c *Comm, err error) { - connection, err := net.DialTimeout("tcp", address, 30*time.Second) +func NewConnection(address string, timelimit ...time.Duration) (c *Comm, err error) { + tlimit := 30 * time.Second + if len(timelimit) > 0 { + tlimit = timelimit[0] + } + connection, err := net.DialTimeout("tcp", address, tlimit) if err != nil { return } diff --git a/src/croc/croc.go b/src/croc/croc.go index a78a63cf..05801589 100644 --- a/src/croc/croc.go +++ b/src/croc/croc.go @@ -76,10 +76,10 @@ type Client struct { FilesToTransferCurrentNum int // send / receive information of current file - CurrentFile *os.File - CurrentFileChunkRanges []int64 - CurrentFileChunks []int64 - + CurrentFile *os.File + CurrentFileChunkRanges []int64 + CurrentFileChunks []int64 + TotalSent int64 TotalChunksTransfered int chunkMap map[uint64]struct{} @@ -113,7 +113,7 @@ type FileInfo struct { } type RemoteFileRequest struct { - CurrentFileChunkRanges []int64 + CurrentFileChunkRanges []int64 FilesToTransferCurrentNum int } @@ -304,6 +304,22 @@ func (c *Client) Send(options TransferOptions) (err error) { log.Debugf("connection established: %+v", conn) for { data, _ := conn.Receive() + if bytes.Equal(data, []byte("ips?")) { + // recipient wants to try to connect to local ips + var ips []string + // only get local ips if the local is enabled + if !c.Options.DisableLocal { + // get list of local ips + ips, err = utils.GetLocalIPs() + if err != nil { + log.Debugf("error getting local ips: %s", err.Error()) + } + // prepend the port that is being listened to + ips = append([]string{c.Options.RelayPorts[0]}, ips...) + } + bips, _ := json.Marshal(ips) + conn.Send(bips) + } if bytes.Equal(data, []byte("handshake")) { break } @@ -324,6 +340,7 @@ func (c *Client) Receive() (err error) { fmt.Fprintf(os.Stderr, "connecting...") // recipient will look for peers first // and continue if it doesn't find any within 100 ms + usingLocal := false if !c.Options.DisableLocal { log.Debug("attempt to discover peers") discoveries, err := peerdiscovery.Discover(peerdiscovery.Settings{ @@ -336,6 +353,7 @@ func (c *Client) Receive() (err error) { log.Debug("switching to local") c.Options.RelayAddress = fmt.Sprintf("%s:%s", discoveries[0].Address, discoveries[0].Payload) c.ExternalIPConnected = c.Options.RelayAddress + usingLocal = true } log.Debugf("discoveries: %+v", discoveries) log.Debug("establishing connection") @@ -348,6 +366,43 @@ func (c *Client) Receive() (err error) { return } log.Debugf("connection established: %+v", c.conn[0]) + + if !usingLocal && !c.Options.DisableLocal { + // ask the sender for their local ips and port + // and try to connect to them + var data []byte + c.conn[0].Send([]byte("ips?")) + data, err = c.conn[0].Receive() + if err != nil { + return + } + log.Debugf("ips data: %s", data) + var ips []string + json.Unmarshal(data, &ips) + if len(ips) > 1 { + port := ips[0] + ips = ips[1:] + for _, ip := range ips { + serverTry := fmt.Sprintf("%s:%s", ip, port) + conn, banner2, externalIP, errConn := tcp.ConnectToTCPServer(serverTry, c.Options.SharedSecret, 50*time.Millisecond) + if errConn != nil { + log.Debugf("could not connect to " + serverTry) + continue + } + log.Debugf("local connection established to %s", conn, serverTry) + log.Debugf("banner: %s", banner2) + // reset to the local port + banner = banner2 + c.Options.RelayAddress = serverTry + c.ExternalIP = externalIP + c.conn[0].Close() + c.conn[0] = nil + c.conn[0] = conn + break + } + } + } + c.conn[0].Send([]byte("handshake")) c.Options.RelayPorts = strings.Split(banner, ",") log.Debug("exchanged header message") @@ -379,12 +434,12 @@ func (c *Client) transfer(options TransferOptions) (err error) { var done bool data, err = c.conn[0].Receive() if err != nil { - log.Debugf("got error receiving: %s",err.Error()) + log.Debugf("got error receiving: %s", err.Error()) break } done, err = c.processMessage(data) if err != nil { - log.Debugf("got error processing: %s",err.Error()) + log.Debugf("got error processing: %s", err.Error()) break } if done { @@ -572,12 +627,12 @@ func (c *Client) processMessage(payload []byte) (done bool, err error) { c.Step3RecipientRequestFile = false } if err != nil { - log.Debugf("got error from processing message: %s",err.Error()) + log.Debugf("got error from processing message: %s", err.Error()) return } err = c.updateState() if err != nil { - log.Debugf("got error from updating state: %s",err.Error()) + log.Debugf("got error from updating state: %s", err.Error()) return } return @@ -609,12 +664,12 @@ func (c *Client) updateState() (err error) { finished := true for i, fileInfo := range c.FilesToTransfer { - log.Debugf("checking %+v",fileInfo) + log.Debugf("checking %+v", fileInfo) if i < c.FilesToTransferCurrentNum { continue } fileHash, errHash := utils.HashFile(path.Join(fileInfo.FolderRemote, fileInfo.Name)) - log.Debugf("%s %+x %+x %+v",fileInfo.Name,fileHash,fileInfo.Hash,errHash) + log.Debugf("%s %+x %+x %+v", fileInfo.Name, fileHash, fileInfo.Hash, errHash) if errHash != nil || !bytes.Equal(fileHash, fileInfo.Hash) { if errHash != nil { // probably can't find, its okay @@ -692,7 +747,7 @@ func (c *Client) updateState() (err error) { c.TotalSent = 0 bRequest, _ := json.Marshal(RemoteFileRequest{ - CurrentFileChunkRanges: c.CurrentFileChunkRanges, + CurrentFileChunkRanges: c.CurrentFileChunkRanges, FilesToTransferCurrentNum: c.FilesToTransferCurrentNum, }) log.Debug("converting to chunk range") @@ -701,13 +756,12 @@ func (c *Client) updateState() (err error) { // setup the progressbar c.setBar() - log.Debugf("sending recipient ready with %d chunks",len(c.CurrentFileChunks)) + log.Debugf("sending recipient ready with %d chunks", len(c.CurrentFileChunks)) err = message.Send(c.conn[0], c.Key, message.Message{ Type: "recipientready", Bytes: bRequest, }) if err != nil { - log.Error(err) return } c.Step3RecipientRequestFile = true @@ -724,7 +778,7 @@ func (c *Client) updateState() (err error) { c.TotalSent = 0 log.Debug("beginning sending comms") for i := 0; i < len(c.Options.RelayPorts); i++ { - log.Debugf("starting sending over comm %d",i) + log.Debugf("starting sending over comm %d", i) go c.sendData(i) } } @@ -750,12 +804,12 @@ func (c *Client) setBar() { ) byteToDo := int64(len(c.CurrentFileChunks) * models.TCP_BUFFER_SIZE / 2) if byteToDo > 0 { - bytesDone := c.FilesToTransfer[c.FilesToTransferCurrentNum].Size -byteToDo + bytesDone := c.FilesToTransfer[c.FilesToTransferCurrentNum].Size - byteToDo log.Debug(byteToDo) log.Debug(c.FilesToTransfer[c.FilesToTransferCurrentNum].Size) log.Debug(bytesDone) if bytesDone > 0 { - c.bar.Add64(bytesDone) + c.bar.Add64(bytesDone) } } } diff --git a/src/croc/croc_test.go b/src/croc/croc_test.go index 8db469a2..abea1205 100644 --- a/src/croc/croc_test.go +++ b/src/croc/croc_test.go @@ -27,6 +27,7 @@ func TestCroc(t *testing.T) { SharedSecret: "test", Debug: true, RelayAddress: "localhost:8081", + RelayPorts: []string{"8081"}, Stdout: false, NoPrompt: true, DisableLocal: true, diff --git a/src/message/message.go b/src/message/message.go index 356e81c5..b5e20bc5 100644 --- a/src/message/message.go +++ b/src/message/message.go @@ -2,7 +2,7 @@ package message import ( "encoding/json" - + log "github.com/cihub/seelog" "github.com/schollz/croc/v6/src/comm" "github.com/schollz/croc/v6/src/compress" @@ -28,7 +28,7 @@ func Send(c *comm.Comm, key crypt.Encryption, m Message) (err error) { if err != nil { return } - log.Debugf("writing %s message (%d bytes)",m.Type,len(mSend)) + log.Debugf("writing %s message (%d bytes)", m.Type, len(mSend)) _, err = c.Write(mSend) return } diff --git a/src/tcp/tcp.go b/src/tcp/tcp.go index 441367b8..c9a67acf 100644 --- a/src/tcp/tcp.go +++ b/src/tcp/tcp.go @@ -59,7 +59,7 @@ func (s *server) start() (err error) { s.rooms.Lock() for room := range s.rooms.rooms { if time.Since(s.rooms.rooms[room].opened) > 3*time.Hour { - roomsToDelete = append(roomsToDelete,room) + roomsToDelete = append(roomsToDelete, room) } } s.rooms.Unlock() @@ -248,8 +248,12 @@ func pipe(conn1 net.Conn, conn2 net.Conn) { } } -func ConnectToTCPServer(address, room string) (c *comm.Comm, banner string, ipaddr string, err error) { - c, err = comm.NewConnection(address) +func ConnectToTCPServer(address, room string, timelimit ...time.Duration) (c *comm.Comm, banner string, ipaddr string, err error) { + if len(timelimit) > 0 { + c, err = comm.NewConnection(address, timelimit[0]) + } else { + c, err = comm.NewConnection(address) + } if err != nil { return } diff --git a/src/utils/utils.go b/src/utils/utils.go index 24deefce..adcd017a 100644 --- a/src/utils/utils.go +++ b/src/utils/utils.go @@ -209,3 +209,20 @@ func ChunkRangesToChunks(chunkRanges []int64) (chunks []int64) { } return } + +func GetLocalIPs() (ips []string, err error) { + addrs, err := net.InterfaceAddrs() + if err != nil { + return + } + ips = []string{} + for _, address := range addrs { + // check the address type and if it is not a loopback the display it + if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { + if ipnet.IP.To4() != nil { + ips = append(ips, ipnet.IP.String()) + } + } + } + return +} diff --git a/src/utils/utils_test.go b/src/utils/utils_test.go index 520dacb3..6346dbdb 100644 --- a/src/utils/utils_test.go +++ b/src/utils/utils_test.go @@ -35,6 +35,7 @@ func BenchmarkImoHash(b *testing.B) { } func TestExists(t *testing.T) { + fmt.Println(GetLocalIPs()) assert.True(t, Exists("bigfile.test")) assert.False(t, Exists("doesnotexist")) }