Problems in receiving fragmented UDP packets in C - 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.

Related

Questions on using raw sockets for sniffing UDP packets

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?

Raw Sockets in C

1.
socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
The linux manual page says about this code.
In socket option, if IP_HDRINCL is set, I can make IP header. Am I right?
If it's right, above socket also let me make TCP header, too?
Then, if IP_HDRINCL is not set, what means above socket?
2.
socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
what means above code comparing to number 1 question's code?
I know IPPROTO_RAW can't receive any IP packets. And here, these sockets only can receive TCP packets, and UDP pakcets each.(Can I see IP Header, Ethernet Header also?)
But how about sending?? I don'know exactly about this.
IP_HDRINCL means: I want my data (for send and recv) to include the ip hdr. And if your data include the ip hdr, it means that the tcp hdr follows (just after the ip hdr), and finally the app's message too (the message your normally give to send ...). Without IP_HDRINCL, you have access to apps data only.
Yes, IPPROTO_TCP and IPPROTO_UDP whith SOCK_RAW are just filters as you say, for sending and receiving. Use IPPROTO_RAW to be able to send any TCP/IP packet (no filter). But to also receive packets, you need also to change AF_INET into AF_PACKET.

How to convert SOCK_DGRAM to SOCK_RAW?

I'm working on an open source where SOCK_DGRAM is used to send RTP packets.
Like this:
int sock = socket(af, SOCK_DGRAM, 0);
But i'm supposed to use the same socket as SOCK_RAW to send the UDP packets that i prepare.
Is this possible to convert the UDP socket to RAW socket?
if it is possible how it can be done?
Thanks in advance
I don't know why you said need to use same socket, otherwise, you can follow the below steps to transfer packet over RAW socket.
create the socket using SOCK_RAW.
define and populate the IP header [struct ipheader]
define and populate the UDP header [struct udphdr]
set the socket for not to use a system (kernel) provied header [setsockopt() for IP_HDRINCLas 1]
send the buffer [sendto()]
You can find some nice tutorials (and maybe some sample codes, too) here.

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.

Socket issue with RTP packets

I'm trying to build an RTP packet metric analyzer in C, but i ended up in a strange issue, I'm cutting down implementation details for ease of exposure:
Since the RTP packets are contained in UDP my socket is initalized with the following parameters:
sock_domain = AF_INET;
sock_type = SOCK_DGRAM;
sock_proto = IPPROTO_UDP;
and binded with those parameters:
socket_addr.sin_family = AF_INET;
socket_addr.sin_port = 10000; // My server is streaming on 10000
socket_addr.sin_addr.s_addr = INADDR_ANY;
and joined the multicast group:
mgroup_req.imr_multiaddr.s_addr = inet_addr("224.1.0.1"); // Multicast group of the stream
mgroup_req.imr_interface.s_addr = INADDR_ANY;
set the multicast group from which i receive to:
mgroup_addr.sin_family = socket_addr.sin_family;
mgroup_addr.sin_port = socket_addr.sin_port;
mgroup_addr.sin_addr.s_addr = mgroup_req.imr_multiaddr.s_addr;
receiving packets with recvfrom function:
errcode = recvfrom(sockfd, &recvbuff, IPMAXSIZE, 0, (struct sockaddr *)&mgroup_addr, &mgroup_addr_len)
Something goes wrong, while i can receive standard UDP packets addressed to the multicast group 224.1.0.1, the RTP packets are not received the first time, but sending them again makes the trick.
Scenario 1:
I send n UDP packets: They are correctly received
Scenario 2:
I send n RTP packets: Nothing happens
I send again the same n RTP packets: They are correctly received
whatever the n number of packets is... so weird but true.
edit:
At the analyzer side I'm running a sniffer and it shows both the packet bursts, so messages arrives at the analyzer side, it's not a sender related problem.
Question:
the code is exactly the same (read: Same executable) for the RTP scenario AND the UDP scenario.
What am I doing wrong?
Side notes:
RTP manage libraries or high-level RTP libraries suggestions are a no-no, I MUST work at this level of abstraction because of the metrics i need to analyze.
Also Network metrics analyzer are a no-no, I MUST do this with my own code.
Thanks in advance.
I'm not convinced that you need to name the mcast group address again as the recvfrom address, as you've already joined the group. Is receiving packets from elsewhere a genuine concern? I would just use recv().
The issue was due to the board i was working on, it was set (not my code) for redirecting RTP packets directly to the MPEG decoder.
Turns out that packets in the decoder are not to be forwarded to the Kernel. Still has to understand why the double send was working.

Resources