getting VS C2664 on sniffer.h libtins - c++

I'm working on a packet-capturing program.
I started from one of libtins examples on http http://libtins.github.io/examples/http-requests/.
but VS prompts a
C2664
Error C2664 'bool main::::operator ()(Tins::Packet &) const': cannot convert argument 1 from 'Tins::PDU' to 'Tins::Packet &' packetSniff path-to-tins\sniffer.h 681
on the following part of the sniffer.h
try {
// If the functor returns false, we're done
#if TINS_IS_CXX11 && !defined(_MSC_VER)
if (!Tins::Internals::invoke_loop_cb(function, *it)) {
return;
}
//here
#else
if (!function(*it->pdu())) {
return;
}
#endif
}
I have already build and run the example from the front page
http://libtins.github.io/
But the following code produces C2664
#define WIN32
#define TINS_STATIC
#define NOMINMAX
#pragma warning(disable : 4996)
#include <string>
#include <iostream>
#include <stdexcept>
#include <boost/regex.hpp>
#include <tins/tcp_ip/stream_follower.h>
#include <tins/sniffer.h>
#include <tins/tins.h>
#include "color.h"
#include <vector>
#include <sstream>
using std::string;
using std::cout;
using std::cerr;
using std::endl;
using std::exception;
using std::vector;
using std::wcout;
using std::stringstream;
using boost::regex;
using boost::match_results;
using Tins::Packet;
using Tins::Sniffer;
using Tins::SnifferConfiguration;
using Tins::TCPIP::Stream;
using Tins::TCPIP::StreamFollower;
using Tins::NetworkInterface;
using termcolor::on_red;
using termcolor::on_green;
using termcolor::reset;
// This example captures and follows TCP streams seen on port 80. It will
// wait until both the client and server send data and then apply a regex
// to both payloads, extrating some information and printing it.
// Don't buffer more than 3kb of data in either request/response
const size_t MAX_PAYLOAD = 3 * 1024;
// The regex to be applied on the request. This will extract the HTTP
// method being used, the request's path and the Host header value.
regex request_regex("([\\w]+) ([^ ]+).+\r\nHost: ([\\d\\w\\.-]+)\r\n");
// The regex to be applied on the response. This finds the response code.
regex response_regex("HTTP/[^ ]+ ([\\d]+)");
void on_server_data(Stream& stream) {
match_results<Stream::payload_type::const_iterator> client_match;
match_results<Stream::payload_type::const_iterator> server_match;
const Stream::payload_type& client_payload = stream.client_payload();
const Stream::payload_type& server_payload = stream.server_payload();
// Run the regexes on client/server payloads
bool valid = regex_search(server_payload.begin(), server_payload.end(),
server_match, response_regex) &&
regex_search(client_payload.begin(), client_payload.end(),
client_match, request_regex);
stringstream ss;
for (char c : server_payload) {
ss << c;
}
cout << on_green << "Server raw payload " <<
ss.str() << reset << endl;
// If we matched both the client and the server regexes
if (valid) {
// Extract all fields
string method = string(client_match[1].first, client_match[1].second);
string url = string(client_match[2].first, client_match[2].second);
string host = string(client_match[3].first, client_match[3].second);
string response_code = string(server_match[1].first, server_match[1].second);
// Now print them
cout << method << " http://" << host << url << " -> " << response_code << endl;
// Once we've seen the first request on this stream, ignore it
stream.ignore_client_data();
stream.ignore_server_data();
}
// Just in case the server returns invalid data, stop at 3kb
if (stream.server_payload().size() > MAX_PAYLOAD) {
stream.ignore_server_data();
}
}
void on_client_data(Stream& stream) {
// Don't hold more than 3kb of data from the client's flow
if (stream.client_payload().size() > MAX_PAYLOAD) {
stream.ignore_client_data();
}
}
void on_new_connection(Stream& stream) {
stream.client_data_callback(&on_client_data);
stream.server_data_callback(&on_server_data);
// Don't automatically cleanup the stream's data, as we'll manage
// the buffer ourselves and let it grow until we see a full request
// and response
stream.auto_cleanup_payloads(false);
}
int main(int argc, char* argv[]) {
// First fetch all network interfaces
vector<NetworkInterface> interfaces = NetworkInterface::all();
// Now iterate them
int i = 0;
for (const NetworkInterface& iface : interfaces) {
// First print the name (GUID)
cout << i++ << ' ' << "Interface name: " << termcolor::on_red << iface.name() <<
termcolor::on_cyan << ' ' << iface.addresses().ip_addr << termcolor::reset;
// Now print the friendly name, a wstring that will contain something like
// "Local Area Connection 2"
wcout << " (" << iface.friendly_name() << ")" << endl;
}
try {
// Construct the sniffer configuration object
SnifferConfiguration config;
// Only capture TCP traffic sent from/to port 80
config.set_filter("tcp port 5000");
// Construct the sniffer we'll use
Sniffer sniffer(interfaces[5].name(), config);
wcout << on_green <<"Starting capture on interface " <<
interfaces[5].friendly_name() << reset << endl;
// Now construct the stream follower
StreamFollower follower;
// We just need to specify the callback to be executed when a new
// stream is captured. In this stream, you should define which callbacks
// will be executed whenever new data is sent on that stream
// (see on_new_connection)
follower.new_stream_callback(&on_new_connection);
// Now start capturing. Every time there's a new packet, call
// follower.process_packet
sniffer.sniff_loop([&](Packet& packet) {
follower.process_packet(packet);
return true;
});
}
catch (exception& ex) {
cerr << "Error: " << ex.what() << endl;
return 1;
}
}

