IP options IP_RECVOPTS on Linux 2.6 - Kindly comment

From: S, Sreeram
Date: Thu Apr 26 2012 - 05:37:32 EST


Hi,
I am Sreeram. I work on TCP/IP on personal interest. I was going through the man page of ip(7).
In the man page, it is documented that there is an option called IP_RECVOPTS which returns the IP header options as a control message.
Exact snippet from the man-page is as follows:


IP_RECVOPTS (since Linux 2.2)
Pass all incoming IP options to the user in a IP_OPTIONS
control message. The routing header and other options
are already filled in for the local host. Not supported
for SOCK_STREAM sockets.

I have written a program which uses recvmsg() to receive the UDP message and also the incoming ancillary/control data.
In that program, I had enabled this option. But I could not get any IP header options ancillary/control message. Initially, I
had defined a pointer to the ip_opts structure defined in bits/in.h . The structure and its documentation are as follows:

#if defined __USE_MISC || defined __USE_GNU
/* Structure used to describe IP options for IP_OPTIONS and IP_RETOPTS.
The `ip_dst' field is used for the first-hop gateway when using a
source route (this gets put into the header proper). */
struct ip_opts
{
struct in_addr ip_dst; /* First hop; zero without source route. */
char ip_opts[40]; /* Actually variable in size. */
};

Since, I did not receive the IP header options message in recvmsg(), I removed the pointer variable for this structure and the associated typecasting to the CMSG_DATA(..) and
Introduced a counter to count the number of ancillary packets received. The count was 3 (IP_TTL and IP_TOS and SO_TIMESTAMP, all which I had enabled using setsockopt())
The program is as follows:

[root@sreeramb-linux Server]# cat recvmsg.c
/* This is a generic UDP server.
* This will return what it received from the client to the client.
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 19000
#define SA struct sockaddr

int main(int argc, char **argv) {
char data[128];
int *ttlptr, count=0;
int sock, retn, size, val=1;
struct sockaddr_in peer;
struct iovec iov;
struct ip_opts *ipopts;
struct msghdr msg;
struct cmsghdr *cmsg;
struct timeval *timeptr;

/* Create a socket. */
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("Socket");
exit(-1);
}
printf("Socket created.\n");

/* Set some options for this socket to get ancillary data. */
setsockopt(sock, IPPROTO_IP, IP_RECVTTL, &val, sizeof(val));
setsockopt(sock, IPPROTO_IP, IP_RECVTOS, &val, sizeof(val));
setsockopt(sock, IPPROTO_IP, IP_RETOPTS, &val, sizeof(val));
setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &val, sizeof(val));

/* Prepare the structure for 'bind'ing */
memset(&peer, 0, sizeof(peer));
peer.sin_family = AF_INET;
peer.sin_port = htons(PORT);
peer.sin_addr.s_addr = INADDR_ANY;

/* Bind to an interface */
retn = bind(sock, (SA *)&peer, sizeof(peer));
if (retn < 0) {
perror("Bind");
close(sock);
exit(-1);
}
printf("Successfully bound to the interface.\n");

/* Now, populate the msghdr to prepare it for use in recvmsg */
memset(data, 0, sizeof(data));
memset(&peer, 0, sizeof(peer));
iov.iov_base = data;
iov.iov_len = sizeof(data);
msg.msg_name = &peer;
msg.msg_namelen = sizeof(peer);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = calloc(1, 1024);
msg.msg_controllen = 1024;
msg.msg_flags = 0;

/* Now, call recvmsg() */
size = sizeof(peer);
retn = recvmsg(sock, &msg, 0);
if (retn < 0) {
perror("recvfrom");
close(sock);
exit(-2);
}
printf("Received some data:\n");
printf(" Client: %s\n", inet_ntoa(peer.sin_addr));
printf(" Data: %s\n", data);

/* Print ancillary data */
for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {

/* Check for TTL in ancillary data. */
if ((cmsg->cmsg_level == IPPROTO_IP)
&&(cmsg->cmsg_type == IP_TTL)) {
ttlptr = (int *) CMSG_DATA(cmsg);
val = *ttlptr;
printf(" TTL: %d\n", val);
}

/* Check for TOS in ancillary data. */
if ((cmsg->cmsg_level == IPPROTO_IP)
&&(cmsg->cmsg_type == IP_TOS)) {
ttlptr = (int *) CMSG_DATA(cmsg);
val = *ttlptr;
printf(" TOS: %d\n", val);
}

/* Get the timestamp of the message. */
if ((cmsg->cmsg_level == SOL_SOCKET)
&& (cmsg->cmsg_type == SO_TIMESTAMP)) {
timeptr = (struct timeval *) CMSG_DATA(cmsg);
printf(" Timestamp: %s", ctime(&timeptr->tv_sec));
}

count++;
}

printf("Total ancillary packets: %d\n", count);
close(sock);
return(0);
}
[root@sreeramb-linux Server]#
[root@sreeramb-linux Server]# uname -a
Linux sreeramb-linux 2.6.35.6-45.fc14.i686 #1 SMP Mon Oct 18 23:56:17 UTC 2010 i686 i686 i386 GNU/Linux
[root@sreeramb-linux Server]#

[ I am using Fedora Core 14]

What could be the reason for not receiving the IP Options message? What should I enable to receive the same?

Kindly guide.

Regards,
Sreeram
¢éì®&Þ~º&¶¬–+-±éÝ¥Šw®žË±Êâmébžìdz¹Þ)í…æèw*jg¬±¨¶‰šŽŠÝj/êäz¹ÞŠà2ŠÞ¨è­Ú&¢)ß«a¶Úþø®G«éh®æj:+v‰¨Šwè†Ù>Wš±êÞiÛaxPjØm¶Ÿÿà -»+ƒùdš_