From d0f1663bf381e377d552fed31f9ec5f07113c0ef Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Fri, 8 Aug 2025 19:24:52 +0900 Subject: [PATCH] renamed pts to pty to avoid name collision --- Makefile | 4 +- client-ctl.go | 4 +- client-metrics.go | 14 +- client-pts.go => client-pty.go | 80 ++++---- client.go | 75 ++++---- cmd/config.go | 10 +- cmd/main.go | 35 ++-- hodu.pb.go | 328 +++++++++++++++++++++------------ hodu.proto | 14 ++ packet.go | 12 ++ server-ctl.go | 4 +- server-metrics.go | 14 +- server-pts.go => server-pty.go | 90 ++++----- server.go | 76 +++++--- xterm.html | 8 +- 15 files changed, 470 insertions(+), 298 deletions(-) rename client-pts.go => client-pty.go (76%) rename server-pts.go => server-pty.go (74%) diff --git a/Makefile b/Makefile index 093c686..fed4981 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ SRCS=\ client-ctl.go \ client-metrics.go \ client-peer.go \ - client-pts.go \ + client-pty.go \ hodu.go \ hodu.pb.go \ hodu_grpc.pb.go \ @@ -25,7 +25,7 @@ SRCS=\ server-ctl.go \ server-metrics.go \ server-peer.go \ - server-pts.go \ + server-pty.go \ server-pxy.go \ system.go \ transform.go \ diff --git a/client-ctl.go b/client-ctl.go index 4975245..6d0310a 100644 --- a/client-ctl.go +++ b/client-ctl.go @@ -109,7 +109,7 @@ type json_out_client_stats struct { ClientConns int64 `json:"client-conns"` ClientRoutes int64 `json:"client-routes"` ClientPeers int64 `json:"client-peers"` - ClientPtsSessions int64 `json:"client-pts-sessions"` + ClientPtySessions int64 `json:"client-pty-sessions"` } // ------------------------------------ @@ -1137,7 +1137,7 @@ func (ctl *client_ctl_stats) ServeHTTP(w http.ResponseWriter, req *http.Request) stats.ClientConns = c.stats.conns.Load() stats.ClientRoutes = c.stats.routes.Load() stats.ClientPeers = c.stats.peers.Load() - stats.ClientPtsSessions = c.stats.pts_sessions.Load() + stats.ClientPtySessions = c.stats.pty_sessions.Load() status_code = WriteJsonRespHeader(w, http.StatusOK) if err = je.Encode(stats); err != nil { goto oops } diff --git a/client-metrics.go b/client-metrics.go index f867b78..51a1cc7 100644 --- a/client-metrics.go +++ b/client-metrics.go @@ -10,7 +10,7 @@ type ClientCollector struct { ClientConns *prometheus.Desc ClientRoutes *prometheus.Desc ClientPeers *prometheus.Desc - PtsSessions *prometheus.Desc + PtySessions *prometheus.Desc } // NewClientCollector returns a new ClientCollector with all prometheus.Desc initialized @@ -47,9 +47,9 @@ func NewClientCollector(client *Client) ClientCollector { "Number of client-side peers", nil, nil, ), - PtsSessions: prometheus.NewDesc( - prefix + "pts_sessions", - "Number of pts sessions", + PtySessions: prometheus.NewDesc( + prefix + "pty_sessions", + "Number of pty sessions", nil, nil, ), } @@ -60,7 +60,7 @@ func (c ClientCollector) Describe(ch chan<- *prometheus.Desc) { ch <- c.ClientConns ch <- c.ClientRoutes ch <- c.ClientPeers - ch <- c.PtsSessions + ch <- c.PtySessions } func (c ClientCollector) Collect(ch chan<- prometheus.Metric) { @@ -93,8 +93,8 @@ func (c ClientCollector) Collect(ch chan<- prometheus.Metric) { ) ch <- prometheus.MustNewConstMetric( - c.PtsSessions, + c.PtySessions, prometheus.GaugeValue, - float64(c.client.stats.pts_sessions.Load()), + float64(c.client.stats.pty_sessions.Load()), ) } diff --git a/client-pts.go b/client-pty.go similarity index 76% rename from client-pts.go rename to client-pty.go index 12b25c5..eb35ea7 100644 --- a/client-pts.go +++ b/client-pty.go @@ -14,28 +14,28 @@ import "sync" import "syscall" import "text/template" -import "github.com/creack/pty" +import pts "github.com/creack/pty" import "golang.org/x/net/websocket" import "golang.org/x/sys/unix" -type client_pts_ws struct { +type client_pty_ws struct { C *Client Id string ws *websocket.Conn } -type client_pts_xterm_file struct { +type client_pty_xterm_file struct { client_ctl file string } // ------------------------------------------------------ -func (pts *client_pts_ws) Identity() string { - return pts.Id +func (pty *client_pty_ws) Identity() string { + return pty.Id } -func (pts *client_pts_ws) send_ws_data(ws *websocket.Conn, type_val string, data string) error { +func (pty *client_pty_ws) send_ws_data(ws *websocket.Conn, type_val string, data string) error { var msg []byte var err error @@ -45,26 +45,26 @@ func (pts *client_pts_ws) send_ws_data(ws *websocket.Conn, type_val string, data } -func (pts *client_pts_ws) connect_pts(username string, password string) (*exec.Cmd, *os.File, error) { +func (pty *client_pty_ws) connect_pty(username string, password string) (*exec.Cmd, *os.File, error) { var c *Client var cmd *exec.Cmd var tty *os.File var err error // username and password are not used yet. - c = pts.C + c = pty.C - if c.pts_shell == "" { - return nil, nil, fmt.Errorf("blank pts shell") + if c.pty_shell == "" { + return nil, nil, fmt.Errorf("blank pty shell") } - cmd = exec.Command(c.pts_shell); - if c.pts_user != "" { + cmd = exec.Command(c.pty_shell); + if c.pty_user != "" { var uid int var gid int var u *user.User - u, err = user.Lookup(c.pts_user) + u, err = user.Lookup(c.pty_user) if err != nil { return nil, nil, err } uid, _ = strconv.Atoi(u.Uid) @@ -81,13 +81,13 @@ func (pts *client_pts_ws) connect_pts(username string, password string) (*exec.C "HOME=" + u.HomeDir, "LOGNAME=" + u.Username, "PATH=" + os.Getenv("PATH"), - "SHELL=" + c.pts_shell, + "SHELL=" + c.pty_shell, "TERM=xterm", "USER=" + u.Username, ) } - tty, err = pty.Start(cmd) + tty, err = pts.Start(cmd) if err != nil { return nil, nil, err } @@ -98,7 +98,7 @@ func (pts *client_pts_ws) connect_pts(username string, password string) (*exec.C return cmd, tty, nil } -func (pts *client_pts_ws) ServeWebsocket(ws *websocket.Conn) (int, error) { +func (pty *client_pty_ws) ServeWebsocket(ws *websocket.Conn) (int, error) { var c *Client var req *http.Request var username string @@ -111,7 +111,7 @@ func (pts *client_pts_ws) ServeWebsocket(ws *websocket.Conn) (int, error) { var conn_ready_chan chan bool var err error - c = pts.C + c = pty.C req = ws.Request() conn_ready_chan = make(chan bool, 3) @@ -134,13 +134,13 @@ func (pts *client_pts_ws) ServeWebsocket(ws *websocket.Conn) (int, error) { unix.PollFd{Fd: int32(out.Fd()), Events: unix.POLLIN}, } - c.stats.pts_sessions.Add(1) + c.stats.pty_sessions.Add(1) buf = make([]byte, 2048) for { n, err = unix.Poll(poll_fds, -1) // -1 means wait indefinitely if err != nil { if errors.Is(err, unix.EINTR) { continue } - c.log.Write("", LOG_ERROR, "[%s] Failed to poll pts stdout - %s", req.RemoteAddr, err.Error()) + c.log.Write("", LOG_ERROR, "[%s] Failed to poll pty stdout - %s", req.RemoteAddr, err.Error()) break } if n == 0 { // timed out @@ -148,7 +148,7 @@ func (pts *client_pts_ws) ServeWebsocket(ws *websocket.Conn) (int, error) { } if (poll_fds[0].Revents & (unix.POLLERR | unix.POLLHUP | unix.POLLNVAL)) != 0 { - c.log.Write(pts.Id, LOG_DEBUG, "[%s] EOF detected on pts stdout", req.RemoteAddr) + c.log.Write(pty.Id, LOG_DEBUG, "[%s] EOF detected on pty stdout", req.RemoteAddr) break; } @@ -156,20 +156,20 @@ func (pts *client_pts_ws) ServeWebsocket(ws *websocket.Conn) (int, error) { n, err = out.Read(buf) if err != nil { if !errors.Is(err, io.EOF) { - c.log.Write(pts.Id, LOG_ERROR, "[%s] Failed to read pts stdout - %s", req.RemoteAddr, err.Error()) + c.log.Write(pty.Id, LOG_ERROR, "[%s] Failed to read pty stdout - %s", req.RemoteAddr, err.Error()) } break } if n > 0 { - err = pts.send_ws_data(ws, "iov", string(buf[:n])) + err = pty.send_ws_data(ws, "iov", string(buf[:n])) if err != nil { - c.log.Write(pts.Id, LOG_ERROR, "[%s] Failed to send to websocket - %s", req.RemoteAddr, err.Error()) + c.log.Write(pty.Id, LOG_ERROR, "[%s] Failed to send to websocket - %s", req.RemoteAddr, err.Error()) break } } } } - c.stats.pts_sessions.Add(-1) + c.stats.pty_sessions.Add(-1) } }() @@ -194,18 +194,18 @@ ws_recv_loop: var err error defer wg.Done() - cmd, tty, err = pts.connect_pts(username, password) + cmd, tty, err = pty.connect_pty(username, password) if err != nil { - c.log.Write(pts.Id, LOG_ERROR, "[%s] Failed to connect pts - %s", req.RemoteAddr, err.Error()) - pts.send_ws_data(ws, "error", err.Error()) + c.log.Write(pty.Id, LOG_ERROR, "[%s] Failed to connect pty - %s", req.RemoteAddr, err.Error()) + pty.send_ws_data(ws, "error", err.Error()) ws.Close() // dirty way to flag out the error } else { - err = pts.send_ws_data(ws, "status", "opened") + err = pty.send_ws_data(ws, "status", "opened") if err != nil { - c.log.Write(pts.Id, LOG_ERROR, "[%s] Failed to write opened event to websocket - %s", req.RemoteAddr, err.Error()) + c.log.Write(pty.Id, LOG_ERROR, "[%s] Failed to write opened event to websocket - %s", req.RemoteAddr, err.Error()) ws.Close() // dirty way to flag out the error } else { - c.log.Write(pts.Id, LOG_DEBUG, "[%s] Opened pts session", req.RemoteAddr) + c.log.Write(pty.Id, LOG_DEBUG, "[%s] Opened pty session", req.RemoteAddr) out = tty in = tty conn_ready_chan <- true @@ -235,8 +235,8 @@ ws_recv_loop: var cols int rows, _ = strconv.Atoi(ev.Data[0]) cols, _ = strconv.Atoi(ev.Data[1]) - pty.Setsize(tty, &pty.Winsize{Rows: uint16(rows), Cols: uint16(cols)}) - c.log.Write(pts.Id, LOG_DEBUG, "[%s] Resized terminal to %d,%d", req.RemoteAddr, rows, cols) + pts.Setsize(tty, &pts.Winsize{Rows: uint16(rows), Cols: uint16(cols)}) + c.log.Write(pty.Id, LOG_DEBUG, "[%s] Resized terminal to %d,%d", req.RemoteAddr, rows, cols) // ignore error } } @@ -245,7 +245,7 @@ ws_recv_loop: } if tty != nil { - err = pts.send_ws_data(ws, "status", "closed") + err = pty.send_ws_data(ws, "status", "closed") if err != nil { goto done } } @@ -260,7 +260,7 @@ done: if tty != nil { tty.Close() } if cmd != nil { cmd.Wait() } wg.Wait() - c.log.Write(pts.Id, LOG_DEBUG, "[%s] Ended pts session", req.RemoteAddr) + c.log.Write(pty.Id, LOG_DEBUG, "[%s] Ended pty session", req.RemoteAddr) return http.StatusOK, err } @@ -268,14 +268,14 @@ done: // ------------------------------------------------------ -func (pts *client_pts_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.Request) (int, error) { +func (pty *client_pty_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.Request) (int, error) { var c *Client var status_code int var err error - c = pts.c + c = pty.c - switch pts.file { + switch pty.file { case "xterm.js": status_code = WriteJsRespHeader(w, http.StatusOK) w.Write(xterm_js) @@ -301,7 +301,7 @@ func (pts *client_pts_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.Req status_code = WriteHtmlRespHeader(w, http.StatusOK) tmpl.Execute(w, &xterm_session_info{ - Mode: "pts", + Mode: "pty", ConnId: "-1", RouteId: "-1", }) @@ -315,9 +315,9 @@ func (pts *client_pts_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.Req status_code = WriteEmptyRespHeader(w, http.StatusNotFound) default: - if strings.HasPrefix(pts.file, "_redir:") { + if strings.HasPrefix(pty.file, "_redir:") { status_code = http.StatusMovedPermanently - w.Header().Set("Location", pts.file[7:]) + w.Header().Set("Location", pty.file[7:]) w.WriteHeader(status_code) } else { status_code = WriteEmptyRespHeader(w, http.StatusNotFound) diff --git a/client.go b/client.go index 329139d..04ccf12 100644 --- a/client.go +++ b/client.go @@ -146,11 +146,11 @@ type Client struct { conns atomic.Int64 routes atomic.Int64 peers atomic.Int64 - pts_sessions atomic.Int64 + pty_sessions atomic.Int64 } - pts_user string - pts_shell string + pty_user string + pty_shell string xterm_html string } @@ -1348,6 +1348,16 @@ start_over: cts.C.log.Write(cts.Sid, LOG_ERROR, "Invalid conn_notice packet from %s", cts.remote_addr_p) } + + case PACKET_KIND_RPTY_START: + // TODO: + case PACKET_KIND_RPTY_STOP: + // TODO: + case PACKET_KIND_RPTY_DATA: + // TODO: + case PACKET_KIND_RPTY_EOF: + // TODO: + default: // do nothing. ignore the rest } @@ -1646,28 +1656,27 @@ func NewClient(ctx context.Context, name string, logger Logger, cfg *ClientConfi c.ctl_mux.Handle("/_ctl/events", c.SafeWrapWebsocketHandler(c.WrapWebsocketHandler(&client_ctl_ws{client_ctl{c: &c, id: HS_ID_CTL}}))) + c.ctl_mux.Handle("/_pty/ws", + c.SafeWrapWebsocketHandler(c.WrapWebsocketHandler(&client_pty_ws{C: &c, Id: HS_ID_CTL}))) - c.ctl_mux.Handle("/_pts/ws", - c.SafeWrapWebsocketHandler(c.WrapWebsocketHandler(&client_pts_ws{C: &c, Id: HS_ID_CTL}))) - - c.ctl_mux.Handle("/_pts/xterm.js", - c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "xterm.js"})) - c.ctl_mux.Handle("/_pts/xterm.js/", - c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_forbidden"})) - c.ctl_mux.Handle("/_pts/xterm-addon-fit.js", - c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "xterm-addon-fit.js"})) - c.ctl_mux.Handle("/_pts/xterm-addon-fit.js/", - c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_forbidden"})) - c.ctl_mux.Handle("/_pts/xterm.css", - c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "xterm.css"})) - c.ctl_mux.Handle("/_pts/xterm.css/", - c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_forbidden"})) - c.ctl_mux.Handle("/_pts/xterm.html", - c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "xterm.html"})) - c.ctl_mux.Handle("/_pts/xterm.html/", // without this forbidden, /_pts/xterm.js/ access resulted in xterm.html. - c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_forbidden"})) - c.ctl_mux.Handle("/_pts/", - c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_redir:xterm.html"})) + c.ctl_mux.Handle("/_pty/xterm.js", + c.WrapHttpHandler(&client_pty_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "xterm.js"})) + c.ctl_mux.Handle("/_pty/xterm.js/", + c.WrapHttpHandler(&client_pty_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_forbidden"})) + c.ctl_mux.Handle("/_pty/xterm-addon-fit.js", + c.WrapHttpHandler(&client_pty_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "xterm-addon-fit.js"})) + c.ctl_mux.Handle("/_pty/xterm-addon-fit.js/", + c.WrapHttpHandler(&client_pty_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_forbidden"})) + c.ctl_mux.Handle("/_pty/xterm.css", + c.WrapHttpHandler(&client_pty_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "xterm.css"})) + c.ctl_mux.Handle("/_pty/xterm.css/", + c.WrapHttpHandler(&client_pty_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_forbidden"})) + c.ctl_mux.Handle("/_pty/xterm.html", + c.WrapHttpHandler(&client_pty_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "xterm.html"})) + c.ctl_mux.Handle("/_pty/xterm.html/", // without this forbidden, /_pty/xterm.js/ access resulted in xterm.html. + c.WrapHttpHandler(&client_pty_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_forbidden"})) + c.ctl_mux.Handle("/_pty/", + c.WrapHttpHandler(&client_pty_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_redir:xterm.html"})) c.ctl_addr = make([]string, len(cfg.CtlAddrs)) c.ctl = make([]*http.Server, len(cfg.CtlAddrs)) @@ -1688,7 +1697,7 @@ func NewClient(ctx context.Context, name string, logger Logger, cfg *ClientConfi c.stats.conns.Store(0) c.stats.routes.Store(0) c.stats.peers.Store(0) - c.stats.pts_sessions.Store(0) + c.stats.pty_sessions.Store(0) return &c } @@ -1985,20 +1994,20 @@ func (c *Client) GetXtermHtml() string { return c.xterm_html } -func (c *Client) SetPtsUser(user string) { - c.pts_user = user +func (c *Client) SetPtyUser(user string) { + c.pty_user = user } -func (c *Client) GetPtsUser() string { - return c.pts_user +func (c *Client) GetPtyUser() string { + return c.pty_user } -func (c *Client) SetPtsShell(user string) { - c.pts_shell = user +func (c *Client) SetPtyShell(user string) { + c.pty_shell = user } -func (c *Client) GetPtsShell() string { - return c.pts_shell +func (c *Client) GetPtyShell() string { + return c.pty_shell } func (c *Client) RunCtlTask(wg *sync.WaitGroup) { diff --git a/cmd/config.go b/cmd/config.go index 557779b..8244366 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -94,8 +94,8 @@ type ServerAppConfig struct { LogRotate int `yaml:"log-rotate"` MaxPeers int `yaml:"max-peer-conns"` // maximum number of connections from peers MaxRpcConns int `yaml:"max-rpc-conns"` // maximum number of rpc connections - PtsUser string `yaml:"pts-user"` - PtsShell string `yaml:"pts-shell"` + PtyUser string `yaml:"pty-user"` + PtyShell string `yaml:"pty-shell"` XtermHtmlFile string `yaml:"xterm-html-file"` } @@ -107,8 +107,10 @@ type ClientAppConfig struct { MaxPeers int `yaml:"max-peer-conns"` // maximum number of connections from peers MaxRpcConns int `yaml:"max-rpc-conns"` // maximum number of rpc connections PeerConnTmout time.Duration `yaml:"peer-conn-timeout"` - PtsUser string `yaml:"pts-user"` - PtsShell string `yaml:"pts-shell"` + TokenText string `yaml:"token-text"` + TokenFile string `yaml:"token-file"` + PtyUser string `yaml:"pty-user"` + PtyShell string `yaml:"pty-shell"` XtermHtmlFile string `yaml:"xterm-html-file"` } diff --git a/cmd/main.go b/cmd/main.go index 773e06e..eee4e5d 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -97,8 +97,8 @@ func server_main(ctl_addrs []string, rpc_addrs []string, pxy_addrs []string, wpx var logmask hodu.LogMask var logfile_maxsize int64 var logfile_rotate int - var pts_user string - var pts_shell string + var pty_user string + var pty_shell string var xterm_html_file string var xterm_html string var err error @@ -135,8 +135,8 @@ func server_main(ctl_addrs []string, rpc_addrs []string, pxy_addrs []string, wpx config.RpcMaxConns = cfg.APP.MaxRpcConns config.MaxPeers = cfg.APP.MaxPeers - pts_user = cfg.APP.PtsUser - pts_shell = cfg.APP.PtsShell + pty_user = cfg.APP.PtyUser + pty_shell = cfg.APP.PtyShell xterm_html_file = cfg.APP.XtermHtmlFile logmask = log_strings_to_mask(cfg.APP.LogMask) @@ -172,8 +172,8 @@ func server_main(ctl_addrs []string, rpc_addrs []string, pxy_addrs []string, wpx return fmt.Errorf("failed to create server - %s", err.Error()) } - if pts_user != "" { s.SetPtsUser(pts_user) } - if pts_shell != "" { s.SetPtsShell(pts_shell) } + if pty_user != "" { s.SetPtyUser(pty_user) } + if pty_shell != "" { s.SetPtyShell(pty_shell) } if xterm_html != "" { s.SetXtermHtml(xterm_html) } s.StartService(nil) @@ -259,8 +259,8 @@ func client_main(ctl_addrs []string, rpc_addrs []string, route_configs []string, var logmask hodu.LogMask var logfile_maxsize int64 var logfile_rotate int - var pts_user string - var pts_shell string + var pty_user string + var pty_shell string var xterm_html_file string var xterm_html string var i int @@ -292,12 +292,23 @@ func client_main(ctl_addrs []string, rpc_addrs []string, route_configs []string, if logfile == "" { logfile = cfg.APP.LogFile } logfile_maxsize = cfg.APP.LogMaxSize logfile_rotate = cfg.APP.LogRotate - pts_user = cfg.APP.PtsUser - pts_shell = cfg.APP.PtsShell + pty_user = cfg.APP.PtyUser + pty_shell = cfg.APP.PtyShell xterm_html_file = cfg.APP.XtermHtmlFile config.RpcConnMax = cfg.APP.MaxRpcConns config.PeerConnMax = cfg.APP.MaxPeers config.PeerConnTmout = cfg.APP.PeerConnTmout + + if cfg.APP.TokenText != "" { + config.Token = cfg.APP.TokenText + } else if cfg.APP.TokenFile != "" { + var bytes []byte + bytes, err = os.ReadFile(cfg.APP.TokenFile) + if err != nil { + return fmt.Errorf("unable to read token file - %s", err.Error()) + } + config.Token = string(bytes) + } } // unlke the server, we allow the client to start with no rpc address. @@ -331,8 +342,8 @@ func client_main(ctl_addrs []string, rpc_addrs []string, route_configs []string, c = hodu.NewClient(context.Background(), HODU_NAME, logger, config) - if pts_user != "" { c.SetPtsUser(pts_user) } - if pts_shell != "" { c.SetPtsShell(pts_shell) } + if pty_user != "" { c.SetPtyUser(pty_user) } + if pty_shell != "" { c.SetPtyShell(pty_shell) } if xterm_html != "" { c.SetXtermHtml(xterm_html) } c.StartService(&cc) diff --git a/hodu.pb.go b/hodu.pb.go index 2a7b4b0..0b61889 100644 --- a/hodu.pb.go +++ b/hodu.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.5 +// protoc-gen-go v1.36.7 // protoc v3.19.6 // source: hodu.proto @@ -101,6 +101,13 @@ const ( PACKET_KIND_CONN_DESC PACKET_KIND = 11 PACKET_KIND_CONN_ERROR PACKET_KIND = 12 PACKET_KIND_CONN_NOTICE PACKET_KIND = 13 + PACKET_KIND_RPTY_START PACKET_KIND = 14 + PACKET_KIND_RPTY_STOP PACKET_KIND = 15 + PACKET_KIND_RPTY_STARTED PACKET_KIND = 16 + PACKET_KIND_RPTY_STOPPED PACKET_KIND = 17 + PACKET_KIND_RPTY_ABORTED PACKET_KIND = 18 + PACKET_KIND_RPTY_EOF PACKET_KIND = 19 + PACKET_KIND_RPTY_DATA PACKET_KIND = 20 ) // Enum value maps for PACKET_KIND. @@ -119,6 +126,13 @@ var ( 11: "CONN_DESC", 12: "CONN_ERROR", 13: "CONN_NOTICE", + 14: "RPTY_START", + 15: "RPTY_STOP", + 16: "RPTY_STARTED", + 17: "RPTY_STOPPED", + 18: "RPTY_ABORTED", + 19: "RPTY_EOF", + 20: "RPTY_DATA", } PACKET_KIND_value = map[string]int32{ "RESERVED": 0, @@ -134,6 +148,13 @@ var ( "CONN_DESC": 11, "CONN_ERROR": 12, "CONN_NOTICE": 13, + "RPTY_START": 14, + "RPTY_STOP": 15, + "RPTY_STARTED": 16, + "RPTY_STOPPED": 17, + "RPTY_ABORTED": 18, + "RPTY_EOF": 19, + "RPTY_DATA": 20, } ) @@ -219,24 +240,24 @@ func (x *Seed) GetFlags() uint64 { type RouteDesc struct { state protoimpl.MessageState `protogen:"open.v1"` RouteId uint32 `protobuf:"varint,1,opt,name=RouteId,proto3" json:"RouteId,omitempty"` - // C->S(ROUTE_START): client-side peer address - // S->C(ROUTE_STARTED): server-side listening address + // C->S(ROUTE_START/STOP): client-side peer address + // S->C(ROUTE_STARTED/STOPPED): server-side listening address TargetAddrStr string `protobuf:"bytes,2,opt,name=TargetAddrStr,proto3" json:"TargetAddrStr,omitempty"` - // C->S(ROUTE_START): human-readable name of client-side peer - // S->C(ROUTE_STARTED): clone as sent by C + // C->S(ROUTE_START/STOPPED): human-readable name of client-side peer + // S->C(ROUTE_STARTED/STOPPED): clone as sent by C TargetName string `protobuf:"bytes,3,opt,name=TargetName,proto3" json:"TargetName,omitempty"` - // C->S(ROUTE_START): desired listening option on the server-side(e.g. tcp, tcp4, tcp6) + + // C->S(ROUTE_START): requested listening option on the server-side(e.g. tcp, tcp4, tcp6) + // // hint to the service-side peer(e.g. local) + // hint to the client-side peer(e.g. tty, http, https) // // S->C(ROUTE_STARTED): cloned as sent by C. ServiceOption uint32 `protobuf:"varint,4,opt,name=ServiceOption,proto3" json:"ServiceOption,omitempty"` - // C->S(ROUTE_START): desired lisening address on the service-side + // C->S(ROUTE_START): requested lisening address on the service-side // S->C(ROUTE_STARTED): cloned as sent by C ServiceAddrStr string `protobuf:"bytes,5,opt,name=ServiceAddrStr,proto3" json:"ServiceAddrStr,omitempty"` - // C->S(ROUTE_START): permitted network of server-side peers. - // S->C(ROUTE_STARTED): cloned as sent by C. + // C->S(ROUTE_START): requested permitted network of server-side peers. + // S->C(ROUTE_STARTED): actual permitted network of server-side peers ServiceNetStr string `protobuf:"bytes,6,opt,name=ServiceNetStr,proto3" json:"ServiceNetStr,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -582,6 +603,58 @@ func (x *ConnNotice) GetText() string { return "" } +type RptyEvent struct { + state protoimpl.MessageState `protogen:"open.v1"` + Token string `protobuf:"bytes,1,opt,name=Token,proto3" json:"Token,omitempty"` + Data []byte `protobuf:"bytes,2,opt,name=Data,proto3" json:"Data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RptyEvent) Reset() { + *x = RptyEvent{} + mi := &file_hodu_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RptyEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RptyEvent) ProtoMessage() {} + +func (x *RptyEvent) ProtoReflect() protoreflect.Message { + mi := &file_hodu_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RptyEvent.ProtoReflect.Descriptor instead. +func (*RptyEvent) Descriptor() ([]byte, []int) { + return file_hodu_proto_rawDescGZIP(), []int{7} +} + +func (x *RptyEvent) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +func (x *RptyEvent) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + type Packet struct { state protoimpl.MessageState `protogen:"open.v1"` Kind PACKET_KIND `protobuf:"varint,1,opt,name=Kind,proto3,enum=PACKET_KIND" json:"Kind,omitempty"` @@ -593,6 +666,7 @@ type Packet struct { // *Packet_Conn // *Packet_ConnErr // *Packet_ConnNoti + // *Packet_Rpty U isPacket_U `protobuf_oneof:"U"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -600,7 +674,7 @@ type Packet struct { func (x *Packet) Reset() { *x = Packet{} - mi := &file_hodu_proto_msgTypes[7] + mi := &file_hodu_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -612,7 +686,7 @@ func (x *Packet) String() string { func (*Packet) ProtoMessage() {} func (x *Packet) ProtoReflect() protoreflect.Message { - mi := &file_hodu_proto_msgTypes[7] + mi := &file_hodu_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -625,7 +699,7 @@ func (x *Packet) ProtoReflect() protoreflect.Message { // Deprecated: Use Packet.ProtoReflect.Descriptor instead. func (*Packet) Descriptor() ([]byte, []int) { - return file_hodu_proto_rawDescGZIP(), []int{7} + return file_hodu_proto_rawDescGZIP(), []int{8} } func (x *Packet) GetKind() PACKET_KIND { @@ -696,6 +770,15 @@ func (x *Packet) GetConnNoti() *ConnNotice { return nil } +func (x *Packet) GetRpty() *RptyEvent { + if x != nil { + if x, ok := x.U.(*Packet_Rpty); ok { + return x.Rpty + } + } + return nil +} + type isPacket_U interface { isPacket_U() } @@ -724,6 +807,10 @@ type Packet_ConnNoti struct { ConnNoti *ConnNotice `protobuf:"bytes,7,opt,name=ConnNoti,proto3,oneof"` } +type Packet_Rpty struct { + Rpty *RptyEvent `protobuf:"bytes,8,opt,name=Rpty,proto3,oneof"` +} + func (*Packet_Route) isPacket_U() {} func (*Packet_Peer) isPacket_U() {} @@ -736,94 +823,96 @@ func (*Packet_ConnErr) isPacket_U() {} func (*Packet_ConnNoti) isPacket_U() {} +func (*Packet_Rpty) isPacket_U() {} + var File_hodu_proto protoreflect.FileDescriptor -var file_hodu_proto_rawDesc = string([]byte{ - 0x0a, 0x0a, 0x68, 0x6f, 0x64, 0x75, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x36, 0x0a, 0x04, - 0x53, 0x65, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, - 0x0a, 0x05, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x46, - 0x6c, 0x61, 0x67, 0x73, 0x22, 0xdf, 0x01, 0x0a, 0x09, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x44, 0x65, - 0x73, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x07, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, - 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x53, 0x74, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0d, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x53, - 0x74, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0e, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x41, 0x64, 0x64, 0x72, 0x53, 0x74, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x64, 0x64, 0x72, 0x53, 0x74, 0x72, - 0x12, 0x24, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x65, 0x74, 0x53, 0x74, - 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x4e, 0x65, 0x74, 0x53, 0x74, 0x72, 0x22, 0x86, 0x01, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x44, - 0x65, 0x73, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, - 0x06, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x50, - 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, - 0x64, 0x64, 0x72, 0x53, 0x74, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x52, 0x65, - 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x53, 0x74, 0x72, 0x12, 0x22, 0x0a, 0x0c, 0x4c, - 0x6f, 0x63, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x53, 0x74, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0c, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x53, 0x74, 0x72, 0x22, - 0x50, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x52, - 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x52, 0x6f, - 0x75, 0x74, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, - 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, - 0x61, 0x22, 0x20, 0x0a, 0x08, 0x43, 0x6f, 0x6e, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x12, 0x14, 0x0a, - 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x22, 0x39, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, - 0x12, 0x18, 0x0a, 0x07, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x07, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x65, - 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x54, 0x65, 0x78, 0x74, 0x22, 0x20, - 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, - 0x54, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x54, 0x65, 0x78, 0x74, - 0x22, 0x89, 0x02, 0x0a, 0x06, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x20, 0x0a, 0x04, 0x4b, - 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x50, 0x41, 0x43, 0x4b, - 0x45, 0x54, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x52, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x22, 0x0a, - 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x52, - 0x6f, 0x75, 0x74, 0x65, 0x44, 0x65, 0x73, 0x63, 0x48, 0x00, 0x52, 0x05, 0x52, 0x6f, 0x75, 0x74, - 0x65, 0x12, 0x1f, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x09, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x44, 0x65, 0x73, 0x63, 0x48, 0x00, 0x52, 0x04, 0x50, 0x65, - 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x09, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x04, 0x44, - 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x04, 0x43, 0x6f, 0x6e, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x09, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x48, 0x00, 0x52, 0x04, - 0x43, 0x6f, 0x6e, 0x6e, 0x12, 0x26, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x6e, 0x45, 0x72, 0x72, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x45, 0x72, 0x72, 0x6f, - 0x72, 0x48, 0x00, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x6e, 0x45, 0x72, 0x72, 0x12, 0x29, 0x0a, 0x08, - 0x43, 0x6f, 0x6e, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, - 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x48, 0x00, 0x52, 0x08, 0x43, - 0x6f, 0x6e, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x42, 0x03, 0x0a, 0x01, 0x55, 0x2a, 0x5e, 0x0a, 0x0c, - 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x12, 0x0a, 0x0a, 0x06, - 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x10, - 0x01, 0x12, 0x08, 0x0a, 0x04, 0x54, 0x43, 0x50, 0x34, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x54, - 0x43, 0x50, 0x36, 0x10, 0x04, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x54, 0x59, 0x10, 0x08, 0x12, 0x08, - 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x10, 0x12, 0x09, 0x0a, 0x05, 0x48, 0x54, 0x54, 0x50, - 0x53, 0x10, 0x20, 0x12, 0x07, 0x0a, 0x03, 0x53, 0x53, 0x48, 0x10, 0x40, 0x2a, 0xe5, 0x01, 0x0a, - 0x0b, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x12, 0x0c, 0x0a, 0x08, - 0x52, 0x45, 0x53, 0x45, 0x52, 0x56, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x4f, - 0x55, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x52, - 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x4f, 0x50, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x52, - 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x03, 0x12, 0x11, - 0x0a, 0x0d, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, - 0x04, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, - 0x44, 0x10, 0x05, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x4f, 0x50, - 0x50, 0x45, 0x44, 0x10, 0x06, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x41, 0x42, - 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x07, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x45, 0x45, 0x52, 0x5f, - 0x45, 0x4f, 0x46, 0x10, 0x08, 0x12, 0x0d, 0x0a, 0x09, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x44, 0x41, - 0x54, 0x41, 0x10, 0x09, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4e, 0x4e, 0x5f, 0x44, 0x45, 0x53, - 0x43, 0x10, 0x0b, 0x12, 0x0e, 0x0a, 0x0a, 0x43, 0x4f, 0x4e, 0x4e, 0x5f, 0x45, 0x52, 0x52, 0x4f, - 0x52, 0x10, 0x0c, 0x12, 0x0f, 0x0a, 0x0b, 0x43, 0x4f, 0x4e, 0x4e, 0x5f, 0x4e, 0x4f, 0x54, 0x49, - 0x43, 0x45, 0x10, 0x0d, 0x32, 0x49, 0x0a, 0x04, 0x48, 0x6f, 0x64, 0x75, 0x12, 0x19, 0x0a, 0x07, - 0x47, 0x65, 0x74, 0x53, 0x65, 0x65, 0x64, 0x12, 0x05, 0x2e, 0x53, 0x65, 0x65, 0x64, 0x1a, 0x05, - 0x2e, 0x53, 0x65, 0x65, 0x64, 0x22, 0x00, 0x12, 0x26, 0x0a, 0x0c, 0x50, 0x61, 0x63, 0x6b, 0x65, - 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x07, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, - 0x1a, 0x07, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, - 0x08, 0x5a, 0x06, 0x2e, 0x2f, 0x68, 0x6f, 0x64, 0x75, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, -}) +const file_hodu_proto_rawDesc = "" + + "\n" + + "\n" + + "hodu.proto\"6\n" + + "\x04Seed\x12\x18\n" + + "\aVersion\x18\x01 \x01(\rR\aVersion\x12\x14\n" + + "\x05Flags\x18\x02 \x01(\x04R\x05Flags\"\xdf\x01\n" + + "\tRouteDesc\x12\x18\n" + + "\aRouteId\x18\x01 \x01(\rR\aRouteId\x12$\n" + + "\rTargetAddrStr\x18\x02 \x01(\tR\rTargetAddrStr\x12\x1e\n" + + "\n" + + "TargetName\x18\x03 \x01(\tR\n" + + "TargetName\x12$\n" + + "\rServiceOption\x18\x04 \x01(\rR\rServiceOption\x12&\n" + + "\x0eServiceAddrStr\x18\x05 \x01(\tR\x0eServiceAddrStr\x12$\n" + + "\rServiceNetStr\x18\x06 \x01(\tR\rServiceNetStr\"\x86\x01\n" + + "\bPeerDesc\x12\x18\n" + + "\aRouteId\x18\x01 \x01(\rR\aRouteId\x12\x16\n" + + "\x06PeerId\x18\x02 \x01(\rR\x06PeerId\x12$\n" + + "\rRemoteAddrStr\x18\x03 \x01(\tR\rRemoteAddrStr\x12\"\n" + + "\fLocalAddrStr\x18\x04 \x01(\tR\fLocalAddrStr\"P\n" + + "\bPeerData\x12\x18\n" + + "\aRouteId\x18\x01 \x01(\rR\aRouteId\x12\x16\n" + + "\x06PeerId\x18\x02 \x01(\rR\x06PeerId\x12\x12\n" + + "\x04Data\x18\x03 \x01(\fR\x04Data\" \n" + + "\bConnDesc\x12\x14\n" + + "\x05Token\x18\x01 \x01(\tR\x05Token\"9\n" + + "\tConnError\x12\x18\n" + + "\aErrorId\x18\x01 \x01(\rR\aErrorId\x12\x12\n" + + "\x04Text\x18\x02 \x01(\tR\x04Text\" \n" + + "\n" + + "ConnNotice\x12\x12\n" + + "\x04Text\x18\x01 \x01(\tR\x04Text\"5\n" + + "\tRptyEvent\x12\x14\n" + + "\x05Token\x18\x01 \x01(\tR\x05Token\x12\x12\n" + + "\x04Data\x18\x02 \x01(\fR\x04Data\"\xab\x02\n" + + "\x06Packet\x12 \n" + + "\x04Kind\x18\x01 \x01(\x0e2\f.PACKET_KINDR\x04Kind\x12\"\n" + + "\x05Route\x18\x02 \x01(\v2\n" + + ".RouteDescH\x00R\x05Route\x12\x1f\n" + + "\x04Peer\x18\x03 \x01(\v2\t.PeerDescH\x00R\x04Peer\x12\x1f\n" + + "\x04Data\x18\x04 \x01(\v2\t.PeerDataH\x00R\x04Data\x12\x1f\n" + + "\x04Conn\x18\x05 \x01(\v2\t.ConnDescH\x00R\x04Conn\x12&\n" + + "\aConnErr\x18\x06 \x01(\v2\n" + + ".ConnErrorH\x00R\aConnErr\x12)\n" + + "\bConnNoti\x18\a \x01(\v2\v.ConnNoticeH\x00R\bConnNoti\x12 \n" + + "\x04Rpty\x18\b \x01(\v2\n" + + ".RptyEventH\x00R\x04RptyB\x03\n" + + "\x01U*^\n" + + "\fROUTE_OPTION\x12\n" + + "\n" + + "\x06UNSPEC\x10\x00\x12\a\n" + + "\x03TCP\x10\x01\x12\b\n" + + "\x04TCP4\x10\x02\x12\b\n" + + "\x04TCP6\x10\x04\x12\a\n" + + "\x03TTY\x10\b\x12\b\n" + + "\x04HTTP\x10\x10\x12\t\n" + + "\x05HTTPS\x10 \x12\a\n" + + "\x03SSH\x10@*\xd7\x02\n" + + "\vPACKET_KIND\x12\f\n" + + "\bRESERVED\x10\x00\x12\x0f\n" + + "\vROUTE_START\x10\x01\x12\x0e\n" + + "\n" + + "ROUTE_STOP\x10\x02\x12\x11\n" + + "\rROUTE_STARTED\x10\x03\x12\x11\n" + + "\rROUTE_STOPPED\x10\x04\x12\x10\n" + + "\fPEER_STARTED\x10\x05\x12\x10\n" + + "\fPEER_STOPPED\x10\x06\x12\x10\n" + + "\fPEER_ABORTED\x10\a\x12\f\n" + + "\bPEER_EOF\x10\b\x12\r\n" + + "\tPEER_DATA\x10\t\x12\r\n" + + "\tCONN_DESC\x10\v\x12\x0e\n" + + "\n" + + "CONN_ERROR\x10\f\x12\x0f\n" + + "\vCONN_NOTICE\x10\r\x12\x0e\n" + + "\n" + + "RPTY_START\x10\x0e\x12\r\n" + + "\tRPTY_STOP\x10\x0f\x12\x10\n" + + "\fRPTY_STARTED\x10\x10\x12\x10\n" + + "\fRPTY_STOPPED\x10\x11\x12\x10\n" + + "\fRPTY_ABORTED\x10\x12\x12\f\n" + + "\bRPTY_EOF\x10\x13\x12\r\n" + + "\tRPTY_DATA\x10\x142I\n" + + "\x04Hodu\x12\x19\n" + + "\aGetSeed\x12\x05.Seed\x1a\x05.Seed\"\x00\x12&\n" + + "\fPacketStream\x12\a.Packet\x1a\a.Packet\"\x00(\x010\x01B\bZ\x06./hodub\x06proto3" var ( file_hodu_proto_rawDescOnce sync.Once @@ -838,7 +927,7 @@ func file_hodu_proto_rawDescGZIP() []byte { } var file_hodu_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_hodu_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_hodu_proto_msgTypes = make([]protoimpl.MessageInfo, 9) var file_hodu_proto_goTypes = []any{ (ROUTE_OPTION)(0), // 0: ROUTE_OPTION (PACKET_KIND)(0), // 1: PACKET_KIND @@ -849,25 +938,27 @@ var file_hodu_proto_goTypes = []any{ (*ConnDesc)(nil), // 6: ConnDesc (*ConnError)(nil), // 7: ConnError (*ConnNotice)(nil), // 8: ConnNotice - (*Packet)(nil), // 9: Packet + (*RptyEvent)(nil), // 9: RptyEvent + (*Packet)(nil), // 10: Packet } var file_hodu_proto_depIdxs = []int32{ - 1, // 0: Packet.Kind:type_name -> PACKET_KIND - 3, // 1: Packet.Route:type_name -> RouteDesc - 4, // 2: Packet.Peer:type_name -> PeerDesc - 5, // 3: Packet.Data:type_name -> PeerData - 6, // 4: Packet.Conn:type_name -> ConnDesc - 7, // 5: Packet.ConnErr:type_name -> ConnError - 8, // 6: Packet.ConnNoti:type_name -> ConnNotice - 2, // 7: Hodu.GetSeed:input_type -> Seed - 9, // 8: Hodu.PacketStream:input_type -> Packet - 2, // 9: Hodu.GetSeed:output_type -> Seed - 9, // 10: Hodu.PacketStream:output_type -> Packet - 9, // [9:11] is the sub-list for method output_type - 7, // [7:9] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name + 1, // 0: Packet.Kind:type_name -> PACKET_KIND + 3, // 1: Packet.Route:type_name -> RouteDesc + 4, // 2: Packet.Peer:type_name -> PeerDesc + 5, // 3: Packet.Data:type_name -> PeerData + 6, // 4: Packet.Conn:type_name -> ConnDesc + 7, // 5: Packet.ConnErr:type_name -> ConnError + 8, // 6: Packet.ConnNoti:type_name -> ConnNotice + 9, // 7: Packet.Rpty:type_name -> RptyEvent + 2, // 8: Hodu.GetSeed:input_type -> Seed + 10, // 9: Hodu.PacketStream:input_type -> Packet + 2, // 10: Hodu.GetSeed:output_type -> Seed + 10, // 11: Hodu.PacketStream:output_type -> Packet + 10, // [10:12] is the sub-list for method output_type + 8, // [8:10] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name } func init() { file_hodu_proto_init() } @@ -875,13 +966,14 @@ func file_hodu_proto_init() { if File_hodu_proto != nil { return } - file_hodu_proto_msgTypes[7].OneofWrappers = []any{ + file_hodu_proto_msgTypes[8].OneofWrappers = []any{ (*Packet_Route)(nil), (*Packet_Peer)(nil), (*Packet_Data)(nil), (*Packet_Conn)(nil), (*Packet_ConnErr)(nil), (*Packet_ConnNoti)(nil), + (*Packet_Rpty)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -889,7 +981,7 @@ func file_hodu_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_hodu_proto_rawDesc), len(file_hodu_proto_rawDesc)), NumEnums: 2, - NumMessages: 8, + NumMessages: 9, NumExtensions: 0, NumServices: 1, }, diff --git a/hodu.proto b/hodu.proto index 85a7ef3..d116e35 100644 --- a/hodu.proto +++ b/hodu.proto @@ -81,6 +81,11 @@ message ConnNotice { string Text = 1; }; +message RptyEvent { + string Token = 1; + bytes Data = 2; +}; + enum PACKET_KIND { RESERVED = 0; // not used ROUTE_START = 1; @@ -95,6 +100,14 @@ enum PACKET_KIND { CONN_DESC = 11; CONN_ERROR = 12; CONN_NOTICE = 13; + + RPTY_START = 14; + RPTY_STOP = 15; + RPTY_STARTED = 16; + RPTY_STOPPED = 17; + RPTY_ABORTED = 18; + RPTY_EOF = 19; + RPTY_DATA = 20; }; message Packet { @@ -107,5 +120,6 @@ message Packet { ConnDesc Conn = 5; ConnError ConnErr = 6; ConnNotice ConnNoti = 7; + RptyEvent Rpty = 8; }; } diff --git a/packet.go b/packet.go index 8606a73..2db66c0 100644 --- a/packet.go +++ b/packet.go @@ -74,3 +74,15 @@ func MakeConnErrorPacket(error_id uint32, msg string) *Packet { func MakeConnNoticePacket(msg string) *Packet { return &Packet{Kind: PACKET_KIND_CONN_NOTICE, U: &Packet_ConnNoti{ConnNoti: &ConnNotice{Text: msg}}} } + +func MakeRptyStartPacket(token string) *Packet { + return &Packet{Kind: PACKET_KIND_RPTY_START, U: &Packet_Rpty{Rpty: &RptyEvent{Token: token}}} +} + +func MakeRptyStopPacket(token string) *Packet { + return &Packet{Kind: PACKET_KIND_RPTY_START, U: &Packet_Rpty{Rpty: &RptyEvent{Token: token}}} +} + +func MakeRptyDataPacket(token string, data []byte) *Packet { + return &Packet{Kind: PACKET_KIND_RPTY_START, U: &Packet_Rpty{Rpty: &RptyEvent{Token: token, Data: data}}} +} diff --git a/server-ctl.go b/server-ctl.go index 88a17cc..ed4e73b 100644 --- a/server-ctl.go +++ b/server-ctl.go @@ -76,7 +76,7 @@ type json_out_server_stats struct { ServerPeers int64 `json:"server-peers"` SshProxySessions int64 `json:"pxy-ssh-sessions"` - ServerPtsSessions int64 `json:"server-pts-sessions"` + ServerPtySessions int64 `json:"server-pty-sessions"` } // this is a more specialized variant of json_in_notice @@ -920,7 +920,7 @@ func (ctl *server_ctl_stats) ServeHTTP(w http.ResponseWriter, req *http.Request) stats.ServerRoutes = s.stats.routes.Load() stats.ServerPeers = s.stats.peers.Load() stats.SshProxySessions = s.stats.ssh_proxy_sessions.Load() - stats.ServerPtsSessions = s.stats.pts_sessions.Load() + stats.ServerPtySessions = s.stats.pty_sessions.Load() status_code = WriteJsonRespHeader(w, http.StatusOK) if err = je.Encode(stats); err != nil { goto oops } diff --git a/server-metrics.go b/server-metrics.go index bba4b95..a1e0c3f 100644 --- a/server-metrics.go +++ b/server-metrics.go @@ -11,7 +11,7 @@ type ServerCollector struct { ServerRoutes *prometheus.Desc ServerPeers *prometheus.Desc SshProxySessions *prometheus.Desc - PtsSessions *prometheus.Desc + PtySessions *prometheus.Desc } // NewServerCollector returns a new ServerCollector with all prometheus.Desc initialized @@ -53,9 +53,9 @@ func NewServerCollector(server *Server) ServerCollector { "Number of SSH proxy sessions", nil, nil, ), - PtsSessions: prometheus.NewDesc( - prefix + "pts_sessions", - "Number of pts session", + PtySessions: prometheus.NewDesc( + prefix + "pty_sessions", + "Number of pty session", nil, nil, ), } @@ -67,7 +67,7 @@ func (c ServerCollector) Describe(ch chan<- *prometheus.Desc) { ch <- c.ServerRoutes ch <- c.ServerPeers ch <- c.SshProxySessions - ch <- c.PtsSessions + ch <- c.PtySessions } func (c ServerCollector) Collect(ch chan<- prometheus.Metric) { @@ -106,8 +106,8 @@ func (c ServerCollector) Collect(ch chan<- prometheus.Metric) { ) ch <- prometheus.MustNewConstMetric( - c.PtsSessions, + c.PtySessions, prometheus.GaugeValue, - float64(c.server.stats.pts_sessions.Load()), + float64(c.server.stats.pty_sessions.Load()), ) } diff --git a/server-pts.go b/server-pty.go similarity index 74% rename from server-pts.go rename to server-pty.go index c84dd50..422c21f 100644 --- a/server-pts.go +++ b/server-pty.go @@ -14,28 +14,34 @@ import "sync" import "syscall" import "text/template" -import "github.com/creack/pty" +import pts "github.com/creack/pty" import "golang.org/x/net/websocket" import "golang.org/x/sys/unix" -type server_pts_ws struct { +type server_pty_ws struct { S *Server Id string ws *websocket.Conn } -type server_pts_xterm_file struct { +type server_rpty_ws struct { + S *Server + Id string + ws *websocket.Conn +} + +type server_pty_xterm_file struct { ServerCtl file string } // ------------------------------------------------------ -func (pts *server_pts_ws) Identity() string { - return pts.Id +func (pty *server_pty_ws) Identity() string { + return pty.Id } -func (pts *server_pts_ws) send_ws_data(ws *websocket.Conn, type_val string, data string) error { +func (pty *server_pty_ws) send_ws_data(ws *websocket.Conn, type_val string, data string) error { var msg []byte var err error @@ -45,26 +51,26 @@ func (pts *server_pts_ws) send_ws_data(ws *websocket.Conn, type_val string, data } -func (pts *server_pts_ws) connect_pts(username string, password string) (*exec.Cmd, *os.File, error) { +func (pty *server_pty_ws) connect_pty(username string, password string) (*exec.Cmd, *os.File, error) { var s *Server var cmd *exec.Cmd var tty *os.File var err error // username and password are not used yet. - s = pts.S + s = pty.S - if s.pts_shell == "" { - return nil, nil, fmt.Errorf("blank pts shell") + if s.pty_shell == "" { + return nil, nil, fmt.Errorf("blank pty shell") } - cmd = exec.Command(s.pts_shell); - if s.pts_user != "" { + cmd = exec.Command(s.pty_shell); + if s.pty_user != "" { var uid int var gid int var u *user.User - u, err = user.Lookup(s.pts_user) + u, err = user.Lookup(s.pty_user) if err != nil { return nil, nil, err } uid, _ = strconv.Atoi(u.Uid) @@ -81,13 +87,13 @@ func (pts *server_pts_ws) connect_pts(username string, password string) (*exec.C "HOME=" + u.HomeDir, "LOGNAME=" + u.Username, "PATH=" + os.Getenv("PATH"), - "SHELL=" + s.pts_shell, + "SHELL=" + s.pty_shell, "TERM=xterm", "USER=" + u.Username, ) } - tty, err = pty.Start(cmd) + tty, err = pts.Start(cmd) if err != nil { return nil, nil, err } @@ -98,7 +104,7 @@ func (pts *server_pts_ws) connect_pts(username string, password string) (*exec.C return cmd, tty, nil } -func (pts *server_pts_ws) ServeWebsocket(ws *websocket.Conn) (int, error) { +func (pty *server_pty_ws) ServeWebsocket(ws *websocket.Conn) (int, error) { var s *Server var req *http.Request var username string @@ -111,7 +117,7 @@ func (pts *server_pts_ws) ServeWebsocket(ws *websocket.Conn) (int, error) { var conn_ready_chan chan bool var err error - s = pts.S + s = pty.S req = ws.Request() conn_ready_chan = make(chan bool, 3) @@ -129,18 +135,17 @@ func (pts *server_pts_ws) ServeWebsocket(ws *websocket.Conn) (int, error) { var n int var err error - poll_fds = []unix.PollFd{ unix.PollFd{Fd: int32(out.Fd()), Events: unix.POLLIN}, } - s.stats.pts_sessions.Add(1) + s.stats.pty_sessions.Add(1) buf = make([]byte, 2048) for { n, err = unix.Poll(poll_fds, -1) // -1 means wait indefinitely if err != nil { if errors.Is(err, unix.EINTR) { continue } - s.log.Write("", LOG_ERROR, "[%s] Failed to poll pts stdout - %s", req.RemoteAddr, err.Error()) + s.log.Write("", LOG_ERROR, "[%s] Failed to poll pty stdout - %s", req.RemoteAddr, err.Error()) break } if n == 0 { // timed out @@ -148,7 +153,7 @@ func (pts *server_pts_ws) ServeWebsocket(ws *websocket.Conn) (int, error) { } if (poll_fds[0].Revents & (unix.POLLERR | unix.POLLHUP | unix.POLLNVAL)) != 0 { - s.log.Write(pts.Id, LOG_DEBUG, "[%s] EOF detected on pts stdout", req.RemoteAddr) + s.log.Write(pty.Id, LOG_DEBUG, "[%s] EOF detected on pty stdout", req.RemoteAddr) break; } @@ -156,20 +161,20 @@ func (pts *server_pts_ws) ServeWebsocket(ws *websocket.Conn) (int, error) { n, err = out.Read(buf) if err != nil { if !errors.Is(err, io.EOF) { - s.log.Write(pts.Id, LOG_ERROR, "[%s] Failed to read pts stdout - %s", req.RemoteAddr, err.Error()) + s.log.Write(pty.Id, LOG_ERROR, "[%s] Failed to read pty stdout - %s", req.RemoteAddr, err.Error()) } break } if n > 0 { - err = pts.send_ws_data(ws, "iov", string(buf[:n])) + err = pty.send_ws_data(ws, "iov", string(buf[:n])) if err != nil { - s.log.Write(pts.Id, LOG_ERROR, "[%s] Failed to send to websocket - %s", req.RemoteAddr, err.Error()) + s.log.Write(pty.Id, LOG_ERROR, "[%s] Failed to send to websocket - %s", req.RemoteAddr, err.Error()) break } } } } - s.stats.pts_sessions.Add(-1) + s.stats.pty_sessions.Add(-1) } }() @@ -194,18 +199,18 @@ ws_recv_loop: var err error defer wg.Done() - cmd, tty, err = pts.connect_pts(username, password) + cmd, tty, err = pty.connect_pty(username, password) if err != nil { - s.log.Write(pts.Id, LOG_ERROR, "[%s] Failed to connect pts - %s", req.RemoteAddr, err.Error()) - pts.send_ws_data(ws, "error", err.Error()) - ws.Close() // dirty way to flag out the error + s.log.Write(pty.Id, LOG_ERROR, "[%s] Failed to connect pty - %s", req.RemoteAddr, err.Error()) + pty.send_ws_data(ws, "error", err.Error()) + ws.Close() // dirty way to flag out the error - this will make websocket.MessageReceive to fail } else { - err = pts.send_ws_data(ws, "status", "opened") + err = pty.send_ws_data(ws, "status", "opened") if err != nil { - s.log.Write(pts.Id, LOG_ERROR, "[%s] Failed to write opened event to websocket - %s", req.RemoteAddr, err.Error()) + s.log.Write(pty.Id, LOG_ERROR, "[%s] Failed to write opened event to websocket - %s", req.RemoteAddr, err.Error()) ws.Close() // dirty way to flag out the error } else { - s.log.Write(pts.Id, LOG_DEBUG, "[%s] Opened pts session", req.RemoteAddr) + s.log.Write(pty.Id, LOG_DEBUG, "[%s] Opened pty session", req.RemoteAddr) out = tty in = tty conn_ready_chan <- true @@ -235,8 +240,8 @@ ws_recv_loop: var cols int rows, _ = strconv.Atoi(ev.Data[0]) cols, _ = strconv.Atoi(ev.Data[1]) - pty.Setsize(tty, &pty.Winsize{Rows: uint16(rows), Cols: uint16(cols)}) - s.log.Write(pts.Id, LOG_DEBUG, "[%s] Resized terminal to %d,%d", req.RemoteAddr, rows, cols) + pts.Setsize(tty, &pts.Winsize{Rows: uint16(rows), Cols: uint16(cols)}) + s.log.Write(pty.Id, LOG_DEBUG, "[%s] Resized terminal to %d,%d", req.RemoteAddr, rows, cols) // ignore error } } @@ -245,7 +250,7 @@ ws_recv_loop: } if tty != nil { - err = pts.send_ws_data(ws, "status", "closed") + err = pty.send_ws_data(ws, "status", "closed") if err != nil { goto done } } @@ -260,22 +265,21 @@ done: if tty != nil { tty.Close() } if cmd != nil { cmd.Wait() } wg.Wait() - s.log.Write(pts.Id, LOG_DEBUG, "[%s] Ended pts session", req.RemoteAddr) + s.log.Write(pty.Id, LOG_DEBUG, "[%s] Ended pty session", req.RemoteAddr) return http.StatusOK, err } - // ------------------------------------------------------ -func (pts *server_pts_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.Request) (int, error) { +func (pty *server_pty_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.Request) (int, error) { var s *Server var status_code int var err error - s = pts.S + s = pty.S - switch pts.file { + switch pty.file { case "xterm.js": status_code = WriteJsRespHeader(w, http.StatusOK) w.Write(xterm_js) @@ -301,7 +305,7 @@ func (pts *server_pts_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.Req status_code = WriteHtmlRespHeader(w, http.StatusOK) tmpl.Execute(w, &xterm_session_info{ - Mode: "pts", + Mode: "pty", ConnId: "-1", RouteId: "-1", }) @@ -314,9 +318,9 @@ func (pts *server_pts_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.Req status_code = WriteEmptyRespHeader(w, http.StatusNotFound) default: - if strings.HasPrefix(pts.file, "_redir:") { + if strings.HasPrefix(pty.file, "_redir:") { status_code = http.StatusMovedPermanently - w.Header().Set("Location", pts.file[7:]) + w.Header().Set("Location", pty.file[7:]) w.WriteHeader(status_code) } else { status_code = WriteEmptyRespHeader(w, http.StatusNotFound) diff --git a/server.go b/server.go index a9c3cd1..43a6970 100644 --- a/server.go +++ b/server.go @@ -153,15 +153,15 @@ type Server struct { routes atomic.Int64 peers atomic.Int64 ssh_proxy_sessions atomic.Int64 - pts_sessions atomic.Int64 + pty_sessions atomic.Int64 } wpx_resp_tf ServerWpxResponseTransformer wpx_foreign_port_proxy_maker ServerWpxForeignPortProxyMaker - pts_user string - pts_shell string + pty_user string + pty_shell string xterm_html string } @@ -635,6 +635,10 @@ func (cts *ServerConn) ReqStopAllServerRoutes() { cts.route_mtx.Unlock() } + +func (cts *ServerConn) StartRpts() { +} + func (cts *ServerConn) ReportPacket(route_id RouteId, pts_id PeerId, packet_type PACKET_KIND, event_data interface{}) error { var r *ServerRoute var ok bool @@ -877,6 +881,17 @@ func (cts *ServerConn) receive_from_stream(wg *sync.WaitGroup) { } else { cts.S.log.Write(cts.Sid, LOG_ERROR, "Invalid conn_notice packet from %s", cts.RemoteAddr) } + + /*case PACKET_KIND_RPTY_START: + case PACKET_KIND_RPTY_STOP:*/ + case PACKET_KIND_RPTY_STARTED: + case PACKET_KIND_RPTY_STOPPED: + case PACKET_KIND_RPTY_ABORTED: + case PACKET_KIND_RPTY_EOF: + case PACKET_KIND_RPTY_DATA: + // inspect the token + // find the right websocket handler... + // report it to the right websocket handler } } @@ -1380,18 +1395,31 @@ func NewServer(ctx context.Context, name string, logger Logger, cfg *ServerConfi s.ctl_mux.Handle("/_ctl/events", s.SafeWrapWebsocketHandler(s.WrapWebsocketHandler(&server_ctl_ws{ServerCtl{S: &s, Id: HS_ID_CTL}}))) - s.ctl_mux.Handle("/_pts/ws", - s.SafeWrapWebsocketHandler(s.WrapWebsocketHandler(&server_pts_ws{S: &s, Id: HS_ID_CTL}))) - s.ctl_mux.Handle("/_pts/xterm.js", - s.WrapHttpHandler(&server_pts_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "xterm.js"})) - s.ctl_mux.Handle("/_pts/xterm-addon-fit.js", - s.WrapHttpHandler(&server_pts_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "xterm-addon-fit.js"})) - s.ctl_mux.Handle("/_pts/xterm.css", - s.WrapHttpHandler(&server_pts_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "xterm.css"})) - s.ctl_mux.Handle("/_pts/xterm.html", - s.WrapHttpHandler(&server_pts_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "xterm.html"})) - s.ctl_mux.Handle("/_pts/", - s.WrapHttpHandler(&server_pts_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "_redir:xterm.html"})) + s.ctl_mux.Handle("/_pty/ws", + s.SafeWrapWebsocketHandler(s.WrapWebsocketHandler(&server_pty_ws{S: &s, Id: HS_ID_CTL}))) + s.ctl_mux.Handle("/_pty/xterm.js", + s.WrapHttpHandler(&server_pty_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "xterm.js"})) + s.ctl_mux.Handle("/_pty/xterm.js/", + s.WrapHttpHandler(&server_pty_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "_forbidden"})) + s.ctl_mux.Handle("/_pty/xterm-addon-fit.js", + s.WrapHttpHandler(&server_pty_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "xterm-addon-fit.js"})) + s.ctl_mux.Handle("/_pty/xterm-addon-fit.js/", + s.WrapHttpHandler(&server_pty_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "_forbidden"})) + s.ctl_mux.Handle("/_pty/xterm.css", + s.WrapHttpHandler(&server_pty_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "xterm.css"})) + s.ctl_mux.Handle("/_pty/xterm.css/", + s.WrapHttpHandler(&server_pty_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "_forbidden"})) + s.ctl_mux.Handle("/_pty/xterm.html", + s.WrapHttpHandler(&server_pty_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "xterm.html"})) + s.ctl_mux.Handle("/_pty/xterm.html/", + s.WrapHttpHandler(&server_pty_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "_forbidden"})) + s.ctl_mux.Handle("/_pty/", + s.WrapHttpHandler(&server_pty_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "_redir:xterm.html"})) + +/* + s.ctl_mux.Handle("/_rpts/ws", + s.SafeWrapWebsocketHandler(s.WrapWebsocketHandler(&server_rpts_ws{S: &s, Id: HS_ID_CTL}))) +*/ s.ctl = make([]*http.Server, len(cfg.CtlAddrs)) for i = 0; i < len(cfg.CtlAddrs); i++ { @@ -1511,7 +1539,7 @@ func NewServer(ctx context.Context, name string, logger Logger, cfg *ServerConfi s.stats.routes.Store(0) s.stats.peers.Store(0) s.stats.ssh_proxy_sessions.Store(0) - s.stats.pts_sessions.Store(0) + s.stats.pty_sessions.Store(0) return &s, nil @@ -1547,20 +1575,20 @@ func (s *Server) GetXtermHtml() string { return s.xterm_html } -func (s *Server) SetPtsUser(user string) { - s.pts_user = user +func (s *Server) SetPtyUser(user string) { + s.pty_user = user } -func (s *Server) GetPtsUser() string { - return s.pts_user +func (s *Server) GetPtyUser() string { + return s.pty_user } -func (s *Server) SetPtsShell(user string) { - s.pts_shell = user +func (s *Server) SetPtyShell(user string) { + s.pty_shell = user } -func (s *Server) GetPtsShell() string { - return s.pts_shell +func (s *Server) GetPtyShell() string { + return s.pty_shell } func (s *Server) run_grpc_server(idx int, wg *sync.WaitGroup) error { diff --git a/xterm.html b/xterm.html index 384ff9a..e7421cf 100644 --- a/xterm.html +++ b/xterm.html @@ -106,7 +106,7 @@ window.onload = function(event) { const login_form_title = document.getElementById('login-form-title'); const login_form = document.getElementById('login-form'); const login_ssh_part = document.getElementById('login-ssh-part'); - const login_pts_part = document.getElementById('login-pts-part'); + const login_pty_part = document.getElementById('login-pty-part'); const username_field = document.getElementById('username'); const password_field= document.getElementById('password'); @@ -114,12 +114,12 @@ window.onload = function(event) { login_ssh_part.style.display = 'block'; username_field.disabled = false; password_field.disabled = false; - login_pts_part.style.display = 'none'; + login_pty_part.style.display = 'none'; } else { login_ssh_part.style.display = 'none'; username_field.disabled = true; password_field.disabled = true; - login_pts_part.style.display = 'block'; + login_pty_part.style.display = 'block'; } const term = new window.Terminal({ @@ -296,7 +296,7 @@ window.onload = function(event) { Password: -