According to the code inside sniffer.h,
try {
// If the functor returns false, we're done
#if TINS_IS_CXX11 && !defined(_MSC_VER)
if (!Tins::Internals::invoke_loop_cb(function, *it)) {
return;
}
//here
#else
if (!function(*it->pdu())) {
return;
}
#endif
}
When you uses VS to compile, the macro _MSC_VER is defined by default, and your code will go to the #else branch, so it will call your callback with a PDU object. To avoid that I would suggest you to choose a different compiler or look for their instructions specifically for MSVC.

I finally came across a work around by casting it to Tins::Packet & in sniffer.h
if (!function((Tins::Packet &)*it->pdu())) {
return;
}

Related

Cannot send and execute correct command through pipes using Boost library in C++

Use the answer in the question: simultaneous read and write to child's stdio using boost.process,
I refactored the code and hybridized the new method using the Boost library. I've been successful in making a pipes connection with Stockfish, but this is also where I get errors I've never seen before, not even Google helps.
Here is what I have tried:
#include <stdio.h>
#include <time.h>
#include <string>
#include <memory.h>
#include <unistd.h>
#include <iostream>
#include <stddef.h>
#include <execinfo.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fstream>
#include </usr/local/include/backtrace.h>
#include </usr/local/include/backtrace-supported.h>
#include <boost/process.hpp>
#include <boost/asio.hpp>
#include <boost/process/async.hpp>
#include <vector>
#include <iomanip>
#include <stdlib.h>
#include <string.h>
using namespace std;
namespace bp = boost::process;
using boost::system::error_code;
using namespace std::chrono_literals;
string errDetails = "Error Details: ";
void delay(int number_of_seconds) {
int ms = 1000 * number_of_seconds;
clock_t start_time = clock();
while (clock() < start_time + ms)
;
}
static void full_write(int fd, const char* buf, size_t len) {
while (len > 0) {
ssize_t ret = write(fd, buf, len);
if ((ret == -1) && (errno != EINTR)) {
break;
}
buf += (size_t) ret;
len -= (size_t) ret;
}
}
void print_backtrace() {
static const char start[] = "--------BACKTRACE--------\n\n";
static const char end[] = "-------------------------\n\n";
void *bt[1024];
int bt_size;
char **bt_syms;
int i;
bt_size = backtrace(bt, 1024);
bt_syms = backtrace_symbols(bt, bt_size);
full_write(STDERR_FILENO, start, strlen(start));
full_write(STDERR_FILENO, errDetails.c_str(), strlen(errDetails.c_str()));
for (i = 1; i < bt_size; i++) {
size_t len = strlen(bt_syms[i]);
full_write(STDERR_FILENO, bt_syms[i], len);
full_write(STDERR_FILENO, "\n", 1);
}
full_write(STDERR_FILENO, end, strlen(end));
free(bt_syms);
}
void abort_application() {
size_t memLeakCount, staticMemLeakCount;
uint64_t memLeakSize, staticMemLeakSize;
for (int i = 0; i < 3; i++) {
/**
* Delay
*/
delay(1);
}
print_backtrace();
abort();
}
inline bool stockfish_check_exists(const std::string& name) {
struct stat buffer;
return (stat(name.c_str(), &buffer) == 0);
}
int main() {
std::future<std::string> data;
boost::asio::io_service svc;
bp::async_pipe in{svc}, out{svc};
string proc = "";
char command[64];
string output = "";
if (stockfish_check_exists("stockfish")) {
proc = "stockfish"; } else {
errDetails = "Stockfish not found!\n\n";
abort_application();
}
std::string const program_dir = proc;
auto on_exit = [](int code, std::error_code ec) {
std::cout << "Exited " << code << "(" << ec.message() << ")\n";
};
bp::child process(proc, bp::std_in < in, svc);
boost::asio::streambuf recv_buffer;
std::cout << "uci send" << std::endl;
boost::asio::async_write(in, boost::asio::buffer("uci\n"),
[&](boost::system::error_code ec, size_t transferred) {
std::cout << "Write: " << transferred << "\n" << std::endl;
in.close();
}
);
std::cout << "isready send" << std::endl;
boost::asio::async_write(in, boost::asio::buffer("isready\n"),
[&](boost::system::error_code ec, size_t transferred) {
std::cout << "Write: " << transferred << "\n" << std::endl;
in.close();
}
);
cout << "Enter your command: ";
cin >> command;
cout << "Your command is: " << command << endl;
if (strcmp(command, "quit") == 0) {
cout << "Quiting......." << endl;
boost::asio::async_write(in, boost::asio::buffer("quit"),
[&](boost::system::error_code ec, size_t transferred) {
std::cout << "Write: " << transferred << std::endl;
in.close();
cout << "Engine quit!" << endl;
}
);
}
svc.run();
return 0;
}
To make it easier to follow, I left out std::std_out > out at the line:
bp::child process(proc, bp::std_in < in, svc);
so that the engine results are immediately displayed in the Terminal window, so I'll know if I've gone astray. And this is when I discovered the strange thing
When I launch the application, it outputs on Terminal as follows:
[2022-01-14 20:25:55]
duythanh#DuyThanhs-MacBook-Pro:/Volumes/Data/ChessGUI$ ./ChessGUI
uci send
isready send
Enter your command: Stockfish 120122 by the Stockfish developers (see AUTHORS file)
id name Stockfish 120122
id author the Stockfish developers (see AUTHORS file)
option name Debug Log File type string default
option name Threads type spin default 1 min 1 max 512
option name Hash type spin default 16 min 1 max 33554432
option name Clear Hash type button
option name Ponder type check default false
option name MultiPV type spin default 1 min 1 max 500
option name Skill Level type spin default 20 min 0 max 20
option name Move Overhead type spin default 10 min 0 max 5000
option name Slow Mover type spin default 100 min 10 max 1000
option name nodestime type spin default 0 min 0 max 10000
option name UCI_Chess960 type check default false
option name UCI_AnalyseMode type check default false
option name UCI_LimitStrength type check default false
option name UCI_Elo type spin default 1350 min 1350 max 2850
option name UCI_ShowWDL type check default false
option name SyzygyPath type string default <empty>
option name SyzygyProbeDepth type spin default 1 min 1 max 100
option name Syzygy50MoveRule type check default true
option name SyzygyProbeLimit type spin default 7 min 0 max 7
option name Use NNUE type check default true
option name EvalFile type string default nn-ac07bd334b62.nnue
uciok
Unknown command: isready
Contrasting with the code above, the two commands were sent through pipes. is uci and isready, this is fine. The first uci command runs successfully, but the isready command, instead of returning readyok, it returns:
Unknown command: isready
I keep trying to type quit, which sends a quit command to the pipe as the exit engine, and it also fails:
Your command is: quit
Quiting.......
Write: 5
Write: 9
Unknown command: quit
Write: 5
Engine quit!
The program will then exit with the engine. I'm still wondering what was going on at the time, but the clues are really hazy as to what was going on behind the scenes.
Please help me. Any help is highly appreciated. Thank you so much everyone
UPDATE: The error continued when Unknown Command: Quit appeared. I typed these commands in Terminal while running Stockfish directly through Terminal, they work as a result, but my program still can't
You are printing to cout as if the async operations happen immediately. That's not the case. The async operations only happen when the io service runs.
svc.run();
Is at the very end of your code. So no async_ operation ever completes (or even starts) before that.
Other problems:
Your out async pipe is never used (not even connected). It's unclear to me how you intend to communicate with the child process that way.
In fairness, you only every write to the child process, so maybe you're not at all interested in the output. (But then perhaps recv_buffer can be deleted just as well).
Your buffers include the terminating NUL characters. (asio::buffer("uci\n") sends {'u','c','i','\n','\0'}). That's going to mess up the child processes's parsing.
You do in.close() in response to every single async_write completion. This guarantees that subsequent writes never can happen, as you closed the pipe.
Then when you send quit you fail to include the '\n' as well
You are reading into a char[64] with operator>> which makes no sense at all. Maybe you are using c++20 (so width of 64 might be assumed) but you never set a width. Most likely you would want to read into a string instead.
However, doing so cannot accept commands with whitespace (because std::ios::skipws is set by default). So, likely you wanted std::getline instead...
The fact that you include a boatload of C headers makes me think you're porting some C code (badly). That's also exemplified by the strcmp use and others, e.g. no need to use ::stat
Don't use using namespace std; (Why is "using namespace std;" considered bad practice?)
Don't use global variables (errDetails)
Don't use loops to wait for a time delay
No need to manually print backtraces. Instead, use Boost:
void abort_application(std::string const& errDetails) {
std::cerr << errDetails << "\n";
std::cerr << boost::stacktrace::stacktrace{} << std::endl;
std::this_thread::sleep_for(3s);
abort();
}
Existing Stockfish Client: Playing Games
You're in luck: I have a written full demo using stockfish on this site: Interfacing with executable using boost in c++.
This example shows how to correctly await and parse expected replies from the child process(es).
You will note that I chose coroutines for the async version:
Just for completeness, I thought I'd try an asynchronous implementation. Using the default Asio callback style this could become unwieldy, so I thought to use Boost Coroutine for the stackful coroutines. That makes it so the implementation can be 99% similar to the synchronous version
Just for comparison, here's what your code should look like if you didn't use coroutines:
Fixing Up Your Code
Live On Coliru
#include <boost/asio.hpp>
#include <boost/process.hpp>
#include <boost/process/async.hpp>
#include <boost/stacktrace/stacktrace.hpp>
#include <chrono>
#include <iomanip>
#include <iostream>
namespace bp = boost::process;
using boost::system::error_code;
using namespace std::literals;
static void abort_application(std::string const& errDetails) {
std::cerr << errDetails << "\n";
std::cerr << boost::stacktrace::stacktrace{} << std::endl;
std::this_thread::sleep_for(3s);
abort();
}
inline static bool stockfish_check_exists(std::string& name) {
return boost::filesystem::exists(name);
}
int main() {
boost::asio::io_service svc;
bp::async_pipe in{svc};
std::string proc = "/usr/games/stockfish";
if (!stockfish_check_exists(proc)) {
abort_application("Stockfish not found!");
}
auto on_exit = [](int code, std::error_code ec) {
std::cout << "Exited " << code << "(" << ec.message() << ")\n";
};
bp::child process(proc, bp::std_in < in, svc, bp::on_exit = on_exit);
std::function<void()> command_loop;
std::string command_buffer;
command_loop = [&] {
std::cout << "Enter your command: " << std::flush;
// boost::asio::streambuf recv_buffer;
if (getline(std::cin, command_buffer)) {
std::cout << "Your command is: " << command_buffer << std::endl;
command_buffer += '\n';
async_write( //
in, boost::asio::buffer(command_buffer),
[&](error_code ec, size_t transferred) {
std::cout << "Write: " << transferred << " (" << ec.message() << ")" << std::endl;
if (command_buffer == "quit\n") {
std::cout << "Quiting......." << std::endl;
// in.close();
std::cout << "Engine quit!" << std::endl;
} else {
command_loop(); // loop
}
});
}
};
std::cout << "uci send" << std::endl;
async_write(
in, boost::asio::buffer("uci\n"sv),
[&](error_code ec, size_t transferred) {
std::cout << "Write: " << transferred << "\n" << std::endl;
std::cout << "isready send" << std::endl;
async_write(in, boost::asio::buffer("isready\n"sv),
[&](error_code ec, size_t n) {
std::cout << "Write: " << n << std::endl;
command_loop(); // start command loop
});
});
svc.run(); // only here any of the operations start
}
Prints, e.g.
Or if Stockfish is in fact installed:

