Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check whether IP address that socket is bound to still exists?

Once I call socket(); bind() (with a specific IP address, not INADDR_ANY); listen(), there seems to be no way of determining if the IP address is still a valid address of one of the system's interfaces.

What I looked into using:

  • Checking error with getsockopt(SO_ERROR);
  • Using epoll()-ing on some EPOLLERR, EPOLL{,RD}HUP events;
  • Hoping that accept() would return an error if the IP address is deleted when process is blocked on this syscall;

Non of those above seem to detect the IP address vanishing and/or change of interface state at all.

  • Calling bind() in some timer callback to periodically check if the IP address may be bound, but this requires another socket has to be created it is not feasible.

I did not test these:

  • Setting SO_BINDTODEVICE in the hope that this will change behavior of the facilities from the first triple in case interface goes down/IP address is removed.

  • Calling some ioctl() like SIOCSPGRP or FIOASYNC since they promise to signal process about asynchronous events that hopefully include disappearance of an IP address.

  • Using netlink to get routing table events, but this is very Linux-specific.

I'm hopping for a more portable way.

What I needing is some event similar to RDMA_CM_EVENT_DEVICE_REMOVAL, but with AF_INET sockets that would notify me when there is no bound interface with that IP address. Even this may be impossible to fulfill, because even bind() completes without error if the interface is down.

like image 924
Philipp Avatar asked Nov 16 '22 03:11

Philipp


1 Answers

You do not need to close a socket when the link goes down with BSD sockets.

This other questions shows how to listen for network routing changes mentioned by Remy.

A simpler way may be to check if the IP is currently bound before using the socket. This is a way to verify that 127.0.0.1 is still valid:

% cat checksocket.c && cc -o checksocket checksocket.c ; ./checksocket
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <net/if.h>

int main (void)
{
    struct ifaddrs *ifa, *i;
    char host[NI_MAXHOST];

    int ret = getifaddrs(&ifa);
    if (ret) {
        perror("getifaddrs:");
        exit(EXIT_FAILURE);
    }

    for (i = ifa; i != NULL; i = i->ifa_next) {
        ret = getnameinfo(i->ifa_addr, sizeof(*(i->ifa_addr)),
            host, sizeof(host), NULL, 0, NI_NUMERICHOST);
        char find[] = "127.0.0.1";
        int len = strlen(host);
        if (!ret && len && !strncmp(host, find, len)) {
            printf("Still valid: %s %s\n", i->ifa_name, ret ? "" : host);
        }
    }

    freeifaddrs(ifa);

    return 0;
}
Still valid: lo0 127.0.0.1
like image 177
James Risner Avatar answered Dec 21 '22 13:12

James Risner