---
 utils/gssd/gss_util.h  |    2 ++
 utils/gssd/gssd.c      |    7 +++++--
 utils/gssd/gssd.man    |   25 ++++++++++++++++++++++++-
 utils/gssd/gssd_proc.c |   33 +++++++++++++++++++++++++++++----
 4 files changed, 60 insertions(+), 7 deletions(-)

--- nfs-utils-1.2.3/utils/gssd/gssd.c.orig	2013-06-06 11:25:12.094049892 +0200
+++ nfs-utils-1.2.3/utils/gssd/gssd.c	2013-06-06 11:29:09.506513168 +0200
@@ -85,7 +85,7 @@
 static void
 usage(char *progname)
 {
-	fprintf(stderr, "usage: %s [-f] [-M] [-n] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir] [-t timeout] [-R preferred realm]\n",
+	fprintf(stderr, "usage: %s [-f] [-M] [-n] [-v] [-r] [-D] [-p pipefsdir] [-k keytab] [-d ccachedir] [-t timeout] [-R preferred realm]\n",
 		progname);
 	exit(1);
 }
@@ -102,7 +102,7 @@
 	char *progname;
 
 	memset(ccachesearch, 0, sizeof(ccachesearch));
-	while ((opt = getopt(argc, argv, "fvrmnMp:k:d:t:R:")) != -1) {
+	while ((opt = getopt(argc, argv, "DfvrmnMp:k:d:t:R:")) != -1) {
 		switch (opt) {
 			case 'f':
 				fg = 1;
@@ -143,6 +143,9 @@
 			case 'R':
 				preferred_realm = strdup(optarg);
 				break;
+			case 'D':
+				avoid_dns = 0;
+				break;
 			default:
 				usage(argv[0]);
 				break;
--- nfs-utils-1.2.3/utils/gssd/gssd.man.orig	2013-06-06 11:25:12.094049892 +0200
+++ nfs-utils-1.2.3/utils/gssd/gssd.man	2013-06-06 11:30:03.825332273 +0200
@@ -6,7 +6,7 @@
 .SH NAME
 rpc.gssd \- rpcsec_gss daemon
 .SH SYNOPSIS
-.B "rpc.gssd [-f] [-n] [-k keytab] [-p pipefsdir] [-v] [-r] [-d ccachedir]"
+.B "rpc.gssd [-f] [-n] [-D] [-k keytab] [-p pipefsdir] [-v] [-r] [-d ccachedir]"
 .SH DESCRIPTION
 The rpcsec_gss protocol gives a means of using the gss-api generic security
 api to provide security for protocols using rpc (in particular, nfs).  Before
@@ -87,6 +87,29 @@
 If the rpcsec_gss library supports setting debug level,
 increases the verbosity of the output (can be specified multiple times).
 .TP
+.B \-D
+The server name passed to GSSAPI for authentication is normally the
+name exactly as requested.  e.g. for NFS
+it is the server name in the "servername:/path" mount request.  Only if this
+servername appears to be an IP address or an
+unqualified name (no dots) will a reverse DNS lookup
+will be performed to get the canoncial server name.
+
+If
+.B \-D
+is present, a reverse DNS lookup will
+.I always
+be used, even if the server name looks like a canonical name.  So it
+is needed if partially qualified, or non canonical names are regularly
+used.
+
+Using
+.B \-D
+can introduce a security vulnerability, so it is recommended that
+.B \-D
+not be used, and that canonical names always be used when requesting
+services.
+.TP
 .B -R realm
 Kerberos tickets from this
 .I realm
--- nfs-utils-1.2.6.orig/utils/gssd/gss_util.h
+++ nfs-utils-1.2.6/utils/gssd/gss_util.h
@@ -42,4 +42,6 @@ void pgsserr(char *msg, u_int32_t maj_st
 	const gss_OID mech);
 int gssd_check_mechs(void);
 
+extern int avoid_dns;
+
 #endif /* _GSS_UTIL_H_ */
--- nfs-utils-1.2.6.orig/utils/gssd/gssd_proc.c
+++ nfs-utils-1.2.6/utils/gssd/gssd_proc.c
@@ -106,6 +106,9 @@ struct pollfd * pollarray;
 
 int pollsize;  /* the size of pollaray (in pollfd's) */
 
+/* Avoid DNS reverse lookups on server names if possible */
+int avoid_dns = 1;
+
 /*
  * convert a presentation address string to a sockaddr_storage struct. Returns
  * true on success or false on failure.
@@ -164,12 +167,34 @@ addrstr_to_sockaddr(struct sockaddr *sa,
  * convert a sockaddr to a hostname
  */
 static char *
-sockaddr_to_hostname(const struct sockaddr *sa, const char *addr)
+get_servername(const char *name, const struct sockaddr *sa, const char *addr)
 {
 	socklen_t		addrlen;
 	int			err;
 	char 			*hostname;
 	char			hbuf[NI_MAXHOST];
+	unsigned char		buf[sizeof(struct in6_addr)];
+
+	if (avoid_dns) {
+		/*
+		 * Determine if this is a server name, or an IP address.
+		 * If it is an IP address, do the DNS lookup otherwise
+		 * skip the DNS lookup.
+		 */
+		int is_fqdn = 1;
+		if (strchr(name, '.') == NULL)
+			is_fqdn = 0; /* local name */
+		else if (inet_pton(AF_INET, name, buf) == 1)
+			is_fqdn = 0; /* IPv4 address */
+		else if (inet_pton(AF_INET6, name, buf) == 1)
+			is_fqdn = 0; /* IPv6 addrss */
+
+		if (is_fqdn) {
+			return strdup(name);
+		}
+		/* Sorry, cannot avoid dns after all */
+	}
+
 
 	switch (sa->sa_family) {
 	case AF_INET:
@@ -207,7 +232,7 @@ read_service_info(char *info_file_name,
 		  struct sockaddr *addr) {
 #define INFOBUFLEN 256
 	char		buf[INFOBUFLEN + 1];
-	static char	dummy[128];
+	static char	server[128];
 	int		nbytes;
 	static char	service[128];
 	static char	address[128];
@@ -235,7 +260,7 @@ read_service_info(char *info_file_name,
 		   "service: %127s %15s version %15s\n"
 		   "address: %127s\n"
 		   "protocol: %15s\n",
-		   dummy,
+		   server,
 		   service, program, version,
 		   address,
 		   protoname);
@@ -268,7 +293,7 @@ read_service_info(char *info_file_name,
 	if (!addrstr_to_sockaddr(addr, address, port))
 		goto fail;
 
-	*servername = sockaddr_to_hostname(addr, address);
+	*servername = get_servername(server, addr, address);
 	if (*servername == NULL)
 		goto fail;
 
