Does TCPdump strip any headers when receiving packets? - c++

So i am attempting to send an already constructed packet over a RAW socket interface (these are packets that have been previously captured and i want to resend them without changing the packet integrity) and am using TCPdump to check that the packets are going over correctly (surprise they are not).
The packets are physically being sent but are always 24 bytes short of what my "sent" returns.
In wireshark my eth headers seem to be erased as my source and dest MAC addresses are "00:00:00:00:00
sock setup is as follows
sock = socket(AF_PACKET,SOCK_RAW,IPPROTO_RAW);
if(sock==-1)
{
qDebug() << "sock error";
}
int reuse = 1;
if(setsockopt(sock, IPPROTO_RAW, IP_HDRINCL, (char *)&reuse, sizeof(reuse)) < 0)
{
qDebug() << "error setting reuse"
}
else
{
"setting reuse"
}
struct sockaddr_ll sll;
struct ifreq ifr;
bzero(&sll, sizeof(sll));
bzero(&ifr, sizeof(ifr));
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifr.ifr_ifindex;
sll.sll_protocol = htons(IPPROTO_RAW);
sll.sll_halen = ETH_ALEN;
strncpy((char*)ifr.ifr_ifrn.ifrn_name,interface.toUtf8.constData(),IFNAMSIZ);
if(ioctl(sock,SIOCGIFINDEX,&ifr) == -1)
{
qDebug() << "error getting interface name";
}
strncpy((char*)ifr.ifr_ifrn.ifrn_name,interface.toUtf8.constData(),IFNAMSIZ);
if(ioctl(sock,SIOCGIFHWADDR,&ifr) == -1)
{
qDebug() << "error getting interface name";
}
if(bind(sock,(struct sockaddr *)&sll,sizeof(sll))==-1)
{
qDebug() << "error binding sock";
}
after this im using
int size = write(sock,(const void*)&packet,hdr.caplen);
i've tried sendto in the past but it would always reconfigure things so this was my next solution which also isnt working as i would like.
I'm not the most savy with TCP/IP stuff so any help would be greatly appreciated!

okay so after just trying a bunch of different stuff i landed on what seems to be my solution.
i created a second pointer that will point to the top of the packet and send that instead.
(char *)sendingPacket;
struct ethhdr *ethh = (struct ethhdr*)packet;
sendingPacket = (char*) ethh;
i don't really understand why this works but sending the other packet doesn't so if anyone has insight please share!

Related

how to deal with multiple clients in c++ socket problem?

