C sockets send UDP and process ICMP reply from router - c

I'm trying to send a UDP packet to a router with a time to live of 1, to then receive an ICMP time exceeded reply. So far I'm able to send the packet, but when my program gets to the recv part of the execution, it just hangs. I have an error check for recvfrom, but it doesn't even get to that. My computer is receiving the request. I know this because I run Wireshark when I run the program and I filter for ICMP requests. Every time I run the program, I receive the reply. What am I doing wrong with recvfrom?
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#define UNSPEC_PROTO 0
int main(int argc, const char *argv[])
{
if (argc != 2) {
printf("usage: routetracer <ip address or hostname>\n");
return -1;
}
struct addrinfo hints; //params for ret val of getaddrinfo
struct addrinfo* ret; //return value of getaddrinfo
struct sockaddr* reply_addr;
char ipv4[INET_ADDRSTRLEN];
char* msg = "THE PORT IS OVER 9000!!!!";
int status = 0;
int ttl = 0;
int src_sock = 0;
int recv_sock = 0;
socklen_t reply_addr_len = sizeof(struct sockaddr);
const char* dest_port = "9001";
int icmp_msg_len = 100;
char icmp_msg[icmp_msg_len];
//define what we want from getaddrinfo
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET; //IPv4
hints.ai_socktype = SOCK_DGRAM; //UDP packets
//call getaddrinfo to fill ret, w/ error chk
if ((status = getaddrinfo(argv[1], dest_port, &hints, &ret)) != 0) {
printf("getaddrinfo: %s\n", gai_strerror(status));
return -1;
}
//extract IPv4 address from ret
struct sockaddr_in* ip = (struct sockaddr_in *)ret->ai_addr;
//convert address from pure numbers to something easier to read
inet_ntop(ret->ai_family, &(ip->sin_addr), ipv4, INET_ADDRSTRLEN);
//kindly inform the user of which hostname they are connecting to
printf("Route for: %s\n", ipv4);
//create a socket for our machine
if ((src_sock = socket(ret->ai_family, ret->ai_socktype,
ret->ai_protocol)) < 0) {
fprintf(stderr, "Error creating host socket: %s\n", strerror(errno));
return -1;
}
//create a socket to recv icmp packet from hops
if ((recv_sock = socket(AF_INET, SOCK_DGRAM, UNSPEC_PROTO)) < 0){
fprintf(stderr, "Error creating recv socket: %s\n", strerror(errno));
}
/*
* We go from hop to hop by incrementing the time to live in the IP header
* for each hop we visit until we reach the destination IP address (which we
* already have). Time to live decrements for every hop, so once it reaches
* zero we report the IP address of the node we are connected to.
*/
//while(test_ip != dest_ip)
//time_to_live++
//send_to(dest_addr)
//receive icmp error message
//get src addr of error msg from ip header of icmp
//test_ip = src addr
/*
while (last_hop == 0) {
ttl++;
setsockopt(sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
sendto(sock, msg, strlen(msg), 0, (struct sockaddr *)ip, sizeof(ip));
}
*/
ttl = 1;
if (!(setsockopt(src_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)))) {
printf("TTL set successfully\n");
} else {
printf("Error setting TTL: %s\n", strerror(errno));
}
if ((sendto(src_sock, msg, strlen(msg), 0, ret->ai_addr,
ret->ai_addrlen)) > 0) {
printf("msg sent successfully\n");
} else {
fprintf(stderr, "Error sending msg: %s\n", strerror(errno));
}
if ((recvfrom(recv_sock, icmp_msg, icmp_msg_len, 0, reply_addr,
&reply_addr_len)) != -1) {
/* PROCESS THE INFORMATION */
printf("Packet received\n");
} else {
fprintf(stderr, "Error receiving packet: %s\n", strerror(errno));
}
return 0;
}

Normally, UDP pretty much ignores ICMP errors, so if you want to see them, you need to open a raw socket to receive all ICMP packets and look for ones relevant to your socket.
On Linux, at least, an alternative is to set the IP_RECVERR socket option. If you do that, you can do a recvmsg with the MSG_ERRQUEUE flag set to get any ICMP (or other) errors associated with your socket. This has the advantage of not requiring elevated privileges or a second socket.

