Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postfix/src/util/   (Postfix Mailserver Version 3.11©)  Datei vom 22.11.2025 mit Größe 26 kB image not shown  

Quelle  myaddrinfo.c

  Sprache: C
 

/*++
/* NAME
/* myaddrinfo 3
/* SUMMARY
/* addrinfo encapsulation and emulation
/* SYNOPSIS
/* #include <myaddrinfo.h>
/*
/* #define MAI_V4ADDR_BITS ...
/* #define MAI_V6ADDR_BITS ...
/* #define MAI_V4ADDR_BYTES ...
/* #define MAI_V6ADDR_BYTES ...
/*
/* typedef struct { char buf[....]; } MAI_HOSTNAME_STR;
/* typedef struct { char buf[....]; } MAI_HOSTADDR_STR;
/* typedef struct { char buf[....]; } MAI_SERVNAME_STR;
/* typedef struct { char buf[....]; } MAI_SERVPORT_STR;
/*
/* int hostname_to_sockaddr(hostname, service, socktype, result)
/* const char *hostname;
/* const char *service;
/* int socktype;
/* struct addrinfo **result;
/*
/* int hostname_to_sockaddr_pf(hostname, pf, service, socktype, result)
/* const char *hostname;
/* int pf;
/* const char *service;
/* int socktype;
/* struct addrinfo **result;
/*
/* int hostaddr_to_sockaddr(hostaddr, service, socktype, result)
/* const char *hostaddr;
/* const char *service;
/* int socktype;
/* struct addrinfo **result;
/*
/* int sockaddr_to_hostaddr(sa, salen, hostaddr, portnum, socktype)
/* const struct sockaddr *sa;
/* SOCKADDR_SIZE salen;
/* MAI_HOSTADDR_STR *hostaddr;
/* MAI_SERVPORT_STR *portnum;
/* int socktype;
/*
/* int sockaddr_to_hostname(sa, salen, hostname, service, socktype)
/* const struct sockaddr *sa;
/* SOCKADDR_SIZE salen;
/* MAI_HOSTNAME_STR *hostname;
/* MAI_SERVNAME_STR *service;
/* int socktype;
/*
/* const char *MAI_STRERROR(error)
/* int error;
/* DESCRIPTION
/* This module provides a simplified user interface to the
/* getaddrinfo(3) and getnameinfo(3) routines (which provide
/* a unified interface to manipulate IPv4 and IPv6 socket
/* address structures).
/*
/* On systems without getaddrinfo(3) and getnameinfo(3) support,
/* emulation for IPv4 only can be enabled by defining
/* EMULATE_IPV4_ADDRINFO.
/*
/* hostname_to_sockaddr() looks up the binary addresses for
/* the specified symbolic hostname or numeric address.  The
/* result should be destroyed with freeaddrinfo(). A null host
/* pointer converts to the null host address.
/*
/* hostname_to_sockaddr_pf() is an extended interface that
/* provides a protocol family override.
/*
/* hostaddr_to_sockaddr() converts a printable network address
/* into the corresponding binary form.  The result should be
/* destroyed with freeaddrinfo(). A null host pointer converts
/* to the null host address.
/*
/* sockaddr_to_hostaddr() converts a binary network address
/* into printable form. The result buffers should be large
/* enough to hold the printable address or port including the
/* null terminator.
/* This function strips off the IPv6 datalink suffix.
/*
/* sockaddr_to_hostname() converts a binary network address
/* into a hostname or service.  The result buffer should be
/* large enough to hold the hostname or service including the
/* null terminator. This routine rejects malformed hostnames
/* or numeric hostnames and pretends that the lookup failed.
/*
/* MAI_STRERROR() is an unsafe macro (it evaluates the argument
/* multiple times) that invokes strerror() or gai_strerror()
/* as appropriate.
/*
/* This module exports the following constants that should be
/* user for storage allocation of name or address information:
/* .IP MAI_V4ADDR_BITS
/* .IP MAI_V6ADDR_BITS
/* .IP MAI_V4ADDR_BYTES
/* .IP MAI_V6ADDR_BYTES
/* The number of bits or bytes needed to store a binary
/* IPv4 or IPv6 network address.
/* .PP
/* The types MAI_HOST{NAME,ADDR}_STR and MAI_SERV{NAME,PORT}_STR
/* implement buffers for the storage of the string representations
/* of symbolic or numerical hosts or services. Do not use
/* buffer types other than the ones that are expected here,
/* or things will blow up with buffer overflow problems.
/*
/* Arguments:
/* .IP hostname
/* On input to hostname_to_sockaddr(), a numeric or symbolic
/* hostname, or a null pointer (meaning the wild-card listen
/* address).  On output from sockaddr_to_hostname(), storage
/* for the result hostname, or a null pointer.
/* .IP pf
/* Protocol type: PF_UNSPEC (meaning: use any protocol that is
/* available), PF_INET, or PF_INET6.  This argument is ignored
/* in EMULATE_IPV4_ADDRINFO mode.
/* .IP hostaddr
/* On input to hostaddr_to_sockaddr(), a numeric hostname,
/* or a null pointer (meaning the wild-card listen address).
/* On output from sockaddr_to_hostaddr(), storage for the
/* result hostaddress, or a null pointer.
/* .IP service
/* On input to hostname/addr_to_sockaddr(), a numeric or
/* symbolic service name, or a null pointer in which case the
/* socktype argument is ignored.  On output from
/* sockaddr_to_hostname/addr(), storage for the result service
/* name, or a null pointer.
/* .IP portnum
/* Storage for the result service port number, or a null pointer.
/* .IP socktype
/* Socket type: SOCK_STREAM, SOCK_DGRAM, etc. This argument is
/* ignored when no service or port are specified.
/* .IP sa
/* Protocol-independent socket address structure.
/* .IP salen
/* Protocol-dependent socket address structure size in bytes.
/* SEE ALSO
/* getaddrinfo(3), getnameinfo(3), freeaddrinfo(3), gai_strerror(3)
/* DIAGNOSTICS
/* All routines either return 0 upon success, or an error code
/* that is compatible with gai_strerror().
/*
/* On systems where addrinfo support is emulated by Postfix,
/* some out-of-memory errors are not reported to the caller,
/* but are handled by mymalloc().
/* BUGS
/* The IPv4-only emulation code does not support requests that
/* specify a service but no socket type. It returns an error
/* indication, instead of enumerating all the possible answers.
/*
/* The hostname/addr_to_sockaddr() routines should accept a
/* list of address families that the caller is interested in,
/* and they should return only information of those types.
/*
/* Unfortunately, it is not possible to remove unwanted address
/* family results from hostname_to_sockaddr(), because we
/* don't know how the system library routine getaddrinfo()
/* allocates memory.  For example, getaddrinfo() could save
/* space by referencing the same string object from multiple
/* addrinfo structures; or it could allocate a string object
/* and the addrinfo structure as one memory block.
/*
/* We could get around this by copying getaddrinfo() results
/* to our own private data structures, but that would only
/* make an already expensive API even more expensive.
/*
/* A better workaround is to return a vector of addrinfo
/* pointers to the elements that contain only the elements
/* that the caller is interested in. The pointer to the
/* original getaddrinfo() result can be hidden at the end
/* after the null terminator, or before the first element.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*
/* Wietse Venema
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*--*/


