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>