Example #1
0
func (s *Svc) CommitConfiguration(from, to config.Configuration) bool {
	existing := make(map[string]*url.URL, len(to.Options.RelayServers))

	for _, addr := range to.Options.RelayServers {
		uri, err := url.Parse(addr)
		if err != nil {
			l.Debugln("Failed to parse relay address", addr, err)
			continue
		}
		existing[uri.String()] = uri
	}

	s.mut.Lock()

	for key, uri := range existing {
		_, ok := s.tokens[key]
		if !ok {
			l.Debugln("Connecting to relay", uri)
			c, err := client.NewClient(uri, s.tlsCfg.Certificates, s.invitations, 10*time.Second)
			if err != nil {
				l.Infoln("Failed to connect to relay", uri, err)
				continue
			}
			s.tokens[key] = s.Add(c)
			s.clients[key] = c
		}
	}

	for key, token := range s.tokens {
		_, ok := existing[key]
		if !ok {
			err := s.Remove(token)
			delete(s.tokens, key)
			delete(s.clients, key)
			l.Debugln("Disconnecting from relay", key, err)
		}
	}

	s.mut.Unlock()

	return true
}
Example #2
0
func (t *relayListener) Serve() {
	t.mut.Lock()
	t.err = nil
	t.mut.Unlock()

	clnt, err := client.NewClient(t.uri, t.tlsCfg.Certificates, nil, 10*time.Second)
	if err != nil {
		t.mut.Lock()
		t.err = err
		t.mut.Unlock()
		l.Warnln("listen (BEP/relay):", err)
		return
	}

	go clnt.Serve()

	t.mut.Lock()
	t.client = clnt
	t.mut.Unlock()

	oldURI := clnt.URI()

	for {
		select {
		case inv, ok := <-t.client.Invitations():
			if !ok {
				return
			}

			conn, err := client.JoinSession(inv)
			if err != nil {
				l.Warnln("Joining relay session (BEP/relay):", err)
				continue
			}

			err = dialer.SetTCPOptions(conn.(*net.TCPConn))
			if err != nil {
				l.Infoln(err)
			}

			var tc *tls.Conn
			if inv.ServerSocket {
				tc = tls.Server(conn, t.tlsCfg)
			} else {
				tc = tls.Client(conn, t.tlsCfg)
			}

			err = tc.Handshake()
			if err != nil {
				tc.Close()
				l.Infoln("TLS handshake (BEP/relay):", err)
				continue
			}

			t.conns <- IntermediateConnection{tc, "Relay (Server)", relayPriority}

		// Poor mans notifier that informs the connection service that the
		// relay URI has changed. This can only happen when we connect to a
		// relay via dynamic+http(s) pool, which upon a relay failing/dropping
		// us, would pick a different one.
		case <-time.After(10 * time.Second):
			currentURI := clnt.URI()
			if currentURI != oldURI {
				oldURI = currentURI
				t.notifyAddressesChanged(t)
			}
		}
	}
}
Example #3
0
func main() {
	log.SetOutput(os.Stdout)
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	var connect, relay, dir string
	var join, test bool

	flag.StringVar(&connect, "connect", "", "Device ID to which to connect to")
	flag.BoolVar(&join, "join", false, "Join relay")
	flag.BoolVar(&test, "test", false, "Generic relay test")
	flag.StringVar(&relay, "relay", "relay://127.0.0.1:22067", "Relay address")
	flag.StringVar(&dir, "keys", ".", "Directory where cert.pem and key.pem is stored")

	flag.Parse()

	certFile, keyFile := filepath.Join(dir, "cert.pem"), filepath.Join(dir, "key.pem")
	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		log.Fatalln("Failed to load X509 key pair:", err)
	}

	id := syncthingprotocol.NewDeviceID(cert.Certificate[0])
	log.Println("ID:", id)

	uri, err := url.Parse(relay)
	if err != nil {
		log.Fatal(err)
	}

	stdin := make(chan string)

	go stdinReader(stdin)

	if join {
		log.Println("Creating client")
		relay, err := client.NewClient(uri, []tls.Certificate{cert}, nil, 10*time.Second)
		if err != nil {
			log.Fatal(err)
		}
		log.Println("Created client")

		go relay.Serve()

		recv := make(chan protocol.SessionInvitation)

		go func() {
			log.Println("Starting invitation receiver")
			for invite := range relay.Invitations() {
				select {
				case recv <- invite:
					log.Println("Received invitation", invite)
				default:
					log.Println("Discarding invitation", invite)
				}
			}
		}()

		for {
			conn, err := client.JoinSession(<-recv)
			if err != nil {
				log.Fatalln("Failed to join", err)
			}
			log.Println("Joined", conn.RemoteAddr(), conn.LocalAddr())
			connectToStdio(stdin, conn)
			log.Println("Finished", conn.RemoteAddr(), conn.LocalAddr())
		}
	} else if connect != "" {
		id, err := syncthingprotocol.DeviceIDFromString(connect)
		if err != nil {
			log.Fatal(err)
		}

		invite, err := client.GetInvitationFromRelay(uri, id, []tls.Certificate{cert}, 10*time.Second)
		if err != nil {
			log.Fatal(err)
		}

		log.Println("Received invitation", invite)
		conn, err := client.JoinSession(invite)
		if err != nil {
			log.Fatalln("Failed to join", err)
		}
		log.Println("Joined", conn.RemoteAddr(), conn.LocalAddr())
		connectToStdio(stdin, conn)
		log.Println("Finished", conn.RemoteAddr(), conn.LocalAddr())
	} else if test {
		if client.TestRelay(uri, []tls.Certificate{cert}, time.Second, 2*time.Second, 4) {
			log.Println("OK")
		} else {
			log.Println("FAIL")
		}
	} else {
		log.Fatal("Requires either join or connect")
	}
}