From 860a487ac82daa419d21ba150bafebfd912c7fde Mon Sep 17 00:00:00 2001 From: Percy Wegmann Date: Tue, 23 Jan 2024 14:30:17 -0600 Subject: [PATCH] POC of gomobile --- .gitignore | 5 +- libtailscale/Makefile | 4 ++ libtailscale/go.mod | 5 ++ libtailscale/go.sum | 2 + libtailscale/libtailscale.go | 130 +++++++++++++++++++++++++++++++++++ 5 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 libtailscale/Makefile create mode 100644 libtailscale/go.mod create mode 100644 libtailscale/go.sum create mode 100644 libtailscale/libtailscale.go diff --git a/.gitignore b/.gitignore index fef2cbf..15213a1 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,7 @@ tailscale.jks *.hprof #IDE -.vscode \ No newline at end of file +.vscode + +libtailscale-sources.jar +libtailscale.aar \ No newline at end of file diff --git a/libtailscale/Makefile b/libtailscale/Makefile new file mode 100644 index 0000000..98e59a3 --- /dev/null +++ b/libtailscale/Makefile @@ -0,0 +1,4 @@ +# Replace JAVA_HOME with the right path for your environment + +libtailscale.aar: *.go go.mod go.sum + JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-21.jdk/Contents/Home gomobile bind -target android -androidapi 21 libtailscale \ No newline at end of file diff --git a/libtailscale/go.mod b/libtailscale/go.mod new file mode 100644 index 0000000..eb7b71e --- /dev/null +++ b/libtailscale/go.mod @@ -0,0 +1,5 @@ +module libtailscale + +go 1.21.5 + +require golang.org/x/mobile v0.0.0-20240112133503-c713f31d574b // indirect diff --git a/libtailscale/go.sum b/libtailscale/go.sum new file mode 100644 index 0000000..6ede63f --- /dev/null +++ b/libtailscale/go.sum @@ -0,0 +1,2 @@ +golang.org/x/mobile v0.0.0-20240112133503-c713f31d574b h1:kfWLZgb8iUBHdE9WydD5V5dHIS/F6HjlBZNyJfn2bs4= +golang.org/x/mobile v0.0.0-20240112133503-c713f31d574b/go.mod h1:4efzQnuA1nICq6h4kmZRMGzbPiP06lZvgADUu1VpJCE= diff --git a/libtailscale/libtailscale.go b/libtailscale/libtailscale.go new file mode 100644 index 0000000..dc6031b --- /dev/null +++ b/libtailscale/libtailscale.go @@ -0,0 +1,130 @@ +package libtailscale + +import ( + "bytes" + "fmt" + "io" + "log" + "net/http" + + "tailscale.com/ipn/ipnlocal" + "tailscale.com/ipn/localapi" + "tailscale.com/net/dns" + "tailscale.com/net/netmon" + "tailscale.com/net/tsdial" + "tailscale.com/tsd" + "tailscale.com/types/logid" + "tailscale.com/wgengine" + "tailscale.com/wgengine/router" +) + +type Request struct { + Method string + Path string + Headers map[string][]string + Body []byte +} + +type Response struct { + StatusCode int + Headers map[string][]string + bodyWriter *bytes.Buffer +} + +func (resp *Response) Body() []byte { + return resp.bodyWriter.Bytes() +} + +type Tailscale interface { + ProcessRequest(req *Request) *Response +} + +type tailscale struct { + backend *ipnlocal.LocalBackend + localapi *localapi.Handler +} + +func NewTailscale() (Tailscale, error) { + logf := log.Printf + var sys tsd.System + var logID logid.PrivateID + logID.UnmarshalText([]byte("dead0000dead0000dead0000dead0000dead0000dead0000dead0000dead0000")) + netMon, err := netmon.New(logf) + if err != nil { + log.Printf("netmon.New: %w", err) + } + dialer := new(tsdial.Dialer) + cb := &router.CallbackRouter{ + SetBoth: func(rcfg *router.Config, dcfg *dns.OSConfig) error { return nil }, + SplitDNS: false, + GetBaseConfigFunc: nil, + } + engine, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{ + Tun: nil, + Router: cb, + DNS: cb, + Dialer: dialer, + SetSubsystem: sys.Set, + NetMon: netMon, + }) + if err != nil { + return nil, fmt.Errorf("runBackend: NewUserspaceEngine: %v", err) + } + sys.Set(engine) + backend, err := ipnlocal.NewLocalBackend(logf, logID.Public(), &sys, 0) + if err != nil { + return nil, err + } + api := localapi.NewHandler(backend, logf, netMon, logID.Public()) + return &tailscale{ + backend: backend, + localapi: api, + }, nil +} + +func (t *tailscale) ProcessRequest(req *Request) (resp *Response) { + defer func() { + if p := recover(); p != nil { + resp = &Response{ + StatusCode: http.StatusInternalServerError, + } + fmt.Fprintf(resp, "%s", p) + } + }() + + resp = &Response{ + StatusCode: http.StatusOK, + Headers: make(map[string][]string), + bodyWriter: &bytes.Buffer{}, + } + t.localapi.ServeHTTP(resp, req.AsHTTPRequest()) + + return +} + +func (req *Request) AsHTTPRequest() *http.Request { + result, _ := http.NewRequest(req.Method, fmt.Sprintf("http://server/%v", req.Path), nil) + if req.Body != nil { + result.Body = io.NopCloser(bytes.NewReader(req.Body)) + } + if req.Headers != nil { + for name, values := range req.Headers { + for _, value := range values { + result.Header.Add(name, value) + } + } + } + return result +} + +func (resp *Response) Header() http.Header { + return http.Header(resp.Headers) +} + +func (resp *Response) WriteHeader(statusCode int) { + resp.StatusCode = statusCode +} + +func (resp *Response) Write(p []byte) (int, error) { + return resp.bodyWriter.Write(p) +}