dns.c 28 KB

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