Compare commits
No commits in common. 'ws' and 'tls' have entirely different histories.
@ -1,36 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package obfssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"os/exec"
|
|
||||||
"os/user"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/containerd/console"
|
|
||||||
"golang.org/x/crypto/ssh"
|
|
||||||
)
|
|
||||||
|
|
||||||
func consoleChange(_console console.Console, session *ssh.Session) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func newPty() (console.Console, string, error) {
|
|
||||||
return nil, "", errors.New("not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func setProcAttr(attr *syscall.SysProcAttr) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func setTermios(fd int, args ssh.TerminalModes) error {
|
|
||||||
return errors.New("not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func setUserEnv(_cmd *exec.Cmd, u *user.User, attr *syscall.SysProcAttr) {
|
|
||||||
if u == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_cmd.Dir = u.HomeDir
|
|
||||||
}
|
|
@ -1,139 +0,0 @@
|
|||||||
//go:build darwin || freebsd || linux || openbsd || solaris
|
|
||||||
// +build darwin freebsd linux openbsd solaris
|
|
||||||
|
|
||||||
package obfssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"os/signal"
|
|
||||||
"os/user"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/containerd/console"
|
|
||||||
"github.com/fangdingjun/go-log/v5"
|
|
||||||
"golang.org/x/crypto/ssh"
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
func consoleChange(_console console.Console, session *ssh.Session) {
|
|
||||||
ch := make(chan os.Signal, 2)
|
|
||||||
signal.Notify(ch, syscall.SIGWINCH)
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ch:
|
|
||||||
ws, _ := _console.Size()
|
|
||||||
_winCh := windowChange{Rows: uint32(ws.Height), Columns: uint32(ws.Width)}
|
|
||||||
d := ssh.Marshal(_winCh)
|
|
||||||
ok, err := session.SendRequest("window-change", true, d)
|
|
||||||
log.Debugf("send window change request %+v %+v", ok, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func newPty() (console.Console, string, error) {
|
|
||||||
return console.NewPty()
|
|
||||||
}
|
|
||||||
|
|
||||||
func setProcAttr(attr *syscall.SysProcAttr) {
|
|
||||||
attr.Setsid = true
|
|
||||||
attr.Setctty = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func setFlag(f *uint32, k uint8, v uint32) {
|
|
||||||
v1, ok := termiosMap[k]
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v != 0 {
|
|
||||||
*f |= v1
|
|
||||||
return
|
|
||||||
}
|
|
||||||
*f &^= v1
|
|
||||||
}
|
|
||||||
|
|
||||||
func applyTermios(flag *unix.Termios, t ssh.TerminalModes) {
|
|
||||||
for k, v := range t {
|
|
||||||
switch k {
|
|
||||||
case ssh.IGNPAR, ssh.PARMRK, ssh.INPCK, ssh.ISTRIP, ssh.INLCR, ssh.IGNCR, ssh.ICRNL, ssh.IUCLC, ssh.IXON, ssh.IXANY, ssh.IXOFF, ssh.IMAXBEL:
|
|
||||||
setFlag(&flag.Iflag, k, v)
|
|
||||||
case ssh.OPOST, ssh.OLCUC, ssh.ONLCR, ssh.OCRNL, ssh.ONOCR, ssh.ONLRET:
|
|
||||||
setFlag(&flag.Oflag, k, v)
|
|
||||||
case ssh.CS7, ssh.CS8, ssh.PARENB, ssh.PARODD:
|
|
||||||
setFlag(&flag.Cflag, k, v)
|
|
||||||
case ssh.ISIG, ssh.ICANON, ssh.XCASE, ssh.ECHO, ssh.ECHOE, ssh.ECHOK, ssh.ECHONL, ssh.ECHOCTL, ssh.ECHOKE, ssh.NOFLSH, ssh.TOSTOP, ssh.PENDIN, ssh.IEXTEN:
|
|
||||||
setFlag(&flag.Lflag, k, v)
|
|
||||||
case ssh.VEOF, ssh.VEOL, ssh.VEOL2, ssh.VDISCARD, ssh.VDSUSP, ssh.VERASE, ssh.VINTR, ssh.VKILL, ssh.VLNEXT, ssh.VQUIT, ssh.VREPRINT, ssh.VSTART, ssh.VSTATUS, ssh.VSTOP, ssh.VSUSP, ssh.VSWTCH, ssh.VWERASE:
|
|
||||||
v1, ok := termiosMap[k]
|
|
||||||
if ok {
|
|
||||||
flag.Cc[v1] = uint8(v)
|
|
||||||
}
|
|
||||||
case ssh.TTY_OP_ISPEED:
|
|
||||||
flag.Ispeed = v
|
|
||||||
case ssh.TTY_OP_OSPEED:
|
|
||||||
flag.Ospeed = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setTermios(fd int, args ssh.TerminalModes) error {
|
|
||||||
t1, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("before %+v", t1)
|
|
||||||
applyTermios(t1, args)
|
|
||||||
|
|
||||||
err = unix.IoctlSetTermios(fd, unix.TCSETS, t1)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
t1, err = unix.IoctlGetTermios(fd, unix.TCGETS)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("after %+v", t1)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setUserEnv(_cmd *exec.Cmd, u *user.User, attr *syscall.SysProcAttr) {
|
|
||||||
if u == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_uid, _ := strconv.ParseUint(u.Uid, 10, 32)
|
|
||||||
_gid, _ := strconv.ParseUint(u.Gid, 10, 32)
|
|
||||||
|
|
||||||
_cmd.Env = append(_cmd.Env, fmt.Sprintf("HOME=%s", u.HomeDir))
|
|
||||||
_cmd.Env = append(_cmd.Env, fmt.Sprintf("LOGNAME=%s", u.Name))
|
|
||||||
_cmd.Dir = u.HomeDir
|
|
||||||
|
|
||||||
if os.Getuid() != 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if attr.Credential == nil {
|
|
||||||
attr.Credential = &syscall.Credential{}
|
|
||||||
}
|
|
||||||
|
|
||||||
attr.Credential.Uid = uint32(_uid)
|
|
||||||
attr.Credential.Gid = uint32(_gid)
|
|
||||||
for _, _env := range _cmd.Env {
|
|
||||||
ss := strings.Split(_env, "=")
|
|
||||||
if ss[0] == "SSH_AUTH_SOCK" {
|
|
||||||
os.Chown(ss[1], int(_uid), int(_gid))
|
|
||||||
}
|
|
||||||
if ss[0] == "SSH_TTY" {
|
|
||||||
os.Chown(ss[1], int(_uid), 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,123 +0,0 @@
|
|||||||
package obfssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
log "github.com/fangdingjun/go-log/v5"
|
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
"golang.org/x/crypto/ssh"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Dialer struct {
|
|
||||||
// NetDial specifies the dial function for creating TCP connections. If
|
|
||||||
// NetDial is nil, net.Dial is used.
|
|
||||||
NetDial func(network, addr string) (net.Conn, error)
|
|
||||||
|
|
||||||
Proxy func() (*url.URL, error)
|
|
||||||
|
|
||||||
// TLSClientConfig specifies the TLS configuration to use with tls.Client.
|
|
||||||
// If nil, the default configuration is used.
|
|
||||||
// If either NetDialTLS or NetDialTLSContext are set, Dial assumes the TLS handshake
|
|
||||||
// is done there and TLSClientConfig is ignored.
|
|
||||||
TLSClientConfig *tls.Config
|
|
||||||
|
|
||||||
NetConf *Conf
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Dialer) Dial(addr string, conf *ssh.ClientConfig) (*Client, error) {
|
|
||||||
if d.NetConf.Timeout == 0 {
|
|
||||||
d.NetConf.Timeout = 15 * time.Second
|
|
||||||
}
|
|
||||||
if d.NetConf.KeepAliveInterval == 0 {
|
|
||||||
d.NetConf.KeepAliveInterval = 10
|
|
||||||
}
|
|
||||||
if d.NetConf.KeepAliveMax == 0 {
|
|
||||||
d.NetConf.KeepAliveMax = 3
|
|
||||||
}
|
|
||||||
var dialFunc func(network, addr string) (net.Conn, error)
|
|
||||||
if d.NetDial == nil {
|
|
||||||
dialFunc = dialer.Dial
|
|
||||||
}
|
|
||||||
|
|
||||||
u, err := url.Parse(addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.Proxy != nil {
|
|
||||||
dialFunc = func(network, addr string) (net.Conn, error) {
|
|
||||||
var conn net.Conn
|
|
||||||
var err error
|
|
||||||
u1, _ := d.Proxy()
|
|
||||||
if u1 == nil {
|
|
||||||
return dialer.Dial(network, addr)
|
|
||||||
}
|
|
||||||
log.Debugf("connect to proxy %s", u1.String())
|
|
||||||
switch u1.Scheme {
|
|
||||||
case "http":
|
|
||||||
conn, err = dialHTTPProxy(addr, u1)
|
|
||||||
case "https":
|
|
||||||
conn, err = dialHTTPSProxy(addr, u1)
|
|
||||||
case "socks5":
|
|
||||||
conn, err = dialSocks5Proxy(addr, u1)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unknown proxy scheme %s", u1.Scheme)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("connect to proxy error %s", err)
|
|
||||||
}
|
|
||||||
return conn, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch u.Scheme {
|
|
||||||
case "":
|
|
||||||
conn, err := dialFunc("tcp", u.Host)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return NewClient(&TimedOutConn{Conn: conn, Timeout: d.NetConf.Timeout}, conf, u.Host, d.NetConf)
|
|
||||||
case "tls":
|
|
||||||
conn, err := dialFunc("tcp", u.Host)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
conn = tls.Client(&TimedOutConn{Conn: conn, Timeout: d.NetConf.Timeout}, d.TLSClientConfig)
|
|
||||||
return NewClient(conn, conf, u.Host, d.NetConf)
|
|
||||||
case "ws":
|
|
||||||
fallthrough
|
|
||||||
case "wss":
|
|
||||||
_addr := fmt.Sprintf("%s://%s%s", u.Scheme, u.Host, u.Path)
|
|
||||||
_dailer := websocket.Dialer{
|
|
||||||
NetDial: func(network, addr string) (net.Conn, error) {
|
|
||||||
c, err := dialFunc(network, addr)
|
|
||||||
return &TimedOutConn{Conn: c, Timeout: d.NetConf.Timeout}, err
|
|
||||||
},
|
|
||||||
TLSClientConfig: d.TLSClientConfig,
|
|
||||||
}
|
|
||||||
wsconn, res, err := _dailer.Dial(_addr, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if res.StatusCode != http.StatusSwitchingProtocols {
|
|
||||||
return nil, fmt.Errorf("websocket connect failed, http code %d", res.StatusCode)
|
|
||||||
}
|
|
||||||
_conn := &wsConn{Conn: wsconn, buf: new(bytes.Buffer), mu: new(sync.Mutex), ch: make(chan struct{})}
|
|
||||||
go _conn.readLoop()
|
|
||||||
return NewClient(_conn, conf, u.Host, d.NetConf)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unknow scheme %s", u.Scheme)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Dialer) DialContext(ctx context.Context, addr string, conf *ssh.ClientConfig) (*Client, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
@ -1,151 +0,0 @@
|
|||||||
package obfssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"net/textproto"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
log "github.com/fangdingjun/go-log/v5"
|
|
||||||
socks "github.com/fangdingjun/socks-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
type httpProxyConn struct {
|
|
||||||
c net.Conn
|
|
||||||
r io.Reader
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hc *httpProxyConn) Read(b []byte) (int, error) {
|
|
||||||
return hc.r.Read(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hc *httpProxyConn) Write(b []byte) (int, error) {
|
|
||||||
return hc.c.Write(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hc *httpProxyConn) Close() error {
|
|
||||||
return hc.c.Close()
|
|
||||||
}
|
|
||||||
func (hc *httpProxyConn) LocalAddr() net.Addr {
|
|
||||||
return hc.c.LocalAddr()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hc *httpProxyConn) RemoteAddr() net.Addr {
|
|
||||||
return hc.c.RemoteAddr()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hc *httpProxyConn) SetDeadline(t time.Time) error {
|
|
||||||
return hc.c.SetDeadline(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hc *httpProxyConn) SetReadDeadline(t time.Time) error {
|
|
||||||
return hc.c.SetReadDeadline(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hc *httpProxyConn) SetWriteDeadline(t time.Time) error {
|
|
||||||
return hc.c.SetWriteDeadline(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate the interface implements
|
|
||||||
var _ net.Conn = &httpProxyConn{}
|
|
||||||
|
|
||||||
func httpProxyHandshake(c net.Conn, addr string) (net.Conn, error) {
|
|
||||||
log.Debugf("http handshake with %s", addr)
|
|
||||||
fmt.Fprintf(c, "CONNECT %s HTTP/1.1\r\n", addr)
|
|
||||||
fmt.Fprintf(c, "Host: %s\r\n", addr)
|
|
||||||
fmt.Fprintf(c, "User-Agent: go/1.7\r\n")
|
|
||||||
fmt.Fprintf(c, "\r\n")
|
|
||||||
|
|
||||||
r := bufio.NewReader(c)
|
|
||||||
tp := textproto.NewReader(r)
|
|
||||||
|
|
||||||
// read status line
|
|
||||||
statusLine, err := tp.ReadLine()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if statusLine[0:4] != "HTTP" {
|
|
||||||
return nil, fmt.Errorf("not http reply")
|
|
||||||
}
|
|
||||||
|
|
||||||
status := strings.Fields(statusLine)[1]
|
|
||||||
|
|
||||||
statusCode, err := strconv.Atoi(status)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if statusCode != 200 {
|
|
||||||
return nil, fmt.Errorf("http status error %d", statusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
// read header
|
|
||||||
if _, err = tp.ReadMIMEHeader(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &httpProxyConn{c: c, r: r}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func dialHTTPProxy(addr string, p *url.URL) (net.Conn, error) {
|
|
||||||
log.Debugf("dial to %s", p.Host)
|
|
||||||
c, err := dialer.Dial("tcp", p.Host)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
c1, err := httpProxyHandshake(c, addr)
|
|
||||||
if err != nil {
|
|
||||||
c.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func dialHTTPSProxy(addr string, p *url.URL) (net.Conn, error) {
|
|
||||||
hostname := p.Host
|
|
||||||
|
|
||||||
tlsconfig := &tls.Config{
|
|
||||||
ServerName: hostname,
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := tls.DialWithDialer(dialer, "tcp", p.Host, tlsconfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.Handshake(); err != nil {
|
|
||||||
c.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
c1, err := httpProxyHandshake(c, addr)
|
|
||||||
if err != nil {
|
|
||||||
c.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func dialSocks5Proxy(addr string, p *url.URL) (net.Conn, error) {
|
|
||||||
c, err := dialer.Dial("tcp", p.Host)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
c1 := &socks.Client{Conn: c}
|
|
||||||
c2, err := c1.Dial("tcp", addr)
|
|
||||||
if err != nil {
|
|
||||||
c1.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c2, err
|
|
||||||
}
|
|
@ -0,0 +1,14 @@
|
|||||||
|
// +build linux darwin
|
||||||
|
|
||||||
|
package obfssh
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/kr/pty"
|
||||||
|
)
|
||||||
|
|
||||||
|
func startPty(cmd *exec.Cmd) (io.ReadWriteCloser, error) {
|
||||||
|
return pty.Start(cmd)
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package obfssh
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func startPty(cmd *exec.Cmd) (io.ReadWriteCloser, error) {
|
||||||
|
return nil, errors.New("not implement")
|
||||||
|
}
|
@ -1,63 +0,0 @@
|
|||||||
package obfssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/crypto/ssh"
|
|
||||||
)
|
|
||||||
|
|
||||||
var termiosMap = map[uint8]uint32{
|
|
||||||
ssh.VINTR: 0,
|
|
||||||
ssh.VQUIT: 1,
|
|
||||||
ssh.VERASE: 2,
|
|
||||||
ssh.VKILL: 3,
|
|
||||||
ssh.VEOF: 4,
|
|
||||||
ssh.VSTART: 8,
|
|
||||||
ssh.VSTOP: 9,
|
|
||||||
ssh.VSUSP: 10,
|
|
||||||
ssh.VEOL: 11,
|
|
||||||
ssh.VREPRINT: 12,
|
|
||||||
ssh.VDISCARD: 13,
|
|
||||||
ssh.VWERASE: 14,
|
|
||||||
ssh.VLNEXT: 15,
|
|
||||||
ssh.VEOL2: 16,
|
|
||||||
ssh.IGNPAR: 0000004,
|
|
||||||
ssh.PARMRK: 0000010,
|
|
||||||
ssh.INPCK: 0000020,
|
|
||||||
ssh.ISTRIP: 0000040,
|
|
||||||
ssh.INLCR: 0000100,
|
|
||||||
ssh.IGNCR: 0000200,
|
|
||||||
ssh.ICRNL: 0000400,
|
|
||||||
ssh.IUCLC: 0001000,
|
|
||||||
ssh.IXON: 0002000,
|
|
||||||
ssh.IXANY: 0004000,
|
|
||||||
ssh.IXOFF: 0010000,
|
|
||||||
ssh.IMAXBEL: 0020000,
|
|
||||||
ssh.OPOST: 0000001,
|
|
||||||
ssh.PARENB: 0000400,
|
|
||||||
ssh.OLCUC: 0000002,
|
|
||||||
ssh.ONLCR: 0000004,
|
|
||||||
ssh.OCRNL: 0000010,
|
|
||||||
ssh.ONOCR: 0000020,
|
|
||||||
ssh.ONLRET: 0000040,
|
|
||||||
ssh.CS7: 0000040,
|
|
||||||
ssh.CS8: 0000060,
|
|
||||||
ssh.PARODD: 0001000,
|
|
||||||
ssh.ISIG: 0000001,
|
|
||||||
ssh.ICANON: 0000002,
|
|
||||||
ssh.XCASE: 0000004,
|
|
||||||
ssh.ECHO: 0000010,
|
|
||||||
ssh.ECHOE: 0000020,
|
|
||||||
ssh.ECHOK: 0000040,
|
|
||||||
ssh.ECHONL: 0000100,
|
|
||||||
ssh.NOFLSH: 0000200,
|
|
||||||
ssh.TOSTOP: 0000400,
|
|
||||||
ssh.ECHOCTL: 0001000,
|
|
||||||
ssh.ECHOKE: 0004000,
|
|
||||||
ssh.PENDIN: 0040000,
|
|
||||||
ssh.IEXTEN: 0100000,
|
|
||||||
/*
|
|
||||||
ssh.VFLUSH: 0,
|
|
||||||
ssh.VSWTCH: 0,
|
|
||||||
ssh.VSTATUS: 0,
|
|
||||||
ssh.VDSUSP: 0,
|
|
||||||
*/
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
package obfssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
log "github.com/fangdingjun/go-log/v5"
|
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
)
|
|
||||||
|
|
||||||
type wsConn struct {
|
|
||||||
*websocket.Conn
|
|
||||||
buf *bytes.Buffer
|
|
||||||
mu *sync.Mutex
|
|
||||||
ch chan struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ net.Conn = &wsConn{}
|
|
||||||
|
|
||||||
func (wc *wsConn) readLoop() {
|
|
||||||
for {
|
|
||||||
_, data, err := wc.ReadMessage()
|
|
||||||
if err != nil {
|
|
||||||
log.Debugln(err)
|
|
||||||
close(wc.ch)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
wc.mu.Lock()
|
|
||||||
wc.buf.Write(data)
|
|
||||||
wc.mu.Unlock()
|
|
||||||
|
|
||||||
select {
|
|
||||||
case wc.ch <- struct{}{}:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wc *wsConn) Read(buf []byte) (int, error) {
|
|
||||||
wc.mu.Lock()
|
|
||||||
|
|
||||||
n, err := wc.buf.Read(buf)
|
|
||||||
if err == nil {
|
|
||||||
wc.mu.Unlock()
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
wc.mu.Unlock()
|
|
||||||
|
|
||||||
if err != io.EOF {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// EOF, no data avaliable, read again
|
|
||||||
select {
|
|
||||||
case _, ok := <-wc.ch:
|
|
||||||
if !ok {
|
|
||||||
return 0, errors.New("connection closed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wc.mu.Lock()
|
|
||||||
defer wc.mu.Unlock()
|
|
||||||
return wc.buf.Read(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wc *wsConn) Write(buf []byte) (int, error) {
|
|
||||||
err := wc.WriteMessage(websocket.BinaryMessage, buf)
|
|
||||||
return len(buf), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wc *wsConn) SetDeadline(t time.Time) error {
|
|
||||||
if err := wc.SetReadDeadline(t); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := wc.SetWriteDeadline(t); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
Loading…
Reference in New Issue