Is ARP table self-learning? - arp

I'm learning data communications and networking.
Here is my question about ARP's mechanism:
Suppose host A and B knows each other's IP address but don't know each other's MAC address. Then when A wants to send IP datagram to B, A needs to go through the ARP processes:
Broadcast the ARP request to the LAN (with B's IP address asking for B's MAC address).
Host B receives the request, and send ARP reply to A (by unicast).
Host A receives the reply.
Now A knows B's MAC address i.e., A's ARP table has B's entry.
BUT How about B's ARP table? Does it has A's entry?
If B receives A's IP datagram and want to send back some IP datagram to A, does B need to go through the above ARP processes to get A's MAC address?
Does ARP table has self-learning mechanism (like switch table), which can update its entry when receiving an ARP request ?
Thanks!

Related

How to send packets from stm32f4, 192.x.x.x to 10.x.x.x with lwip

I`m attempting to force an out-of-gateway address using the udp_sendto () function.
ex) listen IP address : 192.168.1.10 -> send IP address : 224.0.0.1
This concept takes a packet to a unicast address
and sends it to a multicast address.
when i try udp_sendto(224.0.0.1), it`s pending in ip4.c: ip4_route() line 164.
I want inspiration how to fix it.
Thanks a lot for your help!

Socket Programming- Change Socket IP

Note: the question was edited.
I have few questions on Berkeley Socket Programming:
Is it possible to change a socket address after binding? If so- What are the C commands to do so?
2.According to https://www.cs.cmu.edu/~srini/15-441/F01.full/www/assignments/P2/htmlsim_split/node18.html, when a socket is bind to INADDR_ANY, it receives packets from all interfaces, but when a packet is sent,(using sent command) it sends through a single NIC with the default IP.
If I understand correctly- if a server has two active NICs, with different IPs, then a socket with the INADDR_ANY parameter can receive a packet with dst IP=x and send a packet with src IP=y, where x is not y. This can cause problems, for example in TCP connections, where the socket in the other destination is will receive the packet, but will drop it due as the dest IP is not the one expected.
Is it true? And if so- does it means that server programs are NOT using INADDR_ANY where there are (two or more) active NICs with different IPs?
Suppose the NIC of the default IP causes bottleneck. Can we change the socket options so that the packets will be send through another NICs(and not the previous NIC)? Can we do so if the NICs have the default IP address?
Can we send packets through one NIC, and set the IP destination to another NIC? (I.e, NIC1 will only send packets, and NIC2 will only receive packets )
Is it possible to change a socket address after created?
Sockets don't have an IP address to change when created. They get one when bound.
If so- What are the C commands to do so?
The Berkeley Sockets API functions to do so are bind() and connect().
When a socket is bind to INADDR_ANY, it receives packets from all interfaces, but sends through a single NIC with the default IP.
No. It sends packets via whichever NIC is necessary to reach the target in each case.
Your cited source draws a distinction without a difference. A socket bound to INADDR_ANY receives packets from any interface. There is no difference between 'any' and 'all' as far as INADDR_ANY is concerned. It is far easier to understand as 'any'.
If I understand correctly- if a server has two active NICs, with different IPs, then a socket with the INADDR_ANY parameter can receive a packet with dst IP=x and send a packet with src IP=y, where x is not y
No. It sends the packet with the same source address the client originally connected to. That's part of what defines the connection.
This can cause problems, for example in TCP connections, where the socket in the other destination is will receive the packet, but will drop it due as the dest IP is not the one expected.
No. The destination in the packet is the client's IP address. Otherwise it wouldn't even get there. This is just nonsense. If you mean the source IP, see above.
Is it true?
No.
And if so- does it means that server programs are NOT using INADDR_ANY where there are (two or more) active NICs with different IPs?
No. INADDR_ANY means exactly what it says. Any IP address: any NIC.
Suppose the NIC of the default IP causes bottleneck. Can we change the socket options so that the packets will be send through another NICs (and not the previous NIC)?
No, but you can alter the IP routing tables.
Can we do so if the NICs have the default IP address?
Only one of them can have the default IP address. The question doesn't make sense.
Can we send packets through one NIC, and set the destination to another NIC?
Only if you're sending to yourself. Otherwise the question doesn't make sense.
(from your citation) When sending, a socket bound with INADDR_ANY binds to the default IP address, which is that of the lowest-numbered interface
I hope this refers to whatever simulator is being described. If it is meant to be a description of how TCP works it is wrong.

How can non-exclusive ports exist when tcp identify applications using 16-bit port number?

