How to send custom packets in omnet++? - c++

Let's say i created my own packet called myPacket. Is there a way i can send it using socket.sendTo()?
I know socket.sendTo() takes in an INET packet so is there a way to convert myPacket into an INET packet?
The module that is going to receive the packet is Radio. I checked Radio's functions and they take in an inet packet so what can i do about it?
Signal *Radio::createSignal(Packet *packet) const
{
encapsulate(packet);
if (sendRawBytes) {
auto rawPacket = new Packet(packet->getName(), packet->peekAllAsBytes());
rawPacket->copyTags(*packet);
delete packet;
packet = rawPacket;
}
Signal *signal = check_and_cast<Signal *>(medium->transmitPacket(this, packet));
ASSERT(signal->getDuration() != 0);
return signal;
}

Sending messages using sockets needs a socket on the other side. If you have a socket at the other side so go ahead and send your message using a socket.

Basically, messages sent by using the cSimpleModule basic member function send(). This method is used to send messages to other modules through gates. One can also use the scheduleAt() to send a message at specific point in time.
If you use a higher level application such as http or tcp applications, so you are most probably going to use sockets. Sockets also use send() and scheduleAt() to send messages through gates.

You need to do 4 steps:
Define your own .msg class and extend some of the inet predefined classes. See inet/applications/base/ApplicationPacket.msg as an example.
Define your communication protocol aka inet socket object to pass the messages. Look at this guide. Don't forget to pass destination address and port, normally they are defined as .NED parameters and injected through the omnetpp.ini file.
Then you need to write a method, which builds your packet and sends it to the destination address. Take a look at the method UdpBasicApp::sendPacket() at inet/applications/udpapp/UdpBasicApp.cc as an example.
At receiver side I usually have a bunch of processing methods switched in handleMessage method or similar one to catch all possible messages my receiver can receive and process. All such methods take cMessage* msg as an argument and then at the beginning:
Packet* packet = check_and_cast<Packet*>(msg);
if (!packet) {
return;
}
const auto& payload = packet->peekAtFront<YourOwnPacketClass>();
// work with you message body...

Related

How to parse/check an HTTP message in PCapPlusPlus?

In PCap++, I want to detect if a payload is an HTTP request or not. For this, I am trying to parse the string and expect the library to allows me to check if this was done successfully.
Unfortunately, I was unable to achieve this:
I can create a RawPacket with the message
I can create a Packet with the message, but it does not contains any HttpRequestLayer, in consequence, the parsing is useless to detect the validity of the message.
I cannot create an HttpRequestLayer directly from the message.
Some examples:
std::string msg= "GET /index.html HTTP/1.1\nHost: example.com\n\n";
// Try to get a RawPacket: works, but does not helps a lot
struct timeval tp; // requires <time.h>
gettimeofday(&tp, nullptr);
RawPacket rp(static_cast<const uint8_t*>(msg.data()), static_cast<int>(msg.size()), tp, false);
// Trying to parse it: works but detect generic Newtork layer only, no HTTP
Packet p(&rp, false, HTTP);
// Trying to create an HttpRequestLayer directly: crash
HttpRequestLayer http(static_cast<const uint8_t*>(msg.data()), static_cast<int>(msg.size()), nullptr, nullptr);
My question is:
How to detect if a message is a valid HTTP message with PCap++?
Note: I am looking for an efficient solution (very sub-optimal solutions, like generating TCP layers is not an option).
PcapPlusPlus can parse packets, not messages. A RawPacket object expects a stream of bytes that represent a network packet, typically with a data link layer (e.g Ethernet), network layer (e.g IP), transport layer (e.g TCP) and application layer (HTTP in this case). PcapPlusPlus will parse this byte stream into the a list of layers/protocols you can look into.
HTTP is an application protocol, hence any HTTP packet will contain the other layers mentioned above. So providing just the HTTP message is not enough and PcapPlusPlus won't be able to parse it as a packet.
You can learn more about PcapPlusPlus from the tutorials: https://pcapplusplus.github.io/docs/tutorials
Specifically you can look into the packet parsing tutorial:
https://pcapplusplus.github.io/docs/tutorials/packet-parsing
pcpp::Packet has a method of getting layer you need - getLayerOfType. You could detect HTTP message using it.
Example:
timeval tm;
gettimeofday(&tm, NULL);
pcpp::RawPacket rawPacket((uint8_t*)rawPacketFromNet.data(), rawPacketFromNet.size(), tm, false, pcpp::LinkLayerType::LINKTYPE_RAW);
pcpp::Packet parsedPacket(&rawPacket);
pcpp::HttpRequestLayer* httpLayer = parsedPacket.getLayerOfType<pcpp::HttpRequestLayer>();
if (httpLayer)
{
// you have this layer in your packet
uint8_t* dataPtr = httpLayer->getData();
size_t size = httpLayer->getDataLen();
}
I think your example could have worked if you'd start with pcpp::Packet and then add to it http layer. For constructing http layer in your case try to use HttpRequestLayer(HttpMethod method, std::string uri, HttpVersion version);

