root/ext/standard/dns.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. PHP_FUNCTION
  2. PHP_FUNCTION
  3. php_gethostbyaddr
  4. PHP_FUNCTION
  5. PHP_FUNCTION
  6. php_gethostbyname
  7. _php_dns_free_res
  8. PHP_FUNCTION
  9. php_parserr
  10. PHP_FUNCTION
  11. PHP_FUNCTION
  12. PHP_MINIT_FUNCTION

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 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 
 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         if(hostname_len > MAXFQDNLEN) {
 226                 /* name too long, protect from CVE-2015-0235 */
 227                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host name is too long, the limit is %d characters", MAXFQDNLEN);
 228                 RETURN_STRINGL(hostname, hostname_len, 1);
 229         }
 230         addr = php_gethostbyname(hostname);
 231 
 232         RETVAL_STRING(addr, 0);
 233 }
 234 /* }}} */
 235 
 236 /* {{{ proto array gethostbynamel(string hostname)
 237    Return a list of IP addresses that a given hostname resolves to. */
 238 PHP_FUNCTION(gethostbynamel)
 239 {
 240         char *hostname;
 241         int hostname_len;
 242         struct hostent *hp;
 243         struct in_addr in;
 244         int i;
 245 
 246         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &hostname, &hostname_len) == FAILURE) {
 247                 return;
 248         }
 249 
 250         if(hostname_len > MAXFQDNLEN) {
 251                 /* name too long, protect from CVE-2015-0235 */
 252                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host name is too long, the limit is %d characters", MAXFQDNLEN);
 253                 RETURN_FALSE;
 254         }
 255 
 256         hp = gethostbyname(hostname);
 257         if (hp == NULL || hp->h_addr_list == NULL) {
 258                 RETURN_FALSE;
 259         }
 260 
 261         array_init(return_value);
 262 
 263         for (i = 0 ; hp->h_addr_list[i] != 0 ; i++) {
 264                 in = *(struct in_addr *) hp->h_addr_list[i];
 265                 add_next_index_string(return_value, inet_ntoa(in), 1);
 266         }
 267 }
 268 /* }}} */
 269 
 270 /* {{{ php_gethostbyname */
 271 static char *php_gethostbyname(char *name)
 272 {
 273         struct hostent *hp;
 274         struct in_addr in;
 275 
 276         hp = gethostbyname(name);
 277 
 278         if (!hp || !*(hp->h_addr_list)) {
 279                 return estrdup(name);
 280         }
 281 
 282         memcpy(&in.s_addr, *(hp->h_addr_list), sizeof(in.s_addr));
 283 
 284         return estrdup(inet_ntoa(in));
 285 }
 286 /* }}} */
 287 
 288 #if HAVE_FULL_DNS_FUNCS || defined(PHP_WIN32)
 289 # define PHP_DNS_NUM_TYPES      12      /* Number of DNS Types Supported by PHP currently */
 290 
 291 # define PHP_DNS_A      0x00000001
 292 # define PHP_DNS_NS     0x00000002
 293 # define PHP_DNS_CNAME  0x00000010
 294 # define PHP_DNS_SOA    0x00000020
 295 # define PHP_DNS_PTR    0x00000800
 296 # define PHP_DNS_HINFO  0x00001000
 297 # define PHP_DNS_MX     0x00004000
 298 # define PHP_DNS_TXT    0x00008000
 299 # define PHP_DNS_A6     0x01000000
 300 # define PHP_DNS_SRV    0x02000000
 301 # define PHP_DNS_NAPTR  0x04000000
 302 # define PHP_DNS_AAAA   0x08000000
 303 # define PHP_DNS_ANY    0x10000000
 304 # 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)
 305 #endif /* HAVE_FULL_DNS_FUNCS || defined(PHP_WIN32) */
 306 
 307 /* Note: These functions are defined in ext/standard/dns_win32.c for Windows! */
 308 #if !defined(PHP_WIN32) && (HAVE_DNS_SEARCH_FUNC && !(defined(__BEOS__) || defined(NETWARE)))
 309   
 310 #ifndef HFIXEDSZ
 311 #define HFIXEDSZ        12      /* fixed data in header <arpa/nameser.h> */
 312 #endif /* HFIXEDSZ */
 313 
 314 #ifndef QFIXEDSZ
 315 #define QFIXEDSZ        4       /* fixed data in query <arpa/nameser.h> */
 316 #endif /* QFIXEDSZ */
 317 
 318 #undef MAXHOSTNAMELEN
 319 #define MAXHOSTNAMELEN  1024
 320 
 321 #ifndef MAXRESOURCERECORDS
 322 #define MAXRESOURCERECORDS      64
 323 #endif /* MAXRESOURCERECORDS */
 324 
 325 typedef union {
 326         HEADER qb1;
 327         u_char qb2[65536];
 328 } querybuf;
 329 
 330 /* just a hack to free resources allocated by glibc in __res_nsend()
 331  * See also:
 332  *   res_thread_freeres() in glibc/resolv/res_init.c
 333  *   __libc_res_nsend()   in resolv/res_send.c
 334  * */
 335 
 336 #if defined(__GLIBC__) && !defined(HAVE_DEPRECATED_DNS_FUNCS)
 337 #define php_dns_free_res(__res__) _php_dns_free_res(__res__)
 338 static void _php_dns_free_res(struct __res_state res) { /* {{{ */
 339         int ns;
 340         for (ns = 0; ns < MAXNS; ns++) {
 341                 if (res._u._ext.nsaddrs[ns] != NULL) {
 342                         free (res._u._ext.nsaddrs[ns]);
 343                         res._u._ext.nsaddrs[ns] = NULL;
 344                 }
 345         }
 346 } /* }}} */
 347 #else
 348 #define php_dns_free_res(__res__)
 349 #endif
 350 
 351 /* {{{ proto bool dns_check_record(string host [, string type])
 352    Check DNS records corresponding to a given Internet host name or IP address */
 353 PHP_FUNCTION(dns_check_record)
 354 {
 355 #ifndef MAXPACKET
 356 #define MAXPACKET  8192 /* max packet size used internally by BIND */
 357 #endif
 358         u_char ans[MAXPACKET];
 359         char *hostname, *rectype = NULL;
 360         int hostname_len, rectype_len = 0;
 361         int type = T_MX, i;
 362 #if defined(HAVE_DNS_SEARCH)
 363         struct sockaddr_storage from;
 364         uint32_t fromsize = sizeof(from);
 365         dns_handle_t handle;
 366 #elif defined(HAVE_RES_NSEARCH)
 367         struct __res_state state;
 368         struct __res_state *handle = &state;
 369 #endif
 370 
 371         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &hostname, &hostname_len, &rectype, &rectype_len) == FAILURE) {
 372                 return;
 373         }
 374 
 375         if (hostname_len == 0) {
 376                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host cannot be empty");
 377                 RETURN_FALSE;
 378         }
 379 
 380         if (rectype) {
 381                 if (!strcasecmp("A",     rectype)) type = T_A;
 382                 else if (!strcasecmp("NS",    rectype)) type = DNS_T_NS;
 383                 else if (!strcasecmp("MX",    rectype)) type = DNS_T_MX;
 384                 else if (!strcasecmp("PTR",   rectype)) type = DNS_T_PTR;
 385                 else if (!strcasecmp("ANY",   rectype)) type = DNS_T_ANY;
 386                 else if (!strcasecmp("SOA",   rectype)) type = DNS_T_SOA;
 387                 else if (!strcasecmp("TXT",   rectype)) type = DNS_T_TXT;
 388                 else if (!strcasecmp("CNAME", rectype)) type = DNS_T_CNAME;
 389                 else if (!strcasecmp("AAAA",  rectype)) type = DNS_T_AAAA;
 390                 else if (!strcasecmp("SRV",   rectype)) type = DNS_T_SRV;
 391                 else if (!strcasecmp("NAPTR", rectype)) type = DNS_T_NAPTR;
 392                 else if (!strcasecmp("A6",    rectype)) type = DNS_T_A6;
 393                 else {
 394                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type '%s' not supported", rectype);
 395                         RETURN_FALSE;
 396                 }
 397         }
 398 
 399 #if defined(HAVE_DNS_SEARCH)
 400         handle = dns_open(NULL);
 401         if (handle == NULL) {
 402                 RETURN_FALSE;
 403         }
 404 #elif defined(HAVE_RES_NSEARCH)
 405     memset(&state, 0, sizeof(state));
 406     if (res_ninit(handle)) {
 407                         RETURN_FALSE;
 408         }
 409 #else
 410         res_init();
 411 #endif
 412 
 413         RETVAL_TRUE;
 414         i = php_dns_search(handle, hostname, C_IN, type, ans, sizeof(ans));
 415 
 416         if (i < 0) {
 417                 RETVAL_FALSE;
 418         }
 419 
 420         php_dns_free_handle(handle);
 421 }
 422 /* }}} */
 423 
 424 #if HAVE_FULL_DNS_FUNCS
 425 
 426 #define CHECKCP(n) do { \
 427         if (cp + n > end) { \
 428                 return NULL; \
 429         } \
 430 } while (0)
 431 
 432 /* {{{ php_parserr */
 433 static u_char *php_parserr(u_char *cp, u_char *end, querybuf *answer, int type_to_fetch, int store, int raw, zval **subarray)
 434 {
 435         u_short type, class, dlen;
 436         u_long ttl;
 437         long n, i;
 438         u_short s;
 439         u_char *tp, *p;
 440         char name[MAXHOSTNAMELEN];
 441         int have_v6_break = 0, in_v6_break = 0;
 442 
 443         *subarray = NULL;
 444 
 445         n = dn_expand(answer->qb2, end, cp, name, sizeof(name) - 2);
 446         if (n < 0) {
 447                 return NULL;
 448         }
 449         cp += n;
 450 
 451         CHECKCP(10);
 452         GETSHORT(type, cp);
 453         GETSHORT(class, cp);
 454         GETLONG(ttl, cp);
 455         GETSHORT(dlen, cp);
 456         CHECKCP(dlen);
 457         if (type_to_fetch != T_ANY && type != type_to_fetch) {
 458                 cp += dlen;
 459                 return cp;
 460         }
 461 
 462         if (!store) {
 463                 cp += dlen;
 464                 return cp;
 465         }
 466 
 467         ALLOC_INIT_ZVAL(*subarray);
 468         array_init(*subarray);
 469 
 470         add_assoc_string(*subarray, "host", name, 1);
 471         add_assoc_string(*subarray, "class", "IN", 1);
 472         add_assoc_long(*subarray, "ttl", ttl);
 473 
 474         if (raw) {
 475                 add_assoc_long(*subarray, "type", type);
 476                 add_assoc_stringl(*subarray, "data", (char*) cp, (uint) dlen, 1);
 477                 cp += dlen;
 478                 return cp;
 479         }
 480 
 481         switch (type) {
 482                 case DNS_T_A:
 483                         CHECKCP(4);
 484                         add_assoc_string(*subarray, "type", "A", 1);
 485                         snprintf(name, sizeof(name), "%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
 486                         add_assoc_string(*subarray, "ip", name, 1);
 487                         cp += dlen;
 488                         break;
 489                 case DNS_T_MX:
 490                         CHECKCP(2);
 491                         add_assoc_string(*subarray, "type", "MX", 1);
 492                         GETSHORT(n, cp);
 493                         add_assoc_long(*subarray, "pri", n);
 494                         /* no break; */
 495                 case DNS_T_CNAME:
 496                         if (type == DNS_T_CNAME) {
 497                                 add_assoc_string(*subarray, "type", "CNAME", 1);
 498                         }
 499                         /* no break; */
 500                 case DNS_T_NS:
 501                         if (type == DNS_T_NS) {
 502                                 add_assoc_string(*subarray, "type", "NS", 1);
 503                         }
 504                         /* no break; */
 505                 case DNS_T_PTR:
 506                         if (type == DNS_T_PTR) {
 507                                 add_assoc_string(*subarray, "type", "PTR", 1);
 508                         }
 509                         n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2);
 510                         if (n < 0) {
 511                                 return NULL;
 512                         }
 513                         cp += n;
 514                         add_assoc_string(*subarray, "target", name, 1);
 515                         break;
 516                 case DNS_T_HINFO:
 517                         /* See RFC 1010 for values */
 518                         add_assoc_string(*subarray, "type", "HINFO", 1);
 519                         CHECKCP(1);
 520                         n = *cp & 0xFF;
 521                         cp++;
 522                         CHECKCP(n);
 523                         add_assoc_stringl(*subarray, "cpu", (char*)cp, n, 1);
 524                         cp += n;
 525                         CHECKCP(1);
 526                         n = *cp & 0xFF;
 527                         cp++;
 528                         CHECKCP(n);
 529                         add_assoc_stringl(*subarray, "os", (char*)cp, n, 1);
 530                         cp += n;
 531                         break;
 532                 case DNS_T_TXT:
 533                         {
 534                                 int l1 = 0, l2 = 0;
 535                                 zval *entries = NULL;
 536 
 537                                 add_assoc_string(*subarray, "type", "TXT", 1);
 538                                 tp = emalloc(dlen + 1);
 539                                 
 540                                 MAKE_STD_ZVAL(entries);
 541                                 array_init(entries);
 542                                 
 543                                 while (l1 < dlen) {
 544                                         n = cp[l1];
 545                                         if ((l1 + n) >= dlen) {
 546                                                 // Invalid chunk length, truncate
 547                                                 n = dlen - (l1 + 1);
 548                                         }
 549                                         if (n) {
 550                                                 memcpy(tp + l2 , cp + l1 + 1, n);
 551                                                 add_next_index_stringl(entries, cp + l1 + 1, n, 1);
 552                                         }
 553                                         l1 = l1 + n + 1;
 554                                         l2 = l2 + n;
 555                                 }
 556                                 tp[l2] = '\0';
 557                                 cp += dlen;
 558 
 559                                 add_assoc_stringl(*subarray, "txt", tp, l2, 0);
 560                                 add_assoc_zval(*subarray, "entries", entries);
 561                         }
 562                         break;
 563                 case DNS_T_SOA:
 564                         add_assoc_string(*subarray, "type", "SOA", 1);
 565                         n = dn_expand(answer->qb2, end, cp, name, (sizeof name) -2);
 566                         if (n < 0) {
 567                                 return NULL;
 568                         }
 569                         cp += n;
 570                         add_assoc_string(*subarray, "mname", name, 1);
 571                         n = dn_expand(answer->qb2, end, cp, name, (sizeof name) -2);
 572                         if (n < 0) {
 573                                 return NULL;
 574                         }
 575                         cp += n;
 576                         add_assoc_string(*subarray, "rname", name, 1);
 577                         CHECKCP(5*4);
 578                         GETLONG(n, cp);
 579                         add_assoc_long(*subarray, "serial", n);
 580                         GETLONG(n, cp);
 581                         add_assoc_long(*subarray, "refresh", n);
 582                         GETLONG(n, cp);
 583                         add_assoc_long(*subarray, "retry", n);
 584                         GETLONG(n, cp);
 585                         add_assoc_long(*subarray, "expire", n);
 586                         GETLONG(n, cp);
 587                         add_assoc_long(*subarray, "minimum-ttl", n);
 588                         break;
 589                 case DNS_T_AAAA:
 590                         tp = (u_char*)name;
 591                         CHECKCP(8*2);
 592                         for(i=0; i < 8; i++) {
 593                                 GETSHORT(s, cp);
 594                                 if (s != 0) {
 595                                         if (tp > (u_char *)name) {
 596                                                 in_v6_break = 0;
 597                                                 tp[0] = ':';
 598                                                 tp++;
 599                                         }
 600                                         tp += sprintf((char*)tp,"%x",s);
 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                         }
 615                         if (have_v6_break && in_v6_break) {
 616                                 tp[0] = ':';
 617                                 tp++;
 618                         }
 619                         tp[0] = '\0';
 620                         add_assoc_string(*subarray, "type", "AAAA", 1);
 621                         add_assoc_string(*subarray, "ipv6", name, 1);
 622                         break;
 623                 case DNS_T_A6:
 624                         p = cp;
 625                         add_assoc_string(*subarray, "type", "A6", 1);
 626                         CHECKCP(1);
 627                         n = ((int)cp[0]) & 0xFF;
 628                         cp++;
 629                         add_assoc_long(*subarray, "masklen", n);
 630                         tp = (u_char*)name;
 631                         if (n > 15) {
 632                                 have_v6_break = 1;
 633                                 in_v6_break = 1;
 634                                 tp[0] = ':';
 635                                 tp++;
 636                         }
 637                         if (n % 16 > 8) {
 638                                 /* Partial short */
 639                                 if (cp[0] != 0) {
 640                                         if (tp > (u_char *)name) {
 641                                                 in_v6_break = 0;
 642                                                 tp[0] = ':';
 643                                                 tp++;
 644                                         }
 645                                         sprintf((char*)tp, "%x", cp[0] & 0xFF);
 646                                 } else {
 647                                         if (!have_v6_break) {
 648                                                 have_v6_break = 1;
 649                                                 in_v6_break = 1;
 650                                                 tp[0] = ':';
 651                                                 tp++;
 652                                         } else if (!in_v6_break) {
 653                                                 tp[0] = ':';
 654                                                 tp++;
 655                                                 tp[0] = '0';
 656                                                 tp++;
 657                                         }
 658                                 }
 659                                 cp++;
 660                         }
 661                         for (i = (n + 8) / 16; i < 8; i++) {
 662                                 CHECKCP(2);
 663                                 GETSHORT(s, cp);
 664                                 if (s != 0) {
 665                                         if (tp > (u_char *)name) {
 666                                                 in_v6_break = 0;
 667                                                 tp[0] = ':';
 668                                                 tp++;
 669                                         }
 670                                         tp += sprintf((char*)tp,"%x",s);
 671                                 } else {
 672                                         if (!have_v6_break) {
 673                                                 have_v6_break = 1;
 674                                                 in_v6_break = 1;
 675                                                 tp[0] = ':';
 676                                                 tp++;
 677                                         } else if (!in_v6_break) {
 678                                                 tp[0] = ':';
 679                                                 tp++;
 680                                                 tp[0] = '0';
 681                                                 tp++;
 682                                         }
 683                                 }
 684                         }
 685                         if (have_v6_break && in_v6_break) {
 686                                 tp[0] = ':';
 687                                 tp++;
 688                         }
 689                         tp[0] = '\0';
 690                         add_assoc_string(*subarray, "ipv6", name, 1);
 691                         if (cp < p + dlen) {
 692                                 n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2);
 693                                 if (n < 0) {
 694                                         return NULL;
 695                                 }
 696                                 cp += n;
 697                                 add_assoc_string(*subarray, "chain", name, 1);
 698                         }
 699                         break;
 700                 case DNS_T_SRV:
 701                         CHECKCP(3*2);
 702                         add_assoc_string(*subarray, "type", "SRV", 1);
 703                         GETSHORT(n, cp);
 704                         add_assoc_long(*subarray, "pri", n);
 705                         GETSHORT(n, cp);
 706                         add_assoc_long(*subarray, "weight", n);
 707                         GETSHORT(n, cp);
 708                         add_assoc_long(*subarray, "port", n);
 709                         n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2);
 710                         if (n < 0) {
 711                                 return NULL;
 712                         }
 713                         cp += n;
 714                         add_assoc_string(*subarray, "target", name, 1);
 715                         break;
 716                 case DNS_T_NAPTR:
 717                         CHECKCP(2*2);
 718                         add_assoc_string(*subarray, "type", "NAPTR", 1);
 719                         GETSHORT(n, cp);
 720                         add_assoc_long(*subarray, "order", n);
 721                         GETSHORT(n, cp);
 722                         add_assoc_long(*subarray, "pref", n);
 723 
 724                         CHECKCP(1);
 725                         n = (cp[0] & 0xFF);
 726                         cp++;
 727                         CHECKCP(n);
 728                         add_assoc_stringl(*subarray, "flags", (char*)cp, n, 1);
 729                         cp += n;
 730 
 731                         CHECKCP(1);
 732                         n = (cp[0] & 0xFF);
 733                         cp++;
 734                         CHECKCP(n);
 735                         add_assoc_stringl(*subarray, "services", (char*)cp, n, 1);
 736                         cp += n;
 737 
 738                         CHECKCP(1);
 739                         n = (cp[0] & 0xFF);
 740                         cp++;
 741                         CHECKCP(n);
 742                         add_assoc_stringl(*subarray, "regex", (char*)cp, n, 1);
 743                         cp += n;
 744 
 745                         n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2);
 746                         if (n < 0) {
 747                                 return NULL;
 748                         }
 749                         cp += n;
 750                         add_assoc_string(*subarray, "replacement", name, 1);
 751                         break;
 752                 default:
 753                         zval_ptr_dtor(subarray);
 754                         *subarray = NULL;
 755                         cp += dlen;
 756                         break;
 757         }
 758 
 759         return cp;
 760 }
 761 /* }}} */
 762 
 763 /* {{{ proto array|false dns_get_record(string hostname [, int type[, array authns, array addtl]])
 764    Get any Resource Record corresponding to a given Internet host name */
 765 PHP_FUNCTION(dns_get_record)
 766 {
 767         char *hostname;
 768         int hostname_len;
 769         long type_param = PHP_DNS_ANY;
 770         zval *authns = NULL, *addtl = NULL;
 771         int type_to_fetch;
 772 #if defined(HAVE_DNS_SEARCH)
 773         struct sockaddr_storage from;
 774         uint32_t fromsize = sizeof(from);
 775         dns_handle_t handle;
 776 #elif defined(HAVE_RES_NSEARCH)
 777         struct __res_state state;
 778         struct __res_state *handle = &state;
 779 #endif
 780         HEADER *hp;
 781         querybuf answer;
 782         u_char *cp = NULL, *end = NULL;
 783         int n, qd, an, ns = 0, ar = 0;
 784         int type, first_query = 1, store_results = 1;
 785         zend_bool raw = 0;
 786 
 787         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lz!z!b",
 788                         &hostname, &hostname_len, &type_param, &authns, &addtl, &raw) == FAILURE) {
 789                 return;
 790         }
 791 
 792         if (authns) {
 793                 zval_dtor(authns);
 794                 array_init(authns);
 795         }
 796         if (addtl) {
 797                 zval_dtor(addtl);
 798                 array_init(addtl);
 799         }
 800 
 801         if (!raw) {
 802                 if ((type_param & ~PHP_DNS_ALL) && (type_param != PHP_DNS_ANY)) {
 803                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type '%ld' not supported", type_param);
 804                         RETURN_FALSE;
 805                 }
 806         } else {
 807                 if ((type_param < 1) || (type_param > 0xFFFF)) {
 808                         php_error_docref(NULL TSRMLS_CC, E_WARNING,
 809                                 "Numeric DNS record type must be between 1 and 65535, '%ld' given", type_param);
 810                         RETURN_FALSE;
 811                 }
 812         }
 813 
 814         /* Initialize the return array */
 815         array_init(return_value);
 816 
 817         /* - We emulate an or'ed type mask by querying type by type. (Steps 0 - NUMTYPES-1 )
 818          *   If additional info is wanted we check again with DNS_T_ANY (step NUMTYPES / NUMTYPES+1 )
 819          *   store_results is used to skip storing the results retrieved in step
 820          *   NUMTYPES+1 when results were already fetched.
 821          * - In case of PHP_DNS_ANY we use the directly fetch DNS_T_ANY. (step NUMTYPES+1 )
 822          * - In case of raw mode, we query only the requestd type instead of looping type by type
 823          *   before going with the additional info stuff.
 824          */
 825 
 826         if (raw) {
 827                 type = -1;
 828         } else if (type_param == PHP_DNS_ANY) {
 829                 type = PHP_DNS_NUM_TYPES + 1;
 830         } else {
 831                 type = 0;
 832         }
 833 
 834         for ( ;
 835                 type < (addtl ? (PHP_DNS_NUM_TYPES + 2) : PHP_DNS_NUM_TYPES) || first_query;
 836                 type++
 837         ) {
 838                 first_query = 0;
 839                 switch (type) {
 840                         case -1: /* raw */
 841                                 type_to_fetch = type_param;
 842                                 /* skip over the rest and go directly to additional records */
 843                                 type = PHP_DNS_NUM_TYPES - 1;
 844                                 break;
 845                         case 0:
 846                                 type_to_fetch = type_param&PHP_DNS_A     ? DNS_T_A     : 0;
 847                                 break;
 848                         case 1:
 849                                 type_to_fetch = type_param&PHP_DNS_NS    ? DNS_T_NS    : 0;
 850                                 break;
 851                         case 2:
 852                                 type_to_fetch = type_param&PHP_DNS_CNAME ? DNS_T_CNAME : 0;
 853                                 break;
 854                         case 3:
 855                                 type_to_fetch = type_param&PHP_DNS_SOA   ? DNS_T_SOA   : 0;
 856                                 break;
 857                         case 4:
 858                                 type_to_fetch = type_param&PHP_DNS_PTR   ? DNS_T_PTR   : 0;
 859                                 break;
 860                         case 5:
 861                                 type_to_fetch = type_param&PHP_DNS_HINFO ? DNS_T_HINFO : 0;
 862                                 break;
 863                         case 6:
 864                                 type_to_fetch = type_param&PHP_DNS_MX    ? DNS_T_MX    : 0;
 865                                 break;
 866                         case 7:
 867                                 type_to_fetch = type_param&PHP_DNS_TXT   ? DNS_T_TXT   : 0;
 868                                 break;
 869                         case 8:
 870                                 type_to_fetch = type_param&PHP_DNS_AAAA  ? DNS_T_AAAA  : 0;
 871                                 break;
 872                         case 9:
 873                                 type_to_fetch = type_param&PHP_DNS_SRV   ? DNS_T_SRV   : 0;
 874                                 break;
 875                         case 10:
 876                                 type_to_fetch = type_param&PHP_DNS_NAPTR ? DNS_T_NAPTR : 0;
 877                                 break;
 878                         case 11:
 879                                 type_to_fetch = type_param&PHP_DNS_A6    ? DNS_T_A6 : 0;
 880                                 break;
 881                         case PHP_DNS_NUM_TYPES:
 882                                 store_results = 0;
 883                                 continue;
 884                         default:
 885                         case (PHP_DNS_NUM_TYPES + 1):
 886                                 type_to_fetch = DNS_T_ANY;
 887                                 break;
 888                 }
 889 
 890                 if (type_to_fetch) {
 891 #if defined(HAVE_DNS_SEARCH)
 892                         handle = dns_open(NULL);
 893                         if (handle == NULL) {
 894                                 zval_dtor(return_value);
 895                                 RETURN_FALSE;
 896                         }
 897 #elif defined(HAVE_RES_NSEARCH)
 898                     memset(&state, 0, sizeof(state));
 899                     if (res_ninit(handle)) {
 900                         zval_dtor(return_value);
 901                                 RETURN_FALSE;
 902                         }
 903 #else
 904                         res_init();
 905 #endif
 906 
 907                         n = php_dns_search(handle, hostname, C_IN, type_to_fetch, answer.qb2, sizeof answer);
 908 
 909                         if (n < 0) {
 910                                 php_dns_free_handle(handle);
 911                                 switch (h_errno) {
 912                                         case NO_DATA:
 913                                         case HOST_NOT_FOUND:
 914                                                 continue;
 915 
 916                                         case NO_RECOVERY:
 917                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "An unexpected server failure occurred.");
 918                                                 break;
 919 
 920                                         case TRY_AGAIN:
 921                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "A temporary server error occurred.");
 922                                                 break;
 923 
 924                                         default:
 925                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "DNS Query failed");
 926                                 }
 927                                 zval_dtor(return_value);
 928                                 RETURN_FALSE;
 929                         }
 930 
 931                         cp = answer.qb2 + HFIXEDSZ;
 932                         end = answer.qb2 + n;
 933                         hp = (HEADER *)&answer;
 934                         qd = ntohs(hp->qdcount);
 935                         an = ntohs(hp->ancount);
 936                         ns = ntohs(hp->nscount);
 937                         ar = ntohs(hp->arcount);
 938 
 939                         /* Skip QD entries, they're only used by dn_expand later on */
 940                         while (qd-- > 0) {
 941                                 n = dn_skipname(cp, end);
 942                                 if (n < 0) {
 943                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse DNS data received");
 944                                         zval_dtor(return_value);
 945                                         php_dns_free_handle(handle);
 946                                         RETURN_FALSE;
 947                                 }
 948                                 cp += n + QFIXEDSZ;
 949                         }
 950 
 951                         /* YAY! Our real answers! */
 952                         while (an-- && cp && cp < end) {
 953                                 zval *retval;
 954 
 955                                 cp = php_parserr(cp, end, &answer, type_to_fetch, store_results, raw, &retval);
 956                                 if (retval != NULL && store_results) {
 957                                         add_next_index_zval(return_value, retval);
 958                                 }
 959                         }
 960 
 961                         if (authns || addtl) {
 962                                 /* List of Authoritative Name Servers
 963                                  * Process when only requesting addtl so that we can skip through the section
 964                                  */
 965                                 while (ns-- > 0 && cp && cp < end) {
 966                                         zval *retval = NULL;
 967 
 968                                         cp = php_parserr(cp, end, &answer, DNS_T_ANY, authns != NULL, raw, &retval);
 969                                         if (retval != NULL) {
 970                                                 add_next_index_zval(authns, retval);
 971                                         }
 972                                 }
 973                         }
 974 
 975                         if (addtl) {
 976                                 /* Additional records associated with authoritative name servers */
 977                                 while (ar-- > 0 && cp && cp < end) {
 978                                         zval *retval = NULL;
 979 
 980                                         cp = php_parserr(cp, end, &answer, DNS_T_ANY, 1, raw, &retval);
 981                                         if (retval != NULL) {
 982                                                 add_next_index_zval(addtl, retval);
 983                                         }
 984                                 }
 985                         }
 986                         php_dns_free_handle(handle);
 987                 }
 988         }
 989 }
 990 /* }}} */
 991 
 992 /* {{{ proto bool dns_get_mx(string hostname, array mxhosts [, array weight])
 993    Get MX records corresponding to a given Internet host name */
 994 PHP_FUNCTION(dns_get_mx)
 995 {
 996         char *hostname;
 997         int hostname_len;
 998         zval *mx_list, *weight_list = NULL;
 999         int count, qdc;
1000         u_short type, weight;
1001         u_char ans[MAXPACKET];
1002         char buf[MAXHOSTNAMELEN];
1003         HEADER *hp;
1004         u_char *cp, *end;
1005         int i;
1006 #if defined(HAVE_DNS_SEARCH)
1007         struct sockaddr_storage from;
1008         uint32_t fromsize = sizeof(from);
1009         dns_handle_t handle;
1010 #elif defined(HAVE_RES_NSEARCH)
1011         struct __res_state state;
1012         struct __res_state *handle = &state;
1013 #endif
1014 
1015         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|z", &hostname, &hostname_len, &mx_list, &weight_list) == FAILURE) {
1016                 return;
1017         }
1018 
1019         zval_dtor(mx_list);
1020         array_init(mx_list);
1021 
1022         if (weight_list) {
1023                 zval_dtor(weight_list);
1024                 array_init(weight_list);
1025         }
1026 
1027 #if defined(HAVE_DNS_SEARCH)
1028         handle = dns_open(NULL);
1029         if (handle == NULL) {
1030                 RETURN_FALSE;
1031         }
1032 #elif defined(HAVE_RES_NSEARCH)
1033     memset(&state, 0, sizeof(state));
1034     if (res_ninit(handle)) {
1035                         RETURN_FALSE;
1036         }
1037 #else
1038         res_init();
1039 #endif
1040 
1041         i = php_dns_search(handle, hostname, C_IN, DNS_T_MX, (u_char *)&ans, sizeof(ans));
1042         if (i < 0) {
1043                 RETURN_FALSE;
1044         }
1045         if (i > (int)sizeof(ans)) {
1046                 i = sizeof(ans);
1047         }
1048         hp = (HEADER *)&ans;
1049         cp = (u_char *)&ans + HFIXEDSZ;
1050         end = (u_char *)&ans +i;
1051         for (qdc = ntohs((unsigned short)hp->qdcount); qdc--; cp += i + QFIXEDSZ) {
1052                 if ((i = dn_skipname(cp, end)) < 0 ) {
1053                         php_dns_free_handle(handle);
1054                         RETURN_FALSE;
1055                 }
1056         }
1057         count = ntohs((unsigned short)hp->ancount);
1058         while (--count >= 0 && cp < end) {
1059                 if ((i = dn_skipname(cp, end)) < 0 ) {
1060                         php_dns_free_handle(handle);
1061                         RETURN_FALSE;
1062                 }
1063                 cp += i;
1064                 GETSHORT(type, cp);
1065                 cp += INT16SZ + INT32SZ;
1066                 GETSHORT(i, cp);
1067                 if (type != DNS_T_MX) {
1068                         cp += i;
1069                         continue;
1070                 }
1071                 GETSHORT(weight, cp);
1072                 if ((i = dn_expand(ans, end, cp, buf, sizeof(buf)-1)) < 0) {
1073                         php_dns_free_handle(handle);
1074                         RETURN_FALSE;
1075                 }
1076                 cp += i;
1077                 add_next_index_string(mx_list, buf, 1);
1078                 if (weight_list) {
1079                         add_next_index_long(weight_list, weight);
1080                 }
1081         }
1082         php_dns_free_handle(handle);
1083         RETURN_TRUE;
1084 }
1085 /* }}} */
1086 #endif /* HAVE_FULL_DNS_FUNCS */
1087 #endif /* !defined(PHP_WIN32) && (HAVE_DNS_SEARCH_FUNC && !(defined(__BEOS__) || defined(NETWARE))) */
1088 
1089 #if HAVE_FULL_DNS_FUNCS || defined(PHP_WIN32)
1090 PHP_MINIT_FUNCTION(dns) {
1091         REGISTER_LONG_CONSTANT("DNS_A",     PHP_DNS_A,     CONST_CS | CONST_PERSISTENT);
1092         REGISTER_LONG_CONSTANT("DNS_NS",    PHP_DNS_NS,    CONST_CS | CONST_PERSISTENT);
1093         REGISTER_LONG_CONSTANT("DNS_CNAME", PHP_DNS_CNAME, CONST_CS | CONST_PERSISTENT);
1094         REGISTER_LONG_CONSTANT("DNS_SOA",   PHP_DNS_SOA,   CONST_CS | CONST_PERSISTENT);
1095         REGISTER_LONG_CONSTANT("DNS_PTR",   PHP_DNS_PTR,   CONST_CS | CONST_PERSISTENT);
1096         REGISTER_LONG_CONSTANT("DNS_HINFO", PHP_DNS_HINFO, CONST_CS | CONST_PERSISTENT);
1097         REGISTER_LONG_CONSTANT("DNS_MX",    PHP_DNS_MX,    CONST_CS | CONST_PERSISTENT);
1098         REGISTER_LONG_CONSTANT("DNS_TXT",   PHP_DNS_TXT,   CONST_CS | CONST_PERSISTENT);
1099         REGISTER_LONG_CONSTANT("DNS_SRV",   PHP_DNS_SRV,   CONST_CS | CONST_PERSISTENT);
1100         REGISTER_LONG_CONSTANT("DNS_NAPTR", PHP_DNS_NAPTR, CONST_CS | CONST_PERSISTENT);
1101         REGISTER_LONG_CONSTANT("DNS_AAAA",  PHP_DNS_AAAA,  CONST_CS | CONST_PERSISTENT);
1102         REGISTER_LONG_CONSTANT("DNS_A6",    PHP_DNS_A6,    CONST_CS | CONST_PERSISTENT);
1103         REGISTER_LONG_CONSTANT("DNS_ANY",   PHP_DNS_ANY,   CONST_CS | CONST_PERSISTENT);
1104         REGISTER_LONG_CONSTANT("DNS_ALL",   PHP_DNS_ALL,   CONST_CS | CONST_PERSISTENT);
1105         return SUCCESS;
1106 }
1107 #endif /* HAVE_FULL_DNS_FUNCS */
1108 
1109 /*
1110  * Local variables:
1111  * tab-width: 4
1112  * c-basic-offset: 4
1113  * End:
1114  * vim600: sw=4 ts=4 fdm=marker
1115  * vim<600: sw=4 ts=4
1116  */

/* [<][>][^][v][top][bottom][index][help] */