/* System library. */

#include <sys_defs.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>   /* sprintf() */

/* Utility library. */

#include <mymalloc.h>
#include <valid_hostname.h>
#include <sock_addr.h>
#include <stringops.h>
#include <msg.h>
#include <inet_proto.h>
#include <myaddrinfo.h>
#include <split_at.h>
#include <known_tcp_ports.h>

/* Application-specific. */

 /*
  * Use an old trick to save some space: allocate space for two objects in
  * one. In Postfix we often use this trick for structures that have an array
  * of things at the end.
  */

struct ipv4addrinfo {
    struct addrinfo info;
    struct sockaddr_in sin;
};

 /*
  * When we're not interested in service ports, we must pick a socket type
  * otherwise getaddrinfo() will give us duplicate results: one set for TCP,
  * and another set for UDP. For consistency, we'll use the same default
  * socket type for the results from emulation mode.
  */

#define MAI_SOCKTYPE SOCK_STREAM /* getaddrinfo() query */

#ifdef EMULATE_IPV4_ADDRINFO

/* clone_ipv4addrinfo - clone ipv4addrinfo structure */

static struct ipv4addrinfo *clone_ipv4addrinfo(struct ipv4addrinfo * tp)
{
    struct ipv4addrinfo *ip;

    ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
    *ip = *tp;
    ip->info.ai_addr = (struct sockaddr *) &(ip->sin);
    return (ip);
}

