没有超级用户访问权限的C++ ping-like功能

msm*_*886 7 c++ sockets linux ping

我正在尝试编写一个简单的C++ ping函数来查看网络地址是否正在响应.我不需要专门的ICMP,我只需要查看服务器是否存在并响应任何内容.我一直在做一些研究,我提出的每个解决方案都需要创建一个原始套接字或需要程序具有sudo访问权限的东西.我将无法保证我运行此系统的系统将能够修改网络堆栈,因此这是无效的.

以下是我已经看过的一些相关问题.

  1. 在Linux中打开RAW套接字而不是超级用户
  2. ICMP套接字(linux)
  3. 如何使用套接字库Ping - C.
  4. 为什么ping没有管理员权限?
  5. C++ Boost.asio Ping

似乎ping需要超级用户访问是有充分理由的.我不想故意创建一个安全漏洞,我只想查看服务器是否正在响应.是否有一个好的c ++函数或资源可以做到这一点?我会确保发布我提出的任何样本解决方案.我需要一个Linux(BSD)套接字解决方案.由于几乎每个类Unix系统都运行SSH,我甚至可以只针对端口22进行测试.我只是将Linux系统作为约束.

谢谢

msm*_*886 6

这是一个例子popen.我希望有一个更好的解决方案,所以如果有一个套接字或其他方法不诉诸shell调用,我将非常感激.这应该只是运行g++ ping_demo.cpp -o ping_demo.如果它导致编译错误,请告诉我.

// C++ Libraries
#include <cstdio>
#include <iostream>
#include <sstream>
#include <string>


/**
 * @brief Convert String to Number
 */
template <typename TP>
TP str2num( std::string const& value ){

    std::stringstream sin;
    sin << value;
    TP output;
    sin >> output;
    return output;
}


/**
 * @brief Convert number to string
 */
template <typename TP>
std::string num2str( TP const& value ){
    std::stringstream sin;
    sin << value;
    return sin.str();
}


/**
 * @brief Execute Generic Shell Command
 *
 * @param[in]   command Command to execute.
 * @param[out]  output  Shell output.
 * @param[in]   mode read/write access
 *
 * @return 0 for success, 1 otherwise.
 *
*/
int Execute_Command( const std::string&  command,
                     std::string&        output,
                     const std::string&  mode = "r")
{
    // Create the stringstream
    std::stringstream sout;

    // Run Popen
    FILE *in;
    char buff[512];

    // Test output
    if(!(in = popen(command.c_str(), mode.c_str()))){
        return 1;
    }

    // Parse output
    while(fgets(buff, sizeof(buff), in)!=NULL){
        sout << buff;
    }

    // Close
    int exit_code = pclose(in);

    // set output
    output = sout.str();

    // Return exit code
    return exit_code;
}


/**
 * @brief Ping
 *
 * @param[in] address Address to ping.
 * @param[in] max_attempts Number of attempts to try and ping.
 * @param[out] details Details of failure if one occurs.
 *
 * @return True if responsive, false otherwise.
 *
 * @note { I am redirecting stderr to stdout.  I would recommend 
 *         capturing this information separately.}
 */
bool Ping( const std::string& address,
           const int&         max_attempts,
           std::string&       details )
{
    // Format a command string
    std::string command = "ping -c " + num2str(max_attempts) + " " + address + " 2>&1";
    std::string output;

    // Execute the ping command
    int code = Execute_Command( command, details );

    return (code == 0);
}


/**
 * @brief Main Function
 */
int main( int argc, char* argv[] )
{
    // Parse input
    if( argc < 2 ){
        std::cerr << "usage: " << argv[0] << " <address> <max-attempts = 3>" << std::endl;
        return 1;
    }

    // Get the address
    std::string host = argv[1];

    // Get the max attempts
    int max_attempts = 1;
    if( argc > 2 ){
        max_attempts = str2num<int>(argv[2]);
    }
    if( max_attempts < 1 ){
        std::cerr << "max-attempts must be > 0" << std::endl;
        return 1;
    }

    // Execute the command
    std::string details;
    bool result = Ping( host, max_attempts, details );

    // Print the result
    std::cout << host << " ";
    if( result == true ){
        std::cout << " is responding." << std::endl;
    }
    else{
        std::cout << " is not responding.  Cause: " << details << std::endl;
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

样本输出

$> g++ ping_demo.cpp -o ping_demo

$> # Valid Example
$> ./ping_demo localhost
localhost  is responding.

$> # Invalid Example
$> ./ping_demo localhostt
localhostt  is not responding.  Cause: ping: unknown host localhostt

$> # Valid Example
$> ./ping_demo 8.8.8.8
8.8.8.8  is responding.
Run Code Online (Sandbox Code Playgroud)