Quantcast
Channel: Active questions tagged ubuntu - Stack Overflow
Viewing all articles
Browse latest Browse all 7069

C++ Client-Server app (server works on windows client works on ubuntu)

$
0
0

This application allows you to organize a client-server application. Which is intended for sending commands to clients. Each client is processed in a separate thread, and each client can have an unlimited number of sessions. If you want to run this code on your machine, you need to add 2 things to the client code. This is the ip of the machine on which you want to run the server and the password for the "su" command, I hope that you have already set it. This is necessary if you plan to upgrade the bash session privilege to root. All commands are sent from the server. Example of commands.after the user is connected, you select the active user with the command "change 1" 1 this is the user id.after you create a new shell, the "new_shell" command creates a new shell with a unique ID. The following command is "switch_shell 1" 1 this is the shell ID. Now you can send commands like "ip a", "ls", "ps aux" and others, and most importantly, you can send the su command to upgrade to root.

Server(Windows)code

#include <iostream>#include <string>#include <list>#include <vector>#include <winsock2.h>#include <windows.h>#include <ws2tcpip.h>#include <thread>#include <atomic>#include <mutex>#include <unordered_map>#pragma comment(lib, "ws2_32.lib")std::mutex clientsMutex; // Мьютексдлясинхронизациидоступакспискуклиентовclass ClientHandler {public:    SOCKET socket;    int clientID;    std::atomic<bool> running;    ClientHandler(SOCKET sock, int id) : socket(sock), clientID(id), running(true) {}    // Удаляемконструкторкопированияиоператорприсваивания    ClientHandler(const ClientHandler&) = delete;    ClientHandler& operator=(const ClientHandler&) = delete;    void SendCommand(const std::string& command) {        if (send(socket, command.c_str(), static_cast<int>(command.size()), 0) == SOCKET_ERROR) {            std::cerr << "Error: Failed to send command to ClientID: " << clientID << std::endl;            running = false;        }    }    std::string ReceiveResult() {        // Сначалаполучаемдлинусообщения        uint32_t messageLength;        int bytesReceived = recv(socket, reinterpret_cast<char*>(&messageLength), sizeof(messageLength), 0);        if (bytesReceived <= 0) {            running = false;            return "";        }        // Преобразуемдлинусообщенияизсетевогопорядкабайтвхостовый        messageLength = ntohl(messageLength);        // Получаемсамосообщение        std::string result;        result.resize(messageLength);        char* buffer = &result[0];        int totalReceived = 0;        while (totalReceived < static_cast<int>(messageLength)) {            bytesReceived = recv(socket, buffer + totalReceived, static_cast<int>(messageLength - totalReceived), 0);            if (bytesReceived <= 0) {                running = false;                return "";            }            totalReceived += bytesReceived;        }        return result;    }};class Server {private:    std::list<ClientHandler> clients; // Списокклиентов    std::vector<std::thread> clientThreads; // Потокидляобработкиклиентов    std::unordered_map<int, int> activeSessions; // Активныесессии (clientID -> sessionID)    std::mutex sessionsMutex; // Мьютексдлясинхронизациидоступакактивнымсессиям    std::atomic<bool> running;    int activeClientID = -1; // ID активногоклиента    void HandleClient(ClientHandler& client) {        while (client.running) {            std::string result = client.ReceiveResult();            if (!result.empty()) {                std::cout << "Result from ClientID " << client.clientID << ":\n" << result << std::endl;            }            else {                std::cerr << "ClientID " << client.clientID << " disconnected." << std::endl;                break;            }        }        // Удаляемклиентаизсписка        std::lock_guard<std::mutex> lock(clientsMutex);        clients.remove_if([&client](const ClientHandler& c) { return c.clientID == client.clientID; });    }public:    Server() : running(true) {}    void Run() {        WSADATA wsaData;        if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {            std::cerr << "WSAStartup failed." << std::endl;            return;        }        SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);        if (serverSocket == INVALID_SOCKET) {            std::cerr << "Socket creation failed." << std::endl;            WSACleanup();            return;        }        sockaddr_in serverAddr;        serverAddr.sin_family = AF_INET;        serverAddr.sin_addr.s_addr = INADDR_ANY;        serverAddr.sin_port = htons(12345);        if (bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {            std::cerr << "Bind failed." << std::endl;            closesocket(serverSocket);            WSACleanup();            return;        }        if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR) {            std::cerr << "Listen failed." << std::endl;            closesocket(serverSocket);            WSACleanup();            return;        }        std::cout << "Server is running. Waiting for clients..." << std::endl;        while (running) {            SOCKET clientSocket = accept(serverSocket, NULL, NULL);            if (clientSocket == INVALID_SOCKET) {                std::cerr << "Accept failed." << std::endl;                continue;            }            std::lock_guard<std::mutex> lock(clientsMutex);            int clientID = clients.size() + 1;            clients.emplace_back(clientSocket, clientID);            clientThreads.emplace_back(&Server::HandleClient, this, std::ref(clients.back()));            std::cout << "Client connected. ClientID: " << clientID << std::endl;        }        closesocket(serverSocket);        WSACleanup();    }    void HandleCommands() {        std::string command;        while (true) {            std::cout << "Enter command: ";            std::getline(std::cin, command);            if (command.substr(0, 6) == "change") {                // Выборактивногоклиента                int id = std::stoi(command.substr(7));                std::lock_guard<std::mutex> lock(clientsMutex);                auto it = std::find_if(clients.begin(), clients.end(), [id](const ClientHandler& client) {                    return client.clientID == id;                    });                if (it != clients.end()) {                    activeClientID = id;                    std::cout << "Selected ClientID: " << id << std::endl;                }                else {                    std::cout << "ClientID not found." << std::endl;                }            }            else if (command == "list") {                // Списокподключенныхклиентов                std::lock_guard<std::mutex> lock(clientsMutex);                std::cout << "Connected clients:" << std::endl;                for (const auto& client : clients) {                    std::cout << "ClientID: " << client.clientID << std::endl;                }            }            else if (command == "exit") {                running = false;                break;            }            else {                // Отправкакомандыактивномуклиенту                if (activeClientID == -1) {                    std::cout << "No client selected. Use 'change <client_id>' to select a client." << std::endl;                    continue;                }                std::lock_guard<std::mutex> lock(clientsMutex);                auto it = std::find_if(clients.begin(), clients.end(), [this](const ClientHandler& client) {                    return client.clientID == activeClientID;                    });                if (it != clients.end()) {                    it->SendCommand(command);                }                else {                    std::cout << "Active client not found." << std::endl;                }            }        }    }};int main() {    Server server;    std::thread serverThread([&server]() { server.Run(); });    server.HandleCommands();    serverThread.join();    return 0;}

