From: Zdenek Styblik <stybla@turnovfree.net>
Subject: ID:336 - ipmitool does not fall back to IPv4 for IPMI v2 / RMCP+ sessions
References: bsc#1011283
Patch-Mainline: IPMITOOL_1_8_16
Git-commit: 636a785d82e3b0f49e4138b632b48cb5e0a476f8
Git-repo: git.code.sf.net/p/ipmitool/source

Signed-off-by: Thomas Renninger <trenn@suse.de>

Commit implements '-4' and '-6' switch in order to enforce IPv4 or IPv6
connection. In order to do so, struct ipmi_intf has been extended to carry
ai_family flag.

Index: ipmitool-1.8.13/include/ipmitool/ipmi_intf.h
===================================================================
--- ipmitool-1.8.13.orig/include/ipmitool/ipmi_intf.h	2014-02-27 08:56:28.000000000 +0100
+++ ipmitool-1.8.13/include/ipmitool/ipmi_intf.h	2016-11-28 16:04:22.973761546 +0100
@@ -169,6 +169,7 @@ struct ipmi_intf {
 	int noanswer;
 	int picmg_avail;
 	IPMI_OEM manufacturer_id;
+	int ai_family;
 
 	struct ipmi_session * session;
 	struct ipmi_oem_handle * oem;
Index: ipmitool-1.8.13/lib/ipmi_main.c
===================================================================
--- ipmitool-1.8.13.orig/lib/ipmi_main.c	2014-02-27 08:56:28.000000000 +0100
+++ ipmitool-1.8.13/lib/ipmi_main.c	2016-11-28 16:04:22.973761546 +0100
@@ -74,9 +74,9 @@
 #endif
 
 #ifdef ENABLE_ALL_OPTIONS
-# define OPTION_STRING	"I:hVvcgsEKYao:H:d:P:f:U:p:C:L:A:t:T:m:z:S:l:b:B:e:k:y:O:R:N:D:"
+# define OPTION_STRING	"I:46hVvcgsEKYao:H:d:P:f:U:p:C:L:A:t:T:m:z:S:l:b:B:e:k:y:O:R:N:D:"
 #else
-# define OPTION_STRING	"I:hVvcH:f:U:p:d:S:D:"
+# define OPTION_STRING	"I:46hVvcH:f:U:p:d:S:D:"
 #endif
 
 extern int verbose;
@@ -227,6 +227,8 @@ ipmi_option_usage(const char * progname,
 	lprintf(LOG_NOTICE, "       -S sdr         Use local file for remote SDR cache");
 	lprintf(LOG_NOTICE, "       -D tty:b[:s]   Specify the serial device, baud rate to use");
 	lprintf(LOG_NOTICE, "                      and, optionally, specify that interface is the system one");
+	lprintf(LOG_NOTICE, "       -4             Use only IPv4");
+	lprintf(LOG_NOTICE, "       -6             Use only IPv6");
 #ifdef ENABLE_ALL_OPTIONS
 	lprintf(LOG_NOTICE, "       -a             Prompt for remote password");
 	lprintf(LOG_NOTICE, "       -Y             Prompt for the Kg key for IPMIv2 authentication");
@@ -385,6 +387,7 @@ ipmi_main(int argc, char ** argv,
 	int cipher_suite_id = 3; /* See table 22-19 of the IPMIv2 spec */
 	int argflag, i, found;
 	int rc = -1;
+	int ai_family = AF_UNSPEC;
 	char sol_escape_char = SOL_ESCAPE_CHARACTER_DEFAULT;
 	char * devfile  = NULL;
 
@@ -610,6 +613,38 @@ ipmi_main(int argc, char ** argv,
 				goto out_free;
 			}
 			break;
+		case '4':
+			/* IPv4 only */
+			if (ai_family == AF_UNSPEC) {
+				ai_family = AF_INET;
+			} else {
+				if (ai_family == AF_INET6) {
+					lprintf(LOG_ERR,
+						"Parameter is mutually exclusive with -6.");
+				} else {
+					lprintf(LOG_ERR,
+						"Multiple -4 parameters given.");
+				}
+				rc = (-1);
+				goto out_free;
+			}
+			break;
+		case '6':
+			/* IPv6 only */
+			if (ai_family == AF_UNSPEC) {
+				ai_family = AF_INET6;
+			} else {
+				if (ai_family == AF_INET) {
+					lprintf(LOG_ERR,
+						"Parameter is mutually exclusive with -4.");
+				} else {
+					lprintf(LOG_ERR,
+						"Multiple -6 parameters given.");
+				}
+				rc = (-1);
+				goto out_free;
+			}
+			break;
 #ifdef ENABLE_ALL_OPTIONS
 		case 'o':
 			if (oemtype) {
@@ -893,6 +928,7 @@ ipmi_main(int argc, char ** argv,
 	/* setup device file if given */
 	ipmi_main_intf->devfile = devfile;
 
+	ipmi_main_intf->ai_family = ai_family;
 	/* Open the interface with the specified or default IPMB address */
 	ipmi_main_intf->my_addr = arg_addr ? arg_addr : IPMI_BMC_SLAVE_ADDR;
 	if (ipmi_main_intf->open != NULL) {
Index: ipmitool-1.8.13/src/plugins/ipmi_intf.c
===================================================================
--- ipmitool-1.8.13.orig/src/plugins/ipmi_intf.c	2014-02-27 08:56:28.000000000 +0100
+++ ipmitool-1.8.13/src/plugins/ipmi_intf.c	2016-11-28 16:04:22.973761546 +0100
@@ -363,7 +363,7 @@ ipmi_intf_socket_connect(struct ipmi_int
 	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_family   = intf->ai_family;    /* 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; /*  */
