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 7                                                        |
   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 zend_string *php_gethostbyaddr(char *ip);
 124 static zend_string *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, E_WARNING, "unable to fetch host [%d]: %s", errno, strerror(errno));
 139                 RETURN_FALSE;
 140         }
 141 
 142         RETURN_STRING(buf);
 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         size_t addr_len;
 157         zend_string *hostname;
 158 
 159         if (zend_parse_parameters(ZEND_NUM_ARGS(), "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, E_WARNING, "Address is not a valid IPv4 or IPv6 address");
 168 #else
 169                 php_error_docref(NULL, E_WARNING, "Address is not in a.b.c.d form");
 170 #endif
 171                 RETVAL_FALSE;
 172         } else {
 173                 RETVAL_STR(hostname);
 174         }
 175 }
 176 /* }}} */
 177 
 178 /* {{{ php_gethostbyaddr */
 179 static zend_string *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 zend_string_init(ip, strlen(ip), 0);
 207         }
 208 
 209         return zend_string_init(hp->h_name, strlen(hp->h_name), 0);
 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         size_t hostname_len;
 219 
 220         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &hostname, &hostname_len) == FAILURE) {
 221                 return;
 222         }
 223 
 224         if(hostname_len > MAXFQDNLEN) {
 225                 /* name too long, protect from CVE-2015-0235 */
 226                 php_error_docref(NULL, E_WARNING, "Host name is too long, the limit is %d characters", MAXFQDNLEN);
 227                 RETURN_STRINGL(hostname, hostname_len);
 228         }
 229 
 230         RETURN_STR(php_gethostbyname(hostname));
 231 }
 232 /* }}} */
 233 
 234 /* {{{ proto array gethostbynamel(string hostname)
 235    Return a list of IP addresses that a given hostname resolves to. */
 236 PHP_FUNCTION(gethostbynamel)
 237 {
 238         char *hostname;
 239         size_t hostname_len;
 240         struct hostent *hp;
 241         struct in_addr in;
 242         int i;
 243 
 244         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &hostname, &hostname_len) == FAILURE) {
 245                 return;
 246         }
 247 
 248         if(hostname_len > MAXFQDNLEN) {
 249                 /* name too long, protect from CVE-2015-0235 */
 250                 php_error_docref(NULL, E_WARNING, "Host name is too long, the limit is %d characters", MAXFQDNLEN);
 251                 RETURN_FALSE;
 252         }
 253 
 254         hp = gethostbyname(hostname);
 255         if (hp == NULL || hp->h_addr_list == NULL) {
 256                 RETURN_FALSE;
 257         }
 258 
 259         array_init(return_value);
 260 
 261         for (i = 0 ; hp->h_addr_list[i] != 0 ; i++) {
 262                 in = *(struct in_addr *) hp->h_addr_list[i];
 263                 add_next_index_string(return_value, inet_ntoa(in));
 264         }
 265 }
 266 /* }}} */
 267 
 268 /* {{{ php_gethostbyname */
 269 static zend_string *php_gethostbyname(char *name)
 270 {
 271         struct hostent *hp;
 272         struct in_addr in;
 273         char *address;
 274 
 275         hp = gethostbyname(name);
 276 
 277         if (!hp || !*(hp->h_addr_list)) {
 278                 return zend_string_init(name, strlen(name), 0);
 279         }
 280 
 281         memcpy(&in.s_addr, *(hp->h_addr_list), sizeof(in.s_addr));
 282 
 283         address = inet_ntoa(in);
 284         return zend_string_init(address, strlen(address), 0);
 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         size_t 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(), "s|s", &hostname, &hostname_len, &rectype, &rectype_len) == FAILURE) {
 372                 return;
 373         }
 374 
 375         if (hostname_len == 0) {
 376                 php_error_docref(NULL, 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, 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         ZVAL_UNDEF(subarray);
 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         array_init(subarray);
 468 
 469         add_assoc_string(subarray, "host", name);
 470         add_assoc_string(subarray, "class", "IN");
 471         add_assoc_long(subarray, "ttl", ttl);
 472         (void) class;
 473 
 474         if (raw) {
 475                 add_assoc_long(subarray, "type", type);
 476                 add_assoc_stringl(subarray, "data", (char*) cp, (uint) dlen);
 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");
 485                         snprintf(name, sizeof(name), "%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
 486                         add_assoc_string(subarray, "ip", name);
 487                         cp += dlen;
 488                         break;
 489                 case DNS_T_MX:
 490                         CHECKCP(2);
 491                         add_assoc_string(subarray, "type", "MX");
 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");
 498                         }
 499                         /* no break; */
 500                 case DNS_T_NS:
 501                         if (type == DNS_T_NS) {
 502                                 add_assoc_string(subarray, "type", "NS");
 503                         }
 504                         /* no break; */
 505                 case DNS_T_PTR:
 506                         if (type == DNS_T_PTR) {
 507                                 add_assoc_string(subarray, "type", "PTR");
 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);
 515                         break;
 516                 case DNS_T_HINFO:
 517                         /* See RFC 1010 for values */
 518                         add_assoc_string(subarray, "type", "HINFO");
 519                         CHECKCP(1);
 520                         n = *cp & 0xFF;
 521                         cp++;
 522                         CHECKCP(n);
 523                         add_assoc_stringl(subarray, "cpu", (char*)cp, n);
 524                         cp += n;
 525                         CHECKCP(1);
 526                         n = *cp & 0xFF;
 527                         cp++;
 528                         CHECKCP(n);
 529                         add_assoc_stringl(subarray, "os", (char*)cp, n);
 530                         cp += n;
 531                         break;
 532                 case DNS_T_TXT:
 533                         {
 534                                 int l1 = 0, l2 = 0;
 535                                 zval entries;
 536                                 zend_string *tp;
 537 
 538                                 add_assoc_string(subarray, "type", "TXT");
 539                                 tp = zend_string_alloc(dlen, 0);
 540 
 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(ZSTR_VAL(tp) + l2 , cp + l1 + 1, n);
 551                                                 add_next_index_stringl(&entries, (char *) cp + l1 + 1, n);
 552                                         }
 553                                         l1 = l1 + n + 1;
 554                                         l2 = l2 + n;
 555                                 }
 556                                 ZSTR_VAL(tp)[l2] = '\0';
 557                                 ZSTR_LEN(tp) = l2;
 558                                 cp += dlen;
 559 
 560                                 add_assoc_str(subarray, "txt", tp);
 561                                 add_assoc_zval(subarray, "entries", &entries);
 562                         }
 563                         break;
 564                 case DNS_T_SOA:
 565                         add_assoc_string(subarray, "type", "SOA");
 566                         n = dn_expand(answer->qb2, end, cp, name, (sizeof name) -2);
 567                         if (n < 0) {
 568                                 return NULL;
 569                         }
 570                         cp += n;
 571                         add_assoc_string(subarray, "mname", name);
 572                         n = dn_expand(answer->qb2, end, cp, name, (sizeof name) -2);
 573                         if (n < 0) {
 574                                 return NULL;
 575                         }
 576                         cp += n;
 577                         add_assoc_string(subarray, "rname", name);
 578                         CHECKCP(5*4);
 579                         GETLONG(n, cp);
 580                         add_assoc_long(subarray, "serial", n);
 581                         GETLONG(n, cp);
 582                         add_assoc_long(subarray, "refresh", n);
 583                         GETLONG(n, cp);
 584                         add_assoc_long(subarray, "retry", n);
 585                         GETLONG(n, cp);
 586                         add_assoc_long(subarray, "expire", n);
 587                         GETLONG(n, cp);
 588                         add_assoc_long(subarray, "minimum-ttl", n);
 589                         break;
 590                 case DNS_T_AAAA:
 591                         tp = (u_char*)name;
 592                         CHECKCP(8*2);
 593                         for(i=0; i < 8; i++) {
 594                                 GETSHORT(s, cp);
 595                                 if (s != 0) {
 596                                         if (tp > (u_char *)name) {
 597                                                 in_v6_break = 0;
 598                                                 tp[0] = ':';
 599                                                 tp++;
 600                                         }
 601                                         tp += sprintf((char*)tp,"%x",s);
 602                                 } else {
 603                                         if (!have_v6_break) {
 604                                                 have_v6_break = 1;
 605                                                 in_v6_break = 1;
 606                                                 tp[0] = ':';
 607                                                 tp++;
 608                                         } else if (!in_v6_break) {
 609                                                 tp[0] = ':';
 610                                                 tp++;
 611                                                 tp[0] = '0';
 612                                                 tp++;
 613                                         }
 614                                 }
 615                         }
 616                         if (have_v6_break && in_v6_break) {
 617                                 tp[0] = ':';
 618                                 tp++;
 619                         }
 620                         tp[0] = '\0';
 621                         add_assoc_string(subarray, "type", "AAAA");
 622                         add_assoc_string(subarray, "ipv6", name);
 623                         break;
 624                 case DNS_T_A6:
 625                         p = cp;
 626                         add_assoc_string(subarray, "type", "A6");
 627                         CHECKCP(1);
 628                         n = ((int)cp[0]) & 0xFF;
 629                         cp++;
 630                         add_assoc_long(subarray, "masklen", n);
 631                         tp = (u_char*)name;
 632                         if (n > 15) {
 633                                 have_v6_break = 1;
 634                                 in_v6_break = 1;
 635                                 tp[0] = ':';
 636                                 tp++;
 637                         }
 638                         if (n % 16 > 8) {
 639                                 /* Partial short */
 640                                 if (cp[0] != 0) {
 641                                         if (tp > (u_char *)name) {
 642                                                 in_v6_break = 0;
 643                                                 tp[0] = ':';
 644                                                 tp++;
 645                                         }
 646                                         sprintf((char*)tp, "%x", cp[0] & 0xFF);
 647                                 } else {
 648                                         if (!have_v6_break) {
 649                                                 have_v6_break = 1;
 650                                                 in_v6_break = 1;
 651                                                 tp[0] = ':';
 652                                                 tp++;
 653                                         } else if (!in_v6_break) {
 654                                                 tp[0] = ':';
 655                                                 tp++;
 656                                                 tp[0] = '0';
 657                                                 tp++;
 658                                         }
 659                                 }
 660                                 cp++;
 661                         }
 662                         for (i = (n + 8) / 16; i < 8; i++) {
 663                                 CHECKCP(2);
 664                                 GETSHORT(s, cp);
 665                                 if (s != 0) {
 666                                         if (tp > (u_char *)name) {
 667                                                 in_v6_break = 0;
 668                                                 tp[0] = ':';
 669                                                 tp++;
 670                                         }
 671                                         tp += sprintf((char*)tp,"%x",s);
 672                                 } else {
 673                                         if (!have_v6_break) {
 674                                                 have_v6_break = 1;
 675                                                 in_v6_break = 1;
 676                                                 tp[0] = ':';
 677                                                 tp++;
 678                                         } else if (!in_v6_break) {
 679                                                 tp[0] = ':';
 680                                                 tp++;
 681                                                 tp[0] = '0';
 682                                                 tp++;
 683                                         }
 684                                 }
 685                         }
 686                         if (have_v6_break && in_v6_break) {
 687                                 tp[0] = ':';
 688                                 tp++;
 689                         }
 690                         tp[0] = '\0';
 691                         add_assoc_string(subarray, "ipv6", name);
 692                         if (cp < p + dlen) {
 693                                 n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2);
 694                                 if (n < 0) {
 695                                         return NULL;
 696                                 }
 697                                 cp += n;
 698                                 add_assoc_string(subarray, "chain", name);
 699                         }
 700                         break;
 701                 case DNS_T_SRV:
 702                         CHECKCP(3*2);
 703                         add_assoc_string(subarray, "type", "SRV");
 704                         GETSHORT(n, cp);
 705                         add_assoc_long(subarray, "pri", n);
 706                         GETSHORT(n, cp);
 707                         add_assoc_long(subarray, "weight", n);
 708                         GETSHORT(n, cp);
 709                         add_assoc_long(subarray, "port", n);
 710                         n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2);
 711                         if (n < 0) {
 712                                 return NULL;
 713                         }
 714                         cp += n;
 715                         add_assoc_string(subarray, "target", name);
 716                         break;
 717                 case DNS_T_NAPTR:
 718                         CHECKCP(2*2);
 719                         add_assoc_string(subarray, "type", "NAPTR");
 720                         GETSHORT(n, cp);
 721                         add_assoc_long(subarray, "order", n);
 722                         GETSHORT(n, cp);
 723                         add_assoc_long(subarray, "pref", n);
 724 
 725                         CHECKCP(1);
 726                         n = (cp[0] & 0xFF);
 727                         cp++;
 728                         CHECKCP(n);
 729                         add_assoc_stringl(subarray, "flags", (char*)cp, n);
 730                         cp += n;
 731 
 732                         CHECKCP(1);
 733                         n = (cp[0] & 0xFF);
 734                         cp++;
 735                         CHECKCP(n);
 736                         add_assoc_stringl(subarray, "services", (char*)cp, n);
 737                         cp += n;
 738 
 739                         CHECKCP(1);
 740                         n = (cp[0] & 0xFF);
 741                         cp++;
 742                         CHECKCP(n);
 743                         add_assoc_stringl(subarray, "regex", (char*)cp, n);
 744                         cp += n;
 745 
 746                         n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2);
 747                         if (n < 0) {
 748                                 return NULL;
 749                         }
 750                         cp += n;
 751                         add_assoc_string(subarray, "replacement", name);
 752                         break;
 753                 default:
 754                         zval_ptr_dtor(subarray);
 755                         ZVAL_UNDEF(subarray);
 756                         cp += dlen;
 757                         break;
 758         }
 759 
 760         return cp;
 761 }
 762 /* }}} */
 763 
 764 /* {{{ proto array|false dns_get_record(string hostname [, int type[, array authns, array addtl]])
 765    Get any Resource Record corresponding to a given Internet host name */
 766 PHP_FUNCTION(dns_get_record)
 767 {
 768         char *hostname;
 769         size_t hostname_len;
 770         long type_param = PHP_DNS_ANY;
 771         zval *authns = NULL, *addtl = NULL;
 772         int type_to_fetch;
 773 #if defined(HAVE_DNS_SEARCH)
 774         struct sockaddr_storage from;
 775         uint32_t fromsize = sizeof(from);
 776         dns_handle_t handle;
 777 #elif defined(HAVE_RES_NSEARCH)
 778         struct __res_state state;
 779         struct __res_state *handle = &state;
 780 #endif
 781         HEADER *hp;
 782         querybuf answer;
 783         u_char *cp = NULL, *end = NULL;
 784         int n, qd, an, ns = 0, ar = 0;
 785         int type, first_query = 1, store_results = 1;
 786         zend_bool raw = 0;
 787 
 788         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|lz!z!b",
 789                         &hostname, &hostname_len, &type_param, &authns, &addtl, &raw) == FAILURE) {
 790                 return;
 791         }
 792 
 793         if (authns) {
 794                 zval_dtor(authns);
 795                 array_init(authns);
 796         }
 797         if (addtl) {
 798                 zval_dtor(addtl);
 799                 array_init(addtl);
 800         }
 801 
 802         if (!raw) {
 803                 if ((type_param & ~PHP_DNS_ALL) && (type_param != PHP_DNS_ANY)) {
 804                         php_error_docref(NULL, E_WARNING, "Type '%ld' not supported", type_param);
 805                         RETURN_FALSE;
 806                 }
 807         } else {
 808                 if ((type_param < 1) || (type_param > 0xFFFF)) {
 809                         php_error_docref(NULL, E_WARNING,
 810                                 "Numeric DNS record type must be between 1 and 65535, '%ld' given", type_param);
 811                         RETURN_FALSE;
 812                 }
 813         }
 814 
 815         /* Initialize the return array */
 816         array_init(return_value);
 817 
 818         /* - We emulate an or'ed type mask by querying type by type. (Steps 0 - NUMTYPES-1 )
 819          *   If additional info is wanted we check again with DNS_T_ANY (step NUMTYPES / NUMTYPES+1 )
 820          *   store_results is used to skip storing the results retrieved in step
 821          *   NUMTYPES+1 when results were already fetched.
 822          * - In case of PHP_DNS_ANY we use the directly fetch DNS_T_ANY. (step NUMTYPES+1 )
 823          * - In case of raw mode, we query only the requestd type instead of looping type by type
 824          *   before going with the additional info stuff.
 825          */
 826 
 827         if (raw) {
 828                 type = -1;
 829         } else if (type_param == PHP_DNS_ANY) {
 830                 type = PHP_DNS_NUM_TYPES + 1;
 831         } else {
 832                 type = 0;
 833         }
 834 
 835         for ( ;
 836                 type < (addtl ? (PHP_DNS_NUM_TYPES + 2) : PHP_DNS_NUM_TYPES) || first_query;
 837                 type++
 838         ) {
 839                 first_query = 0;
 840                 switch (type) {
 841                         case -1: /* raw */
 842                                 type_to_fetch = type_param;
 843                                 /* skip over the rest and go directly to additional records */
 844                                 type = PHP_DNS_NUM_TYPES - 1;
 845                                 break;
 846                         case 0:
 847                                 type_to_fetch = type_param&PHP_DNS_A     ? DNS_T_A     : 0;
 848                                 break;
 849                         case 1:
 850                                 type_to_fetch = type_param&PHP_DNS_NS    ? DNS_T_NS    : 0;
 851                                 break;
 852                         case 2:
 853                                 type_to_fetch = type_param&PHP_DNS_CNAME ? DNS_T_CNAME : 0;
 854                                 break;
 855                         case 3:
 856                                 type_to_fetch = type_param&PHP_DNS_SOA   ? DNS_T_SOA   : 0;
 857                                 break;
 858                         case 4:
 859                                 type_to_fetch = type_param&PHP_DNS_PTR   ? DNS_T_PTR   : 0;
 860                                 break;
 861                         case 5:
 862                                 type_to_fetch = type_param&PHP_DNS_HINFO ? DNS_T_HINFO : 0;
 863                                 break;
 864                         case 6:
 865                                 type_to_fetch = type_param&PHP_DNS_MX    ? DNS_T_MX    : 0;
 866                                 break;
 867                         case 7:
 868                                 type_to_fetch = type_param&PHP_DNS_TXT   ? DNS_T_TXT   : 0;
 869                                 break;
 870                         case 8:
 871                                 type_to_fetch = type_param&PHP_DNS_AAAA  ? DNS_T_AAAA  : 0;
 872                                 break;
 873                         case 9:
 874                                 type_to_fetch = type_param&PHP_DNS_SRV   ? DNS_T_SRV   : 0;
 875                                 break;
 876                         case 10:
 877                                 type_to_fetch = type_param&PHP_DNS_NAPTR ? DNS_T_NAPTR : 0;
 878                                 break;
 879                         case 11:
 880                                 type_to_fetch = type_param&PHP_DNS_A6    ? DNS_T_A6 : 0;
 881                                 break;
 882                         case PHP_DNS_NUM_TYPES:
 883                                 store_results = 0;
 884                                 continue;
 885                         default:
 886                         case (PHP_DNS_NUM_TYPES + 1):
 887                                 type_to_fetch = DNS_T_ANY;
 888                                 break;
 889                 }
 890 
 891                 if (type_to_fetch) {
 892 #if defined(HAVE_DNS_SEARCH)
 893                         handle = dns_open(NULL);
 894                         if (handle == NULL) {
 895                                 zval_dtor(return_value);
 896                                 RETURN_FALSE;
 897                         }
 898 #elif defined(HAVE_RES_NSEARCH)
 899                     memset(&state, 0, sizeof(state));
 900                     if (res_ninit(handle)) {
 901                         zval_dtor(return_value);
 902                                 RETURN_FALSE;
 903                         }
 904 #else
 905                         res_init();
 906 #endif
 907 
 908                         n = php_dns_search(handle, hostname, C_IN, type_to_fetch, answer.qb2, sizeof answer);
 909 
 910                         if (n < 0) {
 911                                 php_dns_free_handle(handle);
 912                                 switch (h_errno) {
 913                                         case NO_DATA:
 914                                         case HOST_NOT_FOUND:
 915                                                 continue;
 916 
 917                                         case NO_RECOVERY:
 918                                                 php_error_docref(NULL, E_WARNING, "An unexpected server failure occurred.");
 919                                                 break;
 920 
 921                                         case TRY_AGAIN:
 922                                                 php_error_docref(NULL, E_WARNING, "A temporary server error occurred.");
 923                                                 break;
 924 
 925                                         default:
 926                                                 php_error_docref(NULL, E_WARNING, "DNS Query failed");
 927                                 }
 928                                 zval_dtor(return_value);
 929                                 RETURN_FALSE;
 930                         }
 931 
 932                         cp = answer.qb2 + HFIXEDSZ;
 933                         end = answer.qb2 + n;
 934                         hp = (HEADER *)&answer;
 935                         qd = ntohs(hp->qdcount);
 936                         an = ntohs(hp->ancount);
 937                         ns = ntohs(hp->nscount);
 938                         ar = ntohs(hp->arcount);
 939 
 940                         /* Skip QD entries, they're only used by dn_expand later on */
 941                         while (qd-- > 0) {
 942                                 n = dn_skipname(cp, end);
 943                                 if (n < 0) {
 944                                         php_error_docref(NULL, E_WARNING, "Unable to parse DNS data received");
 945                                         zval_dtor(return_value);
 946                                         php_dns_free_handle(handle);
 947                                         RETURN_FALSE;
 948                                 }
 949                                 cp += n + QFIXEDSZ;
 950                         }
 951 
 952                         /* YAY! Our real answers! */
 953                         while (an-- && cp && cp < end) {
 954                                 zval retval;
 955 
 956                                 cp = php_parserr(cp, end, &answer, type_to_fetch, store_results, raw, &retval);
 957                                 if (Z_TYPE(retval) != IS_UNDEF && store_results) {
 958                                         add_next_index_zval(return_value, &retval);
 959                                 }
 960                         }
 961 
 962                         if (authns || addtl) {
 963                                 /* List of Authoritative Name Servers
 964                                  * Process when only requesting addtl so that we can skip through the section
 965                                  */
 966                                 while (ns-- > 0 && cp && cp < end) {
 967                                         zval retval;
 968 
 969                                         cp = php_parserr(cp, end, &answer, DNS_T_ANY, authns != NULL, raw, &retval);
 970                                         if (Z_TYPE(retval) != IS_UNDEF) {
 971                                                 add_next_index_zval(authns, &retval);
 972                                         }
 973                                 }
 974                         }
 975 
 976                         if (addtl) {
 977                                 /* Additional records associated with authoritative name servers */
 978                                 while (ar-- > 0 && cp && cp < end) {
 979                                         zval retval;
 980 
 981                                         cp = php_parserr(cp, end, &answer, DNS_T_ANY, 1, raw, &retval);
 982                                         if (Z_TYPE(retval) != IS_UNDEF) {
 983                                                 add_next_index_zval(addtl, &retval);
 984                                         }
 985                                 }
 986                         }
 987                         php_dns_free_handle(handle);
 988                 }
 989         }
 990 }
 991 /* }}} */
 992 
 993 /* {{{ proto bool dns_get_mx(string hostname, array mxhosts [, array weight])
 994    Get MX records corresponding to a given Internet host name */
 995 PHP_FUNCTION(dns_get_mx)
 996 {
 997         char *hostname;
 998         size_t hostname_len;
 999         zval *mx_list, *weight_list = NULL;
1000         int count, qdc;
1001         u_short type, weight;
1002         u_char ans[MAXPACKET];
1003         char buf[MAXHOSTNAMELEN];
1004         HEADER *hp;
1005         u_char *cp, *end;
1006         int i;
1007 #if defined(HAVE_DNS_SEARCH)
1008         struct sockaddr_storage from;
1009         uint32_t fromsize = sizeof(from);
1010         dns_handle_t handle;
1011 #elif defined(HAVE_RES_NSEARCH)
1012         struct __res_state state;
1013         struct __res_state *handle = &state;
1014 #endif
1015 
1016         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/|z/", &hostname, &hostname_len, &mx_list, &weight_list) == FAILURE) {
1017                 return;
1018         }
1019 
1020         zval_dtor(mx_list);
1021         array_init(mx_list);
1022 
1023         if (weight_list) {
1024                 zval_dtor(weight_list);
1025                 array_init(weight_list);
1026         }
1027 
1028 #if defined(HAVE_DNS_SEARCH)
1029         handle = dns_open(NULL);
1030         if (handle == NULL) {
1031                 RETURN_FALSE;
1032         }
1033 #elif defined(HAVE_RES_NSEARCH)
1034     memset(&state, 0, sizeof(state));
1035     if (res_ninit(handle)) {
1036                         RETURN_FALSE;
1037         }
1038 #else
1039         res_init();
1040 #endif
1041 
1042         i = php_dns_search(handle, hostname, C_IN, DNS_T_MX, (u_char *)&ans, sizeof(ans));
1043         if (i < 0) {
1044                 RETURN_FALSE;
1045         }
1046         if (i > (int)sizeof(ans)) {
1047                 i = sizeof(ans);
1048         }
1049         hp = (HEADER *)&ans;
1050         cp = (u_char *)&ans + HFIXEDSZ;
1051         end = (u_char *)&ans +i;
1052         for (qdc = ntohs((unsigned short)hp->qdcount); qdc--; cp += i + QFIXEDSZ) {
1053                 if ((i = dn_skipname(cp, end)) < 0 ) {
1054                         php_dns_free_handle(handle);
1055                         RETURN_FALSE;
1056                 }
1057         }
1058         count = ntohs((unsigned short)hp->ancount);
1059         while (--count >= 0 && cp < end) {
1060                 if ((i = dn_skipname(cp, end)) < 0 ) {
1061                         php_dns_free_handle(handle);
1062                         RETURN_FALSE;
1063                 }
1064                 cp += i;
1065                 GETSHORT(type, cp);
1066                 cp += INT16SZ + INT32SZ;
1067                 GETSHORT(i, cp);
1068                 if (type != DNS_T_MX) {
1069                         cp += i;
1070                         continue;
1071                 }
1072                 GETSHORT(weight, cp);
1073                 if ((i = dn_expand(ans, end, cp, buf, sizeof(buf)-1)) < 0) {
1074                         php_dns_free_handle(handle);
1075                         RETURN_FALSE;
1076                 }
1077                 cp += i;
1078                 add_next_index_string(mx_list, buf);
1079                 if (weight_list) {
1080                         add_next_index_long(weight_list, weight);
1081                 }
1082         }
1083         php_dns_free_handle(handle);
1084         RETURN_TRUE;
1085 }
1086 /* }}} */
1087 #endif /* HAVE_FULL_DNS_FUNCS */
1088 #endif /* !defined(PHP_WIN32) && (HAVE_DNS_SEARCH_FUNC && !(defined(__BEOS__) || defined(NETWARE))) */
1089 
1090 #if HAVE_FULL_DNS_FUNCS || defined(PHP_WIN32)
1091 PHP_MINIT_FUNCTION(dns) {
1092         REGISTER_LONG_CONSTANT("DNS_A",     PHP_DNS_A,     CONST_CS | CONST_PERSISTENT);
1093         REGISTER_LONG_CONSTANT("DNS_NS",    PHP_DNS_NS,    CONST_CS | CONST_PERSISTENT);
1094         REGISTER_LONG_CONSTANT("DNS_CNAME", PHP_DNS_CNAME, CONST_CS | CONST_PERSISTENT);
1095         REGISTER_LONG_CONSTANT("DNS_SOA",   PHP_DNS_SOA,   CONST_CS | CONST_PERSISTENT);
1096         REGISTER_LONG_CONSTANT("DNS_PTR",   PHP_DNS_PTR,   CONST_CS | CONST_PERSISTENT);
1097         REGISTER_LONG_CONSTANT("DNS_HINFO", PHP_DNS_HINFO, CONST_CS | CONST_PERSISTENT);
1098         REGISTER_LONG_CONSTANT("DNS_MX",    PHP_DNS_MX,    CONST_CS | CONST_PERSISTENT);
1099         REGISTER_LONG_CONSTANT("DNS_TXT",   PHP_DNS_TXT,   CONST_CS | CONST_PERSISTENT);
1100         REGISTER_LONG_CONSTANT("DNS_SRV",   PHP_DNS_SRV,   CONST_CS | CONST_PERSISTENT);
1101         REGISTER_LONG_CONSTANT("DNS_NAPTR", PHP_DNS_NAPTR, CONST_CS | CONST_PERSISTENT);
1102         REGISTER_LONG_CONSTANT("DNS_AAAA",  PHP_DNS_AAAA,  CONST_CS | CONST_PERSISTENT);
1103         REGISTER_LONG_CONSTANT("DNS_A6",    PHP_DNS_A6,    CONST_CS | CONST_PERSISTENT);
1104         REGISTER_LONG_CONSTANT("DNS_ANY",   PHP_DNS_ANY,   CONST_CS | CONST_PERSISTENT);
1105         REGISTER_LONG_CONSTANT("DNS_ALL",   PHP_DNS_ALL,   CONST_CS | CONST_PERSISTENT);
1106         return SUCCESS;
1107 }
1108 #endif /* HAVE_FULL_DNS_FUNCS */
1109 
1110 /*
1111  * Local variables:
1112  * tab-width: 4
1113  * c-basic-offset: 4
1114  * End:
1115  * vim600: sw=4 ts=4 fdm=marker
1116  * vim<600: sw=4 ts=4
1117  */

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