Return to dns.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / standard |
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: */