Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Can't use Unix Sockets in Quick Tunnel mode #1367

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions cmd/cloudflared/tunnel/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ var (
"overwrite-dns",
"help",
}
runQuickTunnel = RunQuickTunnel
)

func Flags() []cli.Flag {
Expand Down Expand Up @@ -313,9 +314,9 @@ func TunnelCommand(c *cli.Context) error {
// Run a quick tunnel
// A unauthenticated named tunnel hosted on <random>.<quick-tunnels-service>.com
// We don't support running proxy-dns and a quick tunnel at the same time as the same process
shouldRunQuickTunnel := c.IsSet("url") || c.IsSet(ingress.HelloWorldFlag)
shouldRunQuickTunnel := c.IsSet("url") || c.IsSet("unix-socket") || c.IsSet(ingress.HelloWorldFlag)
Copy link
Author

@rhyswilliamsza rhyswilliamsza Dec 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't done any side-effect analysis to check whether anyone could be relying on --unix-socket forcing a trapdoor to proxy-dns, but that seems unlikely so it should be okay.

if !c.IsSet("proxy-dns") && c.String("quick-service") != "" && shouldRunQuickTunnel {
return RunQuickTunnel(sc)
return runQuickTunnel(sc)
Comment on lines +317 to +319
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was hoping to avoid changes here as far as possible, but I'm happy to refactor this into a separate function if this is too hacky.

}

// If user provides a config, check to see if they meant to use `tunnel run` instead
Expand Down
76 changes: 76 additions & 0 deletions cmd/cloudflared/tunnel/cmd_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package tunnel

import (
"flag"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v2"
)

func TestHostnameFromURI(t *testing.T) {
Expand All @@ -15,3 +18,76 @@ func TestHostnameFromURI(t *testing.T) {
assert.Equal(t, "", hostnameFromURI("trash"))
assert.Equal(t, "", hostnameFromURI("https://awesomesauce.com"))
}

func TestShouldRunQuickTunnel(t *testing.T) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've scoped this specifically to quick tunnels, so it won't test falling through to other tunnel types.

tests := []struct {
name string
flags map[string]string
expectError bool
}{
{
name: "Quick tunnel with URL set",
flags: map[string]string{"url": "http://127.0.0.1:8080", "quick-service": "https://fakeapi.trycloudflare.com"},
expectError: false,
},
{
name: "Quick tunnel with unix-socket set",
flags: map[string]string{"unix-socket": "/tmp/socket", "quick-service": "https://fakeapi.trycloudflare.com"},
expectError: false,
},
{
name: "Quick tunnel with hello-world flag",
flags: map[string]string{"hello-world": "true", "quick-service": "https://fakeapi.trycloudflare.com"},
expectError: false,
},
{
name: "Quick tunnel with proxy-dns (invalid combo)",
flags: map[string]string{"url": "http://127.0.0.1:9090", "proxy-dns": "true", "quick-service": "https://fakeapi.trycloudflare.com"},
expectError: true,
},
{
name: "No quick-service set",
flags: map[string]string{"url": "http://127.0.0.1:9090"},
expectError: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Mock RunQuickTunnel Function
originalRunQuickTunnel := runQuickTunnel
defer func() { runQuickTunnel = originalRunQuickTunnel }()
mockCalled := false
runQuickTunnel = func(sc *subcommandContext) error {
mockCalled = true
return nil
}

// Mock App Context
app := &cli.App{}
set := flagSetFromMap(tt.flags)
context := cli.NewContext(app, set, nil)

// Call TunnelCommand
err := TunnelCommand(context)

// Validate
if tt.expectError {
assert.False(t, mockCalled)
require.Error(t, err)
} else {
assert.True(t, mockCalled)
require.NoError(t, err)
}
})
}
}

func flagSetFromMap(flags map[string]string) *flag.FlagSet {
set := flag.NewFlagSet("test", 0)
for key, value := range flags {
set.String(key, "", "")
set.Set(key, value)
}
return set
}