/* init_ipv4addrinfo - initialize an ipv4addrinfo structure */

static void init_ipv4addrinfo(struct ipv4addrinfo * ip, int socktype)
{

    /*
     * Portability: null pointers aren't necessarily all-zero bits, so we
     * make explicit assignments to all the pointers that we're aware of.
     */

    memset((void *) ip, 0sizeof(*ip));
    ip->info.ai_family = PF_INET;
    ip->info.ai_socktype = socktype;
    ip->info.ai_protocol = 0;   /* XXX */
    ip->info.ai_addrlen = sizeof(ip->sin);
    ip->info.ai_canonname = 0;
    ip->info.ai_addr = (struct sockaddr *) &(ip->sin);
    ip->info.ai_next = 0;
    ip->sin.sin_family = AF_INET;
#ifdef HAS_SA_LEN
    ip->sin.sin_len = sizeof(ip->sin);
#endif
}

/* find_service - translate numeric or symbolic service name */

static int find_service(const char *service, int socktype)
{
    struct servent *sp;
    const char *proto;
    unsigned port;

    service = filter_known_tcp_port(service);
    if (alldig(service)) {
 port = atoi(service);
 return (port < 65536 ? htons(port) : -1);
    }
    if (socktype == SOCK_STREAM) {
 proto = "tcp";
    } else if (socktype == SOCK_DGRAM) {
 proto = "udp";
    } else {
 return (-1);
    }
    if ((sp = getservbyname(service, proto)) != 0) {
 return (sp->s_port);
    } else {
 return (-1);
    }
}

#endif

/* hostname_to_sockaddr_pf - hostname to binary address form */

int     hostname_to_sockaddr_pf(const char *hostname, int pf,
            const char *service, int socktype,
            struct addrinfo ** res)
{
#ifdef EMULATE_IPV4_ADDRINFO

    /*
     * Emulated getaddrinfo(3) version.
     */

    static struct ipv4addrinfo template;
    struct ipv4addrinfo *ip;
    struct ipv4addrinfo *prev;
    struct in_addr addr;
    struct hostent *hp;
    char  **name_list;
    int     port;

    /*
     * Validate the service.
     */

    if (service) {
 if ((port = find_service(service, socktype)) < 0)
     return (EAI_SERVICE);
    } else {
 port = 0;
 socktype = MAI_SOCKTYPE;
    }

    /*
     * No host means INADDR_ANY.
     */

    if (hostname == 0) {
 ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
 init_ipv4addrinfo(ip, socktype);
 ip->sin.sin_addr.s_addr = INADDR_ANY;
 ip->sin.sin_port = port;
 *res = &(ip->info);
 return (0);
    }

    /*
     * Numeric host.
     */

    if (inet_pton(AF_INET, hostname, (void *) &addr) == 1) {
 ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
 init_ipv4addrinfo(ip, socktype);
 ip->sin.sin_addr = addr;
 ip->sin.sin_port = port;
 *res = &(ip->info);
 return (0);
    }

    /*
     * Look up the IPv4 address list.
     */