Use Futures with Boost Thread Pool

I'm implementing a TCP client which read and send files and strings and I'm using Boost as my main library. I'd like to continue reading or sending files while I keep sending strings, which in these case are the commands to send to the server. For this purpose I thought about using a Thread Pool in order to not overload the client. My question is, can I use futures to use callbacks when on of the thread in the pool ends? In case I can't, is there any other solution?
I was doing something like this, where pool_ is a boost:asio:thread_pool
void send_file(std::string const& file_path){
boost::asio::post(pool_, [this, &file_path] {
handle_send_file(file_path);
});
// DO SOMETHING WHEN handle_send_file ENDS
}
void handle_send_file(std::string const& file_path) {
boost::array<char, 1024> buf{};
boost::system::error_code error;
std::ifstream source_file(file_path, std::ios_base::binary | std::ios_base::ate);
if(!source_file) {
std::cout << "[ERROR] Failed to open " << file_path << std::endl;
//TODO gestire errore
}
size_t file_size = source_file.tellg();
source_file.seekg(0);
std::string file_size_readable = file_size_to_readable(file_size);
// First send file name and file size in bytes to server
boost::asio::streambuf request;
std::ostream request_stream(&request);
request_stream << file_path << "\n"
<< file_size << "\n\n"; // Consider sending readable version, does it change anything?
// Send the request
boost::asio::write(*socket_, request, error);
if(error){
std::cout << "[ERROR] Send request error:" << error << std::endl;
//TODO lanciare un'eccezione? Qua dovrò controllare se il server funziona o no
}
if(DEBUG) {
std::cout << "[DEBUG] " << file_path << " size is: " << file_size_readable << std::endl;
std::cout << "[DEBUG] Start sending file content" << std::endl;
}
long bytes_sent = 0;
float percent = 0;
print_percentage(percent);
while(!source_file.eof()) {
source_file.read(buf.c_array(), (std::streamsize)buf.size());
int bytes_read_from_file = source_file.gcount(); //int is fine because i read at most buf's size, 1024 in this case
if(bytes_read_from_file<=0) {
std::cout << "[ERROR] Read file error" << std::endl;
break;
//TODO gestire questo errore
}
percent = std::ceil((100.0 * bytes_sent) / file_size);
print_percentage(percent);
boost::asio::write(*socket_, boost::asio::buffer(buf.c_array(), source_file.gcount()),
boost::asio::transfer_all(), error);
if(error) {
std::cout << "[ERROR] Send file error:" << error << std::endl;
//TODO lanciare un'eccezione?
}
bytes_sent += bytes_read_from_file;
}
std::cout << "\n" << "[INFO] File " << file_path << " sent successfully!" << std::endl;
}
The operations posted to the pool end without the threads ending. That's the whole purpose of pooling the threads.
void send_file(std::string const& file_path){
post(pool_, [this, &file_path] {
handle_send_file(file_path);
});
// DO SOMETHING WHEN handle_send_file ENDS
}
This has several issues. The largest one is that you should not capture file_path by reference, as the argument is soon out of scope, and the handle_send_file call will run at an unspecified time in another thread. That's a race condition and dangling reference. Undefined Behaviour results.
Then the
// DO SOMETHING WHEN handle_send_file ENDS
is on a line which has no sequence relation with handle_send_file. In fact, it will probably run before that operation ever has a chance to start.
Simplifying
Here's a simplified version:
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <fstream>
#include <iostream>
namespace asio = boost::asio;
using asio::ip::tcp;
static asio::thread_pool pool_;
struct X {
std::unique_ptr<tcp::socket> socket_;
explicit X(unsigned short port) : socket_(new tcp::socket{ pool_ }) {
socket_->connect({ {}, port });
}
asio::thread_pool pool_;
std::unique_ptr<tcp::socket> socket_{ new tcp::socket{ pool_ } };
void send_file(std::string file_path) {
post(pool_, [=, this] {
send_file_implementation(file_path);
// DO SOMETHING WHEN send_file_implementation ENDS
});
}
// throws system_error exception
void send_file_implementation(std::string file_path) {
std::ifstream source_file(file_path,
std::ios_base::binary | std::ios_base::ate);
size_t file_size = source_file.tellg();
source_file.seekg(0);
write(*socket_,
asio::buffer(file_path + "\n" + std::to_string(file_size) + "\n\n"));
boost::array<char, 1024> buf{};
while (source_file.read(buf.c_array(), buf.size()) ||
source_file.gcount() > 0)
{
int n = source_file.gcount();
if (n <= 0) {
using namespace boost::system;
throw system_error(errc::io_error, system_category());
}
write(*socket_, asio::buffer(buf), asio::transfer_exactly(n));
}
}
};
Now, you can indeed run several of these operations in parallel (assuming several instances of X, so you have separate socket_ connections).
To do something at the end, just put code where I moved the comment:
// DO SOMETHING WHEN send_file_implementation ENDS
If you don't know what to do there and you wish to make a future ready at that point, you can:
std::future<void> send_file(std::string file_path) {
std::packaged_task<void()> task([=, this] {
send_file_implementation(file_path);
});
return post(pool_, std::move(task));
}
This overload of post magically¹ returns the future from the packaged task. That packaged task will set the internal promise with either the (void) return value or the exception thrown.
See it in action: Live On Coliru
int main() {
// send two files simultaneously to different connections
X clientA(6868);
X clientB(6969);
std::future<void> futures[] = {
clientA.send_file("main.cpp"),
clientB.send_file("main.cpp"),
};
for (auto& fut : futures) try {
fut.get();
std::cout << "Everything completed without error\n";
} catch(std::exception const& e) {
std::cout << "Error occurred: " << e.what() << "\n";
};
pool_.join();
}
I tested this while running two netcats to listen on 6868/6969:
nc -l -p 6868 | head& nc -l -p 6969 | md5sum&
./a.out
wait
The server prints:
Everything completed without error
Everything completed without error
The netcats print their filtered output:
main.cpp
1907
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <fstream>
#include <iostream>
#include <future>
namespace asio = boost::asio;
using asio::ip::tcp;
7ecb71992bcbc22bda44d78ad3e2a5ef -
¹ not magic: see https://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/reference/async_result.html

