The ports collection's sysutils/ipmitool is 1.8.12, while the current upstream is 1.8.14. Since 1.8.13 introduced some features I'd like to have, I've been working on bringing the port up-to-date. [The port maintainer is aware of this, they don't have the time to do the work and offered the port to me.]
I've hit a minor stumbling block: 1.8.14 added IPv6 support, but it doesn't compile / run on FreeBSD. The stumbling block is a missing declaration of s6_addr16. That definition is found in /usr/include/netinet6/in6.h, but is only active when compiling the kernel. Patching ipmitool's src/plugins/ipmi_intf.c to include a copy of the definition lets the package compile, but any attempt to use an IPv6 address fails with the error "Could not open socket!". The error is caused by the same piece of code that uses s6_addr16 - the cause is that when ipmitool iterates through the list of available IPv6 addresses, it sees that they are all of scope 0 (which is reserved). The code then looks in the s6_addr16 data structure to see if it can fetch the scope from there, also gets an answer of 0, and gives up without even trying to open the socket.
The particular code is:
I was wondering if anyone with more IPv6 experience than I possess can look over this code and see what is going wrong. I suspect that either the scope should be obtained near the top of this code sample, while iterating through the list of interface addresses, or it is peeking in the wrong place.
To build 1.8.14, simply edit the port Makefile to change the PORTVERSION from 1.8.12 to 1.8.14 and remove the PORTREVISION line, remove files/patch-configure, and install the attached patch-ipmi_intf.c in files/. Then do:
Here is a sample run showing the problem (fictitious IPv6 address). Note that any username / password and target IP address will work - the code never even gets to the point where it tries a connect:
Here is the patch-ipmi_intf.c file. For some reason the forum disallows all attachments with "The extension anything is not allowed."
I've hit a minor stumbling block: 1.8.14 added IPv6 support, but it doesn't compile / run on FreeBSD. The stumbling block is a missing declaration of s6_addr16. That definition is found in /usr/include/netinet6/in6.h, but is only active when compiling the kernel. Patching ipmitool's src/plugins/ipmi_intf.c to include a copy of the definition lets the package compile, but any attempt to use an IPv6 address fails with the error "Could not open socket!". The error is caused by the same piece of code that uses s6_addr16 - the cause is that when ipmitool iterates through the list of available IPv6 addresses, it sees that they are all of scope 0 (which is reserved). The code then looks in the s6_addr16 data structure to see if it can fetch the scope from there, also gets an answer of 0, and gives up without even trying to open the socket.
The particular code is:
Code:
} else {
/* No scope specified, try to get this from the list of interfaces */
struct ifaddrs *ifaddrs = NULL;
struct ifaddrs *ifa = NULL;
if (getifaddrs(&ifaddrs) < 0) {
lprintf(LOG_ERR, "Interface address lookup for %s failed",
session->hostname);
break;
}
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL) {
continue;
}
if (ifa->ifa_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *)ifa->ifa_addr;
/* Skip unwanted addresses */
if (IN6_IS_ADDR_MULTICAST(&tmp6->sin6_addr)) {
continue;
}
if (IN6_IS_ADDR_LOOPBACK(&tmp6->sin6_addr)) {
continue;
}
len = sizeof(struct sockaddr_in6);
if ( getnameinfo((struct sockaddr *)tmp6, len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0) {
lprintf(LOG_DEBUG, "Testing %s interface address: %s scope=%d",
ifa->ifa_name != NULL ? ifa->ifa_name : "???",
hbuf,
tmp6->sin6_scope_id);
}
if (tmp6->sin6_scope_id != 0) {
addr6->sin6_scope_id = tmp6->sin6_scope_id;
} else {
/*
* No scope information in interface address information
* On some OS'es, getifaddrs() is returning out the 'kernel' representation
* of scoped addresses which stores the scope in the 3rd and 4th
* byte. See also this page:
* http://www.freebsd.org/doc/en/books/developers-handbook/ipv6.html
*/
if (IN6_IS_ADDR_LINKLOCAL(&tmp6->sin6_addr)
&& (tmp6->sin6_addr.s6_addr16[1] != 0)) {
addr6->sin6_scope_id = ntohs(tmp6->sin6_addr.s6_addr16[1]);
}
}
/* OK, now try to connect with the scope id from this interface address */
if (addr6->sin6_scope_id != 0) {
if (connect(intf->fd, rp->ai_addr, rp->ai_addrlen) != -1) {
memcpy(&session->addr, rp->ai_addr, rp->ai_addrlen);
session->addrlen = rp->ai_addrlen;
session->ai_family = rp->ai_family;
lprintf(LOG_DEBUG, "Successful connected on %s interface with scope id %d", ifa->ifa_name, tmp6->sin6_scope_id);
break; /* Success */
}
}
}
}
To build 1.8.14, simply edit the port Makefile to change the PORTVERSION from 1.8.12 to 1.8.14 and remove the PORTREVISION line, remove files/patch-configure, and install the attached patch-ipmi_intf.c in files/. Then do:
make makesum; makeHere is a sample run showing the problem (fictitious IPv6 address). Note that any username / password and target IP address will work - the code never even gets to the point where it tries a connect:
Code:
(1:16) hostname:/usr/ports/sysutils/ipmitool# work/ipmitool-1.8.14/src/ipmitool -vv -I lan -U username -P password -H 2001:558:1:2::60 sensor
Testing ix0 interface address: 2001:558:1:2::40 scope=0
Could not open socket!
Code:
*** src/plugins/ipmi_intf.c.bak Thu Apr 17 15:13:42 2014
--- src/plugins/ipmi_intf.c Sun May 11 01:09:38 2014
***************
*** 41,46 ****
--- 41,47 ----
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
+ #define s6_addr16 __u6_addr.__u6_addr16
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <unistd.h>