Skip to content

Commit

Permalink
Initial pass at adding IPv6 address support to ipmipower.
Browse files Browse the repository at this point in the history
Albert Chu: Minor tweaks from original patch series, see pull request at

chu11/freeipmi-mirror#7
  • Loading branch information
lamontj authored and chu11 committed Jan 13, 2017
1 parent 7c195e9 commit 84a9079
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 70 deletions.
4 changes: 4 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
2016-12-06 LaMont Jones <[email protected]>

* ipmipower/: Initial pass at IPv6 support.

2016-12-05 Albert Chu <[email protected]>

Support IPv6 addresses in FreeIPMI
Expand Down
21 changes: 12 additions & 9 deletions ipmipower/ipmipower.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ _eliminate_nodes (void)
}

static void
_sendto (cbuf_t cbuf, int fd, struct sockaddr_in *destaddr)
_sendto (cbuf_t cbuf, int fd, struct sockaddr_in6 *destaddr)
{
int n, rv;
uint8_t buf[IPMIPOWER_PACKET_BUFLEN];
Expand All @@ -234,7 +234,7 @@ _sendto (cbuf_t cbuf, int fd, struct sockaddr_in *destaddr)
n,
0,
(struct sockaddr *)destaddr,
sizeof (struct sockaddr_in));
sizeof (struct sockaddr_in6));
else
{
if (ipmi_is_ipmi_1_5_packet (buf, n))
Expand All @@ -243,14 +243,14 @@ _sendto (cbuf_t cbuf, int fd, struct sockaddr_in *destaddr)
n,
0,
(struct sockaddr *)destaddr,
sizeof (struct sockaddr_in));
sizeof (struct sockaddr_in6));
else
rv = ipmi_rmcpplus_sendto (fd,
buf,
n,
0,
(struct sockaddr *)destaddr,
sizeof (struct sockaddr_in));
sizeof (struct sockaddr_in6));
}
} while (rv < 0 && errno == EINTR);

Expand All @@ -269,12 +269,13 @@ _sendto (cbuf_t cbuf, int fd, struct sockaddr_in *destaddr)
}

