Example #1
0
// Connects to a remote node and negotiates a session.
func Dial(host string, port int, key *rsa.PrivateKey) (*Session, error) {
	// Open the stream connection
	addr := fmt.Sprintf("%s:%d", host, port)
	strm, err := stream.Dial(addr, config.SessionDialTimeout)
	if err != nil {
		return nil, err
	}
	// Set up the authenticated session
	secret, err := clientAuth(strm, key)
	if err != nil {
		log.Printf("session: failed to authenticate connection: %v.", err)
		if err := strm.Close(); err != nil {
			log.Printf("session: failed to close unauthenticated connection: %v.", err)
		}
	}
	// Link a new data connection to it
	sess := newSession(strm, secret, false)
	if err = clientLink(sess); err != nil {
		log.Printf("session: failed to link data connection: %v.", err)
		if err := strm.Close(); err != nil {
			log.Printf("session: failed to close unlinked connection: %v.", err)
		}
		return nil, err
	}
	return sess, nil
}
Example #2
0
func client(msg string, ch chan string) {
	// Open a TCP connection to the stream server
	addr := fmt.Sprintf("%s:%d", host, port)
	strm, err := stream.Dial(addr, time.Second)
	if err != nil {
		fmt.Println("Failed to connect to stream server:", err)
		return
	}
	defer strm.Close()

	// Send the message and receive a reply
	if err = strm.Send(msg); err != nil {
		fmt.Println("Failed to send the message:", err)
		return
	}
	if err = strm.Flush(); err != nil {
		fmt.Println("Failed to flush the message:", err)
		return
	}
	if err = strm.Recv(&msg); err != nil {
		fmt.Println("Failed to receive the reply:", err)
		return
	}
	// Return the reply to the caller and terminate
	ch <- msg
}
Example #3
0
// Accepts an incoming tunneling request from a remote, initializes and stores
// the new tunnel into the connection state.
func (c *Connection) buildTunnel(remote uint64, id uint64, key []byte, addrs []string, timeout time.Duration) (*Tunnel, error) {
	deadline := time.Now().Add(timeout)

	// Create the local tunnel endpoint
	c.tunLock.Lock()
	tunId := c.tunIdx
	tun := &Tunnel{
		id:    tunId,
		owner: c,
		term:  make(chan struct{}),
	}
	c.tunIdx++
	c.tunLive[tunId] = tun
	c.tunLock.Unlock()

	// Dial the remote tunnel listener
	var err error
	var strm *stream.Stream
	for _, addr := range addrs {
		strm, err = stream.Dial(addr, timeout)
		if err == nil {
			break
		}
	}
	// If no error occurred, initialize the client endpoint
	if err == nil {
		var conn *link.Link
		conn, err = c.initClientTunnel(strm, remote, id, key, deadline)
		if err != nil {
			if err := strm.Close(); err != nil {
				log.Printf("iris: failed to close uninitialized client tunnel stream: %v.", err)
			}
		} else {
			// Make sure the tunnel wasn't terminated since (init/close race)
			tun.lock.Lock()
			select {
			case <-tun.term:
				conn.Close()
				err = ErrTerminating
			default:
				tun.conn = conn
			}
			tun.lock.Unlock()
		}
	}
	// Tunneling failed, clean up and report error
	if err != nil {
		c.tunLock.Lock()
		delete(c.tunLive, tunId)
		c.tunLock.Unlock()
		return nil, err
	}
	return tun, nil
}
Example #4
0
// Initiates a data channel link to the specified control channel.
func clientLink(sess *Session) error {
	// Wait for the server to specify the session id
	msg, err := sess.CtrlLink.RecvDirect()
	if err != nil {
		return fmt.Errorf("failed to retrieve session id: %v", err)
	}
	// Initiate a new stream connection to the server
	addr := sess.CtrlLink.Sock().RemoteAddr().String()
	strm, err := stream.Dial(addr, config.SessionDialTimeout)
	if err != nil {
		return fmt.Errorf("failed to establish data link: %v", err)
	}
	// Send the temporary id back on the data stream
	req := &initRequest{
		Link: &linkRequest{msg.Head.Meta.(*linkRequest).Id},
	}
	if err = strm.Send(req); err != nil {
		strm.Close()
		return fmt.Errorf("failed to send link request: %v", err)
	}
	if err = strm.Flush(); err != nil {
		strm.Close()
		return fmt.Errorf("failed to flush link request: %v", err)
	}
	// Finalize the session with the data stream
	sess.init(strm, false)

	// Send the data link authentication
	auth := &proto.Message{
		Head: proto.Header{
			Meta: req.Link,
		},
	}
	// Retrieve the remote data link authentication
	if err = sess.DataLink.SendDirect(auth); err != nil {
		return fmt.Errorf("failed to send data auth: %v", err)
	}
	if msg, err := sess.DataLink.RecvDirect(); err != nil {
		return fmt.Errorf("failed to retrieve data auth: %v", err)
	} else if res, ok := msg.Head.Meta.(*linkRequest); !ok {
		return errors.New("corrupt authentication message")
	} else if res.Id != req.Link.Id {
		return errors.New("mismatched authentication message")
	}
	return nil
}
Example #5
0
// 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)
		}
	}
}