setsockopt() SOL_IP API level and IPT_SO_SET_REPLACE switch - c

What exactly does SOL_IP mean as the API level of the setsockopt function
and what exactly does the IPT_SO_SET_REPLACE switch do?
I tried to search for both in Google but I found nothing.
Please help me understand them (if you can expand and explain with examples I'd really appreciate it)

SOL_IP is the network layer being addressed by the socket option. For example, an ordinary TCP socket encompasses the TCP layer, then the IP layer under it, and so forth. setsockopt is used to pass miscellaneous instructions down to a particular layer to request some service, feature or operation: basically anything that you might need to configure that doesn't directly match up with a system call. (The "API level" referred to in the man page is basically the same thing that I'm calling "layer" here.)
Some that you often see in linux programs (and examples of use) include:
SOL_PACKET (configure packet ring, add/drop multicast group memberships)
SOL_IP (set/configure various IP packet options, IP layer behaviors, [as here] netfilter module options)
SOL_TCP (TCP_NODELAY, TCP-specific keepalive params)
SOL_SOCKET (REUSEADDR, keepalives)
The layers you can address in a setsockopt depend on the kind of socket that you created. Here, it's the IP layer being addressed.
In this case, the option being passed down is IPT_SO_SET_REPLACE -- it's not a "core" IP option, but is provided by the IP Tables module, which (IIUC) links itself into the network stack via the "netfilters" interface. I'm not familiar with IP Tables details, but the option appears to be an instruction to IP Tables to replace a set of rule table entries. I think using it would require pretty intimate knowledge of IP Tables to use this socket option.

Just to focus on IPT_SO_SET_REPLACE option.
It is to replace the iptable with a new chain rule (see -R option):
https://www.frozentux.net/iptables-tutorial/iptables-tutorial.html
http://ipset.netfilter.org/iptables.man.html
The above are the command line option to use. If you want to see the C program, just "apt-get source iptables" to get the source code, and then view libiptc/libiptc.c to see how SO_SET_REPLACE is used:
ret = setsockopt(handle->sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
sizeof(*repl) + repl->size);
if (ret < 0)
goto out_free_newcounters;
Which is essentially is to replace the new chain rule, by creating and compiling a new iptable.
More info:
https://en.wikipedia.org/wiki/Iptables

Related

How do I get PID from socket port on Windows?

Given a socket port how do you find the process ID (process name) of the process on Windows 10 that uses this port? I am aware of netstat command but I would like to do it with C code only.
How about there, it appears there's a way: the IP Helper library.
Ref: https://learn.microsoft.com/en-us/windows/win32/iphlp/ip-helper-start-page
I haven't used it for this, but it's clearly going down the right road by providing everything you need to basically roll your own netstat.exe.
The low-level object that contains all the info is MIB_TCPROW2, which has the local and remote address + port, plus dwOwningPid. So we know there's a way.
Drilling down we ultimately need the GetTcpTable2() call, and Microsoft's web page helpfully has what appears to be fully-functional C code to do all this yourself.
https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-gettcptable2
Finding this was the best surprise of my day!

Joining a source specific multicast on same multicast address

I am trying to set up multicast sources for an application on linux using source specific multicast (SSM) and the code is going ok (using the C interface) but I would like to verify that the system will behave as I expect it to.
Setup:
Multicast address - 233.X.X.X:9876
Source1 - 192.X.X.1
Source2 - 192.X.X.2
Interface1 - 192.X.X.100
Interface1 - 192.X.X.101
Steps
Configure so that only Source1 is sending to the multicast address
Start a reader (reader1) that binds to the multicast address and joins the multicast with ssm src as Source1 and interface as Interface1
Observe that data is seen on reader1
Do the same (reader2) but using Source2 and Interface2
Desired Outcome:
Reader1 can see the data from the multicast.
Reader2 can't see the data from the multicast.
I am concerned that the above will not be the case as in my testing using non source specific multicast an IP_ADD_MEMBERSHIP has global effect. So reader2's socket sees data because it is bound to the unique multicast address which has been joined to an interface seeing data. The info at this link under "Joining a Multicast" matches up with my observations.
It may well be that IP_ADD_SOURCE_MEMBERSHIP behaves differently to IP_ADD_MEMBERSHIP but the documentation is sparse and not specific in this regard.
Specific questions:
Is a multicast join using IP_ADD_SOURCE_MEMBERSHIP global i.e. will that cause any socket bind()'d to the multicast address to receive packets from that source.
How is SSM supposed to be used in general? does it make sense to have one multicast address with N sources?
I am inexperienced with network programming so please forgive any shortcomings in my understanding.
Thanks for any assistance.
I've worked through this and after obtaining a copy of Unix Network Programming the behaviour at least seems clear and understandable.
The answer is yes all multicast joins are global whether they be SSM or otherwise. The reason for this is that the join actually takes effect a couple of layers down from a process issuing a join request. Basically, it tells the IP layer to accept multicast packets from the source specified and provide them to any process bound to the socket with the multicast address.
SSM was actually introduced because of the limited address space of IPv4. When using multicast on the internet there are not nearly enough unique multicast addresses such that each person who want to use one could have a unique address. SSM pairs a source address with a multicast address which as a pair form a globally unique identifier i.e. shared multicast address e.g. 239.10.5.1 and source 192.168.1.5. So the reason that SSM exists is purely for this purpose of facilitating multicast in a limited address space. In the environment that our software is working in (Cisco) SSM is being used for redundancy and convenience of transmission, stacking multiple streams of data on the same IP:port combo and having downstream clients select the stream they want. This all works just fine until a given host wants access to more than one stream in the multicast, because they're all on the same multicast address all subscribed processes get all the data, and this is unavoidable due to the way the network stack works.
Final solution
Now that the behaviour has been understood the solution is straightforward, but does require additional code in each running process. Each process must filter the incoming data from the multicast address and only read data from the source(s) that they are interested in. I had hoped that there was some "magic" in built into SSM to do this automatically, but there is not. recvfrom() already provides the senders address so doing this is relatively low cost.

