// Dial tries dialing via proxy if a proxy is configured, and falls back to // a direct connection if no proxy is defined, or connecting via proxy fails. func Dial(network, addr string) (net.Conn, error) { if usingProxy { conn, err := dialer.Dial(network, addr) if err == nil { l.Debugf("Dialing %s address %s via proxy - success, %s -> %s", network, addr, conn.LocalAddr(), conn.RemoteAddr()) if tcpconn, ok := conn.(*net.TCPConn); ok { osutil.SetTCPOptions(tcpconn) } return dialerConn{ conn, newDialerAddr(network, addr), }, nil } l.Debugf("Dialing %s address %s via proxy - error %s", network, addr, err) } conn, err := proxy.Direct.Dial(network, addr) if err == nil { l.Debugf("Dialing %s address %s directly - success, %s -> %s", network, addr, conn.LocalAddr(), conn.RemoteAddr()) if tcpconn, ok := conn.(*net.TCPConn); ok { osutil.SetTCPOptions(tcpconn) } } else { l.Debugf("Dialing %s address %s directly - error %s", network, addr, err) } return conn, err }
func dialWithFallback(proxyDialFunc dialFunc, fallbackDialFunc dialFunc, network, addr string) (net.Conn, error) { conn, err := proxyDialFunc(network, addr) if err == nil { l.Debugf("Dialing %s address %s via proxy - success, %s -> %s", network, addr, conn.LocalAddr(), conn.RemoteAddr()) if tcpconn, ok := conn.(*net.TCPConn); ok { osutil.SetTCPOptions(tcpconn) } return dialerConn{ conn, newDialerAddr(network, addr), }, nil } l.Debugf("Dialing %s address %s via proxy - error %s", network, addr, err) conn, err = fallbackDialFunc(network, addr) if err == nil { l.Debugf("Dialing %s address %s via fallback - success, %s -> %s", network, addr, conn.LocalAddr(), conn.RemoteAddr()) if tcpconn, ok := conn.(*net.TCPConn); ok { osutil.SetTCPOptions(tcpconn) } } else { l.Debugf("Dialing %s address %s via fallback - error %s", network, addr, err) } return conn, err }
func (r *invitationReceiver) Serve() { if r.stop != nil { return } r.stop = make(chan struct{}) for { select { case inv := <-r.invitations: if debug { l.Debugln("Received relay invitation", inv) } conn, err := client.JoinSession(inv) if err != nil { if debug { l.Debugf("Failed to join relay session %s: %v", inv, err) } continue } err = osutil.SetTCPOptions(conn.(*net.TCPConn)) if err != nil { l.Infoln(err) } var tc *tls.Conn if inv.ServerSocket { tc = tls.Server(conn, r.tlsCfg) } else { tc = tls.Client(conn, r.tlsCfg) } err = tc.Handshake() if err != nil { l.Infof("TLS handshake (BEP/relay %s): %v", inv, err) tc.Close() continue } r.conns <- model.IntermediateConnection{ tc, model.ConnectionTypeRelayAccept, } case <-r.stop: return } } }
func tcpListener(uri *url.URL, tlsCfg *tls.Config, conns chan<- model.IntermediateConnection) { tcaddr, err := net.ResolveTCPAddr("tcp", uri.Host) if err != nil { l.Fatalln("listen (BEP/tcp):", err) return } listener, err := net.ListenTCP("tcp", tcaddr) if err != nil { l.Fatalln("listen (BEP/tcp):", err) return } for { conn, err := listener.Accept() if err != nil { l.Warnln("Accepting connection (BEP/tcp):", err) continue } if debugNet { l.Debugln("connect from", conn.RemoteAddr()) } err = osutil.SetTCPOptions(conn.(*net.TCPConn)) if err != nil { l.Infoln(err) } tc := tls.Server(conn, tlsCfg) err = tc.Handshake() if err != nil { l.Infoln("TLS handshake (BEP/tcp):", err) tc.Close() continue } conns <- model.IntermediateConnection{ tc, model.ConnectionTypeBasicAccept, } } }
func tcpDialer(uri *url.URL, tlsCfg *tls.Config) (*tls.Conn, error) { host, port, err := net.SplitHostPort(uri.Host) if err != nil && strings.HasPrefix(err.Error(), "missing port") { // addr is on the form "1.2.3.4" uri.Host = net.JoinHostPort(uri.Host, "22000") } else if err == nil && port == "" { // addr is on the form "1.2.3.4:" uri.Host = net.JoinHostPort(host, "22000") } raddr, err := net.ResolveTCPAddr("tcp", uri.Host) if err != nil { if debugNet { l.Debugln(err) } return nil, err } conn, err := net.DialTCP("tcp", nil, raddr) if err != nil { if debugNet { l.Debugln(err) } return nil, err } err = osutil.SetTCPOptions(conn) if err != nil { l.Infoln(err) } tc := tls.Client(conn, tlsCfg) err = tc.Handshake() if err != nil { tc.Close() return nil, err } return tc, nil }
func (r *invitationReceiver) Serve() { for { select { case inv := <-r.invitations: l.Debugln("Received relay invitation", inv) conn, err := client.JoinSession(inv) if err != nil { l.Debugf("Failed to join relay session %s: %v", inv, err) continue } err = osutil.SetTCPOptions(conn.(*net.TCPConn)) if err != nil { l.Infoln(err) } var tc *tls.Conn if inv.ServerSocket { tc = tls.Server(conn, r.tlsCfg) } else { tc = tls.Client(conn, r.tlsCfg) } err = tc.Handshake() if err != nil { l.Infof("TLS handshake (BEP/relay %s): %v", inv, err) tc.Close() continue } r.conns <- tc case <-r.stop: return } } }
func (s *connectionSvc) connect() { delay := time.Second for { nextDevice: for deviceID, deviceCfg := range s.cfg.Devices() { if deviceID == myID { continue } if s.model.IsPaused(deviceID) { continue } connected := s.model.ConnectedTo(deviceID) s.mut.RLock() ct, ok := s.connType[deviceID] relaysEnabled := s.relaysEnabled s.mut.RUnlock() if connected && ok && ct.IsDirect() { continue } var addrs []string var relays []discover.Relay for _, addr := range deviceCfg.Addresses { if addr == "dynamic" { if s.discoverer != nil { if t, r, err := s.discoverer.Lookup(deviceID); err == nil { addrs = append(addrs, t...) relays = append(relays, r...) } } } else { addrs = append(addrs, addr) } } for _, addr := range addrs { uri, err := url.Parse(addr) if err != nil { l.Infoln("Failed to parse connection url:", addr, err) continue } dialer, ok := dialers[uri.Scheme] if !ok { l.Infoln("Unknown address schema", uri.String()) continue } if debugNet { l.Debugln("dial", deviceCfg.DeviceID, uri.String()) } conn, err := dialer(uri, s.tlsCfg) if err != nil { if debugNet { l.Debugln("dial failed", deviceCfg.DeviceID, uri.String(), err) } continue } if connected { s.model.Close(deviceID, fmt.Errorf("switching connections")) } s.conns <- model.IntermediateConnection{ conn, model.ConnectionTypeDirectDial, } continue nextDevice } // Only connect via relays if not already connected // Also, do not set lastRelayCheck time if we have no relays, // as otherwise when we do discover relays, we might have to // wait up to RelayReconnectIntervalM to connect again. // Also, do not try relays if we are explicitly told not to. if connected || len(relays) == 0 || !relaysEnabled { continue nextDevice } reconIntv := time.Duration(s.cfg.Options().RelayReconnectIntervalM) * time.Minute if last, ok := s.lastRelayCheck[deviceID]; ok && time.Since(last) < reconIntv { if debugNet { l.Debugln("Skipping connecting via relay to", deviceID, "last checked at", last) } continue nextDevice } else if debugNet { l.Debugln("Trying relay connections to", deviceID, relays) } s.lastRelayCheck[deviceID] = time.Now() for _, addr := range relays { uri, err := url.Parse(addr.URL) if err != nil { l.Infoln("Failed to parse relay connection url:", addr, err) continue } inv, err := client.GetInvitationFromRelay(uri, deviceID, s.tlsCfg.Certificates) if err != nil { if debugNet { l.Debugf("Failed to get invitation for %s from %s: %v", deviceID, uri, err) } continue } else if debugNet { l.Debugln("Succesfully retrieved relay invitation", inv, "from", uri) } conn, err := client.JoinSession(inv) if err != nil { if debugNet { l.Debugf("Failed to join relay session %s: %v", inv, err) } continue } else if debugNet { l.Debugln("Sucessfully joined relay session", inv) } err = osutil.SetTCPOptions(conn.(*net.TCPConn)) if err != nil { l.Infoln(err) } var tc *tls.Conn if inv.ServerSocket { tc = tls.Server(conn, s.tlsCfg) } else { tc = tls.Client(conn, s.tlsCfg) } err = tc.Handshake() if err != nil { l.Infof("TLS handshake (BEP/relay %s): %v", inv, err) tc.Close() continue } s.conns <- model.IntermediateConnection{ tc, model.ConnectionTypeRelayDial, } continue nextDevice } } time.Sleep(delay) delay *= 2 if maxD := time.Duration(s.cfg.Options().ReconnectIntervalS) * time.Second; delay > maxD { delay = maxD } } }