mirror of
https://github.com/openziti/zrok.git
synced 2025-06-24 11:41:25 +02:00
Merge pull request #562 from openziti/backend_mode_socks
SOCKS Backend Mode (#558)
This commit is contained in:
commit
7a5bdb54e2
@ -1,5 +1,38 @@
|
|||||||
# ACKNOWLEDGEMENTS
|
# ACKNOWLEDGEMENTS
|
||||||
|
|
||||||
|
## github.com/openziti/zrok/endpoints/socks
|
||||||
|
|
||||||
|
Portions of the `socks` package is based on code from `https://github.com/tailscale/tailscale/blob/v1.58.2/net/socks5/socks5.go`, which included the following license:
|
||||||
|
|
||||||
|
> BSD 3-Clause License
|
||||||
|
>
|
||||||
|
> Copyright (c) 2020 Tailscale Inc & AUTHORS.
|
||||||
|
>
|
||||||
|
> Redistribution and use in source and binary forms, with or without
|
||||||
|
> modification, are permitted provided that the following conditions are met:
|
||||||
|
>
|
||||||
|
> 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
> list of conditions and the following disclaimer.
|
||||||
|
>
|
||||||
|
> 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
> this list of conditions and the following disclaimer in the documentation
|
||||||
|
> and/or other materials provided with the distribution.
|
||||||
|
>
|
||||||
|
> 3. Neither the name of the copyright holder nor the names of its
|
||||||
|
> contributors may be used to endorse or promote products derived from
|
||||||
|
> this software without specific prior written permission.
|
||||||
|
>
|
||||||
|
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
> AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
> DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
> FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
> DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
> SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
> OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
> OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
## github.com/openziti/zrok/drives/davServer
|
## github.com/openziti/zrok/drives/davServer
|
||||||
|
|
||||||
The `davServer` package is based on code from `https://cs.opensource.google/go/go/`, which included the following license:
|
The `davServer` package is based on code from `https://cs.opensource.google/go/go/`, which included the following license:
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
## v0.4.24
|
## v0.4.24
|
||||||
|
|
||||||
|
FEATURE: New `socks` backend mode for use with private sharing. Use `zrok share private --backend-mode socks` and then `zrok access private` that share from somewhere else... very lightweight VPN-like functionality (https://github.com/openziti/zrok/issues/558)
|
||||||
|
|
||||||
FEATURE: New `zrok admin create account` command that allows populating accounts directly into the underlying controller database (https://github.com/openziti/zrok/issues/551)
|
FEATURE: New `zrok admin create account` command that allows populating accounts directly into the underlying controller database (https://github.com/openziti/zrok/issues/551)
|
||||||
|
|
||||||
CHANGE: The `zrok test loopback public` utility to report non-`200` errors and also ensure that the listening side of the test is fully established before starting loopback testing.
|
CHANGE: The `zrok test loopback public` utility to report non-`200` errors and also ensure that the listening side of the test is fully established before starting loopback testing.
|
||||||
|
@ -143,6 +143,28 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
case "socks":
|
||||||
|
fe, err := tcpTunnel.NewFrontend(&tcpTunnel.FrontendConfig{
|
||||||
|
BindAddress: cmd.bindAddress,
|
||||||
|
IdentityName: env.EnvironmentIdentityName(),
|
||||||
|
ShrToken: args[0],
|
||||||
|
RequestsChan: requests,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
if !panicInstead {
|
||||||
|
tui.Error("unable to create private access", err)
|
||||||
|
}
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
if err := fe.Run(); err != nil {
|
||||||
|
if !panicInstead {
|
||||||
|
tui.Error("error starting access", err)
|
||||||
|
}
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
cfg := proxy.DefaultFrontendConfig(env.EnvironmentIdentityName())
|
cfg := proxy.DefaultFrontendConfig(env.EnvironmentIdentityName())
|
||||||
cfg.ShrToken = shrToken
|
cfg.ShrToken = shrToken
|
||||||
|
@ -31,14 +31,14 @@ type reserveCommand struct {
|
|||||||
|
|
||||||
func newReserveCommand() *reserveCommand {
|
func newReserveCommand() *reserveCommand {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "reserve <public|private> <target>",
|
Use: "reserve <public|private> [<target>]",
|
||||||
Short: "Create a reserved share",
|
Short: "Create a reserved share",
|
||||||
Args: cobra.ExactArgs(2),
|
Args: cobra.RangeArgs(1, 2),
|
||||||
}
|
}
|
||||||
command := &reserveCommand{cmd: cmd}
|
command := &reserveCommand{cmd: cmd}
|
||||||
cmd.Flags().StringVarP(&command.uniqueName, "unique-name", "n", "", "A unique name for the reserved share (defaults to generated identifier)")
|
cmd.Flags().StringVarP(&command.uniqueName, "unique-name", "n", "", "A unique name for the reserved share (defaults to generated identifier)")
|
||||||
cmd.Flags().StringArrayVar(&command.frontendSelection, "frontends", []string{"public"}, "Selected frontends to use for the share")
|
cmd.Flags().StringArrayVar(&command.frontendSelection, "frontends", []string{"public"}, "Selected frontends to use for the share")
|
||||||
cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode (public|private: proxy, web, caddy, drive) (private: tcpTunnel, udpTunnel)")
|
cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode (public|private: proxy, web, caddy, drive) (private: tcpTunnel, udpTunnel, socks)")
|
||||||
cmd.Flags().BoolVarP(&command.jsonOutput, "json-output", "j", false, "Emit JSON describing the created reserved share")
|
cmd.Flags().BoolVarP(&command.jsonOutput, "json-output", "j", false, "Emit JSON describing the created reserved share")
|
||||||
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.oauthProvider, "oauth-provider", "", "Enable OAuth provider [google, github]")
|
cmd.Flags().StringVar(&command.oauthProvider, "oauth-provider", "", "Enable OAuth provider [google, github]")
|
||||||
@ -52,7 +52,7 @@ func newReserveCommand() *reserveCommand {
|
|||||||
|
|
||||||
func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
|
func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
|
||||||
shareMode := sdk.ShareMode(args[0])
|
shareMode := sdk.ShareMode(args[0])
|
||||||
privateOnlyModes := []string{"tcpTunnel", "udpTunnel"}
|
privateOnlyModes := []string{"tcpTunnel", "udpTunnel", "socks"}
|
||||||
if shareMode != sdk.PublicShareMode && shareMode != sdk.PrivateShareMode {
|
if shareMode != sdk.PublicShareMode && shareMode != sdk.PrivateShareMode {
|
||||||
tui.Error("invalid sharing mode; expecting 'public' or 'private'", nil)
|
tui.Error("invalid sharing mode; expecting 'public' or 'private'", nil)
|
||||||
} else if shareMode == sdk.PublicShareMode && slices.Contains(privateOnlyModes, cmd.backendMode) {
|
} else if shareMode == sdk.PublicShareMode && slices.Contains(privateOnlyModes, cmd.backendMode) {
|
||||||
@ -66,6 +66,9 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
|
|||||||
var target string
|
var target string
|
||||||
switch cmd.backendMode {
|
switch cmd.backendMode {
|
||||||
case "proxy":
|
case "proxy":
|
||||||
|
if len(args) != 2 {
|
||||||
|
tui.Error("the 'proxy' backend mode expects a <target>", nil)
|
||||||
|
}
|
||||||
v, err := parseUrl(args[1])
|
v, err := parseUrl(args[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tui.Error("invalid target endpoint URL", err)
|
tui.Error("invalid target endpoint URL", err)
|
||||||
@ -73,22 +76,42 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
|
|||||||
target = v
|
target = v
|
||||||
|
|
||||||
case "web":
|
case "web":
|
||||||
|
if len(args) != 2 {
|
||||||
|
tui.Error("the 'web' backend mode expects a <target>", nil)
|
||||||
|
}
|
||||||
target = args[1]
|
target = args[1]
|
||||||
|
|
||||||
case "tcpTunnel":
|
case "tcpTunnel":
|
||||||
|
if len(args) != 2 {
|
||||||
|
tui.Error("the 'tcpTunnel' backend mode expects a <target>", nil)
|
||||||
|
}
|
||||||
target = args[1]
|
target = args[1]
|
||||||
|
|
||||||
case "udpTunnel":
|
case "udpTunnel":
|
||||||
|
if len(args) != 2 {
|
||||||
|
tui.Error("the 'udpTunnel' backend mode expects a <target>", nil)
|
||||||
|
}
|
||||||
target = args[1]
|
target = args[1]
|
||||||
|
|
||||||
case "caddy":
|
case "caddy":
|
||||||
|
if len(args) != 2 {
|
||||||
|
tui.Error("the 'caddy' backend mode expects a <target>", nil)
|
||||||
|
}
|
||||||
target = args[1]
|
target = args[1]
|
||||||
|
|
||||||
case "drive":
|
case "drive":
|
||||||
|
if len(args) != 2 {
|
||||||
|
tui.Error("the 'drive' backend mode expects a <target>", nil)
|
||||||
|
}
|
||||||
target = args[1]
|
target = args[1]
|
||||||
|
|
||||||
|
case "socks":
|
||||||
|
if len(args) != 1 {
|
||||||
|
tui.Error("the 'socks' backend mode does not expect <target>", nil)
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel, udpTunnel, caddy, drive}", cmd.backendMode), nil)
|
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel, udpTunnel, caddy, drive, socks}", cmd.backendMode), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
env, err := environment.LoadRoot()
|
env, err := environment.LoadRoot()
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/openziti/zrok/endpoints"
|
"github.com/openziti/zrok/endpoints"
|
||||||
"github.com/openziti/zrok/endpoints/drive"
|
"github.com/openziti/zrok/endpoints/drive"
|
||||||
"github.com/openziti/zrok/endpoints/proxy"
|
"github.com/openziti/zrok/endpoints/proxy"
|
||||||
|
"github.com/openziti/zrok/endpoints/socks"
|
||||||
"github.com/openziti/zrok/endpoints/tcpTunnel"
|
"github.com/openziti/zrok/endpoints/tcpTunnel"
|
||||||
"github.com/openziti/zrok/endpoints/udpTunnel"
|
"github.com/openziti/zrok/endpoints/udpTunnel"
|
||||||
"github.com/openziti/zrok/environment"
|
"github.com/openziti/zrok/environment"
|
||||||
@ -33,13 +34,13 @@ type sharePrivateCommand struct {
|
|||||||
|
|
||||||
func newSharePrivateCommand() *sharePrivateCommand {
|
func newSharePrivateCommand() *sharePrivateCommand {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "private <target>",
|
Use: "private [<target>]",
|
||||||
Short: "Share a target resource privately",
|
Short: "Share a target resource privately",
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.RangeArgs(0, 1),
|
||||||
}
|
}
|
||||||
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().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode {proxy, web, tcpTunnel, udpTunnel, caddy, drive}")
|
cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode {proxy, web, tcpTunnel, udpTunnel, caddy, drive, socks}")
|
||||||
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
|
||||||
@ -51,6 +52,9 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
|
|||||||
|
|
||||||
switch cmd.backendMode {
|
switch cmd.backendMode {
|
||||||
case "proxy":
|
case "proxy":
|
||||||
|
if len(args) != 1 {
|
||||||
|
tui.Error("the 'proxy' backend mode expects a <target>", nil)
|
||||||
|
}
|
||||||
v, err := parseUrl(args[0])
|
v, err := parseUrl(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !panicInstead {
|
if !panicInstead {
|
||||||
@ -61,21 +65,41 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
|
|||||||
target = v
|
target = v
|
||||||
|
|
||||||
case "web":
|
case "web":
|
||||||
|
if len(args) != 1 {
|
||||||
|
tui.Error("the 'web' backend mode expects a <target>", nil)
|
||||||
|
}
|
||||||
target = args[0]
|
target = args[0]
|
||||||
|
|
||||||
case "tcpTunnel":
|
case "tcpTunnel":
|
||||||
|
if len(args) != 1 {
|
||||||
|
tui.Error("the 'tcpTunnel' backend mode expects a <target>", nil)
|
||||||
|
}
|
||||||
target = args[0]
|
target = args[0]
|
||||||
|
|
||||||
case "udpTunnel":
|
case "udpTunnel":
|
||||||
|
if len(args) != 1 {
|
||||||
|
tui.Error("the 'udpTunnel' backend mode expects a <target>", nil)
|
||||||
|
}
|
||||||
target = args[0]
|
target = args[0]
|
||||||
|
|
||||||
case "caddy":
|
case "caddy":
|
||||||
|
if len(args) != 1 {
|
||||||
|
tui.Error("the 'caddy' backend mode expects a <target>", nil)
|
||||||
|
}
|
||||||
target = args[0]
|
target = args[0]
|
||||||
cmd.headless = true
|
cmd.headless = true
|
||||||
|
|
||||||
case "drive":
|
case "drive":
|
||||||
|
if len(args) != 1 {
|
||||||
|
tui.Error("the 'drive' backend mode expects a <target>", nil)
|
||||||
|
}
|
||||||
target = args[0]
|
target = args[0]
|
||||||
|
|
||||||
|
case "socks":
|
||||||
|
if len(args) != 0 {
|
||||||
|
tui.Error("the 'socks' backend mode does not expect <target>", nil)
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel, udpTunnel, caddy, drive}", cmd.backendMode), nil)
|
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel, udpTunnel, caddy, drive}", cmd.backendMode), nil)
|
||||||
}
|
}
|
||||||
@ -264,6 +288,27 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
case "socks":
|
||||||
|
cfg := &socks.BackendConfig{
|
||||||
|
IdentityPath: zif,
|
||||||
|
ShrToken: shr.Token,
|
||||||
|
Requests: requests,
|
||||||
|
}
|
||||||
|
|
||||||
|
be, err := socks.NewBackend(cfg)
|
||||||
|
if err != nil {
|
||||||
|
if !panicInstead {
|
||||||
|
tui.Error("error creating socks backend", err)
|
||||||
|
}
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := be.Run(); err != nil {
|
||||||
|
logrus.Errorf("error running socks backend: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
tui.Error("invalid backend mode", nil)
|
tui.Error("invalid backend mode", nil)
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/openziti/zrok/endpoints"
|
"github.com/openziti/zrok/endpoints"
|
||||||
"github.com/openziti/zrok/endpoints/drive"
|
"github.com/openziti/zrok/endpoints/drive"
|
||||||
"github.com/openziti/zrok/endpoints/proxy"
|
"github.com/openziti/zrok/endpoints/proxy"
|
||||||
|
"github.com/openziti/zrok/endpoints/socks"
|
||||||
"github.com/openziti/zrok/endpoints/tcpTunnel"
|
"github.com/openziti/zrok/endpoints/tcpTunnel"
|
||||||
"github.com/openziti/zrok/endpoints/udpTunnel"
|
"github.com/openziti/zrok/endpoints/udpTunnel"
|
||||||
"github.com/openziti/zrok/environment"
|
"github.com/openziti/zrok/environment"
|
||||||
@ -92,6 +93,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if resp.Payload.BackendMode != "socks" {
|
||||||
logrus.Infof("sharing target: '%v'", target)
|
logrus.Infof("sharing target: '%v'", target)
|
||||||
|
|
||||||
if resp.Payload.BackendProxyEndpoint != target {
|
if resp.Payload.BackendProxyEndpoint != target {
|
||||||
@ -110,6 +112,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
|
|||||||
} else {
|
} else {
|
||||||
logrus.Infof("using existing backend proxy endpoint: %v", target)
|
logrus.Infof("using existing backend proxy endpoint: %v", target)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var shareDescription string
|
var shareDescription string
|
||||||
switch resp.Payload.ShareMode {
|
switch resp.Payload.ShareMode {
|
||||||
@ -258,6 +261,27 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
case "socks":
|
||||||
|
cfg := &socks.BackendConfig{
|
||||||
|
IdentityPath: zif,
|
||||||
|
ShrToken: shrToken,
|
||||||
|
Requests: requests,
|
||||||
|
}
|
||||||
|
|
||||||
|
be, err := socks.NewBackend(cfg)
|
||||||
|
if err != nil {
|
||||||
|
if !panicInstead {
|
||||||
|
tui.Error("error creating socks backend", err)
|
||||||
|
}
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := be.Run(); err != nil {
|
||||||
|
logrus.Errorf("error running socks backend: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
tui.Error("invalid backend mode", nil)
|
tui.Error("invalid backend mode", nil)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
-- +migrate Up
|
||||||
|
|
||||||
|
alter type backend_mode add value 'socks';
|
@ -0,0 +1,58 @@
|
|||||||
|
-- +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,
|
||||||
|
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' or backend_mode == 'caddy' or backend_mode == 'drive' or backend_mode == 'socks')
|
||||||
|
);
|
||||||
|
insert into shares select * from shares_old;
|
||||||
|
drop index shares_token_idx;
|
||||||
|
create unique index shares_token_idx ON shares(token) WHERE deleted is false;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
drop table shares_old;
|
53
endpoints/socks/backend.go
Normal file
53
endpoints/socks/backend.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package socks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/openziti/sdk-golang/ziti"
|
||||||
|
"github.com/openziti/sdk-golang/ziti/edge"
|
||||||
|
"github.com/openziti/zrok/endpoints"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BackendConfig struct {
|
||||||
|
IdentityPath string
|
||||||
|
ShrToken string
|
||||||
|
Requests chan *endpoints.Request
|
||||||
|
}
|
||||||
|
|
||||||
|
type Backend struct {
|
||||||
|
cfg *BackendConfig
|
||||||
|
listener edge.Listener
|
||||||
|
server *Server
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBackend(cfg *BackendConfig) (*Backend, error) {
|
||||||
|
options := ziti.ListenOptions{
|
||||||
|
ConnectTimeout: 5 * time.Minute,
|
||||||
|
WaitForNEstablishedListeners: 1,
|
||||||
|
}
|
||||||
|
zcfg, err := ziti.NewConfigFromFile(cfg.IdentityPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "error loading ziti identity")
|
||||||
|
}
|
||||||
|
zctx, err := ziti.NewContext(zcfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "error loading ziti context")
|
||||||
|
}
|
||||||
|
listener, err := zctx.ListenWithOptions(cfg.ShrToken, &options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Backend{
|
||||||
|
cfg: cfg,
|
||||||
|
listener: listener,
|
||||||
|
server: &Server{Requests: cfg.Requests},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Backend) Run() error {
|
||||||
|
if err := b.server.Serve(b.listener); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
415
endpoints/socks/socks5.go
Executable file
415
endpoints/socks/socks5.go
Executable file
@ -0,0 +1,415 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
// Package socks5 is a SOCKS5 server implementation.
|
||||||
|
//
|
||||||
|
// This is used for userspace networking in Tailscale. Specifically,
|
||||||
|
// this is used for dialing out of the machine to other nodes, without
|
||||||
|
// the host kernel's involvement, so it doesn't proper routing tables,
|
||||||
|
// TUN, IPv6, etc. This package is meant to only handle the SOCKS5 protocol
|
||||||
|
// details and not any integration with Tailscale internals itself.
|
||||||
|
//
|
||||||
|
// The glue between this package and Tailscale is in net/socks5/tssocks.
|
||||||
|
package socks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"github.com/openziti/zrok/endpoints"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Authentication METHODs described in RFC 1928, section 3.
|
||||||
|
const (
|
||||||
|
noAuthRequired byte = 0
|
||||||
|
passwordAuth byte = 2
|
||||||
|
noAcceptableAuth byte = 255
|
||||||
|
)
|
||||||
|
|
||||||
|
// passwordAuthVersion is the auth version byte described in RFC 1929.
|
||||||
|
const passwordAuthVersion = 1
|
||||||
|
|
||||||
|
// socks5Version is the byte that represents the SOCKS version
|
||||||
|
// in requests.
|
||||||
|
const socks5Version byte = 5
|
||||||
|
|
||||||
|
// commandType are the bytes sent in SOCKS5 packets
|
||||||
|
// that represent the kind of connection the client needs.
|
||||||
|
type commandType byte
|
||||||
|
|
||||||
|
// The set of valid SOCKS5 commands as described in RFC 1928.
|
||||||
|
const (
|
||||||
|
connect commandType = 1
|
||||||
|
bind commandType = 2
|
||||||
|
udpAssociate commandType = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
// addrType are the bytes sent in SOCKS5 packets
|
||||||
|
// that represent particular address types.
|
||||||
|
type addrType byte
|
||||||
|
|
||||||
|
// The set of valid SOCKS5 address types as defined in RFC 1928.
|
||||||
|
const (
|
||||||
|
ipv4 addrType = 1
|
||||||
|
domainName addrType = 3
|
||||||
|
ipv6 addrType = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
// replyCode are the bytes sent in SOCKS5 packets
|
||||||
|
// that represent replies from the server to a client
|
||||||
|
// request.
|
||||||
|
type replyCode byte
|
||||||
|
|
||||||
|
// The set of valid SOCKS5 reply types as per the RFC 1928.
|
||||||
|
const (
|
||||||
|
success replyCode = 0
|
||||||
|
generalFailure replyCode = 1
|
||||||
|
connectionNotAllowed replyCode = 2
|
||||||
|
networkUnreachable replyCode = 3
|
||||||
|
hostUnreachable replyCode = 4
|
||||||
|
connectionRefused replyCode = 5
|
||||||
|
ttlExpired replyCode = 6
|
||||||
|
commandNotSupported replyCode = 7
|
||||||
|
addrTypeNotSupported replyCode = 8
|
||||||
|
)
|
||||||
|
|
||||||
|
// Server is a SOCKS5 proxy server.
|
||||||
|
type Server struct {
|
||||||
|
// Dialer optionally specifies the dialer to use for outgoing connections.
|
||||||
|
// If nil, the net package's standard dialer is used.
|
||||||
|
Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||||
|
|
||||||
|
// Username and Password, if set, are the credential clients must provide.
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
|
||||||
|
// For notifying user-facing components about activity
|
||||||
|
Requests chan *endpoints.Request
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) dial(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
dial := s.Dialer
|
||||||
|
if dial == nil {
|
||||||
|
dialer := &net.Dialer{}
|
||||||
|
dial = dialer.DialContext
|
||||||
|
}
|
||||||
|
return dial(ctx, network, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serve accepts and handles incoming connections on the given listener.
|
||||||
|
func (s *Server) Serve(l net.Listener) error {
|
||||||
|
defer l.Close()
|
||||||
|
for {
|
||||||
|
c, err := l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
defer c.Close()
|
||||||
|
conn := &Conn{clientConn: c, srv: s}
|
||||||
|
err := conn.Run()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Infof("client connection failed: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conn is a SOCKS5 connection for client to reach
|
||||||
|
// server.
|
||||||
|
type Conn struct {
|
||||||
|
// The struct is filled by each of the internal
|
||||||
|
// methods in turn as the transaction progresses.
|
||||||
|
|
||||||
|
srv *Server
|
||||||
|
clientConn net.Conn
|
||||||
|
request *request
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run starts the new connection.
|
||||||
|
func (c *Conn) Run() error {
|
||||||
|
needAuth := c.srv.Username != "" || c.srv.Password != ""
|
||||||
|
authMethod := noAuthRequired
|
||||||
|
if needAuth {
|
||||||
|
authMethod = passwordAuth
|
||||||
|
}
|
||||||
|
|
||||||
|
err := parseClientGreeting(c.clientConn, authMethod)
|
||||||
|
if err != nil {
|
||||||
|
c.clientConn.Write([]byte{socks5Version, noAcceptableAuth})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.clientConn.Write([]byte{socks5Version, authMethod})
|
||||||
|
if !needAuth {
|
||||||
|
return c.handleRequest()
|
||||||
|
}
|
||||||
|
|
||||||
|
user, pwd, err := parseClientAuth(c.clientConn)
|
||||||
|
if err != nil || user != c.srv.Username || pwd != c.srv.Password {
|
||||||
|
c.clientConn.Write([]byte{1, 1}) // auth error
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.clientConn.Write([]byte{1, 0}) // auth success
|
||||||
|
|
||||||
|
return c.handleRequest()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) handleRequest() error {
|
||||||
|
req, err := parseClientRequest(c.clientConn)
|
||||||
|
if err != nil {
|
||||||
|
res := &response{reply: generalFailure}
|
||||||
|
buf, _ := res.marshal()
|
||||||
|
c.clientConn.Write(buf)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if req.command != connect {
|
||||||
|
res := &response{reply: commandNotSupported}
|
||||||
|
buf, _ := res.marshal()
|
||||||
|
c.clientConn.Write(buf)
|
||||||
|
return fmt.Errorf("unsupported command %v", req.command)
|
||||||
|
}
|
||||||
|
c.request = req
|
||||||
|
|
||||||
|
if c.srv.Requests != nil {
|
||||||
|
c.srv.Requests <- &endpoints.Request{
|
||||||
|
Stamp: time.Now(),
|
||||||
|
Method: "CONNECT",
|
||||||
|
Path: fmt.Sprintf("%v:%d", c.request.destination, c.request.port),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
srv, err := c.srv.dial(
|
||||||
|
ctx,
|
||||||
|
"tcp",
|
||||||
|
net.JoinHostPort(c.request.destination, strconv.Itoa(int(c.request.port))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
res := &response{reply: generalFailure}
|
||||||
|
buf, _ := res.marshal()
|
||||||
|
c.clientConn.Write(buf)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer srv.Close()
|
||||||
|
serverAddr, serverPortStr, err := net.SplitHostPort(srv.LocalAddr().String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
serverPort, _ := strconv.Atoi(serverPortStr)
|
||||||
|
|
||||||
|
var bindAddrType addrType
|
||||||
|
if ip := net.ParseIP(serverAddr); ip != nil {
|
||||||
|
if ip.To4() != nil {
|
||||||
|
bindAddrType = ipv4
|
||||||
|
} else {
|
||||||
|
bindAddrType = ipv6
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bindAddrType = domainName
|
||||||
|
}
|
||||||
|
res := &response{
|
||||||
|
reply: success,
|
||||||
|
bindAddrType: bindAddrType,
|
||||||
|
bindAddr: serverAddr,
|
||||||
|
bindPort: uint16(serverPort),
|
||||||
|
}
|
||||||
|
buf, err := res.marshal()
|
||||||
|
if err != nil {
|
||||||
|
res = &response{reply: generalFailure}
|
||||||
|
buf, _ = res.marshal()
|
||||||
|
}
|
||||||
|
c.clientConn.Write(buf)
|
||||||
|
|
||||||
|
errc := make(chan error, 2)
|
||||||
|
go func() {
|
||||||
|
_, err := io.Copy(c.clientConn, srv)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("from backend to client: %w", err)
|
||||||
|
}
|
||||||
|
errc <- err
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
_, err := io.Copy(srv, c.clientConn)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("from client to backend: %w", err)
|
||||||
|
}
|
||||||
|
errc <- err
|
||||||
|
}()
|
||||||
|
return <-errc
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseClientGreeting parses a request initiation packet.
|
||||||
|
func parseClientGreeting(r io.Reader, authMethod byte) error {
|
||||||
|
var hdr [2]byte
|
||||||
|
_, err := io.ReadFull(r, hdr[:])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not read packet header")
|
||||||
|
}
|
||||||
|
if hdr[0] != socks5Version {
|
||||||
|
return fmt.Errorf("incompatible SOCKS version")
|
||||||
|
}
|
||||||
|
count := int(hdr[1])
|
||||||
|
methods := make([]byte, count)
|
||||||
|
_, err = io.ReadFull(r, methods)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not read methods")
|
||||||
|
}
|
||||||
|
for _, m := range methods {
|
||||||
|
if m == authMethod {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("no acceptable auth methods")
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseClientAuth(r io.Reader) (usr, pwd string, err error) {
|
||||||
|
var hdr [2]byte
|
||||||
|
if _, err := io.ReadFull(r, hdr[:]); err != nil {
|
||||||
|
return "", "", fmt.Errorf("could not read auth packet header")
|
||||||
|
}
|
||||||
|
if hdr[0] != passwordAuthVersion {
|
||||||
|
return "", "", fmt.Errorf("bad SOCKS auth version")
|
||||||
|
}
|
||||||
|
usrLen := int(hdr[1])
|
||||||
|
usrBytes := make([]byte, usrLen)
|
||||||
|
if _, err := io.ReadFull(r, usrBytes); err != nil {
|
||||||
|
return "", "", fmt.Errorf("could not read auth packet username")
|
||||||
|
}
|
||||||
|
var hdrPwd [1]byte
|
||||||
|
if _, err := io.ReadFull(r, hdrPwd[:]); err != nil {
|
||||||
|
return "", "", fmt.Errorf("could not read auth packet password length")
|
||||||
|
}
|
||||||
|
pwdLen := int(hdrPwd[0])
|
||||||
|
pwdBytes := make([]byte, pwdLen)
|
||||||
|
if _, err := io.ReadFull(r, pwdBytes); err != nil {
|
||||||
|
return "", "", fmt.Errorf("could not read auth packet password")
|
||||||
|
}
|
||||||
|
return string(usrBytes), string(pwdBytes), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// request represents data contained within a SOCKS5
|
||||||
|
// connection request packet.
|
||||||
|
type request struct {
|
||||||
|
command commandType
|
||||||
|
destination string
|
||||||
|
port uint16
|
||||||
|
destAddrType addrType
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseClientRequest converts raw packet bytes into a
|
||||||
|
// SOCKS5Request struct.
|
||||||
|
func parseClientRequest(r io.Reader) (*request, error) {
|
||||||
|
var hdr [4]byte
|
||||||
|
_, err := io.ReadFull(r, hdr[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not read packet header")
|
||||||
|
}
|
||||||
|
cmd := hdr[1]
|
||||||
|
destAddrType := addrType(hdr[3])
|
||||||
|
|
||||||
|
var destination string
|
||||||
|
var port uint16
|
||||||
|
|
||||||
|
if destAddrType == ipv4 {
|
||||||
|
var ip [4]byte
|
||||||
|
_, err = io.ReadFull(r, ip[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not read IPv4 address")
|
||||||
|
}
|
||||||
|
destination = net.IP(ip[:]).String()
|
||||||
|
} else if destAddrType == domainName {
|
||||||
|
var dstSizeByte [1]byte
|
||||||
|
_, err = io.ReadFull(r, dstSizeByte[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not read domain name size")
|
||||||
|
}
|
||||||
|
dstSize := int(dstSizeByte[0])
|
||||||
|
domainName := make([]byte, dstSize)
|
||||||
|
_, err = io.ReadFull(r, domainName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not read domain name")
|
||||||
|
}
|
||||||
|
destination = string(domainName)
|
||||||
|
} else if destAddrType == ipv6 {
|
||||||
|
var ip [16]byte
|
||||||
|
_, err = io.ReadFull(r, ip[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not read IPv6 address")
|
||||||
|
}
|
||||||
|
destination = net.IP(ip[:]).String()
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("unsupported address type")
|
||||||
|
}
|
||||||
|
var portBytes [2]byte
|
||||||
|
_, err = io.ReadFull(r, portBytes[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not read port")
|
||||||
|
}
|
||||||
|
port = binary.BigEndian.Uint16(portBytes[:])
|
||||||
|
|
||||||
|
return &request{
|
||||||
|
command: commandType(cmd),
|
||||||
|
destination: destination,
|
||||||
|
port: port,
|
||||||
|
destAddrType: destAddrType,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// response contains the contents of
|
||||||
|
// a response packet sent from the proxy
|
||||||
|
// to the client.
|
||||||
|
type response struct {
|
||||||
|
reply replyCode
|
||||||
|
bindAddrType addrType
|
||||||
|
bindAddr string
|
||||||
|
bindPort uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshal converts a SOCKS5Response struct into
|
||||||
|
// a packet. If res.reply == Success, it may throw an error on
|
||||||
|
// receiving an invalid bind address. Otherwise, it will not throw.
|
||||||
|
func (res *response) marshal() ([]byte, error) {
|
||||||
|
pkt := make([]byte, 4)
|
||||||
|
pkt[0] = socks5Version
|
||||||
|
pkt[1] = byte(res.reply)
|
||||||
|
pkt[2] = 0 // null reserved byte
|
||||||
|
pkt[3] = byte(res.bindAddrType)
|
||||||
|
|
||||||
|
if res.reply != success {
|
||||||
|
return pkt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var addr []byte
|
||||||
|
switch res.bindAddrType {
|
||||||
|
case ipv4:
|
||||||
|
addr = net.ParseIP(res.bindAddr).To4()
|
||||||
|
if addr == nil {
|
||||||
|
return nil, fmt.Errorf("invalid IPv4 address for binding")
|
||||||
|
}
|
||||||
|
case domainName:
|
||||||
|
if len(res.bindAddr) > 255 {
|
||||||
|
return nil, fmt.Errorf("invalid domain name for binding")
|
||||||
|
}
|
||||||
|
addr = make([]byte, 0, len(res.bindAddr)+1)
|
||||||
|
addr = append(addr, byte(len(res.bindAddr)))
|
||||||
|
addr = append(addr, []byte(res.bindAddr)...)
|
||||||
|
case ipv6:
|
||||||
|
addr = net.ParseIP(res.bindAddr).To16()
|
||||||
|
if addr == nil {
|
||||||
|
return nil, fmt.Errorf("invalid IPv6 address for binding")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported address type")
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt = append(pkt, addr...)
|
||||||
|
pkt = binary.BigEndian.AppendUint16(pkt, uint16(res.bindPort))
|
||||||
|
|
||||||
|
return pkt, nil
|
||||||
|
}
|
@ -28,7 +28,7 @@ type ShareRequest struct {
|
|||||||
AuthUsers []*AuthUser `json:"authUsers"`
|
AuthUsers []*AuthUser `json:"authUsers"`
|
||||||
|
|
||||||
// backend mode
|
// backend mode
|
||||||
// Enum: [proxy web tcpTunnel udpTunnel caddy drive]
|
// Enum: [proxy web tcpTunnel udpTunnel caddy drive socks]
|
||||||
BackendMode string `json:"backendMode,omitempty"`
|
BackendMode string `json:"backendMode,omitempty"`
|
||||||
|
|
||||||
// backend proxy endpoint
|
// backend proxy endpoint
|
||||||
@ -117,7 +117,7 @@ var shareRequestTypeBackendModePropEnum []interface{}
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
var res []string
|
var res []string
|
||||||
if err := json.Unmarshal([]byte(`["proxy","web","tcpTunnel","udpTunnel","caddy","drive"]`), &res); err != nil {
|
if err := json.Unmarshal([]byte(`["proxy","web","tcpTunnel","udpTunnel","caddy","drive","socks"]`), &res); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
for _, v := range res {
|
for _, v := range res {
|
||||||
@ -144,6 +144,9 @@ const (
|
|||||||
|
|
||||||
// ShareRequestBackendModeDrive captures enum value "drive"
|
// ShareRequestBackendModeDrive captures enum value "drive"
|
||||||
ShareRequestBackendModeDrive string = "drive"
|
ShareRequestBackendModeDrive string = "drive"
|
||||||
|
|
||||||
|
// ShareRequestBackendModeSocks captures enum value "socks"
|
||||||
|
ShareRequestBackendModeSocks string = "socks"
|
||||||
)
|
)
|
||||||
|
|
||||||
// prop value enum
|
// prop value enum
|
||||||
|
@ -1476,7 +1476,8 @@ func init() {
|
|||||||
"tcpTunnel",
|
"tcpTunnel",
|
||||||
"udpTunnel",
|
"udpTunnel",
|
||||||
"caddy",
|
"caddy",
|
||||||
"drive"
|
"drive",
|
||||||
|
"socks"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"backendProxyEndpoint": {
|
"backendProxyEndpoint": {
|
||||||
@ -3099,7 +3100,8 @@ func init() {
|
|||||||
"tcpTunnel",
|
"tcpTunnel",
|
||||||
"udpTunnel",
|
"udpTunnel",
|
||||||
"caddy",
|
"caddy",
|
||||||
"drive"
|
"drive",
|
||||||
|
"socks"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"backendProxyEndpoint": {
|
"backendProxyEndpoint": {
|
||||||
|
@ -184,7 +184,7 @@ class ShareRequest(object):
|
|||||||
:param backend_mode: The backend_mode of this ShareRequest. # noqa: E501
|
:param backend_mode: The backend_mode of this ShareRequest. # noqa: E501
|
||||||
:type: str
|
:type: str
|
||||||
"""
|
"""
|
||||||
allowed_values = ["proxy", "web", "tcpTunnel", "udpTunnel", "caddy", "drive"] # noqa: E501
|
allowed_values = ["proxy", "web", "tcpTunnel", "udpTunnel", "caddy", "drive", "socks"] # noqa: E501
|
||||||
if backend_mode not in allowed_values:
|
if backend_mode not in allowed_values:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Invalid value for `backend_mode` ({0}), must be one of {1}" # noqa: E501
|
"Invalid value for `backend_mode` ({0}), must be one of {1}" # noqa: E501
|
||||||
|
@ -973,7 +973,7 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
backendMode:
|
backendMode:
|
||||||
type: string
|
type: string
|
||||||
enum: ["proxy", "web", "tcpTunnel", "udpTunnel", "caddy", "drive"]
|
enum: ["proxy", "web", "tcpTunnel", "udpTunnel", "caddy", "drive", "socks"]
|
||||||
backendProxyEndpoint:
|
backendProxyEndpoint:
|
||||||
type: string
|
type: string
|
||||||
authScheme:
|
authScheme:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user