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