From: Roy Marples Date: Thu, 21 Feb 2008 16:45:01 +0000 (+0000) Subject: Add a listening port for linux for when we have configured an address and need to... X-Git-Tag: v3.2.3~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8ee31d946ffec9c56c8880f65a058922c9f75c92;p=thirdparty%2Fdhcpcd.git Add a listening port for linux for when we have configured an address and need to renew. Otherwise linux likes to generate an ICMP destination unreachable port unreachable message, which is probably a linux bug as we have obviously read the packet correctly through our packet filter. --- diff --git a/client.c b/client.c index b7957f77..2876f491 100644 --- a/client.c +++ b/client.c @@ -432,6 +432,12 @@ static bool do_socket (state_t *state, int mode) { if (state->interface->fd >= 0) close (state->interface->fd); +#ifdef __linux + if (mode == SOCKET_CLOSED && state->interface->listen_fd >= 0) { + close (state->interface->listen_fd); + state->interface->listen_fd = -1; + } +#endif state->interface->fd = -1; if (mode == SOCKET_OPEN) diff --git a/interface.c b/interface.c index 1fd6f645..1178382d 100644 --- a/interface.c +++ b/interface.c @@ -429,6 +429,9 @@ interface_t *read_interface (const char *ifname, _unused int metric) /* 0 is a valid fd, so init to -1 */ iface->fd = -1; +#ifdef __linux__ + iface->listen_fd = -1; +#endif exit: close (s); diff --git a/interface.h b/interface.h index 3f42ef5c..8215d48f 100644 --- a/interface.h +++ b/interface.h @@ -120,6 +120,7 @@ typedef struct interface_t size_t buffer_length; #ifdef __linux__ + int listen_fd; int socket_protocol; #endif diff --git a/socket.c b/socket.c index a854f940..7ea05d05 100644 --- a/socket.c +++ b/socket.c @@ -451,10 +451,43 @@ int open_socket (interface_t *iface, int protocol) int fd; union sockunion { struct sockaddr sa; + struct sockaddr_in sin; struct sockaddr_ll sll; struct sockaddr_storage ss; } su; struct sock_fprog pf; + struct ifreq ifr; + int n = 1; + + /* We need to bind to a port, otherwise Linux generate ICMP messages + * that cannot contect the port when we have an address. + * We don't actually use this fd at all, instead using our packet + * filter socket. */ + if (iface->listen_fd == -1 && + iface->previous_address.s_addr && + ! IN_LINKLOCAL (iface->previous_address.s_addr)) + { + if ((fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + } else { + memset (&su, 0, sizeof (su)); + su.sin.sin_family = AF_INET; + su.sin.sin_port = htons (DHCP_CLIENT_PORT); + su.sin.sin_addr = iface->previous_address; + if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof (n)) == -1) + logger (LOG_ERR, "SO_REUSEADDR: %s", strerror (errno)); + strncpy (ifr.ifr_name, iface->name, sizeof (ifr.ifr_name)); + if (setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof (ifr)) == -1) + logger (LOG_ERR, "SO_SOBINDTODEVICE: %s", strerror (errno)); + if (bind (fd, &su.sa, sizeof (su)) == -1) { + logger (LOG_ERR, "bind: %s", strerror (errno)); + close (fd); + } else { + iface->listen_fd = fd; + close_on_exec (fd); + } + } + } if ((fd = socket (PF_PACKET, SOCK_DGRAM, htons (protocol))) == -1) { logger (LOG_ERR, "socket: %s", strerror (errno)); @@ -491,8 +524,7 @@ int open_socket (interface_t *iface, int protocol) return (-1); } - if (bind (fd, &su.sa, sizeof (su)) == -1) - { + if (bind (fd, &su.sa, sizeof (su)) == -1) { logger (LOG_ERR, "bind: %s", strerror (errno)); close (fd); return (-1);