1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2008 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)
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_STRING(hostname, 0);
164 : }
165 : }
166 : /* }}} */
167 :
168 : /* {{{ php_gethostbyaddr */
169 : static char *php_gethostbyaddr(char *ip)
170 4 : {
171 : #if HAVE_IPV6 && HAVE_INET_PTON
172 : struct in6_addr addr6;
173 : #endif
174 : struct in_addr addr;
175 : struct hostent *hp;
176 :
177 : #if HAVE_IPV6 && HAVE_INET_PTON
178 4 : if (inet_pton(AF_INET6, ip, &addr6)) {
179 0 : hp = gethostbyaddr((char *) &addr6, sizeof(addr6), AF_INET6);
180 4 : } else if (inet_pton(AF_INET, ip, &addr)) {
181 1 : hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
182 : } else {
183 3 : return NULL;
184 : }
185 : #else
186 : addr.s_addr = inet_addr(ip);
187 :
188 : if (addr.s_addr == -1) {
189 : return NULL;
190 : }
191 :
192 : hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
193 : #endif
194 :
195 1 : if (!hp || hp->h_name == NULL || hp->h_name[0] == '\0') {
196 0 : return estrdup(ip);
197 : }
198 :
199 1 : return estrdup(hp->h_name);
200 : }
201 : /* }}} */
202 :
203 : /* {{{ proto string gethostbyname(string hostname)
204 : Get the IP address corresponding to a given Internet host name */
205 : PHP_FUNCTION(gethostbyname)
206 9 : {
207 : char *hostname;
208 : int hostname_len;
209 : char *addr;
210 :
211 9 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &hostname, &hostname_len) == FAILURE) {
212 1 : return;
213 : }
214 :
215 8 : addr = php_gethostbyname(hostname);
216 :
217 8 : RETVAL_STRING(addr, 0);
218 : }
219 : /* }}} */
220 :
221 : /* {{{ proto array gethostbynamel(string hostname)
222 : Return a list of IP addresses that a given hostname resolves to. */
223 : PHP_FUNCTION(gethostbynamel)
224 4 : {
225 : char *hostname;
226 : int hostname_len;
227 : struct hostent *hp;
228 : struct in_addr in;
229 : int i;
230 :
231 4 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &hostname, &hostname_len) == FAILURE) {
232 2 : return;
233 : }
234 :
235 2 : hp = gethostbyname(hostname);
236 2 : if (hp == NULL || hp->h_addr_list == NULL) {
237 1 : RETURN_FALSE;
238 : }
239 :
240 1 : array_init(return_value);
241 :
242 2 : for (i = 0 ; hp->h_addr_list[i] != 0 ; i++) {
243 1 : in = *(struct in_addr *) hp->h_addr_list[i];
244 1 : add_next_index_string(return_value, inet_ntoa(in), 1);
245 : }
246 : }
247 : /* }}} */
248 :
249 : /* {{{ php_gethostbyname */
250 : static char *php_gethostbyname(char *name)
251 8 : {
252 : struct hostent *hp;
253 : struct in_addr in;
254 :
255 8 : hp = gethostbyname(name);
256 :
257 8 : if (!hp || !*(hp->h_addr_list)) {
258 2 : return estrdup(name);
259 : }
260 :
261 6 : memcpy(&in.s_addr, *(hp->h_addr_list), sizeof(in.s_addr));
262 :
263 6 : return estrdup(inet_ntoa(in));
264 : }
265 : /* }}} */
266 :
267 : #if HAVE_FULL_DNS_FUNCS || defined(PHP_WIN32)
268 : # define PHP_DNS_NUM_TYPES 12 /* Number of DNS Types Supported by PHP currently */
269 :
270 : # define PHP_DNS_A 0x00000001
271 : # define PHP_DNS_NS 0x00000002
272 : # define PHP_DNS_CNAME 0x00000010
273 : # define PHP_DNS_SOA 0x00000020
274 : # define PHP_DNS_PTR 0x00000800
275 : # define PHP_DNS_HINFO 0x00001000
276 : # define PHP_DNS_MX 0x00004000
277 : # define PHP_DNS_TXT 0x00008000
278 : # define PHP_DNS_A6 0x01000000
279 : # define PHP_DNS_SRV 0x02000000
280 : # define PHP_DNS_NAPTR 0x04000000
281 : # define PHP_DNS_AAAA 0x08000000
282 : # define PHP_DNS_ANY 0x10000000
283 : # 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)
284 : #endif /* HAVE_FULL_DNS_FUNCS || defined(PHP_WIN32) */
285 :
286 : /* Note: These functions are defined in ext/standard/dns_win32.c for Windows! */
287 : #if !defined(PHP_WIN32) && (HAVE_DNS_SEARCH_FUNC && !(defined(__BEOS__) || defined(NETWARE)))
288 :
289 : #ifndef HFIXEDSZ
290 : #define HFIXEDSZ 12 /* fixed data in header <arpa/nameser.h> */
291 : #endif /* HFIXEDSZ */
292 :
293 : #ifndef QFIXEDSZ
294 : #define QFIXEDSZ 4 /* fixed data in query <arpa/nameser.h> */
295 : #endif /* QFIXEDSZ */
296 :
297 : #undef MAXHOSTNAMELEN
298 : #define MAXHOSTNAMELEN 1024
299 :
300 : #ifndef MAXRESOURCERECORDS
301 : #define MAXRESOURCERECORDS 64
302 : #endif /* MAXRESOURCERECORDS */
303 :
304 : typedef union {
305 : HEADER qb1;
306 : u_char qb2[65536];
307 : } querybuf;
308 :
309 : /* just a hack to free resources allocated by glibc in __res_nsend()
310 : * See also:
311 : * res_thread_freeres() in glibc/resolv/res_init.c
312 : * __libc_res_nsend() in resolv/res_send.c
313 : * */
314 :
315 : #if defined(__GLIBC__) && !defined(HAVE_DEPRECATED_DNS_FUNCS)
316 : #define php_dns_free_res(__res__) _php_dns_free_res(__res__)
317 2 : static void _php_dns_free_res(struct __res_state res) { /* {{{ */
318 : int ns;
319 8 : for (ns = 0; ns < MAXNS; ns++) {
320 6 : if (res._u._ext.nsaddrs[ns] != NULL) {
321 0 : free (res._u._ext.nsaddrs[ns]);
322 0 : res._u._ext.nsaddrs[ns] = NULL;
323 : }
324 : }
325 2 : } /* }}} */
326 : #else
327 : #define php_dns_free_res(__res__)
328 : #endif
329 :
330 : /* {{{ proto bool dns_check_record(string host [, string type])
331 : Check DNS records corresponding to a given Internet host name or IP address */
332 : PHP_FUNCTION(dns_check_record)
333 1 : {
334 : #ifndef MAXPACKET
335 : #define MAXPACKET 8192 /* max packet size used internally by BIND */
336 : #endif
337 : u_char ans[MAXPACKET];
338 1 : char *hostname, *rectype = NULL;
339 1 : int hostname_len, rectype_len = 0;
340 1 : int type = T_MX, i;
341 : #if defined(HAVE_DNS_SEARCH)
342 : struct sockaddr_storage from;
343 : uint32_t fromsize = sizeof(from);
344 : dns_handle_t handle;
345 : #elif defined(HAVE_RES_NSEARCH)
346 : struct __res_state state;
347 1 : struct __res_state *handle = &state;
348 : #endif
349 :
350 1 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &hostname, &hostname_len, &rectype, &rectype_len) == FAILURE) {
351 0 : return;
352 : }
353 :
354 1 : if (hostname_len == 0) {
355 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host cannot be empty");
356 1 : RETURN_FALSE;
357 : }
358 :
359 0 : if (rectype) {
360 0 : if (!strcasecmp("A", rectype)) type = T_A;
361 0 : else if (!strcasecmp("NS", rectype)) type = DNS_T_NS;
362 0 : else if (!strcasecmp("MX", rectype)) type = DNS_T_MX;
363 0 : else if (!strcasecmp("PTR", rectype)) type = DNS_T_PTR;
364 0 : else if (!strcasecmp("ANY", rectype)) type = DNS_T_ANY;
365 0 : else if (!strcasecmp("SOA", rectype)) type = DNS_T_SOA;
366 0 : else if (!strcasecmp("TXT", rectype)) type = DNS_T_TXT;
367 0 : else if (!strcasecmp("CNAME", rectype)) type = DNS_T_CNAME;
368 0 : else if (!strcasecmp("AAAA", rectype)) type = DNS_T_AAAA;
369 0 : else if (!strcasecmp("SRV", rectype)) type = DNS_T_SRV;
370 0 : else if (!strcasecmp("NAPTR", rectype)) type = DNS_T_NAPTR;
371 0 : else if (!strcasecmp("A6", rectype)) type = DNS_T_A6;
372 : else {
373 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type '%s' not supported", rectype);
374 0 : RETURN_FALSE;
375 : }
376 : }
377 :
378 : #if defined(HAVE_DNS_SEARCH)
379 : handle = dns_open(NULL);
380 : if (handle == NULL) {
381 : RETURN_FALSE;
382 : }
383 : #elif defined(HAVE_RES_NSEARCH)
384 0 : memset(&state, 0, sizeof(state));
385 0 : if (res_ninit(handle)) {
386 0 : RETURN_FALSE;
387 : }
388 : #else
389 : res_init();
390 : #endif
391 :
392 0 : RETVAL_TRUE;
393 0 : i = php_dns_search(handle, hostname, C_IN, type, ans, sizeof(ans));
394 :
395 0 : if (i < 0) {
396 0 : RETVAL_FALSE;
397 : }
398 :
399 0 : php_dns_free_handle(handle);
400 : }
401 : /* }}} */
402 :
403 : #if HAVE_FULL_DNS_FUNCS
404 :
405 : /* {{{ php_parserr */
406 : static u_char *php_parserr(u_char *cp, querybuf *answer, int type_to_fetch, int store, zval **subarray)
407 0 : {
408 : u_short type, class, dlen;
409 : u_long ttl;
410 : long n, i;
411 : u_short s;
412 : u_char *tp, *p;
413 : char name[MAXHOSTNAMELEN];
414 0 : int have_v6_break = 0, in_v6_break = 0;
415 :
416 0 : *subarray = NULL;
417 :
418 0 : n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, sizeof(name) - 2);
419 0 : if (n < 0) {
420 0 : return NULL;
421 : }
422 0 : cp += n;
423 :
424 0 : GETSHORT(type, cp);
425 0 : GETSHORT(class, cp);
426 0 : GETLONG(ttl, cp);
427 0 : GETSHORT(dlen, cp);
428 0 : if (type_to_fetch != T_ANY && type != type_to_fetch) {
429 0 : cp += dlen;
430 0 : return cp;
431 : }
432 :
433 0 : if (!store) {
434 0 : cp += dlen;
435 0 : return cp;
436 : }
437 :
438 0 : ALLOC_INIT_ZVAL(*subarray);
439 0 : array_init(*subarray);
440 :
441 0 : add_assoc_string(*subarray, "host", name, 1);
442 0 : switch (type) {
443 : case DNS_T_A:
444 0 : add_assoc_string(*subarray, "type", "A", 1);
445 0 : snprintf(name, sizeof(name), "%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
446 0 : add_assoc_string(*subarray, "ip", name, 1);
447 0 : cp += dlen;
448 0 : break;
449 : case DNS_T_MX:
450 0 : add_assoc_string(*subarray, "type", "MX", 1);
451 0 : GETSHORT(n, cp);
452 0 : add_assoc_long(*subarray, "pri", n);
453 : /* no break; */
454 : case DNS_T_CNAME:
455 0 : if (type == DNS_T_CNAME) {
456 0 : add_assoc_string(*subarray, "type", "CNAME", 1);
457 : }
458 : /* no break; */
459 : case DNS_T_NS:
460 0 : if (type == DNS_T_NS) {
461 0 : add_assoc_string(*subarray, "type", "NS", 1);
462 : }
463 : /* no break; */
464 : case DNS_T_PTR:
465 0 : if (type == DNS_T_PTR) {
466 0 : add_assoc_string(*subarray, "type", "PTR", 1);
467 : }
468 0 : n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2);
469 0 : if (n < 0) {
470 0 : return NULL;
471 : }
472 0 : cp += n;
473 0 : add_assoc_string(*subarray, "target", name, 1);
474 0 : break;
475 : case DNS_T_HINFO:
476 : /* See RFC 1010 for values */
477 0 : add_assoc_string(*subarray, "type", "HINFO", 1);
478 0 : n = *cp & 0xFF;
479 0 : cp++;
480 0 : add_assoc_stringl(*subarray, "cpu", (char*)cp, n, 1);
481 0 : cp += n;
482 0 : n = *cp & 0xFF;
483 0 : cp++;
484 0 : add_assoc_stringl(*subarray, "os", (char*)cp, n, 1);
485 0 : cp += n;
486 0 : break;
487 : case DNS_T_TXT:
488 : {
489 0 : int ll = 0;
490 0 : zval *entries = NULL;
491 :
492 0 : add_assoc_string(*subarray, "type", "TXT", 1);
493 0 : tp = emalloc(dlen + 1);
494 :
495 0 : MAKE_STD_ZVAL(entries);
496 0 : array_init(entries);
497 :
498 0 : while (ll < dlen) {
499 0 : n = cp[ll];
500 0 : memcpy(tp + ll , cp + ll + 1, n);
501 0 : add_next_index_stringl(entries, cp + ll + 1, n, 1);
502 0 : ll = ll + n + 1;
503 : }
504 0 : tp[dlen] = '\0';
505 0 : cp += dlen;
506 :
507 0 : add_assoc_stringl(*subarray, "txt", tp, dlen - 1, 0);
508 0 : add_assoc_zval(*subarray, "entries", entries);
509 : }
510 0 : break;
511 : case DNS_T_SOA:
512 0 : add_assoc_string(*subarray, "type", "SOA", 1);
513 0 : n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) -2);
514 0 : if (n < 0) {
515 0 : return NULL;
516 : }
517 0 : cp += n;
518 0 : add_assoc_string(*subarray, "mname", name, 1);
519 0 : n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) -2);
520 0 : if (n < 0) {
521 0 : return NULL;
522 : }
523 0 : cp += n;
524 0 : add_assoc_string(*subarray, "rname", name, 1);
525 0 : GETLONG(n, cp);
526 0 : add_assoc_long(*subarray, "serial", n);
527 0 : GETLONG(n, cp);
528 0 : add_assoc_long(*subarray, "refresh", n);
529 0 : GETLONG(n, cp);
530 0 : add_assoc_long(*subarray, "retry", n);
531 0 : GETLONG(n, cp);
532 0 : add_assoc_long(*subarray, "expire", n);
533 0 : GETLONG(n, cp);
534 0 : add_assoc_long(*subarray, "minimum-ttl", n);
535 0 : break;
536 : case DNS_T_AAAA:
537 0 : tp = (u_char*)name;
538 0 : for(i=0; i < 8; i++) {
539 0 : GETSHORT(s, cp);
540 0 : if (s != 0) {
541 0 : if (tp > (u_char *)name) {
542 0 : in_v6_break = 0;
543 0 : tp[0] = ':';
544 0 : tp++;
545 : }
546 0 : tp += sprintf((char*)tp,"%x",s);
547 : } else {
548 0 : if (!have_v6_break) {
549 0 : have_v6_break = 1;
550 0 : in_v6_break = 1;
551 0 : tp[0] = ':';
552 0 : tp++;
553 0 : } else if (!in_v6_break) {
554 0 : tp[0] = ':';
555 0 : tp++;
556 0 : tp[0] = '0';
557 0 : tp++;
558 : }
559 : }
560 : }
561 0 : if (have_v6_break && in_v6_break) {
562 0 : tp[0] = ':';
563 0 : tp++;
564 : }
565 0 : tp[0] = '\0';
566 0 : add_assoc_string(*subarray, "type", "AAAA", 1);
567 0 : add_assoc_string(*subarray, "ipv6", name, 1);
568 0 : break;
569 : case DNS_T_A6:
570 0 : p = cp;
571 0 : add_assoc_string(*subarray, "type", "A6", 1);
572 0 : n = ((int)cp[0]) & 0xFF;
573 0 : cp++;
574 0 : add_assoc_long(*subarray, "masklen", n);
575 0 : tp = (u_char*)name;
576 0 : if (n > 15) {
577 0 : have_v6_break = 1;
578 0 : in_v6_break = 1;
579 0 : tp[0] = ':';
580 0 : tp++;
581 : }
582 0 : if (n % 16 > 8) {
583 : /* Partial short */
584 0 : if (cp[0] != 0) {
585 0 : if (tp > (u_char *)name) {
586 0 : in_v6_break = 0;
587 0 : tp[0] = ':';
588 0 : tp++;
589 : }
590 0 : sprintf((char*)tp, "%x", cp[0] & 0xFF);
591 : } else {
592 0 : if (!have_v6_break) {
593 0 : have_v6_break = 1;
594 0 : in_v6_break = 1;
595 0 : tp[0] = ':';
596 0 : tp++;
597 0 : } else if (!in_v6_break) {
598 0 : tp[0] = ':';
599 0 : tp++;
600 0 : tp[0] = '0';
601 0 : tp++;
602 : }
603 : }
604 0 : cp++;
605 : }
606 0 : for (i = (n + 8) / 16; i < 8; i++) {
607 0 : GETSHORT(s, cp);
608 0 : if (s != 0) {
609 0 : if (tp > (u_char *)name) {
610 0 : in_v6_break = 0;
611 0 : tp[0] = ':';
612 0 : tp++;
613 : }
614 0 : tp += sprintf((char*)tp,"%x",s);
615 : } else {
616 0 : if (!have_v6_break) {
617 0 : have_v6_break = 1;
618 0 : in_v6_break = 1;
619 0 : tp[0] = ':';
620 0 : tp++;
621 0 : } else if (!in_v6_break) {
622 0 : tp[0] = ':';
623 0 : tp++;
624 0 : tp[0] = '0';
625 0 : tp++;
626 : }
627 : }
628 : }
629 0 : if (have_v6_break && in_v6_break) {
630 0 : tp[0] = ':';
631 0 : tp++;
632 : }
633 0 : tp[0] = '\0';
634 0 : add_assoc_string(*subarray, "ipv6", name, 1);
635 0 : if (cp < p + dlen) {
636 0 : n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2);
637 0 : if (n < 0) {
638 0 : return NULL;
639 : }
640 0 : cp += n;
641 0 : add_assoc_string(*subarray, "chain", name, 1);
642 : }
643 0 : break;
644 : case DNS_T_SRV:
645 0 : add_assoc_string(*subarray, "type", "SRV", 1);
646 0 : GETSHORT(n, cp);
647 0 : add_assoc_long(*subarray, "pri", n);
648 0 : GETSHORT(n, cp);
649 0 : add_assoc_long(*subarray, "weight", n);
650 0 : GETSHORT(n, cp);
651 0 : add_assoc_long(*subarray, "port", n);
652 0 : n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2);
653 0 : if (n < 0) {
654 0 : return NULL;
655 : }
656 0 : cp += n;
657 0 : add_assoc_string(*subarray, "target", name, 1);
658 0 : break;
659 : case DNS_T_NAPTR:
660 0 : add_assoc_string(*subarray, "type", "NAPTR", 1);
661 0 : GETSHORT(n, cp);
662 0 : add_assoc_long(*subarray, "order", n);
663 0 : GETSHORT(n, cp);
664 0 : add_assoc_long(*subarray, "pref", n);
665 0 : n = (cp[0] & 0xFF);
666 0 : add_assoc_stringl(*subarray, "flags", (char*)++cp, n, 1);
667 0 : cp += n;
668 0 : n = (cp[0] & 0xFF);
669 0 : add_assoc_stringl(*subarray, "services", (char*)++cp, n, 1);
670 0 : cp += n;
671 0 : n = (cp[0] & 0xFF);
672 0 : add_assoc_stringl(*subarray, "regex", (char*)++cp, n, 1);
673 0 : cp += n;
674 0 : n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2);
675 0 : if (n < 0) {
676 0 : return NULL;
677 : }
678 0 : cp += n;
679 0 : add_assoc_string(*subarray, "replacement", name, 1);
680 0 : break;
681 : default:
682 0 : cp += dlen;
683 : }
684 :
685 0 : add_assoc_string(*subarray, "class", "IN", 1);
686 0 : add_assoc_long(*subarray, "ttl", ttl);
687 :
688 0 : return cp;
689 : }
690 : /* }}} */
691 :
692 : /* {{{ proto array|false dns_get_record(string hostname [, int type[, array authns, array addtl]])
693 : Get any Resource Record corresponding to a given Internet host name */
694 : PHP_FUNCTION(dns_get_record)
695 0 : {
696 : char *hostname;
697 : int hostname_len;
698 0 : long type_param = PHP_DNS_ANY;
699 0 : zval *authns = NULL, *addtl = NULL;
700 0 : int addtl_recs = 0;
701 : int type_to_fetch;
702 : #if defined(HAVE_DNS_SEARCH)
703 : struct sockaddr_storage from;
704 : uint32_t fromsize = sizeof(from);
705 : dns_handle_t handle;
706 : #elif defined(HAVE_RES_NSEARCH)
707 : struct __res_state state;
708 0 : struct __res_state *handle = &state;
709 : #endif
710 : HEADER *hp;
711 : querybuf answer;
712 0 : u_char *cp = NULL, *end = NULL;
713 0 : int n, qd, an, ns = 0, ar = 0;
714 0 : int type, first_query = 1, store_results = 1;
715 :
716 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lzz", &hostname, &hostname_len, &type_param, &authns, &addtl) == FAILURE) {
717 0 : return;
718 : }
719 :
720 0 : if (authns) {
721 0 : zval_dtor(authns);
722 0 : array_init(authns);
723 : }
724 0 : if (addtl) {
725 0 : zval_dtor(addtl);
726 0 : array_init(addtl);
727 0 : addtl_recs = 1;
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);
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);
855 0 : if (retval != NULL) {
856 0 : add_next_index_zval(authns, retval);
857 : }
858 : }
859 : }
860 :
861 0 : if (addtl_recs && 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);
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])
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_string(mx_list, buf, 1);
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 17633 : PHP_MINIT_FUNCTION(dns) {
977 17633 : REGISTER_LONG_CONSTANT("DNS_A", PHP_DNS_A, CONST_CS | CONST_PERSISTENT);
978 17633 : REGISTER_LONG_CONSTANT("DNS_NS", PHP_DNS_NS, CONST_CS | CONST_PERSISTENT);
979 17633 : REGISTER_LONG_CONSTANT("DNS_CNAME", PHP_DNS_CNAME, CONST_CS | CONST_PERSISTENT);
980 17633 : REGISTER_LONG_CONSTANT("DNS_SOA", PHP_DNS_SOA, CONST_CS | CONST_PERSISTENT);
981 17633 : REGISTER_LONG_CONSTANT("DNS_PTR", PHP_DNS_PTR, CONST_CS | CONST_PERSISTENT);
982 17633 : REGISTER_LONG_CONSTANT("DNS_HINFO", PHP_DNS_HINFO, CONST_CS | CONST_PERSISTENT);
983 17633 : REGISTER_LONG_CONSTANT("DNS_MX", PHP_DNS_MX, CONST_CS | CONST_PERSISTENT);
984 17633 : REGISTER_LONG_CONSTANT("DNS_TXT", PHP_DNS_TXT, CONST_CS | CONST_PERSISTENT);
985 17633 : REGISTER_LONG_CONSTANT("DNS_SRV", PHP_DNS_SRV, CONST_CS | CONST_PERSISTENT);
986 17633 : REGISTER_LONG_CONSTANT("DNS_NAPTR", PHP_DNS_NAPTR, CONST_CS | CONST_PERSISTENT);
987 17633 : REGISTER_LONG_CONSTANT("DNS_AAAA", PHP_DNS_AAAA, CONST_CS | CONST_PERSISTENT);
988 17633 : REGISTER_LONG_CONSTANT("DNS_A6", PHP_DNS_A6, CONST_CS | CONST_PERSISTENT);
989 17633 : REGISTER_LONG_CONSTANT("DNS_ANY", PHP_DNS_ANY, CONST_CS | CONST_PERSISTENT);
990 17633 : REGISTER_LONG_CONSTANT("DNS_ALL", PHP_DNS_ALL, CONST_CS | CONST_PERSISTENT);
991 17633 : 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 : */
|