merged tui for tcpTunnel (#307)

This commit is contained in:
Michael Quigley 2023-05-01 12:19:06 -04:00
parent 74fd8d9956
commit 28916e8d2a
No known key found for this signature in database
GPG Key ID: 9B60314A9DD20A62
13 changed files with 115 additions and 162 deletions

View File

@ -6,6 +6,7 @@ import (
httptransport "github.com/go-openapi/runtime/client" httptransport "github.com/go-openapi/runtime/client"
"github.com/openziti/zrok/endpoints" "github.com/openziti/zrok/endpoints"
"github.com/openziti/zrok/endpoints/proxy" "github.com/openziti/zrok/endpoints/proxy"
"github.com/openziti/zrok/endpoints/tcpTunnel"
"github.com/openziti/zrok/rest_client_zrok" "github.com/openziti/zrok/rest_client_zrok"
"github.com/openziti/zrok/rest_client_zrok/share" "github.com/openziti/zrok/rest_client_zrok/share"
"github.com/openziti/zrok/rest_model_zrok" "github.com/openziti/zrok/rest_model_zrok"
@ -48,14 +49,6 @@ func newAccessPrivateCommand() *accessPrivateCommand {
func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) { func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
shrToken := args[0] shrToken := args[0]
endpointUrl, err := url.Parse("http://" + cmd.bindAddress)
if err != nil {
if !panicInstead {
tui.Error("invalid endpoint address", err)
}
panic(err)
}
zrd, err := zrokdir.Load() zrd, err := zrokdir.Load()
if err != nil { if err != nil {
tui.Error("unable to load zrokdir", err) tui.Error("unable to load zrokdir", err)
@ -88,10 +81,62 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
} }
logrus.Infof("allocated frontend '%v'", accessResp.Payload.FrontendToken) logrus.Infof("allocated frontend '%v'", accessResp.Payload.FrontendToken)
protocol := "http://"
switch accessResp.Payload.BackendMode {
case "tcpTunnel":
protocol = "tcp://"
}
endpointUrl, err := url.Parse(protocol + cmd.bindAddress)
if err != nil {
if !panicInstead {
tui.Error("invalid endpoint address", err)
}
panic(err)
}
requests := make(chan *endpoints.Request, 1024)
if accessResp.Payload.BackendMode == "tcpTunnel" {
fe, err := tcpTunnel.NewFrontend(&tcpTunnel.FrontendConfig{
BindAddress: cmd.bindAddress,
IdentityName: "backend",
ShrToken: args[0],
RequestsChan: requests,
})
if err != nil {
if !panicInstead {
tui.Error("unable to create private frontend", err)
}
panic(err)
}
go func() {
if err := fe.Run(); err != nil {
if !panicInstead {
tui.Error("error starting frontend", err)
}
panic(err)
}
}()
} else {
cfg := proxy.DefaultFrontendConfig("backend") cfg := proxy.DefaultFrontendConfig("backend")
cfg.ShrToken = shrToken cfg.ShrToken = shrToken
cfg.Address = cmd.bindAddress cfg.Address = cmd.bindAddress
cfg.RequestsChan = make(chan *endpoints.Request, 1024) cfg.RequestsChan = requests
fe, err := proxy.NewFrontend(cfg)
if err != nil {
if !panicInstead {
tui.Error("unable to create private frontend", err)
}
panic(err)
}
go func() {
if err := fe.Run(); err != nil {
if !panicInstead {
tui.Error("unable to run frontend", err)
}
}
}()
}
c := make(chan os.Signal) c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM) signal.Notify(c, os.Interrupt, syscall.SIGTERM)
@ -101,27 +146,11 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
os.Exit(0) os.Exit(0)
}() }()
frontend, err := proxy.NewFrontend(cfg)
if err != nil {
if !panicInstead {
tui.Error("unable to create private frontend", err)
}
panic(err)
}
go func() {
if err := frontend.Run(); err != nil {
if !panicInstead {
tui.Error("unable to run frontend", err)
}
}
}()
if cmd.headless { if cmd.headless {
logrus.Infof("access the zrok share at the followind endpoint: %v", endpointUrl.String()) logrus.Infof("access the zrok share at the followind endpoint: %v", endpointUrl.String())
for { for {
select { select {
case req := <-cfg.RequestsChan: case req := <-requests:
logrus.Infof("%v -> %v %v", req.RemoteAddr, req.Method, req.Path) logrus.Infof("%v -> %v %v", req.RemoteAddr, req.Method, req.Path)
} }
} }
@ -135,7 +164,7 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
go func() { go func() {
for { for {
select { select {
case req := <-cfg.RequestsChan: case req := <-requests:
if req != nil { if req != nil {
prg.Send(req) prg.Send(req)
} }
@ -147,9 +176,8 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
tui.Error("An error occurred", err) tui.Error("An error occurred", err)
} }
close(cfg.RequestsChan) close(requests)
cmd.destroy(accessResp.Payload.FrontendToken, zrd.Env.ZId, shrToken, zrok, auth) cmd.destroy(accessResp.Payload.FrontendToken, zrd.Env.ZId, shrToken, zrok, auth)
} }
} }

View File

@ -1,107 +0,0 @@
package main
import (
"github.com/go-openapi/runtime"
httptransport "github.com/go-openapi/runtime/client"
"github.com/openziti/zrok/endpoints/tcpTunnel"
"github.com/openziti/zrok/rest_client_zrok"
"github.com/openziti/zrok/rest_client_zrok/share"
"github.com/openziti/zrok/rest_model_zrok"
"github.com/openziti/zrok/tui"
"github.com/openziti/zrok/zrokdir"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"os"
"os/signal"
"syscall"
"time"
)
func init() {
accessPrivateCmd.cmd.AddCommand(newAccessPrivateTunnelCommand().cmd)
}
type accessPrivateTunnelCommand struct {
bindAddress string
cmd *cobra.Command
}
func newAccessPrivateTunnelCommand() *accessPrivateTunnelCommand {
cmd := &cobra.Command{
Use: "tunnel <shareToken>",
Short: "Create a private tunnel frontend to access a share",
Args: cobra.ExactArgs(1),
}
command := &accessPrivateTunnelCommand{cmd: cmd}
cmd.Flags().StringVarP(&command.bindAddress, "bind", "b", "127.0.0.1:9191", "The address to bind the private tunnel")
cmd.Run = command.run
return command
}
func (cmd *accessPrivateTunnelCommand) run(_ *cobra.Command, args []string) {
zrd, err := zrokdir.Load()
if err != nil {
tui.Error("unable to load zrokdir", err)
}
if zrd.Env == nil {
tui.Error("unable to load environment; did you 'zrok enable'?", nil)
}
zrok, err := zrd.Client()
if err != nil {
tui.Error("unable to create zrok client", err)
}
auth := httptransport.APIKeyAuth("X-TOKEN", "header", zrd.Env.Token)
req := share.NewAccessParams()
req.Body = &rest_model_zrok.AccessRequest{
ShrToken: args[0],
EnvZID: zrd.Env.ZId,
}
accessResp, err := zrok.Share.Access(req, auth)
if err != nil {
if !panicInstead {
tui.Error("unable to access", err)
}
panic(err)
}
logrus.Infof("allocated frontend '%v'", accessResp.Payload.FrontendToken)
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
cmd.destroy(accessResp.Payload.FrontendToken, zrd.Env.ZId, args[0], zrok, auth)
os.Exit(0)
}()
fe, err := tcpTunnel.NewFrontend(&tcpTunnel.FrontendConfig{
BindAddress: cmd.bindAddress,
IdentityName: "backend",
ShrToken: args[0],
})
if err != nil {
panic(err)
}
if err := fe.Run(); err != nil {
panic(err)
}
for {
time.Sleep(30 * 24 * time.Hour)
}
}
func (cmd *accessPrivateTunnelCommand) destroy(frontendName, envZId, shrToken string, zrok *rest_client_zrok.Zrok, auth runtime.ClientAuthInfoWriter) {
logrus.Debugf("shutting down '%v'", shrToken)
req := share.NewUnaccessParams()
req.Body = &rest_model_zrok.UnaccessRequest{
FrontendToken: frontendName,
ShrToken: shrToken,
EnvZID: envZId,
}
if _, err := zrok.Share.Unaccess(req, auth); err == nil {
logrus.Debugf("shutdown complete")
} else {
logrus.Errorf("error shutting down: %v", err)
}
}

View File

@ -43,7 +43,7 @@ func newSharePrivateCommand() *sharePrivateCommand {
} }
command := &sharePrivateCommand{cmd: cmd} command := &sharePrivateCommand{cmd: cmd}
cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...") cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...")
cmd.Flags().StringVar(&command.backendMode, "backend-mode", "proxy", "The backend mode {proxy, web, tunnel}") cmd.Flags().StringVar(&command.backendMode, "backend-mode", "proxy", "The backend mode {proxy, web, tcpTunnel}")
cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless") cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless")
cmd.Flags().BoolVar(&command.insecure, "insecure", false, "Enable insecure TLS certificate validation for <target>") cmd.Flags().BoolVar(&command.insecure, "insecure", false, "Enable insecure TLS certificate validation for <target>")
cmd.Run = command.run cmd.Run = command.run
@ -67,11 +67,11 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
case "web": case "web":
target = args[0] target = args[0]
case "tunnel": case "tcpTunnel":
target = args[0] target = args[0]
default: default:
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tunnel}", cmd.backendMode), nil) tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel}", cmd.backendMode), nil)
} }
zrd, err := zrokdir.Load() zrd, err := zrokdir.Load()
@ -172,7 +172,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
panic(err) panic(err)
} }
case "tunnel": case "tcpTunnel":
cfg := &tcpTunnel.BackendConfig{ cfg := &tcpTunnel.BackendConfig{
IdentityPath: zif, IdentityPath: zif,
EndpointAddress: target, EndpointAddress: target,
@ -182,13 +182,13 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
be, err := tcpTunnel.NewBackend(cfg) be, err := tcpTunnel.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { if !panicInstead {
tui.Error("unable to create tunnel backend", err) tui.Error("unable to create tcpTunnel backend", err)
} }
panic(err) panic(err)
} }
go func() { go func() {
if err := be.Run(); err != nil { if err := be.Run(); err != nil {
logrus.Errorf("error running tunnel backend: %v", err) logrus.Errorf("error running tcpTunnel backend: %v", err)
} }
}() }()

