基于libssh库建立中转SSH隧道并执行服务器脚本的技术问询
Alright, since you've already got the initial SSH connection from your PC to the gateway (as user1 with password auth) sorted, let's focus on extending that to reach the target server as the www user (passwordless auth) and run your script. Here's how to do it with libssh:
Step 1: Ensure Gateway-to-Server Auth is Set Up
First, double-check that the www user on the gateway has passwordless SSH access to the server. That means:
- The gateway's
wwwuser has an SSH key pair (usually~www/.ssh/id_rsaand~www/.ssh/id_rsa.pub). - The server's
wwwuser has the gateway's public key added to~www/.ssh/authorized_keys(with proper permissions:chmod 700 ~www/.sshandchmod 600 ~www/.ssh/authorized_keys).
This is non-negotiable for passwordless auth—key-based authentication is the way to go here.
Step 2: Use libssh to Extend the Connection to the Server
You have two solid options depending on your needs:
Option A: Run Script via Gateway Channel (Simpler)
If you just need to execute the script and grab output without a full interactive session, this is the quickest approach. Here's a code snippet:
#include <libssh/libssh.h> #include <stdio.h> #include <stdlib.h> int main() { // Assume gateway_session is already connected and authenticated as user1 ssh_session gateway_session = ...; // Your existing session setup // Create a channel on the gateway ssh_channel channel = ssh_channel_new(gateway_session); if (channel == NULL) { fprintf(stderr, "Failed to create channel: %s\n", ssh_get_error(gateway_session)); return 1; } // Open a session channel if (ssh_channel_open_session(channel) != SSH_OK) { fprintf(stderr, "Failed to open session: %s\n", ssh_get_error(gateway_session)); ssh_channel_free(channel); return 1; } // Command to connect to server as www and run your script const char* cmd = "ssh www@server /path/to/your/target_script.sh"; if (ssh_channel_request_exec(channel, cmd) != SSH_OK) { fprintf(stderr, "Failed to execute command: %s\n", ssh_get_error(gateway_session)); ssh_channel_close(channel); ssh_channel_free(channel); return 1; } // Read and print the script's output char buffer[256]; int bytes_read; while ((bytes_read = ssh_channel_read(channel, buffer, sizeof(buffer)-1, 0)) > 0) { buffer[bytes_read] = '\0'; printf("%s", buffer); } // Cleanup resources ssh_channel_send_eof(channel); ssh_channel_close(channel); ssh_channel_free(channel); ssh_disconnect(gateway_session); ssh_free(gateway_session); return 0; }
Option B: Full Nested SSH Session (More Control)
If you need advanced functionality like multiple commands, file transfers, or persistent interactions with the server, set up a proxy jump using libssh to route the server session through your existing gateway connection:
#include <libssh/libssh.h> int main() { // Existing gateway session (connected as user1) ssh_session gateway_session = ...; // Create a new session for the target server ssh_session server_session = ssh_new(); if (server_session == NULL) { fprintf(stderr, "Failed to create server session\n"); return 1; } // Configure server session options ssh_options_set(server_session, SSH_OPTIONS_HOST, "server"); ssh_options_set(server_session, SSH_OPTIONS_USER, "www"); // Use the gateway as a proxy jump ssh_options_set(server_session, SSH_OPTIONS_PROXY_JUMP, gateway_session); // Connect to the server if (ssh_connect(server_session) != SSH_OK) { fprintf(stderr, "Failed to connect to server: %s\n", ssh_get_error(server_session)); ssh_free(server_session); return 1; } // Authenticate with passwordless key auth if (ssh_userauth_publickey_auto(server_session, NULL, NULL) != SSH_OK) { fprintf(stderr, "Failed to authenticate as www: %s\n", ssh_get_error(server_session)); ssh_disconnect(server_session); ssh_free(server_session); return 1; } // Execute your script on the server ssh_channel channel = ssh_channel_new(server_session); if (channel == NULL) { fprintf(stderr, "Failed to create server channel: %s\n", ssh_get_error(server_session)); ssh_disconnect(server_session); ssh_free(server_session); return 1; } if (ssh_channel_open_session(channel) != SSH_OK) { fprintf(stderr, "Failed to open server session: %s\n", ssh_get_error(server_session)); ssh_channel_free(channel); ssh_disconnect(server_session); ssh_free(server_session); return 1; } const char* script_cmd = "/path/to/your/target_script.sh"; if (ssh_channel_request_exec(channel, script_cmd) != SSH_OK) { fprintf(stderr, "Failed to run script: %s\n", ssh_get_error(server_session)); ssh_channel_close(channel); ssh_channel_free(channel); ssh_disconnect(server_session); ssh_free(server_session); return 1; } // Read script output char buffer[256]; int bytes_read; while ((bytes_read = ssh_channel_read(channel, buffer, sizeof(buffer)-1, 0)) > 0) { buffer[bytes_read] = '\0'; printf("%s", buffer); } // Cleanup all resources ssh_channel_send_eof(channel); ssh_channel_close(channel); ssh_channel_free(channel); ssh_disconnect(server_session); ssh_free(server_session); ssh_disconnect(gateway_session); ssh_free(gateway_session); return 0; }
Step 3: Add Robust Error Handling
Don't skip error checking for each libssh call—ssh_get_error() provides detailed messages that can help debug issues like auth failures, connection timeouts, or permission errors on the gateway/server.
Quick Compilation Tip
When building your code, link against libssh with the -lssh flag:
gcc your_tunnel_code.c -o ssh_multi_hop -lssh
内容的提问来源于stack exchange,提问作者Simo Elmou