    if ((hp = gethostbyname(hostname)) == 0)
 return (h_errno == TRY_AGAIN ? EAI_AGAIN : EAI_NODATA);
    if (hp->h_addrtype != AF_INET
 || hp->h_length != sizeof(template.sin.sin_addr))
 return (EAI_NODATA);

    /*
     * Initialize the result template.
     */

    if (template.info.ai_addrlen == 0)
 init_ipv4addrinfo(&template, socktype);

    /*
     * Copy the address information into an addrinfo structure.
     */

    prev = &template;
    for (name_list = hp->h_addr_list; name_list[0]; name_list++) {
 ip = clone_ipv4addrinfo(prev);
 ip->sin.sin_addr = IN_ADDR(name_list[0]);
 ip->sin.sin_port = port;
 if (prev == &template)
     *res = &(ip->info);
 else
     prev->info.ai_next = &(ip->info);
 prev = ip;
    }
    return (0);
#else

    /*
     * Native getaddrinfo(3) version.
     * 
     * XXX Wild-card listener issues.
     * 
     * With most IPv4 plus IPv6 systems, an IPv6 wild-card listener also listens
     * on the IPv4 wild-card address. Connections from IPv4 clients appear as
     * IPv4-in-IPv6 addresses; when Postfix support for IPv4 is turned on,
     * Postfix automatically maps these embedded addresses to their original
     * IPv4 form. So everything seems to be fine.
     * 
     * However, some applications prefer to use separate listener sockets for
     * IPv4 and IPv6. The Postfix IPv6 patch provided such an example. And
     * this is where things become tricky. On many systems the IPv6 and IPv4
     * wild-card listeners cannot coexist. When one is already active, the
     * other fails with EADDRINUSE. Solaris 9, however, will automagically
     * "do the right thing" and allow both listeners to coexist.
     * 
     * Recent systems have the IPV6_V6ONLY feature (RFC 3493), which tells the
     * system that we really mean IPv6 when we say IPv6. This allows us to
     * set up separate wild-card listener sockets for IPv4 and IPv6. So
     * everything seems to be fine again.
     * 
     * The following workaround disables the wild-card IPv4 listener when
     * IPV6_V6ONLY is unavailable. This is necessary for some Linux versions,
     * but is not needed for Solaris 9 (which allows IPv4 and IPv6 wild-card
     * listeners to coexist). Solaris 10 beta already has IPV6_V6ONLY.
     * 
     * XXX This workaround obviously breaks if we want to support protocols in
     * addition to IPv6 and IPv4, but it is needed only until IPv6
     * implementations catch up with RFC 3493. A nicer fix is to filter the
     * getaddrinfo() result, and to return a vector of addrinfo pointers to
     * only those types of elements that the caller has expressed interested
     * in.
     * 
     * XXX Vanilla AIX 5.1 getaddrinfo() does not support a null hostname with
     * AI_PASSIVE. And since we don't know how getaddrinfo() manages its
     * memory we can't bypass it for this special case, or freeaddrinfo()
     * might blow up. Instead we turn off IPV6_V6ONLY in inet_listen(), and
     * supply a protocol-dependent hard-coded string value to getaddrinfo()
     * below, so that it will convert into the appropriate wild-card address.
     * 
     * XXX AIX 5.[1-3] getaddrinfo() may return a non-null port when a null
     * service argument is specified.
     */

    struct addrinfo hints;
    int     err;

