Merge pull request #309 from openziti/v0.4_backend_mode_tunnel

New `--backend-mode` support for TCP tunnels (and future UDP tunnels) (#170)
This commit is contained in:
Michael Quigley 2023-05-01 13:56:15 -04:00 committed by GitHub
commit c9d4c97de6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 463 additions and 125 deletions

View File

@ -1,5 +1,7 @@
# v0.4.0
FEATURE: New `tcpTunnel` backend mode allowing for private sharing of local TCP sockets with other `zrok` users (https://github.com/openziti/zrok/issues/170)
FEATURE: New metrics infrastructure based on OpenZiti usage events (https://github.com/openziti/zrok/issues/128). See the [v0.4 Metrics Guide](docs/guides/metrics-and-limits/configuring-metrics.md) for more information.
FEATURE: New limits implementation based on the new metrics infrastructure (https://github.com/openziti/zrok/issues/235). See the [v0.4 Limits Guide](docs/guides/metrics-and-limits/configuring-limits.md) for more information.
@ -56,7 +58,7 @@ CHANGE: Incorporate initial docker image build (https://github.com/openziti/zrok
CHANGE: Improve target URL parsing for `zrok share` when using `--backend-mode` proxy (https://github.com/openziti/zrok/issues/211)
New and improved URL handling for proxy backends:
9090 -> http://127.0.0.1:9090
localhost:9090 -> http://127.0.0.1:9090
https://localhost:9090 -> https://localhost:9090

View File

@ -5,7 +5,8 @@ import (
"github.com/go-openapi/runtime"
httptransport "github.com/go-openapi/runtime/client"
"github.com/openziti/zrok/endpoints"
"github.com/openziti/zrok/endpoints/privateFrontend"
"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/share"
"github.com/openziti/zrok/rest_model_zrok"
@ -19,6 +20,8 @@ import (
"syscall"
)
var accessPrivateCmd *accessPrivateCommand
func init() {
accessCmd.AddCommand(newAccessPrivateCommand().cmd)
}
@ -45,14 +48,6 @@ func newAccessPrivateCommand() *accessPrivateCommand {
func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
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()
if err != nil {
tui.Error("unable to load zrokdir", err)
@ -85,10 +80,62 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
}
logrus.Infof("allocated frontend '%v'", accessResp.Payload.FrontendToken)
cfg := privateFrontend.DefaultConfig("backend")
cfg.ShrToken = shrToken
cfg.Address = cmd.bindAddress
cfg.RequestsChan = make(chan *endpoints.Request, 1024)
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.ShrToken = shrToken
cfg.Address = cmd.bindAddress
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)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
@ -98,27 +145,11 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
os.Exit(0)
}()
frontend, err := privateFrontend.NewHTTP(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 {
logrus.Infof("access the zrok share at the followind endpoint: %v", endpointUrl.String())
for {
select {
case req := <-cfg.RequestsChan:
case req := <-requests:
logrus.Infof("%v -> %v %v", req.RemoteAddr, req.Method, req.Path)
}
}
@ -132,7 +163,7 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
go func() {
for {
select {
case req := <-cfg.RequestsChan:
case req := <-requests:
if req != nil {
prg.Send(req)
}
@ -144,17 +175,16 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
tui.Error("An error occurred", err)
}
close(cfg.RequestsChan)
close(requests)
cmd.destroy(accessResp.Payload.FrontendToken, zrd.Env.ZId, shrToken, zrok, auth)
}
}
func (cmd *accessPrivateCommand) destroy(frotendName, envZId, shrToken string, zrok *rest_client_zrok.Zrok, auth runtime.ClientAuthInfoWriter) {
func (cmd *accessPrivateCommand) 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: frotendName,
FrontendToken: frontendName,
ShrToken: shrToken,
EnvZID: envZId,
}

View File

@ -3,7 +3,7 @@ package main
import (
"fmt"
"github.com/michaelquigley/cf"
"github.com/openziti/zrok/endpoints/publicFrontend"
"github.com/openziti/zrok/endpoints/publicProxy"
"github.com/openziti/zrok/tui"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@ -33,7 +33,7 @@ func newAccessPublicCommand() *accessPublicCommand {
}
func (cmd *accessPublicCommand) run(_ *cobra.Command, args []string) {
cfg := publicFrontend.DefaultConfig()
cfg := publicProxy.DefaultConfig()
if len(args) == 1 {
if err := cfg.Load(args[0]); err != nil {
if !panicInstead {
@ -43,7 +43,7 @@ func (cmd *accessPublicCommand) run(_ *cobra.Command, args []string) {
}
}
logrus.Infof(cf.Dump(cfg, cf.DefaultOptions()))
frontend, err := publicFrontend.NewHTTP(cfg)
frontend, err := publicProxy.NewHTTP(cfg)
if err != nil {
if !panicInstead {
tui.Error("unable to create http frontend", err)

View File

@ -3,7 +3,7 @@ package main
import (
"fmt"
"github.com/michaelquigley/cf"
"github.com/openziti/zrok/endpoints/publicFrontend"
"github.com/openziti/zrok/endpoints/publicProxy"
"github.com/openziti/zrok/tui"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@ -29,7 +29,7 @@ func newAccessPublicValidateCommand() *accessPublicValidateCommand {
}
func (cmd *accessPublicValidateCommand) run(_ *cobra.Command, args []string) {
cfg := publicFrontend.DefaultConfig()
cfg := publicProxy.DefaultConfig()
if err := cfg.Load(args[0]); err != nil {
tui.Error(fmt.Sprintf("unable to load configuration '%v'", args[0]), err)
}

View File

@ -2,6 +2,9 @@ package main
import (
"github.com/michaelquigley/pfxlog"
"github.com/openziti/transport/v2"
"github.com/openziti/transport/v2/tcp"
"github.com/openziti/transport/v2/udp"
"github.com/openziti/zrok/tui"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@ -24,6 +27,8 @@ func init() {
rootCmd.AddCommand(configCmd)
rootCmd.AddCommand(shareCmd)
rootCmd.AddCommand(testCmd)
transport.AddAddressParser(tcp.AddressParser{})
transport.AddAddressParser(udp.AddressParser{})
}
var rootCmd = &cobra.Command{

View File

@ -6,8 +6,8 @@ import (
"github.com/go-openapi/runtime"
httptransport "github.com/go-openapi/runtime/client"
"github.com/openziti/zrok/endpoints"
"github.com/openziti/zrok/endpoints/proxyBackend"
"github.com/openziti/zrok/endpoints/webBackend"
"github.com/openziti/zrok/endpoints/proxy"
"github.com/openziti/zrok/endpoints/tcpTunnel"
"github.com/openziti/zrok/model"
"github.com/openziti/zrok/rest_client_zrok"
"github.com/openziti/zrok/rest_client_zrok/share"
@ -43,7 +43,7 @@ func newSharePrivateCommand() *sharePrivateCommand {
}
command := &sharePrivateCommand{cmd: cmd}
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}")
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.insecure, "insecure", false, "Enable insecure TLS certificate validation for <target>")
cmd.Run = command.run
@ -67,8 +67,11 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
case "web":
target = args[0]
case "tcpTunnel":
target = args[0]
default:
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web}", cmd.backendMode), nil)
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel}", cmd.backendMode), nil)
}
zrd, err := zrokdir.Load()
@ -139,7 +142,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
requestsChan := make(chan *endpoints.Request, 1024)
switch cmd.backendMode {
case "proxy":
cfg := &proxyBackend.Config{
cfg := &proxy.BackendConfig{
IdentityPath: zif,
EndpointAddress: target,
ShrToken: resp.Payload.ShrToken,
@ -155,7 +158,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
}
case "web":
cfg := &webBackend.Config{
cfg := &proxy.WebBackendConfig{
IdentityPath: zif,
WebRoot: target,
ShrToken: resp.Payload.ShrToken,
@ -169,6 +172,26 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
panic(err)
}
case "tcpTunnel":
cfg := &tcpTunnel.BackendConfig{
IdentityPath: zif,
EndpointAddress: target,
ShrToken: resp.Payload.ShrToken,
RequestsChan: requestsChan,
}
be, err := tcpTunnel.NewBackend(cfg)
if err != nil {
if !panicInstead {
tui.Error("unable to create tcpTunnel backend", err)
}
panic(err)
}
go func() {
if err := be.Run(); err != nil {
logrus.Errorf("error running tcpTunnel backend: %v", err)
}
}()
default:
tui.Error("invalid backend mode", nil)
}
@ -207,8 +230,8 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
}
}
func (cmd *sharePrivateCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpoints.RequestHandler, error) {
be, err := proxyBackend.NewBackend(cfg)
func (cmd *sharePrivateCommand) proxyBackendMode(cfg *proxy.BackendConfig) (endpoints.RequestHandler, error) {
be, err := proxy.NewBackend(cfg)
if err != nil {
return nil, errors.Wrap(err, "error creating http proxy backend")
}
@ -222,8 +245,8 @@ func (cmd *sharePrivateCommand) proxyBackendMode(cfg *proxyBackend.Config) (endp
return be, nil
}
func (cmd *sharePrivateCommand) webBackendMode(cfg *webBackend.Config) (endpoints.RequestHandler, error) {
be, err := webBackend.NewBackend(cfg)
func (cmd *sharePrivateCommand) webBackendMode(cfg *proxy.WebBackendConfig) (endpoints.RequestHandler, error) {
be, err := proxy.NewWebBackend(cfg)
if err != nil {
return nil, errors.Wrap(err, "error creating http web backend")
}

View File

@ -6,8 +6,7 @@ import (
"github.com/go-openapi/runtime"
httptransport "github.com/go-openapi/runtime/client"
"github.com/openziti/zrok/endpoints"
"github.com/openziti/zrok/endpoints/proxyBackend"
"github.com/openziti/zrok/endpoints/webBackend"
"github.com/openziti/zrok/endpoints/proxy"
"github.com/openziti/zrok/model"
"github.com/openziti/zrok/rest_client_zrok"
"github.com/openziti/zrok/rest_client_zrok/share"
@ -142,7 +141,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
requestsChan := make(chan *endpoints.Request, 1024)
switch cmd.backendMode {
case "proxy":
cfg := &proxyBackend.Config{
cfg := &proxy.BackendConfig{
IdentityPath: zif,
EndpointAddress: target,
ShrToken: resp.Payload.ShrToken,
@ -158,7 +157,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
}
case "web":
cfg := &webBackend.Config{
cfg := &proxy.WebBackendConfig{
IdentityPath: zif,
WebRoot: target,
ShrToken: resp.Payload.ShrToken,
@ -209,8 +208,8 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
}
}
func (cmd *sharePublicCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpoints.RequestHandler, error) {
be, err := proxyBackend.NewBackend(cfg)
func (cmd *sharePublicCommand) proxyBackendMode(cfg *proxy.BackendConfig) (endpoints.RequestHandler, error) {
be, err := proxy.NewBackend(cfg)
if err != nil {
return nil, errors.Wrap(err, "error creating http proxy backend")
}
@ -224,8 +223,8 @@ func (cmd *sharePublicCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpo
return be, nil
}
func (cmd *sharePublicCommand) webBackendMode(cfg *webBackend.Config) (endpoints.RequestHandler, error) {
be, err := webBackend.NewBackend(cfg)
func (cmd *sharePublicCommand) webBackendMode(cfg *proxy.WebBackendConfig) (endpoints.RequestHandler, error) {
be, err := proxy.NewWebBackend(cfg)
if err != nil {
return nil, errors.Wrap(err, "error creating http web backend")
}

View File

@ -5,8 +5,7 @@ import (
tea "github.com/charmbracelet/bubbletea"
httptransport "github.com/go-openapi/runtime/client"
"github.com/openziti/zrok/endpoints"
"github.com/openziti/zrok/endpoints/proxyBackend"
"github.com/openziti/zrok/endpoints/webBackend"
"github.com/openziti/zrok/endpoints/proxy"
"github.com/openziti/zrok/rest_client_zrok/metadata"
"github.com/openziti/zrok/rest_client_zrok/share"
"github.com/openziti/zrok/rest_model_zrok"
@ -108,7 +107,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
requestsChan := make(chan *endpoints.Request, 1024)
switch resp.Payload.BackendMode {
case "proxy":
cfg := &proxyBackend.Config{
cfg := &proxy.BackendConfig{
IdentityPath: zif,
EndpointAddress: target,
ShrToken: shrToken,
@ -124,7 +123,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
}
case "web":
cfg := &webBackend.Config{
cfg := &proxy.WebBackendConfig{
IdentityPath: zif,
WebRoot: target,
ShrToken: shrToken,
@ -187,8 +186,8 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
}
}
func (cmd *shareReservedCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpoints.RequestHandler, error) {
be, err := proxyBackend.NewBackend(cfg)
func (cmd *shareReservedCommand) proxyBackendMode(cfg *proxy.BackendConfig) (endpoints.RequestHandler, error) {
be, err := proxy.NewBackend(cfg)
if err != nil {
return nil, errors.Wrap(err, "error creating http proxy backend")
}
@ -202,8 +201,8 @@ func (cmd *shareReservedCommand) proxyBackendMode(cfg *proxyBackend.Config) (end
return be, nil
}
func (cmd *shareReservedCommand) webBackendMode(cfg *webBackend.Config) (endpoints.RequestHandler, error) {
be, err := webBackend.NewBackend(cfg)
func (cmd *shareReservedCommand) webBackendMode(cfg *proxy.WebBackendConfig) (endpoints.RequestHandler, error) {
be, err := proxy.NewWebBackend(cfg)
if err != nil {
return nil, errors.Wrap(err, "error creating http web backend")
}

View File

@ -86,5 +86,8 @@ func (h *accessHandler) Handle(params share.AccessParams, principal *rest_model_
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

@ -18,6 +18,8 @@ func newShareHandler() *shareHandler {
}
func (h *shareHandler) Handle(params share.ShareParams, principal *rest_model_zrok.Principal) middleware.Responder {
logrus.Info("handling")
trx, err := str.Begin()
if err != nil {
logrus.Errorf("error starting transaction: %v", err)
@ -93,6 +95,7 @@ func (h *shareHandler) Handle(params share.ShareParams, principal *rest_model_zr
}
case "private":
logrus.Info("doing private")
shrZId, frontendEndpoints, err = newPrivateResourceAllocator().allocate(envZId, shrToken, params, edge)
if err != nil {
logrus.Error(err)

View File

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

View File

@ -0,0 +1,54 @@
-- +migrate Up
alter table shares rename to shares_old;
create table shares (
id integer primary key,
environment_id integer constraint fk_environments_shares references environments on delete cascade,
z_id string not null unique,
token string not null unique,
share_mode string not null,
backend_mode string not null,
frontend_selection string,
frontend_endpoint string,
backend_proxy_endpoint string,
reserved boolean not null default(false),
created_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
updated_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')), deleted boolean not null default(false),
constraint chk_z_id check (z_id <> ''),
constraint chk_token check (token <> ''),
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 == 'tcpTunnel' or backend_mode == 'udpTunnel')
);
insert into shares select * from shares_old;
drop table shares_old;
alter table frontends rename to frontends_old;
create table frontends (
id integer primary key,
environment_id integer references environments(id),
token varchar(32) not null unique,
z_id varchar(32) not null,
public_name varchar(64) unique,
url_template varchar(1024),
reserved boolean not null default(false),
created_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
updated_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
deleted boolean not null default(false),
private_share_id integer references shares(id)
);
insert into frontends select * from frontends_old;
drop table frontends_old;
alter table share_limit_journal rename to share_limit_journal_old;
create table share_limit_journal (
id integer primary key,
share_id integer references shares(id),
rx_bytes bigint not null,
tx_bytes bigint not null,
action limit_action_type not null,
created_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
updated_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now'))
);
insert into share_limit_journal select * from share_limit_journal_old;
drop table share_limit_journal_old;

View File

@ -1,17 +0,0 @@
package privateFrontend
import "github.com/openziti/zrok/endpoints"
type Config struct {
IdentityName string
ShrToken string
Address string
RequestsChan chan *endpoints.Request
}
func DefaultConfig(identityName string) *Config {
return &Config{
IdentityName: identityName,
Address: "0.0.0.0:8080",
}
}

View File

@ -1,4 +1,4 @@
package proxyBackend
package proxy
import (
"crypto/tls"
@ -16,7 +16,7 @@ import (
"time"
)
type Config struct {
type BackendConfig struct {
IdentityPath string
EndpointAddress string
ShrToken string
@ -24,14 +24,14 @@ type Config struct {
RequestsChan chan *endpoints.Request
}
type backend struct {
cfg *Config
type Backend struct {
cfg *BackendConfig
requests func() int32
listener edge.Listener
handler http.Handler
}
func NewBackend(cfg *Config) (*backend, error) {
func NewBackend(cfg *BackendConfig) (*Backend, error) {
options := ziti.ListenOptions{
ConnectTimeout: 5 * time.Minute,
MaxConnections: 64,
@ -51,7 +51,7 @@ func NewBackend(cfg *Config) (*backend, error) {
}
handler := util.NewProxyHandler(proxy)
return &backend{
return &Backend{
cfg: cfg,
requests: handler.Requests,
listener: listener,
@ -59,18 +59,18 @@ func NewBackend(cfg *Config) (*backend, error) {
}, nil
}
func (self *backend) Run() error {
if err := http.Serve(self.listener, self.handler); err != nil {
func (b *Backend) Run() error {
if err := http.Serve(b.listener, b.handler); err != nil {
return err
}
return nil
}
func (self *backend) Requests() func() int32 {
return self.requests
func (b *Backend) Requests() func() int32 {
return b.requests
}
func newReverseProxy(cfg *Config) (*httputil.ReverseProxy, error) {
func newReverseProxy(cfg *BackendConfig) (*httputil.ReverseProxy, error) {
targetURL, err := url.Parse(cfg.EndpointAddress)
if err != nil {
return nil, err

View File

@ -1,4 +1,4 @@
package privateFrontend
package proxy
import (
"context"
@ -6,7 +6,7 @@ import (
"github.com/openziti/sdk-golang/ziti"
"github.com/openziti/sdk-golang/ziti/config"
"github.com/openziti/zrok/endpoints"
"github.com/openziti/zrok/endpoints/publicFrontend/notFoundUi"
"github.com/openziti/zrok/endpoints/publicProxy/notFoundUi"
"github.com/openziti/zrok/model"
"github.com/openziti/zrok/util"
"github.com/openziti/zrok/zrokdir"
@ -19,14 +19,28 @@ import (
"time"
)
type httpFrontend struct {
cfg *Config
type FrontendConfig struct {
IdentityName string
ShrToken string
Address string
RequestsChan chan *endpoints.Request
}
func DefaultFrontendConfig(identityName string) *FrontendConfig {
return &FrontendConfig{
IdentityName: identityName,
Address: "0.0.0.0:8080",
}
}
type Frontend struct {
cfg *FrontendConfig
zCtx ziti.Context
shrToken string
handler http.Handler
}
func NewHTTP(cfg *Config) (*httpFrontend, error) {
func NewFrontend(cfg *FrontendConfig) (*Frontend, error) {
zCfgPath, err := zrokdir.ZitiIdentityFile(cfg.IdentityName)
if err != nil {
return nil, errors.Wrapf(err, "error getting ziti identity '%v' from zrokdir", cfg.IdentityName)
@ -48,14 +62,14 @@ func NewHTTP(cfg *Config) (*httpFrontend, error) {
proxy.Transport = zTransport
handler := authHandler(cfg.ShrToken, util.NewProxyHandler(proxy), "zrok", cfg, zCtx)
return &httpFrontend{
return &Frontend{
cfg: cfg,
zCtx: zCtx,
handler: handler,
}, nil
}
func (h *httpFrontend) Run() error {
func (h *Frontend) Run() error {
return http.ListenAndServe(h.cfg.Address, h.handler)
}
@ -72,7 +86,7 @@ func (zdc *zitiDialContext) Dial(_ context.Context, _ string, addr string) (net.
return conn, nil
}
func newServiceProxy(cfg *Config, ctx ziti.Context) (*httputil.ReverseProxy, error) {
func newServiceProxy(cfg *FrontendConfig, ctx ziti.Context) (*httputil.ReverseProxy, error) {
proxy := serviceTargetProxy(cfg, ctx)
director := proxy.Director
proxy.Director = func(req *http.Request) {
@ -97,7 +111,7 @@ func newServiceProxy(cfg *Config, ctx ziti.Context) (*httputil.ReverseProxy, err
return proxy, nil
}
func serviceTargetProxy(cfg *Config, ctx ziti.Context) *httputil.ReverseProxy {
func serviceTargetProxy(cfg *FrontendConfig, ctx ziti.Context) *httputil.ReverseProxy {
director := func(req *http.Request) {
targetShrToken := cfg.ShrToken
if svc, found := endpoints.GetRefreshedService(targetShrToken, ctx); found {
@ -130,7 +144,7 @@ func serviceTargetProxy(cfg *Config, ctx ziti.Context) *httputil.ReverseProxy {
return &httputil.ReverseProxy{Director: director}
}
func authHandler(shrToken string, handler http.Handler, realm string, cfg *Config, ctx ziti.Context) http.HandlerFunc {
func authHandler(shrToken string, handler http.Handler, realm string, cfg *FrontendConfig, ctx ziti.Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if svc, found := endpoints.GetRefreshedService(shrToken, ctx); found {
if cfg, found := svc.Configs[model.ZrokProxyConfig]; found {

View File

@ -1,4 +1,4 @@
package webBackend
package proxy
import (
"fmt"
@ -11,20 +11,20 @@ import (
"time"
)
type Config struct {
type WebBackendConfig struct {
IdentityPath string
WebRoot string
ShrToken string
RequestsChan chan *endpoints.Request
}
type backend struct {
cfg *Config
type WebBackend struct {
cfg *WebBackendConfig
listener edge.Listener
handler http.Handler
}
func NewBackend(cfg *Config) (*backend, error) {
func NewWebBackend(cfg *WebBackendConfig) (*WebBackend, error) {
options := ziti.ListenOptions{
ConnectTimeout: 5 * time.Minute,
MaxConnections: 64,
@ -38,7 +38,7 @@ func NewBackend(cfg *Config) (*backend, error) {
return nil, errors.Wrap(err, "error listening")
}
be := &backend{
be := &WebBackend{
cfg: cfg,
listener: listener,
}
@ -50,14 +50,14 @@ func NewBackend(cfg *Config) (*backend, error) {
return be, nil
}
func (self *backend) Run() error {
func (self *WebBackend) Run() error {
if err := http.Serve(self.listener, self.handler); err != nil {
return err
}
return nil
}
func (self *backend) Requests() func() int32 {
func (self *WebBackend) Requests() func() int32 {
return func() int32 { return 0 }
}

View File

@ -1,4 +1,4 @@
package publicFrontend
package publicProxy
import (
"github.com/michaelquigley/cf"

View File

@ -1,4 +1,4 @@
package publicFrontend
package publicProxy
import (
"context"
@ -6,8 +6,8 @@ import (
"github.com/openziti/sdk-golang/ziti"
"github.com/openziti/sdk-golang/ziti/config"
"github.com/openziti/zrok/endpoints"
"github.com/openziti/zrok/endpoints/publicFrontend/healthUi"
"github.com/openziti/zrok/endpoints/publicFrontend/notFoundUi"
"github.com/openziti/zrok/endpoints/publicProxy/healthUi"
"github.com/openziti/zrok/endpoints/publicProxy/notFoundUi"
"github.com/openziti/zrok/model"
"github.com/openziti/zrok/util"
"github.com/openziti/zrok/zrokdir"

View File

@ -0,0 +1,81 @@
package tcpTunnel
import (
"github.com/openziti/sdk-golang/ziti"
"github.com/openziti/sdk-golang/ziti/config"
"github.com/openziti/sdk-golang/ziti/edge"
"github.com/openziti/zrok/endpoints"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"net"
"time"
)
type BackendConfig struct {
IdentityPath string
EndpointAddress string
ShrToken string
RequestsChan chan *endpoints.Request
}
type Backend struct {
cfg *BackendConfig
listener edge.Listener
}
func NewBackend(cfg *BackendConfig) (*Backend, error) {
options := ziti.ListenOptions{
ConnectTimeout: 5 * time.Minute,
MaxConnections: 64,
}
zcfg, err := config.NewFromFile(cfg.IdentityPath)
if err != nil {
return nil, errors.Wrap(err, "error loading config")
}
listener, err := ziti.NewContextWithConfig(zcfg).ListenWithOptions(cfg.ShrToken, &options)
if err != nil {
return nil, errors.Wrap(err, "error listening")
}
b := &Backend{
cfg: cfg,
listener: listener,
}
return b, nil
}
func (b *Backend) Run() error {
logrus.Info("started")
defer logrus.Info("exited")
for {
if conn, err := b.listener.Accept(); err == nil {
go b.handle(conn)
} else {
return err
}
}
}
func (b *Backend) handle(conn net.Conn) {
logrus.Debugf("handling '%v'", conn.RemoteAddr())
if rAddr, err := net.ResolveTCPAddr("tcp", b.cfg.EndpointAddress); err == nil {
if rConn, err := net.DialTCP("tcp", nil, rAddr); err == nil {
go endpoints.TXer(conn, rConn)
go endpoints.TXer(rConn, conn)
if b.cfg.RequestsChan != nil {
b.cfg.RequestsChan <- &endpoints.Request{
Stamp: time.Now(),
RemoteAddr: conn.RemoteAddr().String(),
Method: "ACCEPT",
Path: rAddr.String(),
}
}
} else {
logrus.Errorf("error dialing '%v': %v", b.cfg.EndpointAddress, err)
_ = conn.Close()
return
}
} else {
logrus.Errorf("error resolving '%v': %v", b.cfg.EndpointAddress, err)
}
}

View File

@ -0,0 +1,81 @@
package tcpTunnel
import (
"github.com/openziti/sdk-golang/ziti"
"github.com/openziti/sdk-golang/ziti/config"
"github.com/openziti/zrok/endpoints"
"github.com/openziti/zrok/model"
"github.com/openziti/zrok/zrokdir"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"net"
"time"
)
type FrontendConfig struct {
BindAddress string
IdentityName string
ShrToken string
RequestsChan chan *endpoints.Request
}
type Frontend struct {
cfg *FrontendConfig
zCtx ziti.Context
lAddr *net.TCPAddr
}
func NewFrontend(cfg *FrontendConfig) (*Frontend, error) {
lAddr, err := net.ResolveTCPAddr("tcp", cfg.BindAddress)
if err != nil {
return nil, errors.Wrapf(err, "error resolving tcp address '%v'", cfg.BindAddress)
}
zCfgPath, err := zrokdir.ZitiIdentityFile(cfg.IdentityName)
if err != nil {
return nil, errors.Wrapf(err, "error getting ziti identity '%v' from zrokdir", cfg.IdentityName)
}
zCfg, err := config.NewFromFile(zCfgPath)
if err != nil {
return nil, errors.Wrap(err, "error loading config")
}
zCfg.ConfigTypes = []string{model.ZrokProxyConfig}
zCtx := ziti.NewContextWithConfig(zCfg)
return &Frontend{
cfg: cfg,
zCtx: zCtx,
lAddr: lAddr,
}, nil
}
func (f *Frontend) Run() error {
l, err := net.ListenTCP("tcp", f.lAddr)
if err != nil {
return errors.Wrapf(err, "error listening at '%v'", f.lAddr)
}
for {
if conn, err := l.Accept(); err == nil {
go f.accept(conn)
logrus.Debugf("accepted tcp connection from '%v'", conn.RemoteAddr())
} else {
return err
}
}
}
func (f *Frontend) accept(conn net.Conn) {
if zConn, err := f.zCtx.Dial(f.cfg.ShrToken); err == nil {
go endpoints.TXer(conn, zConn)
go endpoints.TXer(zConn, conn)
if f.cfg.RequestsChan != nil {
f.cfg.RequestsChan <- &endpoints.Request{
Stamp: time.Now(),
RemoteAddr: conn.RemoteAddr().String(),
Method: "ACCEPT",
Path: f.cfg.ShrToken,
}
}
} else {
logrus.Errorf("error dialing '%v': %v", f.cfg.ShrToken, err)
_ = conn.Close()
}
}

40
endpoints/txer.go Normal file
View File

@ -0,0 +1,40 @@
package endpoints
import (
"github.com/sirupsen/logrus"
"io"
"net"
)
const bufSz = 10240
func TXer(from, to net.Conn) {
logrus.Debugf("started '%v' -> '%v'", from.RemoteAddr(), to.RemoteAddr())
defer logrus.Debugf("exited '%v' -> '%v'", from.RemoteAddr(), to.RemoteAddr())
buf := make([]byte, bufSz)
for {
if rxsz, err := from.Read(buf); err == nil {
if txsz, err := to.Write(buf[:rxsz]); err == nil {
if txsz != rxsz {
logrus.Errorf("short write '%v' -> '%v' (%d != %d)", from.RemoteAddr(), to.RemoteAddr(), txsz, rxsz)
_ = to.Close()
_ = from.Close()
return
}
} else {
logrus.Errorf("write error '%v' -> '%v': %v", from.RemoteAddr(), to.RemoteAddr(), err)
_ = to.Close()
_ = from.Close()
return
}
} else {
if err != io.EOF {
logrus.Errorf("read error '%v' -> '%v': %v", from.RemoteAddr(), to.RemoteAddr(), err)
}
_ = to.Close()
_ = from.Close()
return
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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