Compare commits

...

6 Commits

1 changed files with 293 additions and 21 deletions

View File

@ -16,6 +16,7 @@
//version 3 along with this program.
//If not, see https://www.gnu.org/licenses/agpl-3.0.en.html
#include <chrono>
#include <csignal>
#include <iomanip>
#include <iostream>
@ -23,6 +24,10 @@
#include <string>
#include <sockpp/tcp_acceptor.h>
#include <sockpp/tcp_connector.h>
#include <sockpp/tcp6_acceptor.h>
#include <sockpp/tcp6_connector.h>
#include <sockpp/udp_socket.h>
#include <sockpp/udp6_socket.h>
#include <thread>
#include <vector>
@ -33,12 +38,22 @@
#define EXIT_RUNTIME 1
#define EXIT_USAGE 2
#define EXIT_UNIMPLEMENTED 3
#define EXIT_SIGNAL 4
// TCP v4 server
sockpp::tcp_socket tcpSocket;
sockpp::tcp_acceptor tcpAcceptor;
// TCP v4 client
sockpp::tcp_connector tcpConnector;
// TCP v6 server
sockpp::tcp6_socket tcp6Socket;
sockpp::tcp6_acceptor tcp6Acceptor;
// TCP v6 client
sockpp::tcp6_connector tcp6Connector;
// UDP v4 server and client
sockpp::udp_socket udpSocket;
// UDP v6 server and client
sockpp::udp6_socket udp6Socket;
bool exitProgram = false;
@ -50,6 +65,44 @@ bool outgoing = false;
std::string host;
in_port_t port;
// This is probably bigger than the MTU on any given network.
// This should allow us to read entire packets at once when they arrive
// slowly enough to be read individually.
const uint32_t bufferSize = 2048;
uint8_t networkBuffer[bufferSize];
std::string readByteFromStdin() {
std::string input = "";
// read 2 characters from stdin
char characterInput;
bool readByte = false;
uint16_t iterationsSinceLastInput = 0;
while (input.length() < 2 && !exitProgram) {
if (std::cin.good()) {
std::cin.get(characterInput);
readByte = true;
} else {
readByte = false;
}
// ignore space, tabs, and newlines
if (readByte && characterInput!=' ' && characterInput!='\n' && characterInput!='\r' && characterInput!='\t') {
input.push_back(characterInput);
}
iterationsSinceLastInput++;
if (readByte) {
iterationsSinceLastInput = 0;
}
if (iterationsSinceLastInput>1024) {
// prevent integer overflow
iterationsSinceLastInput = 1024;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
return exitProgram? "" : std::string(1, (char) std::stoi(input, nullptr, 16));
}
void signalHandler(int signal) {
// shut down gracefully
exitProgram = true;
@ -61,21 +114,136 @@ void signalHandler(int signal) {
tcpSocket.shutdown(SHUT_RD);
}
if (tcpConnector) {
tcpConnector.shutdown(SHUT_RD);
}
if (tcp6Socket) {
tcp6Socket.shutdown(SHUT_RD);
}
if (tcp6Connector) {
tcp6Connector.shutdown(SHUT_RD);
}
if (udpSocket) {
udpSocket.shutdown(SHUT_RD);
}
if (udp6Socket) {
udp6Socket.shutdown(SHUT_RD);
}
std::cerr << "Received signal " << signal << ", bye!" << std::endl;
std::exit(signal);
std::exit(EXIT_SIGNAL);
}
void readFromTCPSocket() {
void readFromTCP() {
ssize_t byteCount;
uint8_t buffer[1536];
while (!exitProgram && (outgoing? (byteCount = tcpConnector.read(buffer, sizeof(buffer))) > 0 : (byteCount = tcpSocket.read(buffer, sizeof(buffer))) > 0)) {
while (!exitProgram && (outgoing? (byteCount = tcpConnector.read(networkBuffer, bufferSize)) > 0 : (byteCount = tcpSocket.read(networkBuffer, bufferSize)) > 0)) {
for (ssize_t i=0; i<byteCount; i++) {
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) buffer[i] << " ";
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) networkBuffer[i] << " ";
}
std::cout.flush();
}
}
void writeToTCP() {
while (!exitProgram) {
if (outgoing) {
if (tcpConnector.write(readByteFromStdin()) == -1 && !exitProgram) {
exitProgram = true;
tcpConnector.shutdown(SHUT_RD);
std::cerr << "Error while sending data: " << tcpConnector.last_error_str() << std::endl;
return;
}
} else {
if (tcpSocket.write(readByteFromStdin()) == -1 && !exitProgram) {
exitProgram = true;
tcpSocket.shutdown(SHUT_RD);
std::cerr << "Error while sending data: " << tcpSocket.last_error_str() << std::endl;
return;
}
}
}
}
void readFromTCP6() {
ssize_t byteCount;
while (!exitProgram && (outgoing? (byteCount = tcp6Connector.read(networkBuffer, bufferSize)) > 0 : (byteCount = tcp6Socket.read(networkBuffer, bufferSize)) > 0)) {
for (ssize_t i=0; i<byteCount; i++) {
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) networkBuffer[i] << " ";
}
std::cout.flush();
}
}
void writeToTCP6() {
while (!exitProgram) {
if (outgoing) {
if (tcp6Connector.write(readByteFromStdin()) == -1 && !exitProgram) {
exitProgram = true;
tcp6Connector.shutdown(SHUT_RD);
std::cerr << "Error while sending data: " << tcp6Connector.last_error_str() << std::endl;
return;
}
} else {
if (tcp6Socket.write(readByteFromStdin()) == -1 && !exitProgram) {
exitProgram = true;
tcp6Socket.shutdown(SHUT_RD);
std::cerr << "Error while sending data: " << tcp6Socket.last_error_str() << std::endl;
return;
}
}
}
}
void readFromUDP() {
ssize_t byteCount;
sockpp::udp_socket::addr_t peer;
while ((byteCount = udpSocket.recv_from(networkBuffer, bufferSize, &peer)) > 0) {
std::cout << peer << ": ";
for (ssize_t i=0; i<byteCount; i++) {
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) networkBuffer[i] << " ";
}
std::cout << std::dec << std::endl;
}
}
void writeToUDP(sockpp::udp_socket::addr_t peer) {
while (!exitProgram) {
if (udpSocket.send_to(readByteFromStdin(), peer) == -1 && !exitProgram) {
exitProgram = true;
udpSocket.shutdown(SHUT_RD);
std::cerr << "Error while sending data: " << udpSocket.last_error_str() << std::endl;
return;
}
}
}
void readFromUDP6() {
ssize_t byteCount;
sockpp::udp6_socket::addr_t peer;
while ((byteCount = udp6Socket.recv_from(networkBuffer, bufferSize, &peer)) > 0) {
std::cout << peer << ": ";
for (ssize_t i=0; i<byteCount; i++) {
std::cout << std::hex << std::setfill('0') << std::setw(2) << (short) networkBuffer[i] << " ";
}
std::cout << std::dec << std::endl;
}
}
void writeToUDP6(sockpp::udp6_socket::addr_t peer) {
while (!exitProgram) {
if (udp6Socket.send_to(readByteFromStdin(), peer) == -1 && !exitProgram) {
exitProgram = true;
udp6Socket.shutdown(SHUT_RD);
std::cerr << "Error while sending data: " << udp6Socket.last_error_str() << std::endl;
return;
}
}
}
int main(int argc, char* argv[]) {
std::signal(SIGINT, signalHandler);
std::signal(SIGTERM, signalHandler);
@ -90,11 +258,12 @@ int main(int argc, char* argv[]) {
std::vector<CLI::Option> options;
options.push_back(CLI::Option('c', "connect", "HOST", "make an outgoing connection to HOST instead of listening for an incoming connection"));
options.push_back(CLI::Option('b', "bind", "ADDRESS", "(UDP only) bind to ADDRESS instead of localhost"));
std::vector<CLI::Argument> arguments;
arguments.push_back(CLI::Argument("PORT", "the port to lsiten on (or connect to)"));
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments, "Arbitrary TCP/UDP connections in hex format", "Note: Make sure your terminal is set up so it doesn't buffer input and, if desired, disable input echoing.\n\tSomething like `stty -echo cbreak` should do but it will also disable some key combinations.");
CLI::ArgumentsParser cliParser = CLI::ArgumentsParser(argc, argv, flags, options, arguments, "Arbitrary TCP/UDP connections in hex format", "Spaces, tabs, newlines, and carriage returns in the input are ignored.\n\tYou may want to disable input echoing using `stty -echo` (reenable using `stty echo`).\n\tNote that many terminals do line buffering on the input by default.");
if (cliParser.getFlag("help").value) {
std::cout << cliParser.getUsage() << std::endl;
@ -137,7 +306,7 @@ int main(int argc, char* argv[]) {
}
if (!(ipv4 || ipv6) || (ipv4 && ipv6) || !(tcp || udp) || (tcp && udp)) {
std::cout << cliParser.getUsage() << std::endl;
std::cout << "Please specify which protocols to use (one of IPv4/IPv6, one of TCP/UDP)." << std::endl;
return EXIT_USAGE;
}
@ -155,26 +324,74 @@ int main(int argc, char* argv[]) {
return EXIT_RUNTIME;
}
std::thread threadReadFromTCP = std::thread(readFromTCPSocket);
//std::thread threadWriteToTCP = std::thread(writeToTCPSocket);
std::thread threadReadFromTCP = std::thread(readFromTCP);
std::thread threadWriteToTCP = std::thread(writeToTCP);
threadReadFromTCP.join();
//threadWriteToTCP.join();
threadWriteToTCP.join();
std::cout << std::endl;
return EXIT_SUCCESS;
} else {
// TCP v6 out
return EXIT_UNIMPLEMENTED;
tcp6Connector = sockpp::tcp6_connector({host, port});
if (!tcp6Connector) {
std::cerr << "Error connecting to " << host << " on port " << port << std::endl;
std::cerr << tcp6Connector.last_error_str() << std::endl;
return EXIT_RUNTIME;
}
std::thread threadReadFromTCP6 = std::thread(readFromTCP6);
std::thread threadWriteToTCP6 = std::thread(writeToTCP6);
threadReadFromTCP6.join();
threadWriteToTCP6.join();
std::cout << std::endl;
return EXIT_SUCCESS;
}
} else {
std::cerr << "Connecting to " << host << " on port " << (int) port << " (UDP)..." << std::endl;
std::cerr << "Talking to " << host << " on port " << (int) port << " (UDP)..." << std::endl;
if (ipv4) {
// UDP v4 out
return EXIT_UNIMPLEMENTED;
if (!udpSocket) {
std::cerr << "Error creating UDP socket: " << udpSocket.last_error_str() << std::endl;
}
// Btw: Did you know that UDP has no concept of a connection?
sockpp::udp_socket::addr_t peer = sockpp::inet_address(host, port);
if (!udpSocket.connect(peer)) {
std::cerr << "Error associating socket with " << host << " port " << port << std::endl;
std::cerr << udpSocket.last_error_str() << std::endl;
}
std::thread threadReadFromUDP = std::thread(readFromUDP);
std::thread threadWriteToUDP = std::thread(writeToUDP, peer);
threadReadFromUDP.join();
threadWriteToUDP.join();
std::cout << std::endl;
return EXIT_SUCCESS;
} else {
// UDP v6 out
return EXIT_UNIMPLEMENTED;
if (!udp6Socket) {
std::cerr << "Error creating UDP socket: " << udp6Socket.last_error_str() << std::endl;
}
// Btw: Did you know that UDP has no concept of a connection?
sockpp::udp6_socket::addr_t peer = sockpp::inet6_address(host, port);
if (!udp6Socket.connect(peer)) {
std::cerr << "Error associating socket with " << host << " port " << port << std::endl;
std::cerr << udp6Socket.last_error_str() << std::endl;
}
std::thread threadReadFromUDP6 = std::thread(readFromUDP6);
std::thread threadWriteToUDP6 = std::thread(writeToUDP6, peer);
threadReadFromUDP6.join();
threadWriteToUDP6.join();
std::cout << std::endl;
return EXIT_SUCCESS;
}
}
} else {
@ -196,26 +413,81 @@ int main(int argc, char* argv[]) {
return EXIT_RUNTIME;
}
std::thread threadReadFromTCP = std::thread(readFromTCPSocket);
//std::thread threadWriteToTCP = std::thread(writeToTCPSocket);
std::thread threadReadFromTCP = std::thread(readFromTCP);
std::thread threadWriteToTCP = std::thread(writeToTCP);
threadReadFromTCP.join();
//threadWriteToTCP.join();
threadWriteToTCP.join();
std::cout << std::endl;
return EXIT_SUCCESS;
} else {
// TCP v6 in
return EXIT_UNIMPLEMENTED;
tcp6Acceptor = sockpp::tcp6_acceptor(port);
if (!tcp6Acceptor) {
std::cerr << "Error while creating TCP acceptor: " << tcp6Acceptor.last_error_str() << std::endl;
return EXIT_RUNTIME;
}
sockpp::inet6_address peer;
tcp6Socket = tcp6Acceptor.accept(&peer);
std::cerr << "Incoming connection from " << peer << std::endl;
if (!tcp6Socket) {
std::cerr << "Error on incoming connection: " << tcp6Acceptor.last_error_str() << std::endl;
return EXIT_RUNTIME;
}
std::thread threadReadFromTCP6 = std::thread(readFromTCP6);
std::thread threadWriteToTCP6 = std::thread(writeToTCP6);
threadReadFromTCP6.join();
threadWriteToTCP6.join();
std::cout << std::endl;
return EXIT_SUCCESS;
}
} else {
std::cerr << "Listening on port " << (int) port << " (UDP)..." << std::endl;
std::string address = "localhost";
if (cliParser.getOption("bind").errorCode != ErrorCodes::NOT_PRESENT) {
address = cliParser.getOption("bind").value;
}
std::cerr << "Listening on " << address << " port " << (int) port << " (UDP)..." << std::endl;
if (ipv4) {
// UDP v4 in
return EXIT_UNIMPLEMENTED;
if (!udpSocket) {
std::cerr << "Error creating UDP socket: " << udpSocket.last_error_str() << std::endl;
}
if (!udpSocket.bind(sockpp::inet_address(address, port))) {
std::cerr << "Error binding UDP socket to " << address << " port " << port << ": " << udpSocket.last_error_str() << std::endl;
}
std::thread threadReadFromUDP = std::thread(readFromUDP);
// Can't send bc we have no idea where to send to.
//std::thread threadWriteToUDP = std::thread(writeToUDP);
threadReadFromUDP.join();
//threadWriteToUDP.join();
std::cout << std::endl;
return EXIT_SUCCESS;
} else {
// UDP v6 in
return EXIT_UNIMPLEMENTED;
if (!udp6Socket) {
std::cerr << "Error creating UDP socket: " << udp6Socket.last_error_str() << std::endl;
}
if (!udp6Socket.bind(sockpp::inet6_address(address, port))) {
std::cerr << "Error binding UDP socket to " << address << " port " << port << ": " << udp6Socket.last_error_str() << std::endl;
}
std::thread threadReadFromUDP6 = std::thread(readFromUDP6);
// Can't send bc we have no idea where to send to.
//std::thread threadWriteToUDP6 = std::thread(writeToUDP6);
threadReadFromUDP6.join();
//threadWriteToUDP6.join();
std::cout << std::endl;
return EXIT_SUCCESS;
}
}
}