I need some help with a socket program with multiple clients and one server. To simplify, I create
3 socket clients
1 socket server
For each client, it opens a new connection for sending a new message and closes the connection after a response is received.
For the server, it does not need to deal with connections concurrently, it can deal with the message one by one
here is my code (runnable), compile it with /usr/bin/g++ mycode.cpp -g -lpthread -lrt -Wall -o mycode
#include <iostream>
#include <arpa/inet.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <unordered_map>
#include <thread>
using namespace std;
void Warning(string msg) { std::cout<< msg << std::endl; }
namespace mySocket {
class Memcached {
public:
// start a server
static void controller(int port=7111) { std::thread (server, port).detach(); }
// open a new connection to send a message:
// 1. open a connection
// 2. send the message
// 3. read the message
// 4. close the connection
std::string sendMessage(string msg, string host, int port=7111) {
int sock = 0, client_fd;
struct sockaddr_in serv_addr;
char buffer[1024] = { 0 };
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
std::cout << "Socket creation error, msg: " << msg << ", host: " << host << ", port: " << port << std::endl;
exit(1);
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
if (inet_pton(AF_INET, host.c_str(), &serv_addr.sin_addr) <= 0) {
std::cout << "\nInvalid address/ Address not supported, kmsgey: " << msg << ", host: " << host << ", port: " << port << std::endl;
exit(1);
}
while ((client_fd = connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))) < 0) { sleep(10*1000); }
std::cout << "client sends a message:"<<msg<<", msg size:"<<msg.size()<<std::endl;
send(sock, msg.c_str(), msg.size(), 0);
read(sock, buffer, 1024);
close(client_fd);
return std::string(buffer, strlen(buffer));
}
private:
// start a server
// 1. open a file descriptor
// 2. listen the fd with queue size 10
// 3. accept one connection at a time
// 4. deal with message in the connection
// 5. accept the next connection
// 6. repeat step 3
static void server(int port) {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = { 0 };
unordered_map<string,string> data;
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
Warning("socket failed"); exit(1);
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
Warning("setsockopt failed"); exit(1);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
Warning("bind failed"); exit(1);
}
// the queue size is 10 > 3
if (listen(server_fd, 10) < 0) {
Warning("listen failed"); exit(1);
}
while(1)
{
if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) {
std::cout << "accept failed"; exit(1);
}
memset(&buffer, 0, sizeof(buffer)); //clear the buffer
read(new_socket, buffer, 1024);
std::string msg = std::string(buffer, strlen(buffer));
if (msg.size()==0) {
std::cout<<"I can't believe it"<<std::endl;
}
std::cout<<"received msg from the client:"<<msg<<",msg size:"<<msg.size()<<std::endl;
std::string results="response from the server:["+msg+"]";
send(new_socket, results.c_str(), results.length(), 0);
//usleep(10*1000);
}
if (close(new_socket)<0){
std::cout <<"close error"<<std::endl;
}
shutdown(server_fd, SHUT_RDWR);
}
} ;
}
void operation(int client_id) {
auto obj = new mySocket::Memcached();
for (int i=0; i<10;i++){
int id=client_id*100+i;
std::cout<<obj->sendMessage(std::to_string(id), "127.0.0.1", 7111)<<std::endl<<std::endl;
}
}
int main(int argc, char const* argv[]) {
// start a socket server
mySocket::Memcached::controller();
// start 3 socket clients
std::thread t1(operation, 1);
std::thread t2(operation, 2);
std::thread t3(operation, 3);
t1.join();
t2.join();
t3.join();
}
In the code above, the client always sends a message with a length of 3. However, the server can receive messages with a length of 0 which causes further errors.
I'm struggling with this for several days and can't figure out why it happens. I noticed
if I add a short sleep inside the server while loop, the problem is solved. (uncomment usleep(10*1000); in the code).
or if I only use one client, the problem is also solved.
Any thought helps.
You are using TCP sockets. You may want to use some application-level protocol like HTTP, websockets instead, that will be much easier, because you will not need to worry about how message is sent/received and in which sequence. If you have to stick with TCP sockets, you firstly have to understand few things:
There's two types of TCP sockets you can use: non-blocking and blocking IO (input/output). You are currently using blocking IO. That IO will be sometimes blocked and you won't be able to do anything with sockets. In blocking IO, it can be work arounded by using one socket per thread on server-side. It's not efficient, but it's relatively easy comparing to Non-blocking IO. Non-blocking IO doesn't wait for anything. While in blocking IO you wait for data, in non-blocking IO you create something like events, callbacks, that are used when there's some data. You probably have to read about these types of IO.
In your server function, would be better, if you listen for incoming connections in one thread, and when there's incoming connection, move this connection into another thread and function, that will handle other things. This may solve your problem related to multiple clients at the same time.
In function operation, instead of allocating memory using raw pointer, use static allocation or smart pointers to avoid memory leaks. If you don't want to, then at least, do delete obj; in the end of function.
And the last one thing. You can use some TCP socket wrapper like sockpp to make things a lot easier. You will have anything TCP sockets have, but in C++ style and a little bit easier to understand and maintain. If you can't use application-level protocol, I strongly suggest you to use some wrapper at least.
Update
As was stated by commenters, there are more things you need to know:
TCP sockets are streams. This means that if you send your message with length of 1024 bytes, it can be divided into several TCP data packets and you can't know if it will be divided or not, how much packets other side will receive etc. You have to read in a while loop using recv() and wait for data. There's some tricks which can help you to properly receive data:
You can send length of your message first, so other side will know how much bytes it needs to receive.
You can place some terminating symbol or sequence of terminating symbols in the end of your message and read until these will be received. This can be a little risky, because there's chance that you would not receive these symbols at all and will be reading next.
You have to join client threads only when you know, that server is already started and listening for incoming connections. You can use some variable as a flag for these purposes, but make note, that you have to pay a lot of attention, when reading/writing variable from two or more different threads. For these purposes, you can use mutexes, which are some mechanism that will allow you safely access one variable from several threads.

Trying to receive an SNMP Trap though UDP socket (winsock2)

