NAME

Net::LibSSH - Perl binding for libssh — SSH without SFTP dependency

VERSION

version 0.004

SYNOPSIS

use Net::LibSSH;

my $ssh = Net::LibSSH->new;
$ssh->option(host => 'server.example.com');
$ssh->option(user => 'root');
$ssh->option(port => 22);

$ssh->connect or die "connect failed: " . $ssh->error;
$ssh->auth_agent or die "auth failed: " . $ssh->error;

my $ch = $ssh->channel;
$ch->exec("uname -r");
my $out = $ch->read;
print "Kernel: $out";
print "Exit: ", $ch->exit_status, "\n";

# Optional SFTP (returns undef if SFTP subsystem not available)
if (my $sftp = $ssh->sftp) {
  my $attr = $sftp->stat('/etc/hostname');
  print "size: $attr->{size}\n" if $attr;
}

DESCRIPTION

Net::LibSSH is a Perl XS binding for libssh.

Unlike Net::SSH2 (which wraps libssh2) and Net::OpenSSH (which wraps the system ssh binary), this module links directly against libssh — a separate, actively maintained C library. The key difference for automation use cases: what this module exposes are exec channels via Net::LibSSH::Channel, not a file transfer API. File operations are built on top of those channels — as Rex::LibSSH does — and therefore need no SFTP subsystem on the remote host.

SFTP is supported as an optional feature via "sftp": it returns undef gracefully when the remote server has no SFTP subsystem, rather than crashing.

By default, "connect" verifies the server's host key against knownhosts the same way an interactive ssh client would, and refuses to connect — returning 0, not dying — when the key is unknown, has changed, or cannot be verified. See "connect" for the exact refusal messages and option() for turning that off.

Note: This module is not thread-safe and does not support fork. Use one connection per process.

METHODS

new

my $ssh = Net::LibSSH->new;

Creates a new session object.

option($key, $value)

$ssh->option(host => 'server.example.com');
$ssh->option(port => 22);
$ssh->option(user => 'root');

Set a session option before connecting. Supported keys: host, port, user, knownhosts, timeout, compression, log_verbosity, strict_hostkeycheck.

strict_hostkeycheck controls whether "connect" verifies the server's host key against knownhosts, mirroring libssh's own default: leaving it unset, or setting it to a true value, leaves verification on — the secure default. Setting it to 0 turns verification off entirely: connect then skips the known_hosts check altogether, so it will connect through an unknown or a changed host key without complaint, and without ever writing to knownhosts either way. knownhosts names the file consulted; left unset, that is libssh's own default of ~/.ssh/known_hosts.

Croaks if $key is not one of the keys above, or if libssh rejects the resulting value. $value is not validated on this side of the boundary — numeric options go through Perl's ordinary numeric conversion, so a non-numeric string silently becomes 0 — and whether that ends up croaking is entirely libssh's call, not something you can rely on uniformly. For example, port => 'nonsense' croaks (libssh rejects port 0), while timeout => 'nonsense' or log_verbosity => 'nonsense' are silently accepted as 0. Do not read the absence of a croak here as validation.

connect

$ssh->connect or die $ssh->error;

Connect to the host. Returns 1 on success, 0 on failure, and never dies — including when called on a session that has already been connected and disconnected, see "disconnect".

When strict_hostkeycheck is on (the default, see option()), a successful TCP connection and key exchange is not by itself enough: connect then verifies the server's host key against knownhosts before reporting success, the same check an interactive ssh client makes before it would prompt to trust a new key — except this module never prompts and never writes the file, so it can only refuse. Only a match against the key libssh already has on file for this host lets connect return 1. Every other outcome is a refusal: connect returns 0, the reason is on "error", and the session is left exactly as spent as if "disconnect" had been called on it — a later connect on it returns 0 with "session was disconnected and cannot be reconnected". The refusal messages are:

the host is not in knownhosts

"host key is not in known_hosts and strict_hostkeycheck is on"

