From 843d93cb636540784514ef4fd414b591b28ade67 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Sun, 5 Mar 2023 21:23:03 -0800 Subject: [PATCH] libtailscale: update tailscale_loopback This brings it inline with the tsnet change to support proxies. Signed-off-by: David Crawshaw --- python/src/main.cpp | 2 +- ruby/lib/tailscale.rb | 17 +++++++++-------- tailscale.c | 6 +++--- tailscale.go | 27 +++++++++++++++++---------- tailscale.h | 18 +++++++++++------- tsnetctest/tsnetctest.go | 10 ++++++---- 6 files changed, 47 insertions(+), 33 deletions(-) diff --git a/python/src/main.cpp b/python/src/main.cpp index 8899084..382287a 100644 --- a/python/src/main.cpp +++ b/python/src/main.cpp @@ -80,7 +80,7 @@ PYBIND11_MODULE(_tailscale, m) { )pbdoc"); - m.def("loopback_api", &TsnetLoopbackAPI, R"pbdoc( + m.def("loopback", &TsnetLoopback, R"pbdoc( )pbdoc"); diff --git a/ruby/lib/tailscale.rb b/ruby/lib/tailscale.rb index 3633e41..8e1aba8 100644 --- a/ruby/lib/tailscale.rb +++ b/ruby/lib/tailscale.rb @@ -39,7 +39,7 @@ class Tailscale attach_function :TsnetListenerClose, [:int], :int attach_function :TsnetAccept, [:int, :pointer], :int, blocking: true attach_function :TsnetErrmsg, [:int, :pointer, :size_t], :int - attach_function :TsnetLoopbackAPI, [:int, :pointer, :size_t, :pointer], :int + attach_function :TsnetLoopback, [:int, :pointer, :size_t, :pointer, :pointer], :int end class ClosedError < StandardError @@ -243,19 +243,20 @@ class Tailscale Listener.new self, listener.read_int end - # Start a LocalAPI listener on a loopback address, and returns the address - # and password credential string for the instance. - def loopback_api + # Start a listener on a loopback address, and returns the address + # and credentials for using it as LocalAPI or a proxy. + def loopback assert_open addrbuf = FFI::MemoryPointer.new(:char, 1024) - credbuf = FFI::MemoryPointer.new(:char, 33) - Error.check self, Libtailscale::TsnetLoopbackAPI(@t, addrbuf, addrbuf.size, credbuf) - [addrbuf.read_string, credbuf.read_string] + proxycredbuf = FFI::MemoryPointer.new(:char, 33) + localcredbuf = FFI::MemoryPointer.new(:char, 33) + Error.check self, Libtailscale::TsnetLoopback(@t, addrbuf, addrbuf.size, proxycredbuf, localcredbuf) + [addrbuf.read_string, proxycredbuf.read_string, localcredbuf.read_string] end # Start the local API and return a LocalAPIClient for interacting with it. def local_api_client - addr, cred = loopback_api + addr, _, cred = loopback LocalAPIClient.new(addr, cred) end diff --git a/tailscale.c b/tailscale.c index 091a80e..845b719 100644 --- a/tailscale.c +++ b/tailscale.c @@ -19,7 +19,7 @@ extern int TsnetSetLogFD(int sd, int fd); extern int TsnetListen(int sd, char* net, char* addr, int* listenerOut); extern int TsnetListenerClose(int ld); extern int TsnetAccept(int ld, int* connOut); -extern int TsnetLoopbackAPI(int sd, char* addrOut, size_t addrLen, char* credOut); +extern int TsnetLoopback(int sd, char* addrOut, size_t addrLen, char* proxyOut, char* localOut); tailscale tailscale_new() { return TsnetNewServer(); @@ -72,8 +72,8 @@ int tailscale_set_logfd(tailscale sd, int fd) { return TsnetSetLogFD(sd, fd); } -int tailscale_loopback_api(tailscale sd, char* addr_out, size_t addrlen, char cred_out[static 33]) { - return TsnetLoopbackAPI(sd, addr_out, addrlen, cred_out); +int tailscale_loopback(tailscale sd, char* addr_out, size_t addrlen, char proxy_cred_out[static 33], char local_api_cred_out[static 33]) { + return TsnetLoopback(sd, addr_out, addrlen, proxy_cred_out, local_api_cred_out); } int tailscale_errmsg(tailscale sd, char* buf, size_t buflen) { diff --git a/tailscale.go b/tailscale.go index f80af39..13d6e81 100644 --- a/tailscale.go +++ b/tailscale.go @@ -363,8 +363,8 @@ func TsnetSetLogFD(sd C.int, fd int) C.int { return 0 } -//export TsnetLoopbackAPI -func TsnetLoopbackAPI(sd C.int, addrOut *C.char, addrLen C.size_t, credOut *C.char) C.int { +//export TsnetLoopback +func TsnetLoopback(sd C.int, addrOut *C.char, addrLen C.size_t, proxyOut *C.char, localOut *C.char) C.int { // Panic here to ensure we always leave the out values NUL-terminated. if addrOut == nil { panic("loopback_api passed nil addr_out") @@ -374,18 +374,22 @@ func TsnetLoopbackAPI(sd C.int, addrOut *C.char, addrLen C.size_t, credOut *C.ch // Start out NUL-termianted to cover error conditions. *addrOut = '\x00' - *credOut = '\x00' + *localOut = '\x00' + *proxyOut = '\x00' s, err := getServer(sd) if err != nil { return s.recErr(err) } - addr, cred, err := s.s.LoopbackLocalAPI() + addr, proxyCred, localAPICred, err := s.s.Loopback() if err != nil { return s.recErr(err) } - if len(cred) != 32 { - return s.recErr(fmt.Errorf("libtailscale: len(cred)=%d, want 32", len(cred))) + if len(proxyCred) != 32 { + return s.recErr(fmt.Errorf("libtailscale: len(proxyCred)=%d, want 32", len(proxyCred))) + } + if len(localAPICred) != 32 { + return s.recErr(fmt.Errorf("libtailscale: len(localAPICred)=%d, want 32", len(localAPICred))) } if len(addr)+1 > int(addrLen) { return s.recErr(fmt.Errorf("libtailscale: loopback addr of %d bytes is too long for addrlen %d", len(addr), addrLen)) @@ -394,10 +398,13 @@ func TsnetLoopbackAPI(sd C.int, addrOut *C.char, addrLen C.size_t, credOut *C.ch n := copy(out, addr) out[n] = '\x00' - // credOut is non-nil and 33 bytes long because - // it's defined in C as char cred_out[static 33]. - out = unsafe.Slice((*byte)(unsafe.Pointer(credOut)), 33) - copy(out, cred) + // proxyOut and localOut are non-nil and 33 bytes long because + // they are defined in C as char cred_out[static 33]. + out = unsafe.Slice((*byte)(unsafe.Pointer(proxyOut)), 33) + copy(out, proxyCred) + out[32] = '\x00' + out = unsafe.Slice((*byte)(unsafe.Pointer(localOut)), 33) + copy(out, localAPICred) out[32] = '\x00' return 0 diff --git a/tailscale.h b/tailscale.h index 4b54d17..73618cc 100644 --- a/tailscale.h +++ b/tailscale.h @@ -118,17 +118,21 @@ extern int tailscale_listener_close(tailscale_listener listener); // -1 - call tailscale_errmsg for details extern int tailscale_accept(tailscale_listener listener, tailscale_conn* conn_out); -// tailscale_loopback_api starts a LocalAPI listener on a loopback address. +// tailscale_loopback starts a loopback address server. // -// To make http requests to the LocalAPI: -// 1. cred must be provided as the basic auth password -// 2. the header "Sec-Tailscale: localapi" must be set +// The server has multiple functions. // -// The NUL-terminated ip:port address of the LocalAPI is written to addr_out. -// The 32-byte basic auth password + NUL-terminator is written to cred_out. +// It can be used as a SOCKS5 proxy onto the tailnet. +// Authentication is required with the username "tsnet" and +// the value of proxy_cred used as the password. +// +// The HTTP server also serves out the "LocalAPI" on /localapi. +// As the LocalAPI is powerful, access to endpoints requires BOTH passing a +// "Sec-Tailscale: localapi" HTTP header and passing local_api_cred as +// the basic auth password. // // Returns zero on success or -1 on error, call tailscale_errmsg for details. -extern int tailscale_loopback_api(tailscale sd, char* addr_out, size_t addrlen, char cred_out[static 33]); +extern int tailscale_loopback(tailscale sd, char* addr_out, size_t addrlen, char proxy_cred_out[static 33], char local_api_cred_out[static 33]); // tailscale_errmsg writes the details of the last error to buf. // diff --git a/tsnetctest/tsnetctest.go b/tsnetctest/tsnetctest.go index e2a3d34..8117906 100644 --- a/tsnetctest/tsnetctest.go +++ b/tsnetctest/tsnetctest.go @@ -19,7 +19,8 @@ char* control_url = 0; int addrlen = 128; char* addr = NULL; -char* cred = NULL; +char* proxy_cred = NULL; +char* local_api_cred = NULL; int errlen = 512; char* err = NULL; @@ -37,7 +38,8 @@ int set_err(tailscale sd, char tag) { int test_conn() { err = calloc(errlen, 1); addr = calloc(addrlen, 1); - cred = calloc(33, 1); + proxy_cred = calloc(33, 1); + local_api_cred = calloc(33, 1); int ret; s1 = tailscale_new(); @@ -111,7 +113,7 @@ int test_conn() { return set_err(s1, 'a'); } - if ((ret = tailscale_loopback_api(s1, addr, addrlen, cred)) != 0) { + if ((ret = tailscale_loopback(s1, addr, addrlen, proxy_cred, local_api_cred)) != 0) { return set_err(s1, 'b'); } @@ -186,7 +188,7 @@ func RunTestConn(t *testing.T) { t.Fatal(err) } req.Header.Set("Sec-Tailscale", "localapi") - req.SetBasicAuth("", C.GoString(C.cred)) + req.SetBasicAuth("", C.GoString(C.local_api_cred)) res, err := http.DefaultClient.Do(req) if err != nil { t.Fatal(err)