X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=support%2Fexport%2Fhostname.c;h=3e949a18fe52255b51a4d77713f28b1679f16b75;hp=79b9a8cba6081af5d91c93de78ac57757f275fe1;hb=b50ad13298b3e9519a9bdecb8c146c9ecf39cef8;hpb=94ce1eb94babb4c587b2826452fb053cba745098 diff --git a/support/export/hostname.c b/support/export/hostname.c index 79b9a8c..3e949a1 100644 --- a/support/export/hostname.c +++ b/support/export/hostname.c @@ -1,182 +1,35 @@ /* - * support/export/hostname.c + * Copyright 2010 Oracle. All rights reserved. * - * Functions for hostname. + * This file is part of nfs-utils. * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * nfs-utils is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with nfs-utils. If not, see . */ #ifdef HAVE_CONFIG_H #include #endif -/* -#define TEST -*/ - #include -#include -#include -#include #include +#include +#include #include -#include -#ifdef TEST -#define xmalloc malloc -#else -#include "xmalloc.h" -#include "misc.h" -#endif - #include "sockaddr.h" #include "exportfs.h" -#ifndef HAVE_DECL_AI_ADDRCONFIG -#define AI_ADDRCONFIG 0 -#endif - -#define ALIGNMENT sizeof (char *) - -static int -align (int len, int al) -{ - int i; - i = len % al; - if (i) - len += al - i; - return len; -} - -struct hostent * -get_hostent (const char *addr, int len, int type) -{ - struct hostent *cp; - int len_ent; - const char *name; - int len_name; - int num_aliases = 1; - int len_aliases = sizeof (char *); - int num_addr_list = 1; - int len_addr_list = sizeof (char *); - int pos; - struct in_addr *ipv4; - - switch (type) - { - case AF_INET: - ipv4 = (struct in_addr *) addr; - name = inet_ntoa (*ipv4); - break; - - default: - return NULL; - } - - len_ent = align (sizeof (*cp), ALIGNMENT); - len_name = align (strlen (name) + 1, ALIGNMENT); - - num_addr_list++; - len_addr_list += align (len, ALIGNMENT) + sizeof (char *); - - cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases - + len_addr_list); - - cp->h_addrtype = type; - cp->h_length = len; - pos = len_ent; - cp->h_name = (char *) &(((char *) cp) [pos]); - strcpy (cp->h_name, name); - - pos += len_name; - cp->h_aliases = (char **) &(((char *) cp) [pos]); - pos += num_aliases * sizeof (char *); - cp->h_aliases [0] = NULL; - - pos = len_ent + len_name + len_aliases; - cp->h_addr_list = (char **) &(((char *) cp) [pos]); - pos += num_addr_list * sizeof (char *); - cp->h_addr_list [0] = (char *) &(((char *) cp) [pos]); - memcpy (cp->h_addr_list [0], addr, cp->h_length); - pos += align (cp->h_length, ALIGNMENT); - cp->h_addr_list [1] = NULL; - - return cp; -} - -struct hostent * -hostent_dup (struct hostent *hp) -{ - int len_ent = align (sizeof (*hp), ALIGNMENT); - int len_name = align (strlen (hp->h_name) + 1, ALIGNMENT); - int num_aliases = 1; - int len_aliases = sizeof (char *); - int num_addr_list = 1; - int len_addr_list = sizeof (char *); - int pos, i; - char **sp; - struct hostent *cp; - - for (sp = hp->h_aliases; sp && *sp; sp++) - { - num_aliases++; - len_aliases += align (strlen (*sp) + 1, ALIGNMENT) - + sizeof (char *); - } - - for (sp = hp->h_addr_list; *sp; sp++) - { - num_addr_list++; - len_addr_list += align (hp->h_length, ALIGNMENT) - + sizeof (char *); - } - - cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases - + len_addr_list); - - *cp = *hp; - pos = len_ent; - cp->h_name = (char *) &(((char *) cp) [pos]); - strcpy (cp->h_name, hp->h_name); - - pos += len_name; - cp->h_aliases = (char **) &(((char *) cp) [pos]); - pos += num_aliases * sizeof (char *); - for (sp = hp->h_aliases, i = 0; i < num_aliases; i++, sp++) - if (sp && *sp) - { - cp->h_aliases [i] = (char *) &(((char *) cp) [pos]); - strcpy (cp->h_aliases [i], *sp); - pos += align (strlen (*sp) + 1, ALIGNMENT); - } - else - cp->h_aliases [i] = NULL; - - pos = len_ent + len_name + len_aliases; - cp->h_addr_list = (char **) &(((char *) cp) [pos]); - pos += num_addr_list * sizeof (char *); - for (sp = hp->h_addr_list, i = 0; i < num_addr_list; i++, sp++) - if (*sp) - { - cp->h_addr_list [i] = (char *) &(((char *) cp) [pos]); - memcpy (cp->h_addr_list [i], *sp, hp->h_length); - pos += align (hp->h_length, ALIGNMENT); - } - else - cp->h_addr_list [i] = *sp; - - return cp; -} - -#ifdef HAVE_GETNAMEINFO -static socklen_t -sockaddr_size(const struct sockaddr *sap) -{ - if (sap->sa_family != AF_INET) - return 0; - return (socklen_t)sizeof(struct sockaddr_in); -} -#endif /* HAVE_GETNAMEINFO */ - /** * host_ntop - generate presentation address given a sockaddr * @sap: pointer to socket address @@ -189,7 +42,7 @@ sockaddr_size(const struct sockaddr *sap) char * host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen) { - socklen_t salen = sockaddr_size(sap); + socklen_t salen = nfs_sockaddr_length(sap); int error; memset(buf, 0, buflen); @@ -250,7 +103,7 @@ host_pton(const char *paddr) .ai_family = AF_UNSPEC, }; struct sockaddr_in sin; - int error; + int error, inet4; /* * Although getaddrinfo(3) is easier to use and supports @@ -262,12 +115,17 @@ host_pton(const char *paddr) * have a real AF_INET presentation address, before invoking * getaddrinfo(3) to generate the full addrinfo list. */ + inet4 = 1; if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0) - return NULL; + inet4 = 0; error = getaddrinfo(paddr, NULL, &hint, &ai); switch (error) { case 0: + if (!inet4 && ai->ai_addr->sa_family == AF_INET) { + freeaddrinfo(ai); + break; + } return ai; case EAI_NONAME: if (paddr == NULL) @@ -301,10 +159,14 @@ host_addrinfo(const char *hostname) { struct addrinfo *ai = NULL; struct addrinfo hint = { +#ifdef IPV6_SUPPORTED + .ai_family = AF_UNSPEC, +#else .ai_family = AF_INET, +#endif /* don't return duplicates */ .ai_protocol = (int)IPPROTO_UDP, - .ai_flags = AI_ADDRCONFIG | AI_CANONNAME, + .ai_flags = AI_CANONNAME, }; int error; @@ -341,7 +203,7 @@ __attribute_malloc__ char * host_canonname(const struct sockaddr *sap) { - socklen_t salen = sockaddr_size(sap); + socklen_t salen = nfs_sockaddr_length(sap); char buf[NI_MAXHOST]; int error; @@ -396,17 +258,19 @@ host_canonname(const struct sockaddr *sap) * @sap: pointer to socket address to look up * * Reverse and forward lookups are performed to ensure the address has - * proper forward and reverse mappings. + * matching forward and reverse mappings. * - * Returns address info structure with ai_canonname filled in, or NULL - * if no information is available for @sap. Caller must free the returned - * structure with freeaddrinfo(3). + * Returns addrinfo structure with just the provided address with + * ai_canonname filled in. If there is a problem with resolution or + * the resolved records don't match up properly then it returns NULL + * + * Caller must free the returned structure with freeaddrinfo(3). */ __attribute_malloc__ struct addrinfo * host_reliable_addrinfo(const struct sockaddr *sap) { - struct addrinfo *ai; + struct addrinfo *ai, *a; char *hostname; hostname = host_canonname(sap); @@ -414,9 +278,31 @@ host_reliable_addrinfo(const struct sockaddr *sap) return NULL; ai = host_addrinfo(hostname); + if (!ai) + goto out_free_hostname; + + /* make sure there's a matching address in the list */ + for (a = ai; a; a = a->ai_next) + if (nfs_compare_sockaddr(a->ai_addr, sap)) + break; + + freeaddrinfo(ai); + if (!a) + goto out_free_hostname; + + /* get addrinfo with just the original address */ + ai = host_numeric_addrinfo(sap); + if (!ai) + goto out_free_hostname; + + /* and populate its ai_canonname field */ + free(ai->ai_canonname); + ai->ai_canonname = hostname; + return ai; +out_free_hostname: free(hostname); - return ai; + return NULL; } /** @@ -431,8 +317,8 @@ __attribute_malloc__ struct addrinfo * host_numeric_addrinfo(const struct sockaddr *sap) { - socklen_t salen = sockaddr_size(sap); - char buf[INET_ADDRSTRLEN]; + socklen_t salen = nfs_sockaddr_length(sap); + char buf[INET6_ADDRSTRLEN]; struct addrinfo *ai; int error; @@ -508,159 +394,3 @@ host_numeric_addrinfo(const struct sockaddr *sap) return ai; } #endif /* !HAVE_GETNAMEINFO */ - -static int -is_hostname(const char *sp) -{ - if (*sp == '\0' || *sp == '@') - return 0; - - for (; *sp; sp++) - { - if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/') - return 0; - if (*sp == '\\' && sp[1]) - sp++; - } - - return 1; -} - -int -matchhostname (const char *h1, const char *h2) -{ - struct hostent *hp1, *hp2; - int status; - - if (strcasecmp (h1, h2) == 0) - return 1; - - if (!is_hostname (h1) || !is_hostname (h2)) - return 0; - - hp1 = gethostbyname (h1); - if (hp1 == NULL) - return 0; - - hp1 = hostent_dup (hp1); - - hp2 = gethostbyname (h2); - if (hp2) - { - if (strcasecmp (hp1->h_name, hp2->h_name) == 0) - status = 1; - else - { - char **ap1, **ap2; - - status = 0; - for (ap1 = hp1->h_addr_list; *ap1 && status == 0; ap1++) - for (ap2 = hp2->h_addr_list; *ap2; ap2++) - if (memcmp (*ap1, *ap2, sizeof (struct in_addr)) == 0) - { - status = 1; - break; - } - } - } - else - status = 0; - - free (hp1); - return status; -} - - -/* Map IP to hostname, and then map back to addr to make sure it is a - * reliable hostname - */ -struct hostent * -get_reliable_hostbyaddr(const char *addr, int len, int type) -{ - struct hostent *hp = NULL; - - struct hostent *reverse; - struct hostent *forward; - char **sp; - - reverse = gethostbyaddr (addr, len, type); - if (!reverse) - return NULL; - - /* must make sure the hostent is authorative. */ - - reverse = hostent_dup (reverse); - forward = gethostbyname (reverse->h_name); - - if (forward) { - /* now make sure the "addr" is in the list */ - for (sp = forward->h_addr_list ; *sp ; sp++) { - if (memcmp (*sp, addr, forward->h_length) == 0) - break; - } - - if (*sp) { - /* it's valid */ - hp = hostent_dup (forward); - } - else { - /* it was a FAKE */ - xlog (L_WARNING, "Fake hostname %s for %s - forward lookup doesn't match reverse", - reverse->h_name, inet_ntoa(*(struct in_addr*)addr)); - } - } - else { - /* never heard of it. misconfigured DNS? */ - xlog (L_WARNING, "Fake hostname %s for %s - forward lookup doesn't exist", - reverse->h_name, inet_ntoa(*(struct in_addr*)addr)); - } - - free (reverse); - return hp; -} - - -#ifdef TEST -void -print_host (struct hostent *hp) -{ - char **sp; - - if (hp) - { - printf ("official hostname: %s\n", hp->h_name); - printf ("aliases:\n"); - for (sp = hp->h_aliases; *sp; sp++) - printf (" %s\n", *sp); - printf ("IP addresses:\n"); - for (sp = hp->h_addr_list; *sp; sp++) - printf (" %s\n", inet_ntoa (*(struct in_addr *) *sp)); - } - else - printf ("Not host information\n"); -} - -int -main (int argc, char **argv) -{ - struct hostent *hp = gethostbyname (argv [1]); - struct hostent *cp; - struct in_addr addr; - - print_host (hp); - - if (hp) - { - cp = hostent_dup (hp); - print_host (cp); - free (cp); - } - printf ("127.0.0.1 == %s: %d\n", argv [1], - matchhostname ("127.0.0.1", argv [1])); - addr.s_addr = inet_addr(argv [2]); - printf ("%s\n", inet_ntoa (addr)); - cp = get_hostent ((const char *)&addr, sizeof(addr), AF_INET); - print_host (cp); - return 0; -} -#endif