root/ext/standard/dns_win32.c

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

DEFINITIONS

This source file includes following definitions.
  1. PHP_FUNCTION
  2. PHP_FUNCTION
  3. php_parserr
  4. PHP_FUNCTION

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 2008-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: Pierre A. Joye <pierre@php.net>                             |
  16    +----------------------------------------------------------------------+
  17  */
  18 
  19 #include "php.h"
  20 
  21 #include <windows.h>
  22 #include <Winbase.h >
  23 #include <Windns.h>
  24 
  25 #include "php_dns.h"
  26 
  27 #define PHP_DNS_NUM_TYPES       12      /* Number of DNS Types Supported by PHP currently */
  28 
  29 #define PHP_DNS_A      0x00000001
  30 #define PHP_DNS_NS     0x00000002
  31 #define PHP_DNS_CNAME  0x00000010
  32 #define PHP_DNS_SOA    0x00000020
  33 #define PHP_DNS_PTR    0x00000800
  34 #define PHP_DNS_HINFO  0x00001000
  35 #define PHP_DNS_MX     0x00004000
  36 #define PHP_DNS_TXT    0x00008000
  37 #define PHP_DNS_A6     0x01000000
  38 #define PHP_DNS_SRV    0x02000000
  39 #define PHP_DNS_NAPTR  0x04000000
  40 #define PHP_DNS_AAAA   0x08000000
  41 #define PHP_DNS_ANY    0x10000000
  42 #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)
  43 
  44 PHP_FUNCTION(dns_get_mx) /* {{{ */
  45 {
  46         char *hostname;
  47         size_t hostname_len;
  48         zval *mx_list, *weight_list = NULL;
  49 
  50         DNS_STATUS      status;                 /* Return value of DnsQuery_A() function */
  51         PDNS_RECORD     pResult, pRec;          /* Pointer to DNS_RECORD structure */
  52 
  53         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|z", &hostname, &hostname_len, &mx_list, &weight_list) == FAILURE) {
  54                 return;
  55         }
  56 
  57         status = DnsQuery_A(hostname, DNS_TYPE_MX, DNS_QUERY_STANDARD, NULL, &pResult, NULL);
  58 
  59         if (status) {
  60                 RETURN_FALSE;
  61         }
  62 
  63         zval_dtor(mx_list);
  64         array_init(mx_list);
  65 
  66         if (weight_list) {
  67                 zval_dtor(weight_list);
  68                 array_init(weight_list);
  69         }
  70 
  71         for (pRec = pResult; pRec; pRec = pRec->pNext) {
  72                 DNS_SRV_DATA *srv = &pRec->Data.Srv;
  73 
  74                 if (pRec->wType != DNS_TYPE_MX) {
  75                         continue;
  76                 }
  77 
  78                 add_next_index_string(mx_list, pRec->Data.MX.pNameExchange);
  79                 if (weight_list) {
  80                         add_next_index_long(weight_list, srv->wPriority);
  81                 }
  82         }
  83 
  84         /* Free memory allocated for DNS records. */
  85         DnsRecordListFree(pResult, DnsFreeRecordListDeep);
  86 
  87         RETURN_TRUE;
  88 }
  89 /* }}} */
  90 
  91 /* {{{ proto bool dns_check_record(string host [, string type])
  92    Check DNS records corresponding to a given Internet host name or IP address */
  93 PHP_FUNCTION(dns_check_record)
  94 {
  95         char *hostname, *rectype = NULL;
  96         size_t hostname_len, rectype_len = 0;
  97         int type = DNS_TYPE_MX;
  98 
  99         DNS_STATUS      status;                 /* Return value of DnsQuery_A() function */
 100         PDNS_RECORD     pResult;          /* Pointer to DNS_RECORD structure */
 101 
 102         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", &hostname, &hostname_len, &rectype, &rectype_len) == FAILURE) {
 103                 return;
 104         }
 105 
 106         if (hostname_len == 0) {
 107                 php_error_docref(NULL, E_WARNING, "Host cannot be empty");
 108                 RETURN_FALSE;
 109         }
 110 
 111         if (rectype) {
 112                      if (!strcasecmp("A",     rectype)) type = DNS_TYPE_A;
 113                 else if (!strcasecmp("NS",    rectype)) type = DNS_TYPE_NS;
 114                 else if (!strcasecmp("MX",    rectype)) type = DNS_TYPE_MX;
 115                 else if (!strcasecmp("PTR",   rectype)) type = DNS_TYPE_PTR;
 116                 else if (!strcasecmp("ANY",   rectype)) type = DNS_TYPE_ANY;
 117                 else if (!strcasecmp("SOA",   rectype)) type = DNS_TYPE_SOA;
 118                 else if (!strcasecmp("TXT",   rectype)) type = DNS_TYPE_TEXT;
 119                 else if (!strcasecmp("CNAME", rectype)) type = DNS_TYPE_CNAME;
 120                 else if (!strcasecmp("AAAA",  rectype)) type = DNS_TYPE_AAAA;
 121                 else if (!strcasecmp("SRV",   rectype)) type = DNS_TYPE_SRV;
 122                 else if (!strcasecmp("NAPTR", rectype)) type = DNS_TYPE_NAPTR;
 123                 else if (!strcasecmp("A6",    rectype)) type = DNS_TYPE_A6;
 124                 else {
 125                         php_error_docref(NULL, E_WARNING, "Type '%s' not supported", rectype);
 126                         RETURN_FALSE;
 127                 }
 128         }
 129 
 130         status = DnsQuery_A(hostname, type, DNS_QUERY_STANDARD, NULL, &pResult, NULL);
 131 
 132         if (status) {
 133                 RETURN_FALSE;
 134         }
 135 
 136         RETURN_TRUE;
 137 }
 138 /* }}} */
 139 
 140 /* {{{ php_parserr */
 141 static void php_parserr(PDNS_RECORD pRec, int type_to_fetch, int store, int raw, zval *subarray)
 142 {
 143         int type;
 144         u_long ttl;
 145 
 146         type = pRec->wType;
 147         ttl = pRec->dwTtl;
 148 
 149         if (type_to_fetch != DNS_TYPE_ANY && type != type_to_fetch) {
 150                 return;
 151         }
 152 
 153         if (!store) {
 154                 return;
 155         }
 156 
 157         array_init(subarray);
 158 
 159         add_assoc_string(subarray, "host", pRec->pName);
 160         add_assoc_string(subarray, "class", "IN");
 161         add_assoc_long(subarray, "ttl", ttl);
 162 
 163         if (raw) {
 164                 add_assoc_long(subarray, "type", type);
 165                 add_assoc_stringl(subarray, "data", (char*) &pRec->Data, (uint) pRec->wDataLength);
 166                 return;
 167         }
 168 
 169         switch (type) {
 170                 case DNS_TYPE_A: {
 171                         IN_ADDR ipaddr;
 172                         ipaddr.S_un.S_addr = (pRec->Data.A.IpAddress);
 173                         add_assoc_string(subarray, "type", "A");
 174                         add_assoc_string(subarray, "ip", inet_ntoa(ipaddr));
 175                         break;
 176                 }
 177 
 178                 case DNS_TYPE_MX:
 179                         add_assoc_string(subarray, "type", "MX");
 180                         add_assoc_long(subarray, "pri", pRec->Data.Srv.wPriority);
 181                         /* no break; */
 182 
 183                 case DNS_TYPE_CNAME:
 184                         if (type == DNS_TYPE_CNAME) {
 185                                 add_assoc_string(subarray, "type", "CNAME");
 186                         }
 187                         /* no break; */
 188 
 189                 case DNS_TYPE_NS:
 190                         if (type == DNS_TYPE_NS) {
 191                                 add_assoc_string(subarray, "type", "NS");
 192                         }
 193                         /* no break; */
 194 
 195                 case DNS_TYPE_PTR:
 196                         if (type == DNS_TYPE_PTR) {
 197                                 add_assoc_string(subarray, "type", "PTR");
 198                         }
 199                         add_assoc_string(subarray, "target", pRec->Data.MX.pNameExchange);
 200                         break;
 201 
 202                 /* Not available on windows, the query is possible but there is no DNS_HINFO_DATA structure */
 203                 case DNS_TYPE_HINFO:
 204                 case DNS_TYPE_TEXT:
 205                         {
 206                                 DWORD i = 0;
 207                                 DNS_TXT_DATA *data_txt = &pRec->Data.TXT;
 208                                 DWORD count = data_txt->dwStringCount;
 209                                 zend_string *txt;
 210                                 char *txt_dst;
 211                                 size_t txt_len = 0;
 212                                 zval entries;
 213 
 214                                 add_assoc_string(subarray, "type", "TXT");
 215 
 216                                 array_init(&entries);
 217 
 218                                 for (i = 0; i < count; i++) {
 219                                         txt_len += strlen(data_txt->pStringArray[i]) + 1;
 220                                 }
 221 
 222                                 txt = zend_string_safe_alloc(txt_len, 2, 0, 0);
 223                                 txt_dst = txt->val;
 224                                 for (i = 0; i < count; i++) {
 225                                         size_t len = strlen(data_txt->pStringArray[i]);
 226                                         memcpy(txt_dst, data_txt->pStringArray[i], len);
 227                                         add_next_index_stringl(&entries, data_txt->pStringArray[i], len);
 228                                         txt_dst += len;
 229                                 }
 230                                 txt->len = txt_dst - txt->val;
 231                                 add_assoc_str(subarray, "txt", txt);
 232                                 add_assoc_zval(subarray, "entries", &entries);
 233                         }
 234                         break;
 235 
 236                 case DNS_TYPE_SOA:
 237                         {
 238                                 DNS_SOA_DATA *data_soa = &pRec->Data.Soa;
 239 
 240                                 add_assoc_string(subarray, "type", "SOA");
 241 
 242                                 add_assoc_string(subarray, "mname", data_soa->pNamePrimaryServer);
 243                                 add_assoc_string(subarray, "rname", data_soa->pNameAdministrator);
 244                                 add_assoc_long(subarray, "serial", data_soa->dwSerialNo);
 245                                 add_assoc_long(subarray, "refresh", data_soa->dwRefresh);
 246                                 add_assoc_long(subarray, "retry", data_soa->dwRetry);
 247                                 add_assoc_long(subarray, "expire", data_soa->dwExpire);
 248                                 add_assoc_long(subarray, "minimum-ttl", data_soa->dwDefaultTtl);
 249                         }
 250                         break;
 251 
 252                 case DNS_TYPE_AAAA:
 253                         {
 254                                 DNS_AAAA_DATA *data_aaaa = &pRec->Data.AAAA;
 255                                 char buf[sizeof("AAAA:AAAA:AAAA:AAAA:AAAA:AAAA:AAAA:AAAA")];
 256                                 char *tp = buf;
 257                                 int i;
 258                                 unsigned short out[8];
 259                                 int have_v6_break = 0, in_v6_break = 0;
 260 
 261                                 for (i = 0; i < 4; ++i) {
 262                                         DWORD chunk = data_aaaa->Ip6Address.IP6Dword[i];
 263                                         out[i * 2]     = htons(LOWORD(chunk));
 264                                         out[i * 2 + 1] = htons(HIWORD(chunk));
 265                                 }
 266 
 267                                 for(i=0; i < 8; i++) {
 268                                         if (out[i] != 0) {
 269                                                 if (tp > (u_char *)buf) {
 270                                                         in_v6_break = 0;
 271                                                         tp[0] = ':';
 272                                                         tp++;
 273                                                 }
 274                                                 tp += sprintf((char*)tp,"%x", out[i]);
 275                                         } else {
 276                                                 if (!have_v6_break) {
 277                                                         have_v6_break = 1;
 278                                                         in_v6_break = 1;
 279                                                         tp[0] = ':';
 280                                                         tp++;
 281                                                 } else if (!in_v6_break) {
 282                                                         tp[0] = ':';
 283                                                         tp++;
 284                                                         tp[0] = '0';
 285                                                         tp++;
 286                                                 }
 287                                         }
 288                                 }
 289 
 290                                 if (have_v6_break && in_v6_break) {
 291                                         tp[0] = ':';
 292                                         tp++;
 293                                 }
 294                                 tp[0] = '\0';
 295 
 296                                 add_assoc_string(subarray, "type", "AAAA");
 297                                 add_assoc_string(subarray, "ipv6", buf);
 298                         }
 299                         break;
 300 
 301 #if 0
 302                 /* Won't be implemented. A6 is deprecated. (Pierre) */
 303                 case DNS_TYPE_A6:
 304                         break;
 305 #endif
 306 
 307                 case DNS_TYPE_SRV:
 308                         {
 309                                 DNS_SRV_DATA *data_srv = &pRec->Data.Srv;
 310 
 311                                 add_assoc_string(subarray, "type", "SRV");
 312                                 add_assoc_long(subarray, "pri", data_srv->wPriority);
 313                                 add_assoc_long(subarray, "weight", data_srv->wWeight);
 314                                 add_assoc_long(subarray, "port", data_srv->wPort);
 315                                 add_assoc_string(subarray, "target", data_srv->pNameTarget);
 316                         }
 317                         break;
 318 
 319                 case DNS_TYPE_NAPTR:
 320                         {
 321                                 DNS_NAPTR_DATA * data_naptr = &pRec->Data.Naptr;
 322 
 323                                 add_assoc_string(subarray, "type", "NAPTR");
 324                                 add_assoc_long(subarray, "order", data_naptr->wOrder);
 325                                 add_assoc_long(subarray, "pref", data_naptr->wPreference);
 326                                 add_assoc_string(subarray, "flags", data_naptr->pFlags);
 327                                 add_assoc_string(subarray, "services", data_naptr->pService);
 328                                 add_assoc_string(subarray, "regex", data_naptr->pRegularExpression);
 329                                 add_assoc_string(subarray, "replacement", data_naptr->pReplacement);
 330                         }
 331                         break;
 332 
 333                 default:
 334                         /* unknown type */
 335                         ZVAL_UNDEF(subarray);
 336                         return;
 337         }
 338 
 339 }
 340 /* }}} */
 341 
 342 /* {{{ proto array|false dns_get_record(string hostname [, int type[, array authns, array addtl]])
 343    Get any Resource Record corresponding to a given Internet host name */
 344 PHP_FUNCTION(dns_get_record)
 345 {
 346         char *hostname;
 347         size_t hostname_len;
 348         long type_param = PHP_DNS_ANY;
 349         zval *authns = NULL, *addtl = NULL;
 350         int type, type_to_fetch, first_query = 1, store_results = 1;
 351         zend_bool raw = 0;
 352 
 353         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|lz!z!b",
 354                         &hostname, &hostname_len, &type_param, &authns, &addtl, &raw) == FAILURE) {
 355                 return;
 356         }
 357 
 358         if (authns) {
 359                 zval_dtor(authns);
 360                 array_init(authns);
 361         }
 362         if (addtl) {
 363                 zval_dtor(addtl);
 364                 array_init(addtl);
 365         }
 366 
 367         if (!raw) {
 368                 if ((type_param & ~PHP_DNS_ALL) && (type_param != PHP_DNS_ANY)) {
 369                         php_error_docref(NULL, E_WARNING, "Type '%ld' not supported", type_param);
 370                         RETURN_FALSE;
 371                 }
 372         } else {
 373                 if ((type_param < 1) || (type_param > 0xFFFF)) {
 374                         php_error_docref(NULL, E_WARNING,
 375                                 "Numeric DNS record type must be between 1 and 65535, '%ld' given", type_param);
 376                         RETURN_FALSE;
 377                 }
 378         }
 379 
 380         /* Initialize the return array */
 381         array_init(return_value);
 382 
 383         if (raw) {
 384                 type = -1;
 385         } else if (type_param == PHP_DNS_ANY) {
 386                 type = PHP_DNS_NUM_TYPES + 1;
 387         } else {
 388                 type = 0;
 389         }
 390 
 391         for ( ;
 392                 type < (addtl ? (PHP_DNS_NUM_TYPES + 2) : PHP_DNS_NUM_TYPES) || first_query;
 393                 type++
 394         ) {
 395                 DNS_STATUS      status;                 /* Return value of DnsQuery_A() function */
 396                 PDNS_RECORD     pResult, pRec;          /* Pointer to DNS_RECORD structure */
 397 
 398                 first_query = 0;
 399                 switch (type) {
 400                         case -1: /* raw */
 401                                 type_to_fetch = type_param;
 402                                 /* skip over the rest and go directly to additional records */
 403                                 type = PHP_DNS_NUM_TYPES - 1;
 404                                 break;
 405                         case 0:
 406                                 type_to_fetch = type_param&PHP_DNS_A     ? DNS_TYPE_A     : 0;
 407                                 break;
 408                         case 1:
 409                                 type_to_fetch = type_param&PHP_DNS_NS    ? DNS_TYPE_NS    : 0;
 410                                 break;
 411                         case 2:
 412                                 type_to_fetch = type_param&PHP_DNS_CNAME ? DNS_TYPE_CNAME : 0;
 413                                 break;
 414                         case 3:
 415                                 type_to_fetch = type_param&PHP_DNS_SOA   ? DNS_TYPE_SOA   : 0;
 416                                 break;
 417                         case 4:
 418                                 type_to_fetch = type_param&PHP_DNS_PTR   ? DNS_TYPE_PTR   : 0;
 419                                 break;
 420                         case 5:
 421                                 type_to_fetch = type_param&PHP_DNS_HINFO ? DNS_TYPE_HINFO : 0;
 422                                 break;
 423                         case 6:
 424                                 type_to_fetch = type_param&PHP_DNS_MX    ? DNS_TYPE_MX    : 0;
 425                                 break;
 426                         case 7:
 427                                 type_to_fetch = type_param&PHP_DNS_TXT   ? DNS_TYPE_TEXT   : 0;
 428                                 break;
 429                         case 8:
 430                                 type_to_fetch = type_param&PHP_DNS_AAAA  ? DNS_TYPE_AAAA  : 0;
 431                                 break;
 432                         case 9:
 433                                 type_to_fetch = type_param&PHP_DNS_SRV   ? DNS_TYPE_SRV   : 0;
 434                                 break;
 435                         case 10:
 436                                 type_to_fetch = type_param&PHP_DNS_NAPTR ? DNS_TYPE_NAPTR : 0;
 437                                 break;
 438                         case 11:
 439                                 type_to_fetch = type_param&PHP_DNS_A6    ? DNS_TYPE_A6 : 0;
 440                                 break;
 441                         case PHP_DNS_NUM_TYPES:
 442                                 store_results = 0;
 443                                 continue;
 444                         default:
 445                         case (PHP_DNS_NUM_TYPES + 1):
 446                                 type_to_fetch = DNS_TYPE_ANY;
 447                                 break;
 448                 }
 449 
 450                 if (type_to_fetch) {
 451                         status = DnsQuery_A(hostname, type_to_fetch, DNS_QUERY_STANDARD, NULL, &pResult, NULL);
 452 
 453                         if (status) {
 454                                 if (status == DNS_INFO_NO_RECORDS || status == DNS_ERROR_RCODE_NAME_ERROR) {
 455                                         continue;
 456                                 } else {
 457                                         php_error_docref(NULL, E_WARNING, "DNS Query failed");
 458                                         zval_dtor(return_value);
 459                                         RETURN_FALSE;
 460                                 }
 461                         }
 462 
 463                         for (pRec = pResult; pRec; pRec = pRec->pNext) {
 464                                 zval retval;
 465 
 466                                 if (pRec->Flags.S.Section == DnsSectionAnswer) {
 467                                         php_parserr(pRec, type_to_fetch, store_results, raw, &retval);
 468                                         if (!Z_ISUNDEF(retval) && store_results) {
 469                                                 add_next_index_zval(return_value, &retval);
 470                                         }
 471                                 }
 472 
 473                                 if (authns && pRec->Flags.S.Section == DnsSectionAuthority) {
 474 
 475                                         php_parserr(pRec, type_to_fetch, 1, raw, &retval);
 476                                         if (!Z_ISUNDEF(retval)) {
 477                                                 add_next_index_zval(authns, &retval);
 478                                         }
 479                                 }
 480 
 481 /* Stupid typo in PSDK 6.1, WinDNS.h(1258)... */
 482 #ifndef DnsSectionAdditional
 483 # ifdef DnsSectionAddtional
 484 #  define DnsSectionAdditional DnsSectionAddtional
 485 # else
 486 # define DnsSectionAdditional 3
 487 # endif
 488 #endif
 489                                 if (addtl && pRec->Flags.S.Section == DnsSectionAdditional) {
 490                                         php_parserr(pRec, type_to_fetch, 1, raw, &retval);
 491                                         if (!Z_ISUNDEF(retval)) {
 492                                                 add_next_index_zval(addtl, &retval);
 493                                         }
 494                                 }
 495                         }
 496                         /* Free memory allocated for DNS records. */
 497                         DnsRecordListFree(pResult, DnsFreeRecordListDeep);
 498                 }
 499         }
 500 }
 501 /* }}} */

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