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

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.3 ! misho       5:    | Copyright (c) 1997-2013 The PHP Group                                |
1.1       misho       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: 
1.1.1.2   misho      21: /* $Id$ */
1.1       misho      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 */
1.1.1.2   misho     416: static u_char *php_parserr(u_char *cp, querybuf *answer, int type_to_fetch, int store, int raw, zval **subarray)
1.1       misho     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);
1.1.1.2   misho     452:        add_assoc_string(*subarray, "class", "IN", 1);
                    453:        add_assoc_long(*subarray, "ttl", ttl);
                    454: 
                    455:        if (raw) {
                    456:                add_assoc_long(*subarray, "type", type);
                    457:                add_assoc_stringl(*subarray, "data", (char*) cp, (uint) dlen, 1);
                    458:                cp += dlen;
                    459:                return cp;
                    460:        }
                    461: 
1.1       misho     462:        switch (type) {
                    463:                case DNS_T_A:
                    464:                        add_assoc_string(*subarray, "type", "A", 1);
                    465:                        snprintf(name, sizeof(name), "%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
                    466:                        add_assoc_string(*subarray, "ip", name, 1);
                    467:                        cp += dlen;
                    468:                        break;
                    469:                case DNS_T_MX:
                    470:                        add_assoc_string(*subarray, "type", "MX", 1);
                    471:                        GETSHORT(n, cp);
                    472:                        add_assoc_long(*subarray, "pri", n);
                    473:                        /* no break; */
                    474:                case DNS_T_CNAME:
                    475:                        if (type == DNS_T_CNAME) {
                    476:                                add_assoc_string(*subarray, "type", "CNAME", 1);
                    477:                        }
                    478:                        /* no break; */
                    479:                case DNS_T_NS:
                    480:                        if (type == DNS_T_NS) {
                    481:                                add_assoc_string(*subarray, "type", "NS", 1);
                    482:                        }
                    483:                        /* no break; */
                    484:                case DNS_T_PTR:
                    485:                        if (type == DNS_T_PTR) {
                    486:                                add_assoc_string(*subarray, "type", "PTR", 1);
                    487:                        }
                    488:                        n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2);
                    489:                        if (n < 0) {
                    490:                                return NULL;
                    491:                        }
                    492:                        cp += n;
                    493:                        add_assoc_string(*subarray, "target", name, 1);
                    494:                        break;
                    495:                case DNS_T_HINFO:
                    496:                        /* See RFC 1010 for values */
                    497:                        add_assoc_string(*subarray, "type", "HINFO", 1);
                    498:                        n = *cp & 0xFF;
                    499:                        cp++;
                    500:                        add_assoc_stringl(*subarray, "cpu", (char*)cp, n, 1);
                    501:                        cp += n;
                    502:                        n = *cp & 0xFF;
                    503:                        cp++;
                    504:                        add_assoc_stringl(*subarray, "os", (char*)cp, n, 1);
                    505:                        cp += n;
                    506:                        break;
                    507:                case DNS_T_TXT:
                    508:                        {
                    509:                                int ll = 0;
                    510:                                zval *entries = NULL;
                    511: 
                    512:                                add_assoc_string(*subarray, "type", "TXT", 1);
                    513:                                tp = emalloc(dlen + 1);
                    514:                                
                    515:                                MAKE_STD_ZVAL(entries);
                    516:                                array_init(entries);
                    517:                                
                    518:                                while (ll < dlen) {
                    519:                                        n = cp[ll];
                    520:                                        memcpy(tp + ll , cp + ll + 1, n);
                    521:                                        add_next_index_stringl(entries, cp + ll + 1, n, 1);
                    522:                                        ll = ll + n + 1;
                    523:                                }
                    524:                                tp[dlen] = '\0';
                    525:                                cp += dlen;
                    526: 
1.1.1.3 ! misho     527:                                add_assoc_stringl(*subarray, "txt", tp, (dlen>0)?dlen - 1:0, 0);
1.1       misho     528:                                add_assoc_zval(*subarray, "entries", entries);
                    529:                        }
                    530:                        break;
                    531:                case DNS_T_SOA:
                    532:                        add_assoc_string(*subarray, "type", "SOA", 1);
                    533:                        n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) -2);
                    534:                        if (n < 0) {
                    535:                                return NULL;
                    536:                        }
                    537:                        cp += n;
                    538:                        add_assoc_string(*subarray, "mname", name, 1);
                    539:                        n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) -2);
                    540:                        if (n < 0) {
                    541:                                return NULL;
                    542:                        }
                    543:                        cp += n;
                    544:                        add_assoc_string(*subarray, "rname", name, 1);
                    545:                        GETLONG(n, cp);
                    546:                        add_assoc_long(*subarray, "serial", n);
                    547:                        GETLONG(n, cp);
                    548:                        add_assoc_long(*subarray, "refresh", n);
                    549:                        GETLONG(n, cp);
                    550:                        add_assoc_long(*subarray, "retry", n);
                    551:                        GETLONG(n, cp);
                    552:                        add_assoc_long(*subarray, "expire", n);
                    553:                        GETLONG(n, cp);
                    554:                        add_assoc_long(*subarray, "minimum-ttl", n);
                    555:                        break;
                    556:                case DNS_T_AAAA:
                    557:                        tp = (u_char*)name;
                    558:                        for(i=0; i < 8; i++) {
                    559:                                GETSHORT(s, cp);
                    560:                                if (s != 0) {
                    561:                                        if (tp > (u_char *)name) {
                    562:                                                in_v6_break = 0;
                    563:                                                tp[0] = ':';
                    564:                                                tp++;
                    565:                                        }
                    566:                                        tp += sprintf((char*)tp,"%x",s);
                    567:                                } else {
                    568:                                        if (!have_v6_break) {
                    569:                                                have_v6_break = 1;
                    570:                                                in_v6_break = 1;
                    571:                                                tp[0] = ':';
                    572:                                                tp++;
                    573:                                        } else if (!in_v6_break) {
                    574:                                                tp[0] = ':';
                    575:                                                tp++;
                    576:                                                tp[0] = '0';
                    577:                                                tp++;
                    578:                                        }
                    579:                                }
                    580:                        }
                    581:                        if (have_v6_break && in_v6_break) {
                    582:                                tp[0] = ':';
                    583:                                tp++;
                    584:                        }
                    585:                        tp[0] = '\0';
                    586:                        add_assoc_string(*subarray, "type", "AAAA", 1);
                    587:                        add_assoc_string(*subarray, "ipv6", name, 1);
                    588:                        break;
                    589:                case DNS_T_A6:
                    590:                        p = cp;
                    591:                        add_assoc_string(*subarray, "type", "A6", 1);
                    592:                        n = ((int)cp[0]) & 0xFF;
                    593:                        cp++;
                    594:                        add_assoc_long(*subarray, "masklen", n);
                    595:                        tp = (u_char*)name;
                    596:                        if (n > 15) {
                    597:                                have_v6_break = 1;
                    598:                                in_v6_break = 1;
                    599:                                tp[0] = ':';
                    600:                                tp++;
                    601:                        }
                    602:                        if (n % 16 > 8) {
                    603:                                /* Partial short */
                    604:                                if (cp[0] != 0) {
                    605:                                        if (tp > (u_char *)name) {
                    606:                                                in_v6_break = 0;
                    607:                                                tp[0] = ':';
                    608:                                                tp++;
                    609:                                        }
                    610:                                        sprintf((char*)tp, "%x", cp[0] & 0xFF);
                    611:                                } else {
                    612:                                        if (!have_v6_break) {
                    613:                                                have_v6_break = 1;
                    614:                                                in_v6_break = 1;
                    615:                                                tp[0] = ':';
                    616:                                                tp++;
                    617:                                        } else if (!in_v6_break) {
                    618:                                                tp[0] = ':';
                    619:                                                tp++;
                    620:                                                tp[0] = '0';
                    621:                                                tp++;
                    622:                                        }
                    623:                                }
                    624:                                cp++;
                    625:                        }
                    626:                        for (i = (n + 8) / 16; i < 8; i++) {
                    627:                                GETSHORT(s, cp);
                    628:                                if (s != 0) {
                    629:                                        if (tp > (u_char *)name) {
                    630:                                                in_v6_break = 0;
                    631:                                                tp[0] = ':';
                    632:                                                tp++;
                    633:                                        }
                    634:                                        tp += sprintf((char*)tp,"%x",s);
                    635:                                } else {
                    636:                                        if (!have_v6_break) {
                    637:                                                have_v6_break = 1;
                    638:                                                in_v6_break = 1;
                    639:                                                tp[0] = ':';
                    640:                                                tp++;
                    641:                                        } else if (!in_v6_break) {
                    642:                                                tp[0] = ':';
                    643:                                                tp++;
                    644:                                                tp[0] = '0';
                    645:                                                tp++;
                    646:                                        }
                    647:                                }
                    648:                        }
                    649:                        if (have_v6_break && in_v6_break) {
                    650:                                tp[0] = ':';
                    651:                                tp++;
                    652:                        }
                    653:                        tp[0] = '\0';
                    654:                        add_assoc_string(*subarray, "ipv6", name, 1);
                    655:                        if (cp < p + dlen) {
                    656:                                n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2);
                    657:                                if (n < 0) {
                    658:                                        return NULL;
                    659:                                }
                    660:                                cp += n;
                    661:                                add_assoc_string(*subarray, "chain", name, 1);
                    662:                        }
                    663:                        break;
                    664:                case DNS_T_SRV:
                    665:                        add_assoc_string(*subarray, "type", "SRV", 1);
                    666:                        GETSHORT(n, cp);
                    667:                        add_assoc_long(*subarray, "pri", n);
                    668:                        GETSHORT(n, cp);
                    669:                        add_assoc_long(*subarray, "weight", n);
                    670:                        GETSHORT(n, cp);
                    671:                        add_assoc_long(*subarray, "port", n);
                    672:                        n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2);
                    673:                        if (n < 0) {
                    674:                                return NULL;
                    675:                        }
                    676:                        cp += n;
                    677:                        add_assoc_string(*subarray, "target", name, 1);
                    678:                        break;
                    679:                case DNS_T_NAPTR:
                    680:                        add_assoc_string(*subarray, "type", "NAPTR", 1);
                    681:                        GETSHORT(n, cp);
                    682:                        add_assoc_long(*subarray, "order", n);
                    683:                        GETSHORT(n, cp);
                    684:                        add_assoc_long(*subarray, "pref", n);
                    685:                        n = (cp[0] & 0xFF);
                    686:                        add_assoc_stringl(*subarray, "flags", (char*)++cp, n, 1);
                    687:                        cp += n;
                    688:                        n = (cp[0] & 0xFF);
                    689:                        add_assoc_stringl(*subarray, "services", (char*)++cp, n, 1);
                    690:                        cp += n;
                    691:                        n = (cp[0] & 0xFF);
                    692:                        add_assoc_stringl(*subarray, "regex", (char*)++cp, n, 1);
                    693:                        cp += n;
                    694:                        n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2);
                    695:                        if (n < 0) {
                    696:                                return NULL;
                    697:                        }
                    698:                        cp += n;
                    699:                        add_assoc_string(*subarray, "replacement", name, 1);
                    700:                        break;
                    701:                default:
