11package sshutil
22
33import (
4+ "bytes"
45 "errors"
56 "fmt"
67 "io/fs"
78 "os"
89 "os/exec"
910 "path/filepath"
11+ "regexp"
1012 "strings"
13+ "sync"
1114
15+ "github.com/coreos/go-semver/semver"
1216 "github.com/lima-vm/lima/pkg/lockutil"
1317 "github.com/lima-vm/lima/pkg/osutil"
1418 "github.com/lima-vm/lima/pkg/store/dirnames"
@@ -102,6 +106,15 @@ func DefaultPubKeys(loadDotSSH bool) ([]PubKey, error) {
102106 return res , nil
103107}
104108
109+ var sshInfo struct {
110+ sync.Once
111+ // aesAccelerated is set to true when AES acceleration is available.
112+ // Available on almost all modern Intel/AMD processors.
113+ aesAccelerated bool
114+ // openSSHVersion is set to the version of OpenSSH, or semver.New("0.0.0") if the version cannot be determined.
115+ openSSHVersion semver.Version
116+ }
117+
105118func CommonArgs (useDotSSH bool ) ([]string , error ) {
106119 configDir , err := dirnames .LimaConfigDir ()
107120 if err != nil {
@@ -159,16 +172,24 @@ func CommonArgs(useDotSSH bool) ([]string, error) {
159172 "-F" , "/dev/null" ,
160173 )
161174
162- // By default, `ssh` choose [email protected] , even when AES accelerator is available. 163- // (OpenSSH_8.1p1, macOS 11.6, MacBookPro 2020, Core i7-1068NG7)
164- //
165- // We prioritize AES algorithms when AES accelerator is available.
166- if aesAccelerated {
167- logrus .
Debugf (
"AES accelerator seems available, prioritizing [email protected] and [email protected] " )
168- args = append (
args ,
"-o" ,
"Ciphers=^[email protected] ,[email protected] " )
169- } else {
170- logrus .
Debugf (
"AES accelerator does not seem available, prioritizing [email protected] " )
171- args = append (
args ,
"-o" ,
"Ciphers=^[email protected] " )
175+ sshInfo .Do (func () {
176+ sshInfo .aesAccelerated = detectAESAcceleration ()
177+ sshInfo .openSSHVersion = detectOpenSSHVersion ()
178+ })
179+
180+ // Only OpenSSH version 8.0 and later support adding ciphers to the front of the default set
181+ if ! sshInfo .openSSHVersion .LessThan (* semver .New ("8.0.0" )) {
182+ // By default, `ssh` choose [email protected] , even when AES accelerator is available. 183+ // (OpenSSH_8.1p1, macOS 11.6, MacBookPro 2020, Core i7-1068NG7)
184+ //
185+ // We prioritize AES algorithms when AES accelerator is available.
186+ if sshInfo .aesAccelerated {
187+ logrus .
Debugf (
"AES accelerator seems available, prioritizing [email protected] and [email protected] " )
188+ args = append (
args ,
"-o" ,
"Ciphers=^[email protected] ,[email protected] " )
189+ } else {
190+ logrus .
Debugf (
"AES accelerator does not seem available, prioritizing [email protected] " )
191+ args = append (
args ,
"-o" ,
"Ciphers=^[email protected] " )
192+ }
172193 }
173194 return args , nil
174195}
@@ -195,7 +216,25 @@ func SSHArgs(instDir string, useDotSSH bool) ([]string, error) {
195216 return args , nil
196217}
197218
198- // aesAccelerated is set to true when AES acceleration is available.
199- //
200- // Available on almost all modern Intel/AMD processors.
201- var aesAccelerated = detectAESAcceleration ()
219+ func detectOpenSSHVersion () semver.Version {
220+ var (
221+ v semver.Version
222+ stderr bytes.Buffer
223+ )
224+ cmd := exec .Command ("ssh" , "-V" )
225+ cmd .Stderr = & stderr
226+ if err := cmd .Run (); err != nil {
227+ logrus .Warnf ("failed to run %v: stderr=%q" , cmd .Args , stderr .String ())
228+ } else {
229+ regex := regexp .MustCompile (`^OpenSSH_(\d+\.\d+)(?:p(\d+))?\b` )
230+ matches := regex .FindSubmatch (stderr .Bytes ())
231+ if len (matches ) == 3 {
232+ if len (matches [2 ]) == 0 {
233+ matches [2 ] = []byte ("0" )
234+ }
235+ v = * semver .New (fmt .Sprintf ("%s.%s" , matches [1 ], matches [2 ]))
236+ }
237+ }
238+ logrus .Debugf ("OpenSSH version %s detected" , v )
239+ return v
240+ }
0 commit comments