J. Buschinelli
J. Buschinelli

Reputation: 1

boost asio async_receive won't receive anything

I'm implementing a C++ custom port scanner using raw sockets and I'm facing a problem in my class NetScanner::StartReceive. I traced down the problem to the async_receive method where it never actually receives a response from destination address being scanned. Here's the code:

#include <iostream>
#include <ostream>
#include <istream>
#include <chrono>
#include <functional>
#include <netinet/ip.h>

#include "NetScanner.hpp"
#include "NetUtils.hpp"
#include "../error_handler/ErrorHandler.hpp"

using std::placeholders::_1;
[...]
void NetScanner::HandleReceive(const boost::system::error_code &error, std::size_t len, ScanInfo scan_info, shared_buffer buffer, shared_timer timer) {
    // Checks if the receive operation was aborted due to a timeout.
    if (error == boost::asio::error::operation_aborted) {
      if (timeout_port_.find(scan_info.port) == timeout_port_.end()) {
        StartReceive(scan_info, timer);
      } else {
        PopulatePortInfo(scan_info.port, port_status::FILTERED);
      }
      return;
    } else if (error) { // Checks if an error occurred during the receive operation.
      (error_handler_.*&error_handler::ErrorHandler::HandleError)(error.message());
      PopulatePortInfo(scan_info.port, port_status::ABORTED);
    } else { // Processes the received data.
      buffer->commit(len);
      utils::TCPHeader header;
      std::istream stream(&(*buffer));
      stream >> header;
      if (header.Syn() && header.Ack()) {
        port_info_[header.Source()] =  port_status::OPEN;
      } else if (header.Rst() && header.Ack()) {
        port_info_[header.Source()] = port_status::CLOSED;
      } else {
        StartReceive(scan_info, timer);
        return;
      }
    }
    timer->cancel();
  }

  void NetScanner::HandleScan(const boost::system::error_code &error, std::size_t len, ScanInfo scan_info, shared_buffer buffer) {
    if (error) {
      (error_handler_.*&error_handler::ErrorHandler::HandleError)(error.message());
    } else {
      shared_timer timer = std::make_shared<basic_timer>(io_context_);
      std::cout << "Starting timer.." << std::endl;
      StartTimer(timeout_miliseconds_, scan_info, timer);
      StartReceive(scan_info, timer);
    }
  }

  void NetScanner::StartReceive(ScanInfo scan_info, shared_timer timer) {
    auto &&buffer = std::make_shared<stream_buffer>();
    socket_.async_receive(
      buffer->prepare(buffer_size),
      std::bind(&NetScanner::HandleReceive, this, _1, _2, scan_info, buffer, timer)
    );
  }

  void NetScanner::StartTimer(int milliseconds, ScanInfo scan_info, shared_timer timer) {
    timer->expires_from_now(std::chrono::milliseconds(milliseconds));
    timer->async_wait(std::bind(&NetScanner::Timeout, this, _1, scan_info, timer));
  [...]

When I try to scan any port, it will return me as filtered (even though it is open) because it hits this line of code in the HandleReceive method.

    if (error == boost::asio::error::operation_aborted) {
      if (timeout_port_.find(scan_info.port) == timeout_port_.end()) {

Meaning the async_receive got no buffer from the port being scanned back in the timeframe of the timeout value.

You can check the full code at https://github.com/alexbsec/parasyte/blob/master/src/network/NetScanner.cpp

I tried to increase the timeout, but even with large times the above if statement is still being triggered.

I attempted debugging it by showing what was in the buffer after the alleged async_receive and it is empty.

I also checked that the async_receive tries to receive the answer back for as long as the timeout is set, meaning the if statement above is only triggered after that.

Upvotes: 0

Views: 47

Answers (0)

Related Questions