ITPub博客

首页 > 应用开发 > IT综合 > 远程命令执行系统实战:基于TCP Socket的安全实现

远程命令执行系统实战:基于TCP Socket的安全实现

投稿 IT综合 作者:bhluo 时间:2025-12-25 14:37:39 0 删除 编辑

# 远程命令执行系统实战:基于TCP Socket的安全实现


远程命令执行是系统管理和运维中的常见需求,通过TCP Socket实现这一功能需要兼顾通信效率和安全性。本文将深入探讨如何构建一个安全可靠的远程命令执行系统,涵盖协议设计、安全机制和完整实现。


## 系统架构设计


系统采用客户端-服务器架构,客户端发送命令请求,服务器执行命令并返回结果。整个系统设计遵循以下原则:


1. **协议先行**:定义清晰的通信协议

2. **安全第一**:实施多层次安全防护

3. **错误处理**:完善的异常处理机制

4. **性能考虑**:支持并发连接和命令执行


## 通信协议设计


协议采用二进制格式,包含认证、命令执行和结果返回三个阶段:


```c

// protocol.h - 通信协议定义

#ifndef PROTOCOL_H

#define PROTOCOL_H


#include <stdint.h>


// 消息类型枚举

typedef enum {

    MSG_TYPE_AUTH = 0x01,        // 认证消息

    MSG_TYPE_CMD_REQ = 0x02,     // 命令请求

    MSG_TYPE_CMD_RES = 0x03,     // 命令结果

    MSG_TYPE_ERROR = 0x04,       // 错误消息

    MSG_TYPE_HEARTBEAT = 0x05    // 心跳消息

} MsgType;


// 状态码定义

typedef enum {

    STATUS_OK = 0x00,

    STATUS_AUTH_FAILED = 0x01,

    STATUS_CMD_EXEC_FAILED = 0x02,

    STATUS_CMD_NOT_ALLOWED = 0x03,

    STATUS_TIMEOUT = 0x04,

    STATUS_INTERNAL_ERROR = 0x05

} StatusCode;


// 协议头结构(固定8字节)

typedef struct {

    uint32_t magic;         // 魔数:0x52434D44 (RCMD)

    uint8_t version;        // 协议版本:1

    uint8_t type;           // 消息类型

    uint16_t length;        // 数据部分长度(不包括头部)

} PacketHeader;


// 认证请求结构

typedef struct {

    uint8_t username_len;   // 用户名长度

    uint8_t token_len;      // 令牌长度

    // 变长数据:用户名 + 认证令牌

} AuthRequest;


// 命令请求结构

typedef struct {

    uint32_t timeout;       // 超时时间(秒)

    uint16_t cmd_len;       // 命令长度

    // 变长数据:命令字符串

} CmdRequest;


// 命令响应结构

typedef struct {

    uint32_t exit_code;     // 命令退出码

    uint32_t output_len;    // 输出长度

    // 变长数据:命令输出

} CmdResponse;


#endif

```


## 服务器端实现


服务器端采用多进程模型,每个客户端连接由独立子进程处理,确保隔离性:


```c

// server.c - 服务器主程序

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <sys/socket.h>

#include <sys/wait.h>

#include <sys/types.h>

#include <sys/time.h>

#include <signal.h>

#include <ctype.h>

#include <errno.h>

#include "protocol.h"


#define PORT 8888

#define BACKLOG 5

#define MAX_CMD_LEN 1024

#define MAX_OUTPUT_LEN 4096

#define DEFAULT_TIMEOUT 30


// 全局配置

typedef struct {

    char *allowed_commands[50];

    int cmd_count;

    char *auth_token;

    int max_clients;

    int default_timeout;

} ServerConfig;


// 安全命令列表

const char *DEFAULT_ALLOWED_COMMANDS[] = {

    "ls", "ls -l", "ls -la",

    "pwd", "whoami", "hostname",

    "date", "uptime", "free -h",

    "df -h", "ps aux", "netstat -tln",

    "ifconfig", "ping -c 3", "traceroute",

    NULL

};


// 初始化配置

void init_config(ServerConfig *config) {

    config->auth_token = "secure_token_2024";

    config->max_clients = 100;

    config->default_timeout = DEFAULT_TIMEOUT;

    config->cmd_count = 0;

    

    // 加载允许的命令

    for (int i = 0; DEFAULT_ALLOWED_COMMANDS[i] != NULL; i++) {

        config->allowed_commands[config->cmd_count++] = 

            strdup(DEFAULT_ALLOWED_COMMANDS[i]);

    }

}


// 检查命令是否允许执行

int is_command_allowed(ServerConfig *config, const char *cmd) {

    // 安全检查:过滤危险字符

    const char *danger_chars = "&|;><`$(){}[]\"'\\";

    for (int i = 0; danger_chars[i] != '\0'; i++) {

        if (strchr(cmd, danger_chars[i]) != NULL) {

            return 0;

        }

    }

    

    // 检查命令是否在允许列表中

    for (int i = 0; i < config->cmd_count; i++) {

        if (strncmp(cmd, config->allowed_commands[i], 

                   strlen(config->allowed_commands[i])) == 0) {

            // 确保命令完全匹配或以空格分隔参数

            size_t len = strlen(config->allowed_commands[i]);

            if (cmd[len] == '\0' || cmd[len] == ' ') {

                return 1;

            }

        }

    }

    return 0;

}