    memset((void *) &hints, 0sizeof(hints));
    hints.ai_family = (pf != PF_UNSPEC) ? pf : inet_proto_info()->ai_family;
    hints.ai_socktype = service ? socktype : MAI_SOCKTYPE;
    if (!hostname) {
 hints.ai_flags = AI_PASSIVE;
#if !defined(IPV6_V6ONLY) || defined(BROKEN_AI_PASSIVE_NULL_HOST)
 switch (hints.ai_family) {
 case PF_UNSPEC:
     hints.ai_family = PF_INET6;
#ifdef BROKEN_AI_PASSIVE_NULL_HOST
 case PF_INET6:
     hostname = "::";
     break;
 case PF_INET:
     hostname = "0.0.0.0";
     break;
#endif
 }
#endif
    }
    if (service) {
 service = filter_known_tcp_port(service);
 if (alldig(service))
     hints.ai_flags |= AI_NUMERICSERV;
    }
    err = getaddrinfo(hostname, service, &hints, res);
#if defined(BROKEN_AI_NULL_SERVICE)
    if (service == 0 && err == 0) {
 struct addrinfo *r;
 unsigned short *portp;

 for (r = *res; r != 0; r = r->ai_next)
     if (*(portp = SOCK_ADDR_PORTP(r->ai_addr)) != 0)
  *portp = 0;
    }
#endif
    return (err);
#endif
}

/* hostaddr_to_sockaddr - printable address to binary address form */

int     hostaddr_to_sockaddr(const char *hostaddr, const char *service,
                int socktype, struct addrinfo ** res)
{
#ifdef EMULATE_IPV4_ADDRINFO

    /*
     * Emulated getaddrinfo(3) version.
     */

    struct ipv4addrinfo *ip;
    struct in_addr addr;
    int     port;

    /*
     * Validate the service.
     */

    if (service) {
 if ((port = find_service(service, socktype)) < 0)
     return (EAI_SERVICE);
    } else {
 port = 0;
 socktype = MAI_SOCKTYPE;
    }

    /*
     * No host means INADDR_ANY.
     */

    if (hostaddr == 0) {
 ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
 init_ipv4addrinfo(ip, socktype);
 ip->sin.sin_addr.s_addr = INADDR_ANY;
 ip->sin.sin_port = port;
 *res = &(ip->info);
 return (0);
    }

    /*
     * Deal with bad address forms.
     */

    switch (inet_pton(AF_INET, hostaddr, (void *) &addr)) {
    case 1:     /* Success */
 break;
    default:     /* Unparsable */
 return (EAI_NONAME);
    case -1:     /* See errno */
 return (EAI_SYSTEM);
    }

    /*
     * Initialize the result structure.
     */

    ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
    init_ipv4addrinfo(ip, socktype);

    /*
     * And copy the result.
     */

    ip->sin.sin_addr = addr;
    ip->sin.sin_port = port;
    *res = &(ip->info);

    return (0);
#else

    /*
     * Native getaddrinfo(3) version. See comments in hostname_to_sockaddr().
     * 
     * XXX Vanilla AIX 5.1 getaddrinfo() returns multiple results when
     * converting a printable ipv4 or ipv6 address to socket address with
     * ai_family=PF_UNSPEC, ai_flags=AI_NUMERICHOST, ai_socktype=SOCK_STREAM,
     * ai_protocol=0 or IPPROTO_TCP, and service=0. The workaround is to
     * ignore all but the first result.
     * 
     * XXX AIX 5.[1-3] getaddrinfo() may return a non-null port when a null
     * service argument is specified.
     */

    struct addrinfo hints;
    int     err;

    memset(&hints, 0sizeof(hints));
    hints.ai_family = inet_proto_info()->ai_family;
    hints.ai_socktype = service ? socktype : MAI_SOCKTYPE;
    hints.ai_flags = AI_NUMERICHOST;
    if (!hostaddr) {
 hints.ai_flags |= AI_PASSIVE;
#if !defined(IPV6_V6ONLY) || defined(BROKEN_AI_PASSIVE_NULL_HOST)
 switch (hints.ai_family) {
 case PF_UNSPEC:
     hints.ai_family = PF_INET6;
#ifdef BROKEN_AI_PASSIVE_NULL_HOST
 case PF_INET6:
     hostaddr = "::";
     break;
 case PF_INET:
     hostaddr = "0.0.0.0";
     break;
#endif
 }
#endif
    }
    if (service) {
 service = filter_known_tcp_port(service);
 if (alldig(service))
     hints.ai_flags |= AI_NUMERICSERV;
    }
    err = getaddrinfo(hostaddr, service, &hints, res);
#if defined(BROKEN_AI_NULL_SERVICE)
    if (service == 0 && err == 0) {
 struct addrinfo *r;
 unsigned short *portp;

 for (r = *res; r != 0; r = r->ai_next)
     if (*(portp = SOCK_ADDR_PORTP(r->ai_addr)) != 0)
  *portp = 0;
    }
#endif
    return (err);
#endif
}