1.1.1.2   misho     702:                        zval_ptr_dtor(subarray);
                    703:                        *subarray = NULL;
1.1       misho     704:                        cp += dlen;
1.1.1.2   misho     705:                        break;
1.1       misho     706:        }
                    707: 
                    708:        return cp;
                    709: }
                    710: /* }}} */
                    711: 
                    712: /* {{{ proto array|false dns_get_record(string hostname [, int type[, array authns, array addtl]])
                    713:    Get any Resource Record corresponding to a given Internet host name */
                    714: PHP_FUNCTION(dns_get_record)
                    715: {
                    716:        char *hostname;
                    717:        int hostname_len;
                    718:        long type_param = PHP_DNS_ANY;
                    719:        zval *authns = NULL, *addtl = NULL;
                    720:        int type_to_fetch;
                    721: #if defined(HAVE_DNS_SEARCH)
                    722:        struct sockaddr_storage from;
                    723:        uint32_t fromsize = sizeof(from);
                    724:        dns_handle_t handle;
                    725: #elif defined(HAVE_RES_NSEARCH)
                    726:        struct __res_state state;
                    727:        struct __res_state *handle = &state;
                    728: #endif
                    729:        HEADER *hp;
                    730:        querybuf answer;
                    731:        u_char *cp = NULL, *end = NULL;
                    732:        int n, qd, an, ns = 0, ar = 0;
                    733:        int type, first_query = 1, store_results = 1;
1.1.1.2   misho     734:        zend_bool raw = 0;
1.1       misho     735: 
1.1.1.2   misho     736:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lz!z!b",
                    737:                        &hostname, &hostname_len, &type_param, &authns, &addtl, &raw) == FAILURE) {
1.1       misho     738:                return;
                    739:        }
                    740: 
                    741:        if (authns) {
                    742:                zval_dtor(authns);
                    743:                array_init(authns);
                    744:        }
                    745:        if (addtl) {
                    746:                zval_dtor(addtl);
                    747:                array_init(addtl);
                    748:        }
                    749: 
