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
//
// conf is the client configure
//
// 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
//
func NewClient(c net.Conn, config *ssh.ClientConfig, addr, method, key string) (*Client, error) {
Log(DEBUG, "create obfs conn with method %s", method)
obfsConn, err := NewObfsConn(&TimedOutConn{c, 15 * time.Second}, method, key, false)
func NewClient(c net.Conn, config *ssh.ClientConfig, addr string, conf *Conf) (*Client, error) {
Log(DEBUG, "create obfs conn with method %s", conf.ObfsMethod)
obfsConn, err := NewObfsConn(&TimedOutConn{c, conf.Timeout}, conf.ObfsMethod, conf.ObfsKey, false)
if err != nil {
return nil, err
}
@ -41,12 +43,17 @@ func NewClient(c net.Conn, config *ssh.ClientConfig, addr, method, key string) (
if err != nil {
return nil, err
}
if conf.DisableObfsAfterHandshake {
obfsConn.DisableObfs()
}
sshClient := ssh.NewClient(sshConn, newch, reqs)
client := &Client{
conn: c, sshConn: sshConn, client: sshClient,
ch: make(chan int),
}
go client.keepAlive(10*time.Second, 4)
go client.keepAlive(conf.KeepAliveInterval, conf.KeepAliveMax)
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
import (
//"bytes"
"flag"
"fmt"
"github.com/bgentry/speakeasy"
"github.com/fangdingjun/obfssh"
"github.com/golang/crypto/ssh"
"github.com/golang/crypto/ssh/agent"
//"github.com/golang/crypto/ssh/terminal"
"time"
//"io"
"io/ioutil"
"log"
"net"
"os"
//"os/signal"
"path/filepath"
"strings"
//"sync"
//"syscall"
"time"
)
var method, encryptKey string
type stringSlice []string
func (lf *stringSlice) Set(val string) error {
@ -42,15 +35,17 @@ func (lf *stringSlice) String() string {
return s
}
var localForwards stringSlice
var remoteForwards stringSlice
var dynamicForwards stringSlice
func main() {
var host, port, user, pass, key string
//var localForward, remoteForward, dynamicForward string
var method, encryptKey string
var notRunCmd 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(&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(&encryptKey, "obfs_key", "", "transport encrypt key")
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()
if debug {
obfssh.SSHLogLevel = obfssh.DEBUG
}
auth := []ssh.AuthMethod{}
var agentConn net.Conn
var err error
// read ssh agent and default auth key
if pass == "" && key == "" {
if aconn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil {
obfssh.Log(obfssh.DEBUG, "add auth method with agent %s", os.Getenv("SSH_AUTH_SOCK"))
auth = append(auth, ssh.PublicKeysCallback(agent.NewClient(aconn).Signers))
}
var pkeys []ssh.Signer
home := os.Getenv("HOME")
for _, f := range []string{
@ -89,10 +88,26 @@ func main() {
if pemBytes, err := ioutil.ReadFile(k1); err == nil {
if priKey, err := ssh.ParsePrivateKey(pemBytes); err == nil {
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()
@ -115,11 +130,7 @@ func main() {
host = ss[1]
}
if pass != "" {
obfssh.Log(obfssh.DEBUG, "add password auth method")
auth = append(auth, ssh.Password(pass))
}
// process user specified private key
if key != "" {
pemBytes, err := ioutil.ReadFile(key)
if err != nil {
@ -133,23 +144,48 @@ func main() {
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{
User: user,
Auth: auth,
Timeout: 10 * time.Second,
}
h := net.JoinHostPort(host, port)
c, err := net.Dial("tcp", h)
rhost := net.JoinHostPort(host, port)
c, err := net.Dial("tcp", rhost)
if err != nil {
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 {
log.Fatal(err)
}
var local, remote string
// process port forward
for _, p := range localForwards {
addr := parseForwardAddr(p)
if len(addr) != 4 && len(addr) != 3 {
@ -226,3 +262,26 @@ func parseForwardAddr(s string) []string {
})
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
}

@ -9,12 +9,13 @@ import (
)
type serverConfig struct {
Port int `yaml:"port"`
Key string `yaml:"obfs_key"`
Debug bool `yaml:"debug"`
HostKey string `yaml:"host_key_file"`
Method string `yaml:"obfs_method"`
Users []serverUser `yaml:"users"`
Port int `yaml:"port"`
Key string `yaml:"obfs_key"`
Debug bool `yaml:"debug"`
HostKey string `yaml:"host_key_file"`
Method string `yaml:"obfs_method"`
DisableObfsAfterHandshake bool `yaml:"disable_obfs_after_handshake"`
Users []serverUser `yaml:"users"`
}
type serverUser struct {

@ -17,6 +17,9 @@ host_key_file: ssh_host_rsa_key
#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
# value true or false
debug: true

@ -28,6 +28,12 @@ func main() {
obfssh.SSHLogLevel = obfssh.DEBUG
}
sconf := &obfssh.Conf{
ObfsMethod: conf.Method,
ObfsKey: conf.Key,
DisableObfsAfterHandshake: conf.DisableObfsAfterHandshake,
}
config := &ssh.ServerConfig{
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
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())
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 {
c.Close()
obfssh.Log(obfssh.ERROR, "%s", err.Error())

@ -26,11 +26,13 @@ type Server struct {
//
// 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,
// 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) {
wc, err := NewObfsConn(c, method, key, true)
func NewServer(c net.Conn, config *ssh.ServerConfig, conf *Conf) (*Server, error) {
wc, err := NewObfsConn(c, conf.ObfsMethod, conf.ObfsKey, true)
if err != nil {
return nil, err
}
@ -38,7 +40,11 @@ func NewServer(c net.Conn, config *ssh.ServerConfig, method, key string) (*Serve
if err != nil {
return nil, err
}
//wc.DisableObfs()
if conf.DisableObfsAfterHandshake {
wc.DisableObfs()
}
sc := &Server{conn: c,
sshConn: sshConn,
forwardedPorts: map[string]net.Listener{},

Loading…
Cancel
Save