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, 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>0)?dlen - 1:0, 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 */ 704PHP_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 */ 890PHP_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) 986PHP_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 */ 1013