// returns the two endpoints of a TCP connection over lo0 func getTCPConnectionPair() (net.Conn, net.Conn, error) { lst, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { return nil, nil, err } // We run the Accept in the background since it's blocking, and we use // the channel to make the race thingies happy about writing vs reading // conn0 and err0. var conn0 net.Conn var err0 error done := make(chan struct{}) go func() { conn0, err0 = lst.Accept() close(done) }() // Dial the connection conn1, err := net.Dial("tcp", lst.Addr().String()) if err != nil { return nil, nil, err } // Check any error from accept <-done if err0 != nil { return nil, nil, err0 } // Set the buffer sizes etc as usual dialer.SetTCPOptions(conn0) dialer.SetTCPOptions(conn1) return conn0, conn1, nil }
func (d *tcpDialer) Dial(id protocol.DeviceID, uri *url.URL) (internalConn, error) { uri = fixupPort(uri) conn, err := dialer.DialTimeout(uri.Scheme, uri.Host, 10*time.Second) if err != nil { l.Debugln(err) return internalConn{}, err } err = dialer.SetTCPOptions(conn) if err != nil { l.Infoln(err) } err = dialer.SetTrafficClass(conn, d.cfg.Options().TrafficClass) if err != nil { l.Debugf("failed to set traffic class: %s", err) } tc := tls.Client(conn, d.tlsCfg) err = tlsTimedHandshake(tc) if err != nil { tc.Close() return internalConn{}, err } return internalConn{tc, connTypeTCPClient, tcpPriority}, nil }
func (d *relayDialer) Dial(id protocol.DeviceID, uri *url.URL) (IntermediateConnection, error) { inv, err := client.GetInvitationFromRelay(uri, id, d.tlsCfg.Certificates, 10*time.Second) if err != nil { return IntermediateConnection{}, err } conn, err := client.JoinSession(inv) if err != nil { return IntermediateConnection{}, err } err = dialer.SetTCPOptions(conn) if err != nil { conn.Close() return IntermediateConnection{}, err } var tc *tls.Conn if inv.ServerSocket { tc = tls.Server(conn, d.tlsCfg) } else { tc = tls.Client(conn, d.tlsCfg) } err = tc.Handshake() if err != nil { tc.Close() return IntermediateConnection{}, err } return IntermediateConnection{tc, "Relay (Client)", relayPriority}, nil }
func makeTCPListener(network string) ListenerFactory { return func(uri *url.URL, tlsCfg *tls.Config, conns chan<- model.IntermediateConnection) { tcaddr, err := net.ResolveTCPAddr(network, uri.Host) if err != nil { l.Fatalln("listen (BEP/tcp):", err) return } listener, err := net.ListenTCP(network, 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 } l.Debugln("connect from", conn.RemoteAddr()) err = dialer.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{ Conn: tc, Type: model.ConnectionTypeDirectAccept, } } } }
func (d *relayDialer) Dial(id protocol.DeviceID, uri *url.URL) (internalConn, error) { inv, err := client.GetInvitationFromRelay(uri, id, d.tlsCfg.Certificates, 10*time.Second) if err != nil { return internalConn{}, err } conn, err := client.JoinSession(inv) if err != nil { return internalConn{}, err } err = dialer.SetTCPOptions(conn) if err != nil { conn.Close() return internalConn{}, err } err = dialer.SetTrafficClass(conn, d.cfg.Options().TrafficClass) if err != nil { l.Debugf("failed to set traffic class: %s", err) } var tc *tls.Conn if inv.ServerSocket { tc = tls.Server(conn, d.tlsCfg) } else { tc = tls.Client(conn, d.tlsCfg) } err = tlsTimedHandshake(tc) if err != nil { tc.Close() return internalConn{}, err } return internalConn{tc, connTypeRelayClient, relayPriority}, nil }
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) } } } }
func (t *tcpListener) Serve() { t.mut.Lock() t.err = nil t.mut.Unlock() tcaddr, err := net.ResolveTCPAddr(t.uri.Scheme, t.uri.Host) if err != nil { t.mut.Lock() t.err = err t.mut.Unlock() l.Infoln("listen (BEP/tcp):", err) return } listener, err := net.ListenTCP(t.uri.Scheme, tcaddr) if err != nil { t.mut.Lock() t.err = err t.mut.Unlock() l.Infoln("listen (BEP/tcp):", err) return } defer listener.Close() l.Infof("TCP listener (%v) starting", listener.Addr()) defer l.Infof("TCP listener (%v) shutting down", listener.Addr()) mapping := t.natService.NewMapping(nat.TCP, tcaddr.IP, tcaddr.Port) mapping.OnChanged(func(_ *nat.Mapping, _, _ []nat.Address) { t.notifyAddressesChanged(t) }) defer t.natService.RemoveMapping(mapping) t.mut.Lock() t.mapping = mapping t.mut.Unlock() for { listener.SetDeadline(time.Now().Add(time.Second)) conn, err := listener.Accept() select { case <-t.stop: if err == nil { conn.Close() } t.mut.Lock() t.mapping = nil t.mut.Unlock() return default: } if err != nil { if err, ok := err.(*net.OpError); !ok || !err.Timeout() { l.Warnln("Accepting connection (BEP/tcp):", err) } continue } l.Debugln("connect from", conn.RemoteAddr()) err = dialer.SetTCPOptions(conn) if err != nil { l.Infoln(err) } tc := tls.Server(conn, t.tlsCfg) err = tc.Handshake() if err != nil { l.Infoln("TLS handshake (BEP/tcp):", err) tc.Close() continue } t.conns <- IntermediateConnection{tc, "TCP (Server)", tcpPriority} } }