func (o *Overlay) tunneler(ip net.IP, live chan struct{}, quit chan chan error) { // Listen for incoming streams on the given interface and random port. addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(ip.String(), "0")) if err != nil { panic(fmt.Sprintf("failed to resolve interface (%v): %v.", ip, err)) } sock, err := stream.Listen(addr) if err != nil { panic(fmt.Sprintf("failed to start stream listener: %v.", err)) } sock.Accept(config.IrisTunnelAcceptTimeout) // Save the new listener address into the local (sorted) address list o.lock.Lock() o.tunAddrs = append(o.tunAddrs, addr.String()) sort.Strings(o.tunAddrs) o.lock.Unlock() // Notify the overlay of the successful listen live <- struct{}{} // Process incoming connection until termination is requested var errc chan error for errc == nil { select { case errc = <-quit: // Terminating, close and return continue case strm := <-sock.Sink: // There's a hidden panic possibility here: the listener socket can fail // if the system is overloaded with open connections. Alas, solving it is // not trivial as it would require restarting the whole listener. Figure it // out eventually. // Initialize and authorize the inbound tunnel if err := o.initServerTunnel(strm); err != nil { log.Printf("iris: failed to initialize server tunnel: %v.", err) if err := strm.Close(); err != nil { log.Printf("iris: failed to terminate uninitialized tunnel stream: %v.", err) } } } } // Terminate the peer listener errv := sock.Close() if errv != nil { log.Printf("iris: failed to terminate tunnel listener: %v.", err) } errc <- errv }
// Starts a TCP listener to accept incoming sessions, returning the socket ready // to accept. If an auto-port (0) is requested, the port is updated in the arg. func Listen(addr *net.TCPAddr, key *rsa.PrivateKey) (*Listener, error) { // Open the stream listener socket sock, err := stream.Listen(addr) if err != nil { return nil, err } // Assemble and return the session listener return &Listener{ Sink: make(chan *Session), pends: make(map[int64]chan *stream.Stream), socket: sock, key: key, quit: make(chan chan error), }, nil }
func server(live, quit chan struct{}) { // Open a TCP port to accept incoming stream connections addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", host, port)) if err != nil { fmt.Println("Failed to resolve local address:", err) return } sock, err := stream.Listen(addr) if err != nil { fmt.Println("Failed to listen for incoming streams:", err) return } sock.Accept(time.Second) live <- struct{}{} // While not exiting, process stream connections for { select { case <-quit: if err = sock.Close(); err != nil { fmt.Println("Failed to terminate stream listener:", err) } return case strm := <-sock.Sink: defer strm.Close() // Receive and echo back a string var data string if err = strm.Recv(&data); err != nil { fmt.Println("Failed to receive a string object:", err) continue } if err = strm.Send(&data); err != nil { fmt.Println("Failed to send back a string object:", err) continue } if err = strm.Flush(); err != nil { fmt.Println("Failed to flush the response:", err) return } } } }
// Tests the low level send and receive methods. func TestDirectSendRecv(t *testing.T) { t.Parallel() // Start a stream listener addr, err := net.ResolveTCPAddr("tcp", "localhost:0") if err != nil { t.Fatalf("failed to resolve local address: %v.", err) } listener, err := stream.Listen(addr) if err != nil { t.Fatalf("failed to listen for incoming streams: %v.", err) } listener.Accept(10 * time.Millisecond) defer listener.Close() // Establish a stream connection to the listener host := fmt.Sprintf("%s:%d", "localhost", addr.Port) clientStrm, err := stream.Dial(host, time.Millisecond) if err != nil { t.Fatalf("failed to connect to stream listener: %v.", err) } serverStrm := <-listener.Sink defer clientStrm.Close() defer serverStrm.Close() // Initialize the stream based encrypted links secret := make([]byte, 16) io.ReadFull(rand.Reader, secret) clientHKDF := hkdf.New(sha1.New, secret, []byte("HKDF salt"), []byte("HKDF info")) serverHKDF := hkdf.New(sha1.New, secret, []byte("HKDF salt"), []byte("HKDF info")) clientLink := New(clientStrm, clientHKDF, false) serverLink := New(serverStrm, serverHKDF, true) // Generate some random messages and pass around both ways for i := 0; i < 1000; i++ { // Generate the message to send send := &proto.Message{ Head: proto.Header{ Meta: make([]byte, 32), }, Data: make([]byte, 32), } io.ReadFull(rand.Reader, send.Head.Meta.([]byte)) io.ReadFull(rand.Reader, send.Data) send.Encrypt() // Send the message from client to server if err := clientLink.SendDirect(send); err != nil { t.Fatalf("failed to send message to server: %v.", err) } if recv, err := serverLink.RecvDirect(); err != nil { t.Fatalf("failed to receive message from client: %v.", err) } else if bytes.Compare(send.Head.Meta.([]byte), recv.Head.Meta.([]byte)) != 0 || bytes.Compare(send.Data, recv.Data) != 0 { t.Fatalf("send/receive mismatch: have %+v, want %+v.", recv, send) } // Send the message from server to client if err := serverLink.SendDirect(send); err != nil { t.Fatalf("failed to send message to client: %v.", err) } if recv, err := clientLink.RecvDirect(); err != nil { t.Fatalf("failed to receive message from server: %v.", err) } else if bytes.Compare(send.Head.Meta.([]byte), recv.Head.Meta.([]byte)) != 0 || bytes.Compare(send.Data, recv.Data) != 0 { t.Fatalf("send/receive mismatch: have %+v, want %+v.", recv, send) } } }