PageRenderTime 81ms CodeModel.GetById 23ms RepoModel.GetById 5ms app.codeStats 0ms

/ext/standard/dns.c

http://github.com/php/php-src
C | 1163 lines | 968 code | 107 blank | 88 comment | 187 complexity | bc77c632ea0ca60160f5aad2a946fee6 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | http://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: The typical suspects |
  14. | Pollita <pollita@php.net> |
  15. | Marcus Boerger <helly@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. /* {{{ includes */
  19. #include "php.h"
  20. #include "php_network.h"
  21. #if HAVE_SYS_SOCKET_H
  22. #include <sys/socket.h>
  23. #endif
  24. #ifdef PHP_WIN32
  25. # include "win32/inet.h"
  26. # include <winsock2.h>
  27. # include <windows.h>
  28. # include <Ws2tcpip.h>
  29. #else
  30. #include <netinet/in.h>
  31. #if HAVE_ARPA_INET_H
  32. #include <arpa/inet.h>
  33. #endif
  34. #include <netdb.h>
  35. #ifdef _OSD_POSIX
  36. #undef STATUS
  37. #undef T_UNSPEC
  38. #endif
  39. #if HAVE_ARPA_NAMESER_H
  40. #ifdef DARWIN
  41. # define BIND_8_COMPAT 1
  42. #endif
  43. #include <arpa/nameser.h>
  44. #endif
  45. #if HAVE_RESOLV_H
  46. #include <resolv.h>
  47. #endif
  48. #ifdef HAVE_DNS_H
  49. #include <dns.h>
  50. #endif
  51. #endif
  52. #ifndef MAXHOSTNAMELEN
  53. #define MAXHOSTNAMELEN 255
  54. #endif
  55. /* For the local hostname obtained via gethostname which is different from the
  56. dns-related MAXHOSTNAMELEN constant above */
  57. #ifndef HOST_NAME_MAX
  58. #define HOST_NAME_MAX 255
  59. #endif
  60. #include "php_dns.h"
  61. /* type compat */
  62. #ifndef DNS_T_A
  63. #define DNS_T_A 1
  64. #endif
  65. #ifndef DNS_T_NS
  66. #define DNS_T_NS 2
  67. #endif
  68. #ifndef DNS_T_CNAME
  69. #define DNS_T_CNAME 5
  70. #endif
  71. #ifndef DNS_T_SOA
  72. #define DNS_T_SOA 6
  73. #endif
  74. #ifndef DNS_T_PTR
  75. #define DNS_T_PTR 12
  76. #endif
  77. #ifndef DNS_T_HINFO
  78. #define DNS_T_HINFO 13
  79. #endif
  80. #ifndef DNS_T_MINFO
  81. #define DNS_T_MINFO 14
  82. #endif
  83. #ifndef DNS_T_MX
  84. #define DNS_T_MX 15
  85. #endif
  86. #ifndef DNS_T_TXT
  87. #define DNS_T_TXT 16
  88. #endif
  89. #ifndef DNS_T_AAAA
  90. #define DNS_T_AAAA 28
  91. #endif
  92. #ifndef DNS_T_SRV
  93. #define DNS_T_SRV 33
  94. #endif
  95. #ifndef DNS_T_NAPTR
  96. #define DNS_T_NAPTR 35
  97. #endif
  98. #ifndef DNS_T_A6
  99. #define DNS_T_A6 38
  100. #endif
  101. #ifndef DNS_T_CAA
  102. #define DNS_T_CAA 257
  103. #endif
  104. #ifndef DNS_T_ANY
  105. #define DNS_T_ANY 255
  106. #endif
  107. /* }}} */
  108. static zend_string *php_gethostbyaddr(char *ip);
  109. static zend_string *php_gethostbyname(char *name);
  110. #ifdef HAVE_GETHOSTNAME
  111. /* {{{ proto string|false gethostname()
  112. Get the host name of the current machine */
  113. PHP_FUNCTION(gethostname)
  114. {
  115. char buf[HOST_NAME_MAX + 1];
  116. ZEND_PARSE_PARAMETERS_NONE();
  117. if (gethostname(buf, sizeof(buf))) {
  118. php_error_docref(NULL, E_WARNING, "Unable to fetch host [%d]: %s", errno, strerror(errno));
  119. RETURN_FALSE;
  120. }
  121. RETURN_STRING(buf);
  122. }
  123. /* }}} */
  124. #endif
  125. /* TODO: Reimplement the gethostby* functions using the new winxp+ API, in dns_win32.c, then
  126. we can have a dns.c, dns_unix.c and dns_win32.c instead of a messy dns.c full of #ifdef
  127. */
  128. /* {{{ proto string|false gethostbyaddr(string ip_address)
  129. Get the Internet host name corresponding to a given IP address */
  130. PHP_FUNCTION(gethostbyaddr)
  131. {
  132. char *addr;
  133. size_t addr_len;
  134. zend_string *hostname;
  135. ZEND_PARSE_PARAMETERS_START(1, 1)
  136. Z_PARAM_STRING(addr, addr_len)
  137. ZEND_PARSE_PARAMETERS_END();
  138. hostname = php_gethostbyaddr(addr);
  139. if (hostname == NULL) {
  140. #if HAVE_IPV6 && HAVE_INET_PTON
  141. php_error_docref(NULL, E_WARNING, "Address is not a valid IPv4 or IPv6 address");
  142. #else
  143. php_error_docref(NULL, E_WARNING, "Address is not in a.b.c.d form");
  144. #endif
  145. RETVAL_FALSE;
  146. } else {
  147. RETVAL_STR(hostname);
  148. }
  149. }
  150. /* }}} */
  151. /* {{{ php_gethostbyaddr */
  152. static zend_string *php_gethostbyaddr(char *ip)
  153. {
  154. #if HAVE_IPV6 && HAVE_INET_PTON
  155. struct in6_addr addr6;
  156. #endif
  157. struct in_addr addr;
  158. struct hostent *hp;
  159. #if HAVE_IPV6 && HAVE_INET_PTON
  160. if (inet_pton(AF_INET6, ip, &addr6)) {
  161. hp = gethostbyaddr((char *) &addr6, sizeof(addr6), AF_INET6);
  162. } else if (inet_pton(AF_INET, ip, &addr)) {
  163. hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
  164. } else {
  165. return NULL;
  166. }
  167. #else
  168. addr.s_addr = inet_addr(ip);
  169. if (addr.s_addr == -1) {
  170. return NULL;
  171. }
  172. hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
  173. #endif
  174. if (!hp || hp->h_name == NULL || hp->h_name[0] == '\0') {
  175. return zend_string_init(ip, strlen(ip), 0);
  176. }
  177. return zend_string_init(hp->h_name, strlen(hp->h_name), 0);
  178. }
  179. /* }}} */
  180. /* {{{ proto string gethostbyname(string hostname)
  181. Get the IP address corresponding to a given Internet host name */
  182. PHP_FUNCTION(gethostbyname)
  183. {
  184. char *hostname;
  185. size_t hostname_len;
  186. ZEND_PARSE_PARAMETERS_START(1, 1)
  187. Z_PARAM_STRING(hostname, hostname_len)
  188. ZEND_PARSE_PARAMETERS_END();
  189. if(hostname_len > MAXFQDNLEN) {
  190. /* name too long, protect from CVE-2015-0235 */
  191. php_error_docref(NULL, E_WARNING, "Host name is too long, the limit is %d characters", MAXFQDNLEN);
  192. RETURN_STRINGL(hostname, hostname_len);
  193. }
  194. RETURN_STR(php_gethostbyname(hostname));
  195. }
  196. /* }}} */
  197. /* {{{ proto array|false gethostbynamel(string hostname)
  198. Return a list of IP addresses that a given hostname resolves to. */
  199. PHP_FUNCTION(gethostbynamel)
  200. {
  201. char *hostname;
  202. size_t hostname_len;
  203. struct hostent *hp;
  204. struct in_addr in;
  205. int i;
  206. ZEND_PARSE_PARAMETERS_START(1, 1)
  207. Z_PARAM_STRING(hostname, hostname_len)
  208. ZEND_PARSE_PARAMETERS_END();
  209. if(hostname_len > MAXFQDNLEN) {
  210. /* name too long, protect from CVE-2015-0235 */
  211. php_error_docref(NULL, E_WARNING, "Host name is too long, the limit is %d characters", MAXFQDNLEN);
  212. RETURN_FALSE;
  213. }
  214. hp = php_network_gethostbyname(hostname);
  215. if (!hp) {
  216. RETURN_FALSE;
  217. }
  218. array_init(return_value);
  219. for (i = 0;; i++) {
  220. /* On macos h_addr_list entries may be misaligned. */
  221. struct in_addr *h_addr_entry; /* Don't call this h_addr, it's a macro! */
  222. memcpy(&h_addr_entry, &hp->h_addr_list[i], sizeof(struct in_addr *));
  223. if (!h_addr_entry) {
  224. return;
  225. }
  226. in = *h_addr_entry;
  227. add_next_index_string(return_value, inet_ntoa(in));
  228. }
  229. }
  230. /* }}} */
  231. /* {{{ php_gethostbyname */
  232. static zend_string *php_gethostbyname(char *name)
  233. {
  234. struct hostent *hp;
  235. struct in_addr *h_addr_0; /* Don't call this h_addr, it's a macro! */
  236. struct in_addr in;
  237. char *address;
  238. hp = php_network_gethostbyname(name);
  239. if (!hp) {
  240. return zend_string_init(name, strlen(name), 0);
  241. }
  242. /* On macos h_addr_list entries may be misaligned. */
  243. memcpy(&h_addr_0, &hp->h_addr_list[0], sizeof(struct in_addr *));
  244. if (!h_addr_0) {
  245. return zend_string_init(name, strlen(name), 0);
  246. }
  247. memcpy(&in.s_addr, h_addr_0, sizeof(in.s_addr));
  248. address = inet_ntoa(in);
  249. return zend_string_init(address, strlen(address), 0);
  250. }
  251. /* }}} */
  252. #if HAVE_FULL_DNS_FUNCS || defined(PHP_WIN32)
  253. # define PHP_DNS_NUM_TYPES 13 /* Number of DNS Types Supported by PHP currently */
  254. # define PHP_DNS_A 0x00000001
  255. # define PHP_DNS_NS 0x00000002
  256. # define PHP_DNS_CNAME 0x00000010
  257. # define PHP_DNS_SOA 0x00000020
  258. # define PHP_DNS_PTR 0x00000800
  259. # define PHP_DNS_HINFO 0x00001000
  260. # define PHP_DNS_CAA 0x00002000
  261. # define PHP_DNS_MX 0x00004000
  262. # define PHP_DNS_TXT 0x00008000
  263. # define PHP_DNS_A6 0x01000000
  264. # define PHP_DNS_SRV 0x02000000
  265. # define PHP_DNS_NAPTR 0x04000000
  266. # define PHP_DNS_AAAA 0x08000000
  267. # define PHP_DNS_ANY 0x10000000
  268. # define PHP_DNS_ALL (PHP_DNS_A|PHP_DNS_NS|PHP_DNS_CNAME|PHP_DNS_SOA|PHP_DNS_PTR|PHP_DNS_HINFO|PHP_DNS_CAA|PHP_DNS_MX|PHP_DNS_TXT|PHP_DNS_A6|PHP_DNS_SRV|PHP_DNS_NAPTR|PHP_DNS_AAAA)
  269. #endif /* HAVE_FULL_DNS_FUNCS || defined(PHP_WIN32) */
  270. /* Note: These functions are defined in ext/standard/dns_win32.c for Windows! */
  271. #if !defined(PHP_WIN32) && HAVE_DNS_SEARCH_FUNC
  272. #ifndef HFIXEDSZ
  273. #define HFIXEDSZ 12 /* fixed data in header <arpa/nameser.h> */
  274. #endif /* HFIXEDSZ */
  275. #ifndef QFIXEDSZ
  276. #define QFIXEDSZ 4 /* fixed data in query <arpa/nameser.h> */
  277. #endif /* QFIXEDSZ */
  278. #undef MAXHOSTNAMELEN
  279. #define MAXHOSTNAMELEN 1024
  280. #ifndef MAXRESOURCERECORDS
  281. #define MAXRESOURCERECORDS 64
  282. #endif /* MAXRESOURCERECORDS */
  283. typedef union {
  284. HEADER qb1;
  285. u_char qb2[65536];
  286. } querybuf;
  287. /* just a hack to free resources allocated by glibc in __res_nsend()
  288. * See also:
  289. * res_thread_freeres() in glibc/resolv/res_init.c
  290. * __libc_res_nsend() in resolv/res_send.c
  291. * */
  292. #if defined(__GLIBC__) && !defined(HAVE_DEPRECATED_DNS_FUNCS)
  293. #define php_dns_free_res(__res__) _php_dns_free_res(__res__)
  294. static void _php_dns_free_res(struct __res_state *res) { /* {{{ */
  295. int ns;
  296. for (ns = 0; ns < MAXNS; ns++) {
  297. if (res->_u._ext.nsaddrs[ns] != NULL) {
  298. free (res->_u._ext.nsaddrs[ns]);
  299. res->_u._ext.nsaddrs[ns] = NULL;
  300. }
  301. }
  302. } /* }}} */
  303. #else
  304. #define php_dns_free_res(__res__)
  305. #endif
  306. /* {{{ proto bool dns_check_record(string host [, string type])
  307. Check DNS records corresponding to a given Internet host name or IP address */
  308. PHP_FUNCTION(dns_check_record)
  309. {
  310. #ifndef MAXPACKET
  311. #define MAXPACKET 8192 /* max packet size used internally by BIND */
  312. #endif
  313. u_char ans[MAXPACKET];
  314. char *hostname, *rectype = NULL;
  315. size_t hostname_len, rectype_len = 0;
  316. int type = DNS_T_MX, i;
  317. #if defined(HAVE_DNS_SEARCH)
  318. struct sockaddr_storage from;
  319. uint32_t fromsize = sizeof(from);
  320. dns_handle_t handle;
  321. #elif defined(HAVE_RES_NSEARCH)
  322. struct __res_state state;
  323. struct __res_state *handle = &state;
  324. #endif
  325. ZEND_PARSE_PARAMETERS_START(1, 2)
  326. Z_PARAM_STRING(hostname, hostname_len)
  327. Z_PARAM_OPTIONAL
  328. Z_PARAM_STRING(rectype, rectype_len)
  329. ZEND_PARSE_PARAMETERS_END();
  330. if (hostname_len == 0) {
  331. zend_argument_value_error(1, "cannot be empty");
  332. RETURN_THROWS();
  333. }
  334. if (rectype) {
  335. if (!strcasecmp("A", rectype)) type = DNS_T_A;
  336. else if (!strcasecmp("NS", rectype)) type = DNS_T_NS;
  337. else if (!strcasecmp("MX", rectype)) type = DNS_T_MX;
  338. else if (!strcasecmp("PTR", rectype)) type = DNS_T_PTR;
  339. else if (!strcasecmp("ANY", rectype)) type = DNS_T_ANY;
  340. else if (!strcasecmp("SOA", rectype)) type = DNS_T_SOA;
  341. else if (!strcasecmp("CAA", rectype)) type = DNS_T_CAA;
  342. else if (!strcasecmp("TXT", rectype)) type = DNS_T_TXT;
  343. else if (!strcasecmp("CNAME", rectype)) type = DNS_T_CNAME;
  344. else if (!strcasecmp("AAAA", rectype)) type = DNS_T_AAAA;
  345. else if (!strcasecmp("SRV", rectype)) type = DNS_T_SRV;
  346. else if (!strcasecmp("NAPTR", rectype)) type = DNS_T_NAPTR;
  347. else if (!strcasecmp("A6", rectype)) type = DNS_T_A6;
  348. else {
  349. php_error_docref(NULL, E_WARNING, "Type '%s' not supported", rectype);
  350. RETURN_FALSE;
  351. }
  352. }
  353. #if defined(HAVE_DNS_SEARCH)
  354. handle = dns_open(NULL);
  355. if (handle == NULL) {
  356. RETURN_FALSE;
  357. }
  358. #elif defined(HAVE_RES_NSEARCH)
  359. memset(&state, 0, sizeof(state));
  360. if (res_ninit(handle)) {
  361. RETURN_FALSE;
  362. }
  363. #else
  364. res_init();
  365. #endif
  366. RETVAL_TRUE;
  367. i = php_dns_search(handle, hostname, C_IN, type, ans, sizeof(ans));
  368. if (i < 0) {
  369. RETVAL_FALSE;
  370. }
  371. php_dns_free_handle(handle);
  372. }
  373. /* }}} */
  374. #if HAVE_FULL_DNS_FUNCS
  375. #define CHECKCP(n) do { \
  376. if (cp + n > end) { \
  377. return NULL; \
  378. } \
  379. } while (0)
  380. /* {{{ php_parserr */
  381. static u_char *php_parserr(u_char *cp, u_char *end, querybuf *answer, int type_to_fetch, int store, int raw, zval *subarray)
  382. {
  383. u_short type, class, dlen;
  384. u_long ttl;
  385. long n, i;
  386. u_short s;
  387. u_char *tp, *p;
  388. char name[MAXHOSTNAMELEN];
  389. int have_v6_break = 0, in_v6_break = 0;
  390. ZVAL_UNDEF(subarray);
  391. n = dn_expand(answer->qb2, end, cp, name, sizeof(name) - 2);
  392. if (n < 0) {
  393. return NULL;
  394. }
  395. cp += n;
  396. CHECKCP(10);
  397. GETSHORT(type, cp);
  398. GETSHORT(class, cp);
  399. GETLONG(ttl, cp);
  400. GETSHORT(dlen, cp);
  401. CHECKCP(dlen);
  402. if (dlen == 0) {
  403. /* No data in the response - nothing to do */
  404. return NULL;
  405. }
  406. if (type_to_fetch != DNS_T_ANY && type != type_to_fetch) {
  407. cp += dlen;
  408. return cp;
  409. }
  410. if (!store) {
  411. cp += dlen;
  412. return cp;
  413. }
  414. array_init(subarray);
  415. add_assoc_string(subarray, "host", name);
  416. add_assoc_string(subarray, "class", "IN");
  417. add_assoc_long(subarray, "ttl", ttl);
  418. (void) class;
  419. if (raw) {
  420. add_assoc_long(subarray, "type", type);
  421. add_assoc_stringl(subarray, "data", (char*) cp, (uint32_t) dlen);
  422. cp += dlen;
  423. return cp;
  424. }
  425. switch (type) {
  426. case DNS_T_A:
  427. CHECKCP(4);
  428. add_assoc_string(subarray, "type", "A");
  429. snprintf(name, sizeof(name), "%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
  430. add_assoc_string(subarray, "ip", name);
  431. cp += dlen;
  432. break;
  433. case DNS_T_MX:
  434. CHECKCP(2);
  435. add_assoc_string(subarray, "type", "MX");
  436. GETSHORT(n, cp);
  437. add_assoc_long(subarray, "pri", n);
  438. /* no break; */
  439. case DNS_T_CNAME:
  440. if (type == DNS_T_CNAME) {
  441. add_assoc_string(subarray, "type", "CNAME");
  442. }
  443. /* no break; */
  444. case DNS_T_NS:
  445. if (type == DNS_T_NS) {
  446. add_assoc_string(subarray, "type", "NS");
  447. }
  448. /* no break; */
  449. case DNS_T_PTR:
  450. if (type == DNS_T_PTR) {
  451. add_assoc_string(subarray, "type", "PTR");
  452. }
  453. n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2);
  454. if (n < 0) {
  455. return NULL;
  456. }
  457. cp += n;
  458. add_assoc_string(subarray, "target", name);
  459. break;
  460. case DNS_T_HINFO:
  461. /* See RFC 1010 for values */
  462. add_assoc_string(subarray, "type", "HINFO");
  463. CHECKCP(1);
  464. n = *cp & 0xFF;
  465. cp++;
  466. CHECKCP(n);
  467. add_assoc_stringl(subarray, "cpu", (char*)cp, n);
  468. cp += n;
  469. CHECKCP(1);
  470. n = *cp & 0xFF;
  471. cp++;
  472. CHECKCP(n);
  473. add_assoc_stringl(subarray, "os", (char*)cp, n);
  474. cp += n;
  475. break;
  476. case DNS_T_CAA:
  477. /* See RFC 6844 for values https://tools.ietf.org/html/rfc6844 */
  478. add_assoc_string(subarray, "type", "CAA");
  479. // 1 flag byte
  480. CHECKCP(1);
  481. n = *cp & 0xFF;
  482. add_assoc_long(subarray, "flags", n);
  483. cp++;
  484. // Tag length (1 byte)
  485. CHECKCP(1);
  486. n = *cp & 0xFF;
  487. cp++;
  488. CHECKCP(n);
  489. add_assoc_stringl(subarray, "tag", (char*)cp, n);
  490. cp += n;
  491. if ( (size_t) dlen < ((size_t)n) + 2 ) {
  492. return NULL;
  493. }
  494. n = dlen - n - 2;
  495. CHECKCP(n);
  496. add_assoc_stringl(subarray, "value", (char*)cp, n);
  497. cp += n;
  498. break;
  499. case DNS_T_TXT:
  500. {
  501. int l1 = 0, l2 = 0;
  502. zval entries;
  503. zend_string *tp;
  504. add_assoc_string(subarray, "type", "TXT");
  505. tp = zend_string_alloc(dlen, 0);
  506. array_init(&entries);
  507. while (l1 < dlen) {
  508. n = cp[l1];
  509. if ((l1 + n) >= dlen) {
  510. // Invalid chunk length, truncate
  511. n = dlen - (l1 + 1);
  512. }
  513. if (n) {
  514. memcpy(ZSTR_VAL(tp) + l2 , cp + l1 + 1, n);
  515. add_next_index_stringl(&entries, (char *) cp + l1 + 1, n);
  516. }
  517. l1 = l1 + n + 1;
  518. l2 = l2 + n;
  519. }
  520. ZSTR_VAL(tp)[l2] = '\0';
  521. ZSTR_LEN(tp) = l2;
  522. cp += dlen;
  523. add_assoc_str(subarray, "txt", tp);
  524. add_assoc_zval(subarray, "entries", &entries);
  525. }
  526. break;
  527. case DNS_T_SOA:
  528. add_assoc_string(subarray, "type", "SOA");
  529. n = dn_expand(answer->qb2, end, cp, name, (sizeof name) -2);
  530. if (n < 0) {
  531. return NULL;
  532. }
  533. cp += n;
  534. add_assoc_string(subarray, "mname", name);
  535. n = dn_expand(answer->qb2, end, cp, name, (sizeof name) -2);
  536. if (n < 0) {
  537. return NULL;
  538. }
  539. cp += n;
  540. add_assoc_string(subarray, "rname", name);
  541. CHECKCP(5*4);
  542. GETLONG(n, cp);
  543. add_assoc_long(subarray, "serial", n);
  544. GETLONG(n, cp);
  545. add_assoc_long(subarray, "refresh", n);
  546. GETLONG(n, cp);
  547. add_assoc_long(subarray, "retry", n);
  548. GETLONG(n, cp);
  549. add_assoc_long(subarray, "expire", n);
  550. GETLONG(n, cp);
  551. add_assoc_long(subarray, "minimum-ttl", n);
  552. break;
  553. case DNS_T_AAAA:
  554. tp = (u_char*)name;
  555. CHECKCP(8*2);
  556. for(i=0; i < 8; i++) {
  557. GETSHORT(s, cp);
  558. if (s != 0) {
  559. if (tp > (u_char *)name) {
  560. in_v6_break = 0;
  561. tp[0] = ':';
  562. tp++;
  563. }
  564. tp += sprintf((char*)tp,"%x",s);
  565. } else {
  566. if (!have_v6_break) {
  567. have_v6_break = 1;
  568. in_v6_break = 1;
  569. tp[0] = ':';
  570. tp++;
  571. } else if (!in_v6_break) {
  572. tp[0] = ':';
  573. tp++;
  574. tp[0] = '0';
  575. tp++;
  576. }
  577. }
  578. }
  579. if (have_v6_break && in_v6_break) {
  580. tp[0] = ':';
  581. tp++;
  582. }
  583. tp[0] = '\0';
  584. add_assoc_string(subarray, "type", "AAAA");
  585. add_assoc_string(subarray, "ipv6", name);
  586. break;
  587. case DNS_T_A6:
  588. p = cp;
  589. add_assoc_string(subarray, "type", "A6");
  590. CHECKCP(1);
  591. n = ((int)cp[0]) & 0xFF;
  592. cp++;
  593. add_assoc_long(subarray, "masklen", n);
  594. tp = (u_char*)name;
  595. if (n > 15) {
  596. have_v6_break = 1;
  597. in_v6_break = 1;
  598. tp[0] = ':';
  599. tp++;
  600. }
  601. if (n % 16 > 8) {
  602. /* Partial short */
  603. if (cp[0] != 0) {
  604. if (tp > (u_char *)name) {
  605. in_v6_break = 0;
  606. tp[0] = ':';
  607. tp++;
  608. }
  609. sprintf((char*)tp, "%x", cp[0] & 0xFF);
  610. } else {
  611. if (!have_v6_break) {
  612. have_v6_break = 1;
  613. in_v6_break = 1;
  614. tp[0] = ':';
  615. tp++;
  616. } else if (!in_v6_break) {
  617. tp[0] = ':';
  618. tp++;
  619. tp[0] = '0';
  620. tp++;
  621. }
  622. }
  623. cp++;
  624. }
  625. for (i = (n + 8) / 16; i < 8; i++) {
  626. CHECKCP(2);
  627. GETSHORT(s, cp);
  628. if (s != 0) {
  629. if (tp > (u_char *)name) {
  630. in_v6_break = 0;
  631. tp[0] = ':';
  632. tp++;
  633. }
  634. tp += sprintf((char*)tp,"%x",s);
  635. } else {
  636. if (!have_v6_break) {
  637. have_v6_break = 1;
  638. in_v6_break = 1;
  639. tp[0] = ':';
  640. tp++;
  641. } else if (!in_v6_break) {
  642. tp[0] = ':';
  643. tp++;
  644. tp[0] = '0';
  645. tp++;
  646. }
  647. }
  648. }
  649. if (have_v6_break && in_v6_break) {
  650. tp[0] = ':';
  651. tp++;
  652. }
  653. tp[0] = '\0';
  654. add_assoc_string(subarray, "ipv6", name);
  655. if (cp < p + dlen) {
  656. n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2);
  657. if (n < 0) {
  658. return NULL;
  659. }
  660. cp += n;
  661. add_assoc_string(subarray, "chain", name);
  662. }
  663. break;
  664. case DNS_T_SRV:
  665. CHECKCP(3*2);
  666. add_assoc_string(subarray, "type", "SRV");
  667. GETSHORT(n, cp);
  668. add_assoc_long(subarray, "pri", n);
  669. GETSHORT(n, cp);
  670. add_assoc_long(subarray, "weight", n);
  671. GETSHORT(n, cp);
  672. add_assoc_long(subarray, "port", n);
  673. n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2);
  674. if (n < 0) {
  675. return NULL;
  676. }
  677. cp += n;
  678. add_assoc_string(subarray, "target", name);
  679. break;
  680. case DNS_T_NAPTR:
  681. CHECKCP(2*2);
  682. add_assoc_string(subarray, "type", "NAPTR");
  683. GETSHORT(n, cp);
  684. add_assoc_long(subarray, "order", n);
  685. GETSHORT(n, cp);
  686. add_assoc_long(subarray, "pref", n);
  687. CHECKCP(1);
  688. n = (cp[0] & 0xFF);
  689. cp++;
  690. CHECKCP(n);
  691. add_assoc_stringl(subarray, "flags", (char*)cp, n);
  692. cp += n;
  693. CHECKCP(1);
  694. n = (cp[0] & 0xFF);
  695. cp++;
  696. CHECKCP(n);
  697. add_assoc_stringl(subarray, "services", (char*)cp, n);
  698. cp += n;
  699. CHECKCP(1);
  700. n = (cp[0] & 0xFF);
  701. cp++;
  702. CHECKCP(n);
  703. add_assoc_stringl(subarray, "regex", (char*)cp, n);
  704. cp += n;
  705. n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2);
  706. if (n < 0) {
  707. return NULL;
  708. }
  709. cp += n;
  710. add_assoc_string(subarray, "replacement", name);
  711. break;
  712. default:
  713. zval_ptr_dtor(subarray);
  714. ZVAL_UNDEF(subarray);
  715. cp += dlen;
  716. break;
  717. }
  718. return cp;
  719. }
  720. /* }}} */
  721. /* {{{ proto array|false dns_get_record(string hostname [, int type[, array &authns[, array &addtl[, bool raw]]]])
  722. Get any Resource Record corresponding to a given Internet host name */
  723. PHP_FUNCTION(dns_get_record)
  724. {
  725. char *hostname;
  726. size_t hostname_len;
  727. zend_long type_param = PHP_DNS_ANY;
  728. zval *authns = NULL, *addtl = NULL;
  729. int type_to_fetch;
  730. #if defined(HAVE_DNS_SEARCH)
  731. struct sockaddr_storage from;
  732. uint32_t fromsize = sizeof(from);
  733. dns_handle_t handle;
  734. #elif defined(HAVE_RES_NSEARCH)
  735. struct __res_state state;
  736. struct __res_state *handle = &state;
  737. #endif
  738. HEADER *hp;
  739. querybuf answer;
  740. u_char *cp = NULL, *end = NULL;
  741. int n, qd, an, ns = 0, ar = 0;
  742. int type, first_query = 1, store_results = 1;
  743. zend_bool raw = 0;
  744. ZEND_PARSE_PARAMETERS_START(1, 5)
  745. Z_PARAM_STRING(hostname, hostname_len)
  746. Z_PARAM_OPTIONAL
  747. Z_PARAM_LONG(type_param)
  748. Z_PARAM_ZVAL(authns)
  749. Z_PARAM_ZVAL(addtl)
  750. Z_PARAM_BOOL(raw)
  751. ZEND_PARSE_PARAMETERS_END();
  752. if (authns) {
  753. authns = zend_try_array_init(authns);
  754. if (!authns) {
  755. RETURN_THROWS();
  756. }
  757. }
  758. if (addtl) {
  759. addtl = zend_try_array_init(addtl);
  760. if (!addtl) {
  761. RETURN_THROWS();
  762. }
  763. }
  764. if (!raw) {
  765. if ((type_param & ~PHP_DNS_ALL) && (type_param != PHP_DNS_ANY)) {
  766. php_error_docref(NULL, E_WARNING, "Type '" ZEND_LONG_FMT "' not supported", type_param);
  767. RETURN_FALSE;
  768. }
  769. } else {
  770. if ((type_param < 1) || (type_param > 0xFFFF)) {
  771. php_error_docref(NULL, E_WARNING,
  772. "Numeric DNS record type must be between 1 and 65535, '" ZEND_LONG_FMT "' given", type_param);
  773. RETURN_FALSE;
  774. }
  775. }
  776. /* Initialize the return array */
  777. array_init(return_value);
  778. /* - We emulate an or'ed type mask by querying type by type. (Steps 0 - NUMTYPES-1 )
  779. * If additional info is wanted we check again with DNS_T_ANY (step NUMTYPES / NUMTYPES+1 )
  780. * store_results is used to skip storing the results retrieved in step
  781. * NUMTYPES+1 when results were already fetched.
  782. * - In case of PHP_DNS_ANY we use the directly fetch DNS_T_ANY. (step NUMTYPES+1 )
  783. * - In case of raw mode, we query only the requested type instead of looping type by type
  784. * before going with the additional info stuff.
  785. */
  786. if (raw) {
  787. type = -1;
  788. } else if (type_param == PHP_DNS_ANY) {
  789. type = PHP_DNS_NUM_TYPES + 1;
  790. } else {
  791. type = 0;
  792. }
  793. for ( ;
  794. type < (addtl ? (PHP_DNS_NUM_TYPES + 2) : PHP_DNS_NUM_TYPES) || first_query;
  795. type++
  796. ) {
  797. first_query = 0;
  798. switch (type) {
  799. case -1: /* raw */
  800. type_to_fetch = type_param;
  801. /* skip over the rest and go directly to additional records */
  802. type = PHP_DNS_NUM_TYPES - 1;
  803. break;
  804. case 0:
  805. type_to_fetch = type_param&PHP_DNS_A ? DNS_T_A : 0;
  806. break;
  807. case 1:
  808. type_to_fetch = type_param&PHP_DNS_NS ? DNS_T_NS : 0;
  809. break;
  810. case 2:
  811. type_to_fetch = type_param&PHP_DNS_CNAME ? DNS_T_CNAME : 0;
  812. break;
  813. case 3:
  814. type_to_fetch = type_param&PHP_DNS_SOA ? DNS_T_SOA : 0;
  815. break;
  816. case 4:
  817. type_to_fetch = type_param&PHP_DNS_PTR ? DNS_T_PTR : 0;
  818. break;
  819. case 5:
  820. type_to_fetch = type_param&PHP_DNS_HINFO ? DNS_T_HINFO : 0;
  821. break;
  822. case 6:
  823. type_to_fetch = type_param&PHP_DNS_MX ? DNS_T_MX : 0;
  824. break;
  825. case 7:
  826. type_to_fetch = type_param&PHP_DNS_TXT ? DNS_T_TXT : 0;
  827. break;
  828. case 8:
  829. type_to_fetch = type_param&PHP_DNS_AAAA ? DNS_T_AAAA : 0;
  830. break;
  831. case 9:
  832. type_to_fetch = type_param&PHP_DNS_SRV ? DNS_T_SRV : 0;
  833. break;
  834. case 10:
  835. type_to_fetch = type_param&PHP_DNS_NAPTR ? DNS_T_NAPTR : 0;
  836. break;
  837. case 11:
  838. type_to_fetch = type_param&PHP_DNS_A6 ? DNS_T_A6 : 0;
  839. break;
  840. case 12:
  841. type_to_fetch = type_param&PHP_DNS_CAA ? DNS_T_CAA : 0;
  842. break;
  843. case PHP_DNS_NUM_TYPES:
  844. store_results = 0;
  845. continue;
  846. default:
  847. case (PHP_DNS_NUM_TYPES + 1):
  848. type_to_fetch = DNS_T_ANY;
  849. break;
  850. }
  851. if (type_to_fetch) {
  852. #if defined(HAVE_DNS_SEARCH)
  853. handle = dns_open(NULL);
  854. if (handle == NULL) {
  855. zend_array_destroy(Z_ARR_P(return_value));
  856. RETURN_FALSE;
  857. }
  858. #elif defined(HAVE_RES_NSEARCH)
  859. memset(&state, 0, sizeof(state));
  860. if (res_ninit(handle)) {
  861. zend_array_destroy(Z_ARR_P(return_value));
  862. RETURN_FALSE;
  863. }
  864. #else
  865. res_init();
  866. #endif
  867. n = php_dns_search(handle, hostname, C_IN, type_to_fetch, answer.qb2, sizeof answer);
  868. if (n < 0) {
  869. php_dns_free_handle(handle);
  870. switch (h_errno) {
  871. case NO_DATA:
  872. case HOST_NOT_FOUND:
  873. continue;
  874. case NO_RECOVERY:
  875. php_error_docref(NULL, E_WARNING, "An unexpected server failure occurred.");
  876. break;
  877. case TRY_AGAIN:
  878. php_error_docref(NULL, E_WARNING, "A temporary server error occurred.");
  879. break;
  880. default:
  881. php_error_docref(NULL, E_WARNING, "DNS Query failed");
  882. }
  883. zend_array_destroy(Z_ARR_P(return_value));
  884. RETURN_FALSE;
  885. }
  886. cp = answer.qb2 + HFIXEDSZ;
  887. end = answer.qb2 + n;
  888. hp = (HEADER *)&answer;
  889. qd = ntohs(hp->qdcount);
  890. an = ntohs(hp->ancount);
  891. ns = ntohs(hp->nscount);
  892. ar = ntohs(hp->arcount);
  893. /* Skip QD entries, they're only used by dn_expand later on */
  894. while (qd-- > 0) {
  895. n = dn_skipname(cp, end);
  896. if (n < 0) {
  897. php_error_docref(NULL, E_WARNING, "Unable to parse DNS data received");
  898. zend_array_destroy(Z_ARR_P(return_value));
  899. php_dns_free_handle(handle);
  900. RETURN_FALSE;
  901. }
  902. cp += n + QFIXEDSZ;
  903. }
  904. /* YAY! Our real answers! */
  905. while (an-- && cp && cp < end) {
  906. zval retval;
  907. cp = php_parserr(cp, end, &answer, type_to_fetch, store_results, raw, &retval);
  908. if (Z_TYPE(retval) != IS_UNDEF && store_results) {
  909. add_next_index_zval(return_value, &retval);
  910. }
  911. }
  912. if (authns || addtl) {
  913. /* List of Authoritative Name Servers
  914. * Process when only requesting addtl so that we can skip through the section
  915. */
  916. while (ns-- > 0 && cp && cp < end) {
  917. zval retval;
  918. cp = php_parserr(cp, end, &answer, DNS_T_ANY, authns != NULL, raw, &retval);
  919. if (Z_TYPE(retval) != IS_UNDEF) {
  920. add_next_index_zval(authns, &retval);
  921. }
  922. }
  923. }
  924. if (addtl) {
  925. /* Additional records associated with authoritative name servers */
  926. while (ar-- > 0 && cp && cp < end) {
  927. zval retval;
  928. cp = php_parserr(cp, end, &answer, DNS_T_ANY, 1, raw, &retval);
  929. if (Z_TYPE(retval) != IS_UNDEF) {
  930. add_next_index_zval(addtl, &retval);
  931. }
  932. }
  933. }
  934. php_dns_free_handle(handle);
  935. }
  936. }
  937. }
  938. /* }}} */
  939. /* {{{ proto bool dns_get_mx(string hostname, array mxhosts [, array weight])
  940. Get MX records corresponding to a given Internet host name */
  941. PHP_FUNCTION(dns_get_mx)
  942. {
  943. char *hostname;
  944. size_t hostname_len;
  945. zval *mx_list, *weight_list = NULL;
  946. int count, qdc;
  947. u_short type, weight;
  948. u_char ans[MAXPACKET];
  949. char buf[MAXHOSTNAMELEN];
  950. HEADER *hp;
  951. u_char *cp, *end;
  952. int i;
  953. #if defined(HAVE_DNS_SEARCH)
  954. struct sockaddr_storage from;
  955. uint32_t fromsize = sizeof(from);
  956. dns_handle_t handle;
  957. #elif defined(HAVE_RES_NSEARCH)
  958. struct __res_state state;
  959. struct __res_state *handle = &state;
  960. #endif
  961. ZEND_PARSE_PARAMETERS_START(2, 3)
  962. Z_PARAM_STRING(hostname, hostname_len)
  963. Z_PARAM_ZVAL(mx_list)
  964. Z_PARAM_OPTIONAL
  965. Z_PARAM_ZVAL(weight_list)
  966. ZEND_PARSE_PARAMETERS_END();
  967. mx_list = zend_try_array_init(mx_list);
  968. if (!mx_list) {
  969. RETURN_THROWS();
  970. }
  971. if (weight_list) {
  972. weight_list = zend_try_array_init(weight_list);
  973. if (!weight_list) {
  974. RETURN_THROWS();
  975. }
  976. }
  977. #if defined(HAVE_DNS_SEARCH)
  978. handle = dns_open(NULL);
  979. if (handle == NULL) {
  980. RETURN_FALSE;
  981. }
  982. #elif defined(HAVE_RES_NSEARCH)
  983. memset(&state, 0, sizeof(state));
  984. if (res_ninit(handle)) {
  985. RETURN_FALSE;
  986. }
  987. #else
  988. res_init();
  989. #endif
  990. i = php_dns_search(handle, hostname, C_IN, DNS_T_MX, (u_char *)&ans, sizeof(ans));
  991. if (i < 0) {
  992. RETURN_FALSE;
  993. }
  994. if (i > (int)sizeof(ans)) {
  995. i = sizeof(ans);
  996. }
  997. hp = (HEADER *)&ans;
  998. cp = (u_char *)&ans + HFIXEDSZ;
  999. end = (u_char *)&ans +i;
  1000. for (qdc = ntohs((unsigned short)hp->qdcount); qdc--; cp += i + QFIXEDSZ) {
  1001. if ((i = dn_skipname(cp, end)) < 0 ) {
  1002. php_dns_free_handle(handle);
  1003. RETURN_FALSE;
  1004. }
  1005. }
  1006. count = ntohs((unsigned short)hp->ancount);
  1007. while (--count >= 0 && cp < end) {
  1008. if ((i = dn_skipname(cp, end)) < 0 ) {
  1009. php_dns_free_handle(handle);
  1010. RETURN_FALSE;
  1011. }
  1012. cp += i;
  1013. GETSHORT(type, cp);
  1014. cp += INT16SZ + INT32SZ;
  1015. GETSHORT(i, cp);
  1016. if (type != DNS_T_MX) {
  1017. cp += i;
  1018. continue;
  1019. }
  1020. GETSHORT(weight, cp);
  1021. if ((i = dn_expand(ans, end, cp, buf, sizeof(buf)-1)) < 0) {
  1022. php_dns_free_handle(handle);
  1023. RETURN_FALSE;
  1024. }
  1025. cp += i;
  1026. add_next_index_string(mx_list, buf);
  1027. if (weight_list) {
  1028. add_next_index_long(weight_list, weight);
  1029. }
  1030. }
  1031. php_dns_free_handle(handle);
  1032. RETURN_TRUE;
  1033. }
  1034. /* }}} */
  1035. #endif /* HAVE_FULL_DNS_FUNCS */
  1036. #endif /* !defined(PHP_WIN32) && HAVE_DNS_SEARCH_FUNC */
  1037. #if HAVE_FULL_DNS_FUNCS && !defined(PHP_WIN32)
  1038. PHP_MINIT_FUNCTION(dns) {
  1039. REGISTER_LONG_CONSTANT("DNS_A", PHP_DNS_A, CONST_CS | CONST_PERSISTENT);
  1040. REGISTER_LONG_CONSTANT("DNS_NS", PHP_DNS_NS, CONST_CS | CONST_PERSISTENT);
  1041. REGISTER_LONG_CONSTANT("DNS_CNAME", PHP_DNS_CNAME, CONST_CS | CONST_PERSISTENT);
  1042. REGISTER_LONG_CONSTANT("DNS_SOA", PHP_DNS_SOA, CONST_CS | CONST_PERSISTENT);
  1043. REGISTER_LONG_CONSTANT("DNS_PTR", PHP_DNS_PTR, CONST_CS | CONST_PERSISTENT);
  1044. REGISTER_LONG_CONSTANT("DNS_HINFO", PHP_DNS_HINFO, CONST_CS | CONST_PERSISTENT);
  1045. REGISTER_LONG_CONSTANT("DNS_CAA", PHP_DNS_CAA, CONST_CS | CONST_PERSISTENT);
  1046. REGISTER_LONG_CONSTANT("DNS_MX", PHP_DNS_MX, CONST_CS | CONST_PERSISTENT);
  1047. REGISTER_LONG_CONSTANT("DNS_TXT", PHP_DNS_TXT, CONST_CS | CONST_PERSISTENT);
  1048. REGISTER_LONG_CONSTANT("DNS_SRV", PHP_DNS_SRV, CONST_CS | CONST_PERSISTENT);
  1049. REGISTER_LONG_CONSTANT("DNS_NAPTR", PHP_DNS_NAPTR, CONST_CS | CONST_PERSISTENT);
  1050. REGISTER_LONG_CONSTANT("DNS_AAAA", PHP_DNS_AAAA, CONST_CS | CONST_PERSISTENT);
  1051. REGISTER_LONG_CONSTANT("DNS_A6", PHP_DNS_A6, CONST_CS | CONST_PERSISTENT);
  1052. REGISTER_LONG_CONSTANT("DNS_ANY", PHP_DNS_ANY, CONST_CS | CONST_PERSISTENT);
  1053. REGISTER_LONG_CONSTANT("DNS_ALL", PHP_DNS_ALL, CONST_CS | CONST_PERSISTENT);
  1054. return SUCCESS;
  1055. }
  1056. #endif /* HAVE_FULL_DNS_FUNCS */