How to detect IP address change programmatically in Linux?
In C, to get the current IP I use:
int s;
struct ifreq ifr = {};
s = socket(PF_INET, SOCK_DGRAM, 0);
strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name));
if (ioctl(s, SIOCGIFADDR, &ifr) >= 0)
printf("%s\n",
inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
Replace "eth0" with the interface you're looking at. All you now need to do is poll for a change.
Detect IP-Address change on an interface
Because you use Systemd you might already use systemd-networkd for managing your devices instead of relying on 3rd party code.
You could use the structured journal output to get the last 2 ADDRESS
field of the current BOOD_ID.(sadly, there is no notification mechanism for address changes in systemd-networkd):
→ sudo journalctl -F ADDRESS -u systemd-networkd -n 2
192.168.178.29
So, if there is only one line output, there was no address change.
how to get notified for IP address changes automatically
You receive notifications from the kernel via netlink sockets.
You would need to create a NETLINK_ROUTE
socket and subscribe it to IP changes via bind()
ing it to the RTMGRP_IPV4_IFADDR
group. Then, you'll receive netlink messages of type RTM_NEWADDR
and RTM_DELADDR
with a route attribute of IFA_LOCAL
or IFA_ADDRESS
.
How to change ip on the fly without knowing current device
ip link show
gives you a list of interfaces, with their status:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: wlp6s0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq state DOWN mode DORMANT group default qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
25: enp0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
You just need to check which one says state UP
(in case of Ethernet, it means that the cable is connected, for wireless, it means that the network is associated). In shell, you would do:
interface="`ip link show | awk '/state UP/ { gsub(/:/, "", $2); print $2; exit }'`"
ip addr add 192.168.1.57 dev "$interface"
What should TCP/IP do if one computer changed its IP address which we are sending data to?
Assume a TCP connection between A and B. A's IP address suddenly changes.
From B's point of view, what happens is straightforward: B continues to send its data to A's old IP address. There are two possibilities:
- If A's old IP address is now unused then these packets go nowhere. They are dropped on the floor. B doesn't get any acknowledgements for them. Eventually, B decides that the connection has times out. From B's point of view, this is indistinguishable from the situation where A's network connection disappears altogether or A crashes or the power is turned off, etc...
- If A's old IP address has been claimed by a different machine, say C, then the packets that B is sending to C won't make any sense to C. They don't initiate a new TCP connection (they don't have the
SYN
flags set) and they don't match any existing TCP connection known to C. C will respond withRST
packets, and B will promptly return a "Connection reset by peer" error on the socket.
Either way, the TCP connection is broken and cannot be recovered. Furthermore, there is absolutely nothing either A or B could do about it. A simply isn't going to be able to receive (or send) any more traffic using its old IP address. It is impossible to achieve any further communication on this TCP connection.
From A's perspective it's a little bit different. After A's IP address is changed it ends up in a situation where it has a socket that is bound to a local IP address and port that doesn't exist on the local system anymore. This is normally not allowed (you can't call bind()
to bind to an IP address that is not a valid local IP address for the system) but it has come to pass anyway. The TCP/IP standard doesn't say what should be done in this case, but actual behaviour is that A would invalidate the socket immediately and return some kind of error to the application without delay.
In conclusion: A detects the problem and the connection is immediately broken, while it might take some time for B to detect the problem and return an error.
As for the ARP table, I am not sure why you are bringing that up, since that's at a lower layer (the data link layer) and doesn't really have much to do with what happens at the IP (much less TCP) layer. But, yes, the ARP tables of nodes on the same local network as A (such as a local router) now have a stale entry for A's old IP address. They'll gain a new valid entry for A's new IP address soon enough though (the first time they try to send a packet to this IP address) so it's not a problem. The stale entry could cause traffic for the old IP address to be misdirected at A, but if some other node picks up A's old IP address then gratuitous ARPs will take care of that, too.
Finally, the question "Is there a way to discover the new IP-mac mapping or we simply drop the queued data and return an error?" doesn't make sense. Sure there is a way to discover new IP-mac mappings: it's called ARP. That's ARP's sole function. But it has nothing to do with queued data, which is a concept that only has meaning two or more layers up the protocol stack.
In a comment you clarified that you are talking about the case where A and B are on the same local network as each other, but this doesn't make any difference to the answer. It's the same whether A and B are on the same local network or whether they are on remote networks.
Related Topics
Position of a String Within a String Using Linux Shell Script
Receiving Udp Broadcast Packets on Linux
How to Toggle Cr/Lf in Gnu Screen
Differencebetween Alpine Docker Image and Busybox Docker Image
"Cannot Execute Binary File" When Trying to Run a Shell Script on Linux
How to Set Cronjob with Non-Root User
Dynamically Determining Where a Rogue Avx-512 Instruction Is Executing
X86 Memory Access Segmentation Fault
Setting CPU Affinity of a Process from the Start on Linux
Sed: -I May Not Be Used with Stdin on MAC Os X
Linux 3/1 Virtual Address Split
How to Make a Bash Shell Script Interact with Another Command Line Program
Add Blank Line After Every Result in Grep
How to Mmap the Stack for the Clone() System Call on Linux
Fork() Failing with Out of Memory Error
X86 Assembly: Before Making a System Call on Linux Should You Save All Registers
Use Sed with Ignore Case While Adding Text Before Some Pattern