When receiving on an ICMP socket, (SOCK_RAW with IPPROTO_ICMP), since
there is no concept of "port" in the ICMP protocol, how can an
application determine that a received packet is not part of some other
TCP/UDP/whatever socket transmission that is also happening at the
same time?
For example, suppose you have an application with 2 threads. Thread 1
sets up a TCP server socket, and continuously receives data from a
connected client. Thread 2 continuously sends echo request packets
(ping) to the same client using an ICMP socket, and then receives echo
replys. What is to prevent Thread 2 from receiving one of the TCP
packets instead?
ICMP is a different protocol from TCP and UDP, as determined by the protocol field in the IP header. When you open a socket with IPPROTO_ICMP, you're telling the socket to transmit and receive only packets with IP headers whose protocol field is set to ICMP.
Similarly, sockets opened with IPPROTO_TCP or IPPROTO_UDP respond only to packets whose IP headers contain a protocol field that is set to TCP or UDP, respectively.
You can check the ICMP header for the type and see if its ICMP Echo Response (Type 0). Also in ICMP, the response will contain the request you had sent in the first place.
Received UDP & TCP packets never passed to raw sockets . IF a process wants to read IP datagram containing UDP or TCP packets the packets must be read at data link layer . check this link
http://aschauf.landshut.org/fh/linux/udp_vs_raw/ch01s03.html
if the packet is not cached at layer 2 then it is processed by kernel .
And if the packet is of icmp protocol and it is of type echo request or timestamp request or address mask request then it is entirely processed by kernel otherwise it will passed to RAW SOCKETS.
Another one all datagrams with a protocol field that the kernel does not understand are passed to raw sockets only basic processing of ip is done on them
At last if datagram arrives in fragments then nothing is passed to raw sockets until all fragments are arived and reassembled .
If you want to learn more, then read this book.
Related
I am learning about the ping implementation in C.
The problem is, I was using a raw sockets to receive the packet. For all packets we have a identification value in ICMP header.
I was running the ping in multiple terminal.
For example, I was running three ping google.com in three terminals.
For the first ping the identification value is 23456, the second ping identification value is 34564, and the third ping identification value is 98763.
My problem is the second ping have to receives the identification with 34564 packet, but it receives the identification value as 23456.
For each ping the new raw socket is creating. But it receives another ping packet.
Can anyone please explain me, why it receives another ping packet ?
UPDATE:-
I have another one doubt. The doubt is,
raw sockets reads the packet from where and how it identify the packet is for this raw socket ?
UPDATE 1:-
Here is the link for the codes.
ping_common.c
ping.c
ping.h
What's you are seeing is by design of the raw socket, because raw sockets are meant to receive all the raw packets. So to only receive the reply to certain ICMP packets, you need to apply filters on the socket. First you can use ICMP_FILTER socket options to restrict receiving of certain ICMP types:
struct icmp_filter filter;
filter.data = <bit mask of ICMP types, like ICMP_REPLY>;
setsockopt(sock, SOL_RAW, ICMP_FILTER, &filter, sizeof filter)
Second, you can attach socket filter to enforce only receive the package with the given ICMP ID:
struct sock_fprog filter;
// set filter to check ID with your own ID
setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof filter);
To answer your other doubt:
raw sockets reads the packet from where and how it identify the packet is for this raw socket ?
Raw socket sit along side other protocol handlers after IP layer. From book "Understanding Linux Network Internals" Chapter 25.5:
Here are some examples of interactions between protocols:
IP protocol
The ip_local_deliver_finish routine, described in Chapter 24, delivers
ingress ICMP messages to the receive routine icmp_rcv registered by
the ICMP protocol, but it also delivers them to the raw IP sockets
that registered against the ICMP protocol (raw_v4_input).
We want to receive packets from udp sockets, the udp packets have variable length and we don't know how long they really are until we receive them (parts of them exactly, length were written in the sixth byte).
We tried the function lrs_set_receive_option with MarkerEnd only to find it has no help on this issue. The reason why we want to receive by packets is that we need to respond some packet by sending back user-defined udp packets.
Is there anybody knows how achieve that?
UPDATE
The LR version seems to be v10 or v11.
We need respond an incoming udp packet by sending back a udp packet immediately.
The udp packet may be like this
| orc code | packet length | Real DATA |
Issue is we can't let loadrunner return data for each packets, sometimes it returns many packets in a buffer, sometimes it waits until timeout though when there has been an incoming packet in the socket buffer. While in the c programming language world, when calling recvfrom(udp socket) we are returned only one udp packet per time (per call) which is want we really want.
If you need raw socket support to intercept at the packet level then you are likely going to have to jump to a DLL virtual user in Visual Studio with the raw socket support.
As to your question on UDP support: Yes, a Winsock user supports both core transport types, UDP and TCP. TCP being the more common variant as connection oriented. However, packet examination is at layer 3 of the OSI model for the carrier protocol IP. The ACK should come before you receive the dataflow for your use in the script. You are looking at assembled data flows in the data.ws when you jump to the TCP and UDP level.
Now, you are likely receiving a warning on receive buffer size mismatch which is taking you down this path with a mismatch to the recording size. There is an easy way to address this. If you take your send buffer and construct it using the lrs_set_send_buffer() function, then anything that returns will be taken as correct, ignoring the previously recorded buffer size and not having to wait for a match or timeout before continuing.
I'm trying to send commands using UDP. The receiver is supposed to receive the UDP datagram and reply. However, I would like the reply to always be sent to the sender's source port. I know how to parse the the port (struct header and move the pointer to the right position...), however, I'm looking for a function that returns the whole received frame including the headers and not only the datagram/data.
What about the recvfrom() function? It allows you to grab the data and it fills a sockaddr struct from which you can find the source port of the sender.
The socket is created and bound, then the program receives data with recv(). The question is: How do I now determine from which host + port the packet originates so that I can send data back?
Note: C and Winsock is used.
Use recvfrom instead, it can return the source port and address
My initial UDP socket is binded to 127.0.0.1:9898.
The first time that I get notified of incoming data by epoll/kqueue, I do recvfrom() and I fill a struct sockaddr called peer_name that contain the peer informations (ip:port).
Then I create a new UPD socket using socket(),
then I bind() this newly created socket to the same ip:port (127.0.0.1:9898) than my original socket.
then I connect my newly created socket using connect() to the peer who just sent me something. I have the information in the struct sockaddr called peer_name.
I then add my newly created socket in my epoll/kqueue vector and wait for notification.
I would expect to ONLY receive UDP frame from the peer i'm ""connected to"".
1/ does netstat -a -p udp is suppose to show me the IP:PORT of the peer my newly created socket is ""connected to"" ?
2/ I'm probably doing something wrong since after creating my new socket, this socket receive all incoming UDP packets destinated to the IP:PORT I'm binded to, regardless of the source peer IP:PORT.
I would like to see a working example of what I'm trying to do :)
or any hint on what I'm doing wrong.
thanks!
http://www.softlab.ntua.gr/facilities/documentation/unix/unix-socket-faq/unix-socket-faq-5.html
"Does doing a connect() call affect the receive behaviourof the socket?
Yes, in two ways. First, only datagrams from your "connected peer" are returned. All others arriving at your port are not delivered to you.
But most importantly, a UDP socket must be connected to receive ICMP errors. Pp. 748-749 of "TCP/IP Illustrated, Volume 2" give all the gory details on why this is so."
connect(2) on a UDP socket just sets the default destination address of the socket (where the data will be sent if you use write(2) or send(2) on the socket). It has no other effect -- you can still send packets to other addresses with sendto(2) or sendmsg(2) and you'll still see packets sent from any address.
So it doesn't really make any sense to open a new socket on the port -- for every packet received, you need to look at the source address to see if it comes from an address you've seen already (and thus belongs to that logical stream) or is a new address (a new logical stream).