// 读取完整数据包

int read_packet(int sock_fd, void *buf, size_t len, int timeout_sec) {

    fd_set fds;

    struct timeval tv;

    size_t total_read = 0;

    

    while (total_read < len) {

        FD_ZERO(&fds);

        FD_SET(sock_fd, &fds);

        

        tv.tv_sec = timeout_sec;

        tv.tv_usec = 0;

        

        int ret = select(sock_fd + 1, &fds, NULL, NULL, &tv);

        if (ret <= 0) {

            return -1; // 超时或错误

        }

        

        ssize_t n = read(sock_fd, (char*)buf + total_read, len - total_read);

        if (n <= 0) {

            return -1; // 连接关闭或错误

        }

        total_read += n;

    }

    return 0;

}


// 处理认证请求

int handle_auth(int sock_fd, ServerConfig *config) {

    PacketHeader header;

    if (read_packet(sock_fd, &header, sizeof(header), 5) < 0) {

        return -1;

    }

    

    // 验证协议头

    header.magic = ntohl(header.magic);

    header.length = ntohs(header.length);

    

    if (header.magic != 0x52434D44 || header.type != MSG_TYPE_AUTH) {

        return -1;

    }

    

    // 读取认证数据

    char *auth_data = malloc(header.length + 1);

    if (!auth_data) return -1;

    

    if (read_packet(sock_fd, auth_data, header.length, 5) < 0) {

        free(auth_data);

        return -1;

    }

    auth_data[header.length] = '\0';

    

    // 解析认证信息

    AuthRequest *auth_req = (AuthRequest*)auth_data;

    char *username = auth_data + sizeof(AuthRequest);

    char *token = username + auth_req->username_len;

    

    // 验证令牌

    int authenticated = 0;

    if (auth_req->token_len == strlen(config->auth_token) &&

        memcmp(token, config->auth_token, auth_req->token_len) == 0) {

        authenticated = 1;

    }

    

    // 发送认证响应

    PacketHeader resp_header;

    resp_header.magic = htonl(0x52434D44);

    resp_header.version = 1;

    resp_header.type = authenticated ? MSG_TYPE_AUTH : MSG_TYPE_ERROR;

    resp_header.length = htons(sizeof(StatusCode));

    

    write(sock_fd, &resp_header, sizeof(resp_header));

    

    StatusCode status = authenticated ? STATUS_OK : STATUS_AUTH_FAILED;

    write(sock_fd, &status, sizeof(status));

    

    // 记录日志

    time_t now = time(NULL);

    printf("[%ld] 用户 %.*s 认证 %s\n", 

           now, auth_req->username_len, username,

           authenticated ? "成功" : "失败");

    

    free(auth_data);

    return authenticated ? 0 : -1;

}


// 执行命令并捕获输出

