mirror of
https://github.com/ipmitool/ipmitool.git
synced 2025-05-10 18:47:22 +00:00
PA: 83 - Revised IPv6 patch
Author: Holger Liebig Deduplicated socket connection shared among lan and lanplus. Allows IPv6 address and tries to pick correct scope ID.
This commit is contained in:
parent
d3ca7cb090
commit
f6cabfb089
@ -29,7 +29,7 @@ AC_C_BIGENDIAN
|
||||
AC_FUNC_MALLOC
|
||||
AC_FUNC_SELECT_ARGTYPES
|
||||
AC_FUNC_STRTOD
|
||||
AC_CHECK_FUNCS([alarm gethostbyname socket select])
|
||||
AC_CHECK_FUNCS([alarm gethostbyname getaddrinfo getifaddrs socket select])
|
||||
AC_CHECK_FUNCS([memmove memset strchr strdup strerror])
|
||||
AC_CHECK_FUNCS([getpassphrase])
|
||||
|
||||
@ -39,6 +39,8 @@ AM_PROG_LIBTOOL
|
||||
LIBTOOL="$LIBTOOL --silent"
|
||||
|
||||
AC_SEARCH_LIBS([gethostbyname], [nsl])
|
||||
AC_SEARCH_LIBS([getaddrinfo], [nsl])
|
||||
AC_SEARCH_LIBS([getifaddrs], [nsl])
|
||||
AC_SEARCH_LIBS([socket], [socket], [],
|
||||
[AC_CHECK_LIB([nsl], [socket],
|
||||
[LIBS="$LIBS -lsocket -lnsl"], [], [-lsocket])])
|
||||
|
@ -89,8 +89,9 @@ struct ipmi_session {
|
||||
uint32_t out_seq;
|
||||
uint32_t timeout;
|
||||
|
||||
struct sockaddr_in addr;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
int ai_family; /* Protocol family for socket. */
|
||||
|
||||
/*
|
||||
* This struct holds state data specific to IPMI v2 / RMCP+ sessions
|
||||
@ -211,4 +212,7 @@ void ipmi_intf_session_set_timeout(struct ipmi_intf * intf, uint32_t timeout);
|
||||
void ipmi_intf_session_set_retry(struct ipmi_intf * intf, int retry);
|
||||
void ipmi_cleanup(struct ipmi_intf * intf);
|
||||
|
||||
#if defined(IPMI_INTF_LAN) || defined (IPMI_INTF_LANPLUS)
|
||||
int ipmi_intf_socket_connect(struct ipmi_intf * intf);
|
||||
#endif
|
||||
#endif /* IPMI_INTF_H */
|
||||
|
@ -481,44 +481,14 @@ ipmi_dcmi_prnt_oobDiscover(struct ipmi_intf * intf)
|
||||
intf->abort = 1;
|
||||
intf->session->sol_data.sequence_number = 1;
|
||||
|
||||
/* open port to BMC */
|
||||
memset(&s->addr, 0, sizeof(struct sockaddr_in));
|
||||
s->addr.sin_family = AF_INET;
|
||||
s->addr.sin_port = htons(s->port);
|
||||
|
||||
rc = inet_pton(AF_INET, (const char *)s->hostname, &s->addr.sin_addr);
|
||||
if (rc <= 0) {
|
||||
struct hostent *host = gethostbyname((const char *)s->hostname);
|
||||
if (host == NULL) {
|
||||
lprintf(LOG_ERR, "Address lookup for %s failed",
|
||||
s->hostname);
|
||||
return -1;
|
||||
}
|
||||
if (host->h_addrtype != AF_INET) {
|
||||
lprintf(LOG_ERR,
|
||||
"Address lookup for %s failed. Got %s, expected IPv4 address.",
|
||||
s->hostname,
|
||||
(host->h_addrtype == AF_INET6) ? "IPv6" : "Unknown");
|
||||
return (-1);
|
||||
}
|
||||
s->addr.sin_family = host->h_addrtype;
|
||||
memcpy(&s->addr.sin_addr, host->h_addr, host->h_length);
|
||||
}
|
||||
|
||||
lprintf(LOG_DEBUG, "IPMI LAN host %s port %d",
|
||||
s->hostname, ntohs(s->addr.sin_port));
|
||||
|
||||
intf->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (intf->fd < 0) {
|
||||
lperror(LOG_ERR, "Socket failed");
|
||||
if (ipmi_intf_socket_connect (intf) == -1) {
|
||||
lprintf(LOG_ERR, "Could not open socket!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* connect to UDP socket so we get async errors */
|
||||
rc = connect(intf->fd, (struct sockaddr *)&s->addr,
|
||||
sizeof(struct sockaddr_in));
|
||||
if (rc < 0) {
|
||||
lperror(LOG_ERR, "Connect failed");
|
||||
if (intf->fd < 0) {
|
||||
lperror(LOG_ERR, "Connect to %s failed",
|
||||
s->hostname);
|
||||
intf->close(intf);
|
||||
return -1;
|
||||
}
|
||||
|
@ -381,7 +381,7 @@ int
|
||||
ipmi_tsol_main(struct ipmi_intf * intf, int argc, char ** argv)
|
||||
{
|
||||
struct pollfd fds_wait[3], fds_data_wait[3], *fds;
|
||||
struct sockaddr_in sin, myaddr;
|
||||
struct sockaddr_in sin, myaddr, *sa_in;
|
||||
socklen_t mylen;
|
||||
char *recvip = NULL;
|
||||
char out_buff[IPMI_BUF_SIZE * 8], in_buff[IPMI_BUF_SIZE];
|
||||
@ -398,8 +398,11 @@ ipmi_tsol_main(struct ipmi_intf * intf, int argc, char ** argv)
|
||||
}
|
||||
|
||||
for (i = 0; i<argc; i++) {
|
||||
if (sscanf(argv[i], "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4) == 4)
|
||||
recvip = strdup(argv[i]);
|
||||
if (sscanf(argv[i], "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4) == 4) {
|
||||
/* not free'd ...*/
|
||||
/* recvip = strdup(argv[i]); */
|
||||
recvip = argv[i];
|
||||
}
|
||||
else if (sscanf(argv[i], "port=%d", &ip1) == 1)
|
||||
port = ip1;
|
||||
else if (sscanf(argv[i], "rows=%d", &ip1) == 1)
|
||||
@ -427,8 +430,9 @@ ipmi_tsol_main(struct ipmi_intf * intf, int argc, char ** argv)
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(port);
|
||||
|
||||
sa_in = (struct sockaddr_in *)&intf->session->addr;
|
||||
result = inet_pton(AF_INET, (const char *)intf->session->hostname,
|
||||
&intf->session->addr.sin_addr);
|
||||
&sa_in->sin_addr);
|
||||
|
||||
if (result <= 0) {
|
||||
struct hostent *host = gethostbyname((const char *)intf->session->hostname);
|
||||
@ -444,8 +448,8 @@ ipmi_tsol_main(struct ipmi_intf * intf, int argc, char ** argv)
|
||||
(host->h_addrtype == AF_INET6) ? "IPv6" : "Unknown");
|
||||
return (-1);
|
||||
}
|
||||
intf->session->addr.sin_family = host->h_addrtype;
|
||||
memcpy(&intf->session->addr.sin_addr, host->h_addr, host->h_length);
|
||||
sa_in->sin_family = host->h_addrtype;
|
||||
memcpy(&sa_in->sin_addr, host->h_addr, host->h_length);
|
||||
}
|
||||
|
||||
fd_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
@ -455,6 +459,7 @@ ipmi_tsol_main(struct ipmi_intf * intf, int argc, char ** argv)
|
||||
}
|
||||
if (-1 == bind(fd_socket, (struct sockaddr *)&sin, sizeof(sin))) {
|
||||
lprintf(LOG_ERR, "Failed to bind socket.");
|
||||
close(fd_socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,18 @@
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#if defined(IPMI_INTF_LAN) || defined (IPMI_INTF_LANPLUS)
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include <ipmitool/ipmi_intf.h>
|
||||
#include <ipmitool/ipmi.h>
|
||||
#include <ipmitool/ipmi_sdr.h>
|
||||
@ -321,3 +333,170 @@ ipmi_cleanup(struct ipmi_intf * intf)
|
||||
{
|
||||
ipmi_sdr_list_empty(intf);
|
||||
}
|
||||
|
||||
#if defined(IPMI_INTF_LAN) || defined (IPMI_INTF_LANPLUS)
|
||||
int
|
||||
ipmi_intf_socket_connect(struct ipmi_intf * intf)
|
||||
{
|
||||
struct ipmi_session *session;
|
||||
|
||||
struct sockaddr_storage addr;
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *rp0 = NULL, *rp;
|
||||
char service[NI_MAXSERV];
|
||||
int rc;
|
||||
|
||||
if (!intf || intf->session == NULL)
|
||||
return -1;
|
||||
|
||||
session = intf->session;
|
||||
|
||||
if (session->hostname == NULL || strlen((const char *)session->hostname) == 0) {
|
||||
lprintf(LOG_ERR, "No hostname specified!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* open port to BMC */
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
|
||||
sprintf(service, "%d", session->port);
|
||||
/* Obtain address(es) matching host/port */
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
|
||||
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
|
||||
hints.ai_flags = 0; /* use AI_NUMERICSERV for no name resolution */
|
||||
hints.ai_protocol = IPPROTO_UDP; /* */
|
||||
|
||||
if (getaddrinfo(session->hostname, service, &hints, &rp0) != 0) {
|
||||
lprintf(LOG_ERR, "Address lookup for %s failed",
|
||||
session->hostname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* getaddrinfo() returns a list of address structures.
|
||||
* Try each address until we successfully connect(2).
|
||||
* If socket(2) (or connect(2)) fails, we (close the socket
|
||||
* and) try the next address.
|
||||
*/
|
||||
|
||||
session->ai_family = AF_UNSPEC;
|
||||
for (rp = rp0; rp != NULL; rp = rp->ai_next) {
|
||||
/* We are only interested in IPv4 and IPv6 */
|
||||
if ((rp->ai_family != AF_INET6) && (rp->ai_family == AF_INET))
|
||||
continue;
|
||||
|
||||
intf->fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
if (intf->fd == -1)
|
||||
continue;
|
||||
|
||||
if (rp->ai_family == AF_INET) {
|
||||
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;
|
||||
break; /* Success */
|
||||
}
|
||||
}
|
||||
|
||||
else if (rp->ai_family == AF_INET6) {
|
||||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)rp->ai_addr;
|
||||
char hbuf[NI_MAXHOST];
|
||||
socklen_t len;
|
||||
|
||||
/* The scope was specified on the command line e.g. with -H FE80::219:99FF:FEA0:BD95%eth0 */
|
||||
if ( addr6->sin6_scope_id != 0) {
|
||||
|
||||
len = sizeof(struct sockaddr_in6);
|
||||
if ( getnameinfo((struct sockaddr *)addr6, len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0) {
|
||||
lprintf(LOG_DEBUG, "Trying address: %s scope=%d",
|
||||
hbuf,
|
||||
addr6->sin6_scope_id);
|
||||
}
|
||||
|
||||
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;
|
||||
break; /* Success */
|
||||
}
|
||||
|
||||
} 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 */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddrs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (session->ai_family != AF_UNSPEC)
|
||||
break;
|
||||
|
||||
close(intf->fd);
|
||||
intf->fd = -1;
|
||||
}
|
||||
|
||||
/* No longer needed */
|
||||
freeaddrinfo(rp0);
|
||||
|
||||
return ((intf->fd != -1) ? 0 : -1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2032,44 +2032,14 @@ ipmi_lan_open(struct ipmi_intf * intf)
|
||||
|
||||
intf->session->sol_data.sequence_number = 1;
|
||||
|
||||
/* open port to BMC */
|
||||
memset(&s->addr, 0, sizeof(struct sockaddr_in));
|
||||
s->addr.sin_family = AF_INET;
|
||||
s->addr.sin_port = htons(s->port);
|
||||
|
||||
rc = inet_pton(AF_INET, (const char *)s->hostname, &s->addr.sin_addr);
|
||||
if (rc <= 0) {
|
||||
struct hostent *host = gethostbyname((const char *)s->hostname);
|
||||
if (host == NULL) {
|
||||
lprintf(LOG_ERR, "Address lookup for %s failed",
|
||||
s->hostname);
|
||||
return -1;
|
||||
}
|
||||
if (host->h_addrtype != AF_INET) {
|
||||
lprintf(LOG_ERR,
|
||||
"Address lookup for %s failed. Got %s, expected IPv4 address.",
|
||||
s->hostname,
|
||||
(host->h_addrtype == AF_INET6) ? "IPv6" : "Unknown");
|
||||
return (-1);
|
||||
}
|
||||
s->addr.sin_family = host->h_addrtype;
|
||||
memcpy(&s->addr.sin_addr, host->h_addr, host->h_length);
|
||||
}
|
||||
|
||||
lprintf(LOG_DEBUG, "IPMI LAN host %s port %d",
|
||||
s->hostname, ntohs(s->addr.sin_port));
|
||||
|
||||
intf->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (intf->fd < 0) {
|
||||
lperror(LOG_ERR, "Socket failed");
|
||||
if (ipmi_intf_socket_connect (intf) == -1) {
|
||||
lprintf(LOG_ERR, "Could not open socket!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* connect to UDP socket so we get async errors */
|
||||
rc = connect(intf->fd, (struct sockaddr *)&s->addr,
|
||||
sizeof(struct sockaddr_in));
|
||||
if (rc < 0) {
|
||||
lperror(LOG_ERR, "Connect failed");
|
||||
if (intf->fd < 0) {
|
||||
lperror(LOG_ERR, "Connect to %s failed",
|
||||
s->hostname);
|
||||
intf->close(intf);
|
||||
return -1;
|
||||
}
|
||||
|
@ -84,14 +84,14 @@ static struct ipmi_rs * ipmi_lanplus_send_ipmi_cmd(struct ipmi_intf * intf, stru
|
||||
static struct ipmi_rs * ipmi_lanplus_send_payload(struct ipmi_intf * intf,
|
||||
struct ipmi_v2_payload * payload);
|
||||
static void getIpmiPayloadWireRep(
|
||||
struct ipmi_intf * intf,
|
||||
struct ipmi_v2_payload * payload, /* in */
|
||||
struct ipmi_intf * intf,
|
||||
struct ipmi_v2_payload * payload, /* in */
|
||||
uint8_t * out,
|
||||
struct ipmi_rq * req,
|
||||
uint8_t rq_seq,
|
||||
uint8_t curr_seq);
|
||||
uint8_t curr_seq);
|
||||
static void getSolPayloadWireRep(
|
||||
struct ipmi_intf * intf,
|
||||
struct ipmi_intf * intf,
|
||||
uint8_t * msg,
|
||||
struct ipmi_v2_payload * payload);
|
||||
static void read_open_session_response(struct ipmi_rs * rsp, int offset);
|
||||
@ -113,7 +113,7 @@ static void ack_sol_packet(
|
||||
struct ipmi_intf * intf,
|
||||
struct ipmi_rs * rsp);
|
||||
|
||||
static uint8_t bridgePossible = 0;
|
||||
static uint8_t bridgePossible = 0;
|
||||
|
||||
struct ipmi_intf ipmi_lanplus_intf = {
|
||||
name: "lanplus",
|
||||
@ -3334,7 +3334,6 @@ ipmi_lanplus_open(struct ipmi_intf * intf)
|
||||
{
|
||||
int rc;
|
||||
struct get_channel_auth_cap_rsp auth_cap;
|
||||
struct sockaddr_in addr;
|
||||
struct ipmi_session *session;
|
||||
|
||||
if (!intf || !intf->session)
|
||||
@ -3373,46 +3372,14 @@ ipmi_lanplus_open(struct ipmi_intf * intf)
|
||||
/* Kg is set in ipmi_intf */
|
||||
//memset(session->v2_data.kg, 0, IPMI_KG_BUFFER_SIZE);
|
||||
|
||||
|
||||
/* open port to BMC */
|
||||
memset(&addr, 0, sizeof(struct sockaddr_in));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(session->port);
|
||||
|
||||
rc = inet_pton(AF_INET, (const char *)session->hostname, &addr.sin_addr);
|
||||
if (rc <= 0) {
|
||||
struct hostent *host = gethostbyname((const char *)session->hostname);
|
||||
if (host == NULL) {
|
||||
lprintf(LOG_ERR, "Address lookup for %s failed",
|
||||
session->hostname);
|
||||
return -1;
|
||||
}
|
||||
if (host->h_addrtype != AF_INET) {
|
||||
lprintf(LOG_ERR,
|
||||
"Address lookup for %s failed. Got %s, expected IPv4 address.",
|
||||
session->hostname,
|
||||
(host->h_addrtype == AF_INET6) ? "IPv6" : "Unknown");
|
||||
return (-1);
|
||||
}
|
||||
addr.sin_family = host->h_addrtype;
|
||||
memcpy(&addr.sin_addr, host->h_addr, host->h_length);
|
||||
}
|
||||
|
||||
lprintf(LOG_DEBUG, "IPMI LAN host %s port %d",
|
||||
session->hostname, ntohs(addr.sin_port));
|
||||
|
||||
intf->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (intf->fd < 0) {
|
||||
lperror(LOG_ERR, "Socket failed");
|
||||
if (ipmi_intf_socket_connect (intf) == -1) {
|
||||
lprintf(LOG_ERR, "Could not open socket!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* connect to UDP socket so we get async errors */
|
||||
rc = connect(intf->fd,
|
||||
(struct sockaddr *)&addr, sizeof(struct sockaddr_in));
|
||||
if (rc < 0) {
|
||||
lperror(LOG_ERR, "Connect failed");
|
||||
if (intf->fd < 0) {
|
||||
lperror(LOG_ERR, "Connect to %s failed",
|
||||
session->hostname);
|
||||
intf->close(intf);
|
||||
return -1;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user