I can't come up with the exact socket api,but I remember that there is a socket option that demonstrates the port exclusive/non-exclusive.
If it's not exclusive,how can TCP know which application it should forward to for a specific destination port?
I think you might be referring to the SO_REUSEPORT option available on some systems.
From the BSD man page:
SO_REUSEPORT allows completely duplicate bindings by multiple processes
if they all set SO_REUSEPORT before binding the port. This option permits multiple instances of a program to each receive UDP/IP multicast or
broadcast datagrams destined for the bound port.
Implementations vary a lot for this (from non-existant, to restricted to UDP, to allowing TCP also). In the cases where TCP is allowed, the connexions are distinguished by both source and target (ip,port) pairs. This is sufficient to allow the implementation to decide which app needs which packet. (see Trek - Socket options for instance.)
With multiple apps bind to the same TCP port, you could only have one socket accepting on the port. The others would use the port to initiate outbound connections. The TCP stack always knows where to send the packets to.
incoming packets that initiate (SYN) a connection go to the only accepting socket
incoming packets for a connected stream are routed to the socket they belong to
Note: the sockets themselves (including, I believe the accepting socket) can be shared across multiple processes. See Is there a way for multiple processes to share a listening socket? for example.
Here's how it could work. Voluntarily simplifying TCP (no three-way handshake). Let's note the socket information held by the TCP stack like this
(socketname)[owner app, (local IP, local port), (state, remote IP, remote port)]
With that, let's set up three apps A, B and C:
App A -> bind (localhost,12345,SO_REUSEPORT)
TCP stack: create socket (s1)[belongs to A, (localhost,12345), (not connected)]
App A <- s1
App B -> bind (localhost,12345,SO_REUSEPORT)
TCP stack: create socket (s2)[belongs to B, (localhost,12345), (not connected)]
App B <- s2
App C -> bind (localhost,12345,SO_REUSEPORT)
TCP stack: create socket (s3)[belongs to C, (localhost,12345), (not connected)]
App C <- s3
App C -> s3.listen()
TCP stack: update socket (s3)[belongs to C, (localhost,12345), (open for business)]
App C -> s3.accept()
At this point, no data has been sent, but the kernel knows exactly what socket belongs to what application. Let's have A actually try to do something with its socket:
App A -> s1.connect(otherhost,54321)
TCP stack: update socket (s1)[belongs to A, (localhost,12345), (connecting, otherhost,54321)]
TCP stack: send SYN
Here, three things can happen:
incoming ACK packet from (otherhost,54321) with correct sequence: this is fine, it's for s1, no other possibility
TCP stack: update socket (s1)[belongs to A, (localhost,12345), (connected,otherhost,54321)]
TCP stack: send SYN/ACK
TCP stack: notify App A that socket is connected
App A <- connect succeeded, you can start doin' stuff
incoming SYN packet from (client,4343): can only be for s3, only socket ready for SYN
TCP stack: create new socket (s4)[belongs to C, (localhost,12345), (connected,client,4343)]
TCP stack: send ACK to client
TCP stack: notify App C that (s4) has been accepted
App C <- s4 returned from accept()
incoming packet from somewhere else:
TCP stack: drop or reject, there are no matching sessions
Let's imagine the two things above happened. The kernel information is now:
(s1)[belongs to A, (localhost,12345), (connected,otherhost,54321)]
(s2)[belongs to B, (localhost,12345), (not connected)]
(s3)[belongs to C, (localhost,12345), (open for business)]
(s4)[belongs to C, (localhost,12345), (connected,client,4343)]
Now four kinds of packets can come in:
incoming normal packet from (otherhost,54321): this matches s1, hand it over to App A
incoming normal packet from (client,4343): this matches s4, hand it over to App C
incoming SYN packet from (otherclient,2398): this matches s3, same as before
anything else: drop or reject, invalid state
The TCP stack always nows which socket a packet belongs to. So it knows where to deliver the data.
SO_REUSEADDR is different: it only allows to bind to a port in TIME_WAIT state - i.e. the port is already closing down, the socket that had opened it has been issued a close already (more or less, there are other conditions). With SO_REUSEADDR, only one socket at a time holds the socket open.
A socket is identified by the IP address and the port - both. Together, in the BSD socket API, they are called a "name". You can bind your socket to a name and, if that name comprises a specific address, you can bind another socket to another name with the same port.
Also: a connection is a pair of two sockets, so a single address/port pair can be used in several connections - meaning more than one connected socket can have the same name (but not the same fd).

How do I determine the remote endpoint a UDP packet originates from?

The socket is created and bound, then the program receives data with recv(). The question is: How do I now determine from which host + port the packet originates so that I can send data back?
Note: C and Winsock is used.
Use recvfrom instead, it can return the source port and address

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