Client(Ubuntu2022)code

#include <iostream>#include <string>#include <cstring>#include <unistd.h>#include <arpa/inet.h>#include <sys/socket.h>#include <sys/wait.h>#include <fcntl.h>#include <poll.h>#include <csignal>#include <atomic>#include <vector>#include <thread>#include <mutex>#include <condition_variable>#include <sstream>#include <unordered_map>std::atomic<bool> running(true);std::mutex mtx;std::condition_variable cv;void signalHandler(int signal) {    if (signal == SIGINT) {        running = false;        cv.notify_all(); // Notify all threads to wake up and check the running flag    }}class ShellHandler {private:    int pipeIn[2];  // Pipe for sending input to the shell    int pipeOut[2]; // Pipe for receiving output from the shell    pid_t shellPid;    std::thread shellThread;    std::atomic<bool> shellRunning;    void ShellThreadFunc() {        while (shellRunning) {            std::this_thread::sleep_for(std::chrono::milliseconds(100));        }    }public:    ShellHandler() : shellRunning(true) {        // Create pipes for communication with the shell        if (pipe(pipeIn) == -1 || pipe(pipeOut) == -1) {            std::cerr << "Error: Failed to create pipes. Errno: " << errno << std::endl;            throw std::runtime_error("Failed to create pipes.");        }        // Fork a child process to run the shell        shellPid = fork();        if (shellPid == -1) {            std::cerr << "Error: Failed to fork. Errno: " << errno << std::endl;            throw std::runtime_error("Failed to fork.");        }        if (shellPid == 0) {            // Child process: Run the shell            close(pipeIn[1]);  // Close the write end of the input pipe            close(pipeOut[0]); // Close the read end of the output pipe            // Redirect stdin and stdout to the pipes            dup2(pipeIn[0], STDIN_FILENO);            dup2(pipeOut[1], STDOUT_FILENO);            dup2(pipeOut[1], STDERR_FILENO);            // Execute the shell            execl("/bin/bash", "bash", nullptr);            // If execl fails            std::cerr << "Error: Failed to execute shell. Errno: " << errno << std::endl;            _exit(1);        } else {            // Parent process: Close unused pipe ends            close(pipeIn[0]);  // Close the read end of the input pipe            close(pipeOut[1]); // Close the write end of the output pipe            std::cout << "Shell started with PID: " << shellPid << std::endl;            // Start the shell thread            shellThread = std::thread(&ShellHandler::ShellThreadFunc, this);        }    }    ~ShellHandler() {        shellRunning = false;        if (shellThread.joinable()) {            shellThread.join();        }        // Clean up        if (pipeIn[1] != -1) close(pipeIn[1]);        if (pipeOut[0] != -1) close(pipeOut[0]);        if (shellPid > 0) waitpid(shellPid, nullptr, 0); // Wait for the child process to exit    }    void SendCommand(const std::string& command) {        if (pipeIn[1] == -1) {            std::cerr << "Error: Pipe is closed." << std::endl;            throw std::runtime_error("Error: Pipe is closed.");        }        // Send the command to the shell (ensure it ends with a newline)        std::string cmd = command +"\n";        std::cout << "Sending command to shell: " << cmd << std::endl;        if (write(pipeIn[1], cmd.c_str(), cmd.size()) == -1) {            std::cerr << "Error: Failed to write to pipe. Errno: " << errno << std::endl;            throw std::runtime_error("Error: Failed to write to pipe.");        }    }    std::string ReceiveOutput() {        char buffer[4096] = {0};        std::string result;        ssize_t bytesRead;        // Используем poll дляпроверкиналичияданныхв pipe        struct pollfd fds[1];        fds[0].fd = pipeOut[0];        fds[0].events = POLLIN;        while (true) {            // Ожидаемданныев pipe стаймаутом (например, 100 мс)            int ret = poll(fds, 1, 100);            if (ret == -1) {                std::cerr << "Error: poll failed. Errno: " << errno << std::endl;                break;            } else if (ret == 0) {                // Таймаут, данныхнет, выходимизцикла                break;            }            // Читаемданныеиз pipe            bytesRead = read(pipeOut[0], buffer, sizeof(buffer));            if (bytesRead > 0) {                result.append(buffer, bytesRead);            } else if (bytesRead == -1) {                std::cerr << "Error: Failed to read from pipe. Errno: " << errno << std::endl;                break;            } else {                // EOF (конецфайла), выходимизцикла                break;            }        }        std::cout << "Received output from shell: " << result << std::endl;        return result;    }};class NetworkHandler {private:    int clientSocket;public:    NetworkHandler(const std::string& serverIP, int port) {        // Create a socket        clientSocket = socket(AF_INET, SOCK_STREAM, 0);        if (clientSocket == -1) {            std::cerr << "Error: Failed to create socket. Errno: " << errno << std::endl;            throw std::runtime_error("Failed to create socket.");        }        // Define server address        sockaddr_in serverAddr;        serverAddr.sin_family = AF_INET;        serverAddr.sin_port = htons(port);        inet_pton(AF_INET, serverIP.c_str(), &serverAddr.sin_addr);        // Connect to the server        if (connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {            std::cerr << "Error: Failed to connect to the server. Errno: " << errno << std::endl;            throw std::runtime_error("Failed to connect to the server.");        }        std::cout << "Connected to the server." << std::endl;    }    ~NetworkHandler() {        close(clientSocket);        std::cout << "Client socket closed." << std::endl;    }    std::string ReceiveCommand() {        char buffer[4096] = {0};        int bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0);        if (bytesReceived <= 0) {            std::cerr << "Error: Failed to receive command. Errno: " << errno << std::endl;            throw std::runtime_error("Connection closed by the server.");        }        std::string command(buffer, bytesReceived);        std::cout << "Received command from server: " << command << std::endl;        return command;    }    void SendResult(const std::string& result) {        // First, send the length of the result        uint32_t resultLength = htonl(result.size());        std::cout << "Sending result length: " << result.size() << std::endl;        if (send(clientSocket, &resultLength, sizeof(resultLength), 0) == -1) {            std::cerr << "Error: Failed to send result length. Errno: " << errno << std::endl;            throw std::runtime_error("Failed to send result length.");        }        // Then, send the result itself        std::cout << "Sending result: " << result << std::endl;        if (send(clientSocket, result.c_str(), result.size(), 0) == -1) {            std::cerr << "Error: Failed to send result. Errno: " << errno << std::endl;            throw std::runtime_error("Failed to send result.");        }    }};int main() {    // Set up signal handler for graceful shutdown    std::signal(SIGINT, signalHandler);    try {        NetworkHandler networkHandler("192.168.31.188", 12345); // Replace with server's IP address        std::unordered_map<int, std::unique_ptr<ShellHandler>> shells;        int activeShellId = 0;        int nextShellId = 1;        while (running) {            // Receive a command from the server            std::string command = networkHandler.ReceiveCommand();            if (command == "new_shell") {                // Create a new shell                shells[nextShellId] = std::make_unique<ShellHandler>();                std::string response = "New shell created with ID: " + std::to_string(nextShellId);                networkHandler.SendResult(response);                nextShellId++;            } else if (command.find("switch_shell") == 0) {                // Switch to a specific shell                int requestedShellId = std::stoi(command.substr(12));                if (shells.find(requestedShellId) != shells.end()) {                    activeShellId = requestedShellId;                    std::string response = "Switched to shell with ID: " + std::to_string(requestedShellId);                    networkHandler.SendResult(response);                } else {                    std::string response = "Shell with ID " + std::to_string(requestedShellId) +" does not exist.";                    networkHandler.SendResult(response);                }            } else if (command.find("su") == 0) {                // Handle su command                if (shells.find(activeShellId) != shells.end()) {                    // Send the su command followed by the password                    shells[activeShellId]->SendCommand("su");                    shells[activeShellId]->SendCommand("080800"); // Replace with the actual password                    // Ignore the output of su (e.g., password prompt)                    shells[activeShellId]->ReceiveOutput();                    // Notify the server that privileges are elevated                    std::string response = "Privileges elevated to root";                    networkHandler.SendResult(response);                } else {                    std::string response = "No active shell available.";                    networkHandler.SendResult(response);                }            } else {                // Send the command to the active shell                if (shells.find(activeShellId) != shells.end()) {                    shells[activeShellId]->SendCommand(command);                    std::string output = shells[activeShellId]->ReceiveOutput();                    networkHandler.SendResult(output);                } else {                    std::string response = "No active shell available.";                    networkHandler.SendResult(response);                }            }        }    } catch (const std::exception& e) {        std::cerr << "Fatal error: " << e.what() << std::endl;        return 1;    }    std::cout << "Connection closed." << std::endl;    return 0;}

If you have any tips about this code, write them down. Please rate this question so that more people can see it.


Viewing all articles
Browse latest Browse all 7069

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>