Browse Source

Implemented SSH keepalive; removed TCP keepalive

Rod Hynes 11 years ago
parent
commit
597bcdabb1
4 changed files with 31 additions and 13 deletions
  1. 0 1
      README.md
  2. 0 6
      psiphon/conn_unix.go
  3. 1 1
      psiphon/defaults.go
  4. 30 5
      psiphon/tunnel.go

+ 0 - 1
README.md

@@ -25,7 +25,6 @@ This project is currently at the proof-of-concept stage. Current production Psip
 
 
 ### TODO (future)
 ### TODO (future)
 
 
-* SSH keepalive
 * SSH compression
 * SSH compression
 * preemptive reconnect functionality
 * preemptive reconnect functionality
 * implement page view stats
 * implement page view stats

+ 0 - 6
psiphon/conn_unix.go

@@ -42,12 +42,6 @@ func interruptibleDial(
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	err = syscall.SetsockoptInt(
-		socketFd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE, TUNNEL_TCP_KEEP_ALIVE_PERIOD_SECONDS)
-	if err != nil {
-		syscall.Close(socketFd)
-		return nil, err
-	}
 	/*
 	/*
 		// TODO: requires root, which we won't have on Android in VpnService mode
 		// TODO: requires root, which we won't have on Android in VpnService mode
 		//       an alternative may be to use http://golang.org/pkg/syscall/#UnixRights to
 		//       an alternative may be to use http://golang.org/pkg/syscall/#UnixRights to

+ 1 - 1
psiphon/defaults.go

@@ -29,7 +29,7 @@ const (
 	TUNNEL_CONNECT_TIMEOUT                 = 15 * time.Second
 	TUNNEL_CONNECT_TIMEOUT                 = 15 * time.Second
 	TUNNEL_READ_TIMEOUT                    = 0 * time.Second
 	TUNNEL_READ_TIMEOUT                    = 0 * time.Second
 	TUNNEL_WRITE_TIMEOUT                   = 5 * time.Second
 	TUNNEL_WRITE_TIMEOUT                   = 5 * time.Second
-	TUNNEL_TCP_KEEP_ALIVE_PERIOD_SECONDS   = 60
+	TUNNEL_SSH_KEEP_ALIVE_PERIOD           = 60 * time.Second
 	ESTABLISH_TUNNEL_TIMEOUT               = 60 * time.Second
 	ESTABLISH_TUNNEL_TIMEOUT               = 60 * time.Second
 	CONNECTION_WORKER_POOL_SIZE            = 10
 	CONNECTION_WORKER_POOL_SIZE            = 10
 	HTTP_PROXY_READ_TIMEOUT                = 1 * time.Second
 	HTTP_PROXY_READ_TIMEOUT                = 1 * time.Second

+ 30 - 5
psiphon/tunnel.go

@@ -25,9 +25,11 @@ import (
 	"encoding/base64"
 	"encoding/base64"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
+	"log"
 	"net"
 	"net"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
+	"time"
 )
 )
 
 
 const (
 const (
@@ -39,14 +41,18 @@ const (
 // tunnel includes a network connection to the specified server
 // tunnel includes a network connection to the specified server
 // and an SSH session built on top of that transport.
 // and an SSH session built on top of that transport.
 type Tunnel struct {
 type Tunnel struct {
-	serverEntry *ServerEntry
-	protocol    string
-	conn        *Conn
-	sshClient   *ssh.Client
+	serverEntry      *ServerEntry
+	protocol         string
+	conn             *Conn
+	sshClient        *ssh.Client
+	sshKeepAliveQuit chan struct{}
 }
 }
 
 
 // Close terminates the tunnel.
 // Close terminates the tunnel.
 func (tunnel *Tunnel) Close() {
 func (tunnel *Tunnel) Close() {
+	if tunnel.sshKeepAliveQuit != nil {
+		close(tunnel.sshKeepAliveQuit)
+	}
 	if tunnel.conn != nil {
 	if tunnel.conn != nil {
 		tunnel.conn.Close()
 		tunnel.conn.Close()
 	}
 	}
@@ -121,5 +127,24 @@ func EstablishTunnel(serverEntry *ServerEntry, pendingConns *PendingConns) (tunn
 		return nil, err
 		return nil, err
 	}
 	}
 	sshClient := ssh.NewClient(sshConn, sshChans, sshReqs)
 	sshClient := ssh.NewClient(sshConn, sshChans, sshReqs)
-	return &Tunnel{serverEntry, selectedProtocol, conn, sshClient}, nil
+	sshKeepAliveQuit := make(chan struct{})
+	sshKeepAliveTicker := time.NewTicker(TUNNEL_SSH_KEEP_ALIVE_PERIOD)
+	go func() {
+		for {
+			select {
+			case <-sshKeepAliveTicker.C:
+				_, _, err := sshClient.SendRequest("keepalive@openssh.com", true, nil)
+				if err != nil {
+					log.Printf("ssh keep alive failed: %s", err)
+					// TODO: call Tunnel.Close()?
+					sshKeepAliveTicker.Stop()
+					conn.Close()
+				}
+			case <-sshKeepAliveQuit:
+				sshKeepAliveTicker.Stop()
+				return
+			}
+		}
+	}()
+	return &Tunnel{serverEntry, selectedProtocol, conn, sshClient, sshKeepAliveQuit}, nil
 }
 }