how to capture HTTPS packets using libtins?

Im using libtins library for sniffing.
The given example http_requests.cpp works for HTTP requests.
to capture https packets i tried using
config.set_filter("tcp port 443");
but didn't work
complete code:
#include <string>
#include <iostream>
#include <stdexcept>
#include <boost/regex.hpp>
#include "tins/tcp_ip/stream_follower.h"
#include "tins/sniffer.h"
using std::string;
using std::cout;
using std::cerr;
using std::endl;
using std::exception;
using boost::regex;
using boost::match_results;
using Tins::PDU;
using Tins::Sniffer;
using Tins::SnifferConfiguration;
using Tins::TCPIP::Stream;
using Tins::TCPIP::StreamFollower;
const size_t MAX_PAYLOAD = 3 * 1024;
regex request_regex("([\\w]+) ([^ ]+).+\r\nHost: ([\\d\\w\\.-]+)\r\n");
regex response_regex("HTTP/[^ ]+ ([\\d]+)");
void on_server_data(Stream& stream) {
match_results<Stream::payload_type::const_iterator> client_match;
match_results<Stream::payload_type::const_iterator> server_match;
const Stream::payload_type& client_payload = stream.client_payload();
const Stream::payload_type& server_payload = stream.server_payload();
bool valid = regex_search(server_payload.begin(), server_payload.end(),
server_match, response_regex) &&
regex_search(client_payload.begin(), client_payload.end(),
client_match, request_regex);
if (valid) {
// Extract all fields
string method = string(client_match[1].first, client_match[1].second);
string url = string(client_match[2].first, client_match[2].second);
string host = string(client_match[3].first, client_match[3].second);
string response_code = string(server_match[1].first, server_match[1].second);
// Now print them
cout << method << " http://" << host << url << " -> " << response_code << endl;
// Once we've seen the first request on this stream, ignore it
stream.ignore_client_data();
stream.ignore_server_data();
}
// Just in case the server returns invalid data, stop at 3kb
if (stream.server_payload().size() > MAX_PAYLOAD) {
stream.ignore_server_data();
}
}
void on_client_data(Stream& stream) {
// Don't hold more than 3kb of data from the client's flow
if (stream.client_payload().size() > MAX_PAYLOAD) {
stream.ignore_client_data();
}
}
void on_new_connection(Stream& stream) {
stream.client_data_callback(&on_client_data);
stream.server_data_callback(&on_server_data);
stream.auto_cleanup_payloads(false);
}
int main(int argc, char* argv[]) {
if (argc != 2) {
cout << "Usage: " << argv[0] << " <interface>" << endl;
return 1;
}
try {
SnifferConfiguration config;
config.set_immediate_mode(true);
// Only capture TCP traffic sent from/to port 80
config.set_filter("tcp port 443");
// Construct the sniffer we'll use
Sniffer sniffer(argv[1], config);
cout << "Starting capture on interface " << argv[1] << endl;
// Now construct the stream follower
StreamFollower follower;
follower.new_stream_callback(&on_new_connection);
sniffer.sniff_loop([&](PDU& packet) {
follower.process_packet(packet);
return true;
});
}
catch (exception& ex) {
cerr << "Error: " << ex.what() << endl;
return 1;
}
}
how do i configure it to work for https protocol?
Just changing the port won't actually help.
While it will grab the packets it won't be able to do anything with them as they will be encrypted so none of the regexps will match.
Unless you have access to the private key from the server to decrypt the content then this code will never work.

