What are the equivalents of IP_RECVOPTS and IP_RECVRETOPTS in Windows - c

I'm doing some socket programming that I'm trying to make cross-platform compatible. For Windows systems, I'm including the following headers:
#include <winsock2.h>
#include <ws2tcpip.h>
When I tried to compile my application on Windows, I got errors about the following constants' being undefined:
IP_RECVOPTS
IP_RECVRETOPTS
I thought that odd, because I thought those were pretty common socket options, but perhaps I'm wrong. Either way, sure enough, they're not listed anywhere in the Windows socket documentation.
The documentation in a Linux distro's in.h says the following about these constants:
IP_RECVOPTS /* bool; Receive all IP options w/datagram. */
IP_RECVRETOPTS /* bool; Receive IP options for response. */
In that distro's in.h, the defined value of the first one appears to be 6, while the defined value of the second one appears to be 7.
So, my questions:
Are there equivalent constants in Windows sockets for replacing these two constants (or, perhaps, do I just need to include some other header)?
If not, is the receiving of IP options even possible in Windows sockets?
If so, is it safe for me to hard-code these values on Windows systems to 6 and 7, respectively, or should they be some other value?
UPDATE 1
I continued my Google research today. I found these two interesting tidbits. I don't know whether they help me. The first is the Windows Runtime (WinRT) Socket Address header (WinRTSockAddr.h) from the MixedRealityToolkit repository on Microsoft's official GitHub account. It contains the following:
#define IP_RECVOPTS 6
#define IP_RETOPTS 7
This aligns with *nix values I've seen elsewhere (I've commonly seen IP_RETOPTS aliased to IP_RECVRETOPTS). But then there's this alleged Windows Sockets helper header from the "Geek Research Lab"'s GitHub account. I've no idea if it has any credibility, but it has different values for these constants:
#define IP_RECVOPTS 5 /* bool; receive all IP opts w/dgram */
#define IP_RECVRETOPTS 6 /* bool; receive IP opts for response */
#define IP_RECVDSTADDR 7 /* bool; receive IP dst addr w/dgram */
#define IP_RETOPTS 8 /* ip_opts; set/get IP options */
That's contradictory on all fronts: values and the aliasing of IP_RETOPTS to IP_RECVRETOPTS. :-/

The only somewhat portable standard for accessing IP (as well as TCP and UDP) options is via the ancillary data parameters of sendmsg and recvmsg.
Unfortunately while having access is standardized, the exact details of what options are available can still vary between OSes.
On Linux, see the cmsg man page and note:
CONFORMING TO
This ancillary data model conforms to the POSIX.1g draft, 4.4BSD-
Lite, the IPv6 advanced API described in RFC 2292 and SUSv2.
CMSG_ALIGN() is a Linux extension.
By comparison, the man page describing IP_RECVOPTS has no "CONFORMING TO" section.
The similar Windows documentation page is "IPPROTO_IP Socket Options" on MSDN
In the Windows documentation for WSARecvMsg and WSASendMsg, there's the following note:
based on the Posix.1g specification for the msghdr structure
The documentation for _WSAMSG lists the ancillary data available from Winsock.
The POSIX documentation is here
Unfortunately for portability:
The system documentation shall specify the cmsg_type definitions for the supported protocols.
which is to say, the ancillary data actually available is not portable, because it's not specified by POSIX and/or Single Unix Specification.

Are there equivalent constants in Windows sockets for replacing these
two constants (or, perhaps, do I just need to include some other header)?
No. Unfortunately, this wouldn't be the first time that Windows is slow to implement parts of a particular standard or an RFC. Taking a look at socket options, for example, IP_RECVTTL was added only recently, for Windows 10. So maybe if you wait long enough, you may live to see the options you want supported on Windows? The code you have seen seems to be copy-pasted from some other, non-Windows code. In the case of RakNet, note that WinRTSockAddr.h is only used for WINDOWS_STORE_RT support, which is currently limited.
If not, is the receiving of IP options even possible in Windows
sockets?
No, it does not seem to be. At least I'm not aware of such capability.
If so, is it safe for me to hard-code these values on Windows systems
to 6 and 7, respectively, or should they be some other value?
No, it's probably not safe to hard-code the values. At best, such option values would be ignored, but they could be misinterpreted and result in unwanted behavior.
Since you indicated that you aim to make your code cross-platform, you will likely have to settle for the intersection of features that are supported on all the platforms that you want to support.

Related

Zero is usually right for a protocol?

