epiccastle / bbssh Goto Github PK
View Code? Open in Web Editor NEWBabashka pod for SSH support.
License: Eclipse Public License 2.0
Babashka pod for SSH support.
License: Eclipse Public License 2.0
Hi @retrogradeorbit,
Thanks for the great library.
I am trying the following function when trying bbssh
with babashka/process
(require '[babashka.process :as bp])
(require '[pod.epiccastle.bbssh.core :as bbssh])
(def session
(bbssh/ssh "some-remote-host"
{:username ".."
:identity "..."}))
;; Trying the code from the docs:
;; https://github.com/epiccastle/bbssh/blob/main/docs/01-basics.md#streaming-between-local-and-remote
(-> (bp/process "echo this is local")
(bbssh/exec "md5sum" {:session session})
;; more code but it failed already at this stage
,,)
When eval the above code I am getting the following error:
Multiple methods in multimethod 'print-method' match dispatch value: class
pod.epiccastle.bbssh.core.SshProcess -> interface clojure.lang.IDeref and
interface clojure.lang.IRecord, and neither is preferred
MultiFn.java: 179 clojure.lang.MultiFn/findAndCacheBestMethod
MultiFn.java: 150 clojure.lang.MultiFn/getMethod
MultiFn.java: 154 clojure.lang.MultiFn/getFn
MultiFn.java: 233 clojure.lang.MultiFn/invoke
pprint.clj: 40 cider.nrepl.pprint/pr/fn
AFn.java: 152 clojure.lang.AFn/applyToHelper
AFn.java: 144 clojure.lang.AFn/applyTo
core.clj: 667 clojure.core/apply
core.clj: 1990 clojure.core/with-bindings*
core.clj: 1990 clojure.core/with-bindings*
RestFn.java: 425 clojure.lang.RestFn/invoke
pprint.clj: 37 cider.nrepl.pprint/pr
pprint.clj: 29 cider.nrepl.pprint/pr
Var.java: 393 clojure.lang.Var/invoke
print.clj: 224 nrepl.middleware.print/wrap-print/fn/print
print.clj: 148 nrepl.middleware.print/send-nonstreamed/print-key/fn
print.clj: 147 nrepl.middleware.print/send-nonstreamed/print-key
core.clj: 2759 clojure.core/map/fn/fn
protocols.clj: 49 clojure.core.protocols/iter-reduce
protocols.clj: 75 clojure.core.protocols/fn
protocols.clj: 75 clojure.core.protocols/fn
protocols.clj: 13 clojure.core.protocols/fn/G
core.clj: 6947 clojure.core/transduce
core.clj: 6933 clojure.core/transduce
print.clj: 156 nrepl.middleware.print/send-nonstreamed
print.clj: 138 nrepl.middleware.print/send-nonstreamed
print.clj: 174 nrepl.middleware.print/printing-transport/reify
caught.clj: 58 nrepl.middleware.caught/caught-transport/reify
interruptible_eval.clj: 123 nrepl.middleware.interruptible-eval/evaluate/fn
main.clj: 442 clojure.main/repl/read-eval-print
main.clj: 458 clojure.main/repl/fn
main.clj: 458 clojure.main/repl
main.clj: 368 clojure.main/repl
RestFn.java: 1523 clojure.lang.RestFn/invoke
interruptible_eval.clj: 84 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 56 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 152 nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
AFn.java: 22 clojure.lang.AFn/run
session.clj: 218 nrepl.middleware.session/session-exec/main-loop/fn
session.clj: 217 nrepl.middleware.session/session-exec/main-loop
AFn.java: 22 clojure.lang.AFn/run
Thread.java: 833 java.lang.Thread/run
I am using:
babashka/process {:mvn/version "0.5.21"}
Do you know why this fails?
When using the native pod:
(pods/load-pod 'epiccastle/bbssh "0.2.0")
INFO Connecting to host.foo.com port 22
INFO Local version string: SSH-2.0-JSCH_0.2.3
INFO CheckCiphers: [email protected]
INFO CheckKexes: curve25519-sha256,[email protected],curve448-sha512
INFO curve25519-sha256 is not available.
INFO [email protected] is not available.
...
INFO CheckSignatures: ssh-ed25519,ssh-ed448
INFO ssh-ed25519 is not available.
INFO ssh-ed448 is not available.
....
DEBUG Signature algorithms unavailable for non-agent identities = [ssh-ed25519, ssh-ed448]
DEBUG PubkeyAcceptedAlgorithms in server-sig-algs = [ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, rsa-sha2-512, rsa-sha2-256, ssh-rsa, ssh-ed25519]
...
DEBUG ssh-ed25519 not available for identity foo_key_ed25519
INFO Authentications that can continue: password
INFO Next authentication method: password
Enter Password for [email protected]:22:
When loading the pod as a jvm process:
(pods/load-pod ["java" ... "clojure.main" "-m" "bbssh.core"] {:transport :socket)
...
DEBUG ssh-ed25519 preauth success
DEBUG ssh-ed25519 auth success
INFO Authentication succeeded (publickey).
The relevant code for checking supported algorithms is here.
For Java versions earlier than Java 15, the ed25519 support in jsch comes from bouncy castle. In Java 15+ it uses JCE and doesn't require bouncy castle. So it could be some class loading issue when running in native image.
So in theory this issue could be gone by using Java 17 version of GraalVM to build the image, which doesn't require bouncy castle.
Reach out if you run windows and would like to help!
Implementations for opening, closing, reading from and writing to the SSH_AUTH_SOCK pipe is needed.
Opening: https://github.com/epiccastle/bbssh/blob/v0.2.0/src/c/bbssh.c#L191
Closing: https://github.com/epiccastle/bbssh/blob/v0.2.0/src/c/bbssh.c#L200
Reading: https://github.com/epiccastle/bbssh/blob/v0.2.0/src/c/bbssh.c#L207
Writing: https://github.com/epiccastle/bbssh/blob/v0.2.0/src/c/bbssh.c#L216
Build steps for windows are here: https://github.com/epiccastle/bbssh/blob/v0.2.0/.circleci/config.yml#L169-L258
But for development work one should build a JNI version of the lib as a .dll that can be loaded here: https://github.com/epiccastle/bbssh/blob/v0.2.0/src/clj/bbssh/core.clj#L28
(key-pair/generate agent :ed25519 1024)
clojure.lang.ExceptionInfo: java.lang.NoClassDefFoundError: org/bouncycastle/crypto/params/Ed25519PrivateKeyParameters
{:type :sci/error, :line 21, :column 5, :message "java.lang.NoClassDefFoundError: org/bouncycastle/crypto/params/Ed25519PrivateKeyParameters", :sci.impl/callstack #object[clojure.lang.Volatile 0x24caaaf1 {:status :ready, :val ({:line 88, :column 17, :ns #object[sci.lang.Namespace 0x6b8366c4 "bb-test.test-openssh-config"], :file "/home/crispin/dev/clojure/bbssh/test/./bb_test/test_openssh_config.clj", :sci.impl/f-meta {:name generate, :ns #object[sci.lang.Namespace 0xd6206ce "pod.epiccastle.bbssh.key-pair"], :file "/home/crispin/dev/clojure/bbssh/test/./bb_test/core.clj", :line 11, :column 1, :arglists ([agent key-type] [agent key-type key-size]), :doc "Generate a public/private SSH key pair.\n `key-type` should be `:dsa`, `:rsa`, `:ecdsa`, `:ed25519`\n or `:ed448`.\n `key-size` is the number of bits and defaults to 2048.\n "}} {:line 20, :column 4, :ns #object[sci.lang.Namespace 0xd6206ce "pod.epiccastle.bbssh.key-pair"], :file "/home/crispin/dev/clojure/bbssh/test/./bb_test/core.clj", :sci.impl/f-meta {:name register, :ns #object[sci.lang.Namespace 0x320595b2 "pod.epiccastle.bbssh.impl.cleaner"], :file "/home/crispin/dev/clojure/bbssh/test/./bb_test/core.clj", :line 36, :column 1, :arglists ([key]), :doc "Register a key (a vector of namespace and name) returned from\n the pod `invoke` to garbage collected. Returns the keyword to be used\n inside babashka code.\n "}} {:line 21, :column 5, :ns #object[sci.lang.Namespace 0xd6206ce "pod.epiccastle.bbssh.key-pair"], :file "/home/crispin/dev/clojure/bbssh/test/./bb_test/core.clj", :sci.impl/f-meta {:name generate}})}], :file "/home/crispin/dev/clojure/bbssh/test/./bb_test/core.clj"}
at sci.impl.utils$rethrow_with_location_of_node.invokeStatic (utils.cljc:128)
sci.impl.analyzer$return_call$reify__5234.eval (analyzer.cljc:1211)
sci.impl.analyzer$return_call$reify__5226.eval (analyzer.cljc:1211)
sci.impl.fns$fun$arity_3__3551.invoke (fns.cljc:108)
clojure.lang.AFn.applyToHelper (AFn.java:160)
clojure.lang.AFn.applyTo (AFn.java:144)
clojure.core$apply.invokeStatic (core.clj:667)
sci.impl.fns$eval_fn$fn__4020.doInvoke (fns.cljc:152)
clojure.lang.RestFn.invoke (RestFn.java:436)
sci.lang.Var.invoke (lang.cljc:184)
sci.impl.analyzer$return_call$reify__5234.eval (analyzer.cljc:1211)
sci.impl.evaluator$eval_let$fn__2721.invoke (evaluator.cljc:62)
sci.impl.evaluator$eval_let.invokeStatic (evaluator.cljc:53)
sci.impl.analyzer$analyze_let_STAR_$reify__4891.eval (analyzer.cljc:509)
sci.impl.evaluator$eval_do.invokeStatic (evaluator.cljc:275)
sci.impl.analyzer$return_do$reify__4254.eval (analyzer.cljc:139)
sci.impl.fns$fun$arity_0__3530.invoke (fns.cljc:105)
babashka.impl.clojure.test$test_var_impl$fn__30095.invoke (test.clj:719)
babashka.impl.clojure.test$test_var_impl.invokeStatic (test.clj:719)
babashka.impl.clojure.test$test_var_impl.invoke (test.clj:710)
sci.lang.Var.invoke (lang.cljc:180)
babashka.impl.clojure.test$test_vars$fn__30131$fn__30136.invoke (test.clj:742)
babashka.impl.clojure.test$default_fixture.invokeStatic (test.clj:689)
babashka.impl.clojure.test$default_fixture.invoke (test.clj:685)
babashka.impl.clojure.test$test_vars$fn__30131.invoke (test.clj:742)
babashka.impl.clojure.test$default_fixture.invokeStatic (test.clj:689)
babashka.impl.clojure.test$default_fixture.invoke (test.clj:685)
babashka.impl.clojure.test$test_vars.invokeStatic (test.clj:738)
babashka.impl.clojure.test$test_all_vars.invokeStatic (test.clj:745)
babashka.impl.clojure.test$test_ns.invokeStatic (test.clj:767)
babashka.impl.clojure.test$run_tests$fn__30151.invoke (test.clj:784)
clojure.core$map$fn__5935.invoke (core.clj:2772)
clojure.lang.LazySeq.sval (LazySeq.java:42)
clojure.lang.LazySeq.seq (LazySeq.java:51)
clojure.lang.Cons.next (Cons.java:39)
clojure.lang.RT.boundedLength (RT.java:1790)
clojure.lang.RestFn.applyTo (RestFn.java:130)
clojure.core$apply.invokeStatic (core.clj:669)
babashka.impl.clojure.test$run_tests.invokeStatic (test.clj:777)
babashka.impl.clojure.test$run_tests.doInvoke (test.clj:777)
clojure.lang.RestFn.applyTo (RestFn.java:139)
clojure.core$apply.invokeStatic (core.clj:669)
babashka.impl.test$contextualize$fn__30162.doInvoke (test.clj:7)
clojure.lang.RestFn.invoke (RestFn.java:408)
sci.lang.Var.invoke (lang.cljc:180)
sci.impl.analyzer$return_call$reify__5226.eval (analyzer.cljc:1211)
sci.impl.evaluator$eval_let$fn__2721.invoke (evaluator.cljc:62)
sci.impl.evaluator$eval_let.invokeStatic (evaluator.cljc:53)
sci.impl.analyzer$analyze_let_STAR_$reify__4891.eval (analyzer.cljc:509)
sci.impl.fns$fun$arity_0__3026.doInvoke (fns.cljc:83)
clojure.lang.RestFn.invoke (RestFn.java:397)
clojure.lang.AFn.applyToHelper (AFn.java:152)
clojure.lang.RestFn.applyTo (RestFn.java:132)
clojure.core$apply.invokeStatic (core.clj:667)
clojure.core$apply.invoke (core.clj:662)
sci.lang.Var.invoke (lang.cljc:182)
sci.impl.analyzer$return_call$reify__5230.eval (analyzer.cljc:1211)
sci.impl.interpreter$eval_form.invokeStatic (interpreter.cljc:39)
sci.impl.interpreter$eval_string_STAR_.invokeStatic (interpreter.cljc:61)
sci.core$eval_string_STAR_.invokeStatic (core.cljc:261)
babashka.main$exec$fn__31111$fn__31112.invoke (main.clj:978)
babashka.main$exec$fn__31111.invoke (main.clj:978)
babashka.main$exec.invokeStatic (main.clj:968)
babashka.main$main.invokeStatic (main.clj:1075)
babashka.main$main.doInvoke (main.clj:1050)
clojure.lang.RestFn.applyTo (RestFn.java:137)
clojure.core$apply.invokeStatic (core.clj:667)
babashka.main$_main.invokeStatic (main.clj:1108)
babashka.main$_main.doInvoke (main.clj:1100)
clojure.lang.RestFn.applyTo (RestFn.java:137)
babashka.main.main (:-1)
Caused by: clojure.lang.ExceptionInfo: java.lang.NoClassDefFoundError: org/bouncycastle/crypto/params/Ed25519PrivateKeyParameters
{:type com.jcraft.jsch.JSchException}
at babashka.pods.impl$processor.invokeStatic (impl.clj:205)
babashka.pods.sci$load_pod$fn__27402.invoke (sci.clj:122)
sci.impl.vars$binding_conveyor_fn$fn__424.invoke (vars.cljc:133)
clojure.core$binding_conveyor_fn$fn__5823.invoke (core.clj:2047)
clojure.lang.AFn.call (AFn.java:18)
java.util.concurrent.FutureTask.run (FutureTask.java:264)
java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1128)
java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:628)
java.lang.Thread.run (Thread.java:829)
com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine (PlatformThreads.java:705)
com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine (PosixPlatformThreads.java:202)
If the ssh server has a Banner
setting, that setting is echoed to stdout via the :show-message
method of the user-info structure. You can silence it by building your own user-info structure, but it should be easy to silence the message with the default user-info structure by passing in a simple config argument.
It's kind of an X/Y problem: I need bbssh
to support ED25519 keys, and although it was fixed a couple of versions ago, whenever I pass my ED25519 key as :identity
, I get this exception:
clojure.lang.ExceptionInfo: kdf bcrypt is not available
So I decided to compile bbssh
, thinking it could probably help me debug the thing. But I can't load it:
(pods/load-pod "<skipped>/bbssh/build/bbssh")
just hangs indefinitely. If I grab the precompiled binary, it at least works.
What could be the problem?
$ bb --version
babashka v1.3.186
$ grep -F 'GRAALVM_HOME = ' Makefile
# GRAALVM_HOME = $(HOME)/graalvm-ce-java11-22.2.0
GRAALVM_HOME = /Library/Java/JavaVirtualMachines/graalvm-ce-java11-22.3.1/Contents/Home
$ sw_vers
ProductName: macOS
ProductVersion: 14.0
BuildVersion: 23A344
Both bb
and GraalVM
installed with brew
.
A bug exists when trying to connect to a remote server with just a plain :identity
setting.
https://clojurians.slack.com/archives/CLX41ASCS/p1684437163460199
With ssh I have the option of providing a local socket that forwards to a remote proxy.
Does bbssh support unix socket?
One use case is to connect to docker socket via ssh.
I would like to use https://github.com/lispyclouds/contajners over unix socket for a remote host.
man ssh
-L [bind_address:]port:host:hostport
-L [bind_address:]port:remote_socket
-L local_socket:host:hostport
-L local_socket:remote_socket
Specifies that connections to the given TCP port or Unix socket on the local (client) host are to be forwarded to the given host and port, or Unix socket, on the remote
side. This works by allocating a socket to listen to either a TCP port on the local side, optionally bound to the specified bind_address, or to a Unix socket. Whenever a
connection is made to the local port or socket, the connection is forwarded over the secure channel, and a connection is made to either host port hostport, or the Unix
socket remote_socket, from the remote machine.
reminder to apply the fix from spire
While using the pod to download some files from a remote host the script does not terminate, it gets stuck at the end of the main thread code. I thought it might be due to the thread pool used by agents and added the call to (shutdown-agents)
. However, the script still gets stuck.
I have created a minimal script that reproduces the error:
(ns sample
(:require [babashka.pods :as pods]))
(def bbsh-pod (pods/load-pod 'epiccastle/bbssh "0.5.0"))
(require '[pod.epiccastle.bbssh.core :as ssh])
(require '[pod.epiccastle.bbssh.scp :as scp])
(def user "user")
(def cert "/home/user/.ssh/id_rsa")
;; Main process
(let [session (ssh/ssh "localhost" {:username user :identity cert})
opts {:session session}]
(scp/scp-from "/etc/hosts" "remote-hosts" opts)
(shutdown-agents)
(println "shutdown"))
The script actually downloads the file, but does not terminate. Killing the pod manually with (pods/unload-pod bbsh-pod)
doesn't work either, it blocks on this call also.
How to support ssh-agents? Maybe don't support ssh-agents on windows?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.