In some implementations of sockets, UDP socket has to be connected to receive errors.
So, you need to add connect call and then use send/recv functions.
I've confirmed this on FreeBSD. At least one source clearly states that:
http://www.softlab.ntua.gr/facilities/documentation/unix/unix-socket-faq/unix-socket-faq-5.html (see 5.3 Does doing a connect() call affect the receive behaviourof the socket?)
P.S. Note, however, that you won't receive exact ICMP error message that way. You'll only get some error code, without many details (if any).

Check the options when you are opening your sockets.
See How to sniff all ICMP packets using RAW sockets.
See How to receive ICMP request in C with raw sockets.
You may also want to change the socket options to be non-blocking and use the select() function to determine if there is something to read or not.
For examples on using the select() function see the following.
Blocking recvfrom with select system call.
Unexepcted results with select and recvfrom.

First of all, your code has undefined behavior, because reply_addr is uninitialised. You should fix that first:
struct sockaddr_in reply_addr;
...then:
recvfrom(recv_sock, icmp_msg, icmp_msg_len, 0, (struct sockaddr*)&reply_addr,
&reply_addr_len);
Finally, you need to use raw sockets, not datagram sockets, to receive ICMP packets:
recv_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);

Related

Reading UDP packets with several clients

I have an application installed locally (not developed by me), which broadcasts UDP packets every second.
Reading the packets from my application (developed in C++ in Windows) which also is locally installed, works fine.
WSADATA data;
WORD version = MAKEWORD(2, 2);
int wsOK = WSAStartup(version, &data);
SOCKET serverIn = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in serverHint;
serverHint.sin_addr.S_un.S_addr = INADDR_ANY;
serverHint.sin_family = AF_INET;
serverHint.sin_port = htons(UDP_RECEIVE_PORT);
bind(serverIn, (sockaddr*)&serverHint, sizeof(serverHint));
sockaddr_in client;
int clientSize = sizeof(client);
int RECIEVE_BUFFER_SIZE = 65507;
char* recieveBuffer = new char[RECIEVE_BUFFER_SIZE];
while(updating)
{
int bytesIn = recvfrom(serverIn, recieveBuffer, RECIEVE_BUFFER_SIZE, 0, (sockaddr*)&client, &clientSize);
}
closesocket(serverIn);
WSACleanup();
But I recently noticed while I was testing some code, while my app was running, that the bind(...)
function returned an error code of 10048 (WSAEADDRINUSE). Hence, it seems the first client bound to listen for the UDP packets is the only one who can listen, and the other clients is unable to read the broadcasted UDP packets.
So then I added the SO_REUSEADDR option before calling the bind(...) function to be able to bind successfully to the socket:
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
setsockopt((SOCKET)serverIn, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptVal, bOptLen);
That works, but the recvfrom(...) function then does not recieve any data at all! I guess it waits for the other client to close its socket.
Next solution is to initialize the socket with SOCK_RAW instead.
The above option SO_REUSEADDR is now not needed, and remove it:
SOCKET serverIn = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
This works, I can read the data now! Though, Windows now requires the adminstrator rights for my application. Also I do recieve the UDP information in the data which I do not need.
Is there any better method to do this without requiring administrator rights, any possibility to discard the header information in the buffer?
Below is a little program I wrote to demonstrate that IPv4 UDP broadcast can and does work as expected under Windows (i.e. without requiring raw-sockets or Administrator privileges).
Run it with the command line argument "server" and it will send out one broadcast UDP packet per second.
Then also run several more instances of the same program, with no command line arguments, to receive the UDP packets and print a line of text to stdout whenever they do. The expected behavior should look like this:
As for why it's not working for you -- one possible guess is that your UDP-packet-sending program is actually sending out unicast UDP packets rather than broadcast. If that's the case, then I would expect that only one client program would receive packets (even if multiple clients are bound to the same port). A network trace tool like Wireshark might be able to help you determine if the UDP packets being sent are broadcast or unicast.
Anyway, here's the code:
#include <stdio.h>
#include <ws2tcpip.h>
#pragma comment(lib,"WS2_32")
static int BindUDPSocket(SOCKET sock, unsigned short port, bool allowPortSharing)
{
if (sock == INVALID_SOCKET) return -1;
if (allowPortSharing)
{
const BOOL trueValue = true;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &trueValue, sizeof(trueValue)) < 0) return -1;
}
struct sockaddr_in bindAddr; memset(&bindAddr, 0, sizeof(bindAddr));
bindAddr.sin_family = AF_INET;
bindAddr.sin_addr.s_addr = INADDR_ANY; // aka 0.0.0.0
bindAddr.sin_port = htons(port);
return bind(sock, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
}
int main(int argc, char ** argv)
{
WSADATA data;
WORD version = MAKEWORD(2, 2);
(void) WSAStartup(version, &data);
const unsigned short TEST_PORT = 12345;
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock<0) {printf("socket() failed\n"); exit(10);}
if ((argc > 1)&&(strcmp(argv[1], "server") == 0))
{
if (BindUDPSocket(sock, 0, false)<0) {printf("BindUDPSocket() failed for server\n"); exit(10);}
const BOOL allowBroadcast = true;
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char *) &allowBroadcast, sizeof(allowBroadcast)) < 0)
{
printf("setsockopt(SO_BROADCAST) failed\n");
exit(10);
}
const char buf[] = {0x01, 0x02, 0x03, 0x04}; // dummy data
struct sockaddr_in toAddr; memset(&toAddr, 0, sizeof(toAddr));
toAddr.sin_family = AF_INET;
toAddr.sin_addr.s_addr = INADDR_BROADCAST; // aka 255.255.255.255
toAddr.sin_port = htons(TEST_PORT);
printf("Sending outgoing broadcast UDP sockets on port %u, once per second\n", TEST_PORT);
while(true)
{
if (sendto(sock, buf, sizeof(buf), 0, (const sockaddr *) &toAddr, sizeof(toAddr)) == sizeof(buf))
{
printf("Sent %zu bytes of broadcast UDP data\n", sizeof(buf));
}
else printf("sendto() failed!\n");
Sleep(1000); // wait 1 second
}
}
else
{
if (BindUDPSocket(sock, TEST_PORT, true)<0) {printf("BindUDPSocket() failed for client\n"); exit(10);}
printf("Waiting to receive incoming broadcast UDP sockets on port %u\n", TEST_PORT);
while(true)
{
char buf[1024];
const int ret = recv(sock, buf, sizeof(buf), 0L);
printf("Received %i bytes of incoming UDP data\n", ret);
}
}
}