Ive been trying to build an SNMP trap receiver using C++ and the winsock2 library, I have a thread set up to receive UDP data across port 161... as you would expect, when using a python socket program that i quickly threw together i was able to receive UTF-8 encoded strings and print them to the console. However, when i tried generating a SNMP Trap test event using iDRAC-9 (Dell server remote management tool), i managed to receive the 400 bytes as expected, but only printed 0é☺î☻☺. Frustratingly, the recvfrom() function can only take a char * parameter to receive the data. Im hoping to be able to decode roughly the same detail of data that Wireshark is capturing. Any help would be amazing!
code sample below:
int bytes_received = 0;
BYTE serverBuf[1025]{}; //1 Kilobyte + Null Terminating Character
int serverBufLen = 1024;
struct sockaddr_in SenderAddr {};
int SenderAddrSize = sizeof(SenderAddr);
do {
//Recieve Data
bytes_received = recvfrom(serverSocket, (char*)serverBuf, serverBufLen, 0, (SOCKADDR*)&SenderAddr, &SenderAddrSize);
if (bytes_received == SOCKET_ERROR) {
printf("recvfrom failed with error %d\n", WSAGetLastError());
bytes_received = 0;
}
//Make The String Null Terminated
serverBuf[bytes_received] = '\0';
std::cout << "Bytes Received: ";
std::cout << bytes_received << std::endl;
std::cout << serverBuf << std::endl;
//Send Data Back
char sendBuf[] = "Received\0";
if (sendto(serverSocket, sendBuf, (sizeof(sendBuf) - 1), 0, (SOCKADDR*)&SenderAddr, SenderAddrSize) == SOCKET_ERROR) {
printf("Sending back response got an error: %d\n", WSAGetLastError());
}
} while (active);
Wireshark Info

Multiple connections from same host cause socket disconnection issues

I'm writting a C++ app for Linux. It uses sockets for TCP communication. I read data from remote hosts as follows (a bit simplified for this topic's needs):
Packet Connection::receiveRawData()
{
int length = recv(socketDescriptor, receiveBuffer, MAXBUF, 0);
if(length < 0)
{
std::cout << getConnectionDetails() << " - nothing to read.\n";
return Packet(); //Empty packet object (with no data)
}
else if(length == 0)
{
std::cout << getConnectionDetails() << " - disconnected suddenly!\n";
//Do something about this closed connection
}
return Packet(receiveBuffer, length);
}
getConnectionDetails() shows me adress and port number (like this: xx.xx.xx.xx:yy) so I would know that the message is about specific connection (since even if they're from same host they'll still have different port numbers). Couts are just for debuging purpose.
The thing is, it doesn't work quite well when I close one of the connections from the same host (ie. after making three different connection to the application, but all of them come from same machine). Only when I close them in reversed order (from newest to oldest) it works as expected - it shows "xx.xx.xx.xx:yy - disconnected suddenly!" in app's console. But when I try from oldest to newest, I keep getting "xx.xx.xx.xx:yy - nothing to read." for every connection, even though these connections should be closed!
What's going on? recv() is supposed to return 0 when remote host closed its connection, so why doesn't it happen when I close connection (from the remote host side) from oldest or even from the "middle" (neither oldest nor newest)?
It doesn't occur when I close connections from different machines (so that no machine makes more than one connection to the app) - order of these operations don't matter then, it just works fine as it should.
Edit: some more code so you can see how I set up connection sockets:
//Create "empty" socket object associated with the given port number
Connection::Connection(PortNumberFormat portNum)
: address(), port(portNum), socketDescriptor(socket(AF_INET, SOCK_STREAM, 0)), isConnected(false), isListening(false), isShuttingDown(false)
{
if(socketDescriptor < 0)
throw std::string("Fatal error: cannot create socket! The error was: " + std::string( strerror(errno) ));
}
//Create socket object using specified socket descriptor and mark it as connected to the server
//available on specified address and port
Connection::Connection(SocketDescriptor sock, char *addr, PortNumberFormat portNum)
: address(addr), port(portNum), socketDescriptor(sock), isConnected(true), isListening(false), isShuttingDown(false)
{
setTimeouts();
}
Connection::~Connection()
{
if(socketDescriptor < 0) return;
if(!isShuttingDown) signalShutdown();
close(socketDescriptor);
}
//Turn socket into listening mode by binding it to the specified port
void Connection::startListen()
{
if(isConnected || isListening || socketDescriptor < 0)
throw std::string("Socket can not be set as listening!");
struct sockaddr_in bindData;
int dummy = 1;
memset(&bindData, 0, sizeof(bindData));
bindData.sin_family = AF_INET;
bindData.sin_addr.s_addr = INADDR_ANY;
bindData.sin_port = htons(port);
setsockopt(socketDescriptor, SOL_SOCKET, SO_REUSEADDR, &dummy, sizeof(dummy)); //Release socket ASAP on closing
if(bind(socketDescriptor, (struct sockaddr*)&bindData, sizeof(bindData)) < 0)
throw std::string("Fatal error: cannot bind socket for listening! The error was: " + std::string( strerror(errno) ));
if(listen(socketDescriptor, MAXCONN) < 0)
throw std::string("Fatal error: cannot listen on bound socket! The error was: " + std::string( strerror(errno) ));
isListening = true;
}
//Get new Connection object that represents external client connection
//This method will block until client connects or the socket shutdown occurs
Connection Connection::getClientConnection()
{
if(!isListening || socketDescriptor < 0)
throw std::string("Can't get connection from non-listening socket!");
struct sockaddr_in clientData;
socklen_t len = sizeof(clientData);
SocketDescriptor clientSocket = accept(socketDescriptor, (struct sockaddr*)&clientData, &len);
if(isShuttingDown) //An shutdown occured
{
if(clientSocket < 0)
throw std::string("Information: listening connection is shutting down peacefully.");
//Else...
close(clientSocket); //Just to be extra sure
throw std::string("Warning: listening connection is shutting down. Client connection has been discarded.");
}
if(clientSocket < 0)
throw std::string("Fatal error: cannot open client connection socket! The error was: " + std::string( strerror(errno) ));
return Connection(clientSocket, inet_ntoa(clientData.sin_addr), ntohs(clientData.sin_port));
}
//Invalidates socket and prepares it to be closed
void Connection::signalShutdown()
{
if(socketDescriptor < 0) return;
isShuttingDown = true;
shutdown(socketDescriptor, SHUT_RDWR);
}
inline void Connection::setTimeouts()
{
struct timeval timeout;
timeout.tv_sec = 2;
timeout.tv_usec = 0;
if(setsockopt(socketDescriptor, SOL_SOCKET, SO_RCVTIMEO, (void*)&timeout, sizeof(timeout)) < 0
|| setsockopt(socketDescriptor, SOL_SOCKET, SO_SNDTIMEO, (void*)&timeout, sizeof(timeout)) < 0)
{
//Do something about it
}
}
std::string Connection::getConnectionDetails()
{
return std::string(address + ":" + std::to_string(port));
}
Listening connection is created using first constructor (port number only), then I call startListen() on it. Connections from hosts are returned to external code with getClientConnection() method (they are created using second constructor). Now these are our troublemakers.

