1/* 2 +----------------------------------------------------------------------+ 3 | PHP Version 5 | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1997-2013 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$ */ 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 123static char *php_gethostbyaddr(char *ip); 124static char *php_gethostbyname(char *name); 125 126#ifdef HAVE_GETHOSTNAME 127/* {{{ proto string gethostname() 128 Get the host name of the current machine */ 129PHP_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 */ 153PHP_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 */ 179static 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 */ 215PHP_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. */ 233PHP_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 */ 260static 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 314typedef 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__) 327static 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 */ 342PHP_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 */ 416static u_char *php_parserr(u_char *cp, querybuf *answer, int type_to_fetch, int store, int raw, 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 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 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 527 add_assoc_stringl(*subarray, "txt", tp, (dlen>0)?dlen - 1:0, 0); 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: 702 zval_ptr_dtor(subarray); 703 *subarray = NULL; 704 cp += dlen; 705 break; 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 */ 714PHP_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; 734 zend_bool raw = 0; 735 736 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lz!z!b", 737 &hostname, &hostname_len, &type_param, &authns, &addtl, &raw) == FAILURE) { 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 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 } 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 ) 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. 773 */ 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 ( ; 784 type < (addtl ? (PHP_DNS_NUM_TYPES + 2) : PHP_DNS_NUM_TYPES) || first_query; 785 type++ 786 ) { 787 first_query = 0; 788 switch (type) { 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; 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 887 cp = php_parserr(cp, &answer, type_to_fetch, store_results, raw, &retval); 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 900 cp = php_parserr(cp, &answer, DNS_T_ANY, authns != NULL, raw, &retval); 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 912 cp = php_parserr(cp, &answer, DNS_T_ANY, 1, raw, &retval); 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 */ 926PHP_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) 1022PHP_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 */ 1049