static void
_recvfrom (cbuf_t cbuf, int fd, struct sockaddr_in *srcaddr)
_recvfrom (cbuf_t cbuf, int fd, struct sockaddr_in6 *srcaddr)
{
int n, rv, dropped = 0;
uint8_t buf[IPMIPOWER_PACKET_BUFLEN];
struct sockaddr_in from;
unsigned int fromlen = sizeof (struct sockaddr_in);
struct sockaddr_in6 from;
struct sockaddr_in *from4;
unsigned int fromlen = sizeof (struct sockaddr_in6);

do
{
Expand Down Expand Up @@ -343,9 +344,11 @@ _recvfrom (cbuf_t cbuf, int fd, struct sockaddr_in *srcaddr)
exit (EXIT_FAILURE);
}

from4 = (struct sockaddr_in*)&from;
/* Don't store if this packet is strange for some reason */
if (from.sin_family != AF_INET
|| from.sin_addr.s_addr != srcaddr->sin_addr.s_addr)
if (!(from4->sin_family == AF_INET
&& from4->sin_addr.s_addr == ((struct sockaddr_in*)srcaddr)->sin_addr.s_addr) &&
!(from.sin6_family == AF_INET6 && memcmp (&from.sin6_addr, &srcaddr->sin6_addr, sizeof(from.sin6_addr)) == 0))
return;

/* cbuf should be empty, but if it isn't, empty it */
Expand Down
2 changes: 1 addition & 1 deletion ipmipower/ipmipower.h
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ struct ipmipower_connection
char hostname[MAXHOSTNAMELEN+1];
/* for oem power types ; extra arg passed in via "+extra" at end of hostname */
struct ipmipower_connection_extra_arg *extra_args;
struct sockaddr_in destaddr;
struct sockaddr_in6 destaddr;

/* for eliminate option */
int skip;
Expand Down
162 changes: 102 additions & 60 deletions ipmipower/ipmipower_connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@
#include "cbuf.h"
#include "fi_hostlist.h"

extern int h_errno;

extern cbuf_t ttyout;

extern struct ipmipower_arguments cmd_args;
Expand Down Expand Up @@ -128,13 +126,15 @@ ipmipower_connection_clear (struct ipmipower_connection *ic)
static int
_connection_setup (struct ipmipower_connection *ic, const char *hostname)
{
struct sockaddr_in srcaddr;
struct sockaddr_in6 srcaddr;
struct hostent *result;
char *hostname_first_parse_copy = NULL;
const char *hostname_first_parse_ptr = NULL;
char *hostname_second_parse_copy = NULL;
const char *hostname_second_parse_ptr = NULL;
uint16_t port = RMCP_PRIMARY_RMCP_PORT;
char port_str[12];
struct addrinfo ai_hints, *ai_res, *ai;
int rv = -1;

assert (ic);
Expand All @@ -144,47 +144,6 @@ _connection_setup (struct ipmipower_connection *ic, const char *hostname)

errno = 0;

if ((ic->ipmi_fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
{
if (errno == EMFILE)
{
IPMIPOWER_DEBUG (("file descriptor limit reached"));
return (-1);
}

IPMIPOWER_ERROR (("socket: %s", strerror (errno)));
exit (EXIT_FAILURE);
}

if ((ic->ping_fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
{
if (errno == EMFILE)
{
IPMIPOWER_DEBUG (("file descriptor limit reached"));
return (-1);
}

IPMIPOWER_ERROR (("socket: %s", strerror (errno)));
exit (EXIT_FAILURE);
}

/* Secure ephemeral ports */
bzero (&srcaddr, sizeof (struct sockaddr_in));
srcaddr.sin_family = AF_INET;
srcaddr.sin_port = htons (0);
srcaddr.sin_addr.s_addr = htonl (INADDR_ANY);

if (bind (ic->ipmi_fd, &srcaddr, sizeof (struct sockaddr_in)) < 0)
{
IPMIPOWER_ERROR (("bind: %s", strerror (errno)));
exit (EXIT_FAILURE);
}
if (bind (ic->ping_fd, &srcaddr, sizeof (struct sockaddr_in)) < 0)
{
IPMIPOWER_ERROR (("bind: %s", strerror (errno)));
exit (EXIT_FAILURE);
}

if (!(ic->ipmi_in = cbuf_create (IPMIPOWER_MIN_CONNECTION_BUF,
IPMIPOWER_MAX_CONNECTION_BUF)))
{
Expand Down Expand Up @@ -293,7 +252,45 @@ _connection_setup (struct ipmipower_connection *ic, const char *hostname)
else
hostname_first_parse_ptr = hostname;

if (strchr (hostname_first_parse_ptr, ':'))
if (hostname_first_parse_ptr[0] == '['
&& strchr (hostname_first_parse_ptr, ']'))
{
char *ptr;

/* IPv6 address */
if (!(hostname_second_parse_copy = strdup (hostname_first_parse_ptr+1)))
{
IPMIPOWER_ERROR (("strdup: %s", strerror (errno)));
exit (EXIT_FAILURE);
}

hostname_second_parse_ptr = hostname_second_parse_copy;
ptr = strchr (hostname_second_parse_copy, ']');
*ptr = '\0';
ptr++;
if (*ptr == ':')
{
char *endptr;
int tmp;

*ptr = '\0';
ptr++;

errno = 0;
tmp = strtol (ptr, &endptr, 0);
if (errno
|| endptr[0] != '\0'
|| tmp <= 0
|| tmp > USHRT_MAX)
{
ipmipower_output (IPMIPOWER_MSG_TYPE_HOSTNAME_INVALID, hostname_second_parse_ptr, NULL);
goto cleanup;
}

port = tmp;
}
}
else if (strchr (hostname_first_parse_ptr, ':'))
{
char *ptr;

Expand Down Expand Up @@ -335,29 +332,74 @@ _connection_setup (struct ipmipower_connection *ic, const char *hostname)
strncpy (ic->hostname, hostname_second_parse_ptr, MAXHOSTNAMELEN);
ic->hostname[MAXHOSTNAMELEN] = '\0';

/* Determine the destination address */
bzero (&(ic->destaddr), sizeof (struct sockaddr_in));
ic->destaddr.sin_family = AF_INET;
ic->destaddr.sin_port = htons (port);

if (!(result = gethostbyname (ic->hostname)))
snprintf(port_str, sizeof (port_str), "%d", port);
memset(&ai_hints, 0, sizeof (struct addrinfo));
ai_hints.ai_family = AF_UNSPEC;
ai_hints.ai_socktype = SOCK_DGRAM;
ai_hints.ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG);
if ((result = getaddrinfo (ic->hostname, port_str, &ai_hints, &ai_res )) != 0)
{
if (h_errno == HOST_NOT_FOUND)
if (result == EAI_NODATA)
ipmipower_output (IPMIPOWER_MSG_TYPE_HOSTNAME_INVALID, ic->hostname, NULL);
else
{
#if HAVE_HSTRERROR
IPMIPOWER_ERROR (("gethostbyname() %s: %s", ic->hostname, hstrerror (h_errno)));
#else /* !HAVE_HSTRERROR */
IPMIPOWER_ERROR (("gethostbyname() %s: h_errno = %d", ic->hostname, h_errno));
#endif /* !HAVE_HSTRERROR */
IPMIPOWER_ERROR (("getaddrinfo() %s: %s", ic->hostname, gai_strerror (result)));
exit (EXIT_FAILURE);
}
goto cleanup;
}
ic->destaddr.sin_addr = *((struct in_addr *)result->h_addr);

ic->skip = 0;
/* Try all of the different answers we got, until we succeed. */
for (ai = ai_res; ai != NULL; ai = ai->ai_next)
{
if ((ic->ipmi_fd = socket (ai->ai_family,
ai->ai_socktype, ai->ai_protocol)) < 0)
{
if (errno == EMFILE)
{
IPMIPOWER_DEBUG (("file descriptor limit reached"));
return (-1);
}
}

if ((ic->ping_fd = socket (ai->ai_family,
ai->ai_socktype, ai->ai_protocol)) < 0)
{
if (errno == EMFILE)
{
IPMIPOWER_DEBUG (("file descriptor limit reached"));
return (-1);
}
}
/* Secure ephemeral ports */
bzero (&srcaddr, sizeof (struct sockaddr_in6));
srcaddr.sin6_family = ai->ai_family; /* always the same place */
/* All zero is otherwise correct. */

if ((bind (ic->ipmi_fd, &srcaddr, sizeof (struct sockaddr_in6)) < 0)
|| (bind (ic->ping_fd, &srcaddr, sizeof (struct sockaddr_in6)) < 0))
{
close(ic->ipmi_fd);
close(ic->ping_fd);
continue;
}

/* Determine the destination address */
if (ai->ai_addrlen > sizeof (struct sockaddr_in6))
{
IPMIPOWER_ERROR (("getaddrinfo: unexpected address length %d",
ai->ai_addrlen));
exit (EXIT_FAILURE);
}
memcpy (&(ic->destaddr), ai->ai_addr, ai->ai_addrlen);
ic->skip = 0;
break;
}

if (!ai)
{
IPMIPOWER_ERROR (("socket/bind: %s", strerror (errno)));
exit (EXIT_FAILURE);
}

rv = 0;
cleanup:
Expand Down

0 comments on commit 84a9079

Please sign in to comment.