How to read TENTATIVE flag of IPv6 Address? - c

I am assigning ipv6 address using ioctl() system call prgramtically.
I want to know if there is a way, i can find the assigned ip is tentative/duplicate ?
Thanks.

Host: Enumerate the interfaces with getifaddrs().
(edit) Looks like you need to call sysctl(NET_IPV6_OPT_DAD_ENABLE) before getifaddrs()?
http://lwn.net/Articles/218597/
Network: Send an ICMP ping is the typical but not fool proof method that DHCP servers use.
It is assumed if you are setting the IP then you are implementing a form of DHCP and you control all the addresses for that segment. Otherwise just use the link-local scope already unique addresses.

You can read TENTATIVE flag of IPv6 Address as below:
Indicates flags that are set on the multicast address. As of RFC 2373, the only flag defined is the Transient (T) flag. The T flag uses the low-order bit of the Flags field.
* If 0, the multicast address is a permanently assigned, well-known multicast address allocated by the Internet Assigned Numbers Authority (IANA).
* If 1, the multicast address is a not permanently assigned, or transient.

One way to get the state of the address is to use the rtnetlink library via the RTM_GETADDR message which retrieves the ifaddrmsg structure which contains ifa_flags. Look at the man page here for information:
http://man7.org/linux/man-pages/man7/rtnetlink.7.html
The flags and ifaddrmsg structure are shown in if_addr.h:
https://github.com/torvalds/linux/blob/master/include/uapi/linux/if_addr.h

Related

Purpose of sendto address for C raw socket?

I'm sending some ping packets via a raw socket in C, on my linux machine.
int sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
This means that I specify the IP packet header when I write to the socket (IP_HDRINCL is implied).
Writing to the socket with send fails, telling me I need to specify an address.
If I use sendto then it works. For sendto I must specify a sockaddr_in struct to use, which includes the fields sin_family, sin_port and sin_addr.
However, I have noticed a few things:
The sin_family is AF_INET - which was already specified when the socket was created.
The sin_port is naturally unused (ports are not a concept for IP).
It doesn't matter what address I use, so long as it is an external address (the IP packet specifies 8.8.8.8 and the sin_addr specifies 1.1.1.1).
It seems none of the extra fields in sendto are actually used to great extent. So, is there a technical reason why I have to use sendto instead of send or is it just an oversight in the API?
Writing to the socket with send fails, telling me I need to specify an address.
It fails, because the send() function can only be used on connected sockets (as stated here). Usually you would use send() for TCP communication (connection-oriented) and sendto() can be used to send UDP datagrams (connectionless).
Since you want to send "ping" packets, or more correctly ICMP datagrams, which are clearly connectionless, you have to use the sendto() function.
It seems none of the extra fields in sendto are actually used to great
extent. So, is there a technical reason why I have to use sendto
instead of send or is it just an oversight in the API?
Short answer:
When you are not allowed to use send(), then there is only one option left, called sendto().
Long answer:
It is not just an oversight in the API. If you want to send a UDP datagram by using an ordinary socket (e.g. SOCK_DGRAM), sendto() needs the information about the destination address and port, which you provided in the struct sockaddr_in, right? The kernel will insert that information into the resulting IP header, since the struct sockaddr_in is the only place where you specified who the receiver will be. Or in other words: in this case the kernel has to take the destination info from your struct as you don't provide an additional IP header.
Because sendto() is not only used for UDP but also raw sockets, it has to be a more or less "generic" function which can cover all the different use cases, even when some parameters like the port number are not relevant/used in the end.
For instance, by using IPPROTO_RAW (which automatically implies IP_HDRINCL), you show your intention that you want to create the IP header on your own. Thus the last two arguments of sendto() are actually redundant information, because they're already included in the data buffer you pass to sendto() as the second argument. Note that, even when you use IP_HDRINCL with your raw socket, the kernel will fill in the source address and checksum of your IP datagram if you set the corresponding fields to 0.
If you want to write your own ping program, you could also change the last argument in your socket() function from IPPROTO_RAW to IPPROTO_ICMP and let the kernel create the IP header for you, so you have one thing less to worry about. Now you can easily see how the two sendto()-parameters *dest_addr and addrlen become significant again because it's the only place where you provide a destination address.
The language and APIs are very old and have grown over time. Some APIs can look weird from todays perspective but you can't change the old interfaces without breaking a huge amount of existing code. Sometimes you just have to get used to things that were defined/designed many years or decades ago.
Hope that answers your question.
The send() call is used when the sockets are in a TCP SOCK_STREAM connected state.
From the man page:
the send() call may be used only when the socket is in a connected
state (so that the intended recipient is known).
Since your application obviously does not connect with any other socket, we cannot expect send() to work.
In addition to InvertedHeli's answer, the dest_addr passed in sendto() will be used by kernel to determine which network interface to used.
For example, if dest_addr has ip 127.0.0.1 and the raw packet has dest address 8.8.8.8, your packet will still be routed to the lo interface.

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.

