Use relay as backup to find local ports (#127)

This commit is contained in:
Zack 2019-05-03 13:51:27 -07:00 committed by GitHub
parent fef1c3ca3b
commit 1f3d30c78e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 108 additions and 25 deletions

View File

@ -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 {

View File

@ -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
}

View File

@ -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")
@ -707,7 +762,6 @@ func (c *Client) updateState() (err error) {
Bytes: bRequest,
})
if err != nil {
log.Error(err)
return
}
c.Step3RecipientRequestFile = true

View File

@ -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,

View File

@ -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) {
if len(timelimit) > 0 {
c, err = comm.NewConnection(address, timelimit[0])
} else {
c, err = comm.NewConnection(address)
}
if err != nil {
return
}

View File

@ -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
}

View File

@ -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"))
}