View File

@ -86,5 +86,8 @@ func (h *accessHandler) Handle(params share.AccessParams, principal *rest_model_
return share.NewAccessInternalServerError() return share.NewAccessInternalServerError()
} }
return share.NewAccessCreated().WithPayload(&rest_model_zrok.AccessResponse{FrontendToken: feToken}) return share.NewAccessCreated().WithPayload(&rest_model_zrok.AccessResponse{
FrontendToken: feToken,
BackendMode: shr.BackendMode,
})
} }

View File

@ -1,3 +1,4 @@
-- +migrate Up -- +migrate Up
alter type backend_mode rename value 'dav' to 'tunnel'; alter type backend_mode rename value 'dav' to 'tcpTunnel';
alter type backend_mode add value 'udpTunnel';

View File

@ -18,7 +18,7 @@ create table shares (
constraint chk_z_id check (z_id <> ''), constraint chk_z_id check (z_id <> ''),
constraint chk_token check (token <> ''), constraint chk_token check (token <> ''),
constraint chk_share_mode check (share_mode == 'public' or share_mode == 'private'), constraint chk_share_mode check (share_mode == 'public' or share_mode == 'private'),
constraint chk_backend_mode check (backend_mode == 'proxy' or backend_mode == 'web' or backend_mode == 'tunnel') constraint chk_backend_mode check (backend_mode == 'proxy' or backend_mode == 'web' or backend_mode == 'tcpTunnel' or backend_mode == 'udpTunnel')
); );
insert into shares select * from shares_old; insert into shares select * from shares_old;
drop table shares_old; drop table shares_old;

