Questions on using raw sockets for sniffing UDP packets - c

I want to use raw sockets for packet analysis/sniffing limited to UDP. Yes I am aware of wireshark and libpcap. The scope of my analyzer is very limited and has to be implemented in C on Linux.
I know that we start with:
sd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
Then while reading, using recvfrom, we use the flag MSG_PEEK.
Questions:
Is the MSG_PEEK flag required if we use SOCK_RAW? .
If I read from this socket, will I get all incoming UDP packets on all interfaces and ports?
Does the read (with MSG_PEEK flag or otherwise) allow reading non-blocking sockets just like it would be had MSG_PEEK flag not been used? (I am using epoll). In epoll_ctl, one has to specify the fd to be monitored. Are all UDP sockets mapped to this single socket? So, if data is available on any UDP socket opened by other processes, this socket's EPOLLIN event will be triggered?
Will this reading (with MSG_PEEK or without) impact the reading of sockets in the actual program that use the packets for real applications?

Related

What's the difference between Linux SOCK_RAW and SOCK_STREAM?

I've been studying networking with c code and cryptography lately and upon pondering random questions I stumbled across a block of code that's used for packet sniffing and I had a question on the actual socket that gets used in the function recvfrom(). The socket gets initialized through the following sock function rawSock = socket(AF_INET, SOCK_RAW, 0).
I understand that SOCK_STREAM and SOCK_RAW are macros that represent an integer; but the question isn't about the values, it's about the results.
When would I use SOCK_STREAM over SOCK_RAW and vice versa?
I understand basic client and server communications using SOCK_STREAM. I'm working with C and in Linux
Read the man page.
For the prototype
int socket(int domain, int type, int protocol);
The types can be
SOCK_STREAM Provides sequenced, reliable, two-way, connection-
based byte streams. An out-of-band data transmission
mechanism may be supported.
or
SOCK_RAW Provides raw network protocol access.
In one line, SOCK_STREAM is for connection oriented sockets, where the underlying OS creates and manages the headers for L4 (TCP), L3 and L2. OTOH SOCK_RAW provides more fine-grained control over header and packet construction, where the user has to construct and supply the headers and can also manage the contents.
To elaborate:
Sockets of type SOCK_STREAM are full-duplex byte streams. They do
not preserve record boundaries. A stream socket must be in a
connected state before any data may be sent or received on it. A
connection to another socket is created with a connect(2) call. Once
connected, data may be transferred using read(2) and write(2) calls
or some variant of the send(2) and recv(2) calls. When a session has
been completed a close(2) may be performed. Out-of-band data may
also be transmitted as described in send(2) and received as described
in recv(2).
and
SOCK_RAW sockets allow sending of datagrams to
correspondents named in sendto(2) calls. Datagrams are generally
received with recvfrom(2), which returns the next datagram along with
the address of its sender.

Identical bound port UDP sockets and receiving data on all of them

I need to do an important test. The test's condition is as bellow.
I am using winsock and I have 2 UDP sockets (Sock-A and Sock-B) which with SO_REUSEADDR option both of them have been bound to port 1000 on one PC.
Both of them transmit UDP packets out to another socket (Sock-C) and Sock-C which is located in different LAN receives their messages.
Sock-C responds them with some messages, but unfortunately I can see just Sock-A (which has been opened sooner) just gets the messages, and Sock-B doesn't get anything. When I close Sock-A I can see that Sock-B starts to receiving the messages.
Any of you know what should I do to let both of Sock-A and Sock-B can receive messages from Sock-C?
Thanks~
This is normal behavior. I think this can't be done with 2 sockets listening on the same port.
Why are you binding 2 sockets to the same port?
Read Socket options SO_REUSEADDR and SO_REUSEPORT, how do they differ? Do they mean the same across all major operating systems?
In linux it will even try to distribute the datagrams evenly between the 2 sockets, so its random. You will need to change how you send/receive packets.

Receive Ethernet packets in Linux with several Ethtypes in C