the host is known, but under a different key

"host key has changed from the known_hosts entry -- possible man-in-the-middle attack"

the host is known, but under a different key type

"host key type differs from the known_hosts entry -- possible man-in-the-middle attack"

knownhosts exists but could not be read

"could not verify host key against known_hosts"

There is no equivalent here of an interactive client's "yes, trust this key" prompt: a host has to be added to knownhosts out of band — ssh-keyscan, or letting an actual ssh client connect to it once — before connect will accept it, or verification has to be turned off with strict_hostkeycheck => 0, see option(). A host reachable on a non-standard port needs the [host]:port form in knownhosts; libssh looks the entry up under that form, not under the bare hostname.

With strict_hostkeycheck off, none of the above runs: connect returns 1 on a successful key exchange regardless of what knownhosts says, or whether the host is in it at all.

disconnect

$ssh->disconnect;

Disconnect from the host. Every Net::LibSSH::Channel and Net::LibSSH::SFTP object already opened on this session is invalidated by the same call — libssh frees the channels as part of disconnecting. From that point on, every method on such an object but close croaks with "session was disconnected", a message distinct from a channel's own "channel is closed" so a caller can tell its own teardown from this one; see "close" in Net::LibSSH::Channel. Closing such a channel, or simply letting it or an SFTP object go out of scope, is safe and does nothing.

$ssh->channel and $ssh->sftp called on a session that has already disconnected return undef rather than croaking — the same graceful-failure contract they already have for any other failure to open.

The session itself is not reusable once it has actually been connected and then disconnected: calling "connect" again on it returns 0 immediately, with error() reporting "session was disconnected and cannot be reconnected". This module refuses the call itself, without asking libssh — measured against libssh 0.10.6, ssh_connect() on such a session does not fail fast, it sits out the whole timeout option and only then reports a misleading "Timeout connecting to ...". Treat disconnect/connect as one-way — not a cycle you can repeat on the same session.

Calling disconnect on a session that was never successfully connected does not spend it: a later "connect" on it still works normally. Only a connect/disconnect pair is terminal, not the mere act of disconnecting.

error

my $msg = $ssh->error;

Return the last error message from libssh, or undef — not the empty string — when libssh has nothing to report. A few messages are this module's own rather than libssh's, and take precedence over whatever libssh has to say: the spent-session refusal described in "disconnect", and the host-key refusals "connect" raises when strict_hostkeycheck rejects the server's key.

auth_password($password)

$ssh->auth_password('s3cr3t') or die $ssh->error;

auth_publickey($privkey_path)

$ssh->auth_publickey('/root/.ssh/id_ed25519') or die $ssh->error;

auth_agent

$ssh->auth_agent or die $ssh->error;

Authenticate via the SSH agent, falling back to the default key files (public-key auto-authentication) whenever the agent attempt does not succeed — not only when no agent is running, but also when a reachable agent's authentication is rejected. A true return therefore does not by itself prove that the agent was used; it only means one of the two methods succeeded.

channel

my $ch = $ssh->channel;

Open a new session channel. Returns a Net::LibSSH::Channel object, or undef on failure — including when called on a session that has already disconnected, see "disconnect". The returned channel keeps this session alive on its own; see Net::LibSSH::Channel for what that guarantees and what it does not.

sftp

my $sftp = $ssh->sftp;  # returns undef if SFTP not available

Open an SFTP session. Returns a Net::LibSSH::SFTP object, or undef if the remote server does not support SFTP. This is the documented way to detect SFTP availability — sftp never throws for that reason, on this or any other failure to open the session, including being called on a session that has already disconnected, see "disconnect". Like "channel", the returned object keeps this session alive on its own.

SEE ALSO

Net::LibSSH::Channel, Net::LibSSH::SFTP, Alien::libssh, Net::SSH2

SUPPORT

Issues

Please report bugs and feature requests on GitHub at https://github.com/Getty/p5-net-libssh/issues.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <getty@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.