How to use miniupnpc with Boost.Asio UDP when binding a socket to a random port

I'm astonished by the lack of documentation on miniupnp, I believe there's a lot of people using it, but almost no documentation at all, I found a piece of code in the source of RakNet to guide me.
Now I'm having a conceptual issue...
I'm developing an app that connects to a server via UDP (the server should be accessible, the server UDP port is a specific one which is open, and I can test this using any open port checker), then the server puts two or more clients talking to each other (p2p), so I need to circumvent NAT in the clients for that to work.
I already have NAT punch through working, and that already solves lots of cases.
Now, I want to add the UPNP functionality, to attack the NAT issue with this too.
I'm using miniupnpc, and I handle the connections with Boost.Asio.
struct UPNPDev * devlist = 0;
devlist = upnpDiscover(2000, 0, 0, 0, 0, 0);
if (devlist) {
std::cout << "\nList of UPNP devices found on the network :\n";
struct UPNPDev * device;
for(device = devlist; device; device = device->pNext) {
std::cout << "\ndesc: " << device->descURL << "\n st: " << device->st << "\n";
}
char lanaddr[64]; /* my ip address on the LAN */
struct UPNPUrls urls;
struct IGDdatas data;
if (UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)) == 1) {
string port = lexical_cast<string>(socket->local_endpoint().port());
int r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
port.c_str(), port.c_str(), lanaddr, 0, "UDP", 0, "0");
if (r != UPNPCOMMAND_SUCCESS) {
std::cout << "\nupnp fail";
}
char intPort[6];
char intClient[16];
char desc[128];
char enabled[128];
char leaseDuration[128];
r = UPNP_GetSpecificPortMappingEntry(urls.controlURL,
data.first.servicetype,
port.c_str(), "UDP", 0,
intClient, intPort,
desc, enabled, leaseDuration);
if (r != UPNPCOMMAND_SUCCESS) {
std::cout << "\nupnp fail";
}else {
std::cout << "\nupnp success on port " << port;
}
}
}
As you can see, I execute the UPNP after having bound the socket (I bind it without an specific port, like this:)
asio::udp::socket socket(*this->ioService, asio::udp::endpoint());
My question is, does this UPNP execution makes any sense? Will this socket actually use the UPNP port map if I execute the UPNP on the random port bound to the socket AFTER I bind it?
Thanks guys!

