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