/* sockaddr_to_hostaddr - binary address to printable address form */

int     sockaddr_to_hostaddr(const struct sockaddr *sa, SOCKADDR_SIZE salen,
                MAI_HOSTADDR_STR *hostaddr,
                MAI_SERVPORT_STR *portnum,
                int unused_socktype)
{
#ifdef EMULATE_IPV4_ADDRINFO
    char    portbuf[sizeof("65535")];
    ssize_t len;

    /*
     * Emulated getnameinfo(3) version. The buffer length includes the space
     * for the null terminator.
     */

    if (sa->sa_family != AF_INET) {
 errno = EAFNOSUPPORT;
 return (EAI_SYSTEM);
    }
    if (hostaddr != 0) {
 if (inet_ntop(AF_INET, (void *) &(SOCK_ADDR_IN_ADDR(sa)),
        hostaddr->buf, sizeof(hostaddr->buf)) == 0)
     return (EAI_SYSTEM);
    }
    if (portnum != 0) {
 sprintf(portbuf, "%d", ntohs(SOCK_ADDR_IN_PORT(sa)) & 0xffff);
 if ((len = strlen(portbuf)) >= sizeof(portnum->buf)) {
     errno = ENOSPC;
     return (EAI_SYSTEM);
 }
 memcpy(portnum->buf, portbuf, len + 1);
    }
    return (0);
#else
    int     ret;

    /*
     * Native getnameinfo(3) version.
     */

    ret = getnameinfo(sa, salen,
        hostaddr ? hostaddr->buf : (char *) 0,
        hostaddr ? sizeof(hostaddr->buf) : 0,
        portnum ? portnum->buf : (char *) 0,
        portnum ? sizeof(portnum->buf) : 0,
        NI_NUMERICHOST | NI_NUMERICSERV);
    if (hostaddr != 0 && ret == 0 && sa->sa_family == AF_INET6)
 (void) split_at(hostaddr->buf, '%');
    return (ret);
#endif
}

/* sockaddr_to_hostname - binary address to printable hostname */

int     sockaddr_to_hostname(const struct sockaddr *sa, SOCKADDR_SIZE salen,
                MAI_HOSTNAME_STR *hostname,
                MAI_SERVNAME_STR *service,
                int socktype)
{
#ifdef EMULATE_IPV4_ADDRINFO

    /*
     * Emulated getnameinfo(3) version.
     */

    struct hostent *hp;
    struct servent *sp;
    size_t  len;

    /*
     * Sanity check.
     */

    if (sa->sa_family != AF_INET)
 return (EAI_NODATA);

    /*
     * Look up the host name.
     */

    if (hostname != 0) {
 if ((hp = gethostbyaddr((char *) &(SOCK_ADDR_IN_ADDR(sa)),
    sizeof(SOCK_ADDR_IN_ADDR(sa)),
    AF_INET)) == 0)
     return (h_errno == TRY_AGAIN ? EAI_AGAIN : EAI_NONAME);

 /*
  * Save the result. The buffer length includes the space for the null
  * terminator. Hostname sanity checks are at the end of this
  * function.
 */

 if ((len = strlen(hp->h_name)) >= sizeof(hostname->buf)) {
     errno = ENOSPC;
     return (EAI_SYSTEM);
 }
 memcpy(hostname->buf, hp->h_name, len + 1);
    }

    /*
     * Look up the service.
     */

    if (service != 0) {
 if ((sp = getservbyport(ntohs(SOCK_ADDR_IN_PORT(sa)),
         socktype == SOCK_DGRAM ? "udp" : "tcp")) == 0)
     return (EAI_NONAME);

 /*
  * Save the result. The buffer length includes the space for the null
  * terminator.
 */

 if ((len = strlen(sp->s_name)) >= sizeof(service->buf)) {
     errno = ENOSPC;
     return (EAI_SYSTEM);
 }
 memcpy(service->buf, sp->s_name, len + 1);
    }
#else

    /*
     * Native getnameinfo(3) version.
     */

    int     err;

    err = getnameinfo(sa, salen,
        hostname ? hostname->buf : (char *) 0,
        hostname ? sizeof(hostname->buf) : 0,
        service ? service->buf : (char *) 0,
        service ? sizeof(service->buf) : 0,
        socktype == SOCK_DGRAM ?
        NI_NAMEREQD | NI_DGRAM : NI_NAMEREQD);
    if (err != 0)
 return (err);
#endif

    /*
     * Hostname sanity checks.
     */

    if (hostname != 0) {
 if (valid_hostaddr(hostname->buf, DONT_GRIPE)) {
     msg_warn("numeric hostname: %s", hostname->buf);
     return (EAI_NONAME);
 }
 if (!valid_hostname(hostname->buf, DO_GRIPE))
     return (EAI_NONAME);
    }
    return (0);
}