What's going wrong with this SOCKS proxy request?

I'm currently trying to implement SOCKS 4/5 functionality in my C++ program (i.e. requests to arbitrary protocols and hosts can be redirected through a given SOCKS proxy if desired). I'm developing purely for Windows so using Winsock 2.
My problem is slightly less abstract than simply "how does this work" though. I've read the RFC for SOCKS 4 (I decided to implement SOCKS 4 first since it has less bytes in its requests to contend with) but I'm struggling to create the C string I need to send().
At present, I have a struct defined called Socks4Msg which looks like this:
struct Socks4Msg {
const static uint8_t version = 0x04; //SOCKS version 4 (obviously)
const static uint8_t command = 0x01; //1 is TCP CONNECT command
const static uint8_t nullbyte = 0x00; //null byte sent at message end
uint16_t port; //16 bit/2 byte port (network order)
uint32_t ip; //32 bit/4 byte IP address (network order)
Socks4Msg(uint16_t p, uint32_t i) : port(p), ip(i) { }
};
The function which creates the actual socket and does the work is here (where p and h hold the port and host to test through the proxy -- p is a string to maintain compatibility with HttpProxy which I've already implemented). port and addr are part of the class and are an int and string respectively; they're the details of the proxy server.
int Socks4Proxy::test(std::string p, std::string h) const {
uint16_t network_port = htons(str_to_numt<uint16_t>(p));
uint32_t network_ip = hostname_to_ip(h);
Socks4Msg msg_struct(network_port,network_ip);
SOCKET s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
int last_error;
if(s == INVALID_SOCKET) {
last_error = WSAGetLastError();
std::cerr << "Failed to initialise socket! Error code: " << last_error << std::endl;
return 2;
}
sockaddr_in st_addr;
st_addr.sin_family = AF_INET;
st_addr.sin_port = htons(port);
ipaddr_t ip = inet_addr(addr.c_str());
st_addr.sin_addr.S_un.S_addr = ip;
if(connect(s,(sockaddr*)&st_addr,sizeof(st_addr))!=0) {
last_error = WSAGetLastError();
std::cerr << "Socket failed to connect. Error code: " << last_error << std::endl;
return 2;
}
uint8_t message[13];
uint8_t* message_ptr;
memset(message, 0, 13);
message_ptr = message;
*message_ptr = msg_struct.version;
message_ptr++;
*message_ptr = msg_struct.command;
message_ptr++;
*message_ptr = msg_struct.port;
message_ptr += 2;
*message_ptr = msg_struct.ip;
message_ptr += 4;
*message_ptr = 'b'; message_ptr++; *message_ptr = 'o'; message_ptr++; *message_ptr = 'b'; message_ptr++;
*message_ptr = msg_struct.nullbyte;
message_ptr++;
*message_ptr = 0x00;
char smessage[13];
memcpy(smessage, message, 13);
int return_val;
while(return_val = send(s, smessage, strlen(smessage), 0)) {
if(return_val == SOCKET_ERROR) {
last_error = WSAGetLastError();
std::cerr << "Writing data failed. Error code: " << last_error << std::endl;
return 2;
}
//implement return_val < strlen(message) here
else break;
}
//remainder of function
I have tested and verified that the members of msg_struct contain the correct data (and in the correct byte order) before the C string manipulation starts.
I've tried doing it using memcpy() (e.g. memcpy(message_ptr, &msg_struct.port, 2)) in place of the assignments but I just can't understand why Wireshack always quotes the byte length of the sent data as 2 (i.e. version and command) but nothing else. (I know my knowledge of C strings - and therefore the code at that point - is a bit rough but I can't explain why it doesn't work)
Any advice would be greatly appreciated!
First of all message_ptr is uint8_t* and *message_ptr = msg_struct.ip; is wrong. You should cast message_ptr to uint_32t* and then assign data, like * ((uint32_t*)message_ptr) = msg_struct.ip; otherwise msg_struct.ip will be converted to uint8_t and then assigned. Same problems with other fields.
Check this and let me know if it is woring again :)
BTW. I think Wireshark network traffic analyzer could help you a lot in searching such kind of problems.
UPDATE
Probably a better idea is to create a structure which represents the message you want to send and cast message_ptr to the pointer on this structure. But do not forget to tell your compiler not to add any paddings.
UPDATE 2
Network and host byte order.
Do not forget that you should change bytes order using hton, ntoh, htonl or ntohl functions.