Annotation of embedaddon/php/ext/standard/dns.c, revision 1.1

1.1     ! misho       1: /*
        !             2:    +----------------------------------------------------------------------+
        !             3:    | PHP Version 5                                                        |
        !             4:    +----------------------------------------------------------------------+
        !             5:    | Copyright (c) 1997-2012 The PHP Group                                |
        !             6:    +----------------------------------------------------------------------+
        !             7:    | This source file is subject to version 3.01 of the PHP license,      |
        !             8:    | that is bundled with this package in the file LICENSE, and is        |
        !             9:    | available through the world-wide-web at the following url:           |
        !            10:    | http://www.php.net/license/3_01.txt                                  |
        !            11:    | If you did not receive a copy of the PHP license and are unable to   |
        !            12:    | obtain it through the world-wide-web, please send a note to          |
        !            13:    | license@php.net so we can mail you a copy immediately.               |
        !            14:    +----------------------------------------------------------------------+
        !            15:    | Authors: The typical suspects                                        |
        !            16:    |          Pollita <pollita@php.net>                                   |
        !            17:    |          Marcus Boerger <helly@php.net>                              |
        !            18:    +----------------------------------------------------------------------+
        !            19:  */
        !            20: 
        !            21: /* $Id: dns.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            22: 
        !            23: /* {{{ includes */
        !            24: #include "php.h"
        !            25: #include "php_network.h"
        !            26: 
        !            27: #if HAVE_SYS_SOCKET_H
        !            28: #include <sys/socket.h>
        !            29: #endif
        !            30: 
        !            31: #ifdef PHP_WIN32
        !            32: # include "win32/inet.h"
        !            33: # include <winsock2.h>
        !            34: # include <windows.h>
        !            35: # include <Ws2tcpip.h>
        !            36: #else  /* This holds good for NetWare too, both for Winsock and Berkeley sockets */
        !            37: #include <netinet/in.h>
        !            38: #if HAVE_ARPA_INET_H
        !            39: #include <arpa/inet.h>
        !            40: #endif
        !            41: #include <netdb.h>
        !            42: #ifdef _OSD_POSIX
        !            43: #undef STATUS
        !            44: #undef T_UNSPEC
        !            45: #endif
        !            46: #if HAVE_ARPA_NAMESER_H
        !            47: #ifdef DARWIN
        !            48: # define BIND_8_COMPAT 1
        !            49: #endif
        !            50: #include <arpa/nameser.h>
        !            51: #endif
        !            52: #if HAVE_RESOLV_H
        !            53: #include <resolv.h>
        !            54: #endif
        !            55: #ifdef HAVE_DNS_H
        !            56: #include <dns.h>
        !            57: #endif
        !            58: #endif
        !            59: 
        !            60: /* Borrowed from SYS/SOCKET.H */
        !            61: #if defined(NETWARE) && defined(USE_WINSOCK)
        !            62: #define AF_INET 2   /* internetwork: UDP, TCP, etc. */
        !            63: #endif
        !            64: 
        !            65: #ifndef MAXHOSTNAMELEN
        !            66: #define MAXHOSTNAMELEN 255
        !            67: #endif
        !            68: 
        !            69: /* For the local hostname obtained via gethostname which is different from the
        !            70:    dns-related MAXHOSTNAMELEN constant above */
        !            71: #ifndef HOST_NAME_MAX
        !            72: #define HOST_NAME_MAX 255
        !            73: #endif
        !            74: 
        !            75: #include "php_dns.h"
        !            76: 
        !            77: /* type compat */
        !            78: #ifndef DNS_T_A
        !            79: #define DNS_T_A                1
        !            80: #endif
        !            81: #ifndef DNS_T_NS
        !            82: #define DNS_T_NS       2
        !            83: #endif
        !            84: #ifndef DNS_T_CNAME
        !            85: #define DNS_T_CNAME    5
        !            86: #endif
        !            87: #ifndef DNS_T_SOA
        !            88: #define DNS_T_SOA      6
        !            89: #endif
        !            90: #ifndef DNS_T_PTR
        !            91: #define DNS_T_PTR      12
        !            92: #endif
        !            93: #ifndef DNS_T_HINFO
        !            94: #define DNS_T_HINFO    13
        !            95: #endif
        !            96: #ifndef DNS_T_MINFO
        !            97: #define DNS_T_MINFO    14
        !            98: #endif
        !            99: #ifndef DNS_T_MX
        !           100: #define DNS_T_MX       15
        !           101: #endif
        !           102: #ifndef DNS_T_TXT
        !           103: #define DNS_T_TXT      16
        !           104: #endif
        !           105: #ifndef DNS_T_AAAA
        !           106: #define DNS_T_AAAA     28
        !           107: #endif
        !           108: #ifndef DNS_T_SRV
        !           109: #define DNS_T_SRV      33
        !           110: #endif
        !           111: #ifndef DNS_T_NAPTR
        !           112: #define DNS_T_NAPTR    35
        !           113: #endif
        !           114: #ifndef DNS_T_A6
        !           115: #define DNS_T_A6       38
        !           116: #endif
        !           117: 
        !           118: #ifndef DNS_T_ANY
        !           119: #define DNS_T_ANY      255
        !           120: #endif
        !           121: /* }}} */
        !           122: 
        !           123: static char *php_gethostbyaddr(char *ip);
        !           124: static char *php_gethostbyname(char *name);
        !           125: 
        !           126: #ifdef HAVE_GETHOSTNAME
        !           127: /* {{{ proto string gethostname()
        !           128:    Get the host name of the current machine */
        !           129: PHP_FUNCTION(gethostname)
        !           130: {
        !           131:        char buf[HOST_NAME_MAX];
        !           132: 
        !           133:        if (zend_parse_parameters_none() == FAILURE) {
        !           134:                return;
        !           135:        }
        !           136: 
        !           137:        if (gethostname(buf, sizeof(buf) - 1)) {
        !           138:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to fetch host [%d]: %s", errno, strerror(errno));
        !           139:                RETURN_FALSE;
        !           140:        }
        !           141: 
        !           142:        RETURN_STRING(buf, 1);
        !           143: }
        !           144: /* }}} */
        !           145: #endif
        !           146: 
        !           147: /* TODO: Reimplement the gethostby* functions using the new winxp+ API, in dns_win32.c, then
        !           148:  we can have a dns.c, dns_unix.c and dns_win32.c instead of a messy dns.c full of #ifdef
        !           149: */
        !           150: 
        !           151: /* {{{ proto string gethostbyaddr(string ip_address)
        !           152:    Get the Internet host name corresponding to a given IP address */
        !           153: PHP_FUNCTION(gethostbyaddr)
        !           154: {
        !           155:        char *addr;
        !           156:        int addr_len;
        !           157:        char *hostname;
        !           158: 
        !           159:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &addr, &addr_len) == FAILURE) {
        !           160:                return;
        !           161:        }
        !           162: 
        !           163:        hostname = php_gethostbyaddr(addr);
        !           164: 
        !           165:        if (hostname == NULL) {
        !           166: #if HAVE_IPV6 && HAVE_INET_PTON
        !           167:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Address is not a valid IPv4 or IPv6 address");
        !           168: #else
        !           169:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Address is not in a.b.c.d form");
        !           170: #endif
        !           171:                RETVAL_FALSE;
        !           172:        } else {
        !           173:                RETVAL_STRING(hostname, 0);
        !           174:        }
        !           175: }
        !           176: /* }}} */
        !           177: 
        !           178: /* {{{ php_gethostbyaddr */
        !           179: static char *php_gethostbyaddr(char *ip)
        !           180: {
        !           181: #if HAVE_IPV6 && HAVE_INET_PTON
        !           182:        struct in6_addr addr6;
        !           183: #endif
        !           184:        struct in_addr addr;
        !           185:        struct hostent *hp;
        !           186: 
        !           187: #if HAVE_IPV6 && HAVE_INET_PTON
        !           188:        if (inet_pton(AF_INET6, ip, &addr6)) {
        !           189:                hp = gethostbyaddr((char *) &addr6, sizeof(addr6), AF_INET6);
        !           190:        } else if (inet_pton(AF_INET, ip, &addr)) {
        !           191:                hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
        !           192:        } else {
        !           193:                return NULL;
        !           194:        }
        !           195: #else
        !           196:        addr.s_addr = inet_addr(ip);
        !           197: 
        !           198:        if (addr.s_addr == -1) {
        !           199:                return NULL;
        !           200:        }
        !           201: 
        !           202:        hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
        !           203: #endif
        !           204: 
        !           205:        if (!hp || hp->h_name == NULL || hp->h_name[0] == '\0') {
        !           206:                return estrdup(ip);
        !           207:        }
        !           208: 
        !           209:        return estrdup(hp->h_name);
        !           210: }
        !           211: /* }}} */
        !           212: 
        !           213: /* {{{ proto string gethostbyname(string hostname)
        !           214:    Get the IP address corresponding to a given Internet host name */
        !           215: PHP_FUNCTION(gethostbyname)
        !           216: {
        !           217:        char *hostname;
        !           218:        int hostname_len;
        !           219:        char *addr;
        !           220: 
        !           221:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &hostname, &hostname_len) == FAILURE) {
        !           222:                return;
        !           223:        }
        !           224: 
        !           225:        addr = php_gethostbyname(hostname);
        !           226: 
        !           227:        RETVAL_STRING(addr, 0);
        !           228: }
        !           229: /* }}} */
        !           230: 
        !           231: /* {{{ proto array gethostbynamel(string hostname)
        !           232:    Return a list of IP addresses that a given hostname resolves to. */
        !           233: PHP_FUNCTION(gethostbynamel)
        !           234: {
        !           235:        char *hostname;
        !           236:        int hostname_len;
        !           237:        struct hostent *hp;
        !           238:        struct in_addr in;
        !           239:        int i;
        !           240: 
        !           241:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &hostname, &hostname_len) == FAILURE) {
        !           242:                return;
        !           243:        }
        !           244: 
        !           245:        hp = gethostbyname(hostname);
        !           246:        if (hp == NULL || hp->h_addr_list == NULL) {
        !           247:                RETURN_FALSE;
        !           248:        }
        !           249: 
        !           250:        array_init(return_value);
        !           251: 
        !           252:        for (i = 0 ; hp->h_addr_list[i] != 0 ; i++) {
        !           253:                in = *(struct in_addr *) hp->h_addr_list[i];
        !           254:                add_next_index_string(return_value, inet_ntoa(in), 1);
        !           255:        }
        !           256: }
        !           257: /* }}} */
        !           258: 
        !           259: /* {{{ php_gethostbyname */
        !           260: static char *php_gethostbyname(char *name)
        !           261: {
        !           262:        struct hostent *hp;
        !           263:        struct in_addr in;
        !           264: 
        !           265:        hp = gethostbyname(name);
        !           266: 
        !           267:        if (!hp || !*(hp->h_addr_list)) {
        !           268:                return estrdup(name);
        !           269:        }
        !           270: 
        !           271:        memcpy(&in.s_addr, *(hp->h_addr_list), sizeof(in.s_addr));
        !           272: 
        !           273:        return estrdup(inet_ntoa(in));
        !           274: }
        !           275: /* }}} */
        !           276: 
        !           277: #if HAVE_FULL_DNS_FUNCS || defined(PHP_WIN32)
        !           278: # define PHP_DNS_NUM_TYPES     12      /* Number of DNS Types Supported by PHP currently */
        !           279: 
        !           280: # define PHP_DNS_A      0x00000001
        !           281: # define PHP_DNS_NS     0x00000002
        !           282: # define PHP_DNS_CNAME  0x00000010
        !           283: # define PHP_DNS_SOA    0x00000020
        !           284: # define PHP_DNS_PTR    0x00000800
        !           285: # define PHP_DNS_HINFO  0x00001000
        !           286: # define PHP_DNS_MX     0x00004000
        !           287: # define PHP_DNS_TXT    0x00008000
        !           288: # define PHP_DNS_A6     0x01000000
        !           289: # define PHP_DNS_SRV    0x02000000
        !           290: # define PHP_DNS_NAPTR  0x04000000
        !           291: # define PHP_DNS_AAAA   0x08000000
        !           292: # define PHP_DNS_ANY    0x10000000
        !           293: # define PHP_DNS_ALL    (PHP_DNS_A|PHP_DNS_NS|PHP_DNS_CNAME|PHP_DNS_SOA|PHP_DNS_PTR|PHP_DNS_HINFO|PHP_DNS_MX|PHP_DNS_TXT|PHP_DNS_A6|PHP_DNS_SRV|PHP_DNS_NAPTR|PHP_DNS_AAAA)
        !           294: #endif /* HAVE_FULL_DNS_FUNCS || defined(PHP_WIN32) */
        !           295: 
        !           296: /* Note: These functions are defined in ext/standard/dns_win32.c for Windows! */
        !           297: #if !defined(PHP_WIN32) && (HAVE_DNS_SEARCH_FUNC && !(defined(__BEOS__) || defined(NETWARE)))
        !           298:   
        !           299: #ifndef HFIXEDSZ
        !           300: #define HFIXEDSZ        12      /* fixed data in header <arpa/nameser.h> */
        !           301: #endif /* HFIXEDSZ */
        !           302: 
        !           303: #ifndef QFIXEDSZ
        !           304: #define QFIXEDSZ        4       /* fixed data in query <arpa/nameser.h> */
        !           305: #endif /* QFIXEDSZ */
        !           306: 
        !           307: #undef MAXHOSTNAMELEN
        !           308: #define MAXHOSTNAMELEN  1024
        !           309: 
        !           310: #ifndef MAXRESOURCERECORDS
        !           311: #define MAXRESOURCERECORDS     64
        !           312: #endif /* MAXRESOURCERECORDS */
        !           313: 
        !           314: typedef union {
        !           315:        HEADER qb1;
        !           316:        u_char qb2[65536];
        !           317: } querybuf;
        !           318: 
        !           319: /* just a hack to free resources allocated by glibc in __res_nsend()
        !           320:  * See also:
        !           321:  *   res_thread_freeres() in glibc/resolv/res_init.c
        !           322:  *   __libc_res_nsend()   in resolv/res_send.c
        !           323:  * */
        !           324: 
        !           325: #if defined(__GLIBC__) && !defined(HAVE_DEPRECATED_DNS_FUNCS)
        !           326: #define php_dns_free_res(__res__) _php_dns_free_res(__res__)
        !           327: static void _php_dns_free_res(struct __res_state res) { /* {{{ */
        !           328:        int ns;
        !           329:        for (ns = 0; ns < MAXNS; ns++) {
        !           330:                if (res._u._ext.nsaddrs[ns] != NULL) {
        !           331:                        free (res._u._ext.nsaddrs[ns]);
        !           332:                        res._u._ext.nsaddrs[ns] = NULL;
        !           333:                }
        !           334:        }
        !           335: } /* }}} */
        !           336: #else
        !           337: #define php_dns_free_res(__res__)
        !           338: #endif
        !           339: 
        !           340: /* {{{ proto bool dns_check_record(string host [, string type])
        !           341:    Check DNS records corresponding to a given Internet host name or IP address */
        !           342: PHP_FUNCTION(dns_check_record)
        !           343: {
        !           344: #ifndef MAXPACKET
        !           345: #define MAXPACKET  8192 /* max packet size used internally by BIND */
        !           346: #endif
        !           347:        u_char ans[MAXPACKET];
        !           348:        char *hostname, *rectype = NULL;
        !           349:        int hostname_len, rectype_len = 0;
        !           350:        int type = T_MX, i;
        !           351: #if defined(HAVE_DNS_SEARCH)
        !           352:        struct sockaddr_storage from;
        !           353:        uint32_t fromsize = sizeof(from);
        !           354:        dns_handle_t handle;
        !           355: #elif defined(HAVE_RES_NSEARCH)
        !           356:        struct __res_state state;
        !           357:        struct __res_state *handle = &state;
        !           358: #endif
        !           359: 
        !           360:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &hostname, &hostname_len, &rectype, &rectype_len) == FAILURE) {
        !           361:                return;
        !           362:        }
        !           363: 
        !           364:        if (hostname_len == 0) {
        !           365:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host cannot be empty");
        !           366:                RETURN_FALSE;
        !           367:        }
        !           368: 
        !           369:        if (rectype) {
        !           370:                if (!strcasecmp("A",     rectype)) type = T_A;
        !           371:                else if (!strcasecmp("NS",    rectype)) type = DNS_T_NS;
        !           372:                else if (!strcasecmp("MX",    rectype)) type = DNS_T_MX;
        !           373:                else if (!strcasecmp("PTR",   rectype)) type = DNS_T_PTR;
        !           374:                else if (!strcasecmp("ANY",   rectype)) type = DNS_T_ANY;
        !           375:                else if (!strcasecmp("SOA",   rectype)) type = DNS_T_SOA;
        !           376:                else if (!strcasecmp("TXT",   rectype)) type = DNS_T_TXT;
        !           377:                else if (!strcasecmp("CNAME", rectype)) type = DNS_T_CNAME;
        !           378:                else if (!strcasecmp("AAAA",  rectype)) type = DNS_T_AAAA;
        !           379:                else if (!strcasecmp("SRV",   rectype)) type = DNS_T_SRV;
        !           380:                else if (!strcasecmp("NAPTR", rectype)) type = DNS_T_NAPTR;
        !           381:                else if (!strcasecmp("A6",    rectype)) type = DNS_T_A6;
        !           382:                else {
        !           383:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type '%s' not supported", rectype);
        !           384:                        RETURN_FALSE;
        !           385:                }
        !           386:        }
        !           387: 
        !           388: #if defined(HAVE_DNS_SEARCH)
        !           389:        handle = dns_open(NULL);
        !           390:        if (handle == NULL) {
        !           391:                RETURN_FALSE;
        !           392:        }
        !           393: #elif defined(HAVE_RES_NSEARCH)
        !           394:     memset(&state, 0, sizeof(state));
        !           395:     if (res_ninit(handle)) {
        !           396:                        RETURN_FALSE;
        !           397:        }
        !           398: #else
        !           399:        res_init();
        !           400: #endif
        !           401: 
        !           402:        RETVAL_TRUE;
        !           403:        i = php_dns_search(handle, hostname, C_IN, type, ans, sizeof(ans));
        !           404: 
        !           405:        if (i < 0) {
        !           406:                RETVAL_FALSE;
        !           407:        }
        !           408: 
        !           409:        php_dns_free_handle(handle);
        !           410: }
        !           411: /* }}} */
        !           412: 
        !           413: #if HAVE_FULL_DNS_FUNCS
        !           414: 
        !           415: /* {{{ php_parserr */
        !           416: static u_char *php_parserr(u_char *cp, querybuf *answer, int type_to_fetch, int store, zval **subarray)
        !           417: {
        !           418:        u_short type, class, dlen;
        !           419:        u_long ttl;
        !           420:        long n, i;
        !           421:        u_short s;
        !           422:        u_char *tp, *p;
        !           423:        char name[MAXHOSTNAMELEN];
        !           424:        int have_v6_break = 0, in_v6_break = 0;
        !           425: 
        !           426:        *subarray = NULL;
        !           427: 
        !           428:        n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, sizeof(name) - 2);
        !           429:        if (n < 0) {
        !           430:                return NULL;
        !           431:        }
        !           432:        cp += n;
        !           433: 
        !           434:        GETSHORT(type, cp);
        !           435:        GETSHORT(class, cp);
        !           436:        GETLONG(ttl, cp);
        !           437:        GETSHORT(dlen, cp);
        !           438:        if (type_to_fetch != T_ANY && type != type_to_fetch) {
        !           439:                cp += dlen;
        !           440:                return cp;
        !           441:        }
        !           442: 
        !           443:        if (!store) {
        !           444:                cp += dlen;
        !           445:                return cp;
        !           446:        }
        !           447: 
        !           448:        ALLOC_INIT_ZVAL(*subarray);
        !           449:        array_init(*subarray);
        !           450: 
        !           451:        add_assoc_string(*subarray, "host", name, 1);
        !           452:        switch (type) {
        !           453:                case DNS_T_A:
        !           454:                        add_assoc_string(*subarray, "type", "A", 1);
        !           455:                        snprintf(name, sizeof(name), "%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
        !           456:                        add_assoc_string(*subarray, "ip", name, 1);
        !           457:                        cp += dlen;
        !           458:                        break;
        !           459:                case DNS_T_MX:
        !           460:                        add_assoc_string(*subarray, "type", "MX", 1);
        !           461:                        GETSHORT(n, cp);
        !           462:                        add_assoc_long(*subarray, "pri", n);
        !           463:                        /* no break; */
        !           464:                case DNS_T_CNAME:
        !           465:                        if (type == DNS_T_CNAME) {
        !           466:                                add_assoc_string(*subarray, "type", "CNAME", 1);
        !           467:                        }
        !           468:                        /* no break; */
        !           469:                case DNS_T_NS:
        !           470:                        if (type == DNS_T_NS) {
        !           471:                                add_assoc_string(*subarray, "type", "NS", 1);
        !           472:                        }
        !           473:                        /* no break; */
        !           474:                case DNS_T_PTR:
        !           475:                        if (type == DNS_T_PTR) {
        !           476:                                add_assoc_string(*subarray, "type", "PTR", 1);
        !           477:                        }
        !           478:                        n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2);
        !           479:                        if (n < 0) {
        !           480:                                return NULL;
        !           481:                        }
        !           482:                        cp += n;
        !           483:                        add_assoc_string(*subarray, "target", name, 1);
        !           484:                        break;
        !           485:                case DNS_T_HINFO:
        !           486:                        /* See RFC 1010 for values */
        !           487:                        add_assoc_string(*subarray, "type", "HINFO", 1);
        !           488:                        n = *cp & 0xFF;
        !           489:                        cp++;
        !           490:                        add_assoc_stringl(*subarray, "cpu", (char*)cp, n, 1);
        !           491:                        cp += n;
        !           492:                        n = *cp & 0xFF;
        !           493:                        cp++;
        !           494:                        add_assoc_stringl(*subarray, "os", (char*)cp, n, 1);
        !           495:                        cp += n;
        !           496:                        break;
        !           497:                case DNS_T_TXT:
        !           498:                        {
        !           499:                                int ll = 0;
        !           500:                                zval *entries = NULL;
        !           501: 
        !           502:                                add_assoc_string(*subarray, "type", "TXT", 1);
        !           503:                                tp = emalloc(dlen + 1);
        !           504:                                
        !           505:                                MAKE_STD_ZVAL(entries);
        !           506:                                array_init(entries);
        !           507:                                
        !           508:                                while (ll < dlen) {
        !           509:                                        n = cp[ll];
        !           510:                                        memcpy(tp + ll , cp + ll + 1, n);
        !           511:                                        add_next_index_stringl(entries, cp + ll + 1, n, 1);
        !           512:                                        ll = ll + n + 1;
        !           513:                                }
        !           514:                                tp[dlen] = '\0';
        !           515:                                cp += dlen;
        !           516: 
        !           517:                                add_assoc_stringl(*subarray, "txt", tp, dlen - 1, 0);
        !           518:                                add_assoc_zval(*subarray, "entries", entries);
        !           519:                        }
        !           520:                        break;
        !           521:                case DNS_T_SOA:
        !           522:                        add_assoc_string(*subarray, "type", "SOA", 1);
        !           523:                        n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) -2);
        !           524:                        if (n < 0) {
        !           525:                                return NULL;
        !           526:                        }
        !           527:                        cp += n;
        !           528:                        add_assoc_string(*subarray, "mname", name, 1);
        !           529:                        n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) -2);
        !           530:                        if (n < 0) {
        !           531:                                return NULL;
        !           532:                        }
        !           533:                        cp += n;
        !           534:                        add_assoc_string(*subarray, "rname", name, 1);
        !           535:                        GETLONG(n, cp);
        !           536:                        add_assoc_long(*subarray, "serial", n);
        !           537:                        GETLONG(n, cp);
        !           538:                        add_assoc_long(*subarray, "refresh", n);
        !           539:                        GETLONG(n, cp);
        !           540:                        add_assoc_long(*subarray, "retry", n);
        !           541:                        GETLONG(n, cp);
        !           542:                        add_assoc_long(*subarray, "expire", n);
        !           543:                        GETLONG(n, cp);
        !           544:                        add_assoc_long(*subarray, "minimum-ttl", n);
        !           545:                        break;
        !           546:                case DNS_T_AAAA:
        !           547:                        tp = (u_char*)name;
        !           548:                        for(i=0; i < 8; i++) {
        !           549:                                GETSHORT(s, cp);
        !           550:                                if (s != 0) {
        !           551:                                        if (tp > (u_char *)name) {
        !           552:                                                in_v6_break = 0;
        !           553:                                                tp[0] = ':';
        !           554:                                                tp++;
        !           555:                                        }
        !           556:                                        tp += sprintf((char*)tp,"%x",s);
        !           557:                                } else {
        !           558:                                        if (!have_v6_break) {
        !           559:                                                have_v6_break = 1;
        !           560:                                                in_v6_break = 1;
        !           561:                                                tp[0] = ':';
        !           562:                                                tp++;
        !           563:                                        } else if (!in_v6_break) {
        !           564:                                                tp[0] = ':';
        !           565:                                                tp++;
        !           566:                                                tp[0] = '0';
        !           567:                                                tp++;
        !           568:                                        }
        !           569:                                }
        !           570:                        }
        !           571:                        if (have_v6_break && in_v6_break) {
        !           572:                                tp[0] = ':';
        !           573:                                tp++;
        !           574:                        }
        !           575:                        tp[0] = '\0';
        !           576:                        add_assoc_string(*subarray, "type", "AAAA", 1);
        !           577:                        add_assoc_string(*subarray, "ipv6", name, 1);
        !           578:                        break;
        !           579:                case DNS_T_A6:
        !           580:                        p = cp;
        !           581:                        add_assoc_string(*subarray, "type", "A6", 1);
        !           582:                        n = ((int)cp[0]) & 0xFF;
        !           583:                        cp++;
        !           584:                        add_assoc_long(*subarray, "masklen", n);
        !           585:                        tp = (u_char*)name;
        !           586:                        if (n > 15) {
        !           587:                                have_v6_break = 1;
        !           588:                                in_v6_break = 1;
        !           589:                                tp[0] = ':';
        !           590:                                tp++;
        !           591:                        }
        !           592:                        if (n % 16 > 8) {
        !           593:                                /* Partial short */
        !           594:                                if (cp[0] != 0) {
        !           595:                                        if (tp > (u_char *)name) {
        !           596:                                                in_v6_break = 0;
        !           597:                                                tp[0] = ':';
        !           598:                                                tp++;
        !           599:                                        }
        !           600:                                        sprintf((char*)tp, "%x", cp[0] & 0xFF);
        !           601:                                } else {
        !           602:                                        if (!have_v6_break) {
        !           603:                                                have_v6_break = 1;
        !           604:                                                in_v6_break = 1;
        !           605:                                                tp[0] = ':';
        !           606:                                                tp++;
        !           607:                                        } else if (!in_v6_break) {
        !           608:                                                tp[0] = ':';
        !           609:                                                tp++;
        !           610:                                                tp[0] = '0';
        !           611:                                                tp++;
        !           612:                                        }
        !           613:                                }
        !           614:                                cp++;
        !           615:                        }
        !           616:                        for (i = (n + 8) / 16; i < 8; i++) {
        !           617:                                GETSHORT(s, cp);
        !           618:                                if (s != 0) {
        !           619:                                        if (tp > (u_char *)name) {
        !           620:                                                in_v6_break = 0;
        !           621:                                                tp[0] = ':';
        !           622:                                                tp++;
        !           623:                                        }
        !           624:                                        tp += sprintf((char*)tp,"%x",s);
        !           625:                                } else {
        !           626:                                        if (!have_v6_break) {
        !           627:                                                have_v6_break = 1;
        !           628:                                                in_v6_break = 1;
        !           629:                                                tp[0] = ':';
        !           630:                                                tp++;
        !           631:                                        } else if (!in_v6_break) {
        !           632:                                                tp[0] = ':';
        !           633:                                                tp++;
        !           634:                                                tp[0] = '0';
        !           635:                                                tp++;
        !           636:                                        }
        !           637:                                }
        !           638:                        }
        !           639:                        if (have_v6_break && in_v6_break) {
        !           640:                                tp[0] = ':';
        !           641:                                tp++;
        !           642:                        }
        !           643:                        tp[0] = '\0';
        !           644:                        add_assoc_string(*subarray, "ipv6", name, 1);
        !           645:                        if (cp < p + dlen) {
        !           646:                                n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2);
        !           647:                                if (n < 0) {
        !           648:                                        return NULL;
        !           649:                                }
        !           650:                                cp += n;
        !           651:                                add_assoc_string(*subarray, "chain", name, 1);
        !           652:                        }
        !           653:                        break;
        !           654:                case DNS_T_SRV:
        !           655:                        add_assoc_string(*subarray, "type", "SRV", 1);
        !           656:                        GETSHORT(n, cp);
        !           657:                        add_assoc_long(*subarray, "pri", n);
        !           658:                        GETSHORT(n, cp);
        !           659:                        add_assoc_long(*subarray, "weight", n);
        !           660:                        GETSHORT(n, cp);
        !           661:                        add_assoc_long(*subarray, "port", n);
        !           662:                        n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2);
        !           663:                        if (n < 0) {
        !           664:                                return NULL;
        !           665:                        }
        !           666:                        cp += n;
        !           667:                        add_assoc_string(*subarray, "target", name, 1);
        !           668:                        break;
        !           669:                case DNS_T_NAPTR:
        !           670:                        add_assoc_string(*subarray, "type", "NAPTR", 1);
        !           671:                        GETSHORT(n, cp);
        !           672:                        add_assoc_long(*subarray, "order", n);
        !           673:                        GETSHORT(n, cp);
        !           674:                        add_assoc_long(*subarray, "pref", n);
        !           675:                        n = (cp[0] & 0xFF);
        !           676:                        add_assoc_stringl(*subarray, "flags", (char*)++cp, n, 1);
        !           677:                        cp += n;
        !           678:                        n = (cp[0] & 0xFF);
        !           679:                        add_assoc_stringl(*subarray, "services", (char*)++cp, n, 1);
        !           680:                        cp += n;
        !           681:                        n = (cp[0] & 0xFF);
        !           682:                        add_assoc_stringl(*subarray, "regex", (char*)++cp, n, 1);
        !           683:                        cp += n;
        !           684:                        n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2);
        !           685:                        if (n < 0) {
        !           686:                                return NULL;
        !           687:                        }
        !           688:                        cp += n;
        !           689:                        add_assoc_string(*subarray, "replacement", name, 1);
        !           690:                        break;
        !           691:                default:
        !           692:                        cp += dlen;
        !           693:        }
        !           694: 
        !           695:        add_assoc_string(*subarray, "class", "IN", 1);
        !           696:        add_assoc_long(*subarray, "ttl", ttl);
        !           697: 
        !           698:        return cp;
        !           699: }
        !           700: /* }}} */
        !           701: 
        !           702: /* {{{ proto array|false dns_get_record(string hostname [, int type[, array authns, array addtl]])
        !           703:    Get any Resource Record corresponding to a given Internet host name */
        !           704: PHP_FUNCTION(dns_get_record)
        !           705: {
        !           706:        char *hostname;
        !           707:        int hostname_len;
        !           708:        long type_param = PHP_DNS_ANY;
        !           709:        zval *authns = NULL, *addtl = NULL;
        !           710:        int type_to_fetch;
        !           711: #if defined(HAVE_DNS_SEARCH)
        !           712:        struct sockaddr_storage from;
        !           713:        uint32_t fromsize = sizeof(from);
        !           714:        dns_handle_t handle;
        !           715: #elif defined(HAVE_RES_NSEARCH)
        !           716:        struct __res_state state;
        !           717:        struct __res_state *handle = &state;
        !           718: #endif
        !           719:        HEADER *hp;
        !           720:        querybuf answer;
        !           721:        u_char *cp = NULL, *end = NULL;
        !           722:        int n, qd, an, ns = 0, ar = 0;
        !           723:        int type, first_query = 1, store_results = 1;
        !           724: 
        !           725:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lzz", &hostname, &hostname_len, &type_param, &authns, &addtl) == FAILURE) {
        !           726:                return;
        !           727:        }
        !           728: 
        !           729:        if (authns) {
        !           730:                zval_dtor(authns);
        !           731:                array_init(authns);
        !           732:        }
        !           733:        if (addtl) {
        !           734:                zval_dtor(addtl);
        !           735:                array_init(addtl);
        !           736:        }
        !           737: 
        !           738:        if (type_param & ~PHP_DNS_ALL && type_param != PHP_DNS_ANY) {
        !           739:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type '%ld' not supported", type_param);
        !           740:                RETURN_FALSE;
        !           741:        }
        !           742: 
        !           743:        /* Initialize the return array */
        !           744:        array_init(return_value);
        !           745: 
        !           746:        /* - We emulate an or'ed type mask by querying type by type. (Steps 0 - NUMTYPES-1 )
        !           747:         *   If additional info is wanted we check again with DNS_T_ANY (step NUMTYPES / NUMTYPES+1 )
        !           748:         *   store_results is used to skip storing the results retrieved in step
        !           749:         *   NUMTYPES+1 when results were already fetched.
        !           750:         * - In case of PHP_DNS_ANY we use the directly fetch DNS_T_ANY. (step NUMTYPES+1 )
        !           751:         */
        !           752:        for (type = (type_param == PHP_DNS_ANY ? (PHP_DNS_NUM_TYPES + 1) : 0);
        !           753:                type < (addtl ? (PHP_DNS_NUM_TYPES + 2) : PHP_DNS_NUM_TYPES) || first_query;
        !           754:                type++
        !           755:        ) {
        !           756:                first_query = 0;
        !           757:                switch (type) {
        !           758:                        case 0:
        !           759:                                type_to_fetch = type_param&PHP_DNS_A     ? DNS_T_A     : 0;
        !           760:                                break;
        !           761:                        case 1:
        !           762:                                type_to_fetch = type_param&PHP_DNS_NS    ? DNS_T_NS    : 0;
        !           763:                                break;
        !           764:                        case 2:
        !           765:                                type_to_fetch = type_param&PHP_DNS_CNAME ? DNS_T_CNAME : 0;
        !           766:                                break;
        !           767:                        case 3:
        !           768:                                type_to_fetch = type_param&PHP_DNS_SOA   ? DNS_T_SOA   : 0;
        !           769:                                break;
        !           770:                        case 4:
        !           771:                                type_to_fetch = type_param&PHP_DNS_PTR   ? DNS_T_PTR   : 0;
        !           772:                                break;
        !           773:                        case 5:
        !           774:                                type_to_fetch = type_param&PHP_DNS_HINFO ? DNS_T_HINFO : 0;
        !           775:                                break;
        !           776:                        case 6:
        !           777:                                type_to_fetch = type_param&PHP_DNS_MX    ? DNS_T_MX    : 0;
        !           778:                                break;
        !           779:                        case 7:
        !           780:                                type_to_fetch = type_param&PHP_DNS_TXT   ? DNS_T_TXT   : 0;
        !           781:                                break;
        !           782:                        case 8:
        !           783:                                type_to_fetch = type_param&PHP_DNS_AAAA  ? DNS_T_AAAA  : 0;
        !           784:                                break;
        !           785:                        case 9:
        !           786:                                type_to_fetch = type_param&PHP_DNS_SRV   ? DNS_T_SRV   : 0;
        !           787:                                break;
        !           788:                        case 10:
        !           789:                                type_to_fetch = type_param&PHP_DNS_NAPTR ? DNS_T_NAPTR : 0;
        !           790:                                break;
        !           791:                        case 11:
        !           792:                                type_to_fetch = type_param&PHP_DNS_A6    ? DNS_T_A6 : 0;
        !           793:                                break;
        !           794:                        case PHP_DNS_NUM_TYPES:
        !           795:                                store_results = 0;
        !           796:                                continue;
        !           797:                        default:
        !           798:                        case (PHP_DNS_NUM_TYPES + 1):
        !           799:                                type_to_fetch = DNS_T_ANY;
        !           800:                                break;
        !           801:                }
        !           802: 
        !           803:                if (type_to_fetch) {
        !           804: #if defined(HAVE_DNS_SEARCH)
        !           805:                        handle = dns_open(NULL);
        !           806:                        if (handle == NULL) {
        !           807:                                zval_dtor(return_value);
        !           808:                                RETURN_FALSE;
        !           809:                        }
        !           810: #elif defined(HAVE_RES_NSEARCH)
        !           811:                    memset(&state, 0, sizeof(state));
        !           812:                    if (res_ninit(handle)) {
        !           813:                        zval_dtor(return_value);
        !           814:                                RETURN_FALSE;
        !           815:                        }
        !           816: #else
        !           817:                        res_init();
        !           818: #endif
        !           819: 
        !           820:                        n = php_dns_search(handle, hostname, C_IN, type_to_fetch, answer.qb2, sizeof answer);
        !           821: 
        !           822:                        if (n < 0) {
        !           823:                                php_dns_free_handle(handle);
        !           824:                                continue;
        !           825:                        }
        !           826: 
        !           827:                        cp = answer.qb2 + HFIXEDSZ;
        !           828:                        end = answer.qb2 + n;
        !           829:                        hp = (HEADER *)&answer;
        !           830:                        qd = ntohs(hp->qdcount);
        !           831:                        an = ntohs(hp->ancount);
        !           832:                        ns = ntohs(hp->nscount);
        !           833:                        ar = ntohs(hp->arcount);
        !           834: 
        !           835:                        /* Skip QD entries, they're only used by dn_expand later on */
        !           836:                        while (qd-- > 0) {
        !           837:                                n = dn_skipname(cp, end);
        !           838:                                if (n < 0) {
        !           839:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse DNS data received");
        !           840:                                        zval_dtor(return_value);
        !           841:                                        php_dns_free_handle(handle);
        !           842:                                        RETURN_FALSE;
        !           843:                                }
        !           844:                                cp += n + QFIXEDSZ;
        !           845:                        }
        !           846: 
        !           847:                        /* YAY! Our real answers! */
        !           848:                        while (an-- && cp && cp < end) {
        !           849:                                zval *retval;
        !           850: 
        !           851:                                cp = php_parserr(cp, &answer, type_to_fetch, store_results, &retval);
        !           852:                                if (retval != NULL && store_results) {
        !           853:                                        add_next_index_zval(return_value, retval);
        !           854:                                }
        !           855:                        }
        !           856: 
        !           857:                        if (authns || addtl) {
        !           858:                                /* List of Authoritative Name Servers
        !           859:                                 * Process when only requesting addtl so that we can skip through the section
        !           860:                                 */
        !           861:                                while (ns-- > 0 && cp && cp < end) {
        !           862:                                        zval *retval = NULL;
        !           863: 
        !           864:                                        cp = php_parserr(cp, &answer, DNS_T_ANY, authns != NULL, &retval);
        !           865:                                        if (retval != NULL) {
        !           866:                                                add_next_index_zval(authns, retval);
        !           867:                                        }
        !           868:                                }
        !           869:                        }
        !           870: 
        !           871:                        if (addtl) {
        !           872:                                /* Additional records associated with authoritative name servers */
        !           873:                                while (ar-- > 0 && cp && cp < end) {
        !           874:                                        zval *retval = NULL;
        !           875: 
        !           876:                                        cp = php_parserr(cp, &answer, DNS_T_ANY, 1, &retval);
        !           877:                                        if (retval != NULL) {
        !           878:                                                add_next_index_zval(addtl, retval);
        !           879:                                        }
        !           880:                                }
        !           881:                        }
        !           882:                        php_dns_free_handle(handle);
        !           883:                }
        !           884:        }
        !           885: }
        !           886: /* }}} */
        !           887: 
        !           888: /* {{{ proto bool dns_get_mx(string hostname, array mxhosts [, array weight])
        !           889:    Get MX records corresponding to a given Internet host name */
        !           890: PHP_FUNCTION(dns_get_mx)
        !           891: {
        !           892:        char *hostname;
        !           893:        int hostname_len;
        !           894:        zval *mx_list, *weight_list = NULL;
        !           895:        int count, qdc;
        !           896:        u_short type, weight;
        !           897:        u_char ans[MAXPACKET];
        !           898:        char buf[MAXHOSTNAMELEN];
        !           899:        HEADER *hp;
        !           900:        u_char *cp, *end;
        !           901:        int i;
        !           902: #if defined(HAVE_DNS_SEARCH)
        !           903:        struct sockaddr_storage from;
        !           904:        uint32_t fromsize = sizeof(from);
        !           905:        dns_handle_t handle;
        !           906: #elif defined(HAVE_RES_NSEARCH)
        !           907:        struct __res_state state;
        !           908:        struct __res_state *handle = &state;
        !           909: #endif
        !           910: 
        !           911:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|z", &hostname, &hostname_len, &mx_list, &weight_list) == FAILURE) {
        !           912:                return;
        !           913:        }
        !           914: 
        !           915:        zval_dtor(mx_list);
        !           916:        array_init(mx_list);
        !           917: 
        !           918:        if (weight_list) {
        !           919:                zval_dtor(weight_list);
        !           920:                array_init(weight_list);
        !           921:        }
        !           922: 
        !           923: #if defined(HAVE_DNS_SEARCH)
        !           924:        handle = dns_open(NULL);
        !           925:        if (handle == NULL) {
        !           926:                RETURN_FALSE;
        !           927:        }
        !           928: #elif defined(HAVE_RES_NSEARCH)
        !           929:     memset(&state, 0, sizeof(state));
        !           930:     if (res_ninit(handle)) {
        !           931:                        RETURN_FALSE;
        !           932:        }
        !           933: #else
        !           934:        res_init();
        !           935: #endif
        !           936: 
        !           937:        i = php_dns_search(handle, hostname, C_IN, DNS_T_MX, (u_char *)&ans, sizeof(ans));
        !           938:        if (i < 0) {
        !           939:                RETURN_FALSE;
        !           940:        }
        !           941:        if (i > (int)sizeof(ans)) {
        !           942:                i = sizeof(ans);
        !           943:        }
        !           944:        hp = (HEADER *)&ans;
        !           945:        cp = (u_char *)&ans + HFIXEDSZ;
        !           946:        end = (u_char *)&ans +i;
        !           947:        for (qdc = ntohs((unsigned short)hp->qdcount); qdc--; cp += i + QFIXEDSZ) {
        !           948:                if ((i = dn_skipname(cp, end)) < 0 ) {
        !           949:                        php_dns_free_handle(handle);
        !           950:                        RETURN_FALSE;
        !           951:                }
        !           952:        }
        !           953:        count = ntohs((unsigned short)hp->ancount);
        !           954:        while (--count >= 0 && cp < end) {
        !           955:                if ((i = dn_skipname(cp, end)) < 0 ) {
        !           956:                        php_dns_free_handle(handle);
        !           957:                        RETURN_FALSE;
        !           958:                }
        !           959:                cp += i;
        !           960:                GETSHORT(type, cp);
        !           961:                cp += INT16SZ + INT32SZ;
        !           962:                GETSHORT(i, cp);
        !           963:                if (type != DNS_T_MX) {
        !           964:                        cp += i;
        !           965:                        continue;
        !           966:                }
        !           967:                GETSHORT(weight, cp);
        !           968:                if ((i = dn_expand(ans, end, cp, buf, sizeof(buf)-1)) < 0) {
        !           969:                        php_dns_free_handle(handle);
        !           970:                        RETURN_FALSE;
        !           971:                }
        !           972:                cp += i;
        !           973:                add_next_index_string(mx_list, buf, 1);
        !           974:                if (weight_list) {
        !           975:                        add_next_index_long(weight_list, weight);
        !           976:                }
        !           977:        }
        !           978:        php_dns_free_handle(handle);
        !           979:        RETURN_TRUE;
        !           980: }
        !           981: /* }}} */
        !           982: #endif /* HAVE_FULL_DNS_FUNCS */
        !           983: #endif /* !defined(PHP_WIN32) && (HAVE_DNS_SEARCH_FUNC && !(defined(__BEOS__) || defined(NETWARE))) */
        !           984: 
        !           985: #if HAVE_FULL_DNS_FUNCS || defined(PHP_WIN32)
        !           986: PHP_MINIT_FUNCTION(dns) {
        !           987:        REGISTER_LONG_CONSTANT("DNS_A",     PHP_DNS_A,     CONST_CS | CONST_PERSISTENT);
        !           988:        REGISTER_LONG_CONSTANT("DNS_NS",    PHP_DNS_NS,    CONST_CS | CONST_PERSISTENT);
        !           989:        REGISTER_LONG_CONSTANT("DNS_CNAME", PHP_DNS_CNAME, CONST_CS | CONST_PERSISTENT);
        !           990:        REGISTER_LONG_CONSTANT("DNS_SOA",   PHP_DNS_SOA,   CONST_CS | CONST_PERSISTENT);
        !           991:        REGISTER_LONG_CONSTANT("DNS_PTR",   PHP_DNS_PTR,   CONST_CS | CONST_PERSISTENT);
        !           992:        REGISTER_LONG_CONSTANT("DNS_HINFO", PHP_DNS_HINFO, CONST_CS | CONST_PERSISTENT);
        !           993:        REGISTER_LONG_CONSTANT("DNS_MX",    PHP_DNS_MX,    CONST_CS | CONST_PERSISTENT);
        !           994:        REGISTER_LONG_CONSTANT("DNS_TXT",   PHP_DNS_TXT,   CONST_CS | CONST_PERSISTENT);
        !           995:        REGISTER_LONG_CONSTANT("DNS_SRV",   PHP_DNS_SRV,   CONST_CS | CONST_PERSISTENT);
        !           996:        REGISTER_LONG_CONSTANT("DNS_NAPTR", PHP_DNS_NAPTR, CONST_CS | CONST_PERSISTENT);
        !           997:        REGISTER_LONG_CONSTANT("DNS_AAAA",  PHP_DNS_AAAA,  CONST_CS | CONST_PERSISTENT);
        !           998:        REGISTER_LONG_CONSTANT("DNS_A6",    PHP_DNS_A6,    CONST_CS | CONST_PERSISTENT);
        !           999:        REGISTER_LONG_CONSTANT("DNS_ANY",   PHP_DNS_ANY,   CONST_CS | CONST_PERSISTENT);
        !          1000:        REGISTER_LONG_CONSTANT("DNS_ALL",   PHP_DNS_ALL,   CONST_CS | CONST_PERSISTENT);
        !          1001:        return SUCCESS;
        !          1002: }
        !          1003: #endif /* HAVE_FULL_DNS_FUNCS */
        !          1004: 
        !          1005: /*
        !          1006:  * Local variables:
        !          1007:  * tab-width: 4
        !          1008:  * c-basic-offset: 4
        !          1009:  * End:
        !          1010:  * vim600: sw=4 ts=4 fdm=marker
        !          1011:  * vim<600: sw=4 ts=4
        !          1012:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>