sendto() does not generate error if destination does not exist

I am using sendto() function in C. I have set the destination address and dest port. While sending UDP frames I can see the frames in Wireshark and the number of packet Wireshark shows are exactly as I have defined in my program.
The problem is even though the destination address is not reachable the frames are being sent and I can see it in Wireshark.
Should not the sendto() function generates a error if the destination IP is not existing?
if (sendto(sockfd, &buffer[i], UDP_FRAME, 0,
(const struct sockaddr*)&server, sizeof(server)) < 0)
{
fprintf(stderr, "Error in sendto()\n");
//return EXIT_FAILURE;
}
Dest. IP: 234.168.0.1
Dest port: 80 or 9 (discard protocol)
#define PORT (80)
#define FRAMES (20000)
#define UDP_FRAME (1442)
#define SERVERADDRESS "234.168.0.1"
#define BUFFER_SIZE (FRAMES * UDP_FRAME)
char buffer[BUFFER_SIZE];
int main(int argc, char **argv)
{
struct timespec start, end, loop_start, loop_end;
int sockfd, count_frame = 0, frames_total, i = UDP_FRAME, n=1;
struct sockaddr_in server;
printf("Build Data...\n");
build(buffer, sizeof(buffer));
printf("Configure socket...\n");
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
fprintf(stderr, "Error opening socket");
return EXIT_FAILURE;
}
/*----------------------------------------------------*/
/*--- Initialize address protocol ---*/
/*----------------------------------------------------*/
bzero((char*)&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(SERVERADDRESS);
server.sin_port = htons(PORT);
/*---------------------------------------------------*/
/*--- S E N D I N G D A T A --*/
/*---------------------------------------------------*/
printf("\nSend UDP data...\n\n");
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
clock_gettime(CLOCK_MONOTONIC_RAW, &loop_start);
frames_total = 0;
for (int i = 0; i < BUFFER_SIZE; i += UDP_FRAME) {
//while(1) {
if (sendto(sockfd, &buffer[i], UDP_FRAME, 0,
(const struct sockaddr*)&server, sizeof(server)) < 0)
{
fprintf(stderr, "Error in sendto()\n");
//return EXIT_FAILURE;
}
count_frame += 1;
clock_gettime(CLOCK_MONOTONIC_RAW, &loop_end);
if ((loop_end.tv_nsec - loop_start.tv_nsec) > 5000000) {
printf("\nCount [%d] ... ", n);
printf("Fames sent: %d\n", count_frame);
frames_total += count_frame;
n+=1;
count_frame = 0;
clock_gettime(CLOCK_MONOTONIC_RAW, &loop_start);
}
}
printf("Total successful counted frames: %d \n", frames_total);
return EXIT_SUCCESS;
}
UDP is an unreliable protocol. A call to sendto is successful once the packet leaves the interface. After that, whether it gets to its destination or not is up to the network.
Even if the network supports ICMP messages stating that the host or port is not reachable, it won't matter in your particular case because you're sending to a multicast address. If you have at least one multicast-capable interface, the system will pick one to send the packet over. It could be received by multiple (or no) hosts. So it doesn't make sense to say that the destination is not reachable.
sendto() will give you an error if the host doesn't know a route to the host (which is almost never the case, since your host will have a default gateway). Otherwise, you might (or might not) receive an ICMP destination unreachable message if your packet did not reach the targeted application, but this is unreliable and won't be communicated by the call to sendto().
What you can do is to query the socket with
struct sock_extended_err err;
socklen_t errlen = sizeof(err);
getsockopt(fd, SOL_IP, IP_RECVERR, &err, &errlen);
for received errors, which will give you detailed information about received errors on the socket (i.e. ICMP port unreachable, ICMP host unreachable, etc. pp). This can help, but as I said, it is not realiable, since ICMP messages are often strictly rate limited, filtered on the way or not sent at all, if your packet is blocked by a packet filter (firewall).

