# Checks for library functions.
AC_REPLACE_FUNCS([strlcpy])
+AC_REPLACE_FUNCS([getifaddrs])
AC_PROG_GCC_TRADITIONAL
#if !HAVE_DECL_ETHERTYPE_VLAN
#define ETHERTYPE_VLAN 0x8100
#endif
+
+#if !HAVE_GETIFADDRS
+struct ifaddrs {
+ struct ifaddrs *ifa_next; /* Next item in list */
+ char *ifa_name; /* Name of interface */
+ unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */
+ struct sockaddr *ifa_addr; /* Address of interface */
+ struct sockaddr *ifa_netmask; /* Netmask of interface */
+ /* At most one of the following two is valid. If the IFF_BROADCAST
+ bit is set in `ifa_flags', then `ifa_broadaddr' is valid. If the
+ IFF_POINTOPOINT bit is set, then `ifa_dstaddr' is valid.
+ It is never the case that both these bits are set at once. */
+ union {
+ struct sockaddr *ifu_broadaddr;
+ /* Broadcast address of interface */
+ struct sockaddr *ifu_dstaddr;
+ /* Point-to-point destination address */
+ } ifa_ifu;
+# ifndef ifa_broadaddr
+# define ifa_broadaddr ifa_ifu.ifu_broadaddr
+# endif
+# ifndef ifa_dstaddr
+# define ifa_dstaddr ifa_ifu.ifu_dstaddr
+# endif
+ void *ifa_data; /* Address-specific data */
+};
+
+int getifaddrs(struct ifaddrs **ifap);
+void freeifaddrs(struct ifaddrs *ifa);
+#endif
+
+#if !HAVE_STRLCPY
+size_t strlcpy(char *, const char *, size_t);
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "lldpd.h"
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+/* This implementation uses ioctl and not netlink. This should work with many
+ * earlier Linux. However, because we use an AF_INET socket, we only get IPv4
+ * addresses. Since lldpd only handles IPv4 for now, this is not a
+ * problem. Moreover, IPv6 + libc not having getifaddrs should be pretty
+ * rare. */
+int
+getifaddrs(struct ifaddrs **ifap)
+{
+ int sock, n, i;
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ char buffer[8192];
+ struct ifaddrs *ifa = NULL, *lifa = NULL;
+
+ *ifap = NULL;
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ return -1;
+
+ ifc.ifc_len = sizeof(buffer);
+ ifc.ifc_buf = buffer;
+ if (ioctl(sock, SIOCGIFCONF, &ifc) == -1)
+ goto fault;
+ ifr = ifc.ifc_req;
+ n = ifc.ifc_len / sizeof(struct ifreq);
+ for (i = 0; i < n; i++) {
+ if (ioctl(sock, SIOCGIFFLAGS, &ifr[i]) == -1)
+ goto fault;
+ ifa = (struct ifaddrs*)calloc(1, sizeof(struct ifaddrs));
+ if ((ifa->ifa_name = strdup(ifr[i].ifr_name)) == NULL)
+ goto fault;
+ ifa->ifa_flags = ifr[i].ifr_flags;
+ /* Address */
+ if (ioctl(sock, SIOCGIFADDR, &ifr[i]) != -1) {
+ if ((ifa->ifa_addr =
+ (struct sockaddr *)malloc(
+ sizeof(struct sockaddr_storage))) == NULL)
+ goto fault;
+ memcpy(ifa->ifa_addr, &ifr[i].ifr_addr,
+ sizeof(struct sockaddr_storage));
+ }
+ /* Netmask */
+ if (ioctl(sock, SIOCGIFNETMASK, &ifr[i]) != -1) {
+ if ((ifa->ifa_netmask =
+ (struct sockaddr *)malloc(
+ sizeof(struct sockaddr_storage))) == NULL)
+ goto fault;
+ memcpy(ifa->ifa_netmask, &ifr[i].ifr_addr,
+ sizeof(struct sockaddr_storage));
+ }
+ /* Broadcast or point to point */
+ if (ifr[i].ifr_flags & IFF_BROADCAST) {
+ if (ioctl(sock, SIOCGIFBRDADDR, &ifr[i]) != -1) {
+ if ((ifa->ifa_ifu.ifu_broadaddr =
+ (struct sockaddr *)malloc(
+ sizeof(struct sockaddr_storage))) == NULL)
+ goto fault;
+ memcpy(ifa->ifa_ifu.ifu_broadaddr,
+ &ifr[i].ifr_addr,
+ sizeof(struct sockaddr_storage));
+ }
+ } else if (ifr[i].ifr_flags & IFF_POINTOPOINT) {
+ if (ioctl(sock, SIOCGIFDSTADDR, &ifr[i]) != -1) {
+ if ((ifa->ifa_ifu.ifu_dstaddr =
+ (struct sockaddr *)malloc(
+ sizeof(struct sockaddr_storage))) == NULL)
+ goto fault;
+ memcpy(ifa->ifa_ifu.ifu_dstaddr,
+ &ifr[i].ifr_addr,
+ sizeof(struct sockaddr_storage));
+ }
+ }
+ /* Link them together */
+ if (lifa)
+ lifa->ifa_next = ifa;
+ else
+ *ifap = ifa;
+ lifa = ifa;
+ ifa = NULL;
+ }
+ return 0;
+fault:
+ freeifaddrs(ifa); /* It is not linked at anything if not NULL */
+ freeifaddrs(*ifap);
+ close(sock);
+ return -1;
+}
+
+void
+freeifaddrs(struct ifaddrs *ifa)
+{
+ struct ifaddrs *pifa;
+ while (ifa) {
+ pifa = ifa;
+ ifa = ifa->ifa_next;
+ free(pifa->ifa_name);
+ free(pifa->ifa_netmask);
+ free(pifa->ifa_addr);
+ if (pifa->ifa_flags & IFF_BROADCAST)
+ free(pifa->ifa_ifu.ifu_broadaddr);
+ else if (pifa->ifa_flags & IFF_POINTOPOINT)
+ free(pifa->ifa_ifu.ifu_dstaddr);
+ free(pifa->ifa_data);
+ free(pifa);
+ }
+}
#include <fcntl.h>
#include <fnmatch.h>
#include <arpa/inet.h>
-#include <ifaddrs.h>
#include <net/if_arp.h>
#include <linux/if_vlan.h>
#include <linux/if_bonding.h>
#include <net/if.h>
#else
#include <arpa/inet.h>
+#include <sys/types.h>
#include <linux/if.h>
#endif
+#if HAVE_GETIFADDRS
#include <ifaddrs.h>
+#endif
#include <net/ethernet.h>
#include <netinet/in.h>
#include <linux/ethtool.h>
/* agent_priv.c */
void agent_priv_register_domain();
-/* strlcpy.c */
-size_t strlcpy(char *, const char *, size_t);
-
/* client.c */
struct client_handle {
enum hmsg_type type;
-TESTS = check_pack check_lldp check_cdp check_sonmp check_edp
+TESTS = check_pack check_lldp check_cdp check_sonmp check_edp check_ifaddrs
if HAVE_CHECK
check_edp_CFLAGS = @CHECK_CFLAGS@
check_edp_LDADD = $(top_builddir)/src/liblldpd.la @CHECK_LIBS@
+check_ifaddrs_SOURCES = check_ifaddrs.c \
+ $(top_builddir)/src/lldpd.h \
+ $(top_builddir)/src/getifaddrs.c
+check_ifaddrs_CFLAGS = @CHECK_CFLAGS@
+check_ifaddrs_LDADD = $(top_builddir)/src/liblldpd.la @CHECK_LIBS@
+
if USE_SNMP
check_pack_LDADD += @NETSNMP_LIB@
check_lldp_LDADD += @NETSNMP_LIB@
check_cdp_LDADD += @NETSNMP_LIB@
check_sonmp_LDADD += @NETSNMP_LIB@
check_edp_LDADD += @NETSNMP_LIB@
+check_ifaddrs_LDADD += @NETSNMP_LIB@
endif
endif
-MOSTLYCLEANFILES = lldp_send_*.pcap cdp_send_*.pcap sonmp_send_*.pcap edp_send_*.pcap
+MOSTLYCLEANFILES = lldp_send_*.pcap cdp_send_*.pcap sonmp_send_*.pcap edp_send_*.pcap \
+ ifdump.txt
--- /dev/null
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <check.h>
+#include "../src/lldpd.h"
+
+#define DUMP "ifdump.txt"
+
+/* This is not a real test. It should dump into a file the list of interfaces */
+
+static const char *
+addr_string (struct sockaddr *sa) {
+ static char buf[64];
+ if (sa == NULL)
+ return "<0000>";
+ switch (sa->sa_family) {
+ case AF_INET:
+ return inet_ntop(AF_INET,
+ &((struct sockaddr_in *)sa)->sin_addr,
+ buf, sizeof(buf));
+ case AF_INET6:
+ return "<ipv6>";
+ case AF_UNSPEC:
+ return "<---->";
+ case AF_PACKET:
+ return "<pckt>";
+ default:
+ snprintf(buf, 64, "<%4d>", sa->sa_family);
+ }
+ return buf;
+}
+
+START_TEST (test_ifaddrs)
+{
+ struct ifaddrs *ifap, *ifa;
+ FILE* dump;
+
+ if (getifaddrs(&ifap) < 0) {
+ fail("unable to get interface list");
+ return;
+ }
+ dump = fopen(DUMP, "w+");
+ if (dump == NULL) {
+ fail("unable to open dump file " DUMP);
+ return;
+ }
+ fprintf(dump,
+ "Name Flags Address Netmask Broadcast/Destination\n");
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ fprintf(dump, "%-15s%#.4x ",
+ ifa->ifa_name, ifa->ifa_flags);
+ fprintf(dump, "%-15s ",
+ addr_string(ifa->ifa_addr));
+ fprintf(dump, "%-15s ",
+ addr_string(ifa->ifa_netmask));
+ fprintf(dump, "%-15s\n",
+ addr_string(ifa->ifa_broadaddr));
+ }
+ fclose(dump);
+}
+END_TEST
+
+Suite *
+ifaddrs_suite(void)
+{
+ Suite *s = suite_create("getifaddrs");
+
+ /* Single objects packing/unpacking */
+ TCase *tc_core = tcase_create("getifaddrs");
+ tcase_add_test(tc_core, test_ifaddrs);
+ suite_add_tcase(s, tc_core);
+
+ return s;
+}
+
+int
+main()
+{
+ int number_failed;
+ Suite *s = ifaddrs_suite ();
+ SRunner *sr = srunner_create (s);
+ srunner_run_all (sr, CK_ENV);
+ number_failed = srunner_ntests_failed (sr);
+ srunner_free (sr);
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}