Retire the slash32 logic in inet_netmask() in favor of a more generic
netmask parser that can support IPv6 addresses.
If an invalid IP address string is given to inet_addr(3), it returns
INADDR_NONE, which is actually a "valid" address (255.255.255.255).
We're none the wiser to the substitution until something breaks later.
This patch provides better sanity checking of the parsed address, now
that such an error can be reported to client_init()'s callers.
We can also check the prefixlen value a little more carefully as well.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
#include <string.h>
#include <ctype.h>
#include <netdb.h>
#include <string.h>
#include <ctype.h>
#include <netdb.h>
#include "misc.h"
#include "nfslib.h"
#include "misc.h"
#include "nfslib.h"
-init_netmask(nfs_client *clp, const char *slash)
+init_netmask(nfs_client *clp, const char *slash, const sa_family_t family)
{
struct sockaddr_in sin = {
.sin_family = AF_INET,
};
{
struct sockaddr_in sin = {
.sin_family = AF_INET,
};
+ unsigned long prefixlen;
+ uint32_t shift;
- if (strchr(slash + 1, '.') != NULL)
- sin.sin_addr.s_addr = inet_addr(slash + 1);
- else {
- int prefixlen = atoi(slash + 1);
- if (0 < prefixlen && prefixlen <= 32)
- sin.sin_addr.s_addr =
- htonl((uint32_t)~0 << (32 - prefixlen));
- else
+ /* No slash present; assume netmask is all ones */
+ if (slash == NULL) {
+ switch (family) {
+ case AF_INET:
+ prefixlen = 32;
+ break;
+ default:
+ goto out_badfamily;
+ }
+ } else {
+ char *endptr;
+
+ /* A spelled out netmask address, perhaps? */
+ if (strchr(slash + 1, '.') != NULL) {
+ if (inet_pton(AF_INET, slash + 1,
+ &sin.sin_addr.s_addr) == 0)
+ goto out_badmask;
+ set_addrlist_in(clp, 1, &sin);
+ return 1;
+ }
+
+ /* A prefixlen was given */
+ prefixlen = strtoul(slash + 1, &endptr, 10);
+ if (*endptr != '\0' && prefixlen != ULONG_MAX && errno != ERANGE)
- set_addrlist_in(clp, 1, &sin);
- return 1;
+ switch (family) {
+ case AF_INET:
+ if (prefixlen > 32)
+ goto out_badprefix;
+ shift = 32 - (uint32_t)prefixlen;
+ sin.sin_addr.s_addr = htonl((uint32_t)~0 << shift);
+ set_addrlist_in(clp, 1, &sin);
+ return 1;
+ }
+
+out_badfamily:
+ xlog(L_ERROR, "Unsupported address family for %s", clp->m_hostname);
+ return 0;
+
+out_badmask:
+ xlog(L_ERROR, "Invalid netmask `%s' for %s", slash + 1, clp->m_hostname);
+ return 0;
out_badprefix:
xlog(L_ERROR, "Invalid prefix `%s' for %s", slash + 1, clp->m_hostname);
out_badprefix:
xlog(L_ERROR, "Invalid prefix `%s' for %s", slash + 1, clp->m_hostname);
static int
init_subnetwork(nfs_client *clp)
{
static int
init_subnetwork(nfs_client *clp)
{
- static char slash32[] = "/32";
- char *cp;
-
- cp = strchr(clp->m_hostname, '/');
- if (cp == NULL)
- cp = slash32;
-
- *cp = '\0';
- ai = host_pton(clp->m_hostname);
- *cp = '/';
+ sa_family_t family;
+ char *slash;
+
+ slash = strchr(clp->m_hostname, '/');
+ if (slash != NULL) {
+ *slash = '\0';
+ ai = host_pton(clp->m_hostname);
+ *slash = '/';
+ } else
+ ai = host_pton(clp->m_hostname);
if (ai == NULL) {
xlog(L_ERROR, "Invalid IP address %s", clp->m_hostname);
return false;
}
if (ai == NULL) {
xlog(L_ERROR, "Invalid IP address %s", clp->m_hostname);
return false;
}
set_addrlist(clp, 0, ai->ai_addr);
set_addrlist(clp, 0, ai->ai_addr);
+ family = ai->ai_addr->sa_family;
+
- return init_netmask(clp, cp);
+ return init_netmask(clp, slash, family);