summaryrefslogtreecommitdiffstats
path: root/rfc1035/rfc1035ifconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'rfc1035/rfc1035ifconf.c')
-rw-r--r--rfc1035/rfc1035ifconf.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/rfc1035/rfc1035ifconf.c b/rfc1035/rfc1035ifconf.c
new file mode 100644
index 0000000..47b24b2
--- /dev/null
+++ b/rfc1035/rfc1035ifconf.c
@@ -0,0 +1,183 @@
+/*
+** Copyright 2002 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#include "rfc1035.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+
+#if HAVE_SIOCGIFCONF
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+static int getifconf(int fd, struct rfc1035_ifconf **ifconf_ptr)
+{
+ struct ifreq ifreq_buf[64];
+ struct ifconf ifc;
+ int i;
+ const struct sockaddr_in *sin;
+ RFC1035_ADDR addr;
+ char ipaddr[RFC1035_NTOABUFSIZE];
+ struct rfc1035_ifconf *ifcptr;
+ struct rfc1035_ifconf **ifconf;
+
+ ifc.ifc_len=sizeof(ifreq_buf);
+ ifc.ifc_req=ifreq_buf;
+
+ if (ioctl(fd, SIOCGIFCONF, &ifc) < 0)
+ return (0);
+
+ for (i=0; i * sizeof(struct ifreq) < ifc.ifc_len; i++)
+ {
+ sin=(const struct sockaddr_in *)&ifreq_buf[i].ifr_addr;
+
+#if RFC1035_IPV6
+ if (sin->sin_family == AF_INET6)
+ {
+ struct sockaddr_in6 sin6;
+
+ memcpy(&sin6, sin, sizeof(sin6));
+ addr=sin6.sin6_addr;
+ }
+ else if (sin->sin_family == AF_INET)
+ rfc1035_ipv4to6(&addr, &sin->sin_addr);
+ else
+ continue;
+#else
+ if (sin->sin_family == AF_INET)
+ addr=sin->sin_addr;
+ else
+ continue;
+#endif
+
+ rfc1035_ntoa(&addr, ipaddr);
+
+ /*
+ ** Eliminate any dupes.
+ */
+
+ ifconf=ifconf_ptr;
+
+ while ( *ifconf )
+ {
+ char ipaddr2[RFC1035_NTOABUFSIZE];
+
+ rfc1035_ntoa(&(*ifconf)->ifaddr, ipaddr2);
+
+ if (strcmp(ipaddr, ipaddr2) == 0)
+ break;
+
+ ifconf= &(*ifconf)->next;
+ }
+
+ if ( *ifconf )
+ continue; /* Already have this IP addr */
+
+ if ( (ifcptr=malloc(sizeof(struct rfc1035_ifconf))) == NULL ||
+ (ifcptr->ifname=strdup(ifreq_buf[i].ifr_name)) == NULL)
+ {
+ if (ifcptr)
+ free(ifcptr);
+ return (-1);
+ }
+
+ ifcptr->ifaddr=addr;
+ ifcptr->next=NULL;
+
+ *ifconf= ifcptr;
+ }
+ return (0);
+}
+
+/*
+** On systems that support IPv6, issue an SIOCGIFCONF on both an IPv4 and
+** an IPv6 socket, for good measure.
+*/
+
+static int doifconf(struct rfc1035_ifconf **ifconf_list)
+{
+ int fd;
+
+ fd=socket(PF_INET, SOCK_STREAM, 0);
+
+ if (fd >= 0)
+ {
+ if (getifconf(fd, ifconf_list))
+ {
+ close(fd);
+ return (-1);
+ }
+ close(fd);
+ }
+
+#if RFC1035_IPV6
+
+ fd=socket(PF_INET6, SOCK_STREAM, 0);
+
+ if (fd >= 0)
+ {
+ if (getifconf(fd, ifconf_list))
+ {
+ close(fd);
+ return (-1);
+ }
+ close(fd);
+ }
+#endif
+ return (0);
+}
+
+struct rfc1035_ifconf *rfc1035_ifconf(int *errflag)
+{
+ struct rfc1035_ifconf *ifconf_list=NULL;
+ int dummy;
+
+ if (!errflag)
+ errflag= &dummy;
+
+ *errflag= -1;
+ if (doifconf(&ifconf_list))
+ {
+ rfc1035_ifconf_free(ifconf_list);
+ return (NULL);
+ }
+
+ *errflag=0;
+ return ifconf_list;
+}
+
+#else
+
+struct rfc1035_ifconf *rfc1035_ifconf(int *errflag)
+{
+ if (errflag)
+ *errflag=0;
+ return NULL;
+}
+#endif
+
+void rfc1035_ifconf_free(struct rfc1035_ifconf *ifconf_list)
+{
+ while (ifconf_list)
+ {
+ struct rfc1035_ifconf *p=ifconf_list->next;
+
+ free(ifconf_list->ifname);
+ free(ifconf_list);
+ ifconf_list=p;
+ }
+}
+