c - pcap filter expression

I was wondering how the input data in this expression actually works.
char *filter = "dst host 172.17.14.90 and ip";
From what I understand the dest host bit and the following IPv4 address defines what address the recieved packet should be addressed to.
The man page was a bit confusing on that point saying:
dst host host
True if the IPv4/v6 destination field of the packet is host,
which may be either an address or a name.
http://www.manpagez.com/man/7/pcap-filter/
so is that what it means? and as for the and ip bit I have no clue.
You are right about the first bit:
dst host 172.17.14.90
means that the packet should be addressed to 172.17.14.90.
The second one:
ip
like the manpage says is an abbreviation for:
ether proto ip
which means that the packet must be sent using the IP protocol.
So, to sum up: the packet must be sent using the IP protocol to the host having IP address 172.17.14.90.
As a note, the above could be expressed simpler using:
ip dst host 172.17.14.90
(the shorter syntax is explained near host explanation in the manpage)

Does sendto() dst_addr arg matters if used on a raw socket with IP_HDRINCL set?

The question is almost all in the title.
I was wondering, given that:
- I use a raw socket (on GNU/Linux);
- the option IP_HDRINCL is set so that I craft the IP headers by myself.
As the dest IP addr is provided in the crafted IP header, does the dst_addr argument still plays a role or is it totally useless & only here cause that's how the function prototype is ?
The destination address is used to route the packet - it'll be the key that's used for a routing table lookup to determine the next hop address to send it to. It should usually be the same as the destination address you set in the header.
No it does not matter.
What you enter in the headers is where the packet would go.

Discovering the default gateway without DHCP