/* myaddrinfo_control - fine control */

void    myaddrinfo_control(int name,...)
{
    const char *myname = "myaddrinfo_control";
    va_list ap;

    for (va_start(ap, name); name != 0; name = va_arg(ap, int)) {
 switch (name) {
 default:
     msg_panic("%s: bad name %d", myname, name);
 }
    }
    va_end(ap);
}

#ifdef EMULATE_IPV4_ADDRINFO

/* freeaddrinfo - release storage */

void    freeaddrinfo(struct addrinfo * ai)
{
    struct addrinfo *ap;
    struct addrinfo *next;

    /*
     * Artifact of implementation: tolerate a null pointer argument.
     */

    for (ap = ai; ap != 0; ap = next) {
 next = ap->ai_next;
 if (ap->ai_canonname)
     myfree(ap->ai_canonname);
 /* ap->ai_addr is allocated within this memory block */
 myfree((void *) ap);
    }
}

static char *ai_errlist[] = {
    "Success",
    "Address family for hostname not supported"/* EAI_ADDRFAMILY */
    "Temporary failure in name resolution"/* EAI_AGAIN  */
    "Invalid value for ai_flags"/* EAI_BADFLAGS   */
    "Non-recoverable failure in name resolution"/* EAI_FAIL  */
    "ai_family not supported",  /* EAI_FAMILY     */
    "Memory allocation failure"/* EAI_MEMORY     */
    "No address associated with hostname"/* EAI_NODATA     */
    "hostname nor servname provided, or not known"/* EAI_NONAME     */
    "service name not supported for ai_socktype"/* EAI_SERVICE    */
    "ai_socktype not supported"/* EAI_SOCKTYPE   */
    "System error returned in errno"/* EAI_SYSTEM     */
    "Invalid value for hints",  /* EAI_BADHINTS   */
    "Resolved protocol is unknown"/* EAI_PROTOCOL   */
    "Unknown error",   /* EAI_MAX   */
};

/* gai_strerror - error number to string */

char   *gai_strerror(int ecode)
{

    /*
     * Note: EAI_SYSTEM errors are not automatically handed over to
     * strerror(). The application decides.
     */

    if (ecode < 0 || ecode > EAI_MAX)
 ecode = EAI_MAX;
    return (ai_errlist[ecode]);
}

#endif

#ifdef TEST

 /*
  * A test program that takes some info from the command line and runs it
  * forward and backward through the above conversion routines.
  */

#include <stdlib.h>
#include <msg.h>
#include <vstream.h>
#include <msg_vstream.h>

static int compare_family(const void *a, const void *b)
{
    struct addrinfo *resa = *(struct addrinfo **) a;
    struct addrinfo *resb = *(struct addrinfo **) b;

    return (resa->ai_family - resb->ai_family);
}