Know from which pcap filter my packet came

I'm trying to use libpcap to sniff some "network interfaces" (loopback included).
In my example application, I have packets coming from the loopback in the ports 1234, 1235 and 1236. I found already a way to make libpcap filter only packets coming from these addresses, using libpcap_setfilter(): my goal was to forward these packets accordingly to the address/port from which they came (for example, packets coming from 127.0.0.1/1234 could go through the eth0 interface; packets coming from 127.0.0.1/1235 could be forwarded through the eth1; and the ones coming from 127.0.0.1/1236 could be forwarded though the eth2).
My question is: is there any way to know from exactly what port these packets came without having to look at their content? Can I, for example, set many filters and somehow know from what filter was the one who filtered my packet?
I've already read a lot of the documentation and of tutorials, but none seemed useful so far. I also will be ok if the answer is "it is not possible".
Thanks in advance.
The capture mechanisms atop which libpcap runs support only one filter, so libpcap has no APIs to set multiple filters.
You could, however, open multiple pcap_t's for the same network interface and apply different filters to them. Reading from multiple pcap_t's, however, is potentially platform-dependent. I infer from the "eth0", "eth1", and "eth2" that this is Linux, so you should be able to use select() or poll() or... on the return values from pcap_get_selectable_fd() on the pcap_t's and, if select() or poll() or... says a given descriptor is readable, call pcap_dispatch() on the corresponding pcap_t to process packets for that pcap_t.

How to Multicast (send) to first NIC?

I found recently that if I have a dial-up connection (this is for a kiosk) and a local area network connection, when the dial-up connection is established (with internet access), my multicast sendto would default to the dial-up rather than my LAN NIC. This made the multicast go out to the dial-up connection instead rather than to my LAN which has several multicast subscribers.
I understand that I need to use IP_MULTICAST_IF to set the interface on my multicast socket. Question is how do I enumerate the interfaces and how do I use IP_MULTICAST_IF in setsockopt?
On the kiosk Windows XP Embedded, there's always going to be just one local area connection NIC. How do I get this interface and pass its IP address (is this what IP_MULTICAST_IF is expecting??) to setsockopt?
Apparently setsockopt and IP_MULTICAST_IF don't work if wsock32.dll is used instead of ws2_32.dll. I thought I was doing it wrong when I kept getting 1.0.0.0 as the IP address even when it was something else that I've set with setsockopt. Funny thing is, before the call to IP_MULTICAST_IF, it would return 0.0.0.0, so setsockopt` did change something, just not correctly.
Someone else who had this same problem way back in 2004 - http://us.generation-nt.com/ip-multicast-problem-help-37595922.html. When we #include "winsock2.h" we need to use ws2_32.dll. However, with C++ Builder, it's impossible to use ws2_32.dll when we use winsock2.h - the RTL implicitly links in wsock32.dll and you can't link ws2_32.dll even if you explicitly specify #pragma comment(lib, "ws2_32.lib"). Embarcadero really need to fix this! Someone in the RTL team must've decided it's clever to implicitly include wsock32.dll. The only 'clever' thing it did was users didn't have to include one line in their code - #pragma comment(lib, "wsock32.lib"). While they're at that, they might as well include every single DLL files known to mankind.
Use GetAdaptersAddresses() to enumerate all available interface IP addresses.
IP_MULTICAST_IF is for IPv4 addresses only. It expects you to pass a DWORD value containing the desired IPv4 address (in network byte order) to setsockopt(), eg:
DWORD dwIP = ...;
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&dwIP, sizeof(dwIP));

How to check if port is available

Is there an API function on Linux (kernel 2.6.20) which can be used to check if a given TCP/IP port is used - bound and/or connected ?
Is bind() the only solution (binding to the given port using a socket with the SO_REUSEADDR option, and then closing it) ?
Hmm,
According to strace -o trace.out netstat -at
netstat does this by looking at
/proc/net/tcp
and
/proc/net/tcp6
The used ports are in hex in the second field of the entries in that file.
You can get the state of the connection by looking at the 4th field, for example 0A is LISTEN and 01 is ESTABLISHED.
The holy portable BSD socket API won't allow you to know whether the port is in use before you try to allocate it. Don't try to outsmart the API. I know how tempting it is, I've been in that situation before. But any superficially smart way of doing this (by e.g. the proc filesystem) is prone to subtle errors, compatibility problems in the future, race conditions and so forth.
Grab the source of the netstat command and see how it sees. However, you will always have a race. Also, SO_REUSEADDR won't let you use a port someone else is actively using, of course, just one in close-wait.

Resources