diff options
author | Niels de Vos <ndevos@redhat.com> | 2014-06-29 16:30:30 +0200 |
---|---|---|
committer | Niels de Vos <ndevos@redhat.com> | 2014-07-02 00:53:18 -0700 |
commit | cacc1311626aa8b2dfe9f937cf1b14bb534a8937 (patch) | |
tree | 63369e3f37d058444f2ce93640684af0f407ecae /libglusterfs | |
parent | cf5a5ab1a81bb61bb66982757ccd301d015ac16e (diff) |
gNFS: Fix multi-homed m/c issue in NFS subdir auth
NFS subdir authentication doesn't correctly handle multi-homed
(host with multiple NIC having multiple IP addr) OR multi-protocol
(IPv4 and IPv6) network addresses.
When user/admin sets HOSTNAME in gluster CLI for NFS subdir auth,
mnt3_verify_auth() routine does not iterate over all the resolved
n/w addrs returned by getaddrinfo() n/w API. Instead, it just tests
with the one returned first.
1. Iterate over all the n/w addrs (linked list) returned by getaddrinfo().
2. Move the n/w mask calculation part to mnt3_export_fill_hostspec()
instead of doing it in mnt3_verify_auth() i.e. calculating for each
mount request. It does not change for MOUNT req.
3. Integrate "subnet support code rpc-auth.addr.<volname>.allow"
and "NFS subdir auth code" to remove code duplication.
Cherry-picked from commit d3f0de90d0c5166e63f5764d2f21703fd29ce976:
> Change-Id: I26b0def52c22cda35ca11766afca3df5fd4360bf
> BUG: 1102293
> Signed-off-by: Santosh Kumar Pradhan <spradhan@redhat.com>
> Reviewed-on: http://review.gluster.org/8048
> Reviewed-by: Rajesh Joseph <rjoseph@redhat.com>
> Tested-by: Gluster Build System <jenkins@build.gluster.com>
> Reviewed-by: Niels de Vos <ndevos@redhat.com>
Change-Id: Ie92a8ac602bec2cd77268acb7b23ad8ba3c52f5f
BUG: 1112980
Signed-off-by: Niels de Vos <ndevos@redhat.com>
Reviewed-on: http://review.gluster.org/8198
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Santosh Pradhan <spradhan@redhat.com>
Diffstat (limited to 'libglusterfs')
-rw-r--r-- | libglusterfs/src/common-utils.c | 81 | ||||
-rw-r--r-- | libglusterfs/src/common-utils.h | 3 |
2 files changed, 84 insertions, 0 deletions
diff --git a/libglusterfs/src/common-utils.c b/libglusterfs/src/common-utils.c index 1dfb418e4a8..96319624361 100644 --- a/libglusterfs/src/common-utils.c +++ b/libglusterfs/src/common-utils.c @@ -1921,6 +1921,70 @@ out: return ret; } +/** + * valid_ipv4_subnetwork() takes the pattern and checks if it contains + * a valid ipv4 subnetwork pattern i.e. xx.xx.xx.xx/n. IPv4 address + * part (xx.xx.xx.xx) and mask bits lengh part (n). The mask bits lengh + * must be in 0-32 range (ipv4 addr is 32 bit). The pattern must be + * in this format. + * + * Returns _gf_true if both IP addr and mask bits len are valid + * _gf_false otherwise. + */ +gf_boolean_t +valid_ipv4_subnetwork (const char *address) +{ + char *slash = NULL; + char *paddr = NULL; + char *endptr = NULL; + long prefixlen = -1; + gf_boolean_t retv = _gf_true; + + if (address == NULL) { + gf_log_callingfn (THIS->name, GF_LOG_WARNING, + "argument invalid"); + return _gf_false; + } + + paddr = gf_strdup (address); + if (paddr == NULL) /* ENOMEM */ + return _gf_false; + + /* + * INVALID: If '/' is not present OR + * Nothing specified after '/' + */ + slash = strchr(paddr, '/'); + if ((slash == NULL) || (slash[1] == '\0')) { + gf_log_callingfn (THIS->name, GF_LOG_WARNING, + "Invalid IPv4 subnetwork format"); + retv = _gf_false; + goto out; + } + + *slash = '\0'; + retv = valid_ipv4_address (paddr, strlen(paddr), _gf_false); + if (retv == _gf_false) { + gf_log_callingfn (THIS->name, GF_LOG_WARNING, + "Invalid IPv4 subnetwork address"); + goto out; + } + + prefixlen = strtol (slash + 1, &endptr, 10); + if ((errno != 0) || (*endptr != '\0') || + (prefixlen < 0) || (prefixlen > IPv4_ADDR_SIZE)) { + gf_log_callingfn (THIS->name, GF_LOG_WARNING, + "Invalid IPv4 subnetwork mask"); + retv = _gf_false; + goto out; + } + + retv = _gf_true; +out: + GF_FREE (paddr); + return retv; +} + char valid_ipv6_address (char *address, int length, gf_boolean_t wildcard_acc) { @@ -2045,6 +2109,23 @@ gf_sock_union_equal_addr (union gf_sock_union *a, return _gf_false; } +/* + * Check if both have same network address. + * Extract the network address from the sockaddr(s) addr by applying the + * network mask. If they match, return boolean _gf_true, _gf_false otherwise. + * + * (x == y) <=> (x ^ y == 0) + * (x & y) ^ (x & z) <=> x & (y ^ z) + * + * ((ip1 & mask) == (ip2 & mask)) <=> ((mask & (ip1 ^ ip2)) == 0) + */ +gf_boolean_t +mask_match(const uint32_t a, const uint32_t b, const uint32_t m) +{ + return (((a ^ b) & m) == 0); +} + + /*Thread safe conversion function*/ char * uuid_utoa (uuid_t uuid) diff --git a/libglusterfs/src/common-utils.h b/libglusterfs/src/common-utils.h index 6f8436fcba0..a0c0db170de 100644 --- a/libglusterfs/src/common-utils.h +++ b/libglusterfs/src/common-utils.h @@ -49,6 +49,8 @@ void trap (void); #define roof(a,b) ((((a)+(b)-1)/((b)?(b):1))*(b)) #define floor(a,b) (((a)/((b)?(b):1))*(b)) +#define IPv4_ADDR_SIZE 32 + #define GF_UNIT_KB 1024ULL #define GF_UNIT_MB 1048576ULL @@ -572,6 +574,7 @@ void skip_word (char **str); /* returns a new string with nth word of given string. n>=1 */ char *get_nth_word (const char *str, int n); +gf_boolean_t mask_match (const uint32_t a, const uint32_t b, const uint32_t m); char valid_host_name (char *address, int length); char valid_ipv4_address (char *address, int length, gf_boolean_t wildcard_acc); char valid_ipv6_address (char *address, int length, gf_boolean_t wildcard_acc); |