Detecting a Change of Ip Address in Linux

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 with RST 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



Leave a reply



Submit