Getting a readable PCAP dump from libtins

I'm using libtins in C++ project on Linux to create a pcap dump.
The pcap dump that I am getting from my code does not appear to be readable by Wireshark, tcp dump, or the example that I used to try and read the code with libtins.
I need my program to produce output which is readable by wireshark, as well as being readable in a way that I can read it via code in my project as well.
Edit:
relevant code:
bool packetHandler(const PDU &pdu) {
const IP &ip = pdu.rfind_pdu<IP>();
return true;
cout << ip.src_addr() << " -> " << ip.dst_addr() << endl;
return true;
}
int main(int argc, char** argv)
{
if(getuid() != 0)
{
printf("You must run this program as root!\n");
exit(1);
}
try
{
std::string pcap_path = "/tmp/test.pcap";
std::string device = "eth0";
printf("Filepath: %s\n", pcap_path.c_str());
PacketWriter writer(pcap_path, DataLinkType<EthernetII>());
std::vector<EthernetII> vec(1000, EthernetII(hwaddr(device)));
writer.write(vec.begin(), vec.end());
writer.write(vec[0]);
} catch(Tins::unknown_link_type e)
{
printf("ERROR:\t%s\n", e.what());
} catch(std::runtime_error e)
{
printf("ERROR:\t%s\n", e.what());
}
}
I have also tried this code to read the pcap but it doesn't output anything:
#include <tins/tins.h>
using namespace Tins;
using namespace std;
bool packetHandler(PDU &pdu)
{
// Find the IP layer
const IP &ip = pdu.rfind_pdu<IP>();
cout << ip.src_addr() << " -> " << ip.dst_addr() << endl;
return true;
}
int main() {
FileSniffer sniffer("/tmp/test.pcap");
sniffer.sniff_loop(packetHandler);
}
edit.. again
As you can see from wireshark I'm getting the incorrect values for each field and data which is all 0s. https://i.imgur.com/wfCnaaA.png (sry I couldn't embed the image because I don't have 10 reputation points on here).
I need to be able to see the IP addresses, data, etc in the correct fields on wireshark but I'm not getting the correct data.
I've just started to study libtins. I've got how to capture packets, based in this tutorial here: https://libtins.github.io/tutorial/sniffing/
#include <tins/tins.h>
#include <iostream>
#include <typeinfo>
using namespace Tins;
using namespace std;
/*
Compile
g++ loop_sniffing_simple.cpp -o loop_sniffing_simple.o -O3 -std=c++11 -lpthread -ltins
Run
sudo ./loop_sniffing_simple.o
From other machine (192.168.72.57) send something
*/
void test() {
SnifferConfiguration config;
config.set_promisc_mode(true);
config.set_filter("ip host 192.168.72.57");
Sniffer sniffer("wlp2s0", config);
// sniffer.sniff_loop(doo);
PacketWriter writer = PacketWriter("sniffer.pcap", DataLinkType<IP>());
int n_packet = 0;
const int totalPackets = 4;
for (auto &packet : sniffer) {
auto pdu = packet.release_pdu();
IP ip = pdu->rfind_pdu<IP>();
cout << "Destination IP: " << ip.dst_addr()
<< " source IP: " << ip.src_addr() << endl;
// cout << typeid(ip).name() << endl;
// writer.write(pdu->rfind_pdu<IP>());
writer.write(ip);
++n_packet;
if (n_packet == totalPackets) {
break;
}
}
}
int main() {
test();
return 0;
}
In the end you will have a correct pcap file
Other example, I guess it is better:
#include <vector>
#include <tins/tins.h>
#include <iostream>
using namespace Tins;
using namespace std;
/*
Compile
g++ packet_objects.cpp -o packet_objects.o -O3 -std=c++11 -lpthread -ltins
*/
int main() {
vector<Packet> vt;
PacketWriter writer = PacketWriter("sniffer_obj.pcap", DataLinkType<IP>());
Sniffer sniffer("wlp2s0");
while (vt.size() != 10) {
// next_packet returns a PtrPacket, which can be implicitly converted to Packet.
vt.push_back(sniffer.next_packet());
}
// Done, now let's cehck the packets
for (const auto& packet : vt) {
// Is there an IP PDU somewhere?
if(packet.pdu()->find_pdu<IP>()) {
// Just print timestamp's seconds and IP source address
cout << "At: " << packet.timestamp().seconds()
<< " - " << packet.pdu()->rfind_pdu<IP>().src_addr()
<< std::endl;
IP ip = packet.pdu()->rfind_pdu<IP>();
writer.write(ip);
}
}
return 0;
}

