【问题标题】:socket connection "Operation not permitted" error even root with boost/pinger.cpp套接字连接“不允许操作”错误,即使 root 使用 boost/pinger.cpp
【发布时间】:2020-07-03 06:34:51
【问题描述】:

我尝试连接到套接字以发送带有修改后的 boost/pinger.cpp 返回的 icmp echo 请求

Operation not permitted

即使我是 root 用户。

在 Ubuntu 20.04 中,我正在使用 sudo 运行程序,它可以正常工作。但是,如果我使用 poky OS (Yocto)(当然是 root)在 ARM 上运行,它会返回我所说的错误。

当我尝试时发生错误

mSocket.async_connect(mDestination, boost::bind(&Pinger::startSend, this, boost::placeholders::_1));

这是我的代码

pinger.cpp

#include "pinger.h"

Pinger::Pinger(boost::asio::io_context &io_context, const char *destination)
    : mResolver(io_context), mSocket(io_context),
      mTimeoutTimer(io_context), mSequenceNumber(1)
{
    mDestination = *mResolver.resolve(boost::asio::ip::icmp::v4(), destination, "");
}

void Pinger::start()
{
    startConnect();
}

void Pinger::stop()
{
    mSocket.close();
    mTimeoutTimer.cancel();
}

void Pinger::startConnect()
{
    mSocket.async_connect(mDestination, boost::bind(&Pinger::startSend, this, boost::placeholders::_1));
}

void Pinger::startSend(const boost::system::error_code &ec)
{
    if (ec)
        return;

    std::string body("\"Hello!\" from pinger.");

    // Create an ICMP header for an echo request.
    icmp_header echo_request;
    echo_request.type(icmp_header::echo_request);
    echo_request.code(0);
    echo_request.identifier(getIdentifier());
    echo_request.sequence_number(mSequenceNumber);
    compute_checksum(echo_request, body.begin(), body.end());

    // Encode the request packet.
    boost::asio::streambuf request_buffer;
    std::ostream os(&request_buffer);
    os << echo_request << body;

    // Send the request.
    mTimeSent = boost::asio::steady_timer::clock_type::now();
    mSocket.async_send(request_buffer.data(), boost::bind(&Pinger::startReceive, this, boost::placeholders::_1));

    // Wait up to ten seconds for a reply.
    mTimeoutTimer.expires_at(mTimeSent + boost::asio::chrono::seconds(15));
    mTimeoutTimer.async_wait(boost::bind(&Pinger::handleTimeout, this, boost::placeholders::_1));
}

void Pinger::startReceive(const boost::system::error_code &ec)
{
    if (ec)
        return;

    // Discard any data already in the buffer.
    mReplyBuffer.consume(mReplyBuffer.size());

    // Wait for a reply. We prepare the buffer to receive up to 64KB.
    mSocket.async_receive(mReplyBuffer.prepare(65536),
                          boost::bind(&Pinger::handleReceive, this, boost::placeholders::_1, _2));
}

void Pinger::handleReceive(const boost::system::error_code &ec, std::size_t length)
{
    if (ec)
        return;

    // The actual number of bytes received is committed to the buffer so that we
    // can extract it using a std::istream object.
    mReplyBuffer.commit(length);

    // Decode the reply packet.
    std::istream is(&mReplyBuffer);
    ipv4_header ipv4_hdr;
    icmp_header icmp_hdr;
    is >> ipv4_hdr >> icmp_hdr;

    // We can receive all ICMP packets received by the host, so we need to
    // filter that match the our identifier.
    if (is && icmp_hdr.identifier() == getIdentifier() && icmp_hdr.sequence_number() == mSequenceNumber)
    {
        if (!mResultSent)
        {
            mResultSent = true;
            stop();
            onResult(true);
            return;
        }
    }
}

void Pinger::handleTimeout(const boost::system::error_code &ec)
{
    if (ec == boost::asio::error::operation_aborted)
        return;

    if (!mResultSent)
    {
        mResultSent = true;
        stop();
        onResult(false);
    }
}

unsigned short Pinger::getIdentifier()
{
#if defined(BOOST_ASIO_WINDOWS)
    return static_cast<unsigned short>(::GetCurrentProcessId());
#else
    return static_cast<unsigned short>(::getpid());
#endif
}

pinger.h


#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/signals2.hpp>
#include <istream>
#include <iostream>
#include <ostream>

#include "icmp_header.hpp"
#include "ipv4_header.hpp"

class Pinger
{
public:
    Pinger(boost::asio::io_context &io_context, const char *destination);

    void start();
    void stop();

    //signals
    boost::signals2::signal<void(bool isAlive)> onResult;

private:
    void startConnect();
    void startSend(const boost::system::error_code &ec);
    void startReceive(const boost::system::error_code &ec);
    void handleReceive(const boost::system::error_code &ec, std::size_t length);
    void handleTimeout(const boost::system::error_code &ec);
    static unsigned short getIdentifier();

    boost::asio::ip::icmp::resolver mResolver;
    boost::asio::ip::icmp::endpoint mDestination;
    boost::asio::ip::icmp::socket mSocket;
    boost::asio::steady_timer mTimeoutTimer;
    unsigned short mSequenceNumber;
    boost::asio::chrono::steady_clock::time_point mTimeSent;
    boost::asio::streambuf mReplyBuffer;
    bool mResultSent = false;
};


【问题讨论】:

    标签: c++ arm boost-asio yocto icmp


    【解决方案1】:

    一言不发

    setcap cap_net_raw,cap_net_admin=eip ./your_exeutable
    

    可能会有帮助。

    boost::asio::ip::icmp::socket mSocket;
    

    看起来它将在后台使用 SOCK_RAW

    【讨论】:

    • 感谢您的回答。我尝试了 setcap 但没有用,是的,它使用原始的 sokcet。实际上我想我错过了向操作系统添加一些东西。是否有任何库或依赖项来运行原始套接字或发送 icmp 请求?
    猜你喜欢
    • 1970-01-01
    • 2017-12-05
    • 2011-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-12
    • 2020-06-07
    • 2011-09-22
    相关资源
    最近更新 更多