From my basic socket understanding, sockets have a buffer, from which application can read the data received from a NIC. Once the application reads the data from the buffer, the data is gone from buffer perspective. But the sniffers like wireshark, are able to copy the packet? How can they read packet from a particular port and still the application manages to get it?
Raw socket sniffs from Ethernet, it do not fetch from port, but accepts all Unicast/Multicast message. Because data to any port go from Ethernet layer.
Wireshark uses WinPcap drives, which sniffs data from Ethernet layer.
Related
I am trying to write a C sniffer for Linux, and understand the actions happening in the kernel while sniffing.
I am having troubles finding an answer for the following question:
If I initialize my socket in the following way:
sock_raw = socket(AF_PACKET , SOCK_RAW , htons(ETH_P_ALL));
What happens in the kernel? How am I seeing all the incoming and outgoing packets, but not "hijacking" them? Because what I have understood do far is that when the kernel receives a packet, it sends it to the relevant protocol handler function. Therefore I can't understand - does the kernel clone the packet and sends it in addition to the socket I opened?
What happens in the kernel?
The kernel simply duplicates the packets as soon as it receives them from the physical layer (for incoming packets) or just before sending them out to the physical layer (for outgoing packets). One copy of each packet is sent to your socket (if you use ETH_PH_ALL then you are listening on all interfaces, but you could also bind(2) to a particular one). After a copy is sent to your socket, the other copy then continues being processed like it normally would (e.g. identifying and decoding the protocol, checking firewall rules, etc).
How am I seeing all the incoming and outgoing packets, but not "hijacking" them?
In order for hijacking to happen, you would need to write data to the socket injecting new packets (accurately crafted depending on the protocol you want to hijack). If you only read incoming packets, you are merely sniffing, without hijacking anything.
does the kernel clone the packet and sends it in addition to the socket I opened?
Yes, that's basically what happens. This image could help you visualize it.
man 7 packet also describes this:
Packet sockets are used to receive or send raw packets at the device driver (OSI Layer 2) level. They allow the user to implement protocol modules in user space on top of the physical layer.
The socket_type is either SOCK_RAW for raw packets including the link-level header or SOCK_DGRAM for cooked packets with the link-level header removed. The link-level header information is available in a common format in a sockaddr_ll structure. protocol is the IEEE 802.3 protocol number in network byte order. See the <linux/if_ether.h> include file for a list of allowed protocols. When protocol is set to htons(ETH_P_ALL), then all protocols are received. All incoming packets of that protocol type will be passed to the packet socket before they are passed to the protocols implemented in the kernel.
I need to intercept/redirect TCP and UDP packets that have its payloads matching some regex patterns and also get original destination address and port.
I can't just redirect TCP and UDP packets to my application by the use of DSTNAT on firewall (and splice() if don't match patterns) because that wouldn't allow me to get their original destination addresses and ports from before they are changed/translated.
So I read about divert sockets and they look promising. I'm in doubt however, as I couldn't find anywhere how much an application can read of a packet received on a divert socket. Is it possible to read entire packet (including TCP and UDP payload) or just its headers? Is entire packet sent to divert socket or just first received fragment (maybe limited by MTU/MRU or how much send() could push on single call on other end...)?
If it matters, the firewall I'm going to use for diverting packets is ipfw.
I'm programming an application for transferring a file between two host with an UDP socket.
But it seems that some data arrives corrupted at the client.
My question is: is it possible that if the server is faster than the client, the client could read corrupted data from the socket?
I use sendto() in the server and read() in the client (I use the connect() before beginning transferring the file in the client),
and if yes: how can I stop the server from sending new data until the client has read all the previous data?
is it possible that if the server is faster than the client, the
client could read corrupted data from the socket?
No it is not possible - every datagram that you see is error checked by the IP layer and will be as it was sent.
how can I stop the server from sending new data until the client has
read all the previous data?
Typically you send a small packet, the receiver sends an acknowledgement, then you send the next. Problem with UDP however is packets can get dropped without telling you event duplicated moreover you can flood the network as there is no congestion control..
So why re-invent the wheel, use TCP for sending files which takes care of reliability and congestion control - everyone has been using that for decades, e.g. this web page is delivered to you using HTTP which uses TCP.
I'd like to debug multicast reception by the Linux kernel, because I'm not receiving any packets. Let me be more specific: I'm building a flexible userland transport mode network daemon. One of the options of running it, is using UDP sockets. One of the use cases, is to transport UDP packets that go to multicast addresses.
So I end up with UDP packets to a multicast destination, transported by a UDP packet to the same multicast destination. That's asking for trouble, I know, but I get away with it: using SO_BINDTODEVICE, I can pretty much cheat my way through the routing table and packets are sent out as I intended.
On the receiving side, I'm not so lucky. Linux does not give my receiving socket the multicast packets. It just won't see them, although tcpdump proves that they arrive at the interface. Note that unicast - using the very same sockets - is not a problem at all. I can send and receive them to my heart's content. Not so with multicast.
So I'd like to know what the Linux kernel 'thinks' in that bit between receiving the packet (which it obviously does), and giving it to my process' UDP server socket (which it doesn't do). Any thoughts?
This is a quick question for linux c programming raw sockets. If I wanted to just listen to any interface with a raw socket, must I actually bind to an ip address or interface to listen to traffic? From what I understand, I feel like I should be able to just call sock(); and then start recvfrom() traffic. Maybe I'm wrong, but I've seen some programs that don't use it.
You are right, the only thing you will need to do is call socket() and then recvfrom(). Nevertheless be aware of the fact that there are some limitations with listening using SOCK_RAW.
If you're not using raw sockets on a "send-and-forget" basis, you will
be interested in reading the reply packet(s) for your raw packet(s).
The decision logic for whether a packet will be delivered to a raw
socket can be enumarated as such:
TCP and UDP packets are never delivered to raw sockets, they are always handled by the kernel protocol stack.
Copies of ICMP packets are delivered to a matching raw socket. For some of the ICMP types (ICMP echo request, ICMP timestamp request,
mask request) the kernel, at the same time, may wish to do some
processing and generate replies.
All IGMP packets are delivered to raw sockets: e.g. OSPF packets.
All other packets destined for protocols that are not processed by a kernel subsystem are delivered to raw sockets.
The fact that you're dealing with a protocol for which reply packets
are delivered to your raw socket does not necessarily mean that you'll
get the reply packet. For this you may also need to consider:
setting the protocol accordingly while creating your socket via socket(2)system call. For instance, if you're sending an ICMP
echo-request packet, and want to receive ICMP echo-reply, you can set
the protocol argument (3rd argument) to IPPROTO_ICMP).
setting the protocol argument in socket(2) to 0, so any protocol number in the received packet header will match.
defining a local address for your socket (via e.g. bind(2)), so if the destination address matches the socket's local address, it'll be
delivered to your application also.
For more details you can read e.g. this.
If you meant to capture the traffic on a interface, you can use libpcap.