I have been going through the GNU, libc manual on using the sockets. As per to the documentation here
Exact wording from the documentation is,
zero is usually right for protocol.
I have seen several examples of code where engineers have put 0 for the protocol when implementing a socket regardless of the protocol in use!
int socket (int namespace, int style, int protocol)
May I know, What does the author mean by above statement ? I could sense that there are situations in which 0 might not be the correct answer as per to the author's statement, If so, would it be possible for someone to elaborate on such scenarios ? Most importantly where do we get the value for protocol ? Is there any standard to refer to for protocol numbers ?
The valid values for protocol is dependent on the namespace used and the kernel the program is running on.
I assume, since the question is tagged gnu, that you are running under linux. You may then find a list of valid namespaces, and links to documentation of those namespaces with man 'socket(2)'. For instance, you may find documentation for the internet namespaces AM_INET and AM_INET6 under man 'ip(7)' and man 'ipv6(7)'
Reading the ip(7) manpage you may then see that AM_INET supports protocols IPPROTO_TCP and IPPROTO_SCTP for stream sockets, and IPPROTO_UDP and IPPROTO_UDPLITE for datagram sockets.
If you want to dig further, the different protocols also have their own manpages

Conditional compilation based on functionality in Linux kernel headers

Consider the case where I'm using some functionality from the Linux headers exported to user space, such as perf_event_open from <linux/perf_event.h>.
The functionality offered by this API has changed over time, as members have been added to the perf_event_attr, such as perf_event_attr.cap_user_time.
How can I write source that compiles and uses these new functionalities if they are available locally, but falls back gracefully if they aren't and doesn't use them?
In particular, how can I detect in the pre-processor whether this stuff is available?
I've used this perf_event_attr as an example, but my question is a general one because structure members, new structures, definitions and functions are added all the time.
Note that here I'm only considering the case where a process is compiled on the same system that it will run on: if you want to compile on one host and run on another you need a different set of tricks.
Use the macros from /usr/include/linux/version.h:
#include <linux/version.h>
int main() {
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
// ^^^^^^ change for the proper version when `perf_event_attr.cap_user_time` was introduced
// use old interface
#else
// use new interface
// use perf_event_attr.cap_user_time
#endif
}
You might go into this with the following assumptions
The features available in the header files correspond to those documented for the specific Linux version.
The kernel running during execution corresponds to <linux/version.h> during compilation
Ideally, I suggest not to rely on these two assumptions at all.
The first assumption fails primarily due to backports, e.g. in enterprise Linux versions based on ancient kernels. If you care about different versions, you probably care about them.
Instead, I recommend utilizing the methods for checking for struct members and include files in build system, e.g. for CMake:
CHECK_STRUCT_HAS_MEMBER("struct perf_event_attr" cap_user_time linux/perf_event.h HAVE_PERF_CAP_USER_TIME)
CHECK_INCLUDE_FILES can also be useful.
The second assumption can fail for many reasons, even if the binary is not moved between systems; E.g. updating the kernel but not recompiling the binary or simply booting another kernel. Specifically perf_event_open fails with EINVAL if a reserved bit is set. This allows you to retry with an alternative implementation not using the requested feature.
In short, statically check for the feature instead of the version. Dynamically, try and retry the legacy implementation if it failed.
Just in addition to other answers.
If you're aiming for supporting both cross-version and cross-distro code, you should also keep in mind that there are distros (Centos/RHEL) which pull some recent changes from new kernels to old. So you may encounter a situation in which you'll have LINUX_VERSION_CODE equal to some old kernel version, but there will be some changes (new fields in data structures, new functions, etc.) from recent kernel. In such case this macro is insufficient.
You can add something like (to avoid preprocessor errors in case it is not a Centos distro):
#ifndef RHEL_RELEASE_CODE
#define RHEL_RELEASE_CODE 0
#endif
#ifndef RHEL_RELEASE_VERSION
#define RHEL_RELEASE_VERSION(x,y) 1
#endif
And use it with > or >= where you need:
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0) || RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,2)
...
for Centos/RHEL custom kernels support.
P.S. of course it's necessary to examine an appropriate versions of Centos/RHEL, and understand when and what exactly has changed in the code sections that affect you.

Find out MAC address on Linux&FreeBSD in C

