From: Vincent Bernat Date: Mon, 6 May 2013 19:31:42 +0000 (+0200) Subject: solaris: preliminary support X-Git-Tag: 0.7.3~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c3e340b6be8add4eb3a41882847a96e66793e82c;p=thirdparty%2Flldpd.git solaris: preliminary support Basic functionalities are present. However, the interface support is very poor. There is no way to detect bridges, VLAN and aggregates. There is no MAC/PHY support. There is no detection of wireless devices. The code to detect IP forwarding is here but does not work inside the chroot. --- diff --git a/configure.ac b/configure.ac index 570031bc..5689c9e4 100644 --- a/configure.ac +++ b/configure.ac @@ -84,6 +84,7 @@ AC_CACHE_SAVE # Checks for header files. AC_HEADER_RESOLV AC_CHECK_HEADERS([valgrind/valgrind.h]) +lldp_CHECK_STDINT AC_CACHE_SAVE diff --git a/m4/os.m4 b/m4/os.m4 index 28ab1686..584e9d56 100644 --- a/m4/os.m4 +++ b/m4/os.m4 @@ -23,6 +23,7 @@ AC_DEFUN([lldp_CHECK_OS], [ lldp_DEFINE_OS(openbsd*, OpenBSD, OPENBSD) lldp_DEFINE_OS(netbsd*, NetBSD, NETBSD) lldp_DEFINE_OS(darwin*, [Mac OS X], OSX) + lldp_DEFINE_OS(solaris*, Solaris, SOLARIS) if test x"$os" = x; then AC_MSG_RESULT(no) diff --git a/m4/stdint.m4 b/m4/stdint.m4 new file mode 100644 index 00000000..96558be0 --- /dev/null +++ b/m4/stdint.m4 @@ -0,0 +1,13 @@ +# +# lldp_CHECK_STDINT +# +AC_DEFUN([lldp_CHECK_STDINT], [ + AC_CHECK_TYPES([u_int32_t, uint32_t]) + if test "_$ac_cv_type_uint32_t" = _yes; then + if test "_$ac_cv_type_u_int32_t" = _no; then + AC_DEFINE(u_int8_t, uint8_t, [Compatibility with Linux u_int8_t]) + AC_DEFINE(u_int16_t, uint16_t, [Compatibility with Linux u_int16_t]) + AC_DEFINE(u_int32_t, uint32_t, [Compatibility with Linux u_int32_t]) + AC_DEFINE(u_int64_t, uint64_t, [Compatibility with Linux u_int64_t]) + fi + fi]) diff --git a/src/compat/fgetln.c b/src/compat/fgetln.c index 45e63f49..0490469b 100644 --- a/src/compat/fgetln.c +++ b/src/compat/fgetln.c @@ -27,7 +27,6 @@ #define _GNU_SOURCE #include -#include #include #include diff --git a/src/ctl.h b/src/ctl.h index 9d019bd7..9dc65e3f 100644 --- a/src/ctl.h +++ b/src/ctl.h @@ -20,6 +20,10 @@ #define LLDPD_CTL_SOCKET "/var/run/lldpd.socket" +#if HAVE_CONFIG_H +# include +#endif + #include #include "marshal.h" diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am index bcf79b58..86ea9039 100644 --- a/src/daemon/Makefile.am +++ b/src/daemon/Makefile.am @@ -24,38 +24,56 @@ liblldpd_la_LIBADD = \ if HOST_OS_LINUX liblldpd_la_SOURCES += \ + forward-linux.c \ interfaces-linux.c \ netlink.c \ dmi-linux.c endif if HOST_OS_DRAGONFLY liblldpd_la_SOURCES += \ + forward-bsd.c \ + interfaces-bpf.c \ interfaces-bsd.c \ dmi-dummy.c endif if HOST_OS_FREEBSD liblldpd_la_SOURCES += \ + forward-bsd.c \ + interfaces-bpf.c \ interfaces-bsd.c \ dmi-freebsd.c endif if HOST_OS_OPENBSD liblldpd_la_SOURCES += \ + interfaces-bpf.c \ + forward-bsd.c \ interfaces-bsd.c \ dmi-openbsd.c endif if HOST_OS_NETBSD liblldpd_la_SOURCES += \ + forward-bsd.c \ + interfaces-bpf.c \ interfaces-bsd.c \ dmi-dummy.c endif if HOST_OS_OSX liblldpd_la_SOURCES += \ + forward-bsd.c \ + interfaces-bpf.c \ interfaces-bsd.c \ dmi-osx.c liblldpd_la_LDFLAGS = -framework Foundation liblldpd_la_LDFLAGS += -framework CoreFoundation -framework IOKit liblldpd_la_LDFLAGS += -framework IOKit endif +if HOST_OS_SOLARIS +liblldpd_la_SOURCES += \ + forward-solaris.c \ + interfaces-bpf.c \ + interfaces-solaris.c \ + dmi-dummy.c +endif # Add SNMP support if needed if USE_SNMP diff --git a/src/daemon/forward-bsd.c b/src/daemon/forward-bsd.c new file mode 100644 index 00000000..e22a45d5 --- /dev/null +++ b/src/daemon/forward-bsd.c @@ -0,0 +1,36 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2013 Vincent Bernat + * + * Permission to use, copy, modify, and/or 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 +#include + +int +interfaces_routing_enabled(struct lldpd *cfg) { + (void)cfg; + int n, mib[4] = { + CTL_NET, + PF_INET, + IPPROTO_IP, + IPCTL_FORWARDING + }; + size_t len = sizeof(int); + if (sysctl(mib, 4, &n, &len, NULL, 0) != -1) + return (n == 1); + return -1; +} diff --git a/src/daemon/forward-linux.c b/src/daemon/forward-linux.c new file mode 100644 index 00000000..c7d9f735 --- /dev/null +++ b/src/daemon/forward-linux.c @@ -0,0 +1,36 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2013 Vincent Bernat + * + * Permission to use, copy, modify, and/or 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 + +int +interfaces_routing_enabled(struct lldpd *cfg) { + (void)cfg; + int f; + char status; + int rc; + if ((f = priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) { + if (read(f, &status, 1) == 1) { + rc = (status == '1'); + } else rc = -1; + close(f); + return rc; + } + return -1; +} diff --git a/src/daemon/forward-solaris.c b/src/daemon/forward-solaris.c new file mode 100644 index 00000000..d2fca55e --- /dev/null +++ b/src/daemon/forward-solaris.c @@ -0,0 +1,53 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2013 Vincent Bernat + * + * Permission to use, copy, modify, and/or 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 +#include +#include +#include + +int +interfaces_routing_enabled(struct lldpd *cfg) { + int rc; + size_t iocsize = sizeof(mod_ioc_prop_t) + 1; + mod_ioc_prop_t *mip = calloc(1, iocsize); + if (mip == NULL) { + log_warn("interfaces", "unable to allocate memory for ioctl"); + return -1; + } + mip->mpr_version = MOD_PROP_VERSION; + mip->mpr_flags = MOD_PROP_ACTIVE; + mip->mpr_proto = MOD_PROTO_IPV4; + mip->mpr_valsize = iocsize + 1 - sizeof(mod_ioc_prop_t); + strlcpy(mip->mpr_name, "forwarding", sizeof(mip->mpr_name)); + struct strioctl ioc = { + .ic_cmd = SIOCGETPROP, + .ic_timout = 0, + .ic_len = iocsize, + .ic_dp = (char*)mip + }; + if (ioctl(cfg->g_sock, I_STR, &ioc) == -1) { + free(mip); + log_debug("interfaces", "unable to get value for IPv4 forwarding"); + return -1; + } + + rc = (*mip->mpr_val == '1'); + free(mip); + return rc; +} diff --git a/src/daemon/interfaces-bpf.c b/src/daemon/interfaces-bpf.c new file mode 100644 index 00000000..a03a11bc --- /dev/null +++ b/src/daemon/interfaces-bpf.c @@ -0,0 +1,117 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2013 Vincent Bernat + * + * Permission to use, copy, modify, and/or 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 +#include + +struct bpf_buffer { + size_t len; /* Total length of the buffer */ + char data[0]; /* Data */ +}; + +int +ifbpf_phys_init(struct lldpd *cfg, + struct lldpd_hardware *hardware) +{ + struct bpf_buffer *buffer = NULL; + int fd = -1; + + log_debug("interfaces", "initialize ethernet device %s", + hardware->h_ifname); + if ((fd = priv_iface_init(hardware->h_ifindex, hardware->h_ifname)) == -1) + return -1; + + /* Allocate receive buffer */ + hardware->h_data = buffer = + malloc(ETHER_MAX_LEN + sizeof(struct bpf_buffer)); + if (buffer == NULL) { + log_warn("interfaces", + "unable to allocate buffer space for BPF on %s", + hardware->h_ifname); + goto end; + } + buffer->len = ETHER_MAX_LEN; + + /* Setup multicast */ + interfaces_setup_multicast(cfg, hardware->h_ifname, 0); + + hardware->h_sendfd = fd; /* Send */ + + levent_hardware_add_fd(hardware, fd); /* Receive */ + log_debug("interfaces", "interface %s initialized (fd=%d)", hardware->h_ifname, + fd); + return 0; + +end: + if (fd >= 0) close(fd); + free(buffer); + hardware->h_data = NULL; + return -1; +} + +/* Ethernet send/receive through BPF */ +static int +ifbpf_eth_send(struct lldpd *cfg, struct lldpd_hardware *hardware, + char *buffer, size_t size) +{ + log_debug("interfaces", "send PDU to ethernet device %s (fd=%d)", + hardware->h_ifname, hardware->h_sendfd); + return write(hardware->h_sendfd, + buffer, size); +} + +static int +ifbpf_eth_recv(struct lldpd *cfg, + struct lldpd_hardware *hardware, + int fd, char *buffer, size_t size) +{ + struct bpf_buffer *bpfbuf = hardware->h_data; + struct bpf_hdr *bh; + log_debug("interfaces", "receive PDU from ethernet device %s", + hardware->h_ifname); + + /* We assume we have only receive one packet (unbuffered mode). Dunno if + * this is correct. */ + if (read(fd, bpfbuf->data, bpfbuf->len) == -1) { + log_warn("interfaces", "error while receiving frame on %s", + hardware->h_ifname); + hardware->h_rx_discarded_cnt++; + return -1; + } + bh = (struct bpf_hdr*)bpfbuf->data; + if (bh->bh_caplen < size) + size = bh->bh_caplen; + memcpy(buffer, bpfbuf->data + bh->bh_hdrlen, size); + + return size; +} + +static int +ifbpf_eth_close(struct lldpd *cfg, struct lldpd_hardware *hardware) +{ + log_debug("interfaces", "close ethernet device %s", + hardware->h_ifname); + interfaces_setup_multicast(cfg, hardware->h_ifname, 1); + return 0; +} + +struct lldpd_ops bpf_ops = { + .send = ifbpf_eth_send, + .recv = ifbpf_eth_recv, + .cleanup = ifbpf_eth_close, +}; diff --git a/src/daemon/interfaces-bsd.c b/src/daemon/interfaces-bsd.c index 9d1cb1a4..ee4e378d 100644 --- a/src/daemon/interfaces-bsd.c +++ b/src/daemon/interfaces-bsd.c @@ -580,103 +580,7 @@ ifbsd_macphy(struct lldpd *cfg, #endif } -struct bpf_buffer { - size_t len; /* Total length of the buffer */ - char data[0]; /* Data */ -}; - -static int -ifbsd_phys_init(struct lldpd *cfg, - struct lldpd_hardware *hardware) -{ - struct bpf_buffer *buffer = NULL; - int fd = -1; - - log_debug("interfaces", "initialize ethernet device %s", - hardware->h_ifname); - if ((fd = priv_iface_init(hardware->h_ifindex, hardware->h_ifname)) == -1) - return -1; - - /* Allocate receive buffer */ - hardware->h_data = buffer = - malloc(ETHER_MAX_LEN + sizeof(struct bpf_buffer)); - if (buffer == NULL) { - log_warn("interfaces", - "unable to allocate buffer space for BPF on %s", - hardware->h_ifname); - goto end; - } - buffer->len = ETHER_MAX_LEN; - - /* Setup multicast */ - interfaces_setup_multicast(cfg, hardware->h_ifname, 0); - - hardware->h_sendfd = fd; /* Send */ - - levent_hardware_add_fd(hardware, fd); /* Receive */ - log_debug("interfaces", "interface %s initialized (fd=%d)", hardware->h_ifname, - fd); - return 0; - -end: - if (fd >= 0) close(fd); - free(buffer); - hardware->h_data = NULL; - return -1; -} - -/* Ethernet send/receive through BPF */ -static int -ifbsd_eth_send(struct lldpd *cfg, struct lldpd_hardware *hardware, - char *buffer, size_t size) -{ - log_debug("interfaces", "send PDU to ethernet device %s (fd=%d)", - hardware->h_ifname, hardware->h_sendfd); - return write(hardware->h_sendfd, - buffer, size); -} - -static int -ifbsd_eth_recv(struct lldpd *cfg, - struct lldpd_hardware *hardware, - int fd, char *buffer, size_t size) -{ - struct bpf_buffer *bpfbuf = hardware->h_data; - struct bpf_hdr *bh; - log_debug("interfaces", "receive PDU from ethernet device %s", - hardware->h_ifname); - - /* We assume we have only receive one packet (unbuffered mode). Dunno if - * this is correct. */ - if (read(fd, bpfbuf->data, bpfbuf->len) == -1) { - log_warn("interfaces", "error while receiving frame on %s", - hardware->h_ifname); - hardware->h_rx_discarded_cnt++; - return -1; - } - bh = (struct bpf_hdr*)bpfbuf->data; - if (bh->bh_caplen < size) - size = bh->bh_caplen; - memcpy(buffer, bpfbuf->data + bh->bh_hdrlen, size); - - return size; -} - -static int -ifbsd_eth_close(struct lldpd *cfg, struct lldpd_hardware *hardware) -{ - log_debug("interfaces", "close ethernet device %s", - hardware->h_ifname); - interfaces_setup_multicast(cfg, hardware->h_ifname, 1); - return 0; -} - -static struct lldpd_ops eth_ops = { - .send = ifbsd_eth_send, - .recv = ifbsd_eth_recv, - .cleanup = ifbsd_eth_close, -}; - +extern struct lldpd_ops bpf_ops; void interfaces_update(struct lldpd *cfg) { @@ -714,7 +618,7 @@ interfaces_update(struct lldpd *cfg) interfaces_helper_whitelist(cfg, interfaces); interfaces_helper_physical(cfg, interfaces, - ð_ops, ifbsd_phys_init); + &bpf_ops, ifbpf_phys_init); #ifdef ENABLE_DOT1 interfaces_helper_vlan(cfg, interfaces); #endif diff --git a/src/daemon/interfaces-solaris.c b/src/daemon/interfaces-solaris.c new file mode 100644 index 00000000..304f71c9 --- /dev/null +++ b/src/daemon/interfaces-solaris.c @@ -0,0 +1,178 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2013 Vincent Bernat + * + * Permission to use, copy, modify, and/or 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 +#include +#include + +/* Solaris comes with libdladm which seems to be handy to get all the necessary + * information. Unfortunately, this library needs a special device file and a + * Unix socket to a daemon. This is a bit difficult to use it in a + * privilege-separated daemon. Therefore, we keep using ioctl(). This should + * also improve compatibility with older versions of Solaris. + */ + +static void +ifsolaris_extract(struct lldpd *cfg, + struct interfaces_device_list *interfaces, + struct interfaces_address_list *addresses, + struct lifreq *lifr) { + int flags = 0; + int index = 0; + struct interfaces_address *address = NULL; + struct interfaces_device *device = NULL; + + sa_family_t lifr_af = lifr->lifr_addr.ss_family; + struct lifreq lifrl = { .lifr_name = {} }; + strlcpy(lifrl.lifr_name, lifr->lifr_name, sizeof(lifrl.lifr_name)); + + /* Flags */ + if (ioctl(cfg->g_sock, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) { + log_warn("interfaces", "unable to get flags for %s", + lifrl.lifr_name); + return; + } + flags = lifrl.lifr_flags; + if (!((flags & IFF_UP) && (flags & IFF_RUNNING))) { + log_debug("interfaces", + "skip %s: down", lifrl.lifr_name); + return; + } + + /* Index */ + if (ioctl(cfg->g_sock, SIOCGLIFINDEX, (caddr_t)&lifrl) < 0) { + log_warn("interfaces", "unable to get index for %s", + lifrl.lifr_name); + return; + } + index = lifrl.lifr_index; + + /* Record the address */ + if ((address = malloc(sizeof(struct interfaces_address))) == NULL) { + log_warn("interfaces", + "not enough memory for a new IP address on %s", + lifrl.lifr_name); + return; + } + address->flags = flags; + address->index = index; + memcpy(&address->address, + &lifr->lifr_addr, + (lifr_af == AF_INET)? + sizeof(struct sockaddr_in): + sizeof(struct sockaddr_in6)); + TAILQ_INSERT_TAIL(addresses, address, next); + + /* Hardware address */ + if (ioctl(cfg->g_sock, SIOCGLIFHWADDR, (caddr_t)&lifrl) < 0) { + log_debug("interfaces", "unable to get hardware address for %s", + lifrl.lifr_name); + return; + } + struct sockaddr_dl *saddrdl = (struct sockaddr_dl*)&lifrl.lifr_addr; + if (saddrdl->sdl_type != 4) { + log_debug("interfaces", "skip %s: not an ethernet device (%d)", + lifrl.lifr_name, saddrdl->sdl_type); + return; + } + + /* Handle the interface */ + if ((device = calloc(1, sizeof(struct interfaces_device))) == NULL) { + log_warn("interfaces", "unable to allocate memory for %s", + lifrl.lifr_name); + return; + } + + device->name = strdup(lifrl.lifr_name); + device->flags = flags; + device->index = index; + device->type = IFACE_PHYSICAL_T; + device->address = malloc(ETHER_ADDR_LEN); + if (device->address) + memcpy(device->address, LLADDR(saddrdl), ETHER_ADDR_LEN); + + /* MTU */ + if (ioctl(cfg->g_sock, SIOCGLIFMTU, (caddr_t)&lifrl) < 0) { + log_debug("interfaces", "unable to get MTU for %s", + lifrl.lifr_name); + } else device->mtu = lifrl.lifr_mtu; + + TAILQ_INSERT_TAIL(interfaces, device, next); +} + +extern struct lldpd_ops bpf_ops; +void +interfaces_update(struct lldpd *cfg) { + caddr_t buffer = NULL; + struct interfaces_device_list *interfaces; + struct interfaces_address_list *addresses; + interfaces = malloc(sizeof(struct interfaces_device_list)); + addresses = malloc(sizeof(struct interfaces_address_list)); + if (interfaces == NULL || addresses == NULL) { + log_warnx("interfaces", "unable to allocate memory"); + goto end; + } + TAILQ_INIT(interfaces); + TAILQ_INIT(addresses); + + struct lifnum lifn = { + .lifn_family = AF_UNSPEC, + .lifn_flags = LIFC_ENABLED + }; + if (ioctl(cfg->g_sock, SIOCGLIFNUM, &lifn) < 0) { + log_warn("interfaces", "unable to get the number of interfaces"); + goto end; + } + + size_t bufsize = lifn.lifn_count * sizeof(struct lifreq); + if ((buffer = malloc(bufsize)) == NULL) { + log_warn("interfaces", "unable to allocate buffer to get interfaces"); + goto end; + } + + struct lifconf lifc = { + .lifc_family = AF_UNSPEC, + .lifc_flags = LIFC_ENABLED, + .lifc_len = bufsize, + .lifc_buf = buffer + }; + if (ioctl(cfg->g_sock, SIOCGLIFCONF, (char *)&lifc) < 0) { + log_warn("interfaces", "unable to get the network interfaces"); + goto end; + } + + int num = lifc.lifc_len / sizeof (struct lifreq); + if (num > lifn.lifn_count) num = lifn.lifn_count; + log_debug("interfaces", "got %d interfaces", num); + + struct lifreq *lifrp = (struct lifreq *)buffer; + for (int n = 0; n < num; n++, lifrp++) + ifsolaris_extract(cfg, interfaces, addresses, lifrp); + + interfaces_helper_whitelist(cfg, interfaces); + interfaces_helper_physical(cfg, interfaces, + &bpf_ops, ifbpf_phys_init); + interfaces_helper_mgmt(cfg, addresses); + interfaces_helper_chassis(cfg, interfaces); + +end: + free(buffer); + interfaces_free_devices(interfaces); + interfaces_free_addresses(addresses); +} diff --git a/src/daemon/interfaces.c b/src/daemon/interfaces.c index 2392b86a..3f80c12d 100644 --- a/src/daemon/interfaces.c +++ b/src/daemon/interfaces.c @@ -360,8 +360,11 @@ interfaces_helper_chassis(struct lldpd *cfg, #ifndef IN_IS_ADDR_LOOPBACK #define IN_IS_ADDR_LOOPBACK(a) ((a)->s_addr == htonl(INADDR_LOOPBACK)) #endif +#ifndef IN_IS_ADDR_ANY +#define IN_IS_ADDR_ANY(a) ((a)->s_addr == htonl(INADDR_ANY)) +#endif #ifndef IN_IS_ADDR_GLOBAL -#define IN_IS_ADDR_GLOBAL(a) (!IN_IS_ADDR_LOOPBACK(a)) +#define IN_IS_ADDR_GLOBAL(a) (!IN_IS_ADDR_LOOPBACK(a) && !IN_IS_ADDR_ANY(a)) #endif #ifndef IN6_IS_ADDR_GLOBAL #define IN6_IS_ADDR_GLOBAL(a) \ diff --git a/src/daemon/lldpd.c b/src/daemon/lldpd.c index c7b8ecf1..17aa30d0 100644 --- a/src/daemon/lldpd.c +++ b/src/daemon/lldpd.c @@ -37,14 +37,6 @@ #include #include #include -#if defined HOST_OS_FREEBSD || \ - defined HOST_OS_DRAGONFLY || \ - defined HOST_OS_OPENBSD || \ - defined HOST_OS_NETBSD || \ - defined HOST_OS_OSX -# include -# include -#endif static void usage(void); @@ -877,32 +869,14 @@ lldpd_med(struct lldpd_chassis *chassis) #endif static int -lldpd_forwarding_enabled(void) +lldpd_routing_enabled(struct lldpd *cfg) { - int rc = 0; -#if defined HOST_OS_LINUX - int f; - char status; - if ((f = priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) { - if ((read(f, &status, 1) == 1) && (status == '1')) - rc = 1; - close(f); + int routing; + if ((routing = interfaces_routing_enabled(cfg)) == -1) { + log_debug("localchassis", "unable to check if routing is enabled"); + return 0; } -#elif defined HOST_OS_FREEBSD || defined HOST_OS_OPENBSD || defined HOST_OS_NETBSD || defined HOST_OS_OSX || defined HOST_OS_DRAGONFLY - int n, mib[4] = { - CTL_NET, - PF_INET, - IPPROTO_IP, - IPCTL_FORWARDING - }; - size_t len = sizeof(int); - if (sysctl(mib, 4, &n, &len, NULL, 0) != -1) - rc = (n == 1); -#else -#error Unsupported OS -#endif - else log_debug("localchassis", "unable to check if forwarding is enabled"); - return rc; + return routing; } static void @@ -915,7 +889,7 @@ lldpd_update_localchassis(struct lldpd *cfg) assert(LOCAL_CHASSIS(cfg) != NULL); /* Set system name and description */ - if (uname(&un) != 0) + if (uname(&un) < 0) fatal("localchassis", "failed to get system information"); if ((hp = priv_gethostbyname()) == NULL) fatal("localchassis", "failed to get system name"); @@ -944,9 +918,9 @@ lldpd_update_localchassis(struct lldpd *cfg) } } - /* Check forwarding */ - if (lldpd_forwarding_enabled()) { - log_debug("localchassis", "forwarding is enabled, enable router capability"); + /* Check routing */ + if (lldpd_routing_enabled(cfg)) { + log_debug("localchassis", "routing is enabled, enable router capability"); LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_ROUTER; } else LOCAL_CHASSIS(cfg)->c_cap_enabled &= ~LLDP_CAP_ROUTER; diff --git a/src/daemon/lldpd.h b/src/daemon/lldpd.h index 8e436ed3..2afb3b87 100644 --- a/src/daemon/lldpd.h +++ b/src/daemon/lldpd.h @@ -341,6 +341,7 @@ void interfaces_helper_vlan(struct lldpd *, #endif void interfaces_setup_multicast(struct lldpd *, const char *, int); +int interfaces_routing_enabled(struct lldpd *); #ifdef HOST_OS_LINUX /* netlink.c */ @@ -349,4 +350,8 @@ struct interfaces_address_list *netlink_get_addresses(void); int netlink_subscribe_changes(void); #endif +#ifndef HOST_OS_LINUX +int ifbpf_phys_init(struct lldpd *, struct lldpd_hardware *); +#endif + #endif /* _LLDPD_H */ diff --git a/src/daemon/priv.c b/src/daemon/priv.c index fc3e5a56..4737077a 100644 --- a/src/daemon/priv.c +++ b/src/daemon/priv.c @@ -44,12 +44,16 @@ HOST_OS_DRAGONFLY || \ HOST_OS_NETBSD || \ HOST_OS_OPENBSD || \ - HOST_OS_OSX + HOST_OS_OSX || \ + HOST_OS_SOLARIS # include #endif #if defined HOST_OS_FREEBSD || HOST_OS_OSX || HOST_OS_DRAGONFLY # include #endif +#if defined HOST_OS_SOLARIS +# include +#endif #include /* Use resolv.h */ @@ -237,7 +241,7 @@ asroot_gethostbyname() struct utsname un; struct hostent *hp; int len; - if (uname(&un) != 0) + if (uname(&un) < 0) fatal("privsep", "failed to get system information"); if ((hp = gethostbyname(un.nodename)) == NULL) { log_info("privsep", "unable to get system name"); @@ -408,21 +412,26 @@ asroot_iface_init() defined HOST_OS_DRAGONFLY || \ defined HOST_OS_OPENBSD || \ defined HOST_OS_NETBSD || \ - defined HOST_OS_OSX - int n = 0; + defined HOST_OS_OSX || \ + defined HOST_OS_SOLARIS int enable, required; - char dev[20]; struct bpf_insn filter[] = { LLDPD_FILTER_F }; - struct ifreq ifr = {}; + struct ifreq ifr = { .ifr_name = {} }; struct bpf_program fprog = { .bf_insns = filter, .bf_len = sizeof(filter)/sizeof(struct bpf_insn) }; +#ifndef HOST_OS_SOLARIS + int n = 0; + char dev[20]; do { snprintf(dev, sizeof(dev), "/dev/bpf%d", n++); fd = open(dev, O_RDWR); } while (fd < 0 && errno == EBUSY); +#else + fd = open("/dev/bpf", O_RDWR); +#endif if (fd < 0) { rc = errno; log_warn("privsep", "unable to find a free BPF"); @@ -526,7 +535,7 @@ static void asroot_iface_multicast() { int add, rc = 0; - struct ifreq ifr = {}; + struct ifreq ifr = { .ifr_name = {} }; must_read(remote, ifr.ifr_name, IFNAMSIZ); #if defined HOST_OS_LINUX must_read(remote, ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN); @@ -540,9 +549,11 @@ asroot_iface_multicast() dlp->sdl_alen = ETHER_ADDR_LEN; dlp->sdl_slen = 0; must_read(remote, LLADDR(dlp), ETHER_ADDR_LEN); -#elif defined HOST_OS_OPENBSD || defined HOST_OS_NETBSD +#elif defined HOST_OS_OPENBSD || defined HOST_OS_NETBSD || defined HOST_OS_SOLARIS struct sockaddr *sap = (struct sockaddr *)&ifr.ifr_addr; +#if ! defined HOST_OS_SOLARIS sap->sa_len = sizeof(struct sockaddr); +#endif sap->sa_family = AF_UNSPEC; must_read(remote, sap->sa_data, ETHER_ADDR_LEN); #else diff --git a/src/daemon/privsep_fdpass.c b/src/daemon/privsep_fdpass.c index 0e09f085..cb6bc9ea 100644 --- a/src/daemon/privsep_fdpass.c +++ b/src/daemon/privsep_fdpass.c @@ -31,6 +31,10 @@ * POSSIBILITY OF SUCH DAMAGE. */ +/* The following are needed by Solaris. The first to get CMSG_* and the second + * to keep IFNAMSIZ */ +#define _XOPEN_SOURCE 600 +#define __EXTENSIONS__ #include "lldpd.h" #include