add more commandline options

client
   add keepalive, timeout options

all add disable obfs after handshake option
master
fangdingjun 8 years ago
parent 233ba2732a
commit ad396effa3

@ -28,12 +28,14 @@ type Client struct {
// //
// key is obfs encrypt key // key is obfs encrypt key
// //
// conf is the client configure
//
// if set method to none or "", means disable the obfs, // if set method to none or "", means disable the obfs,
// when the obfs is disabled, the client can connect to standard ssh server, like OpenSSH server // when the obfs is disabled, the client can connect to standard ssh server, like OpenSSH server
// //
func NewClient(c net.Conn, config *ssh.ClientConfig, addr, method, key string) (*Client, error) { func NewClient(c net.Conn, config *ssh.ClientConfig, addr string, conf *Conf) (*Client, error) {
Log(DEBUG, "create obfs conn with method %s", method) Log(DEBUG, "create obfs conn with method %s", conf.ObfsMethod)
obfsConn, err := NewObfsConn(&TimedOutConn{c, 15 * time.Second}, method, key, false) obfsConn, err := NewObfsConn(&TimedOutConn{c, conf.Timeout}, conf.ObfsMethod, conf.ObfsKey, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -41,12 +43,17 @@ func NewClient(c net.Conn, config *ssh.ClientConfig, addr, method, key string) (
if err != nil { if err != nil {
return nil, err return nil, err
} }
if conf.DisableObfsAfterHandshake {
obfsConn.DisableObfs()
}
sshClient := ssh.NewClient(sshConn, newch, reqs) sshClient := ssh.NewClient(sshConn, newch, reqs)
client := &Client{ client := &Client{
conn: c, sshConn: sshConn, client: sshClient, conn: c, sshConn: sshConn, client: sshClient,
ch: make(chan int), ch: make(chan int),
} }
go client.keepAlive(10*time.Second, 4) go client.keepAlive(conf.KeepAliveInterval, conf.KeepAliveMax)
return client, nil return client, nil
} }

@ -0,0 +1,26 @@
package obfssh
import (
"time"
)
// Conf keeps the configure of server or client
type Conf struct {
// ObfsMethod is the encrpt method
ObfsMethod string
// ObfsKey is key for encrypt
ObfsKey string
// Timeout is the socket timeout on read/write
Timeout time.Duration
// DisableObfsAfterHandShake disable the obfs encryption after ssh handshake done
DisableObfsAfterHandshake bool
// KeepAliveInterval the keep alive interval
KeepAliveInterval time.Duration
// KeepAliveMax the max times of keep alive error
KeepAliveMax int
}

@ -1,28 +1,21 @@
package main package main
import ( import (
//"bytes"
"flag" "flag"
"fmt" "fmt"
"github.com/bgentry/speakeasy"
"github.com/fangdingjun/obfssh" "github.com/fangdingjun/obfssh"
"github.com/golang/crypto/ssh" "github.com/golang/crypto/ssh"
"github.com/golang/crypto/ssh/agent" "github.com/golang/crypto/ssh/agent"
//"github.com/golang/crypto/ssh/terminal"
"time"
//"io"
"io/ioutil" "io/ioutil"
"log" "log"
"net" "net"
"os" "os"
//"os/signal"
"path/filepath" "path/filepath"
"strings" "strings"
//"sync" "time"
//"syscall"
) )
var method, encryptKey string
type stringSlice []string type stringSlice []string
func (lf *stringSlice) Set(val string) error { func (lf *stringSlice) Set(val string) error {
@ -42,15 +35,17 @@ func (lf *stringSlice) String() string {
return s return s
} }
var localForwards stringSlice
var remoteForwards stringSlice
var dynamicForwards stringSlice
func main() { func main() {
var host, port, user, pass, key string var host, port, user, pass, key string
//var localForward, remoteForward, dynamicForward string var method, encryptKey string
var notRunCmd bool var notRunCmd bool
var debug bool var debug bool
var disableObfsAfterHandshake bool
var keepAliveInterval, keepAliveMax int
var localForwards stringSlice
var remoteForwards stringSlice
var dynamicForwards stringSlice
flag.StringVar(&user, "l", os.Getenv("USER"), "ssh username") flag.StringVar(&user, "l", os.Getenv("USER"), "ssh username")
flag.StringVar(&pass, "pw", "", "ssh password") flag.StringVar(&pass, "pw", "", "ssh password")
@ -63,19 +58,23 @@ func main() {
flag.StringVar(&method, "obfs_method", "", "transport encrypt method, avaliable: rc4, aes, empty means disable encrypt") flag.StringVar(&method, "obfs_method", "", "transport encrypt method, avaliable: rc4, aes, empty means disable encrypt")
flag.StringVar(&encryptKey, "obfs_key", "", "transport encrypt key") flag.StringVar(&encryptKey, "obfs_key", "", "transport encrypt key")
flag.BoolVar(&debug, "d", false, "verbose mode") flag.BoolVar(&debug, "d", false, "verbose mode")
flag.IntVar(&keepAliveInterval, "keepalive_interval", 10, "keep alive interval")
flag.IntVar(&keepAliveMax, "keepalive_max", 5, "keep alive max")
flag.BoolVar(&disableObfsAfterHandshake, "disalbe_obfs_after_handshake", false, "disable obfs after handshake")
flag.Parse() flag.Parse()
if debug { if debug {
obfssh.SSHLogLevel = obfssh.DEBUG obfssh.SSHLogLevel = obfssh.DEBUG
} }
auth := []ssh.AuthMethod{} auth := []ssh.AuthMethod{}
var agentConn net.Conn
var err error
// read ssh agent and default auth key // read ssh agent and default auth key
if pass == "" && key == "" { if pass == "" && key == "" {
if aconn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil { var pkeys []ssh.Signer
obfssh.Log(obfssh.DEBUG, "add auth method with agent %s", os.Getenv("SSH_AUTH_SOCK"))
auth = append(auth, ssh.PublicKeysCallback(agent.NewClient(aconn).Signers))
}
home := os.Getenv("HOME") home := os.Getenv("HOME")
for _, f := range []string{ for _, f := range []string{
@ -89,10 +88,26 @@ func main() {
if pemBytes, err := ioutil.ReadFile(k1); err == nil { if pemBytes, err := ioutil.ReadFile(k1); err == nil {
if priKey, err := ssh.ParsePrivateKey(pemBytes); err == nil { if priKey, err := ssh.ParsePrivateKey(pemBytes); err == nil {
obfssh.Log(obfssh.DEBUG, "add private key: %s", k1) obfssh.Log(obfssh.DEBUG, "add private key: %s", k1)
auth = append(auth, ssh.PublicKeys(priKey)) //auth = append(auth, ssh.PublicKeys(priKey))
pkeys = append(pkeys, priKey)
} }
} }
} }
if len(pkeys) != 0 {
obfssh.Log(obfssh.DEBUG, "private key length %d", len(pkeys))
auth = append(auth, ssh.PublicKeys(pkeys...))
}
agentConn, err = net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
if err == nil {
defer agentConn.Close()
obfssh.Log(obfssh.DEBUG, "add auth method with agent %s", os.Getenv("SSH_AUTH_SOCK"))
agentClient := agent.NewClient(agentConn)
auth = append(auth, ssh.PublicKeysCallback(agentClient.Signers))
} else {
obfssh.Log(obfssh.DEBUG, "connect to agent failed")
}
} }
args := flag.Args() args := flag.Args()
@ -115,11 +130,7 @@ func main() {
host = ss[1] host = ss[1]
} }
if pass != "" { // process user specified private key
obfssh.Log(obfssh.DEBUG, "add password auth method")
auth = append(auth, ssh.Password(pass))
}
if key != "" { if key != "" {
pemBytes, err := ioutil.ReadFile(key) pemBytes, err := ioutil.ReadFile(key)
if err != nil { if err != nil {
@ -133,23 +144,48 @@ func main() {
auth = append(auth, ssh.PublicKeys(priKey)) auth = append(auth, ssh.PublicKeys(priKey))
} }
if pass != "" {
obfssh.Log(obfssh.DEBUG, "add password auth method")
auth = append(auth, ssh.Password(pass))
} else {
obfssh.Log(obfssh.DEBUG, "add keyboard interactive auth")
//auth = append(auth,
// ssh.RetryableAuthMethod(ssh.KeyboardInteractive(keyboardAuth), 3))
auth = append(auth,
ssh.RetryableAuthMethod(ssh.PasswordCallback(passwordAuth), 3))
}
config := &ssh.ClientConfig{ config := &ssh.ClientConfig{
User: user, User: user,
Auth: auth, Auth: auth,
Timeout: 10 * time.Second, Timeout: 10 * time.Second,
} }
h := net.JoinHostPort(host, port) rhost := net.JoinHostPort(host, port)
c, err := net.Dial("tcp", h)
c, err := net.Dial("tcp", rhost)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
client, err := obfssh.NewClient(c, config, h, method, encryptKey) conf := &obfssh.Conf{
ObfsMethod: method,
ObfsKey: encryptKey,
Timeout: time.Duration(keepAliveInterval+5) * time.Second,
KeepAliveInterval: time.Duration(keepAliveInterval) * time.Second,
KeepAliveMax: keepAliveMax,
DisableObfsAfterHandshake: disableObfsAfterHandshake,
}
client, err := obfssh.NewClient(c, config, rhost, conf)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
var local, remote string var local, remote string
// process port forward
for _, p := range localForwards { for _, p := range localForwards {
addr := parseForwardAddr(p) addr := parseForwardAddr(p)
if len(addr) != 4 && len(addr) != 3 { if len(addr) != 4 && len(addr) != 3 {
@ -226,3 +262,26 @@ func parseForwardAddr(s string) []string {
}) })
return ss return ss
} }
/*
func keyboardAuth(user, instruction string, question []string, echos []bool) (answers []string, err error) {
if len(question) == 0 {
fmt.Printf("%s %s\n", user, instruction)
return nil, nil
}
r := bufio.NewReader(os.Stdin)
var s string
for i := range question {
fmt.Printf("%s ", question[i])
s, err = r.ReadString('\n')
answers = append(answers, s)
}
return
}
*/
func passwordAuth() (string, error) {
// read password from console
s, err := speakeasy.Ask("Password: ")
return strings.Trim(s, " \r\n"), err
}

@ -14,6 +14,7 @@ type serverConfig struct {
Debug bool `yaml:"debug"` Debug bool `yaml:"debug"`
HostKey string `yaml:"host_key_file"` HostKey string `yaml:"host_key_file"`
Method string `yaml:"obfs_method"` Method string `yaml:"obfs_method"`
DisableObfsAfterHandshake bool `yaml:"disable_obfs_after_handshake"`
Users []serverUser `yaml:"users"` Users []serverUser `yaml:"users"`
} }

@ -17,6 +17,9 @@ host_key_file: ssh_host_rsa_key
#obfs_method: rc4 #obfs_method: rc4
obfs_method: "rc4" obfs_method: "rc4"
# when set to true, only the ssh handshake packet is encrypted
disable_obfs_after_handshake: true
# show more log message # show more log message
# value true or false # value true or false
debug: true debug: true

@ -28,6 +28,12 @@ func main() {
obfssh.SSHLogLevel = obfssh.DEBUG obfssh.SSHLogLevel = obfssh.DEBUG
} }
sconf := &obfssh.Conf{
ObfsMethod: conf.Method,
ObfsKey: conf.Key,
DisableObfsAfterHandshake: conf.DisableObfsAfterHandshake,
}
config := &ssh.ServerConfig{ config := &ssh.ServerConfig{
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) { PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
if u, err := conf.getUser(c.User()); err == nil { if u, err := conf.getUser(c.User()); err == nil {
@ -86,7 +92,7 @@ func main() {
obfssh.Log(obfssh.DEBUG, "accept tcp connection from %s", c.RemoteAddr()) obfssh.Log(obfssh.DEBUG, "accept tcp connection from %s", c.RemoteAddr())
go func(c net.Conn) { go func(c net.Conn) {
sc, err := obfssh.NewServer(c, config, conf.Method, conf.Key) sc, err := obfssh.NewServer(c, config, sconf)
if err != nil { if err != nil {
c.Close() c.Close()
obfssh.Log(obfssh.ERROR, "%s", err.Error()) obfssh.Log(obfssh.ERROR, "%s", err.Error())

@ -26,11 +26,13 @@ type Server struct {
// //
// key is obfs encrypt key // key is obfs encrypt key
// //
// conf is the server configure
//
// if set method to none or "", means disable obfs encryption, when the obfs is disabled, // if set method to none or "", means disable obfs encryption, when the obfs is disabled,
// the server can accept connection from standard ssh client, like OpenSSH client // the server can accept connection from standard ssh client, like OpenSSH client
// //
func NewServer(c net.Conn, config *ssh.ServerConfig, method, key string) (*Server, error) { func NewServer(c net.Conn, config *ssh.ServerConfig, conf *Conf) (*Server, error) {
wc, err := NewObfsConn(c, method, key, true) wc, err := NewObfsConn(c, conf.ObfsMethod, conf.ObfsKey, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -38,7 +40,11 @@ func NewServer(c net.Conn, config *ssh.ServerConfig, method, key string) (*Serve
if err != nil { if err != nil {
return nil, err return nil, err
} }
//wc.DisableObfs()
if conf.DisableObfsAfterHandshake {
wc.DisableObfs()
}
sc := &Server{conn: c, sc := &Server{conn: c,
sshConn: sshConn, sshConn: sshConn,
forwardedPorts: map[string]net.Listener{}, forwardedPorts: map[string]net.Listener{},

Loading…
Cancel
Save