Skip to content

Commit

Permalink
Fix auth.go not finding the tsnet.Listener
Browse files Browse the repository at this point in the history
Signed-off-by: hello <[email protected]>
  • Loading branch information
beep-beep-beep-boop authored Jun 20, 2024
1 parent 4e8fde6 commit 082211a
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 1 deletion.
52 changes: 51 additions & 1 deletion auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ package tscaddy

import (
"fmt"
"net"
"net/http"
"reflect"
"strings"

"github.com/caddyserver/caddy/v2"
Expand Down Expand Up @@ -40,6 +42,54 @@ func (Auth) CaddyModule() caddy.ModuleInfo {
}
}

// findTsnetListener recursively searches ln for wrapped or embedded net.Listeners
// until it finds a tsnetListener or runs out.
// ok indicates if a tsnetListener was found.
//
// In the future consider alternative approach if Caddy supports unwrapping listeners.
// See discussion in https://github.com/tailscale/caddy-tailscale/pull/70
func findTsnetListener(ln net.Listener) (_ tsnetListener, ok bool) {
if ln == nil {
return nil, false
}

// if ln is a tsnetListener, return it.
if tsn, ok := ln.(tsnetListener); ok {
return tsn, true
}

// if ln is a wrappedListener, unwrap it.
if wl, ok := ln.(wrappedListener); ok {
return findTsnetListener(wl.Unwrap())
}

// if ln has an embedded net.Listener field, unwrap it.
s := reflect.ValueOf(ln)
if s.Kind() == reflect.Ptr {
s = s.Elem()
}
if s.Kind() != reflect.Struct {
return nil, false
}

innerLn := s.FieldByName("Listener")
if innerLn.IsZero() {
// no more child/embedded listeners left
return nil, false
}

// if the "Listener" field is a net.Listener, use it.
if wl, ok := innerLn.Interface().(net.Listener); ok {
return findTsnetListener(wl)
}
return nil, false
}

// wrappedListener is implemented by types that wrap net.Listeners.
type wrappedListener interface {
Unwrap() net.Listener
}

// client returns the tailscale LocalClient for the TailscaleAuth module.
// If the LocalClient has not already been configured, the provided request will be used to
// lookup the tailscale node that serviced the request, and get the associated LocalClient.
Expand All @@ -52,7 +102,7 @@ func (ta *Auth) client(r *http.Request) (*tailscale.LocalClient, error) {
// server.
server := r.Context().Value(caddyhttp.ServerCtxKey).(*caddyhttp.Server)
for _, listener := range server.Listeners() {
if tsl, ok := listener.(tsnetListener); ok {
if tsl, ok := findTsnetListener(listener); ok {
var err error
ta.localclient, err = tsl.Server().LocalClient()
if err != nil {
Expand Down
7 changes: 7 additions & 0 deletions module.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,13 @@ type tsnetServerListener struct {
net.Listener
}

func (t *tsnetServerListener) Unwrap() net.Listener {
if t == nil {
return nil
}
return t.Listener
}

func (t *tsnetServerListener) Close() error {
if err := t.Listener.Close(); err != nil {
return err
Expand Down

0 comments on commit 082211a

Please sign in to comment.