mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			305 lines
		
	
	
	
		
			8.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			305 lines
		
	
	
	
		
			8.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (c) 1985, 1988, 1993
 | 
						|
 *    The Regents of the University of California.  All rights reserved.
 | 
						|
 * 
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions
 | 
						|
 * are met:
 | 
						|
 * 1. Redistributions of source code must retain the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer.
 | 
						|
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer in the
 | 
						|
 *    documentation and/or other materials provided with the distribution.
 | 
						|
 * 3. All advertising materials mentioning features or use of this software
 | 
						|
 *    must display the following acknowledgement:
 | 
						|
 *      This product includes software developed by the University of
 | 
						|
 *      California, Berkeley and its contributors.
 | 
						|
 * 4. Neither the name of the University nor the names of its contributors
 | 
						|
 *    may be used to endorse or promote products derived from this software
 | 
						|
 *    without specific prior written permission.
 | 
						|
 * 
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 | 
						|
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
						|
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
						|
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 | 
						|
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
						|
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
						|
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
						|
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
						|
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
						|
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
						|
 * SUCH DAMAGE.
 | 
						|
 *
 | 
						|
 * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc.
 | 
						|
 * All Rights Reserved.
 | 
						|
 *
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions
 | 
						|
 * are met: 
 | 
						|
 *
 | 
						|
 * 1. Redistributions of source code must retain the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer. 
 | 
						|
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer in the
 | 
						|
 *    documentation and/or other materials provided with the distribution.
 | 
						|
 * 3. Neither the name of Silicon Graphics, Inc. nor the names of its
 | 
						|
 *    contributors may be used to endorse or promote products derived from
 | 
						|
 *    this software without specific prior written permission. 
 | 
						|
 *
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
						|
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
						|
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
						|
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
						|
 * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
						|
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 | 
						|
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
						|
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 | 
						|
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
						|
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
						|
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 */
 | 
						|
 | 
						|
#include "stx.h"
 | 
						|
 | 
						|
#define MAXPACKET 1024
 | 
						|
 | 
						|
#if !defined(NETDB_INTERNAL) && defined(h_NETDB_INTERNAL)
 | 
						|
#define NETDB_INTERNAL h_NETDB_INTERNAL
 | 
						|
#endif
 | 
						|
 | 
						|
/* New in Solaris 7 */
 | 
						|
#if !defined(_getshort) && defined(ns_get16)
 | 
						|
#define _getshort(cp) ns_get16(cp)
 | 
						|
#define _getlong(cp)  ns_get32(cp)
 | 
						|
#endif
 | 
						|
 | 
						|
typedef union {
 | 
						|
    HEADER hdr;
 | 
						|
    u_char buf[MAXPACKET];
 | 
						|
} querybuf_t;
 | 
						|
 | 
						|
int _stx_dns_ttl;
 | 
						|
 | 
						|
 | 
						|
