blob: 8a23a89b7874466b8146946e5ec65a15b96d57b8 [file] [log] [blame]
/*
* support/export/hostname.c
*
* Functions for hostname.
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
/*
#define TEST
*/
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <xlog.h>
#ifdef TEST
#define xmalloc malloc
#else
#include "xmalloc.h"
#include "misc.h"
#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;
}
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