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.
Related
Able to send UDP message to a particular IP port using Poco Lib socket communication, But unable to receive the UDP message as it is getting stuck at receiveFrom API of DatagramSocket as in below code.
I am sending message every second and also have to receive acknowledgement every second, for that i have timer , Client and Server Threads running parallelly. The problem here is I am unable to receive the UDP packets which are being captured on wireshark. It is getting stuck at receiveFrom.
Please find below Client Server and main files.
` Server.hpp
#pragma once
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/DatagramSocket.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/MulticastSocket.h"
#include "Poco/RunnableAdapter.h"
#include "Poco/Thread.h"
#include <cstring>
#include <iostream>
using namespace std;
using namespace Poco;
using namespace Poco::Net;
struct Server
{
int bufferSize;
SocketAddress sockets;
static bool debugModeEnabled;
Server() :
bufferSize(1024) { //sockets = SocketAddress(10000);
}
Server(const UInt16& port, const int& bufferSize)
{
sockets = SocketAddress(port);
this->bufferSize = bufferSize;
}
void receiveMessages()
{
char buffer[bufferSize];
try
{
Poco::Net::DatagramSocket datagram(sockets);//(socket);
datagram.bind(sockets);
cout << "Server started socket" << endl;
while (!datagram.available())
{
SocketAddress sender;
cout << "Server started socket 2" << endl;
int size = datagram.receiveFrom(buffer, bufferSize, sender);
//int size = datagram.receiveBytes(buffer, bufferSize);
cout << "received bytes size" << size << endl;
buffer[size] = '\0';
//std::string str(buffer);
//cout << (debugModeEnabled ? (sender.toString() + ": ") : "- ") << buffer << endl;
cout << "received: " << size << buffer << endl;
//cout << buffer << "Server adasdasd" << endl;
if (string(buffer) == "\\end")
{
//cerr << "\nUser: " << sender.toString() << " ended connection" << endl;
datagram.close(); // Closes the server
}
}
}
catch (const Poco::Exception& exc)
{
std::cerr << exc.displayText() << std::endl;
}
}
};
bool Server::debugModeEnabled = false;
`
`Client.hpp
#pragma once
#include "Poco/Net/DatagramSocket.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/RunnableAdapter.h"
#include "Poco/Thread.h"
#include <iostream>
#include <string>
using namespace std;
using namespace Poco;
using namespace Poco::Net;
struct Client
{
SocketAddress socket;
string str;
// By default the client connects to itself
Client() { socket = SocketAddress("127.0.0.1", 10000); }
Client(const Poco::Net::IPAddress& IP, const UInt16& port, const string& val) :
str(val)
{
socket = SocketAddress(IP, port);
}
void sendMessages()
{
DatagramSocket datagram;
datagram.connect(socket);
string message = str;
//cout << "sending: " << hex << hexify(message) << endl;
unsigned int bytes_sent = 0;
while (!datagram.available())
{
//getline(cin, message);
//bytes_sent = datagram.sendBytes(message.data(), static_cast<int>(message.size()));
bytes_sent = datagram.sendTo(message.data(), static_cast<int>(message.size()),socket);
cout << "number of bytes sent: " << std::dec << bytes_sent << endl;
if (bytes_sent >= message.size())
{
datagram.close();
}
}
}
string IP() { return socket.host().toString(); }
UInt16 port() { return socket.port(); }
static void sendMessage(const Poco::Net::IPAddress& IP, const UInt16& port, const string& message)
{
SocketAddress socket(IP, port);
DatagramSocket datagram;
datagram.connect(socket);
datagram.sendBytes(message.data(), int(message.size()));
}
};
`
` main.cpp
int bufferSize = 1024;
int exit_status = 0;
Client client(IP, ciPort, str);
Server server(mdilPort, bufferSize);
RunnableAdapter<Client> clientRunnable(client, &Client::sendMessages);
RunnableAdapter<Server> serverRunnable(server, &Server::receiveMessages);
Thread clientThread, serverThread;
// Client::sendMessage(IP, ciPort, "hello!!");
try
{
Timer t = Timer();
t.setInterval([&]() {
cout << "client Tick" << endl;
// pApp->SendIndications();
clientThread.start(clientRunnable);
clientThread.join();
},
1000);
t.setInterval([&]() {
cout<< "server Tick" << endl;
serverThread.start(serverRunnable);
serverThread.join();
},
1000);
t.setTimeout([&]() {
std::cout << "Hey.. After 30s. But I will stop the timer!" << std::endl;
t.stop();
exit(exit_status);
},
30000);
std::cout << "I am Timer" << std::endl;
while (true); // Keep main thread active
}
catch (...)
{
std::cout << "catched exception" << std::endl;
//return -1;
}
`
I tried the conventional Socket Programming API's to receive the UDP packets but there also it is getting stuck at receiveFrom API. also tried running both client and server on different process to make sure there is no issue with the multi threading synchronization, but both the approach didnt help. I am able to capture the response at Wireshark but unable to receive on the application side using Poco Lib socket API's. Also allowed visual studio code through firewall as well
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:
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;
}
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;
}
I am implementing fastCGI in c++ along with nginx. Until now, I am able to develop basic http request method and some url redirection. But, I am not able to send the body of message while redirecting from post url to another post url. Below is my code:
#include <stdlib.h>
#include <stdio.h>
#include <sstream>
#include <iostream>
#include <string>
#include "string.h"
#include "fcgio.h"
#include <fcgi_stdio.h>
#include <boost/algorithm/string.hpp>
using namespace std;
using namespace boost;
// Maximum bytes
const unsigned long STDIN_MAX = 1000000;
/**
* Note this is not thread safe due to the static allocation of the
* content_buffer.
*/
string get_request_content(const FCGX_Request & request) {
char * content_length_str = FCGX_GetParam("CONTENT_LENGTH", request.envp);
unsigned long content_length = STDIN_MAX;
if (content_length_str) {
content_length = strtol(content_length_str, &content_length_str, 10);
if (*content_length_str) {
cerr << "Can't Parse 'CONTENT_LENGTH='"
<< FCGX_GetParam("CONTENT_LENGTH", request.envp)
<< "'. Consuming stdin up to " << STDIN_MAX << endl;
}
if (content_length > STDIN_MAX) {
content_length = STDIN_MAX;
}
} else {
// Do not read from stdin if CONTENT_LENGTH is missing
content_length = 0;
}
char * content_buffer = new char[content_length];
cin.read(content_buffer, content_length);
content_length = cin.gcount();
// Chew up any remaining stdin - this shouldn't be necessary
// but is because mod_fastcgi doesn't handle it correctly.
// ignore() doesn't set the eof bit in some versions of glibc++
// so use gcount() instead of eof()...
do cin.ignore(1024); while (cin.gcount() == 1024);
string content(content_buffer, content_length);
delete [] content_buffer;
return content;
}
int main(void) {
// Backup the stdio streambufs
streambuf * cin_streambuf = cin.rdbuf();
streambuf * cout_streambuf = cout.rdbuf();
streambuf * cerr_streambuf = cerr.rdbuf();
FCGX_Request request;
FCGX_Init();
FCGX_InitRequest(&request, 0, 0);
while (FCGX_Accept_r(&request) == 0) {
fcgi_streambuf cin_fcgi_streambuf(request.in);
fcgi_streambuf cout_fcgi_streambuf(request.out);
fcgi_streambuf cerr_fcgi_streambuf(request.err);
cin.rdbuf(&cin_fcgi_streambuf);
cout.rdbuf(&cout_fcgi_streambuf);
cerr.rdbuf(&cerr_fcgi_streambuf);
const char * uri = FCGX_GetParam("REQUEST_URI", request.envp);
string content = get_request_content(request);
if (content.length() == 0) {
content = ", something!";
}
const char * mediaType = FCGX_GetParam("REQUEST_METHOD",request.envp);
string value;
if(iequals(mediaType,"POST")&&iequals(uri,"/postmethod")) {
get_request_content(request);
cout << "HTTP/1.1 200 OK\r\nContent-Length: " << content.length() << "\r\n\r\n" << content;
}
if(iequals(mediaType,"GET")&&iequals(uri,"/getmethod")) {
string aalu = "this is the new lenght";
cout << "HTTP/1.1 200 OK\r\nContent-Length: " << aalu.length() << "\r\n\r\n" << aalu;
FCGX_Finish_r(&request);
}
if(iequals(mediaType,"GET")&&iequals(uri,"/redirect")) {
cout << "HTTP/1.1 301\r\nLocation: http://localhost/getmethod\r\n\r\n";
// cout << "Status: 301\r\n"
// << "Location: http://localhost/getmethod\r\n";
// << "\r\n";
// << "<html><body>Not Found</body></html>\n";
}
if(iequals(mediaType,"GET")&&iequals(uri,"/postredirect")) { // problem here
string json = "{\"topic\":\"asdf\",\"message\":\"message\"}";
cout << "HTTP/1.1 308\r\nLocation: http://localhost/postmethod\r\n\r\n";
// cout << "Status: 304\r\n"
// << "Location: http://localhost/postmethod\r\n"
// << "\r\n"
// << "<html><body>json</body></html>\n";
}
if(iequals(mediaType,"POST")&&iequals(uri,"/getredirect")) {
string json = "{\"topic\":\"asdf\",\"message\":\"message\"}";
cout << "HTTP/1.1 303\r\nLocation: http://localhost/getmethod\r\n\r\n";
// cout << "Status: 304\r\n"
// << "Location: http://localhost/postmethod\r\n"
// << "\r\n"
// << "<html><body>json</body></html>\n";
}
if(iequals(mediaType,"POST")&&iequals(uri,"/posttopostredirect")) {
string json = "{\"topic\":\"adf\",\"message\":\"message\"}";
cout << "Status: 307\r\n"
<<"Location: http://localhost/postmethod\r\n"
<<"\r\n"
<<"\n";
// cout << "Status: 305\r\n"
// << "Location: http://localhost/postmethod\r\n"
// << "\r\n"
// << "<html><body>"+json+"</body></html>\n";
}
if(iequals(mediaType,"GET")&&iequals(uri,"/getttogettredirect")) {
string json = "{\"topic\":\"ssdf\",\"message\":\"message\"}";
cout << "HTTP/1.X 301\r\nLocation: http://localhost/getmethod\r\n\r\n";
// cout << "Status: 307\r\n"
// << "Location: http://localhost/postmethod\r\n"
// << "\r\n";
// << "<html><body>json</body></html>\n";
}
}
// restore stdio streambufs
cin.rdbuf(cin_streambuf);
cout.rdbuf(cout_streambuf);
cerr.rdbuf(cerr_streambuf);
return 0;
}
/posttopostredirect url is redirecting to /postmethod url. Here, I wish to send json string (above) when /posttopostredirect is hit to /postmethod url. But couldnot figure out how to do so
Any content of HTTP redirect messages is completely ignored. This has nothing to do with FastCGI. This is how HTTP works. HTTP redirect messages cannot be used to send any content. Well, they could, but the HTTP client will simply ignore it, and issue a GET request to the redirected-to URL.
The only thing that can be done is to include any data as parameters encoded in the redirected-to URL. This is done the same way as encoding any parameters in the URL.