libtailscale: update tailscale_loopback

This brings it inline with the tsnet change to support proxies.

Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
This commit is contained in:
David Crawshaw
2023-03-05 21:23:03 -08:00
committed by David Crawshaw
parent 30ea07bf54
commit 843d93cb63
6 changed files with 47 additions and 33 deletions

View File

@@ -80,7 +80,7 @@ PYBIND11_MODULE(_tailscale, m) {
)pbdoc");
m.def("loopback_api", &TsnetLoopbackAPI, R"pbdoc(
m.def("loopback", &TsnetLoopback, R"pbdoc(
)pbdoc");

View File

@@ -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

View File

@@ -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) {

View File

@@ -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

View File

@@ -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.
//

View File

@@ -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)