From e1d847772bbb9512d2273561dad60937c18d4602 Mon Sep 17 00:00:00 2001 From: Brian Lichtman Date: Sat, 10 Feb 2018 17:37:46 -0500 Subject: [PATCH] Network Interface Detection Bug Fix It appears that the socket ioctl command SIOCGIFCONF can return invalid objects. When the socket ioctl command SIOCGIFFLAGS was called on the network interfaces returned by SIOCGIFCONF, the function can return in error with errno ENODEV (19) "No such device." Specifically, this affected running the software on my DD-WRT ARM based linux distrobution. According to "http://refspecs.linuxbase.org/LSB_3.0.0/LSB-PDA/LSB-PDA/baselib-sockio-2.html", "The SIOCGIFCONF interface is superceded by the if_nameindex() family of functions (see ISO POSIX (2003))." After switching to use if_nameindex(), the hdhomerun_local_ip_info() function is now successfully is able to lookup network interfaces on DD-WRT's ARM implementation. Additionally, I have tested this on my Macbook and it appears to work with no problems. Testing was done by running the command "./hdhomerun_config discover" --- hdhomerun_sock_posix.c | 58 +++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 37 deletions(-) mode change 100644 => 100755 hdhomerun_sock_posix.c diff --git a/hdhomerun_sock_posix.c b/hdhomerun_sock_posix.c old mode 100644 new mode 100755 index d71acf0..63b1e50 --- a/hdhomerun_sock_posix.c +++ b/hdhomerun_sock_posix.c @@ -20,13 +20,11 @@ #include "hdhomerun.h" +#include #include +#include #include -#ifndef SIOCGIFCONF -#include -#endif - #ifndef _SIZEOF_ADDR_IFREQ #define _SIZEOF_ADDR_IFREQ(x) sizeof(x) #endif @@ -35,54 +33,39 @@ #define MSG_NOSIGNAL 0 #endif + struct hdhomerun_sock_t { int sock; }; int hdhomerun_local_ip_info(struct hdhomerun_local_ip_info_t ip_info_list[], int max_count) { - int sock = socket(AF_INET, SOCK_DGRAM, 0); + int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (sock == -1) { return -1; } - struct ifconf ifc; - size_t ifreq_buffer_size = 1024; - - while (1) { - ifc.ifc_len = (int)ifreq_buffer_size; - ifc.ifc_buf = (char *)malloc(ifreq_buffer_size); - if (!ifc.ifc_buf) { - close(sock); - return -1; - } - - memset(ifc.ifc_buf, 0, ifreq_buffer_size); - - if (ioctl(sock, SIOCGIFCONF, &ifc) != 0) { - free(ifc.ifc_buf); - close(sock); - return -1; - } - - if (ifc.ifc_len < (int)ifreq_buffer_size) { - break; - } - - free(ifc.ifc_buf); - ifreq_buffer_size += 1024; + /* + * Retrieve network interfaces from OS. if_nameindex() dynamically allocates a list of + * network interface names and indexs. + */ + struct if_nameindex *if_ni, *iter; + if_ni = if_nameindex(); + if (if_ni == NULL) { + perror("if_nameindex"); + exit(EXIT_FAILURE); } - char *ptr = ifc.ifc_buf; - char *end = ifc.ifc_buf + ifc.ifc_len; - + struct ifreq *ifr = malloc(sizeof(struct ifreq)); int count = 0; - while (ptr < end) { - struct ifreq *ifr = (struct ifreq *)ptr; - ptr += _SIZEOF_ADDR_IFREQ(*ifr); + for (iter = if_ni; ! (iter->if_index == 0 && iter->if_name == NULL); ++iter) { + + /* Set interface's name for flag lookup. */ + strncpy(ifr->ifr_name, iter->if_name, IF_NAMESIZE); /* Flags. */ if (ioctl(sock, SIOCGIFFLAGS, ifr) != 0) { + fprintf(stderr, "ioctl: flags SIOCGIFFLAGS errno %d/%s\n", errno, strerror(errno)); continue; } @@ -122,7 +105,8 @@ int hdhomerun_local_ip_info(struct hdhomerun_local_ip_info_t ip_info_list[], int count++; } - free(ifc.ifc_buf); + if_freenameindex(if_ni); + free(ifr); close(sock); return count; }