int     main(int argc, char **argv)
{
    struct addrinfo *info;
    struct addrinfo *ip;
    struct addrinfo **resv;
    MAI_HOSTNAME_STR host;
    MAI_HOSTADDR_STR addr;
    MAI_SERVNAME_STR serv;
    MAI_SERVPORT_STR port;
    size_t  len, n;
    int     err;
    char   *aport;

    msg_vstream_init(argv[0], VSTREAM_ERR);

    if (argc != 4)
 msg_fatal("usage: %s protocols hostname hostaddress", argv[0]);

    inet_proto_init(argv[0], argv[1]);

    msg_info("=== hostname %s ===", argv[2]);

#define STR_OR_NULL(s) ((s) ? (s) : "(null)")

    aport = split_at(argv[2], ':');
    if ((err = hostname_to_sockaddr(argv[2], aport, 0, &info)) != 0) {
 msg_warn("hostname_to_sockaddr(%s:%s): %s",
   argv[2], STR_OR_NULL(aport), err == EAI_SYSTEM ?
   strerror(errno) : gai_strerror(err));
    } else {
 for (len = 0, ip = info; ip != 0; ip = ip->ai_next)
     len += 1;
 resv = (struct addrinfo **) mymalloc(len * sizeof(*resv));
 for (len = 0, ip = info; ip != 0; ip = ip->ai_next)
     resv[len++] = ip;
 qsort((void *) resv, len, sizeof(*resv), compare_family);
 for (n = 0; n < len; n++) {
     ip = resv[n];
     if ((err = sockaddr_to_hostaddr(ip->ai_addr, ip->ai_addrlen, &addr,
         &port, 0)) != 0) {
  msg_warn("sockaddr_to_hostaddr: %s",
     err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
  continue;
     }
     msg_info("%s:%s -> family=%d sock=%d proto=%d %s:%s",
       argv[2], STR_OR_NULL(aport), ip->ai_family,
       ip->ai_socktype, ip->ai_protocol, addr.buf, port.buf);
     if ((err = sockaddr_to_hostname(ip->ai_addr, ip->ai_addrlen, &host,
         &serv, 0)) != 0) {
  msg_warn("sockaddr_to_hostname: %s",
     err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
  continue;
     }
     msg_info("%s:%s -> %s:%s", addr.buf, port.buf, host.buf, serv.buf);
 }
 freeaddrinfo(info);
 myfree((void *) resv);
    }

    msg_info("=== host address %s ===", argv[3]);

    aport = split_at(argv[3], ':');
    if ((err = hostaddr_to_sockaddr(argv[3], aport, 0, &ip)) != 0) {
 msg_warn("hostaddr_to_sockaddr(%s:%s): %s",
   argv[3], STR_OR_NULL(aport), err == EAI_SYSTEM ?
   strerror(errno) : gai_strerror(err));
    } else {
 if ((err = sockaddr_to_hostaddr(ip->ai_addr, ip->ai_addrlen, &addr,
     &port, 0)) != 0) {
     msg_warn("sockaddr_to_hostaddr: %s",
     err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
 } else {
     msg_info("%s:%s -> family=%d sock=%d proto=%d %s:%s", argv[3], STR_OR_NULL(aport),
       ip->ai_family, ip->ai_socktype, ip->ai_protocol, addr.buf, port.buf);
     if ((err = sockaddr_to_hostname(ip->ai_addr, ip->ai_addrlen, &host,
         &serv, 0)) != 0) {
  msg_warn("sockaddr_to_hostname: %s",
     err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
     } else
  msg_info("%s:%s -> %s:%s", addr.buf, port.buf, host.buf, serv.buf);
     freeaddrinfo(ip);
 }
    }
    exit(0);
}

#endif

Messung V0.5 in Prozent
C=74 H=95 G=84

¤ Dauer der Verarbeitung: 0.20 Sekunden  (vorverarbeitet am  2026-08-10) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.