Back to index

php5  5.3.10
dns_win32.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 2008-2009 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Pierre A. Joye <pierre@php.net>                             |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 #include "php.h"
00020 
00021 #include <windows.h>
00022 #include <Winbase.h >
00023 #include <Windns.h>
00024 
00025 #include "php_dns.h"
00026 
00027 #define PHP_DNS_NUM_TYPES   12     /* Number of DNS Types Supported by PHP currently */
00028 
00029 #define PHP_DNS_A      0x00000001
00030 #define PHP_DNS_NS     0x00000002
00031 #define PHP_DNS_CNAME  0x00000010
00032 #define PHP_DNS_SOA    0x00000020
00033 #define PHP_DNS_PTR    0x00000800
00034 #define PHP_DNS_HINFO  0x00001000
00035 #define PHP_DNS_MX     0x00004000
00036 #define PHP_DNS_TXT    0x00008000
00037 #define PHP_DNS_A6     0x01000000
00038 #define PHP_DNS_SRV    0x02000000
00039 #define PHP_DNS_NAPTR  0x04000000
00040 #define PHP_DNS_AAAA   0x08000000
00041 #define PHP_DNS_ANY    0x10000000
00042 #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)
00043 
00044 PHP_FUNCTION(dns_get_mx) /* {{{ */
00045 {
00046        char *hostname;
00047        int hostname_len;
00048        zval *mx_list, *weight_list = NULL;
00049 
00050        DNS_STATUS      status;                 /* Return value of DnsQuery_A() function */
00051        PDNS_RECORD     pResult, pRec;          /* Pointer to DNS_RECORD structure */
00052 
00053        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|z", &hostname, &hostname_len, &mx_list, &weight_list) == FAILURE) {
00054               return;
00055        }
00056 
00057        status = DnsQuery_A(hostname, DNS_TYPE_MX, DNS_QUERY_STANDARD, NULL, &pResult, NULL);
00058 
00059        if (status) {
00060               RETURN_FALSE;
00061        }
00062 
00063        zval_dtor(mx_list);
00064        array_init(mx_list);
00065 
00066        if (weight_list) {
00067               zval_dtor(weight_list);
00068               array_init(weight_list);
00069        }
00070 
00071        for (pRec = pResult; pRec; pRec = pRec->pNext) {
00072               DNS_SRV_DATA *srv = &pRec->Data.Srv;
00073 
00074               if (pRec->wType != DNS_TYPE_MX) {
00075                      continue;
00076               }
00077 
00078               add_next_index_string(mx_list, pRec->Data.MX.pNameExchange, 1);
00079               if (weight_list) {
00080                      add_next_index_long(weight_list, srv->wPriority);
00081               }
00082        }
00083 
00084        /* Free memory allocated for DNS records. */
00085        DnsRecordListFree(pResult, DnsFreeRecordListDeep);
00086 
00087        RETURN_TRUE;
00088 }
00089 /* }}} */
00090 
00091 /* {{{ proto bool dns_check_record(string host [, string type])
00092    Check DNS records corresponding to a given Internet host name or IP address */
00093 PHP_FUNCTION(dns_check_record)
00094 {
00095        char *hostname, *rectype = NULL;
00096        int hostname_len, rectype_len = 0;
00097        int type = DNS_TYPE_MX;
00098 
00099        DNS_STATUS      status;                 /* Return value of DnsQuery_A() function */
00100        PDNS_RECORD     pResult;          /* Pointer to DNS_RECORD structure */
00101 
00102        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &hostname, &hostname_len, &rectype, &rectype_len) == FAILURE) {
00103               return;
00104        }
00105 
00106        if (hostname_len == 0) {
00107               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host cannot be empty");
00108               RETURN_FALSE;
00109        }
00110 
00111        if (rectype) {
00112                    if (!strcasecmp("A",     rectype)) type = DNS_TYPE_A;
00113               else if (!strcasecmp("NS",    rectype)) type = DNS_TYPE_NS;
00114               else if (!strcasecmp("MX",    rectype)) type = DNS_TYPE_MX;
00115               else if (!strcasecmp("PTR",   rectype)) type = DNS_TYPE_PTR;
00116               else if (!strcasecmp("ANY",   rectype)) type = DNS_TYPE_ANY;
00117               else if (!strcasecmp("SOA",   rectype)) type = DNS_TYPE_SOA;
00118               else if (!strcasecmp("TXT",   rectype)) type = DNS_TYPE_TEXT;
00119               else if (!strcasecmp("CNAME", rectype)) type = DNS_TYPE_CNAME;
00120               else if (!strcasecmp("AAAA",  rectype)) type = DNS_TYPE_AAAA;
00121               else if (!strcasecmp("SRV",   rectype)) type = DNS_TYPE_SRV;
00122               else if (!strcasecmp("NAPTR", rectype)) type = DNS_TYPE_NAPTR;
00123               else if (!strcasecmp("A6",    rectype)) type = DNS_TYPE_A6;
00124               else {
00125                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type '%s' not supported", rectype);
00126                      RETURN_FALSE;
00127               }
00128        }
00129 
00130        status = DnsQuery_A(hostname, type, DNS_QUERY_STANDARD, NULL, &pResult, NULL);
00131 
00132        if (status) {
00133               RETURN_FALSE;
00134        }
00135 
00136        RETURN_TRUE;
00137 }
00138 /* }}} */
00139 
00140 /* {{{ php_parserr */
00141 static void php_parserr(PDNS_RECORD pRec, int type_to_fetch, int store, zval **subarray)
00142 {
00143        int type;
00144        u_long ttl;
00145 
00146        type = pRec->wType;
00147        ttl = pRec->dwTtl;
00148 
00149        if (type_to_fetch != DNS_TYPE_ANY && type != type_to_fetch) {
00150               return;
00151        }
00152 
00153        if (!store) {
00154               return;
00155        }
00156 
00157        ALLOC_INIT_ZVAL(*subarray);
00158        array_init(*subarray);
00159 
00160        add_assoc_string(*subarray, "host", pRec->pName, 1);
00161        switch (type) {
00162               case DNS_TYPE_A: {
00163                      IN_ADDR ipaddr;
00164                      ipaddr.S_un.S_addr = (pRec->Data.A.IpAddress);
00165                      add_assoc_string(*subarray, "type", "A", 1);
00166                      add_assoc_string(*subarray, "ip", inet_ntoa(ipaddr), 1);
00167                      break;
00168               }
00169 
00170               case DNS_TYPE_MX:
00171                      add_assoc_string(*subarray, "type", "MX", 1);
00172                      add_assoc_long(*subarray, "pri", pRec->Data.Srv.wPriority);
00173                      /* no break; */
00174 
00175               case DNS_TYPE_CNAME:
00176                      if (type == DNS_TYPE_CNAME) {
00177                             add_assoc_string(*subarray, "type", "CNAME", 1);
00178                      }
00179                      /* no break; */
00180 
00181               case DNS_TYPE_NS:
00182                      if (type == DNS_TYPE_NS) {
00183                             add_assoc_string(*subarray, "type", "NS", 1);
00184                      }
00185                      /* no break; */
00186 
00187               case DNS_TYPE_PTR:
00188                      if (type == DNS_TYPE_PTR) {
00189                             add_assoc_string(*subarray, "type", "PTR", 1);
00190                      }
00191                      add_assoc_string(*subarray, "target", pRec->Data.MX.pNameExchange, 1);
00192                      break;
00193 
00194               /* Not available on windows, the query is possible but there is no DNS_HINFO_DATA structure */
00195               case DNS_TYPE_HINFO:
00196               case DNS_TYPE_TEXT:
00197                      {
00198                             DWORD i = 0;
00199                             DNS_TXT_DATA *data_txt = &pRec->Data.TXT;
00200                             DWORD count = data_txt->dwStringCount;
00201                             char *txt, *txt_dst;
00202                             long txt_len = 0;
00203                             zval *entries;
00204 
00205                             add_assoc_string(*subarray, "type", "TXT", 1);
00206                             
00207                             ALLOC_INIT_ZVAL(entries);
00208                             array_init(entries);
00209                             
00210                             for (i = 0; i < count; i++) {
00211                                    txt_len += strlen(data_txt->pStringArray[i]) + 1;
00212                             }
00213 
00214                             txt = ecalloc(txt_len * 2, 1);
00215                             txt_dst = txt;
00216                             for (i = 0; i < count; i++) {
00217                                    int len = strlen(data_txt->pStringArray[i]);
00218                                    memcpy(txt_dst, data_txt->pStringArray[i], len);
00219                                    add_next_index_stringl(entries, data_txt->pStringArray[i], len, 1);
00220                                    txt_dst += len;
00221                             }
00222 
00223                             add_assoc_string(*subarray, "txt", txt, 0);
00224                             add_assoc_zval(*subarray, "entries", entries);
00225                      }
00226                      break;
00227 
00228               case DNS_TYPE_SOA:
00229                      {
00230                             DNS_SOA_DATA *data_soa = &pRec->Data.Soa;
00231 
00232                             add_assoc_string(*subarray, "type", "SOA", 1);
00233 
00234                             add_assoc_string(*subarray, "mname", data_soa->pNamePrimaryServer, 1);
00235                             add_assoc_string(*subarray, "rname", data_soa->pNameAdministrator, 1);
00236                             add_assoc_long(*subarray, "serial", data_soa->dwSerialNo);
00237                             add_assoc_long(*subarray, "refresh", data_soa->dwRefresh);
00238                             add_assoc_long(*subarray, "retry", data_soa->dwRetry);
00239                             add_assoc_long(*subarray, "expire", data_soa->dwExpire);
00240                             add_assoc_long(*subarray, "minimum-ttl", data_soa->dwDefaultTtl);
00241                      }
00242                      break;
00243 
00244               case DNS_TYPE_AAAA:
00245                      {
00246                             DNS_AAAA_DATA *data_aaaa = &pRec->Data.AAAA;
00247                             char buf[sizeof("AAAA:AAAA:AAAA:AAAA:AAAA:AAAA:AAAA:AAAA")];
00248                             char *tp = buf;
00249                             int i;
00250                             unsigned short out[8];
00251                             int have_v6_break = 0, in_v6_break = 0;
00252 
00253                             for (i = 0; i < 4; ++i) {
00254                                    DWORD chunk = data_aaaa->Ip6Address.IP6Dword[i];
00255                                    out[i * 2]     = htons(LOWORD(chunk));
00256                                    out[i * 2 + 1] = htons(HIWORD(chunk));
00257                             }
00258 
00259                             for(i=0; i < 8; i++) {
00260                                    if (out[i] != 0) {
00261                                           if (tp > (u_char *)buf) {
00262                                                  in_v6_break = 0;
00263                                                  tp[0] = ':';
00264                                                  tp++;
00265                                           }
00266                                           tp += sprintf((char*)tp,"%x", out[i]);
00267                                    } else {
00268                                           if (!have_v6_break) {
00269                                                  have_v6_break = 1;
00270                                                  in_v6_break = 1;
00271                                                  tp[0] = ':';
00272                                                  tp++;
00273                                           } else if (!in_v6_break) {
00274                                                  tp[0] = ':';
00275                                                  tp++;
00276                                                  tp[0] = '0';
00277                                                  tp++;
00278                                           }
00279                                    }
00280                             }
00281 
00282                             if (have_v6_break && in_v6_break) {
00283                                    tp[0] = ':';
00284                                    tp++;
00285                             }
00286                             tp[0] = '\0';
00287 
00288                             add_assoc_string(*subarray, "type", "AAAA", 1);
00289                             add_assoc_string(*subarray, "ipv6", buf, 1);
00290                      }
00291                      break;
00292 
00293 #if 0
00294               /* Won't be implemented. A6 is deprecated. (Pierre) */
00295               case DNS_TYPE_A6:
00296                      break;
00297 #endif
00298 
00299               case DNS_TYPE_SRV:
00300                      {
00301                             DNS_SRV_DATA *data_srv = &pRec->Data.Srv;
00302 
00303                             add_assoc_string(*subarray, "type", "SRV", 1);
00304                             add_assoc_long(*subarray, "pri", data_srv->wPriority);
00305                             add_assoc_long(*subarray, "weight", data_srv->wWeight);
00306                             add_assoc_long(*subarray, "port", data_srv->wPort);
00307                             add_assoc_string(*subarray, "target", data_srv->pNameTarget, 1);
00308                      }
00309                      break;
00310 
00311               case DNS_TYPE_NAPTR:
00312                      {
00313 #if _MSC_VER >= 1500
00314                             DNS_NAPTR_DATA * data_naptr = &pRec->Data.Naptr;
00315 
00316                             add_assoc_string(*subarray, "type", "NAPTR", 1);
00317                             add_assoc_long(*subarray, "order", data_naptr->wOrder);
00318                             add_assoc_long(*subarray, "pref", data_naptr->wPreference);
00319                             add_assoc_string(*subarray, "flags", data_naptr->pFlags, 1);
00320                             add_assoc_string(*subarray, "services", data_naptr->pService, 1);
00321                             add_assoc_string(*subarray, "regex", data_naptr->pRegularExpression, 1);
00322                             add_assoc_string(*subarray, "replacement", data_naptr->pReplacement, 1);
00323 #endif
00324                      }
00325                      break;
00326 
00327               default:
00328                      break;
00329        }
00330 
00331        add_assoc_string(*subarray, "class", "IN", 1);
00332        add_assoc_long(*subarray, "ttl", ttl);
00333 }
00334 /* }}} */
00335 
00336 /* {{{ proto array|false dns_get_record(string hostname [, int type[, array authns, array addtl]])
00337    Get any Resource Record corresponding to a given Internet host name */
00338 PHP_FUNCTION(dns_get_record)
00339 {
00340        char *hostname;
00341        int hostname_len;
00342        long type_param = PHP_DNS_ANY;
00343        zval *authns = NULL, *addtl = NULL;
00344        int type, type_to_fetch, first_query = 1, store_results = 1;
00345 
00346        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lzz", &hostname, &hostname_len, &type_param, &authns, &addtl) == FAILURE) {
00347               return;
00348        }
00349 
00350        if (authns) {
00351               zval_dtor(authns);
00352               array_init(authns);
00353        }
00354        if (addtl) {
00355               zval_dtor(addtl);
00356               array_init(addtl);
00357        }
00358 
00359        if (type_param & ~PHP_DNS_ALL && type_param != PHP_DNS_ANY) {
00360               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type '%ld' not supported", type_param);
00361               RETURN_FALSE;
00362        }
00363 
00364        /* Initialize the return array */
00365        array_init(return_value);
00366 
00367        for (type = (type_param == PHP_DNS_ANY ? (PHP_DNS_NUM_TYPES + 1) : 0);
00368               type < (addtl ? (PHP_DNS_NUM_TYPES + 2) : PHP_DNS_NUM_TYPES) || first_query;
00369               type++
00370        ) {
00371               DNS_STATUS      status;                 /* Return value of DnsQuery_A() function */
00372               PDNS_RECORD     pResult, pRec;          /* Pointer to DNS_RECORD structure */
00373 
00374               first_query = 0;
00375               switch (type) {
00376                      case 0:
00377                             type_to_fetch = type_param&PHP_DNS_A     ? DNS_TYPE_A     : 0;
00378                             break;
00379                      case 1:
00380                             type_to_fetch = type_param&PHP_DNS_NS    ? DNS_TYPE_NS    : 0;
00381                             break;
00382                      case 2:
00383                             type_to_fetch = type_param&PHP_DNS_CNAME ? DNS_TYPE_CNAME : 0;
00384                             break;
00385                      case 3:
00386                             type_to_fetch = type_param&PHP_DNS_SOA   ? DNS_TYPE_SOA   : 0;
00387                             break;
00388                      case 4:
00389                             type_to_fetch = type_param&PHP_DNS_PTR   ? DNS_TYPE_PTR   : 0;
00390                             break;
00391                      case 5:
00392                             type_to_fetch = type_param&PHP_DNS_HINFO ? DNS_TYPE_HINFO : 0;
00393                             break;
00394                      case 6:
00395                             type_to_fetch = type_param&PHP_DNS_MX    ? DNS_TYPE_MX    : 0;
00396                             break;
00397                      case 7:
00398                             type_to_fetch = type_param&PHP_DNS_TXT   ? DNS_TYPE_TEXT   : 0;
00399                             break;
00400                      case 8:
00401                             type_to_fetch = type_param&PHP_DNS_AAAA    ? DNS_TYPE_AAAA  : 0;
00402                             break;
00403                      case 9:
00404                             type_to_fetch = type_param&PHP_DNS_SRV   ? DNS_TYPE_SRV   : 0;
00405                             break;
00406                      case 10:
00407                             type_to_fetch = type_param&PHP_DNS_NAPTR ? DNS_TYPE_NAPTR : 0;
00408                             break;
00409                      case 11:
00410                             type_to_fetch = type_param&PHP_DNS_A6      ? DNS_TYPE_A6 : 0;
00411                             break;
00412                      case PHP_DNS_NUM_TYPES:
00413                             store_results = 0;
00414                             continue;
00415                      default:
00416                      case (PHP_DNS_NUM_TYPES + 1):
00417                             type_to_fetch = DNS_TYPE_ANY;
00418                             break;
00419               }
00420 
00421               if (type_to_fetch) {
00422                      status = DnsQuery_A(hostname, type_to_fetch, DNS_QUERY_STANDARD, NULL, &pResult, NULL);
00423 
00424                      if (status) {
00425                             if (status == DNS_INFO_NO_RECORDS || status == DNS_ERROR_RCODE_NAME_ERROR) {
00426                                    continue;
00427                             } else {
00428                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Dns Query failed");
00429                                    zval_dtor(return_value);
00430                                    RETURN_FALSE;
00431                             }
00432                      }
00433 
00434                      for (pRec = pResult; pRec; pRec = pRec->pNext) {
00435                             DNS_SRV_DATA *srv = &pRec->Data.Srv;
00436                             zval *retval = NULL;
00437 
00438                             if (pRec->Flags.S.Section == DnsSectionAnswer) {
00439                                    php_parserr(pRec, type_to_fetch, store_results, &retval);
00440                                    if (retval != NULL && store_results) {
00441                                           add_next_index_zval(return_value, retval);
00442                                    }
00443                             }
00444 
00445                             if (authns && pRec->Flags.S.Section == DnsSectionAuthority) {
00446 
00447                                    php_parserr(pRec, type_to_fetch, store_results, &retval);
00448                                    if (retval != NULL) {
00449                                           add_next_index_zval(authns, retval);
00450                                    }
00451                             }
00452 
00453 /* Stupid typo in PSDK 6.1, WinDNS.h(1258)... */
00454 #ifndef DnsSectionAdditional
00455 # ifdef DnsSectionAddtional
00456 #  define DnsSectionAdditional DnsSectionAddtional
00457 # else
00458 # define DnsSectionAdditional 3
00459 # endif
00460 #endif
00461                             if (addtl && pRec->Flags.S.Section == DnsSectionAdditional) {
00462                                    php_parserr(pRec, type_to_fetch, store_results, &retval);
00463                                    if (retval != NULL) {
00464                                           add_next_index_zval(addtl, retval);
00465                                    }
00466                             }
00467                      }
00468                      /* Free memory allocated for DNS records. */
00469                      DnsRecordListFree(pResult, DnsFreeRecordListDeep);
00470               }
00471        }
00472 }
00473 /* }}} */