view usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/inet.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
line wrap: on
line source

/*
 * Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"@(#)inet.c	1.3	03/05/09 SMI"

/*
 * Utility functions which help with address and hostname manipulation in a
 * mixed IPv4 / IPv6 environment.
 */

#include "config.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include "proto.h"

#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif

/* Converts a hostname into an IP address in presentation form */
char *inet_htop(const char *hostname)
{
#ifdef INET6
    static char abuf[INET6_ADDRSTRLEN];
    struct addrinfo hints, *result;
    char *str = NULL;
    void *addr = NULL;

    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_CANONNAME;
    hints.ai_family = PF_UNSPEC;

    if (getaddrinfo(hostname, NULL, &hints, &result) == 0) {
	if (result->ai_family == AF_INET)
	    addr = ((void *)&((struct sockaddr_in *)result->ai_addr)->sin_addr);
	else if (result->ai_family == AF_INET6)
	    addr = ((void *)&((struct sockaddr_in6 *)result->ai_addr)->sin6_addr);
	if (addr)
	    str = (char *)inet_ntop_native(result->ai_family, addr, abuf,
					   sizeof(abuf));
	freeaddrinfo(result);
	return str;
    }
#else
    struct hostent *hp;
    struct in_addr in;

    if ((hp = gethostbyname(hostname)) != NULL) {
	memcpy(&in, hp->h_addr, sizeof(in));
	return inet_ntoa(in);
    }
#endif
    return NULL;
}

/*
 * Converts a socket structures IP address into presentation form.
 * Note: returns a pointer to a buffer which is overwritten on each call.
 */
char *inet_stop(struct SOCKSTORAGE *ss)
{
#ifdef INET6
    static char abuf[INET6_ADDRSTRLEN];
    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss;

    if (ss->ss_family == AF_INET6)
        return (char *)inet_ntop_native(AF_INET6, &sin6->sin6_addr, abuf, sizeof (abuf));
#endif
    return inet_ntoa(((struct sockaddr_in *)ss)->sin_addr);
}

char *wu_gethostbyname(const char *hostname)
{
#ifdef INET6
    static char hostbuf[MAXHOSTNAMELEN];
    struct addrinfo hints, *result;

    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_CANONNAME;
    hints.ai_family = PF_UNSPEC;

    if (getaddrinfo(hostname, NULL, &hints, &result) == 0) {
	strncpy(hostbuf, result->ai_canonname, sizeof(hostbuf));
	hostbuf[sizeof(hostbuf) - 1] = '\0';
	freeaddrinfo(result);
	return hostbuf;
    }
#else
    struct hostent *hp = gethostbyname(hostname);

    if (hp)
	return hp->h_name;
#endif
    return NULL;
}

int wu_gethostbyaddr(struct SOCKSTORAGE *ss, char *hostname, int hostlen)
{
#ifdef INET6
    char hostbuf[NI_MAXHOST];
#else
    struct hostent *hp;
#endif

    if ((ss == NULL) || (hostname == NULL) || (hostlen < 1))
	return 0;

#ifdef INET6
    if (getnameinfo((struct sockaddr *)ss, SOCK_LEN(*ss), hostbuf,
		    sizeof(hostbuf), NULL, 0, NI_NAMEREQD) == 0) {
	strncpy(hostname, hostbuf, hostlen);
	hostname[hostlen - 1] = '\0';
	return 1;
    }
#else
    hp = gethostbyaddr((char *)&ss->sin_addr, sizeof(struct in_addr), AF_INET);
    if (hp) {
	strncpy(hostname, hp->h_name, hostlen);
	hostname[hostlen - 1] = '\0';
	return 1;
    }
#endif
    return 0;
}