Raw sockets: sendto() and recvfrom() not working

I am trying to write a client/server application using RAW sockets.
There are multiple problems:
When the client sends a message to the server using sendto() method, an error invalid argument is returned by sendto() method. Why this error message?. The corresponding code is marked under the section ERROR 1. The code of sendto() is commented in this post.
Since I have commented the send message part, the client should wait for a message; recvfrom() being a blocking system call. Instead, recvfrom() returns with a message E always. From where did this message arrive?. The corresponding code is marked as ERROR 2.
If I change protocol (3rd) argument in socket() to 0 or IPPROTO_RAW I get Protocol not supported error. Why these errors?
The operating system is Ubuntu.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h> // For the socket () etc. functions.
#include <netinet/in.h> // For IPv4 data struct..
#include <string.h> // For memset.
#include <arpa/inet.h> // For inet_pton ().
#define BUF_SIZE 30
void main ()
{
int rst; // Return status of functions.
/**************** Create a socket. *******************************/
int sfd; // Socket file descriptor.
sfd = socket (AF_INET, SOCK_RAW, IPPROTO_UDP); /*
* AF_INET --> IPv4, SOCK_RAW for Raw socket,
* 0 --> for any protocol. */
if (sfd == -1)
{
perror ("Client: socket error");
exit (1);
}
/*********** Server's address ***********************************/
struct sockaddr_in srv_addr;
socklen_t addrlen = sizeof (struct sockaddr_in);
// Initializing the server's address to zero.
memset (&srv_addr, 0, addrlen);
srv_addr.sin_family = AF_INET; // Address is in IPv4 format.
// srv_addr.sin_port = htons (0); // Port number of the server.
rst = inet_pton (AF_INET, "127.0.0.1", &srv_addr.sin_addr); /* Note
* that third field should point to an in_addr (in6_addr). */
if (rst <= 0)
{
perror ("Client Presentation to network address conversion.\n");
exit (1);
}
/****************** ERROR 1 ************************************
******************* Sending message to the server. *************/
const int flags = 0;
const char *msg = "Hello";
/* rst = sendto (sfd, msg, strlen(msg)+1, flags,
(struct sockaddr *) &srv_addr,
sizeof (struct sockaddr_in));
if (rst < 0)
{
perror ("Client: Sendto function call failed");
exit (1);
}
else
printf ("Client: Sent data size = %d\n", rst);
*/
/******************* ERROR 2 ***********************************
******************* Receiving message from server. ************/
// Initializing the server's address to zero.
memset (&srv_addr, 0, addrlen);
char buf[BUF_SIZE] = {'\0'};
rst = recvfrom (sfd, buf, BUF_SIZE, flags,
(struct sockaddr *) &srv_addr,
&addrlen);
if (rst < 0)
{
perror ("Client: couldn't receive");
exit (1);
}
printf ("Message from server = |%s|\n", buf);
/* Address of the server. */
const char *buf2 = inet_ntop (AF_INET,
(struct sockaddr *) &srv_addr, buf, BUF_SIZE);
if (buf2 == NULL)
{
perror ("Client: Conversion of sender's address to presentation failed");
exit (1);
}
printf ("Servers address, = %s\n", buf2);
close (sfd);
}
SOCK_RAW is not for use with UDP. SOCK_DGRAM is correct. For a tutorial, see:
a tutorial from Rutgers
edit: overlooked the init of the srv_addr... sorry.
using AF_INET + SOCK_RAW socket you can send anything - the payload is just added on top of the IP-layer. the IPPROTO_UDP just tells the kernel what the next layer will be (the layer your payload is added to) and which value the protocol field of the IP header must be set to. so to stay save (if you go to send raw data) set the protocol to something not commonly used).
you need the permission to create a raw socket. this commonly means: start as root, create the socket and then drop the privileges.
q2: this is the message you send to yourself (and a strong indication that your code somehow worked). The 'E' is just the first byte (0x45) in the IP-header - version 4 and header length 5. just dump the whole buffer..., eg.
printf ("Message from server = |");
for (i = 0; i < rst; i++)
printf("%c", isprint(buf[i]) ? buf[i] : '?') ;
printf ("|\n");
q3:
0 means: guess what is usually used (eg. INET + DGRAM -> TCP). As you specified raw the kernel is not able to choose a common protocol for the next layer.
IPPROTO_RAW should work (see comment of #nos)

UDP Multicast not receiving message

I am trying to make a simple UDP multicast example where a message is sent from one program and received from the other but right now the output is only:
Connected
Message Sent
and
bind
setup multicast
Can someone please tell me what I am missing so that I can receive the message successfully? Thank you!! Here are the codes in full:
int main(int argc, char *argv[])
{
int udp_socket_info;
struct sockaddr_in udp_server;
char* message="test";
//create socket
udp_socket_info = socket(AF_INET, SOCK_DGRAM, 0);
if (udp_socket_info == -1) {
puts("Could not create socket");
}
//assign local values
udp_server.sin_addr.s_addr = inet_addr("225.0.0.37"); //multicast address
udp_server.sin_family = AF_INET;
udp_server.sin_port = htons( 1100 );
//checks connection
if (connect(udp_socket_info, (struct sockaddr *)&udp_server, sizeof(udp_server)) < 0) {
perror("Connection error");
}
puts("Connected");
//sends message
if( sendto(udp_socket_info , message , strlen(message) , 0, (struct sockaddr *)&udp_server, sizeof(udp_server)) < 0) {
perror("Send failed");
}
puts("Message Sent");
}
and the second program is
int main(int argc, char *argv[])
{
//initialize udp socket and structures
int udp_socket_info;
struct sockaddr_in udp_server;
struct sockaddr addr;
struct ip_mreq mreq;
socklen_t fromlen;
fromlen = sizeof addr;
char incoming_message[100];
//create udp socket
udp_socket_info = socket(AF_INET, SOCK_DGRAM, 0);
if (udp_socket_info == -1) {
puts("Could not create socket");
}
// set up
memset((char*)&udp_server,0,sizeof(udp_server));
udp_server.sin_family=AF_INET;
udp_server.sin_port = htons( 1100 );
udp_server.sin_addr.s_addr = inet_addr("192.168.0.100"); //local address
// bind
if (bind(udp_socket_info,(struct sockaddr *)&udp_server, sizeof(udp_server)) < 0) {
perror("bind error");
exit (1);
}
puts("bind");
// use setsockopt() to join multicast group
mreq.imr_multiaddr.s_addr=inet_addr("225.0.0.37"); //multicast address
mreq.imr_interface.s_addr= htonl(INADDR_ANY); //can use local address here too
if (setsockopt(udp_socket_info, IPPROTO_IP,IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
perror("setsockopt");
exit (1);
}
puts("setup multicast");
//Receive an incoming message
if( recvfrom(udp_socket_info, incoming_message , sizeof(incoming_message), 0, &addr, &fromlen) < 0) {
puts("Received failed");
exit (1);
}
puts("Message received");
puts(incoming_message);
}
You should bind the receiving socket to INADDR_ANY, not a local interface address. Otherwise you run the risk that the sender is out there via a different route and can't reach your socket. On some platforms you can bind it to the multicast address itself.
NB when you get an error it isn't sufficient to print a message of your own devising. The message must contain the errno, or the result of strerror(). For example, call perror().
Your receiver should not bind to a local address. It should instead bind to either INADDR_ANY or the multicast address you intend on joining. Binding to a local address breaks multicast on Linux systems.
Note that if you bind to a multicast address, this means you'll only receive packets for that multicast address. If you want to receive from multiple multicast addresses or if you also want to receive unicast packets then you need to bind to INADDR_ANY.
When joining a multicast group, using INADDR_ANY causes you to join the specified group on the default network interface. It's generally a good idea to explicitly specify an interface.
As EJP mentioned, you should always use perror to print error messages from any system or library call to ensure that a meaningful error message is printed.
Wireshark is an important tool for programs such as this. It helps you ensure that packets are going out and coming in the network interfaces you expect.
Also, if the sender and receive are on different network segments, you'll need to set the TTL via the IP_MULTICAST_TTL socket option. You also need to make sure that any routers between them are configured to pass multicast traffic.

Send an UDP packet and receive an ICMP response from router in C

I'm trying write a C program that sends an UDP packet to a given IP adress and waits for an ICMP response of a router telling that the time to live expired. It's kept very simple because I just want to understand the mechanism at first. What I need is someone checking my code giving feedback on what's wrong and what's missing. I'm very unexperienced at C-programming but I have to do it as an assignment - giving my best to understand it...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ip.h>
// The packet length
#define PCKT_LEN 8192
// Source IP, source port, target IP, target port from the command line arguments
int main(int argc, char *argv[])
{
int send, recv, resp;
int ttl = 1; // Time to live
char buffer[PCKT_LEN];
// Destination address
struct sockaddr_in dst;
// ICMP Response
struct msghdr icmp;
memset(buffer, 0, PCKT_LEN);
// Create a raw socket with UDP protocol
if ((send = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
printf("Could not process socket() [send].\n");
return EXIT_FAILURE;
}
// ICMP Socket
if ((recv = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
{
printf("Could not process socket() [recv].\n");
return EXIT_FAILURE;
}
dst.sin_family = AF_INET;
dst.sin_addr.s_addr = inet_addr("74.125.39.106");
dst.sin_port = htons(60001);
// Define time to life
if(setsockopt(send, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0)
{
printf("Could not process setsockopt().\n");
return EXIT_FAILURE;
}
if(sendto(send, buffer, sizeof(buffer), 0, (struct sockaddr *) &dst, sizeof(dst)) < 0)
{
printf("Could not process sendto().\n");
return EXIT_FAILURE;
}
if((resp = recvmsg(recv, (struct msghdr *) &icmp, IP_RECVERR|MSG_ERRQUEUE)) < 0 )
{
printf("Could not process recvmsg().\n");
return EXIT_FAILURE;
}
close(send);
close(recv);
return 0;
}
I keep receiving "Could not process recvmsg()." and I have no clue anymore what else to try. I'd like to receive an ICMP answer and read its senders IP-Address.
Looking forward to helpfull hints.
Best regards!
I normally use
recvfrom(serversock, buf, 100, 0, (struct sockaddr *)&rcv,&size);
printf("Received packet from %s:%d\nData: %s\n\n", inet_ntoa(rcv.sin_addr), ntohs(rcv.sin_port), buf);

Resources