diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/gdm-address.c | 116 |
1 files changed, 98 insertions, 18 deletions
diff --git a/common/gdm-address.c b/common/gdm-address.c index 490b7fcc..9e23f1a0 100644 --- a/common/gdm-address.c +++ b/common/gdm-address.c @@ -30,6 +30,8 @@ #include <sys/socket.h> #endif #include <netdb.h> +#include <sys/ioctl.h> +#include <net/if.h> #ifndef G_OS_WIN32 #include <sys/socket.h> @@ -280,25 +282,71 @@ gdm_address_is_loopback (GdmAddress *address) return FALSE; } -const GList * -gdm_address_peek_local_list (void) +static void +add_local_siocgifconf (GList **list) { - static GList *the_list = NULL; - static time_t last_time = 0; - char hostbuf[BUFSIZ]; - struct addrinfo *result; - struct addrinfo *res; + struct ifconf ifc; + struct ifreq ifreq; + struct ifreq *ifr; + struct ifreq *the_end; + int sock; + char buf[BUFSIZ]; + + if ((sock = socket (PF_INET, SOCK_DGRAM, 0)) < 0) { + perror ("socket"); + return; + } - /* Don't check more then every 5 seconds */ - if (last_time + 5 > time (NULL)) { - return the_list; + ifc.ifc_len = sizeof (buf); + ifc.ifc_buf = buf; + if (ioctl (sock, SIOCGIFCONF, (char *) &ifc) < 0) { + perror ("SIOCGIFCONF"); + close (sock); + return; } - g_list_foreach (the_list, (GFunc)gdm_address_free, NULL); - g_list_free (the_list); - the_list = NULL; + /* Get IP address of each active IP network interface. */ + the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); + + for (ifr = ifc.ifc_req; ifr < the_end; ifr++) { + if (ifr->ifr_addr.sa_family == AF_INET) { + /* IP net interface */ + ifreq = *ifr; + + if (ioctl (sock, SIOCGIFFLAGS, (char *) &ifreq) < 0) { + perror("SIOCGIFFLAGS"); + } else if (ifreq.ifr_flags & IFF_UP) { /* active interface */ + if (ioctl (sock, SIOCGIFADDR, (char *) &ifreq) < 0) { + perror("SIOCGIFADDR"); + } else { + GdmAddress *address; + address = gdm_address_new_from_sockaddr ((struct sockaddr *)&ifreq.ifr_addr, + sizeof (struct sockaddr)); + + gdm_address_debug (address); + + *list = g_list_append (*list, address); + } + } + } + + /* Support for variable-length addresses. */ +#ifdef HAS_SA_LEN + ifr = (struct ifreq *) ((caddr_t) ifr + + ifr->ifr_addr.sa_len - sizeof(struct sockaddr)); +#endif + } - last_time = time (NULL); + close (sock); +} + +static void +add_local_addrinfo (GList **list) +{ + char hostbuf[BUFSIZ]; + struct addrinfo *result; + struct addrinfo *res; + struct addrinfo hints; hostbuf[BUFSIZ-1] = '\0'; if (gethostname (hostbuf, BUFSIZ-1) != 0) { @@ -306,26 +354,58 @@ gdm_address_peek_local_list (void) snprintf (hostbuf, BUFSIZ-1, "localhost"); } + memset (&hints, 0, sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_CANONNAME; + + g_debug ("GdmAddress: looking up hostname: %s", hostbuf); result = NULL; - if (getaddrinfo (hostbuf, NULL, NULL, &result) != 0) { + if (getaddrinfo (hostbuf, NULL, &hints, &result) != 0) { g_debug ("%s: Could not get address from hostname!", "gdm_peek_local_address_list"); - return NULL; + return; } for (res = result; res != NULL; res = res->ai_next) { GdmAddress *address; + g_debug ("family=%d sock_type=%d protocol=%d flags=0x%x canonname=%s\n", + res->ai_family, + res->ai_socktype, + res->ai_protocol, + res->ai_flags, + res->ai_canonname); address = gdm_address_new_from_sockaddr (res->ai_addr, res->ai_addrlen); - the_list = g_list_append (the_list, address); + *list = g_list_append (*list, address); } if (result != NULL) { freeaddrinfo (result); result = NULL; } +} + +const GList * +gdm_address_peek_local_list (void) +{ + static GList *list = NULL; + static time_t last_time = 0; + + /* Don't check more then every 5 seconds */ + if (last_time + 5 > time (NULL)) { + return list; + } + + g_list_foreach (list, (GFunc)gdm_address_free, NULL); + g_list_free (list); + list = NULL; + + last_time = time (NULL); + + add_local_siocgifconf (&list); + add_local_addrinfo (&list); - return the_list; + return list; } gboolean |