int execute_command(const char *cmd, int timeout, char *output, int output_size) {

    int stdout_pipe[2], stderr_pipe[2];

    

    if (pipe(stdout_pipe) < 0 || pipe(stderr_pipe) < 0) {

        return -1;

    }

    

    pid_t pid = fork();

    if (pid < 0) {

        close(stdout_pipe[0]); close(stdout_pipe[1]);

        close(stderr_pipe[0]); close(stderr_pipe[1]);

        return -1;

    }

    

    if (pid == 0) {

        // 子进程:设置进程组

        setpgid(0, 0);

        

        // 重定向输出

        dup2(stdout_pipe[1], STDOUT_FILENO);

        dup2(stderr_pipe[1], STDERR_FILENO);

        

        // 关闭不需要的文件描述符

        close(stdout_pipe[0]); close(stdout_pipe[1]);

        close(stderr_pipe[0]); close(stderr_pipe[1]);

        

        // 执行命令

        execl("/bin/bash", "bash", "-c", cmd, NULL);

        exit(127); // exec失败

    }

    

    // 父进程

    close(stdout_pipe[1]);

    close(stderr_pipe[1]);

    

    // 设置超时

    fd_set readfds;

    struct timeval tv;

    int max_fd = stdout_pipe[0] > stderr_pipe[0] ? 

                 stdout_pipe[0] : stderr_pipe[0];

    

    FD_ZERO(&readfds);

    FD_SET(stdout_pipe[0], &readfds);

    FD_SET(stderr_pipe[0], &readfds);

    

    tv.tv_sec = timeout;

    tv.tv_usec = 0;

    

    int ret = select(max_fd + 1, &readfds, NULL, NULL, &tv);

    

    if (ret == 0) {

        // 超时,终止进程组

        kill(-pid, SIGKILL);

        waitpid(pid, NULL, 0);

        close(stdout_pipe[0]);

        close(stderr_pipe[0]);

        return -2;

    }

    

    // 读取输出

    output[0] = '\0';

    char buffer[256];

    ssize_t n;

    

    // 读取标准输出

    while ((n = read(stdout_pipe[0], buffer, sizeof(buffer)-1)) > 0) {

        buffer[n] = '\0';

        if (strlen(output) + n < output_size - 100) {

            strcat(output, buffer);

        }

    }

    

    // 读取标准错误

    strcat(output, "\n--- stderr ---\n");

    while ((n = read(stderr_pipe[0], buffer, sizeof(buffer)-1)) > 0) {

        buffer[n] = '\0';

        if (strlen(output) + n < output_size - 1) {

            strcat(output, buffer);

        }

    }

    

    // 等待子进程结束

    int status;

    waitpid(pid, &status, 0);

    

    close(stdout_pipe[0]);

    close(stderr_pipe[0]);

    

    return WEXITSTATUS(status);

}


// 处理命令请求

void handle_command(int sock_fd, ServerConfig *config) {

    PacketHeader header;

    CmdRequest cmd_req;

    

    // 读取命令请求头

    if (read_packet(sock_fd, &header, sizeof(header), 10) < 0) {

        return;

    }

    

    header.magic = ntohl(header.magic);

    header.length = ntohs(header.length);

    

    if (header.magic != 0x52434D44 || header.type != MSG_TYPE_CMD_REQ) {

        send_error(sock_fd, STATUS_INTERNAL_ERROR);

        return;

    }

    

    // 读取命令请求体

    if (read_packet(sock_fd, &cmd_req, sizeof(cmd_req), 10) < 0) {

        send_error(sock_fd, STATUS_INTERNAL_ERROR);

        return;

    }

    

    cmd_req.timeout = ntohl(cmd_req.timeout);

    cmd_req.cmd_len = ntohs(cmd_req.cmd_len);

    

    if (cmd_req.cmd_len == 0 || cmd_req.cmd_len > MAX_CMD_LEN) {

<"4f.xingjungy.cn"><"6j.xingjungy.cn"><"2z.xingjungy.cn">

        send_error(sock_fd, STATUS_CMD_NOT_ALLOWED);

        return;

    }

    

    // 读取命令字符串

    char command[MAX_CMD_LEN + 1];

    if (read_packet(sock_fd, command, cmd_req.cmd_len, 10) < 0) {

        send_error(sock_fd, STATUS_INTERNAL_ERROR);

        return;

    }

    command[cmd_req.cmd_len] = '\0';

    

    // 验证命令

    if (!is_command_allowed(config, command)) {

        send_error(sock_fd, STATUS_CMD_NOT_ALLOWED);

        return;

    }

    

    // 设置执行超时

    int timeout = cmd_req.timeout > 0 ? cmd_req.timeout : config->default_timeout;

    if (timeout > 300) timeout = 300; // 限制最大5分钟

    

    // 执行命令

    char output[MAX_OUTPUT_LEN];

    int exit_code = execute_command(command, timeout, output, sizeof(output));

    

    // 发送响应

    PacketHeader resp_header;

    resp_header.magic = htonl(0x52434D44);

    resp_header.version = 1;

    

    if (exit_code >= 0) {

        resp_header.type = MSG_TYPE_CMD_RES;

        CmdResponse cmd_res;

        cmd_res.exit_code = htonl(exit_code);

        cmd_res.output_len = htonl(strlen(output));

        

        resp_header.length = htons(sizeof(cmd_res) + strlen(output));

        

        write(sock_fd, &resp_header, sizeof(resp_header));

        write(sock_fd, &cmd_res, sizeof(cmd_res));

        write(sock_fd, output, strlen(output));

    } else if (exit_code == -2) {

        send_error(sock_fd, STATUS_TIMEOUT);

    } else {

        send_error(sock_fd, STATUS_CMD_EXEC_FAILED);

    }

    

    // 记录日志

    time_t now = time(NULL);

    printf("[%ld] 执行命令: %s (退出码: %d)\n", 

           now, command, exit_code);

}