I am trying to find out MAC address and I managed to create working solution using sysctl in Linux, problem is, that this solution is not working on FreeBSD version I am developing on. Is there any way I can find out mac address in C other than using sysctl?
Use the libpcap library. Its the most multi platform way you can find.
This library is used on network sniffers and intrusion detections, as well as dedicate measuring other network statistics. The nethogs utility to measure per process network usage, the iftop used to measure per machine/port bandwidth usage. Is very flexible in many roles.
Is written in C but there are some wrappers for other languages.
1: http://en.wikipedia.org/wiki/Pcap
[2]: http://www.tcpdump.org
[3]: http://sourceforge.net/projects/libpcap/
Edit:
here is a complete and exact and working example with the code and functions detailed:
http://coderrr.wordpress.com/2008/03/07/get-the-mac-address-of-a-local-ip/
There are plenty of tutorials and the source code is your best friend.
Edit 2: blaze pointed out getifaddrs(3) which seems to do the job, just a few caveats, its a non-posix function. Is a bsd function which glibc linux supports but do NOT documents. Is almost an undocumented featured :-)
All documentation are man pages and from the manual at kernel.org:
Not in POSIX.1-2001. This function first appeared in BSDi and is
present on
the BSD systems, but with slightly different semantics documented--returning
one entry per interface, not per address. This means ifa_addr and other
fields can actually be NULL if the interface has no address, and no link-level
address is returned if the interface has an IP address assigned. Also, the
way of choosing either ifa_broadaddr or ifa_dstaddr differs on various
systems.
and
The addresses returned on Linux will usually be the IPv4 and IPv6
addresses
assigned to the interface, but also one AF_PACKET address per interface
containing lower-level details about the interface and its physical layer. In
this case, the ifa_data field may contain a pointer to a struct
net_device_stats, defined in , which contains various
interface attributes and statistics.
So it may vary in behavior and you'll may have to #ifndef compile anyway.
The kernel.org man page at http://www.kernel.org/doc/man-pages/online/pages/man3/getifaddrs.3.html does provides example code in it, which may be helpful. My local linux man page is rather poor in comparison to the above linked.
I still think that libpcap is more portable if only because someone else had done all the portability work and all the extra features you gain by using it.
Hope this helps.
getifaddrs(3) returns IP addresses and MAC addresses on local interfaces. Portable between Linux and FreeBSD.

Efficient way to browse header definitions

As an example: on my system (Ubuntu 10.04), the sockaddr structure is defined in /bits/sockaddr.h as
struct sockaddr{
_SOCKADDR_COMMON (sa_); /*...*/
char sa_data[14]; /*...*/
};
and similarly for sockaddr_in, with first field name sin_.
However, all the examples I see access the field sin_
structure_name.sin_family
I meant to track down the typedef (?) for completeness, followed included headers and such, but failed (I got to sa_family_t and similar).
As a more general question: is there, say, a searchable online source where you can simply search for where a macro or typedef is in the header files - either for a particular Ubuntu distribution, or more generically for 'typical' Linux installations? Or, obviously, a clever way from within Ubuntu's shell; or some description of how to be more efficient doing this any other idea.
This is the link:
LXR / The Linux Cross Reference
done...i'll get you the reference for the Linux Kernel API Browser later (used to be able to find it online somewhere). There's the Linux Kernel Archives for the actual source code, which you probably could generate documentation from anyways.
Sorry, but I've not come across something as beautiful as say, the
jQuery API Browser. Hopefully the 'Ubuntu Manpage' #
manpages.ubuntu.com/manpages/lucid/man7/netdevice.7.html, for example,
might suffice. Also for stuff like the struct sockaddr{, you might
like to check out the Linux Kernel API Browser (or something similar)
as that belongs to standard Linux networking protocol headers.
You could try: http://www.google.com/codesearch perhaps?

Using the name resolver of resolv.h with IPv6

I write or modify programs which perform name resolution and need a
good control of the process. So I do not use getaddrinfo(), I go
deeper and use res_query() / res_send() / etc in resolv.h, documented
in resolver(3).
Although not documented, the common way to set the resolver used is to
update _res.nsaddr_list. But this array, defined in resolv.h, stores
struct sockaddr_in, that is IPv4 addresses only. (IPv6 addresses
are struct sockaddr_in6, a family-independant system would use struct sockaddr.)
I'm looking for a way (preferrably portable, at least among the
various Unix) to tell _res that I want also IPv6 addresses.
Apparently, a long time ago, there was in FreeBSD a _res_ext with this
ability but I cannot find it anymore in a recent FreeBSD 7 (grep
_res_ext /usr/include/resolv.h finds nothing). You can still find
code which uses it (try yourself with Google Codesearch).
Thanks to Alnitak, I noticed it is apparently now _res._ext and not .res_ext. I wonder where these sort of things are documented or announced... I have no idea how portable _res._ext is. I can find it on Debian and FreeBSD. It seems there are few programs which use it.
Stéphane - if your resolv.h doesn't include any support for sockaddr_in6 then that suggests that on your particular O/S the resolver does not itself support IPv6 transport.
I've checked some of my systems here:
MacOS X 10.5.6 - supports the BIND 9 library, which has a res_setservers() function which can take IPv6 addresses, no _res._ext extension.
CentOS 5.2 - has the _res._ext extension, although there's no mention of IPv6 in the man page for resolv.conf except that there's a setting to tell the resolver to return AAAA records before looking for A records for gethostbyname().
EDIT - also, the CVS repository for FreeBSD suggests that FreeBSD 7.0 (see tag FREEBSD_7_0_0_RELEASE) does also support res_setservers() from Bind 9.
glibc:
res_setservers: no
__res_state._u._ext.nsaddrs
__res_state._u._ext.nsmap
set the latter to MAXNS+1 according to:
http://sourceware.org/ml/libc-hacker/2002-05/msg00035.html
BSD-libc:
res_setservers: yes
__res_state._u._ext.__res_state_ext
Seems messy to me and you'll probably need autoconf.

Resources