1.1.1.2   misho     750:        if (!raw) {
                    751:                if ((type_param & ~PHP_DNS_ALL) && (type_param != PHP_DNS_ANY)) {
                    752:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type '%ld' not supported", type_param);
                    753:                        RETURN_FALSE;
                    754:                }
                    755:        } else {
                    756:                if ((type_param < 1) || (type_param > 0xFFFF)) {
                    757:                        php_error_docref(NULL TSRMLS_CC, E_WARNING,
                    758:                                "Numeric DNS record type must be between 1 and 65535, '%ld' given", type_param);
                    759:                        RETURN_FALSE;
                    760:                }
1.1       misho     761:        }
                    762: 
                    763:        /* Initialize the return array */
                    764:        array_init(return_value);
                    765: 
                    766:        /* - We emulate an or'ed type mask by querying type by type. (Steps 0 - NUMTYPES-1 )
                    767:         *   If additional info is wanted we check again with DNS_T_ANY (step NUMTYPES / NUMTYPES+1 )
                    768:         *   store_results is used to skip storing the results retrieved in step
                    769:         *   NUMTYPES+1 when results were already fetched.
                    770:         * - In case of PHP_DNS_ANY we use the directly fetch DNS_T_ANY. (step NUMTYPES+1 )
1.1.1.2   misho     771:         * - In case of raw mode, we query only the requestd type instead of looping type by type
                    772:         *   before going with the additional info stuff.
1.1       misho     773:         */
1.1.1.2   misho     774: 
                    775:        if (raw) {
                    776:                type = -1;
                    777:        } else if (type_param == PHP_DNS_ANY) {
                    778:                type = PHP_DNS_NUM_TYPES + 1;
                    779:        } else {
                    780:                type = 0;
                    781:        }
                    782: 
                    783:        for ( ;
1.1       misho     784:                type < (addtl ? (PHP_DNS_NUM_TYPES + 2) : PHP_DNS_NUM_TYPES) || first_query;
                    785:                type++
                    786:        ) {
                    787:                first_query = 0;
                    788:                switch (type) {
1.1.1.2   misho     789:                        case -1: /* raw */
                    790:                                type_to_fetch = type_param;
                    791:                                /* skip over the rest and go directly to additional records */
                    792:                                type = PHP_DNS_NUM_TYPES - 1;
                    793:                                break;
1.1       misho     794:                        case 0:
                    795:                                type_to_fetch = type_param&PHP_DNS_A     ? DNS_T_A     : 0;
                    796:                                break;
                    797:                        case 1:
                    798:                                type_to_fetch = type_param&PHP_DNS_NS    ? DNS_T_NS    : 0;
                    799:                                break;
                    800:                        case 2:
                    801:                                type_to_fetch = type_param&PHP_DNS_CNAME ? DNS_T_CNAME : 0;
                    802:                                break;
                    803:                        case 3:
                    804:                                type_to_fetch = type_param&PHP_DNS_SOA   ? DNS_T_SOA   : 0;
                    805:                                break;
                    806:                        case 4:
                    807:                                type_to_fetch = type_param&PHP_DNS_PTR   ? DNS_T_PTR   : 0;
                    808:                                break;
                    809:                        case 5:
                    810:                                type_to_fetch = type_param&PHP_DNS_HINFO ? DNS_T_HINFO : 0;
                    811:                                break;
                    812:                        case 6:
                    813:                                type_to_fetch = type_param&PHP_DNS_MX    ? DNS_T_MX    : 0;
                    814:                                break;
                    815:                        case 7:
                    816:                                type_to_fetch = type_param&PHP_DNS_TXT   ? DNS_T_TXT   : 0;
                    817:                                break;
                    818:                        case 8:
                    819:                                type_to_fetch = type_param&PHP_DNS_AAAA  ? DNS_T_AAAA  : 0;
                    820:                                break;
                    821:                        case 9:
                    822:                                type_to_fetch = type_param&PHP_DNS_SRV   ? DNS_T_SRV   : 0;
                    823:                                break;
                    824:                        case 10:
                    825:                                type_to_fetch = type_param&PHP_DNS_NAPTR ? DNS_T_NAPTR : 0;
                    826:                                break;
                    827:                        case 11:
                    828:                                type_to_fetch = type_param&PHP_DNS_A6    ? DNS_T_A6 : 0;
                    829:                                break;
                    830:                        case PHP_DNS_NUM_TYPES:
                    831:                                store_results = 0;
                    832:                                continue;
                    833:                        default:
                    834:                        case (PHP_DNS_NUM_TYPES + 1):
                    835:                                type_to_fetch = DNS_T_ANY;
                    836:                                break;
                    837:                }
                    838: 
                    839:                if (type_to_fetch) {
                    840: #if defined(HAVE_DNS_SEARCH)
                    841:                        handle = dns_open(NULL);
                    842:                        if (handle == NULL) {
                    843:                                zval_dtor(return_value);
                    844:                                RETURN_FALSE;
                    845:                        }
                    846: #elif defined(HAVE_RES_NSEARCH)
                    847:                    memset(&state, 0, sizeof(state));
                    848:                    if (res_ninit(handle)) {
                    849:                        zval_dtor(return_value);
                    850:                                RETURN_FALSE;
                    851:                        }
                    852: #else
                    853:                        res_init();
                    854: #endif
                    855: 
                    856:                        n = php_dns_search(handle, hostname, C_IN, type_to_fetch, answer.qb2, sizeof answer);
                    857: 
                    858:                        if (n < 0) {
                    859:                                php_dns_free_handle(handle);
                    860:                                continue;
                    861:                        }
                    862: 
                    863:                        cp = answer.qb2 + HFIXEDSZ;
                    864:                        end = answer.qb2 + n;
                    865:                        hp = (HEADER *)&answer;
                    866:                        qd = ntohs(hp->qdcount);
                    867:                        an = ntohs(hp->ancount);
                    868:                        ns = ntohs(hp->nscount);
                    869:                        ar = ntohs(hp->arcount);
                    870: 
                    871:                        /* Skip QD entries, they're only used by dn_expand later on */
                    872:                        while (qd-- > 0) {
                    873:                                n = dn_skipname(cp, end);
                    874:                                if (n < 0) {
                    875:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse DNS data received");
                    876:                                        zval_dtor(return_value);
                    877:                                        php_dns_free_handle(handle);
                    878:                                        RETURN_FALSE;
                    879:                                }
                    880:                                cp += n + QFIXEDSZ;
                    881:                        }
                    882: 
                    883:                        /* YAY! Our real answers! */
                    884:                        while (an-- && cp && cp < end) {
                    885:                                zval *retval;
                    886: 
1.1.1.2   misho     887:                                cp = php_parserr(cp, &answer, type_to_fetch, store_results, raw, &retval);
1.1       misho     888:                                if (retval != NULL && store_results) {
                    889:                                        add_next_index_zval(return_value, retval);
                    890:                                }
                    891:                        }
                    892: 
                    893:                        if (authns || addtl) {
                    894:                                /* List of Authoritative Name Servers
                    895:                                 * Process when only requesting addtl so that we can skip through the section
                    896:                                 */
                    897:                                while (ns-- > 0 && cp && cp < end) {
                    898:                                        zval *retval = NULL;
                    899: 
1.1.1.2   misho     900:                                        cp = php_parserr(cp, &answer, DNS_T_ANY, authns != NULL, raw, &retval);
1.1       misho     901:                                        if (retval != NULL) {
                    902:                                                add_next_index_zval(authns, retval);
                    903:                                        }
                    904:                                }
                    905:                        }
                    906: 
                    907:                        if (addtl) {
                    908:                                /* Additional records associated with authoritative name servers */
                    909:                                while (ar-- > 0 && cp && cp < end) {
                    910:                                        zval *retval = NULL;
                    911: 
1.1.1.2   misho     912:                                        cp = php_parserr(cp, &answer, DNS_T_ANY, 1, raw, &retval);
1.1       misho     913:                                        if (retval != NULL) {
                    914:                                                add_next_index_zval(addtl, retval);
                    915:                                        }
                    916:                                }
                    917:                        }
                    918:                        php_dns_free_handle(handle);
                    919:                }
                    920:        }
                    921: }
                    922: /* }}} */
                    923: 
                    924: /* {{{ proto bool dns_get_mx(string hostname, array mxhosts [, array weight])
                    925:    Get MX records corresponding to a given Internet host name */
                    926: PHP_FUNCTION(dns_get_mx)
                    927: {
                    928:        char *hostname;
                    929:        int hostname_len;
                    930:        zval *mx_list, *weight_list = NULL;
                    931:        int count, qdc;
                    932:        u_short type, weight;
                    933:        u_char ans[MAXPACKET];
                    934:        char buf[MAXHOSTNAMELEN];
                    935:        HEADER *hp;
                    936:        u_char *cp, *end;
                    937:        int i;
                    938: #if defined(HAVE_DNS_SEARCH)
                    939:        struct sockaddr_storage from;
                    940:        uint32_t fromsize = sizeof(from);
                    941:        dns_handle_t handle;
                    942: #elif defined(HAVE_RES_NSEARCH)
                    943:        struct __res_state state;
                    944:        struct __res_state *handle = &state;
                    945: #endif
                    946: 
                    947:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|z", &hostname, &hostname_len, &mx_list, &weight_list) == FAILURE) {
                    948:                return;
                    949:        }
                    950: 
                    951:        zval_dtor(mx_list);
                    952:        array_init(mx_list);
                    953: 
                    954:        if (weight_list) {
                    955:                zval_dtor(weight_list);
                    956:                array_init(weight_list);
                    957:        }
                    958: 
                    959: #if defined(HAVE_DNS_SEARCH)
                    960:        handle = dns_open(NULL);
                    961:        if (handle == NULL) {
                    962:                RETURN_FALSE;
                    963:        }
                    964: #elif defined(HAVE_RES_NSEARCH)
                    965:     memset(&state, 0, sizeof(state));
                    966:     if (res_ninit(handle)) {
                    967:                        RETURN_FALSE;
                    968:        }
                    969: #else
                    970:        res_init();
                    971: #endif
                    972: 
                    973:        i = php_dns_search(handle, hostname, C_IN, DNS_T_MX, (u_char *)&ans, sizeof(ans));
                    974:        if (i < 0) {
                    975:                RETURN_FALSE;
                    976:        }
                    977:        if (i > (int)sizeof(ans)) {
                    978:                i = sizeof(ans);
                    979:        }
                    980:        hp = (HEADER *)&ans;
                    981:        cp = (u_char *)&ans + HFIXEDSZ;
                    982:        end = (u_char *)&ans +i;
                    983:        for (qdc = ntohs((unsigned short)hp->qdcount); qdc--; cp += i + QFIXEDSZ) {
                    984:                if ((i = dn_skipname(cp, end)) < 0 ) {
                    985:                        php_dns_free_handle(handle);
                    986:                        RETURN_FALSE;
                    987:                }
                    988:        }
                    989:        count = ntohs((unsigned short)hp->ancount);
                    990:        while (--count >= 0 && cp < end) {
                    991:                if ((i = dn_skipname(cp, end)) < 0 ) {
                    992:                        php_dns_free_handle(handle);
                    993:                        RETURN_FALSE;
                    994:                }
                    995:                cp += i;
                    996:                GETSHORT(type, cp);
                    997:                cp += INT16SZ + INT32SZ;
                    998:                GETSHORT(i, cp);
                    999:                if (type != DNS_T_MX) {
                   1000:                        cp += i;
                   1001:                        continue;
                   1002:                }
                   1003:                GETSHORT(weight, cp);
                   1004:                if ((i = dn_expand(ans, end, cp, buf, sizeof(buf)-1)) < 0) {
                   1005:                        php_dns_free_handle(handle);
                   1006:                        RETURN_FALSE;
                   1007:                }
                   1008:                cp += i;
                   1009:                add_next_index_string(mx_list, buf, 1);
                   1010:                if (weight_list) {
                   1011:                        add_next_index_long(weight_list, weight);
                   1012:                }
                   1013:        }
                   1014:        php_dns_free_handle(handle);
                   1015:        RETURN_TRUE;
                   1016: }
                   1017: /* }}} */
                   1018: #endif /* HAVE_FULL_DNS_FUNCS */
                   1019: #endif /* !defined(PHP_WIN32) && (HAVE_DNS_SEARCH_FUNC && !(defined(__BEOS__) || defined(NETWARE))) */
                   1020: 
                   1021: #if HAVE_FULL_DNS_FUNCS || defined(PHP_WIN32)
                   1022: PHP_MINIT_FUNCTION(dns) {
                   1023:        REGISTER_LONG_CONSTANT("DNS_A",     PHP_DNS_A,     CONST_CS | CONST_PERSISTENT);
                   1024:        REGISTER_LONG_CONSTANT("DNS_NS",    PHP_DNS_NS,    CONST_CS | CONST_PERSISTENT);
                   1025:        REGISTER_LONG_CONSTANT("DNS_CNAME", PHP_DNS_CNAME, CONST_CS | CONST_PERSISTENT);
                   1026:        REGISTER_LONG_CONSTANT("DNS_SOA",   PHP_DNS_SOA,   CONST_CS | CONST_PERSISTENT);
                   1027:        REGISTER_LONG_CONSTANT("DNS_PTR",   PHP_DNS_PTR,   CONST_CS | CONST_PERSISTENT);
                   1028:        REGISTER_LONG_CONSTANT("DNS_HINFO", PHP_DNS_HINFO, CONST_CS | CONST_PERSISTENT);
                   1029:        REGISTER_LONG_CONSTANT("DNS_MX",    PHP_DNS_MX,    CONST_CS | CONST_PERSISTENT);
                   1030:        REGISTER_LONG_CONSTANT("DNS_TXT",   PHP_DNS_TXT,   CONST_CS | CONST_PERSISTENT);
                   1031:        REGISTER_LONG_CONSTANT("DNS_SRV",   PHP_DNS_SRV,   CONST_CS | CONST_PERSISTENT);
                   1032:        REGISTER_LONG_CONSTANT("DNS_NAPTR", PHP_DNS_NAPTR, CONST_CS | CONST_PERSISTENT);
                   1033:        REGISTER_LONG_CONSTANT("DNS_AAAA",  PHP_DNS_AAAA,  CONST_CS | CONST_PERSISTENT);
                   1034:        REGISTER_LONG_CONSTANT("DNS_A6",    PHP_DNS_A6,    CONST_CS | CONST_PERSISTENT);
                   1035:        REGISTER_LONG_CONSTANT("DNS_ANY",   PHP_DNS_ANY,   CONST_CS | CONST_PERSISTENT);
                   1036:        REGISTER_LONG_CONSTANT("DNS_ALL",   PHP_DNS_ALL,   CONST_CS | CONST_PERSISTENT);
                   1037:        return SUCCESS;
                   1038: }
                   1039: #endif /* HAVE_FULL_DNS_FUNCS */
                   1040: 
                   1041: /*
                   1042:  * Local variables:
                   1043:  * tab-width: 4
                   1044:  * c-basic-offset: 4
                   1045:  * End:
                   1046:  * vim600: sw=4 ts=4 fdm=marker
                   1047:  * vim<600: sw=4 ts=4
                   1048:  */

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