1
0
forked from x/icebergs
This commit is contained in:
harveyshao 2022-08-16 17:39:12 +08:00
parent bf34e9ceee
commit 325d28f090
9 changed files with 98 additions and 138 deletions

View File

@ -21,7 +21,7 @@ func _sess_check(m *ice.Message, sessid string) {
if m.Warn(kit.Time(kit.Format(value[mdb.TIME])) < kit.Time(m.Time()), ice.ErrNotValid, sessid) {
return // 会话超时
}
m.Logs(ice.LOG_AUTH,
m.Auth(
USERROLE, m.Option(ice.MSG_USERROLE, value[USERROLE]),
USERNAME, m.Option(ice.MSG_USERNAME, value[USERNAME]),
USERNICK, m.Option(ice.MSG_USERNICK, value[USERNICK]),

View File

@ -34,7 +34,7 @@ func _user_login(m *ice.Message, name, word string) {
if m.Warn(word != "" && word != kit.Format(kit.Value(value, kit.Keys(mdb.EXTRA, PASSWORD))), ice.ErrNotRight) {
return
}
m.Logs(ice.LOG_AUTH,
m.Auth(
USERROLE, m.Option(ice.MSG_USERROLE, value[USERROLE]),
USERNAME, m.Option(ice.MSG_USERNAME, value[USERNAME]),
USERNICK, m.Option(ice.MSG_USERNICK, value[USERNICK]),

View File

@ -54,7 +54,7 @@ func _islocalhost(m *ice.Message, ip string) (ok bool) {
return false
}
if mdb.Richs(m, HOST, kit.Keym(aaa.WHITE), ip, nil) != nil {
m.Logs(ice.LOG_AUTH, aaa.WHITE, ip)
m.Auth(aaa.WHITE, ip)
return true
}
return false

View File

@ -102,7 +102,7 @@ func _space_handle(m *ice.Message, safe bool, frame *Frame, c *websocket.Conn, n
if msg.Option(ice.MSG_USERROLE) == aaa.VOID && ice.Info.UserName == aaa.TECH {
msg.Option(ice.MSG_USERROLE, aaa.TECH) // 演示空间
}
msg.Logs(ice.LOG_AUTH, aaa.USERROLE, msg.Option(ice.MSG_USERROLE), aaa.USERNAME, msg.Option(ice.MSG_USERNAME))
msg.Auth(aaa.USERROLE, msg.Option(ice.MSG_USERROLE), aaa.USERNAME, msg.Option(ice.MSG_USERNAME))
msg.Go(func() { _space_exec(msg, source, target, c, name) })
continue
}

View File

@ -45,7 +45,7 @@ func _action_auth(m *ice.Message, share string) *ice.Message {
msg.Append(mdb.TYPE, "")
return msg // 共享过期
}
m.Logs(ice.LOG_AUTH,
m.Auth(
aaa.USERROLE, m.Option(ice.MSG_USERROLE, msg.Append(aaa.USERROLE)),
aaa.USERNAME, m.Option(ice.MSG_USERNAME, msg.Append(aaa.USERNAME)),
aaa.USERNICK, m.Option(ice.MSG_USERNICK, msg.Append(aaa.USERNICK)),

View File

@ -18,6 +18,10 @@ func (m *Message) join(arg ...Any) (string, []Any) {
meta = append(meta, v)
i--
continue
case []string:
list = append(list, v...)
i--
continue
}
if key := strings.TrimSpace(kit.Format(arg[i])); i == len(arg)-1 {
list = append(list, key)
@ -72,6 +76,10 @@ func (m *Message) Logs(level string, arg ...Any) *Message {
return m.log(level, str, meta...)
}
func (m *Message) Auth(arg ...Any) *Message {
str, meta := m.join(arg...)
return m.log(LOG_AUTH, str, meta...)
}
func (m *Message) Cost(arg ...Any) *Message {
str, meta := m.join(arg...)
if len(arg) == 0 {

View File

@ -2,13 +2,9 @@ package ssh
import (
"io"
"net"
"os/exec"
"strings"
"golang.org/x/crypto/ssh"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/mdb"
psh "shylinux.com/x/icebergs/base/ssh"
@ -16,27 +12,7 @@ import (
kit "shylinux.com/x/toolkits"
)
func _ssh_exec(m *ice.Message, cmd string, arg []string, env []string, input io.Reader, output io.Writer, done func()) {
m.Logs(mdb.IMPORT, CMD, cmd, ARG, arg, ENV, env)
c := exec.Command(cmd, arg...)
// c.Env = env
c.Stdin = input
c.Stdout = output
c.Stderr = output
m.Assert(c.Start())
m.Go(func() {
defer done()
c.Process.Wait()
})
}
func _ssh_close(m *ice.Message, c net.Conn, channel ssh.Channel) {
defer channel.Close()
channel.Write([]byte(m.Conf(SERVICE, kit.Keym(GOODBYE))))
}
func _ssh_watch(m *ice.Message, meta ice.Maps, h string, input io.Reader, output io.Writer) {
func _ssh_watch(m *ice.Message, h string, output io.Writer, input io.Reader) io.Closer {
r, w := io.Pipe()
bio := io.TeeReader(input, w)
m.Go(func() { io.Copy(output, r) })
@ -52,8 +28,7 @@ func _ssh_watch(m *ice.Message, meta ice.Maps, h string, input io.Reader, output
switch buf[i] {
case '\r', '\n':
cmd := strings.TrimSpace(string(buf[:i]))
m.Logs(mdb.IMPORT, tcp.HOSTNAME, meta[tcp.HOSTNAME], aaa.USERNAME, meta[aaa.USERNAME], CMD, cmd)
m.Cmdy(mdb.INSERT, CHANNEL, kit.Keys(mdb.HASH, h), mdb.LIST, mdb.TYPE, CMD, mdb.TEXT, cmd)
m.Cmdy(mdb.INSERT, m.Prefix(CHANNEL), kit.Keys(mdb.HASH, h), mdb.LIST, mdb.TYPE, CMD, mdb.TEXT, cmd)
i = 0
default:
if i += n; i >= ice.MOD_BUFS {
@ -62,6 +37,7 @@ func _ssh_watch(m *ice.Message, meta ice.Maps, h string, input io.Reader, output
}
}
})
return r
}
const CHANNEL = "channel"
@ -70,34 +46,24 @@ func init() {
psh.Index.MergeCommands(ice.Commands{
CHANNEL: {Name: "channel hash id auto", Help: "通道", Actions: ice.MergeActions(ice.Actions{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
mdb.Richs(m, CHANNEL, "", mdb.FOREACH, func(key string, value ice.Map) {
kit.Value(value, kit.Keym(mdb.STATUS), tcp.CLOSE)
mdb.HashSelectUpdate(m, mdb.FOREACH, func(value ice.Map) {
kit.Value(value, mdb.STATUS, tcp.CLOSE)
})
}},
mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) {
m.OptionFields(m.Config(mdb.FIELD))
m.Cmdy(mdb.PRUNES, SERVICE, "", mdb.HASH, mdb.STATUS, tcp.ERROR)
m.Cmdy(mdb.PRUNES, CHANNEL, "", mdb.HASH, mdb.STATUS, tcp.CLOSE)
}},
mdb.REPEAT: {Name: "repeat", Help: "执行", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(CHANNEL, ctx.ACTION, ctx.COMMAND, CMD, m.Option(mdb.TEXT))
}},
ctx.COMMAND: {Name: "command cmd=pwd", Help: "命令", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(mdb.INSERT, CHANNEL, kit.Keys(mdb.HASH, m.Option(mdb.HASH)),
mdb.LIST, mdb.TYPE, CMD, mdb.TEXT, m.Option(CMD))
mdb.Richs(m, CHANNEL, "", m.Option(mdb.HASH), func(key string, value ice.Map) {
if w, ok := kit.Value(value, kit.Keym(INPUT)).(io.Writer); ok {
w.Write([]byte(m.Option(CMD) + ice.NL))
}
})
m.ProcessRefresh300ms()
mdb.ZoneInsert(m, m.OptionSimple(mdb.HASH), mdb.TYPE, CMD, mdb.TEXT, m.Option(CMD))
if w, ok := mdb.HashTarget(m, m.Option(mdb.HASH), nil).(io.Writer); ok {
w.Write([]byte(m.Option(CMD) + ice.NL))
m.Sleep300ms()
}
}},
}, mdb.HashAction(mdb.FIELD, "time,hash,status,username,hostport,tty,count")), Hand: func(m *ice.Message, arg ...string) {
mdb.REPEAT: {Name: "repeat", Help: "执行", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy("", ctx.COMMAND, CMD, m.Option(mdb.TEXT))
}},
}, mdb.HashAction(mdb.FIELD, "time,hash,status,tty,count,username,hostport")), Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 { // 通道列表
m.Action(mdb.PRUNES)
mdb.HashSelect(m, arg...)
m.Set(ice.MSG_APPEND, ctx.ACTION)
m.Tables(func(value ice.Maps) {
mdb.HashSelect(m, arg...).Tables(func(value ice.Maps) {
m.PushButton(kit.Select("", ctx.COMMAND, value[mdb.STATUS] == tcp.OPEN), mdb.REMOVE)
})
return

View File

@ -5,10 +5,13 @@ import (
"encoding/base64"
"errors"
"fmt"
"io"
"net"
"os"
"strings"
"golang.org/x/crypto/ssh"
pty "shylinux.com/x/creackpty"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/cli"
@ -27,20 +30,20 @@ func _ssh_config(m *ice.Message, h string) *ssh.ServerConfig {
config := &ssh.ServerConfig{
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
meta, err := _ssh_meta(conn), errors.New(ice.ErrNotRight)
if tcp.IsLocalHost(m, strings.Split(conn.RemoteAddr().String(), ice.DF)[0]) {
m.Logs(ice.LOG_AUTH, tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User())
if tcp.IsLocalHost(m, strings.Split(meta[tcp.HOSTPORT], ice.DF)[0]) {
m.Auth(aaa.USERNAME, meta[aaa.USERNAME], tcp.HOSTPORT, meta[tcp.HOSTPORT])
err = nil // 本机用户
} else {
mdb.ZoneSelectCB(m, h, func(value ice.Maps) {
if !strings.HasPrefix(value[mdb.NAME], conn.User()+"@") {
if !strings.HasPrefix(value[mdb.NAME], meta[aaa.USERNAME]+"@") {
return
}
if s, e := base64.StdEncoding.DecodeString(value[mdb.TEXT]); !m.Warn(e) {
if pub, e := ssh.ParsePublicKey([]byte(s)); !m.Warn(e) {
if bytes.Compare(pub.Marshal(), key.Marshal()) == 0 {
m.Logs(ice.LOG_AUTH, tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User(), tcp.HOSTNAME, value[mdb.NAME])
meta[tcp.HOSTNAME] = kit.Select("", kit.Split(value[mdb.NAME], "@"), 1)
m.Auth(aaa.USERNAME, meta[aaa.USERNAME], tcp.HOSTPORT, meta[tcp.HOSTPORT], tcp.HOSTNAME, meta[tcp.HOSTNAME])
err = nil // 认证成功
}
}
@ -51,16 +54,12 @@ func _ssh_config(m *ice.Message, h string) *ssh.ServerConfig {
},
PasswordCallback: func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
meta, err := _ssh_meta(conn), errors.New(ice.ErrNotRight)
if aaa.UserLogin(m, conn.User(), string(password)) {
m.Logs(ice.LOG_AUTH, tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User(), aaa.PASSWORD, strings.Repeat("*", len(string(password))))
if aaa.UserLogin(m, meta[aaa.USERNAME], string(password)) {
m.Auth(aaa.USERNAME, meta[aaa.USERNAME], tcp.HOSTPORT, meta[tcp.HOSTPORT], aaa.PASSWORD, strings.Repeat("*", len(string(password))))
err = nil // 密码登录
}
return &ssh.Permissions{Extensions: meta}, err
},
BannerCallback: func(conn ssh.ConnMetadata) string {
m.Logs(ice.LOG_AUTH, tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User())
return m.Config(WELCOME)
},
}
if key, err := ssh.ParsePrivateKey([]byte(m.Cmdx(nfs.CAT, kit.HomePath(m.Option(PRIVATE))))); m.Assert(err) {
@ -73,7 +72,6 @@ func _ssh_accept(m *ice.Message, h string, c net.Conn) {
if m.Warn(err) {
return
}
m.Go(func() { ssh.DiscardRequests(reqs) })
for ch := range chans {
@ -81,12 +79,67 @@ func _ssh_accept(m *ice.Message, h string, c net.Conn) {
if m.Warn(err) {
continue
}
func(channel ssh.Channel, requests <-chan *ssh.Request) {
m.Go(func() { _ssh_handle(m, conn.Permissions.Extensions, c, channel, requests) })
}(channel, requests)
m.Go(func() {
m.Logs(CHANNEL, tcp.HOSTPORT, c.RemoteAddr().String(), "->", c.LocalAddr().String())
defer m.Logs("dischan", tcp.HOSTPORT, c.RemoteAddr().String(), "->", c.LocalAddr().String())
_ssh_prepare(m.Spawn(conn.Permissions.Extensions), channel, requests)
})
}
}
func _ssh_prepare(m *ice.Message, channel ssh.Channel, requests <-chan *ssh.Request) {
pty, tty, err := pty.Open()
if m.Warn(err) {
return
}
defer tty.Close()
list := []string{cli.PATH + "=" + kit.Env(cli.PATH)}
for request := range requests {
m.Logs(REQUEST, tcp.HOSTPORT, m.Option(tcp.HOSTPORT), mdb.TYPE, request.Type)
switch request.Type {
case "pty-req":
termLen := request.Payload[3]
termEnv := string(request.Payload[4 : termLen+4])
_ssh_size(pty.Fd(), request.Payload[termLen+4:])
list = append(list, "TERM="+termEnv)
case "window-change":
_ssh_size(pty.Fd(), request.Payload)
case "env":
var env struct{ Name, Value string }
if err := ssh.Unmarshal(request.Payload, &env); err != nil {
continue
}
list = append(list, env.Name+"="+env.Value)
case "shell":
_ssh_handle(m, channel, pty, tty)
case "exec":
defer channel.Close()
m.Optionv(cli.CMD_OUTPUT, channel)
m.Cmd(cli.SYSTEM, kit.Select("sh", kit.Env(cli.SHELL)), "-c", string(request.Payload[4:request.Payload[3]+4]))
return
}
request.Reply(true, nil)
}
}
func _ssh_handle(m *ice.Message, channel ssh.Channel, pty, tty *os.File) {
h := m.Cmdx(mdb.INSERT, m.Prefix(CHANNEL), "", mdb.HASH, mdb.STATUS, tcp.OPEN, TTY, tty.Name(), m.OptionSimple(aaa.USERNAME, tcp.HOSTPORT), kit.Dict(mdb.TARGET, pty))
m.Go(func() { io.Copy(channel, pty) })
p := _ssh_watch(m, h, pty, channel)
m.Optionv(cli.CMD_INPUT, tty)
m.Optionv(cli.CMD_OUTPUT, tty)
channel.Write([]byte(m.Config(WELCOME)))
m.Cmd(cli.DAEMON, kit.Select("sh", kit.Env(cli.SHELL)), func() {
defer m.Cmd(mdb.MODIFY, m.Prefix(CHANNEL), "", mdb.HASH, mdb.HASH, h, mdb.STATUS, tcp.CLOSE)
channel.Write([]byte(m.Config(GOODBYE)))
channel.Close()
p.Close()
})
}
const (
WELCOME = "welcome"
@ -100,7 +153,7 @@ func init() {
psh.Index.Merge(&ice.Context{Configs: ice.Configs{
SERVICE: {Name: SERVICE, Help: "服务", Value: kit.Data(
mdb.SHORT, tcp.PORT, mdb.FIELD, "time,port,status,private,authkey,count",
WELCOME, "\r\nwelcome to contexts world\r\n", GOODBYE, "\r\ngoodbye of contexts world\r\n",
WELCOME, "welcome to contexts world\r\n", GOODBYE, "goodbye of contexts world\r\n",
)},
}, Commands: ice.Commands{
SERVICE: {Name: "service port id auto listen prunes", Help: "服务", Actions: ice.MergeActions(ice.Actions{
@ -128,7 +181,7 @@ func init() {
mdb.INSERT: {Name: "insert text:textarea", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
if ls := kit.Split(m.Option(mdb.TEXT)); len(ls) > 2 {
m.Cmdy(mdb.INSERT, SERVICE, kit.Keys(mdb.HASH, kit.Hashs(m.Option(tcp.PORT))), mdb.LIST,
m.Cmdy(mdb.INSERT, m.Prefix(SERVICE), kit.Keys(mdb.HASH, kit.Hashs(m.Option(tcp.PORT))), mdb.LIST,
mdb.TYPE, ls[0], mdb.NAME, ls[len(ls)-1], mdb.TEXT, strings.Join(ls[1:len(ls)-1], "+"))
}
}},

View File

@ -2,18 +2,8 @@ package ssh
import (
"encoding/binary"
"io"
"net"
"syscall"
"unsafe"
pty "shylinux.com/x/creackpty"
"golang.org/x/crypto/ssh"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/tcp"
kit "shylinux.com/x/toolkits"
)
type Winsize struct{ Height, Width, x, y uint16 }
@ -21,63 +11,6 @@ type Winsize struct{ Height, Width, x, y uint16 }
func _ssh_size(fd uintptr, b []byte) {
w := binary.BigEndian.Uint32(b)
h := binary.BigEndian.Uint32(b[4:])
ws := &Winsize{Width: uint16(w), Height: uint16(h)}
syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(ws)))
}
func _ssh_sizes(fd uintptr, w, h int) {
ws := &Winsize{Width: uint16(w), Height: uint16(h)}
syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(ws)))
}
func _ssh_handle(m *ice.Message, meta ice.Maps, c net.Conn, channel ssh.Channel, requests <-chan *ssh.Request) {
m.Logs(CHANNEL, tcp.HOSTPORT, c.RemoteAddr(), "->", c.LocalAddr())
defer m.Logs("dischan", tcp.HOSTPORT, c.RemoteAddr(), "->", c.LocalAddr())
shell := kit.Select("bash", kit.Env("SHELL"))
list := []string{cli.PATH + "=" + kit.Env(cli.PATH)}
pty, tty, err := pty.Open()
if m.Warn(err) {
return
}
defer tty.Close()
h := mdb.Rich(m, CHANNEL, "", kit.Data(mdb.STATUS, tcp.OPEN, TTY, tty.Name(), INPUT, pty, OUTPUT, tty, meta))
meta[CHANNEL] = h
for request := range requests {
m.Logs(REQUEST, tcp.HOSTPORT, c.RemoteAddr(), mdb.TYPE, request.Type)
switch request.Type {
case "pty-req":
termLen := request.Payload[3]
termEnv := string(request.Payload[4 : termLen+4])
_ssh_size(pty.Fd(), request.Payload[termLen+4:])
list = append(list, "TERM="+termEnv)
case "window-change":
_ssh_size(pty.Fd(), request.Payload)
case "env":
var env struct{ Name, Value string }
if err := ssh.Unmarshal(request.Payload, &env); err != nil {
continue
}
list = append(list, env.Name+"="+env.Value)
case "exec":
_ssh_exec(m, shell, []string{"-c", string(request.Payload[4 : request.Payload[3]+4])}, list, channel, channel, func() {
channel.Close()
})
case "shell":
_ssh_watch(m, meta, h, channel, pty)
m.Go(func() { io.Copy(channel, pty) })
_ssh_exec(m, shell, nil, list, tty, tty, func() {
defer m.Cmd(mdb.MODIFY, CHANNEL, "", mdb.HASH, mdb.HASH, h, mdb.STATUS, tcp.CLOSE)
_ssh_close(m, c, channel)
})
}
request.Reply(true, nil)
}
}