// 发送错误响应

void send_error(int sock_fd, StatusCode error_code) {

    PacketHeader header;

    header.magic = htonl(0x52434D44);

    header.version = 1;

    header.type = MSG_TYPE_ERROR;

    header.length = htons(sizeof(StatusCode));

    

    write(sock_fd, &header, sizeof(header));

    write(sock_fd, &error_code, sizeof(error_code));

}


// 客户端处理函数

void handle_client(int sock_fd, ServerConfig *config) {

    // 设置进程标题

    char proc_title[32];

    snprintf(proc_title, sizeof(proc_title), "rcmd-client-%d", sock_fd);

    

    // 认证

    if (handle_auth(sock_fd, config) < 0) {

        close(sock_fd);

        exit(0);

    }

    

    // 命令处理循环

    while (1) {

        // 设置接收超时

        struct timeval tv = {300, 0}; // 5分钟

        setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

        

        PacketHeader header;

        ssize_t n = recv(sock_fd, &header, sizeof(header), MSG_PEEK);

        

        if (n <= 0) {

            break; // 连接关闭或超时

        }

        

        if (n == sizeof(header)) {

            recv(sock_fd, &header, sizeof(header), 0);

            header.magic = ntohl(header.magic);

            

            if (header.magic == 0x52434D44) {

                switch (header.type) {

                    case MSG_TYPE_CMD_REQ:

                        handle_command(sock_fd, config);

                        break;

                    case MSG_TYPE_HEARTBEAT:

                        // 心跳包响应

                        header.type = MSG_TYPE_HEARTBEAT;

                        header.length = 0;

                        send(sock_fd, &header, sizeof(header), 0);

                        break;

                    default:

                        send_error(sock_fd, STATUS_INTERNAL_ERROR);

                        break;

                }

            }

        }

    }

    

    close(sock_fd);

    exit(0);

}


int main() {

    int server_fd;

    struct sockaddr_in addr;

    ServerConfig config;

    

    // 初始化配置

    init_config(&config);

    

    // 创建socket

    server_fd = socket(AF_INET, SOCK_STREAM, 0);

    if (server_fd < 0) {

        perror("socket创建失败");

        return 1;

    }

    

    // 设置socket选项

    int opt = 1;

    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    

    // 绑定地址

    addr.sin_family = AF_INET;

    addr.sin_addr.s_addr = INADDR_ANY;

    addr.sin_port = htons(PORT);

    

    if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {

        perror("绑定地址失败");

        close(server_fd);

        return 1;

    }

    

    // 监听

    if (listen(server_fd, BACKLOG) < 0) {

        perror("监听失败");

        close(server_fd);

        return 1;

    }

    

    printf("远程命令执行服务器启动,端口: %d\n", PORT);

    printf("认证令牌: %s\n", config.auth_token);

    printf("允许的命令数量: %d\n", config.cmd_count);

    

    // 忽略子进程退出信号

    signal(SIGCHLD, SIG_IGN);

    

    // 主循环

    while (1) {

        struct sockaddr_in client_addr;

        socklen_t client_len = sizeof(client_addr);

        

        int client_fd = accept(server_fd, 

                              (struct sockaddr*)&client_addr, 

                              &client_len);

        

        if (client_fd < 0) {

            if (errno == EINTR) continue;

            perror("接受连接失败");

            continue;

        }

        

        printf("新客户端: %s:%d\n", 

               inet_ntoa(client_addr.sin_addr),

               ntohs(client_addr.sin_port));

        

        // 创建子进程处理客户端

        pid_t pid = fork();

        if (pid < 0) {

            perror("创建子进程失败");

            close(client_fd);

            continue;

        }

        

        if (pid == 0) {

            // 子进程

            close(server_fd);

            handle_client(client_fd, &config);

        } else {

            // 父进程

            close(client_fd);

        }

    }

    

    close(server_fd);

    return 0;

}