A crazy question, but is there anyway to discover the default gateway without DHCP?
This would be for a device on a network which does not use DHCP which does not have an IP address as yet. I was thinking if I could discover the default gateway, then i could try to guess an unused ip address then broadcast on the network to see if it's being used.
I may be asking for trouble i understand. E.g. if there is already a computer which has a static IP and is shutdown.
Packet sniff for a while and then apply heuristics. I'm assuming IPv4 and Ethernet for the rest of this. This won't work so well if Ethernet Switches are used rather than HUBs. More on that at the end.
Create your own RARP (reverse address resolution) table based on the Ethernet (or whatever) and IP headers you see as well as actual ARP packets (ignoring broadcast and multicast IP and MAC addresses). Make sure that your table is able to map multiple IP addresses to a single hardware interface. Any IP addresses in the table that are entered or verified by actual ARP packets should be flagged as such.
The gateway(s) is likely to recieve and send more traffic. This traffic is likely to have many IP addresses from many different networks but have the same hardware address. The gateway will show up in your table as one MAC address with lots of IP addresses. It is likely that you will have observed an ARP transaction involving this MAC address address, so you can look for an IP address that aliases that MAC that also has the seen in ARP packet flag set. That is almost certainly a gateway's IP address.
You will probably be able to guess the network address and subnet mask based on the IP address of the gateway, but this might not be something you can trust. If you want to try to make this work on a network with a non-standard netmask you can try to do the following.
Make two IP address sized accumulator variables:
uint32_t acc_and = 0xFFffFFff;
uint32_t acc_or = 0x00000000;
And then for each ARP verified address in your table you do
acc_and &= ip_addr;
acc_or |= ip_addr;
You could also use destination IP addresses (that aren't multicast) in packets that came from the gateway for this, but you would have to know the gateway before you could flag them as such.
finding the netmask and network address
The network portion of the address should stay the same in both (after the first operation), but in acc_and the bottom bits should start clearing out while in the acc_or the bottom bits should start filling up. With enough samples you would be able to determine the network address by:
uint32_t net_addr = acc_and & acc_or;
and the netmask by:
uint32_t net_mask = acc_and ^ acc_or;
Getting enough sampled local IP addresses could take too long, so you can start trying to narrow it down by:
uint32_t almost_net_mask = acc_and ^ acc_or;
int i = 0;
while ( 1 & almost_net_mask ) {
i++;
almost_net_mask >>= 1;
}
uint32_t net_mask = 0xFFffFFff;
while( i-- ) {
net_mask <<=1;
}
This would find you the last 1 bit set. The lowest 0 bit is obviously not part of the local portion of the address. Alternately you could get the same i by:
i = ffs( ~ ( acc_and ^ acc_or ) ) ; // assuming that int on your system is 32 bit. if not use ffsl
If you really really want to be sure of your netmask and network address now you can try some other things. You can try to see if the gateway will attempt to forward packets you send it to what you think should be local addresses to them. For this would would have to go ahead and assign yourself an IP address, which is risky if your netmask isn't right.
choosing an IP for yourself
Try to choose the lowest legal IP address that you haven't seen traffic to or from to increase the chance that it is not out of range. You could spoof an ARP request for that address and look for any replies (you could use your own real MAC address but possibly make up an IP for this. doesn't have to be your IP, which might confuse things for a little bit). After you have found an IP address that you can't ARP claim it for yourself.
It is possible that you ended up with an IP address that is actually too high. This is difficult to know for sure since your netmask is still just a good guess. You're out of luck if this is the case because there is not free slot for you to live.
back to the netmask
To see if your netmask needs adjusting try sending IP packets with destination addresses that you haven't see in the local network but that could be in the local network based on your guesses at the netmask and the network address. If these guesses are off they should have too many bits assigned to the network address, so sending to addresses which change the lower bits from the netmasked portion of the (so far) best guessed network address is what you want. You can try sending these as you normally would by ARPing the IP address and seeing if anyone replies, but since you are guessing addresses and likely to miss, it might be better to try creating the packet(s) with the destination MAC address set to the gateway to see if it would forward it. It may be configured not to, so you could try to see if it would by first doing this for a member of the network which you have already observed in the network and then see if it forwards it for you. If the gateway forwards the packet then you can rely on its idea of the netmask to narrow down your idea of the netmask. If the gateway will not forward for packets destine for known members of the local network then you can either just keep using your idea of the local netmask and network until you have a reason to adjust it or send out ARP requests for addresses in that range (which will only answer your question as either "yes" or "maybe" with no possibility of a sure "no").
if you are using an Ethernet switch, rather than a HUB
If you are using an Ethernet switch things get much more difficult because the switch will not forward Ethernet frames to you if it knows that the frames should go somewhere else, so you will not see them. It will forward many ARP requests, though, since they are broadcast unless the sender still has an entry for that IP in its ARP cache and is just trying for an early renewal of that entry (this may not be done by all systems). This will make building your idea of the network and its members much more difficult, but you will likely be able to do a decent job. You will probably have to rely on the quantity of ARP request for the gateway and from the gateway being higher than the other systems to spot it, though. This is error prone as a file server could have similar traffic.
Could be done but not in easy way (according to my poor knowledge).
Solution I would analyze further:
Detect Gateway - 2 possibilities (all off them related with data sniffing):
capture DHCP offer packets and
retrieve gateway
look for packet which is addressed to outer network (e.g. do arp request on each target IP address - if no answer you have probable mac address of the default gateway - you need to find IP address of this gateway (analyze arp packets, all packets, etc..)
one you have ip address do a arp requests and find you free ip.
sniffing library I think is libpcap or winpcap.
Never done even something similiar but If I wouldn't find any references on google I would go this way I think.
On a Windows network, you could use IP 0.0.0.0 and open a UDP socket with port 67 (or maybe 68) and wait for SMB broadcast messages to learn an IP address. From there, you can use ARP packets to search for devices on addresses close to that IP.
Try to find an unused address that as close to the original IP (identical upper bits) in case the network uses a netmask smaller than 255.255.255.0. Once you find an unused IP, claim it for your device and send a gratuitous ARP.
Now continue your ARP scan, and whenever you find a device that responds, temporarily set it as your default gateway and try to ping a known IP address of a device on the Internet that will respond. If you get a response, you've found your gateway.
That's a lot of work when using DHCP will get you there 99% of the time.

Resources