/* Compares a socket structures IP address with addr, returning 0 on a match */
int sock_cmp_inaddr(struct SOCKSTORAGE *ss, struct in_addr addr) {
#ifdef INET6
    if (ss->ss_family == AF_INET6) {
	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss;

	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
	    u_char *a = (u_char *)&sin6->sin6_addr;

	    /* compare the IPv4 part of an IPv4-mapped IPv6 address */
	    return memcmp(&addr, a + sizeof(struct in6_addr) - sizeof(struct in_addr), sizeof(struct in_addr));
	}
	return 1;
    }
#endif
    return ((struct sockaddr_in *)ss)->sin_addr.s_addr != addr.s_addr;
}

#ifdef INET6
/* Sets a socket structures IP address to addr */
void sock_set_inaddr(struct SOCKSTORAGE *ss, struct in_addr addr) {
    if (ss->ss_family == AF_INET6) {
	struct in6_addr *in6;

	in6 = &((struct sockaddr_in6 *)ss)->sin6_addr;
	memset(&in6->s6_addr[0], 0, 10);
	memset(&in6->s6_addr[10], 0xff, 2);
	memcpy(&in6->s6_addr[12], &addr, sizeof(struct in_addr));
	return;
    }
    ((struct sockaddr_in *)ss)->sin_addr = addr;
}

/* Compares two socket structure IP addresses, returning 0 if they match */
int sock_cmp_addr(struct SOCKSTORAGE *ss1, struct SOCKSTORAGE *ss2) {
    if (ss1->ss_family == AF_INET6) {
	if (ss2->ss_family == AF_INET6)
	    return memcmp(&((struct sockaddr_in6 *)ss1)->sin6_addr,
			  &((struct sockaddr_in6 *)ss2)->sin6_addr,
			  sizeof(struct in6_addr));
	return sock_cmp_inaddr(ss1, ((struct sockaddr_in *)ss2)->sin_addr);
    }
    return sock_cmp_inaddr(ss2, ((struct sockaddr_in *)ss1)->sin_addr);
}

void sock_set_scope(struct SOCKSTORAGE *dst, struct SOCKSTORAGE *src) {
#ifdef HAVE_SIN6_SCOPE_ID
    struct sockaddr_in6 *src_in6 = (struct sockaddr_in6 *)src;
    struct sockaddr_in6 *dst_in6 = (struct sockaddr_in6 *)dst;

    if (dst->ss_family == AF_INET6) {
	if ((src->ss_family == AF_INET6) &&
	    (memcmp(&src_in6->sin6_addr, &dst_in6->sin6_addr,
		    sizeof(struct in6_addr)) == 0))
	    dst_in6->sin6_scope_id = src_in6->sin6_scope_id;
	else
	    dst_in6->sin6_scope_id = 0;
    }
#endif
}

/*
 * Similar to inet_pton(), str can be an IPv4 or IPv6 address, but an IPv6
 * address is returned in addr.
 */
int inet_pton6(char *str, struct in6_addr *addr)
{
    struct in_addr v4addr;

    /* Try v6 first */
    if (inet_pton(AF_INET6, str, addr) != 1) {
	/* If that fails, try v4 and map it */
	if (inet_pton(AF_INET, str, &v4addr) == 1) {
	    memset(&addr->s6_addr[0], 0, 10);
	    memset(&addr->s6_addr[10], 0xff, 2);
	    memcpy(&addr->s6_addr[12], &v4addr, sizeof(struct in_addr));
	}
	else
	    return 0;
    }
    return 1;
}

/*
 * Similar to inet_ntop(), except when addr is an IPv4-mapped IPv6 address
 * returns a printable IPv4 address (not an IPv4-mapped IPv6 address).
 */
const char *inet_ntop_native(int af, const void *addr, char *dst, size_t size)
{
    const char *result;

    if (af == AF_INET6) {
	if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr))
	    result = inet_ntop(AF_INET, (char *)addr + sizeof(struct in6_addr)
			       - sizeof(struct in_addr), dst, size);
	else
	    result = inet_ntop(AF_INET6, addr, dst, size);
    }
    else
	result = inet_ntop(af, addr, dst, size);
    return result;
}
#endif /* INET6 */