Message to all connected clients(Winsock)(c++)

I have a server, which creates a separate thread for each new client
while ((client_socket = accept(server_socket, (sockaddr*)&client_info, &client_addr_size)))
{
nclients++;
HOSTENT *hst;
hst = gethostbyaddr((char*)&client_info.sin_addr.S_un.S_addr, 4, AF_INET);
printf("+%s [%s] new connect!\n", (hst) ? hst->h_name : "", inet_ntoa(client_info.sin_addr));
PRINTUSERS;
DWORD thID;
CreateThread(NULL, NULL, SexToClient, &client_socket, NULL, &thID);
}
Stream function every n seconds sends a message.(All streams do not do it at the same time).How to send a message to all clients at the same time?(broadcast)
I cant See Streamfunction. Without the corresponding function I cant give a perfect answer. Normally you would send (asynchron) in a for loop to all clients. The System would teen send the Massage to each Client one After Another. If you want to truly send a Massage to multiple clients at the Same time you need to use multicast.
(= sending one package which will arrive at multiple clients.) Unfortunately this is not possible using TCP, since TCP etablishes a (secure) point to point connection between one host and one client. You would have to use UDP. Remember that UDP wont care if the packages will arrive in the right Order, are correct or arrive at all.

Conflicts between different types of packets in OMNeT++

I have created a simulation in OMNeT++
where I have one client and one server (both of them are UDPBasicApp modules). The client sends packets
to the server. The server also sends packets to the client, which are two subclasses of cPacket.
Unfortunately, there are conflicts between those two types of packets
when they are received by the client. Let's assume that the types of the two packets are called
FirstPacket and SecondPacket respectively (classes derived from cPacket). By running the simulation, as soon as the client receives the first
packet from the server the simulation crashes and I get someting like the following error message:
"check_and_cast(): cannot cast (FirstPacket*).ClientServer.client.udpApp[0] to type SecondPacket"
How I can solve this problem? How the server can successfully receive both types of packets sent by the client?
You are probably using something like SecondPacket* p = check_and_cast<SecondPacket*>(pkt); to force each incoming packet to be treated as being of type SecondPacket. OMNeT++'s check_and_cast will abort your simulation if this is not the case. A simple solution is to use a dynamic_cast instead:
PacketTypeA* a = dynamic_cast<PacketTypeA*>(pkt);
PacketTypeB* b = dynamic_cast<PacketTypeB*>(pkt);
if (a) {
printf("got packet type A: %d", a->some_field_of_a);
}
if (b) {
printf("got packet type B: %d", b->some_field_of_b);
}

Can we pass the captured packets as argument to Socket send() function

I'm beginner to Networking. We have sender and receiver application. I have captured the packets sent by sender to receiver using WinDump.
I'm writing a python sender application which will fuzz the packets sent by sender to receiver.
I just want to confirm, can I directly put the packet data obtained using WinDump to socket send() method.
Say, "arp who-has host1 tell host2" is the packet obtained by WinDump
Can I write,
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(arp who-has host1 tell host2)
In general pyhton network programming you can not pass as the arguments using send method.you just only pass the string as arguments as variable.
Basically we are using the send() and sendall() method to transmits the TCP messages.
I have mentioned the below desciption for both the method.
socket send() method :
The socket's send() method is not guaranteed to send all of the data you pass it. Instead, it returns the number of bytes that were actually sent and expects your application to handle retransmission of the unsent portion
from socket import socket
sock = socket()
sock.connect(('1.2.3.4', 1234))
sock.send('My Name is Dasadiya Chaitanya !!!\n'')
sock.close()
socket sendall() method :
which is same work as the send() method but python provides a convenience method called sendall() that makes sure all of your data is sent before returning and also provide the guarantee to send all the data to the receiver.
from socket import socket
sock = socket()
sock.connect(('1.2.3.4', 1234))
sock.sendall('My Name is Dasadiya Chaitanya !!!\n')
sock.close()
I hope this should helpful for you :)

Answer an UDP packet

I have a UDP server using the following code:
void initialize()
{
connect(&_udpSocket, SIGNAL(readyRead()), this, SLOT(onUdpDatagram()));
_udpSocket.bind(QHostAddress::Any, 28283);
}
void onUdpDatagram()
{
qDebug() << "udp packet received!";
_udpSocket.write("Hello");
}
Unfortunately when a UDP packet is received, I have the following error in the log:
QIODevice::write: device not open
How can I make the UDP socket writable? I tried to create another socket for the answer that connect to the sender address and port but the sending won't use the 28283 port anymore...
Any idea?
For info: I'm using Qt 5.2.1 on MacOS 10.9
UDP is not a connection-based protocol. You don't get a separate socket for each peer, instead there's one socket for all communication on a single port.
Therefore, there's some extra effort needed to reply to an incoming UDP packet. You need to retrieve the sender address from the datagram you received, and send back to that same address. In the sockets API this is done by using recvfrom and sendto functions instead of recv (or read) and send (or write) -- the latter are designed for connected sockets like you use with TCP.
You didn't show the declaration (really, the type) for your _udpSocket variable, so I'm assuming that you are using a QUdpSocket. In that case, it looks like you will want to use the readDatagram and writeDatagram functions, which like recvfrom and sendto, have an additional parameter for the peer address (actually, it's a pair, one for the IP address, one for the port).
Here's what the Qt documentation says about that:
The most common way to use this class is to bind to an address and port using bind(), then call writeDatagram() and readDatagram() to transfer data. If you want to use the standard QIODevice functions read(), readLine(), write(), etc., you must first connect the socket directly to a peer by calling connectToHost().
Coincidentally, this warning was introduced by me in Qt upstream:
QIODevice::write: device not open
It should be pretty clear unlike before the introduction of this, namely: you have forgotten to connect to the host with your udp socket. You cannot expect it to write and/or read if it is not even open and/or connected. See the documentation for details:
If you want to use the standard QIODevice functions read(), readLine(), write(), etc., you must first connect the socket directly to a peer by calling connectToHost().
You have to do something like this somewhere in your code:
_udpSocket.connectToHost(myHostAddress, 28283, ReadWrite, AnyIPProtocol);
The last two parameters can be skipped as they are the default. As you can read from the documentation, this method call will open the socket for you, too, which is necessary to get done for QIODevice read and write operations.
That being said, you really should not neglect error checking in your code as it currently seems to stand. It will be difficult to find the issues this way.
Also, it is ice on the cake, but I would encourage you to start using the "new" signal-slot syntax, which is not so new, but much more modern and handier:
void initialize()
{
connect(&_udpSocket, &QUdpSocket::connected, [&_udpSocket]() {
connect(&_udpSocket, &QUdpSocket::readyRead, [&_udpSocket]() {
qDebug() << "udp packet received!";
if (_udpSocket.write("Hello") != 6)
qDebug() << "Failed to write:" << _udpSocket.errorString();
});
});
connect(&_udpSocket, &QUdpSocket::error, [&_udpSocket]() {
qDebug() << "Error occured:" << _udpSocket.errorString();
});
_udpSocket.connectToHost(myHostAddress, 28283, ReadWrite, AnyIPProtocol);
}