static int parse_answer(querybuf_t *ans, int len, struct in_addr *addrs,
 | 
						|
			int *num_addrs)
 | 
						|
{
 | 
						|
    char buf[MAXPACKET];
 | 
						|
    HEADER *ahp;
 | 
						|
    u_char *cp, *eoa;
 | 
						|
    int type, n, i;
 | 
						|
 | 
						|
    ahp = &ans->hdr;
 | 
						|
    eoa = ans->buf + len;
 | 
						|
    cp = ans->buf + sizeof(HEADER);
 | 
						|
    h_errno = TRY_AGAIN;
 | 
						|
    _stx_dns_ttl = -1;
 | 
						|
    i = 0;
 | 
						|
 | 
						|
    while (ahp->qdcount > 0) {
 | 
						|
	ahp->qdcount--;
 | 
						|
	cp += dn_skipname(cp, eoa) + QFIXEDSZ;
 | 
						|
    }
 | 
						|
    while (ahp->ancount > 0 && cp < eoa && i < *num_addrs) {
 | 
						|
	ahp->ancount--;
 | 
						|
	if ((n = dn_expand(ans->buf, eoa, cp, buf, sizeof(buf))) < 0)
 | 
						|
	    return -1;
 | 
						|
	cp += n;
 | 
						|
	if (cp + 4 + 4 + 2 >= eoa)
 | 
						|
	    return -1;
 | 
						|
	type = _getshort(cp);
 | 
						|
	cp += 4;
 | 
						|
	if (type == T_A)
 | 
						|
	    _stx_dns_ttl = _getlong(cp);
 | 
						|
	cp += 4;
 | 
						|
	n = _getshort(cp);
 | 
						|
	cp += 2;
 | 
						|
	if (type == T_A) {
 | 
						|
	    if (n > sizeof(*addrs) || cp + n > eoa)
 | 
						|
		return -1;
 | 
						|
	    memcpy(&addrs[i++], cp, n);
 | 
						|
	}
 | 
						|
	cp += n;
 | 
						|
    }
 | 
						|
 | 
						|
    *num_addrs = i;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int query_domain(st_netfd_t nfd, const char *name,
 | 
						|
			struct in_addr *addrs, int *num_addrs,
 | 
						|
			st_utime_t timeout)
 | 
						|
{
 | 
						|
    querybuf_t qbuf;
 | 
						|
    u_char *buf = qbuf.buf;
 | 
						|
    HEADER *hp = &qbuf.hdr;
 | 
						|
    int blen = sizeof(qbuf);
 | 
						|
    int i, len, id;
 | 
						|
 | 
						|
    for (i = 0; i < _res.nscount; i++) {
 | 
						|
	len = res_mkquery(QUERY, name, C_IN, T_A, NULL, 0, NULL, buf, blen);
 | 
						|
	if (len <= 0) {
 | 
						|
	    h_errno = NO_RECOVERY;
 | 
						|
	    return -1;
 | 
						|
	}
 | 
						|
	id = hp->id;
 | 
						|
 | 
						|
	if (st_sendto(nfd, buf, len, (struct sockaddr *)&(_res.nsaddr_list[i]),
 | 
						|
		      sizeof(struct sockaddr), timeout) != len) {
 | 
						|
	    h_errno = NETDB_INTERNAL;
 | 
						|
	    /* EINTR means interrupt by other thread, NOT by a caught signal */
 | 
						|
	    if (errno == EINTR)
 | 
						|
		return -1;
 | 
						|
	    continue;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Wait for reply */
 | 
						|
	do {
 | 
						|
	    len = st_recvfrom(nfd, buf, blen, NULL, NULL, timeout);
 | 
						|
	    if (len <= 0)
 | 
						|
		break;
 | 
						|
	} while (id != hp->id);
 | 
						|
 | 
						|
	if (len < HFIXEDSZ) {
 | 
						|
	    h_errno = NETDB_INTERNAL;
 | 
						|
	    if (len >= 0)
 | 
						|
		errno = EMSGSIZE;
 | 
						|
	    else if (errno == EINTR)  /* see the comment above */
 | 
						|
		return -1;
 | 
						|
	    continue;
 | 
						|
	}
 | 
						|
 | 
						|
	hp->ancount = ntohs(hp->ancount);
 | 
						|
	hp->qdcount = ntohs(hp->qdcount);
 | 
						|
	if ((hp->rcode != NOERROR) || (hp->ancount == 0)) {
 | 
						|
	    switch (hp->rcode) {
 | 
						|
	    case NXDOMAIN:
 | 
						|
		h_errno = HOST_NOT_FOUND;
 | 
						|
		break;
 | 
						|
	    case SERVFAIL:
 | 
						|
		h_errno = TRY_AGAIN;
 | 
						|
		break;
 | 
						|
	    case NOERROR:
 | 
						|
		h_errno = NO_DATA;
 | 
						|
		break;
 | 
						|
	    case FORMERR:
 | 
						|
	    case NOTIMP:
 | 
						|
	    case REFUSED:
 | 
						|
	    default:
 | 
						|
		h_errno = NO_RECOVERY;
 | 
						|
	    }
 | 
						|
	    continue;
 | 
						|
	}
 | 
						|
 | 
						|
	if (parse_answer(&qbuf, len, addrs, num_addrs) == 0)
 | 
						|
	    return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    return -1;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#define CLOSE_AND_RETURN(ret) \
 | 
						|
  {                           \
 | 
						|
    n = errno;                \
 | 
						|
    st_netfd_close(nfd);      \
 | 
						|
    errno = n;                \
 | 
						|
    return (ret);             \
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
int _stx_dns_getaddrlist(const char *host, struct in_addr *addrs,
 | 
						|
                         int *num_addrs, st_utime_t timeout)
 | 
						|
{
 | 
						|
    char name[MAXDNAME], **domain;
 | 
						|
    const char *cp;
 | 
						|
    int s, n, maxlen, dots;
 | 
						|
    int trailing_dot, tried_as_is;
 | 
						|
    st_netfd_t nfd;
 | 
						|
 | 
						|
    if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
 | 
						|
	h_errno = NETDB_INTERNAL;
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
    if (_res.options & RES_USEVC) {
 | 
						|
	h_errno = NETDB_INTERNAL;
 | 
						|
	errno = ENOSYS;
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
    if (!host || *host == '\0') {
 | 
						|
	h_errno = HOST_NOT_FOUND;
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Create UDP socket */
 | 
						|
    if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
 | 
						|
	h_errno = NETDB_INTERNAL;
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
    if ((nfd = st_netfd_open_socket(s)) == NULL) {
 | 
						|
	h_errno = NETDB_INTERNAL;
 | 
						|
	n = errno;
 | 
						|
	close(s);
 | 
						|
	errno = n;
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    maxlen = sizeof(name) - 1;
 | 
						|
    n = 0;
 | 
						|
    dots = 0;
 | 
						|
    trailing_dot = 0;
 | 
						|
    tried_as_is = 0;
 | 
						|
 | 
						|
    for (cp = host; *cp && n < maxlen; cp++) {
 | 
						|
	dots += (*cp == '.');
 | 
						|
	name[n++] = *cp;
 | 
						|
    }
 | 
						|
    if (name[n - 1] == '.')
 | 
						|
	trailing_dot = 1;
 | 
						|
 | 
						|
    /*
 | 
						|
     * If there are dots in the name already, let's just give it a try
 | 
						|
     * 'as is'.  The threshold can be set with the "ndots" option.
 | 
						|
     */
 | 
						|
    if (dots >= _res.ndots) {
 | 
						|
	if (query_domain(nfd, host, addrs, num_addrs, timeout) == 0)
 | 
						|
	    CLOSE_AND_RETURN(0);
 | 
						|
	if (h_errno == NETDB_INTERNAL && errno == EINTR)
 | 
						|
	    CLOSE_AND_RETURN(-1);
 | 
						|
	tried_as_is = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    /*
 | 
						|
     * We do at least one level of search if
 | 
						|
     *     - there is no dot and RES_DEFNAME is set, or
 | 
						|
     *     - there is at least one dot, there is no trailing dot,
 | 
						|
     *       and RES_DNSRCH is set.
 | 
						|
     */
 | 
						|
    if ((!dots && (_res.options & RES_DEFNAMES)) ||
 | 
						|
	(dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
 | 
						|
	name[n++] = '.';
 | 
						|
	for (domain = _res.dnsrch; *domain; domain++) {
 | 
						|
	    strncpy(name + n, *domain, maxlen - n);
 | 
						|
	    if (query_domain(nfd, name, addrs, num_addrs, timeout) == 0)
 | 
						|
		CLOSE_AND_RETURN(0);
 | 
						|
	    if (h_errno == NETDB_INTERNAL && errno == EINTR)
 | 
						|
		CLOSE_AND_RETURN(-1);
 | 
						|
	    if (!(_res.options & RES_DNSRCH))
 | 
						|
		break;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    /*
 | 
						|
     * If we have not already tried the name "as is", do that now.
 | 
						|
     * note that we do this regardless of how many dots were in the
 | 
						|
     * name or whether it ends with a dot.
 | 
						|
     */
 | 
						|
    if (!tried_as_is) {
 | 
						|
	if (query_domain(nfd, host, addrs, num_addrs, timeout) == 0)
 | 
						|
	    CLOSE_AND_RETURN(0);
 | 
						|
    }
 | 
						|
 | 
						|
    CLOSE_AND_RETURN(-1);
 | 
						|
}
 | 
						|
 |