C++ Rest giving me an error when trying to show JSON file from web

I am trying to make a program that can display a JSON file in console with C++'s REST API. I'm trying to get the JSON file from api.trello.com but every example I come across gives me an error, usually about cbegin() & cend() and how it is not a value of web::json::value...
here is my code:
// The code includes the most frequently used includes necessary to work with C++ REST SDK
#include "cpprest/containerstream.h"
#include "cpprest/filestream.h"
#include "cpprest/http_client.h"
#include "cpprest/json.h"
#include "cpprest/producerconsumerstream.h"
#include <iostream>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
using namespace ::pplx;
using namespace utility;
using namespace concurrency::streams;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace web::json;
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
// Retrieves a JSON value from an HTTP request.
pplx::task<void> RequestJSONValueAsync()
{
// TODO: To successfully use this example, you must perform the request
// against a server that provides JSON data.
// This example fails because the returned Content-Type is text/html and not application/json.
http_client client(L"website.com/theRealURLContainsSecretKeys");
return client.request(methods::GET).then([](http_response response) -> pplx::task<json::value>
{
if (response.status_code() == status_codes::OK)
{
return response.extract_json();
}
// Handle error cases, for now return empty json value...
return pplx::task_from_result(json::value());
})
.then([](pplx::task<json::value> previousTask)
{
try
{
const json::value& v = previousTask.get();
// Perform actions here to process the JSON value...
}
catch (const http_exception& e)
{
// Print error.
wostringstream ss;
ss << e.what() << endl;
wcout << ss.str();
}
});
/* Output:
Content-Type must be application/json to extract (is: text/html)
*/
}
// Demonstrates how to iterate over a JSON object.
void IterateJSONValue()
{
// Create a JSON object.
json::value obj;
obj[L"key1"] = json::value::boolean(false);
obj[L"key2"] = json::value::number(44);
obj[L"key3"] = json::value::number(43.6);
obj[L"key4"] = json::value::string(U("str"));
// Loop over each element in the object.
for (auto iter = obj.cbegin(); iter != obj.cend(); ++iter)
{
// Make sure to get the value as const reference otherwise you will end up copying
// the whole JSON value recursively which can be expensive if it is a nested object.
const json::value &str = iter->first;
const json::value &v = iter->second;
// Perform actions here to process each string and value in the JSON object...
std::wcout << L"String: " << str.as_string() << L", Value: " << v.to_string() << endl;
}
/* Output:
String: key1, Value: false
String: key2, Value: 44
String: key3, Value: 43.6
String: key4, Value: str
*/
}
int wmain()
{
// This example uses the task::wait method to ensure that async operations complete before the app exits.
// In most apps, you typically don�t wait for async operations to complete.
wcout << L"Calling RequestJSONValueAsync..." << endl;
RequestJSONValueAsync().wait();
wcout << L"Calling IterateJSONValue..." << endl;
//IterateJSONValue();
system("pause");
}
I am having this error in VS 2015.
The only errors are in IterateJSONValue()
What is my problem and how can I fix it?
json::value does not contain a member function cbegin(). If you access obj.as_object() or obj.as_array() you will find your begin/end members.
// Loop over each element in the object.
for (const auto &pr : obj.as_object()) {
std::wcout << L"String: " << pr.first << L", Value: " << pr.second << endl;
}