cmd/tailscale: make file cp send files via tailscaled localapi

So Taildrop sends work even if the local tailscaled is running in
netstack mode, as it often is on Synology, etc.

Updates #2179 (which is primarily about receiving, but both important)

Change-Id: I9bd1afdc8d25717e0ab6802c7cf2f5e0bd89a3b2
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2021-11-30 08:47:52 -08:00
committed by Brad Fitzpatrick
parent 46a9782322
commit 3181bbb8e4
3 changed files with 73 additions and 33 deletions

View File

@@ -90,6 +90,27 @@ func DoLocalRequest(req *http.Request) (*http.Response, error) {
return tsClient.Do(req)
}
func doLocalRequestNiceError(req *http.Request) (*http.Response, error) {
res, err := DoLocalRequest(req)
if err == nil {
if server := res.Header.Get("Tailscale-Version"); server != "" && server != version.Long && onVersionMismatch != nil {
onVersionMismatch(version.Long, server)
}
return res, nil
}
if ue, ok := err.(*url.Error); ok {
if oe, ok := ue.Err.(*net.OpError); ok && oe.Op == "dial" {
path := req.URL.Path
pathPrefix := path
if i := strings.Index(path, "?"); i != -1 {
pathPrefix = path[:i]
}
return nil, fmt.Errorf("Failed to connect to local Tailscale daemon for %s; %s Error: %w", pathPrefix, tailscaledConnectHint(), oe)
}
}
return nil, err
}
type errorJSON struct {
Error string
}
@@ -140,23 +161,11 @@ func send(ctx context.Context, method, path string, wantStatus int, body io.Read
if err != nil {
return nil, err
}
res, err := DoLocalRequest(req)
res, err := doLocalRequestNiceError(req)
if err != nil {
if ue, ok := err.(*url.Error); ok {
if oe, ok := ue.Err.(*net.OpError); ok && oe.Op == "dial" {
pathPrefix := path
if i := strings.Index(path, "?"); i != -1 {
pathPrefix = path[:i]
}
return nil, fmt.Errorf("Failed to connect to local Tailscale daemon for %s; %s Error: %w", pathPrefix, tailscaledConnectHint(), oe)
}
}
return nil, err
}
defer res.Body.Close()
if server := res.Header.Get("Tailscale-Version"); server != "" && server != version.Long && onVersionMismatch != nil {
onVersionMismatch(version.Long, server)
}
slurp, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
@@ -295,6 +304,30 @@ func FileTargets(ctx context.Context) ([]apitype.FileTarget, error) {
return fts, nil
}
// PushFile sends Taildrop file r to target.
//
// A size of -1 means unknown.
// The name parameter is the original filename, not escaped.
func PushFile(ctx context.Context, target tailcfg.StableNodeID, size int64, name string, r io.Reader) error {
req, err := http.NewRequestWithContext(ctx, "PUT", "http://local-tailscaled.sock/localapi/v0/file-put/"+string(target)+"/"+url.PathEscape(name), r)
if err != nil {
return err
}
if size != -1 {
req.ContentLength = size
}
res, err := doLocalRequestNiceError(req)
if err != nil {
return err
}
if res.StatusCode == 200 {
io.Copy(io.Discard, res.Body)
return nil
}
all, _ := io.ReadAll(res.Body)
return fmt.Errorf("%s: %s", res.Status, all)
}
func CheckIPForwarding(ctx context.Context) error {
body, err := get200(ctx, "/localapi/v0/check-ip-forwarding")
if err != nil {