```


## 客户端实现


客户端提供交互式界面,支持命令执行和结果查看:


```c

// client.c - 客户端程序

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <sys/socket.h>

#include <readline/readline.h>

#include <readline/history.h>

#include "protocol.h"


#define SERVER_IP "127.0.0.1"

#define SERVER_PORT 8888

#define AUTH_TOKEN "secure_token_2024"


// 连接服务器

int connect_to_server(const char *ip, int port) {

    int sock_fd = socket(AF_INET, SOCK_STREAM, 0);

    if (sock_fd < 0) {

        perror("创建socket失败");

        return -1;

    }

    

    struct sockaddr_in addr;

    addr.sin_family = AF_INET;

    addr.sin_port = htons(port);

    

    if (inet_pton(AF_INET, ip, &addr.sin_addr) <= 0) {

        perror("无效的IP地址");

        close(sock_fd);

        return -1;

    }

    

    if (connect(sock_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {

        perror("连接服务器失败");

        close(sock_fd);

        return -1;

    }

    

    // 设置socket选项

    struct timeval tv = {10, 0}; // 10秒超时

    setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

    

    return sock_fd;

}


// 发送认证请求

int send_auth_request(int sock_fd, const char *username) {

    PacketHeader header;

    header.magic = htonl(0x52434D44);

    header.version = 1;

    header.type = MSG_TYPE_AUTH;

    

    // 构建认证数据

    size_t username_len = strlen(username);

    size_t token_len = strlen(AUTH_TOKEN);

    size_t total_len = sizeof(AuthRequest) + username_len + token_len;

    

    header.length = htons(total_len);

    

    // 发送协议头

    if (send(sock_fd, &header, sizeof(header), 0) != sizeof(header)) {

        return -1;

    }

    

    // 发送认证数据

    AuthRequest auth_req;

    auth_req.username_len = username_len;

    auth_req.token_len = token_len;

    

    send(sock_fd, &auth_req, sizeof(auth_req), 0);

    send(sock_fd, username, username_len, 0);

    send(sock_fd, AUTH_TOKEN, token_len, 0);

    

    // 接收响应

    if (recv(sock_fd, &header, sizeof(header), 0) != sizeof(header)) {

        return -1;

    }

    

    header.magic = ntohl(header.magic);

    header.length = ntohs(header.length);

    

    if (header.magic != 0x52434D44) {

        return -1;

    }

    

    StatusCode status;

    if (recv(sock_fd, &status, sizeof(status), 0) != sizeof(status)) {

        return -1;

    }

    

    return (status == STATUS_OK) ? 0 : -1;

}


// 执行远程命令

int execute_remote_command(int sock_fd, const char *cmd, int timeout) {

    PacketHeader header;

    header.magic = htonl(0x52434D44);

    header.version = 1;

    header.type = MSG_TYPE_CMD_REQ;

    <"1q.xingjungy.cn">


    // 构建命令请求

    CmdRequest cmd_req;

    cmd_req.timeout = htonl(timeout);

    cmd_req.cmd_len = htons(strlen(cmd));

    

    size_t total_len = sizeof(cmd_req) + strlen(cmd);

    header.length = htons(total_len);

    

    // 发送请求

    send(sock_fd, &header, sizeof(header), 0);

    send(sock_fd, &cmd_req, sizeof(cmd_req), 0);

    send(sock_fd, cmd, strlen(cmd), 0);

    

    // 接收响应

    if (recv(sock_fd, &header, sizeof(header), 0) != sizeof(header)) {

        return -1;

    }

    

    header.magic = ntohl(header.magic);

    header.length = ntohs(header.length);

    

    if (header.magic != 0x52434D44) {

        printf("协议错误\n");

        return -1;

    }

    

    // 处理响应

    if (header.type == MSG_TYPE_CMD_RES) {

<"5a.xingjungy.cn"><"8t.xingjungy.cn">

        CmdResponse cmd_res;

        if (recv(sock_fd, &cmd_res, sizeof(cmd_res), 0) != sizeof(cmd_res)) {

            return -1;

        }

        

        cmd_res.exit_code = ntohl(cmd_res.exit_code);

        cmd_res.output_len = ntohl(cmd_res.output_len);

        

        // 读取命令输出

        if (cmd_res.output_len > 0) {

            char *output = malloc(cmd_res.output_len + 1);

            if (output) {

                size_t total = 0;

                while (total < cmd_res.output_len) {

                    ssize_t n = recv(sock_fd, output + total, 

                                    cmd_res.output_len - total, 0);

                    if (n <= 0) break;

                    total += n;

                }

                output[cmd_res.output_len] = '\0';

                printf("%s\n", output);

                free(output);

            }

        }

        

        printf("退出码: %d\n", cmd_res.exit_code);

        return cmd_res.exit_code;

    } else if (header.type == MSG_TYPE_ERROR) {

        StatusCode error_code;

        if (recv(sock_fd, &error_code, sizeof(error_code), 0) != sizeof(error_code)) {

            return -1;

        }

        

        switch (error_code) {

            case STATUS_AUTH_FAILED:

                printf("错误: 认证失败\n");

                break;

            case STATUS_CMD_NOT_ALLOWED:

                printf("错误: 命令不允许执行\n");

                break;

            case STATUS_TIMEOUT:

                printf("错误: 命令执行超时\n");

                break;

            default:

                printf("错误: 服务器内部错误\n");

        }

        return -1;

    }

    

    return -1;

}


// 主函数

int main(int argc, char *argv[]) {

    printf("远程命令执行客户端\n");

    printf("==================\n");

    

    // 连接服务器

    int sock_fd = connect_to_server(SERVER_IP, SERVER_PORT);

    if (sock_fd < 0) {

        return 1;

    }

    

    // 获取用户名

    char *username = getenv("USER");

    if (!username) username = "unknown";

    

    // 认证

    if (send_auth_request(sock_fd, username) < 0) {

        printf("认证失败\n");

        close(sock_fd);

        return 1;

    }

    

    printf("认证成功!已连接到服务器\n");

    printf("输入 'exit' 或 'quit' 退出\n");

    printf("输入 'help' 查看可用命令\n\n");

    

    // 主循环

    while (1) {

        char *input = readline("remote> ");

        if (!input) break;

        

        // 添加历史记录

        if (strlen(input) > 0) {

            add_history(input);

        }

        

        // 退出命令

        if (strcmp(input, "exit") == 0 || strcmp(input, "quit") == 0) {

            free(input);

            break;

        }

        

        // 帮助命令

        if (strcmp(input, "help") == 0) {

            printf("可用命令示例:\n");

            printf("  ls, pwd, whoami, date\n");

            printf("  df -h, ps aux, free -h\n");

            printf("  ping -c 3 google.com\n");

            printf("  支持大多数常见系统命令\n");

            free(input);

            continue;

        }

        

        // 执行远程命令

        if (strlen(input) > 0) {

            int result = execute_remote_command(sock_fd, input, 30);

            if (result < 0 && result != -2) {

                printf("命令执行失败\n");

            }

        }

        

        free(input);

    }

    

    close(sock_fd);

    printf("客户端退出\n");

    return 0;

}

```


## 编译和运行


```bash

# 编译服务器

gcc -o rcmd_server server.c -lpthread


# 编译客户端

gcc -o rcmd_client client.c -lreadline


# 启动服务器(需要端口权限)

sudo ./rcmd_server


# 在另一个终端启动客户端

./rcmd_client

```


## 安全增强建议


1. **SSL/TLS加密**:使用OpenSSL实现传输加密

2. **审计日志**:记录所有命令执行和访问

3. **双因素认证**:增加额外的认证方式

4. **命令白名单**:严格限制可执行命令

5. **资源限制**:限制命令执行时间和资源使用

6. **IP白名单**:限制可连接的客户端IP


## 调试和故障排除


```bash

# 查看服务器日志

tail -f /var/log/syslog | grep rcmd


# 网络连接检查

netstat -tlnp | grep 8888


# 使用strace调试

strace -f -e trace=network -p $(pidof rcmd_server)


# 使用tcpdump分析流量

tcpdump -i lo port 8888 -X

```


## 总结


通过实现远程命令执行系统,我们深入掌握了TCP Socket编程的多个关键方面。从协议设计、安全机制、并发处理到错误恢复,这个项目涵盖了构建生产级网络应用所需的核心技术。


安全始终是远程执行系统的首要考虑因素。通过实施多层安全防护,包括认证、命令验证、输入过滤和资源限制,可以构建出既实用又安全的远程管理系统。


这个系统可以作为许多实际应用的基础框架,经过适当扩展和增强,可以用于系统监控、自动化运维、远程管理等场景。掌握这些核心技术,将为开发更复杂的分布式系统和服务打下坚实基础。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3106259/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2015-11-01

  • 博文量
    895
  • 访问量
    933564