Compare commits

...

22 Commits

Author SHA1 Message Date
Timmy Welch
8f5bdaed8a Fix hostkey being too short
Some checks failed
Push / CI (push) Has been cancelled
Modern versions of ssh refuse to connect to a server with a rsa key that
  is less than 2048 and this may change to 3072 or 4096 in the future.
  ed25519 cannot change keysize
2025-12-28 13:12:09 -08:00
Michael Stapelberg
3d571d9ebb cmd/breakglass: fallback to HTTP instead of detecting stripping
This follows gokrazy/tools commit
ba6a8936f4
2025-12-09 17:22:34 +01:00
Michael Stapelberg
e8f40f784b cmd/breakglass: use updateflag.Value, add own -insecure flag
related to https://github.com/gokrazy/tools/pull/68
2025-12-05 17:50:59 +01:00
Michael Stapelberg
e4167a5b08 cmd/breakglass: remove old -gokrazy_url and -tls flags
These have been deprecated for years.
All users should have switched to the instance-centric config by now.

related to https://github.com/gokrazy/tools/pull/68
2025-12-05 17:34:49 +01:00
dependabot[bot]
596b54e033 Bump golang.org/x/crypto from 0.35.0 to 0.45.0 (#26)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.35.0 to 0.45.0.
- [Commits](https://github.com/golang/crypto/compare/v0.35.0...v0.45.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.45.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-20 07:37:04 +01:00
Mark Drayton
02513c1dab README: fix -debug_tarball_pattern name mismatch (#25) 2025-08-24 09:03:20 +02:00
dependabot[bot]
ac3ee429ce Bump golang.org/x/oauth2 from 0.23.0 to 0.27.0 (#24)
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.23.0 to 0.27.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.23.0...v0.27.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-version: 0.27.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-19 10:26:34 +02:00
dependabot[bot]
c0fb5a7864 Bump golang.org/x/crypto from 0.33.0 to 0.35.0 (#23)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.33.0 to 0.35.0.
- [Commits](https://github.com/golang/crypto/compare/v0.33.0...v0.35.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.35.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-15 08:47:08 +02:00
Michael Stapelberg
adb5ce3ea1 use gokapi package to query build timestamp 2025-02-22 08:12:43 +01:00
Michael Stapelberg
62e5a663a8 GitHub Actions: update to latest versions of actions 2025-02-22 07:23:07 +01:00
Tim H
8965ef43ba Get buildTimestamp via a request to Unix socket (#22)
Fixes https://github.com/gokrazy/breakglass/issues/21
2025-02-22 07:20:22 +01:00
Michael Stapelberg
5f675f1989 pull in latest gokrazy package 2025-02-22 07:18:42 +01:00
Michael Stapelberg
a233c4f4d4 go.mod: bump language version to 1.24 2025-02-22 07:18:24 +01:00
Michael Stapelberg
86e60e7477 update to latest gokrazy/internal
related to https://github.com/gokrazy/gokrazy/issues/191
2025-01-26 22:46:35 +01:00
Michael Stapelberg
c9528b4abb try to install busybox into a tmpfs /bin (with fallback)
This code path requires gokrazy/tools at this commit or newer:
37e2f95c5c

And gokrazy/serial-breakglass at this commit or newer:
bf9bc19235

Afterwards, with an ~/.ssh/config entry like this:

    Host scan2drive
        ProxyCommand breakglass -proxy %h

…using Emacs TRAMP should just work:

    emacs /ssh:scan2drive:/perm/keep/index.md
2024-12-31 09:53:25 +01:00
dependabot[bot]
6c59aaaf28 Bump golang.org/x/crypto from 0.17.0 to 0.31.0 (#20)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.17.0 to 0.31.0.
- [Commits](https://github.com/golang/crypto/compare/v0.17.0...v0.31.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-12 08:22:41 +01:00
Michael Stapelberg
0327ae332c breakglass: enable -enable_banner by default
The banner is useful and recognizeable.
I think it should be turned on by default.
2024-06-09 22:11:23 +02:00
Brad Fitzpatrick
09eeab3321 Support getting public keys from AWS EC2 metadata (#18)
Updates gokrazy/gokrazy#265

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2024-06-04 19:01:21 +02:00
Michael Stapelberg
44b3fe64f1 remove ssh-rsa warning
bradfitz confirmed ssh-rsa keys work again.

fixes https://github.com/gokrazy/breakglass/issues/11
2024-05-29 19:59:05 +02:00
dependabot[bot]
eacd5a447e Bump golang.org/x/crypto from 0.6.0 to 0.17.0 (#17)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.6.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.6.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-19 08:51:47 +01:00
Michael Stapelberg
e771a5894b pull in latest gokrazy/gokrazy for ifaddr change 2023-08-12 11:30:49 +02:00
Michael Stapelberg
158f63b4af go get -u 2023-02-25 16:20:58 +01:00
9 changed files with 235 additions and 135 deletions

View File

@@ -9,21 +9,18 @@ jobs:
name: CI name: CI
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4
- name: Set up Go 1.x - name: Set up latest stable Go
uses: actions/setup-go@v2 uses: actions/setup-go@v5
with: with:
# Run on the latest minor release of Go 1.19: go-version: 'stable'
go-version: ^1.19
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Ensure all files were formatted as per gofmt - name: Ensure all files were formatted as per gofmt
run: | run: |
[ "$(gofmt -l $(find . -name '*.go') 2>&1)" = "" ] [ "$(gofmt -l $(find . -name '*.go') 2>&1)" = "" ]
- name: Build packages - name: Build and test
run: | run: |
go install -v ./... go install ./...
go test -v ./...

View File

@@ -97,7 +97,7 @@ busybox: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically li
for GNU/Linux 3.7.0, BuildID[sha1]=c9e20e9849ed0ca3c2bd058427ac31a27c008efe, stripped for GNU/Linux 3.7.0, BuildID[sha1]=c9e20e9849ed0ca3c2bd058427ac31a27c008efe, stripped
$ ln -s busybox sh $ ln -s busybox sh
$ tar cf breakglass.tar --dereference sh $ tar cf breakglass.tar --dereference sh
$ breakglass -debug_tarball_pattern=debug.tar gokrazy $ breakglass -debug_tarball_pattern=breakglass.tar gokrazy
/tmp/breakglass564067692 # df -h /tmp/breakglass564067692 # df -h
Filesystem Size Used Available Use% Mounted on Filesystem Size Used Available Use% Mounted on
/dev/root 60.5M 60.5M 0 100% / /dev/root 60.5M 60.5M 0 100% /

View File

@@ -5,21 +5,22 @@ package main
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"context"
"crypto/ed25519"
"crypto/rand" "crypto/rand"
"crypto/rsa"
"crypto/x509" "crypto/x509"
"encoding/json"
"encoding/pem" "encoding/pem"
"flag" "flag"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"net" "net"
"net/http"
"os" "os"
"strings" "strings"
"syscall" "syscall"
"github.com/gokrazy/gokapi"
"github.com/gokrazy/gokapi/ondeviceapi"
"github.com/gokrazy/gokrazy" "github.com/gokrazy/gokrazy"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
@@ -28,7 +29,7 @@ import (
var ( var (
authorizedKeysPath = flag.String("authorized_keys", authorizedKeysPath = flag.String("authorized_keys",
"/perm/breakglass.authorized_keys", "/perm/breakglass.authorized_keys",
"path to an OpenSSH authorized_keys file") "path to an OpenSSH authorized_keys file; if the value is 'ec2', fetch the SSH key(s) from the AWS IMDSv2 metadata")
hostKeyPath = flag.String("host_key", hostKeyPath = flag.String("host_key",
"/perm/breakglass.host_key", "/perm/breakglass.host_key",
@@ -39,7 +40,7 @@ var (
"port for breakglass to listen on") "port for breakglass to listen on")
enableBanner = flag.Bool("enable_banner", enableBanner = flag.Bool("enable_banner",
false, true,
"Adds a banner to greet the user on login") "Adds a banner to greet the user on login")
forwarding = flag.String("forward", forwarding = flag.String("forward",
@@ -48,7 +49,14 @@ var (
) )
func loadAuthorizedKeys(path string) (map[string]bool, error) { func loadAuthorizedKeys(path string) (map[string]bool, error) {
b, err := ioutil.ReadFile(path) var b []byte
var err error
switch path {
case "ec2":
b, err = loadAWSEC2SSHKeys()
default:
b, err = ioutil.ReadFile(path)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -60,15 +68,7 @@ func loadAuthorizedKeys(path string) (map[string]bool, error) {
if tr := strings.TrimSpace(s.Text()); tr == "" || strings.HasPrefix(tr, "#") { if tr := strings.TrimSpace(s.Text()); tr == "" || strings.HasPrefix(tr, "#") {
continue continue
} }
pubKey, comment, _, _, err := ssh.ParseAuthorizedKey(s.Bytes()) pubKey, _, _, _, err := ssh.ParseAuthorizedKey(s.Bytes())
// This warning can be removed once the mentioned issue is resolved
if keyType := pubKey.Type(); keyType == "ssh-rsa" {
log.Print("Warning: You added a ssh-rsa key to your authorized keys, these do currently not work.")
log.Print("Further information: https://github.com/gokrazy/breakglass/issues/11")
log.Printf("Affected key: %s [...] %s (line %d)", keyType, comment, lineNum)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -91,7 +91,7 @@ func loadHostKey(path string) (ssh.Signer, error) {
} }
func createHostKey(path string) (ssh.Signer, error) { func createHostKey(path string) (ssh.Signer, error) {
key, err := rsa.GenerateKey(rand.Reader, 1024) _, key, err := ed25519.GenerateKey(rand.Reader)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -116,40 +116,16 @@ func createHostKey(path string) (ssh.Signer, error) {
} }
func buildTimestamp() (string, error) { func buildTimestamp() (string, error) {
var statusReply struct { cfg, err := gokapi.ConnectOnDevice()
BuildTimestamp string `json:"BuildTimestamp"`
}
pw, err := os.ReadFile("/etc/gokr-pw.txt")
if err != nil { if err != nil {
return "", err return "", err
} }
port, err := os.ReadFile("/etc/http-port.txt") cl := ondeviceapi.NewAPIClient(cfg)
res, _, err := cl.SuperviseApi.Index(context.Background())
if err != nil { if err != nil {
return "", err return "", err
} }
req, err := http.NewRequest("GET", "http://gokrazy:"+strings.TrimSpace(string(pw))+"@localhost:"+strings.TrimSpace(string(port))+"/", nil) return res.BuildTimestamp, nil
if err != nil {
return "", err
}
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
if got, want := resp.StatusCode, http.StatusOK; got != want {
b, _ := ioutil.ReadAll(resp.Body)
return "", fmt.Errorf("unexpected HTTP status code: got %v, want %v (body: %s)", resp.Status, want, strings.TrimSpace(string(b)))
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
if err := json.Unmarshal(b, &statusReply); err != nil {
return "", err
}
return statusReply.BuildTimestamp, nil
} }
var motd string var motd string

84
breakglassaws.go Normal file
View File

@@ -0,0 +1,84 @@
// Code for interacting with AWS EC2.
package main
import (
"bytes"
"errors"
"fmt"
"io"
"net/http"
"strings"
)
// getEC2MetadataToken returns an IMDSv2 token from the AWS EC2 metadata
// server. This is needed for subsequent metadata requests, at least when
// the VM was created in IMDSv2-required mode, as is common.
//
// See https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html
func getEC2MetadataToken() (string, error) {
req, _ := http.NewRequest("PUT", "http://169.254.169.254/latest/api/token", nil)
req.Header.Add("X-aws-ec2-metadata-token-ttl-seconds", "300")
res, err := http.DefaultClient.Do(req)
if err != nil {
return "", fmt.Errorf("failed to get metadata token: %w", err)
}
defer res.Body.Close()
if res.StatusCode != 200 {
return "", fmt.Errorf("failed to get metadata token: %v", res.Status)
}
all, err := io.ReadAll(res.Body)
if err != nil {
return "", fmt.Errorf("failed to read metadata token: %w", err)
}
return strings.TrimSpace(string(all)), nil
}
// loadAWSEC2SSHKeys returns 1 or more SSH public keys from the AWS
// EC2 metadata server and returns them concatenanted, one per line,
// as if they were all together in an ~/.ssh/authorized_keys file.
//
// See https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html#instance-metadata-ex-5
func loadAWSEC2SSHKeys() ([]byte, error) {
token, err := getEC2MetadataToken()
if err != nil {
return nil, err
}
var authorizedKeys bytes.Buffer
getKeyIndex := func(idx int) error {
req, _ := http.NewRequest("GET", fmt.Sprintf("http://169.254.169.254/latest/meta-data/public-keys/%d/openssh-key", idx), nil)
req.Header.Add("X-aws-ec2-metadata-token", token)
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != 200 {
return errors.New(res.Status)
}
all, err := io.ReadAll(res.Body)
if err != nil {
return err
}
// Write out a ~/.ssh/authorized_keys -looking file,
// with each key on its own line.
fmt.Fprintf(&authorizedKeys, "%s\n", bytes.TrimSpace(all))
return nil
}
for i := 0; ; i++ {
err := getKeyIndex(i)
if err == nil {
continue
}
if i == 0 {
// We expect at least one SSH key (index 0) if the
// use requested this mode, so return an error if the
// first one fails.
return nil, err
}
// But on subsequent errors, just assume we've hit the end.
// This is a little lazy.
break
}
return authorizedKeys.Bytes(), nil
}

53
busybox.go Normal file
View File

@@ -0,0 +1,53 @@
package main
import (
"fmt"
"log"
"os"
"os/exec"
"strings"
"syscall"
)
const wellKnownBusybox = "/usr/local/bin/busybox"
// mountBin bind-mounts /bin to a tmpfs.
func mountBin() error {
b, err := os.ReadFile("/proc/self/mountinfo")
if err != nil {
return err
}
for _, line := range strings.Split(strings.TrimSpace(string(b)), "\n") {
parts := strings.Fields(line)
if len(parts) < 5 {
continue
}
mountpoint := parts[4]
log.Printf("Found mountpoint %q", parts[4])
if mountpoint == "/bin" {
log.Printf("/bin file system already mounted, nothing to do")
return nil
}
}
if err := syscall.Mount("tmpfs", "/bin", "tmpfs", 0, ""); err != nil {
return fmt.Errorf("mounting tmpfs on /bin: %v", err)
}
return nil
}
func installBusybox() error {
// /bin is read-only by default, so mount a tmpfs over it
if err := mountBin(); err != nil {
return err
}
install := exec.Command(wellKnownBusybox, "--install", "-s", "/bin")
install.Stdout = os.Stdout
install.Stderr = os.Stderr
if err := install.Run(); err != nil {
return fmt.Errorf("%v: %v", install.Args, err)
}
return nil
}

View File

@@ -26,7 +26,6 @@ import (
"github.com/gokrazy/internal/config" "github.com/gokrazy/internal/config"
"github.com/gokrazy/internal/httpclient" "github.com/gokrazy/internal/httpclient"
"github.com/gokrazy/internal/instanceflag" "github.com/gokrazy/internal/instanceflag"
"github.com/gokrazy/internal/tlsflag"
"github.com/gokrazy/internal/updateflag" "github.com/gokrazy/internal/updateflag"
) )
@@ -35,9 +34,11 @@ type bg struct {
cfg *config.Struct cfg *config.Struct
forceRestart bool forceRestart bool
sshConfig string sshConfig string
insecure bool
// state // state
GOARCH string GOARCH string
update updateflag.Value
} }
func (bg *bg) startBreakglass() error { func (bg *bg) startBreakglass() error {
@@ -46,35 +47,26 @@ func (bg *bg) startBreakglass() error {
return err return err
} }
updateHttpClient, foundMatchingCertificate, updateBaseURL, err := httpclient.For(bg.cfg) updateHttpClient, _, updateBaseURL, err := httpclient.For(bg.update, bg.cfg)
if err != nil { if err != nil {
return err return err
} }
updateHttpClient.Jar = jar updateHttpClient.Jar = jar
remoteScheme, err := httpclient.GetRemoteScheme(updateBaseURL)
if remoteScheme == "https" && !tlsflag.Insecure() {
updateBaseURL.Scheme = "https"
updateflag.SetUpdate(updateBaseURL.String())
}
if updateBaseURL.Scheme != "https" && foundMatchingCertificate {
fmt.Printf("\n")
fmt.Printf("!!!WARNING!!! Possible SSL-Stripping detected!\n")
fmt.Printf("Found certificate for hostname in your client configuration but the host does not offer https!\n")
fmt.Printf("\n")
if !tlsflag.Insecure() {
log.Fatalf("update canceled: TLS certificate found, but negotiating a TLS connection with the target failed")
}
fmt.Printf("Proceeding anyway as requested (-insecure).\n")
}
if err != nil {
return err
}
form, err := updateHttpClient.Get(updateBaseURL.String() + "status?path=/user/breakglass") form, err := updateHttpClient.Get(updateBaseURL.String() + "status?path=/user/breakglass")
if err != nil { if err != nil {
if updateBaseURL.Scheme == "https" && bg.insecure {
// Try falling back to HTTP
bg.cfg.Update.UseTLS = "off"
updateHttpClient, _, updateBaseURL, err = httpclient.For(bg.update, bg.cfg)
if err != nil {
return err
}
form, err = updateHttpClient.Get(updateBaseURL.String() + "status?path=/user/breakglass")
if err != nil {
return err
}
}
return err return err
} }
if form.StatusCode == http.StatusNotFound { if form.StatusCode == http.StatusNotFound {
@@ -198,6 +190,11 @@ func breakglass() error {
false, false,
"prepare the SSH connection only, but do not execute SSH (useful for using breakglass within an SSH ProxyCommand)") "prepare the SSH connection only, but do not execute SSH (useful for using breakglass within an SSH ProxyCommand)")
insecure = flag.Bool(
"insecure",
false,
"Fall back to HTTP if HTTPS is configured, but does not work.")
proxy = flag.Bool( proxy = flag.Bool(
"proxy", "proxy",
false, false,
@@ -209,13 +206,6 @@ func breakglass() error {
"an alternative per-user configuration file for ssh and scp") "an alternative per-user configuration file for ssh and scp")
) )
// TODO: remove the -tls and -gokrazy_url flags after 2023-June (half a year
// after the introduction of instance centric config), so that we can then
// merge these flags into tools/internal/oldpacker and remove their global
// state.
tlsflag.RegisterFlags(flag.CommandLine)
updateflag.RegisterFlags(flag.CommandLine, "gokrazy_url")
flag.Usage = func() { flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n\n", os.Args[0]) fmt.Fprintf(os.Stderr, "Usage of %s:\n\n", os.Args[0])
@@ -231,17 +221,10 @@ func breakglass() error {
log.Fatalf("syntax: breakglass <hostname> [command]") log.Fatalf("syntax: breakglass <hostname> [command]")
} }
// If the user did not explicitly specify -update=yes, we default to it.
// This differs from the gokr-packer, but breakglass is only useful for
// gokrazy instances that already exist.
if updateflag.NewInstallation() {
updateflag.SetUpdate("yes")
}
instance := flag.Arg(0) instance := flag.Arg(0)
instanceflag.SetInstance(instance) instanceflag.SetInstance(instance)
cfg, err := config.ReadFromFile() cfg, err := config.ApplyInstanceFlag()
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
// best-effort compatibility for old setups // best-effort compatibility for old setups
@@ -255,6 +238,8 @@ func breakglass() error {
cfg: cfg, cfg: cfg,
forceRestart: *forceRestart, forceRestart: *forceRestart,
sshConfig: *sshConfig, sshConfig: *sshConfig,
insecure: *insecure,
update: updateflag.Value{Update: "yes"},
} }
if cfg.Update.Hostname == "" { if cfg.Update.Hostname == "" {
cfg.Update.Hostname = cfg.Hostname cfg.Update.Hostname = cfg.Hostname

22
go.mod
View File

@@ -1,22 +1,24 @@
module github.com/gokrazy/breakglass module github.com/gokrazy/breakglass
go 1.19 go 1.24.0
require ( require (
github.com/gokrazy/gokrazy v0.0.0-20211024151958-b718dd90ae71 github.com/gokrazy/gokapi v0.0.0-20250222071133-506fdb322775
github.com/gokrazy/internal v0.0.0-20230117180442-8b3fd7aed8bb github.com/gokrazy/gokrazy v0.0.0-20250222061409-bd0bb5f1d0b5
github.com/gokrazy/internal v0.0.0-20251208203110-3c1aa9087c82
github.com/google/renameio/v2 v2.0.0 github.com/google/renameio/v2 v2.0.0
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/kr/pty v1.1.8 github.com/kr/pty v1.1.8
github.com/pkg/sftp v1.13.5-0.20220330091711-a17a626ab843 github.com/pkg/sftp v1.13.5
golang.org/x/crypto v0.1.0 golang.org/x/crypto v0.45.0
) )
require ( require (
github.com/creack/pty v1.1.7 // indirect github.com/creack/pty v1.1.18 // indirect
github.com/kenshaw/evdev v0.1.0 // indirect
github.com/kr/fs v0.1.0 // indirect github.com/kr/fs v0.1.0 // indirect
github.com/mdlayher/watchdog v0.0.0-20201005150459-8bdc4f41966b // indirect github.com/mdlayher/watchdog v0.0.0-20221003142519-49be0df7b3b5 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sys v0.1.0 // indirect golang.org/x/oauth2 v0.27.0 // indirect
rsc.io/goversion v1.2.0 // indirect golang.org/x/sys v0.38.0 // indirect
) )

57
go.sum
View File

@@ -1,61 +1,54 @@
github.com/anatol/vmtest v0.0.0-20210623221036-69fc760fbd4b/go.mod h1:l08qtd2JHjoYWIROnbKoKCUqIbe54ndrXwDdyiDfq30=
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gokrazy/gokrazy v0.0.0-20211024151958-b718dd90ae71 h1:NHLkr4NYMY9gZGTI+jzIo38ZffMHkPbBzMcUDkyHs0g= github.com/gokrazy/gokapi v0.0.0-20250222071133-506fdb322775 h1:f5+2UMRRbr3+e/gdWCBNn48chS/KMMljfbmlSSHfRBA=
github.com/gokrazy/gokrazy v0.0.0-20211024151958-b718dd90ae71/go.mod h1:eq2ROPhZJtxxEi21P8cbNqP8pwRBSpW/4LGKwNiQg2Y= github.com/gokrazy/gokapi v0.0.0-20250222071133-506fdb322775/go.mod h1:q9mIV8al0wqmqFXJhKiO3SOHkL9/7Q4kIMynqUQWhgU=
github.com/gokrazy/internal v0.0.0-20210621162516-1b3b5687a06d/go.mod h1:Gqv1x1DNrObmBvVvblpZbvZizZ0dU5PwiwYHipmtY9Y= github.com/gokrazy/gokrazy v0.0.0-20250222061409-bd0bb5f1d0b5 h1:VQhDGxRliP4ZTQ8+33v4VKtOpX4VzN8pA4zBMZQSSxs=
github.com/gokrazy/internal v0.0.0-20230117180442-8b3fd7aed8bb h1:MT59ew5neGiU6hqFOnlqwo6pavSpdX1JUgBOvzDjNec= github.com/gokrazy/gokrazy v0.0.0-20250222061409-bd0bb5f1d0b5/go.mod h1:6fAh0J7aH6o5HWSiwN6uxNlm6Rjx1BxeNMWyNBQZ6sI=
github.com/gokrazy/internal v0.0.0-20230117180442-8b3fd7aed8bb/go.mod h1:ddHcxXZ/VVQOSAWcRBbkYY58+QOw4L145ye6phyDmRA= github.com/gokrazy/internal v0.0.0-20251208203110-3c1aa9087c82 h1:4ghNfD9NaZLpFrqQiBF6mPVFeMYXJSky38ubVA4ic2E=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/gokrazy/internal v0.0.0-20251208203110-3c1aa9087c82/go.mod h1:dQY4EMkD4L5ZjYJ0SPtpgYbV7MIUMCxNIXiOfnZ6jP4=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/gopacket v1.1.16/go.mod h1:UCLx9mCmAwsVbn6qQl1WIEt2SO7Nd2fD0th1TBAsqBw= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg= github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/kenshaw/evdev v0.1.0 h1:wmtceEOFfilChgdNT+c/djPJ2JineVsQ0N14kGzFRUo=
github.com/kenshaw/evdev v0.1.0/go.mod h1:B/fErKCihUyEobz0mjn2qQbHgyJKFQAxkXSvkeeA/Wo=
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI= github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/mdlayher/raw v0.0.0-20190303161257-764d452d77af/go.mod h1:rC/yE65s/DoHB6BzVOUBNYBGTg772JVytyAytffIZkY= github.com/mdlayher/watchdog v0.0.0-20221003142519-49be0df7b3b5 h1:80FAK3TW5lVymfHu3kvB1QvTZvy9Kmx1lx6sT5Ep16s=
github.com/mdlayher/watchdog v0.0.0-20201005150459-8bdc4f41966b h1:7tUBfsEEBWfFeHOB7CUfoOamak+Gx/BlirfXyPk1WjI= github.com/mdlayher/watchdog v0.0.0-20221003142519-49be0df7b3b5/go.mod h1:z0QjVpjpK4jksEkffQwS3+abQ3XFTm1bnimyDzWyUk0=
github.com/mdlayher/watchdog v0.0.0-20201005150459-8bdc4f41966b/go.mod h1:bmoJUS6qOA3uKFvF3KVuhf7mU1KQirzQMeHXtPyKEqg= github.com/pkg/sftp v1.13.5 h1:a3RLUqkyjYRtBTZJZ1VRrKbN3zhuPLlUc3sphVz81go=
github.com/pkg/sftp v1.13.5-0.20220330091711-a17a626ab843 h1:aIV4Pjj4gI4eGy8t60Pfji8tdDDohxwBU5ZCb4ulHvw= github.com/pkg/sftp v1.13.5/go.mod h1:wHDZ0IZX6JcBYRK1TH9bcVq8G7TLpVHYIGJRFnmPfxg=
github.com/pkg/sftp v1.13.5-0.20220330091711-a17a626ab843/go.mod h1:wHDZ0IZX6JcBYRK1TH9bcVq8G7TLpVHYIGJRFnmPfxg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rtr7/dhcp4 v0.0.0-20181120124042-778e8c2e24a5/go.mod h1:FwstIpm6vX98QgtR8KEwZcVjiRn2WP76LjXAHj84fK0=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201005065044-765f4ea38db3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
rsc.io/goversion v1.2.0 h1:SPn+NLTiAG7w30IRK/DKp1BjvpWabYgxlLp/+kx5J8w=
rsc.io/goversion v1.2.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo=

10
ssh.go
View File

@@ -215,6 +215,16 @@ type exitStatus struct {
} }
func findShell() string { func findShell() string {
if _, err := os.Stat(wellKnownBusybox); err == nil {
// Install busybox to /bin to provide the typical userspace utilities
// in standard locations (makes Emacs TRAMP work, for example).
if err := installBusybox(); err != nil {
log.Printf("installing busybox failed: %v", err)
// fallthrough
} else {
return "/bin/sh" // available after installation
}
}
if path, err := exec.LookPath("sh"); err == nil { if path, err := exec.LookPath("sh"); err == nil {
return path return path
} }