mirror of https://github.com/schollz/croc.git
Use relay as backup to find local ports (#127)
This commit is contained in:
parent
fef1c3ca3b
commit
1f3d30c78e
|
@ -21,7 +21,7 @@ import (
|
||||||
var Version string
|
var Version string
|
||||||
|
|
||||||
func Run() (err error) {
|
func Run() (err error) {
|
||||||
// use all of the processors
|
// use all of the processors
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
|
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
|
@ -42,6 +42,7 @@ func Run() (err error) {
|
||||||
ArgsUsage: "[filename]",
|
ArgsUsage: "[filename]",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.StringFlag{Name: "code, c", Usage: "codephrase used to connect to relay"},
|
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)"},
|
cli.StringFlag{Name: "ports", Value: "9009,9010,9011,9012,9013", Usage: "ports of the local relay (optional)"},
|
||||||
},
|
},
|
||||||
HelpName: "croc send",
|
HelpName: "croc send",
|
||||||
|
@ -167,6 +168,7 @@ func send(c *cli.Context) (err error) {
|
||||||
NoPrompt: c.GlobalBool("yes"),
|
NoPrompt: c.GlobalBool("yes"),
|
||||||
RelayAddress: c.GlobalString("relay"),
|
RelayAddress: c.GlobalString("relay"),
|
||||||
Stdout: c.GlobalBool("stdout"),
|
Stdout: c.GlobalBool("stdout"),
|
||||||
|
DisableLocal: c.Bool("no-local"),
|
||||||
RelayPorts: strings.Split(c.String("ports"), ","),
|
RelayPorts: strings.Split(c.String("ports"), ","),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -16,8 +16,12 @@ type Comm struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConnection gets a new comm to a tcp address
|
// NewConnection gets a new comm to a tcp address
|
||||||
func NewConnection(address string) (c *Comm, err error) {
|
func NewConnection(address string, timelimit ...time.Duration) (c *Comm, err error) {
|
||||||
connection, err := net.DialTimeout("tcp", address, 30*time.Second)
|
tlimit := 30 * time.Second
|
||||||
|
if len(timelimit) > 0 {
|
||||||
|
tlimit = timelimit[0]
|
||||||
|
}
|
||||||
|
connection, err := net.DialTimeout("tcp", address, tlimit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,10 +76,10 @@ type Client struct {
|
||||||
FilesToTransferCurrentNum int
|
FilesToTransferCurrentNum int
|
||||||
|
|
||||||
// send / receive information of current file
|
// send / receive information of current file
|
||||||
CurrentFile *os.File
|
CurrentFile *os.File
|
||||||
CurrentFileChunkRanges []int64
|
CurrentFileChunkRanges []int64
|
||||||
CurrentFileChunks []int64
|
CurrentFileChunks []int64
|
||||||
|
|
||||||
TotalSent int64
|
TotalSent int64
|
||||||
TotalChunksTransfered int
|
TotalChunksTransfered int
|
||||||
chunkMap map[uint64]struct{}
|
chunkMap map[uint64]struct{}
|
||||||
|
@ -113,7 +113,7 @@ type FileInfo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type RemoteFileRequest struct {
|
type RemoteFileRequest struct {
|
||||||
CurrentFileChunkRanges []int64
|
CurrentFileChunkRanges []int64
|
||||||
FilesToTransferCurrentNum int
|
FilesToTransferCurrentNum int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,6 +304,22 @@ func (c *Client) Send(options TransferOptions) (err error) {
|
||||||
log.Debugf("connection established: %+v", conn)
|
log.Debugf("connection established: %+v", conn)
|
||||||
for {
|
for {
|
||||||
data, _ := conn.Receive()
|
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")) {
|
if bytes.Equal(data, []byte("handshake")) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -324,6 +340,7 @@ func (c *Client) Receive() (err error) {
|
||||||
fmt.Fprintf(os.Stderr, "connecting...")
|
fmt.Fprintf(os.Stderr, "connecting...")
|
||||||
// recipient will look for peers first
|
// recipient will look for peers first
|
||||||
// and continue if it doesn't find any within 100 ms
|
// and continue if it doesn't find any within 100 ms
|
||||||
|
usingLocal := false
|
||||||
if !c.Options.DisableLocal {
|
if !c.Options.DisableLocal {
|
||||||
log.Debug("attempt to discover peers")
|
log.Debug("attempt to discover peers")
|
||||||
discoveries, err := peerdiscovery.Discover(peerdiscovery.Settings{
|
discoveries, err := peerdiscovery.Discover(peerdiscovery.Settings{
|
||||||
|
@ -336,6 +353,7 @@ func (c *Client) Receive() (err error) {
|
||||||
log.Debug("switching to local")
|
log.Debug("switching to local")
|
||||||
c.Options.RelayAddress = fmt.Sprintf("%s:%s", discoveries[0].Address, discoveries[0].Payload)
|
c.Options.RelayAddress = fmt.Sprintf("%s:%s", discoveries[0].Address, discoveries[0].Payload)
|
||||||
c.ExternalIPConnected = c.Options.RelayAddress
|
c.ExternalIPConnected = c.Options.RelayAddress
|
||||||
|
usingLocal = true
|
||||||
}
|
}
|
||||||
log.Debugf("discoveries: %+v", discoveries)
|
log.Debugf("discoveries: %+v", discoveries)
|
||||||
log.Debug("establishing connection")
|
log.Debug("establishing connection")
|
||||||
|
@ -348,6 +366,43 @@ func (c *Client) Receive() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debugf("connection established: %+v", c.conn[0])
|
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.conn[0].Send([]byte("handshake"))
|
||||||
c.Options.RelayPorts = strings.Split(banner, ",")
|
c.Options.RelayPorts = strings.Split(banner, ",")
|
||||||
log.Debug("exchanged header message")
|
log.Debug("exchanged header message")
|
||||||
|
@ -379,12 +434,12 @@ func (c *Client) transfer(options TransferOptions) (err error) {
|
||||||
var done bool
|
var done bool
|
||||||
data, err = c.conn[0].Receive()
|
data, err = c.conn[0].Receive()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("got error receiving: %s",err.Error())
|
log.Debugf("got error receiving: %s", err.Error())
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
done, err = c.processMessage(data)
|
done, err = c.processMessage(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("got error processing: %s",err.Error())
|
log.Debugf("got error processing: %s", err.Error())
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if done {
|
if done {
|
||||||
|
@ -572,12 +627,12 @@ func (c *Client) processMessage(payload []byte) (done bool, err error) {
|
||||||
c.Step3RecipientRequestFile = false
|
c.Step3RecipientRequestFile = false
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("got error from processing message: %s",err.Error())
|
log.Debugf("got error from processing message: %s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = c.updateState()
|
err = c.updateState()
|
||||||
if err != nil {
|
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
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -609,12 +664,12 @@ func (c *Client) updateState() (err error) {
|
||||||
finished := true
|
finished := true
|
||||||
|
|
||||||
for i, fileInfo := range c.FilesToTransfer {
|
for i, fileInfo := range c.FilesToTransfer {
|
||||||
log.Debugf("checking %+v",fileInfo)
|
log.Debugf("checking %+v", fileInfo)
|
||||||
if i < c.FilesToTransferCurrentNum {
|
if i < c.FilesToTransferCurrentNum {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fileHash, errHash := utils.HashFile(path.Join(fileInfo.FolderRemote, fileInfo.Name))
|
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 || !bytes.Equal(fileHash, fileInfo.Hash) {
|
||||||
if errHash != nil {
|
if errHash != nil {
|
||||||
// probably can't find, its okay
|
// probably can't find, its okay
|
||||||
|
@ -692,7 +747,7 @@ func (c *Client) updateState() (err error) {
|
||||||
|
|
||||||
c.TotalSent = 0
|
c.TotalSent = 0
|
||||||
bRequest, _ := json.Marshal(RemoteFileRequest{
|
bRequest, _ := json.Marshal(RemoteFileRequest{
|
||||||
CurrentFileChunkRanges: c.CurrentFileChunkRanges,
|
CurrentFileChunkRanges: c.CurrentFileChunkRanges,
|
||||||
FilesToTransferCurrentNum: c.FilesToTransferCurrentNum,
|
FilesToTransferCurrentNum: c.FilesToTransferCurrentNum,
|
||||||
})
|
})
|
||||||
log.Debug("converting to chunk range")
|
log.Debug("converting to chunk range")
|
||||||
|
@ -701,13 +756,12 @@ func (c *Client) updateState() (err error) {
|
||||||
// setup the progressbar
|
// setup the progressbar
|
||||||
c.setBar()
|
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{
|
err = message.Send(c.conn[0], c.Key, message.Message{
|
||||||
Type: "recipientready",
|
Type: "recipientready",
|
||||||
Bytes: bRequest,
|
Bytes: bRequest,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Step3RecipientRequestFile = true
|
c.Step3RecipientRequestFile = true
|
||||||
|
@ -724,7 +778,7 @@ func (c *Client) updateState() (err error) {
|
||||||
c.TotalSent = 0
|
c.TotalSent = 0
|
||||||
log.Debug("beginning sending comms")
|
log.Debug("beginning sending comms")
|
||||||
for i := 0; i < len(c.Options.RelayPorts); i++ {
|
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)
|
go c.sendData(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -750,12 +804,12 @@ func (c *Client) setBar() {
|
||||||
)
|
)
|
||||||
byteToDo := int64(len(c.CurrentFileChunks) * models.TCP_BUFFER_SIZE / 2)
|
byteToDo := int64(len(c.CurrentFileChunks) * models.TCP_BUFFER_SIZE / 2)
|
||||||
if byteToDo > 0 {
|
if byteToDo > 0 {
|
||||||
bytesDone := c.FilesToTransfer[c.FilesToTransferCurrentNum].Size -byteToDo
|
bytesDone := c.FilesToTransfer[c.FilesToTransferCurrentNum].Size - byteToDo
|
||||||
log.Debug(byteToDo)
|
log.Debug(byteToDo)
|
||||||
log.Debug(c.FilesToTransfer[c.FilesToTransferCurrentNum].Size)
|
log.Debug(c.FilesToTransfer[c.FilesToTransferCurrentNum].Size)
|
||||||
log.Debug(bytesDone)
|
log.Debug(bytesDone)
|
||||||
if bytesDone > 0 {
|
if bytesDone > 0 {
|
||||||
c.bar.Add64(bytesDone)
|
c.bar.Add64(bytesDone)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ func TestCroc(t *testing.T) {
|
||||||
SharedSecret: "test",
|
SharedSecret: "test",
|
||||||
Debug: true,
|
Debug: true,
|
||||||
RelayAddress: "localhost:8081",
|
RelayAddress: "localhost:8081",
|
||||||
|
RelayPorts: []string{"8081"},
|
||||||
Stdout: false,
|
Stdout: false,
|
||||||
NoPrompt: true,
|
NoPrompt: true,
|
||||||
DisableLocal: true,
|
DisableLocal: true,
|
||||||
|
|
|
@ -2,7 +2,7 @@ package message
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
log "github.com/cihub/seelog"
|
log "github.com/cihub/seelog"
|
||||||
"github.com/schollz/croc/v6/src/comm"
|
"github.com/schollz/croc/v6/src/comm"
|
||||||
"github.com/schollz/croc/v6/src/compress"
|
"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 {
|
if err != nil {
|
||||||
return
|
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)
|
_, err = c.Write(mSend)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ func (s *server) start() (err error) {
|
||||||
s.rooms.Lock()
|
s.rooms.Lock()
|
||||||
for room := range s.rooms.rooms {
|
for room := range s.rooms.rooms {
|
||||||
if time.Since(s.rooms.rooms[room].opened) > 3*time.Hour {
|
if time.Since(s.rooms.rooms[room].opened) > 3*time.Hour {
|
||||||
roomsToDelete = append(roomsToDelete,room)
|
roomsToDelete = append(roomsToDelete, room)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.rooms.Unlock()
|
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) {
|
func ConnectToTCPServer(address, room string, timelimit ...time.Duration) (c *comm.Comm, banner string, ipaddr string, err error) {
|
||||||
c, err = comm.NewConnection(address)
|
if len(timelimit) > 0 {
|
||||||
|
c, err = comm.NewConnection(address, timelimit[0])
|
||||||
|
} else {
|
||||||
|
c, err = comm.NewConnection(address)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,3 +209,20 @@ func ChunkRangesToChunks(chunkRanges []int64) (chunks []int64) {
|
||||||
}
|
}
|
||||||
return
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ func BenchmarkImoHash(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExists(t *testing.T) {
|
func TestExists(t *testing.T) {
|
||||||
|
fmt.Println(GetLocalIPs())
|
||||||
assert.True(t, Exists("bigfile.test"))
|
assert.True(t, Exists("bigfile.test"))
|
||||||
assert.False(t, Exists("doesnotexist"))
|
assert.False(t, Exists("doesnotexist"))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue