Recreate and send packet captured by nfqueue - c++

I capture all the packets in one side with help of nfqueue, "record" them (all the data: ip info, next protocol info etc) with nfq_get_payload and deliver them into another side with help of udp. How can I restore this packet on another side and then send to myself(2 side) like there is no udp-encapsulation between? Should I use some nfqueue API or I have to implement all the protocols packet creation (UDP, ICMP, TCP, etc)? And how should I send this restored packet?

Ok, I successfully recreated and sent forward my packet encapsulated in UDP. After recreation I needed to send this packet to another IP, but you can use original destination address. So the code snippet:
char *full_packet;
int size;
// some actions to get full_packet and size from UDP packet
// assume you recreated this: int size = nfq_get_payload(nfa, &full_packet);
int sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
// also optional string needed in my case:
setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, "wlan0", strlen("wlan0"));
if (sock == -1) {
perror("socket() failed");
return 1;
}
struct sockaddr_in to;
struct ip *iph = (struct ip *)full_packet;
to.sin_addr.s_addr = inet_addr("192.168.0.107"); // here you can set IP address where you need send this packet
to.sin_family = AF_INET;
int bytes = sendto(sock, full_packet, size, 0, (struct sockaddr*) &to, sizeof(to));
if (bytes == -1) {
perror("send() failed");
return 1;
}
I hope this will help somebody

Related

How to receive multicast UDP packets correctly?

new to multicast networking, I need to receive UDP packets from a multicast channel through one of the NICs on my windows box, followed Microsoft docs and some blog entry, but still having issues.
I create a socket via
ls = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
call.
Then setsockopt to SO_REUSEADDR
unsigned int reuse = 1;
if( setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0 )
{
LOG4CXX_ERROR(logger, "Reusing ADDR failed. Err: " << WSAGetLastError());
}
If socket is good
int result = bind(ls, reinterpret_cast<SOCKADDR*>(&server), sizeof(server));
where
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(myport);
If bind succedes
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("e.f.g.h");
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if( setsockopt(ls, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)) < 0 )
{
LOG4CXX_ERROR(logger, "setsockopt multicast group add membership failed. Err: " << WSAGetLastError());
}
The box on which I need to receive packets has four NICs, network administrators told me that I have to use the third one, let's say that it has a.b.c.d IPv4 address
They told me also that mcast IP is e.f.g.h
If I run windump.exe -i 3 on my windows box I see something like this
... 12:53:58.454987 IP i.k.l.m.xxxxx > e.f.g.h.myport: UDP, length 58
...
After initializing my UDP socket I call recvfrom
sz = recvfrom(ls, buffer, DATA_BLOCK_SIZE, 0, reinterpret_cast<SOCKADDR*>(&client), &size);
where sz is an int, ls is my socket, buffer is a "suitable buffer", DATA_BLOCK_SIZE is buffer size, client is a SOCKADDR pointer to receive info from the sender, and size is the received message size.
My code stucks in the recvfrom call never receiving anything.
I'm clearly making a mistake somewhere but not understanding where and worse why.
If someone can explain me what's happening it will be very appreciated.
SOLVED ...
I changed these lines only
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("e.f.g.h");
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
to
struct ip_mreq mreq;
inet_pton(AF_INET, "e.f.g.h", &(mreq.imr_multiaddr));
inet_pton(AF_INET, "a.b.c.d", &(mreq.imr_interface));
As I have guessed I was not correctly indicating in my struct ip_mreq which was the network interface to use for multicast messages.
It was my fault. Sorry for the noise.

C++ Send packet through UDP but not receiving it

I'm currently working on a project need to broadcast the data packet to a common port D88 for every second, but the client can not receive the data packet. I'm not sure I'm using the right way to send the packet.
int sockfdBroad;
struct sockaddr_in addrBroad;
swStat.packetBroadSent=0;
sockfdBroad=socket(AF_INET,SOCK_DGRAM,0);
bzero(&addrBroad,sizeof(addrBroad));
addrBroad.sin_family = AF_INET;
addrBroad.sin_addr.s_addr=inet_addr("192.168.1.255");
addrBroad.sin_port=htons(3464);
if ((cycles%1000)==0)
{
currenttime = getMicrosTimeStamp();
createTimePacket(bufferTime,currenttime,Odroid_Trigger);
sendto(sockfdBroad,bufferTime,PACKET_LENGTH_TIME,0,(struct sockaddr *)&addrBroad,sizeof(addrBroad));
swStat.packetBroadSent++;
}
Assuming that the netmask for 192.168.1.255 is 255.255.255.0, 192.168.1.255 is a broadcast address. From man ip(7):
Datagrams to broadcast addresses can be only sent or received when the SO_BROADCAST socket flag is set.
In other words, both the sender and the receiver must do:
int value = 1;
if(-1 == setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &value, sizeof value))
// Handle error.
If you check the return value of sendto it must be -1 and errno == EACCESS. Always check the return values.

Directed UDP to IP address that doesn't exist

I am experiencing slowdowns when attempting to send a UDP message to an IP address that is non-existent. We read a list of IP/ports out of a configuration file and expect that those combinations will exist. In some situations, the remote machine may not be online yet and the IP will not exist on the network. In this case, i would prefer that we do not attempt to send the data.
I'm looking for suggestions on a good way to determine that the IP doesn't exist in order to skip sending the data. I do not want to completely remove it from the list because there is the chance that the machine may come online and i'd like to continue sending data.
Relevant code:
int SendData(const char *data, int size, bool openIfClosed)
{
std::lock_guard<std::mutex> lock(sendMutex);
//if the socket was not already opened, close it after i do my send
bool closeAfterSend = mySocket == INVALID_SOCKET ? true : false;
if (!OpenSocket(openIfClosed))
return 0;
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(remotePort);
address.sin_addr.s_addr = remoteIPAddress.GetIPAddressAsULong();
//check if remote address exists prior to send?
int bytesSent = sendto(mySocket, data,
size, 0, (struct sockaddr *)&address, sizeof(address));
if (bytesSent == size)
numMsgsOut++;
else
{
//fail
}
if (closeAfterSend && openIfClosed)
{
closesocket(mySocket);
mySocket = INVALID_SOCKET;
}
return bytesSent;
}

Cannot receive UDP Stream from Port 2368 (Linux) C

I'm currently working with a Laser Sensor that delivers a UDP data stream on Port 2368. I can see the packets with Wireshark.
As I'm not able to post an image, I write what Wireshark shows for a packet:
Source: 192.168.17.141
Destination: 192.168.3.255
Protocol: UDP
Source Port: https (443)
Destination Port: opentable (2368)
However, I want to read the packets using sockets with following example C program:
int main(int argc, char *argv[])
{
int sock, n, res;
unsigned int length = 1206;
char* buffer = new char[1206];
sock= socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) error("socket");
uint16_t udp_port = 2368;
sockaddr_in my_addr;
socklen_t len = sizeof(sockaddr_in);
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(udp_port);
my_addr.sin_addr.s_addr = INADDR_ANY;
cout << my_addr.sin_family << endl;
cout << my_addr.sin_port << endl;
cout << my_addr.sin_addr.s_addr << endl;
res = bind(sock, (sockaddr *)&my_addr, sizeof(sockaddr_in));
if (res == -1)
{
perror("bind");
return -1;
}
while (true)
{
n = recvfrom(sock,buffer,1,0,NULL,NULL);
if (n < 0) error("recvfrom");
}
close(sock);
return 0;
}
The program is successful until it comes to recvfrom(). There the socket waits for packages and does not receive anything. I wrote the same program for Windows with Winsock and it worked perfectly. As I am relatively new to Linux OS I do not know how to fix this problem and would be thankful for advice!
Additional information: I manually assigned following IP and netmask to eth4 (this is the interface where the device is connected):
IP: 192.168.3.5
NM: 255.255.255.0
Set the SO_BROADCAST option, even for receiving. According to the socket(7) manpage:
SO_BROADCAST:
Set or get the broadcast flag. When enabled, datagram sockets receive packets sent to a broadcast address and they are allowed to send packets to a broadcast address. This option has no effect on stream-oriented sockets.
It could also be that your interface config is incorrect. Verify that you have a 192.168.3.xxx/24 address configured for the interface in question.
char buffer[1200+6]; /* no need for dynamic buffers */
...
n = recvfrom(sock, buffer, sizeof buffer, 0, NULL, NULL);
BTW your usage of recvfrom() is equivalent to
n = recv(sock, buffer, sizeof buffer, 0);
, or even:
n = read(sock, buffer, sizeof buffer);
You have
IP: 192.168.3.5 NM: 255.255.255.0
and
Source: 192.168.17.141 Destination: 192.168.3.255
This can't work, if there is no router involved. Try
IP: 192.168.3.5 NM: 255.255.0.0
as an interims measure, but do read up on IP
Edit: Maybe better look into your Laser sensor and set it to 192.168.3.[something free] with Destination directly your 192.168.3.5, and debug the broadcasting later.

WSARecvFrom on unconnected UDP socket does not return

I am writing a small program that tests an UDP network service. The implementation of the service is allowed to create a new socket for the session and respond to the client from there, at which point the client is then required to talk to this address (similar to TFTP).
Minimal client sans error checking looks like this:
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in destaddr = { ... };
MSGBUF msg[] = { ... };
DWORD sent;
WSASendTo(fd, msg, sizeof msg / sizeof *msg, &sent, 0, (sockaddr *)sa, sizeof sa, 0, 0);
char buffer[4096];
MSGBUF rcvmsg = { sizeof buffer, buffer };
DWORD received;
sockaddr_storage sa;
socklen_t sa_len = sizeof sa;
DWORD flags = 0;
WSARecvFrom(fd, &rcvmsg, 1, &received, &flags, (sockaddr *)&sa, &sa_len, 0, 0);
The client works fine if the server responds from the same address and port that the initial message was sent to, however replies from another port are silently discarded and the client hangs in WSARecvFrom.
Explicitly binding the socket to { AF_INET, INADDR_ANY, 0 } to force assignment of a local port, or invoking listen(fd, 5); makes no difference, as expected.
Is there anything in WSASendTo that implicitly connects an UDP socket, and if so, what should I do to avoid this?
UDP doesn't have connections. Datagrams are sent to and from ports; it's one-way communication.
It sounds to me like your server is letting itself be assigned a temporary port (i.e. passing 0 as the port in sockaddr_in), instead of using a specific port. This won't work.
Since UDP has no concept of a connection, each time you send data, it could be sent from a different port; the first send doesn't reserve the port that it was given, it just sends a datagram from it and then lets it go.
Your server should be binding itself to a specific port.
Meh, it was a firewall issue. Adding the application to the list of programs allowed to receive incoming traffic fixed the issue.