View File

@ -62,12 +62,14 @@ func (b *Backend) handle(conn net.Conn) {
if rConn, err := net.DialTCP("tcp", nil, rAddr); err == nil { if rConn, err := net.DialTCP("tcp", nil, rAddr); err == nil {
go endpoints.TXer(conn, rConn) go endpoints.TXer(conn, rConn)
go endpoints.TXer(rConn, conn) go endpoints.TXer(rConn, conn)
if b.cfg.RequestsChan != nil {
b.cfg.RequestsChan <- &endpoints.Request{ b.cfg.RequestsChan <- &endpoints.Request{
Stamp: time.Now(), Stamp: time.Now(),
RemoteAddr: conn.RemoteAddr().String(), RemoteAddr: conn.RemoteAddr().String(),
Method: "OPEN", Method: "ACCEPT",
Path: rAddr.String(), Path: rAddr.String(),
} }
}
} else { } else {
logrus.Errorf("error dialing '%v': %v", b.cfg.EndpointAddress, err) logrus.Errorf("error dialing '%v': %v", b.cfg.EndpointAddress, err)
_ = conn.Close() _ = conn.Close()

View File

@ -9,12 +9,14 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"net" "net"
"time"
) )
type FrontendConfig struct { type FrontendConfig struct {
BindAddress string BindAddress string
IdentityName string IdentityName string
ShrToken string ShrToken string
RequestsChan chan *endpoints.Request
} }
type Frontend struct { type Frontend struct {
@ -53,7 +55,7 @@ func (f *Frontend) Run() error {
for { for {
if conn, err := l.Accept(); err == nil { if conn, err := l.Accept(); err == nil {
go f.accept(conn) go f.accept(conn)
logrus.Infof("accepted tcp connection from '%v'", conn.RemoteAddr()) logrus.Debugf("accepted tcp connection from '%v'", conn.RemoteAddr())
} else { } else {
return err return err
} }
@ -64,7 +66,14 @@ func (f *Frontend) accept(conn net.Conn) {
if zConn, err := f.zCtx.Dial(f.cfg.ShrToken); err == nil { if zConn, err := f.zCtx.Dial(f.cfg.ShrToken); err == nil {
go endpoints.TXer(conn, zConn) go endpoints.TXer(conn, zConn)
go endpoints.TXer(zConn, conn) go endpoints.TXer(zConn, conn)
logrus.Infof("accepted '%v' <=> '%v'", conn.RemoteAddr(), zConn.RemoteAddr()) if f.cfg.RequestsChan != nil {
f.cfg.RequestsChan <- &endpoints.Request{
Stamp: time.Now(),
RemoteAddr: conn.RemoteAddr().String(),
Method: "ACCEPT",
Path: f.cfg.ShrToken,
}
}
} else { } else {
logrus.Errorf("error dialing '%v': %v", f.cfg.ShrToken, err) logrus.Errorf("error dialing '%v': %v", f.cfg.ShrToken, err)
_ = conn.Close() _ = conn.Close()

View File

@ -17,6 +17,9 @@ import (
// swagger:model accessResponse // swagger:model accessResponse
type AccessResponse struct { type AccessResponse struct {
// backend mode
BackendMode string `json:"backendMode,omitempty"`
// frontend token // frontend token
FrontendToken string `json:"frontendToken,omitempty"` FrontendToken string `json:"frontendToken,omitempty"`
} }

View File

@ -28,7 +28,7 @@ type ShareRequest struct {
AuthUsers []*AuthUser `json:"authUsers"` AuthUsers []*AuthUser `json:"authUsers"`
// backend mode // backend mode
// Enum: [proxy web tunnel] // Enum: [proxy web tcpTunnel udpTunnel]
BackendMode string `json:"backendMode,omitempty"` BackendMode string `json:"backendMode,omitempty"`
// backend proxy endpoint // backend proxy endpoint
@ -100,7 +100,7 @@ var shareRequestTypeBackendModePropEnum []interface{}
func init() { func init() {
var res []string var res []string
if err := json.Unmarshal([]byte(`["proxy","web","tunnel"]`), &res); err != nil { if err := json.Unmarshal([]byte(`["proxy","web","tcpTunnel","udpTunnel"]`), &res); err != nil {
panic(err) panic(err)
} }
for _, v := range res { for _, v := range res {
@ -116,8 +116,11 @@ const (
// ShareRequestBackendModeWeb captures enum value "web" // ShareRequestBackendModeWeb captures enum value "web"
ShareRequestBackendModeWeb string = "web" ShareRequestBackendModeWeb string = "web"
// ShareRequestBackendModeTunnel captures enum value "tunnel" // ShareRequestBackendModeTCPTunnel captures enum value "tcpTunnel"
ShareRequestBackendModeTunnel string = "tunnel" ShareRequestBackendModeTCPTunnel string = "tcpTunnel"
// ShareRequestBackendModeUDPTunnel captures enum value "udpTunnel"
ShareRequestBackendModeUDPTunnel string = "udpTunnel"
) )
// prop value enum // prop value enum

View File

@ -852,6 +852,9 @@ func init() {
"accessResponse": { "accessResponse": {
"type": "object", "type": "object",
"properties": { "properties": {
"backendMode": {
"type": "string"
},
"frontendToken": { "frontendToken": {
"type": "string" "type": "string"
} }
@ -1167,7 +1170,8 @@ func init() {
"enum": [ "enum": [
"proxy", "proxy",
"web", "web",
"tunnel" "tcpTunnel",
"udpTunnel"
] ]
}, },
"backendProxyEndpoint": { "backendProxyEndpoint": {
@ -2130,6 +2134,9 @@ func init() {
"accessResponse": { "accessResponse": {
"type": "object", "type": "object",
"properties": { "properties": {
"backendMode": {
"type": "string"
},
"frontendToken": { "frontendToken": {
"type": "string" "type": "string"
} }
@ -2445,7 +2452,8 @@ func init() {
"enum": [ "enum": [
"proxy", "proxy",
"web", "web",
"tunnel" "tcpTunnel",
"udpTunnel"
] ]
}, },
"backendProxyEndpoint": { "backendProxyEndpoint": {

View File

@ -537,6 +537,8 @@ definitions:
properties: properties:
frontendToken: frontendToken:
type: string type: string
backendMode:
type: string
authUser: authUser:
type: object type: object
@ -771,7 +773,7 @@ definitions:
type: string type: string
backendMode: backendMode:
type: string type: string
enum: ["proxy", "web", "tunnel"] enum: ["proxy", "web", "tcpTunnel", "udpTunnel"]
backendProxyEndpoint: backendProxyEndpoint:
type: string type: string
authScheme: authScheme:

View File

@ -14,6 +14,7 @@
* @memberof module:types * @memberof module:types
* *
* @property {string} frontendToken * @property {string} frontendToken
* @property {string} backendMode
*/ */
/** /**