I want to receive ethernet packets from socket in Linux, but only those, which have one of two custom Ethtype values.
As I know, if only 1 ethtype should be received, it's possible to specify this value while creating socket like this
int socket = socket(PF_PACKET, SOCK_RAW, htons(ETHERTYPE_CUSTOM_1);
But what if I have 2 different ethtypes? Should I use 2 sockets or write some custom filter? Or is there some any simple way?
Create two sockets, one for each ethertype. Then you can use select() or epoll() to wait for packets on either socket at the same time.
I think you should use libpcap library. You need to access bpf packer filter.
This is easy one.
Or you can use iptables rules an netfilter library. You need to set prerouting iptables rules to forward all packet to specific port and your application binding this port as listening mode and you can receive full packet.

Problems in receiving fragmented UDP packets in C

I'm using 2 different C programs to received fragmented packets, one using a raw socket defined as following:
_socket0 = socket( PF_PACKET, SOCK_RAW, htons(ETH_P_ALL) );
one using an UDP socket defined as following:
_socket0=socket(AF_INET, SOCK_DGRAM, 0);
The first one works fine, the second one doesn't work, I'm not able to see nothings.
Anyone can tell me the reason?
A fragment of an UDP packet is not a UDP packet, so it won't be passed to a UDP socket. UDP sockets are for reading/writing whole UDP packets, not IP packets carrying fragments of one.

Strange Linux socket protocols behaviour

I'm a little confused about the difference between the definitions of protocols on Linux when using socket(). I am attempting to listen for connections over TCP using socket(PF_INET, SOCK_STREAM, proto), where proto is (in my mind) disputed, or at least seems odd.
From <netinet/in.h>:
...
IPPROTO_IP = 0, /* Dummy protocol for TCP. */
...
IPPROTO_TCP = 6, /* Transmission Control Protocol. */
...
Agreed with by /etc/protocols:
ip 0 IP # internet protocol, pseudo protocol number
hopopt 0 HOPOPT # hop-by-hop options for ipv6
...
tcp 6 TCP # transmission control protocol
...
I learned from an online tutorial, and also from the man page tcp(7) that you initialise a TCP socket using
tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
which works absolutely fine, and certainly is a TCP socket. One thing about using the above arguments to initialise a socket is that the code
struct timeval timeout = {1, 0};
setsockopt(tcp_socket, 0, SO_RCVTIMEO, &timeout, sizeof(timeout); // 1s timeout
// Exactly the same for SO_SNDTIMEO here
works absolutely fine, but not after replacing all protocol arguments (including in socket()) with IPPROTO_TCP, as opposed to IPPROTO_IP which they have, as above.
So after experimenting with the difference, I've needed to ask a few searching questions:
Why, when I replace all protocol arguments with IPPROTO_TCP, do I get error 92 ("Protocol not available") when setting timeouts, when protocol 0 is apparently just a 'dummy' TCP?
Why does socket() require the information of whether it should be a stream, datagram or raw socket when that information is (always?) implicitly known from the protocol, and vice versa? (i.e. TCP is a stream protocol, UDP is a datagram protocol, ...)
What could be meant by "dummy TCP"?
What is hopopt, and why does it have the same protocol number as 'ip'?
Many thanks.
Giving 0 as protocol to socket just means that you want to use the default protocol for the family/socktype pair. In this case that is TCP, and thus you get the same result as with IPPROTO_TCP.
Your error is in the setsockopt call. The correct one would be
setsockopt(tcp_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); // 1s timeout
the 0 there is not for protocol, but for option level. IPPROTO_TCP is another option level, but you can't combine that with SO_RCVTIMEO. It can only be used together with SOL_SOCKET.
The ones you use with IPPROTO_TCP are the ones listed in tcp(7), e.g. TCP_NODELAY.
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); should work fine.
Passing 0 as the protocol just means, give me the default. Which on every system is TCP for stream sockets and UDP for datagram sockets, when dealing with IP. But socket() can be used for many other things bar giving you a TCP or UDP socket.
socket() is quite general in nature. socket(AF_INET, SOCK_STREAM, 0); just reads as; "give me a streaming socket within the IP protocol family". Passing 0 means you have no preferences over which protocol - though TCP is the obvious choice for any system. But theoretically, it could have given you e.g. an SCTP socket.
Whether you want datagram or streaming sockets is not implicit for protocols. There are many more protocols bar IP based protocols, and many can be used in either datagram or streaming mode such as SCCP used in SS7 networks.
For IP based protocols, SCTP can be used in a datagram based, or streaming fashion. Thus socket(AF_INET,IPPROTO_SCTP); would be ambiguous. And for datagram sockets, there's other choices as well, UDP, DCCP, UDPlite.
socket(AF_INET,SOCK_SEQPACKET,0); is another interesting choice. It cannot return a TCP socket, TCP is not packet based. It cannot return and UDP socket, UDP gives no guarantee of sequential delivery. But an SCTP socket would do, if the system supports it.
I have no explanation for why someone made the comment "dummy TCP" in that the linux netinet/in.h
hopopt is the IPv6 HOP by hop option. In IPv6, the protocol discriminator field is also used as an extension mechanism. In IPv4 packets there is a protocol field which is the protocol discriminator, it'll be set to IPPROTO_TCP if that IPv4 datagram carries TCP. If that IPv4 packet also carries some additional info(options), they are coded by other mechanisms.
IPv6 does this differently, if there is an extension(option), that extension is coded in the protocol field. So if the IPv6 packet needs the hop-by-hop option, IPPROTO_HOPOPTS is placed in the protocol field. The actual hop-by-hop option also have a protocol discriminator, which signals what the next protocol is - which might be IPPROTO_TCP, or yet another option.

Resources