2 * Unix interface for libresolv
4 * Copyright 2021 Hans Leidekker for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include <sys/types.h>
34 #ifdef HAVE_NETINET_IN_H
35 # include <netinet/in.h>
37 #ifdef HAVE_ARPA_NAMESER_H
38 # include <arpa/nameser.h>
48 #define WIN32_NO_STATUS
58 #include "wine/debug.h"
59 #include "wine/heap.h"
62 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi
);
64 static CPTABLEINFO unix_cptable
;
65 static ULONG unix_cp
= CP_UTF8
;
67 static DWORD WINAPI
get_unix_codepage_once( RTL_RUN_ONCE
*once
, void *param
, void **context
)
69 static const WCHAR wineunixcpW
[] = { 'W','I','N','E','U','N','I','X','C','P',0 };
70 UNICODE_STRING name
, value
;
71 WCHAR value_buffer
[13];
75 RtlInitUnicodeString( &name
, wineunixcpW
);
76 value
.Buffer
= value_buffer
;
77 value
.MaximumLength
= sizeof(value_buffer
);
78 if (!RtlQueryEnvironmentVariable_U( NULL
, &name
, &value
))
79 RtlUnicodeStringToInteger( &value
, 10, &unix_cp
);
80 if (unix_cp
!= CP_UTF8
&& !NtGetNlsSectionPtr( 11, unix_cp
, NULL
, &ptr
, &size
))
81 RtlInitCodePageTable( ptr
, &unix_cptable
);
85 static BOOL
get_unix_codepage( void )
87 static RTL_RUN_ONCE once
= RTL_RUN_ONCE_INIT
;
89 return !RtlRunOnceExecuteOnce( &once
, get_unix_codepage_once
, NULL
, NULL
);
92 static DWORD
dnsapi_umbstowcs( const char *src
, WCHAR
*dst
, DWORD dstlen
)
94 DWORD srclen
= strlen( src
) + 1;
99 if (unix_cp
== CP_UTF8
)
101 RtlUTF8ToUnicodeN( dst
, dstlen
, &len
, src
, srclen
);
106 len
= srclen
* sizeof(WCHAR
);
107 if (dst
) RtlCustomCPToUnicodeN( &unix_cptable
, dst
, dstlen
, &len
, src
, srclen
);
112 static const char *debugstr_type( unsigned short type
)
118 #define X(x) case (x): str = #x; break;
177 return wine_dbg_sprintf( "0x%04x", type
);
180 return wine_dbg_sprintf( "%s", str
);
183 static const char *debugstr_section( ns_sect section
)
187 case ns_s_qd
: return "Question";
188 case ns_s_an
: return "Answer";
189 case ns_s_ns
: return "Authority";
190 case ns_s_ar
: return "Additional";
192 return wine_dbg_sprintf( "0x%02x", section
);
196 /* call res_init() just once because of a bug in Mac OS X 10.4 */
197 /* call once per thread on systems that have per-thread _res */
198 static void init_resolver( void )
200 if (!(_res
.options
& RES_INIT
)) res_init();
203 static unsigned long map_options( DWORD options
)
205 unsigned long ret
= 0;
207 if (options
== DNS_QUERY_STANDARD
)
210 if (options
& DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE
)
212 if (options
& DNS_QUERY_USE_TCP_ONLY
)
214 if (options
& DNS_QUERY_NO_RECURSION
)
216 if (options
& DNS_QUERY_NO_LOCAL_NAME
)
218 if (options
& DNS_QUERY_NO_HOSTS_FILE
)
219 ret
|= RES_NOALIASES
;
220 if (options
& DNS_QUERY_TREAT_AS_FQDN
)
221 ret
&= ~RES_DEFNAMES
;
223 if (options
& DNS_QUERY_DONT_RESET_TTL_VALUES
)
224 FIXME( "option DNS_QUERY_DONT_RESET_TTL_VALUES not implemented\n" );
225 if (options
& DNS_QUERY_RESERVED
)
226 FIXME( "option DNS_QUERY_RESERVED not implemented\n" );
227 if (options
& DNS_QUERY_WIRE_ONLY
)
228 FIXME( "option DNS_QUERY_WIRE_ONLY not implemented\n" );
229 if (options
& DNS_QUERY_NO_WIRE_QUERY
)
230 FIXME( "option DNS_QUERY_NO_WIRE_QUERY not implemented\n" );
231 if (options
& DNS_QUERY_BYPASS_CACHE
)
232 FIXME( "option DNS_QUERY_BYPASS_CACHE not implemented\n" );
233 if (options
& DNS_QUERY_RETURN_MESSAGE
)
234 FIXME( "option DNS_QUERY_RETURN_MESSAGE not implemented\n" );
236 if (options
& DNS_QUERY_NO_NETBT
)
237 TRACE( "netbios query disabled\n" );
242 static DNS_STATUS
map_error( int error
)
246 case ns_r_noerror
: return ERROR_SUCCESS
;
247 case ns_r_formerr
: return DNS_ERROR_RCODE_FORMAT_ERROR
;
248 case ns_r_servfail
: return DNS_ERROR_RCODE_SERVER_FAILURE
;
249 case ns_r_nxdomain
: return DNS_ERROR_RCODE_NAME_ERROR
;
250 case ns_r_notimpl
: return DNS_ERROR_RCODE_NOT_IMPLEMENTED
;
251 case ns_r_refused
: return DNS_ERROR_RCODE_REFUSED
;
252 case ns_r_yxdomain
: return DNS_ERROR_RCODE_YXDOMAIN
;
253 case ns_r_yxrrset
: return DNS_ERROR_RCODE_YXRRSET
;
254 case ns_r_nxrrset
: return DNS_ERROR_RCODE_NXRRSET
;
255 case ns_r_notauth
: return DNS_ERROR_RCODE_NOTAUTH
;
256 case ns_r_notzone
: return DNS_ERROR_RCODE_NOTZONE
;
258 FIXME( "unmapped error code: %d\n", error
);
259 return DNS_ERROR_RCODE_NOT_IMPLEMENTED
;
263 static DNS_STATUS
map_h_errno( int error
)
268 case HOST_NOT_FOUND
: return DNS_ERROR_RCODE_NAME_ERROR
;
269 case TRY_AGAIN
: return DNS_ERROR_RCODE_SERVER_FAILURE
;
270 case NO_RECOVERY
: return DNS_ERROR_RCODE_REFUSED
;
271 #ifdef NETDB_INTERNAL
272 case NETDB_INTERNAL
: return DNS_ERROR_RCODE
;
275 FIXME( "unmapped error code: %d\n", error
);
276 return DNS_ERROR_RCODE_NOT_IMPLEMENTED
;
280 DNS_STATUS CDECL
resolv_get_searchlist( DNS_TXT_DATAW
*list
, DWORD
*len
)
282 DWORD i
, needed
, str_needed
= 0;
287 for (i
= 0; i
< MAXDNSRCH
+ 1 && _res
.dnsrch
[i
]; i
++)
288 str_needed
+= dnsapi_umbstowcs( _res
.dnsrch
[i
], NULL
, 0 );
290 needed
= FIELD_OFFSET(DNS_TXT_DATAW
, pStringArray
[i
]) + str_needed
;
292 if (!list
|| *len
< needed
)
295 return !list
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
299 list
->dwStringCount
= i
;
301 ptr
= (char *)(list
->pStringArray
+ i
);
302 end
= ptr
+ str_needed
;
303 for (i
= 0; i
< MAXDNSRCH
+ 1 && _res
.dnsrch
[i
]; i
++)
305 list
->pStringArray
[i
] = (WCHAR
*)ptr
;
306 ptr
+= dnsapi_umbstowcs( _res
.dnsrch
[i
], list
->pStringArray
[i
], end
- ptr
);
308 return ERROR_SUCCESS
;
312 static inline int filter( unsigned short sin_family
, USHORT family
)
314 if (sin_family
!= AF_INET
&& sin_family
!= AF_INET6
) return TRUE
;
315 if (sin_family
== AF_INET6
&& family
== WS_AF_INET
) return TRUE
;
316 if (sin_family
== AF_INET
&& family
== WS_AF_INET6
) return TRUE
;
321 #ifdef HAVE_RES_GETSERVERS
323 DNS_STATUS CDECL
resolv_get_serverlist( USHORT family
, DNS_ADDR_ARRAY
*addrs
, DWORD
*len
)
325 struct __res_state
*state
= &_res
;
326 DWORD i
, found
, total
, needed
;
327 union res_sockaddr_union
*buf
;
331 total
= res_getservers( state
, NULL
, 0 );
332 if (!total
) return DNS_ERROR_NO_DNS_SERVERS
;
334 if (!addrs
&& family
!= WS_AF_INET
&& family
!= WS_AF_INET6
)
336 *len
= FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[total
]);
337 return ERROR_SUCCESS
;
340 buf
= malloc( total
* sizeof(union res_sockaddr_union
) );
341 if (!buf
) return ERROR_NOT_ENOUGH_MEMORY
;
343 total
= res_getservers( state
, buf
, total
);
345 for (i
= 0, found
= 0; i
< total
; i
++)
347 if (filter( buf
[i
].sin
.sin_family
, family
)) continue;
350 if (!found
) return DNS_ERROR_NO_DNS_SERVERS
;
352 needed
= FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[found
]);
353 if (!addrs
|| *len
< needed
)
356 return !addrs
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
359 memset( addrs
, 0, needed
);
360 addrs
->AddrCount
= addrs
->MaxCount
= found
;
362 for (i
= 0, found
= 0; i
< total
; i
++)
364 if (filter( buf
[i
].sin
.sin_family
, family
)) continue;
366 if (buf
[i
].sin6
.sin6_family
== AF_INET6
)
368 SOCKADDR_IN6
*sa
= (SOCKADDR_IN6
*)addrs
->AddrArray
[found
].MaxSa
;
369 sa
->sin6_family
= WS_AF_INET6
;
370 memcpy( &sa
->sin6_addr
, &buf
[i
].sin6
.sin6_addr
, sizeof(sa
->sin6_addr
) );
371 addrs
->AddrArray
[found
].Data
.DnsAddrUserDword
[0] = sizeof(*sa
);
375 SOCKADDR_IN
*sa
= (SOCKADDR_IN
*)addrs
->AddrArray
[found
].MaxSa
;
376 sa
->sin_family
= WS_AF_INET
;
377 sa
->sin_addr
.WS_s_addr
= buf
[i
].sin
.sin_addr
.s_addr
;
378 addrs
->AddrArray
[found
].Data
.DnsAddrUserDword
[0] = sizeof(*sa
);
384 return ERROR_SUCCESS
;
389 DNS_STATUS CDECL
resolv_get_serverlist( USHORT family
, DNS_ADDR_ARRAY
*addrs
, DWORD
*len
)
391 DWORD needed
, found
, i
;
395 if (!_res
.nscount
) return DNS_ERROR_NO_DNS_SERVERS
;
396 if (!addrs
&& family
!= WS_AF_INET
&& family
!= WS_AF_INET6
)
398 *len
= FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[_res
.nscount
]);
399 return ERROR_SUCCESS
;
402 for (i
= 0, found
= 0; i
< _res
.nscount
; i
++)
404 unsigned short sin_family
= AF_INET
;
405 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
406 if (_res
._u
._ext
.nsaddrs
[i
]) sin_family
= _res
._u
._ext
.nsaddrs
[i
]->sin6_family
;
408 if (filter( sin_family
, family
)) continue;
411 if (!found
) return DNS_ERROR_NO_DNS_SERVERS
;
413 needed
= FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[found
]);
414 if (!addrs
|| *len
< needed
)
417 return !addrs
? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
420 memset( addrs
, 0, needed
);
421 addrs
->AddrCount
= addrs
->MaxCount
= found
;
423 for (i
= 0, found
= 0; i
< _res
.nscount
; i
++)
425 unsigned short sin_family
= AF_INET
;
426 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
427 if (_res
._u
._ext
.nsaddrs
[i
]) sin_family
= _res
._u
._ext
.nsaddrs
[i
]->sin6_family
;
429 if (filter( sin_family
, family
)) continue;
431 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
432 if (sin_family
== AF_INET6
)
434 SOCKADDR_IN6
*sa
= (SOCKADDR_IN6
*)addrs
->AddrArray
[found
].MaxSa
;
435 sa
->sin6_family
= WS_AF_INET6
;
436 memcpy( &sa
->sin6_addr
, &_res
._u
._ext
.nsaddrs
[i
]->sin6_addr
, sizeof(sa
->sin6_addr
) );
437 addrs
->AddrArray
[found
].Data
.DnsAddrUserDword
[0] = sizeof(*sa
);
442 SOCKADDR_IN
*sa
= (SOCKADDR_IN
*)addrs
->AddrArray
[found
].MaxSa
;
443 sa
->sin_family
= WS_AF_INET
;
444 sa
->sin_addr
.WS_s_addr
= _res
.nsaddr_list
[i
].sin_addr
.s_addr
;
445 addrs
->AddrArray
[found
].Data
.DnsAddrUserDword
[0] = sizeof(*sa
);
450 return ERROR_SUCCESS
;
454 DNS_STATUS CDECL
resolv_set_serverlist( const IP4_ARRAY
*addrs
)
460 if (!addrs
|| !addrs
->AddrCount
) return ERROR_SUCCESS
;
461 if (addrs
->AddrCount
> MAXNS
)
463 WARN( "too many servers: %d only using the first: %d\n",
464 addrs
->AddrCount
, MAXNS
);
465 _res
.nscount
= MAXNS
;
467 else _res
.nscount
= addrs
->AddrCount
;
469 for (i
= 0; i
< _res
.nscount
; i
++)
470 _res
.nsaddr_list
[i
].sin_addr
.s_addr
= addrs
->AddrArray
[i
];
472 return ERROR_SUCCESS
;
475 static char *dname_from_msg( ns_msg msg
, const unsigned char *pos
)
477 char *str
, dname
[NS_MAXDNAME
] = ".";
479 /* returns *compressed* length, ignore it */
480 ns_name_uncompress( ns_msg_base(msg
), ns_msg_end(msg
), pos
, dname
, sizeof(dname
) );
482 if ((str
= RtlAllocateHeap( GetProcessHeap(), 0, strlen(dname
) + 1 ))) strcpy( str
, dname
);
486 static char *str_from_rdata( const unsigned char *rdata
)
489 unsigned int len
= rdata
[0];
491 if ((str
= RtlAllocateHeap( GetProcessHeap(), 0, len
+ 1 )))
493 memcpy( str
, ++rdata
, len
);
499 static unsigned int get_record_size( const ns_rr
*rr
)
501 const unsigned char *pos
= rr
->rdata
;
502 unsigned int num
= 0, size
= sizeof(DNS_RECORDA
);
508 pos
+= sizeof(WORD
) + sizeof(BYTE
) + sizeof(BYTE
);
509 size
+= rr
->rdata
+ rr
->rdlength
- pos
- 1;
514 pos
+= sizeof(PCHAR
) + sizeof(WORD
) + 2 * sizeof(BYTE
);
515 pos
+= 3 * sizeof(DWORD
) + 2 * sizeof(WORD
);
516 size
+= rr
->rdata
+ rr
->rdlength
- pos
- 1;
524 while (pos
[0] && pos
< rr
->rdata
+ rr
->rdlength
)
529 size
+= (num
- 1) * sizeof(PCHAR
);
535 size
+= rr
->rdlength
- 1;
540 case 0xff01: /* WINS */
542 FIXME( "unhandled type: %s\n", debugstr_type( rr
->type
) );
551 static DNS_STATUS
copy_rdata( ns_msg msg
, const ns_rr
*rr
, DNS_RECORDA
*r
, WORD
*dlen
)
553 DNS_STATUS ret
= ERROR_SUCCESS
;
554 const unsigned char *pos
= rr
->rdata
;
555 unsigned int i
, size
;
561 r
->Data
.A
.IpAddress
= *(const DWORD
*)pos
;
562 *dlen
= sizeof(DNS_A_DATA
);
567 for (i
= 0; i
< sizeof(IP6_ADDRESS
)/sizeof(DWORD
); i
++)
569 r
->Data
.AAAA
.Ip6Address
.IP6Dword
[i
] = *(const DWORD
*)pos
;
570 pos
+= sizeof(DWORD
);
573 *dlen
= sizeof(DNS_AAAA_DATA
);
578 /* FIXME: byte order? */
579 r
->Data
.KEY
.wFlags
= *(const WORD
*)pos
; pos
+= sizeof(WORD
);
580 r
->Data
.KEY
.chProtocol
= *pos
++;
581 r
->Data
.KEY
.chAlgorithm
= *pos
++;
583 size
= rr
->rdata
+ rr
->rdlength
- pos
;
585 for (i
= 0; i
< size
; i
++)
586 r
->Data
.KEY
.Key
[i
] = *pos
++;
588 *dlen
= sizeof(DNS_KEY_DATA
) + (size
- 1) * sizeof(BYTE
);
594 r
->Data
.MINFO
.pNameMailbox
= dname_from_msg( msg
, pos
);
595 if (!r
->Data
.MINFO
.pNameMailbox
) return ERROR_NOT_ENOUGH_MEMORY
;
597 if (ns_name_skip( &pos
, ns_msg_end( msg
) ) < 0)
598 return DNS_ERROR_BAD_PACKET
;
600 r
->Data
.MINFO
.pNameErrorsMailbox
= dname_from_msg( msg
, pos
);
601 if (!r
->Data
.MINFO
.pNameErrorsMailbox
)
603 RtlFreeHeap( GetProcessHeap(), 0, r
->Data
.MINFO
.pNameMailbox
);
604 return ERROR_NOT_ENOUGH_MEMORY
;
607 *dlen
= sizeof(DNS_MINFO_DATAA
);
614 r
->Data
.MX
.wPreference
= ntohs( *(const WORD
*)pos
);
615 r
->Data
.MX
.pNameExchange
= dname_from_msg( msg
, pos
+ sizeof(WORD
) );
616 if (!r
->Data
.MX
.pNameExchange
) return ERROR_NOT_ENOUGH_MEMORY
;
618 *dlen
= sizeof(DNS_MX_DATAA
);
623 r
->Data
.Null
.dwByteCount
= rr
->rdlength
;
624 memcpy( r
->Data
.Null
.Data
, rr
->rdata
, rr
->rdlength
);
626 *dlen
= sizeof(DNS_NULL_DATA
) + rr
->rdlength
- 1;
631 r
->Data
.OPT
.wDataLength
= rr
->rdlength
;
632 r
->Data
.OPT
.wPad
= 0;
633 memcpy( r
->Data
.OPT
.Data
, rr
->rdata
, rr
->rdlength
);
635 *dlen
= sizeof(DNS_OPT_DATA
) + rr
->rdlength
- 1;
647 r
->Data
.PTR
.pNameHost
= dname_from_msg( msg
, pos
);
648 if (!r
->Data
.PTR
.pNameHost
) return ERROR_NOT_ENOUGH_MEMORY
;
650 *dlen
= sizeof(DNS_PTR_DATAA
);
655 r
->Data
.SIG
.pNameSigner
= dname_from_msg( msg
, pos
);
656 if (!r
->Data
.SIG
.pNameSigner
) return ERROR_NOT_ENOUGH_MEMORY
;
658 if (ns_name_skip( &pos
, ns_msg_end( msg
) ) < 0)
659 return DNS_ERROR_BAD_PACKET
;
661 /* FIXME: byte order? */
662 r
->Data
.SIG
.wTypeCovered
= *(const WORD
*)pos
; pos
+= sizeof(WORD
);
663 r
->Data
.SIG
.chAlgorithm
= *pos
++;
664 r
->Data
.SIG
.chLabelCount
= *pos
++;
665 r
->Data
.SIG
.dwOriginalTtl
= *(const DWORD
*)pos
; pos
+= sizeof(DWORD
);
666 r
->Data
.SIG
.dwExpiration
= *(const DWORD
*)pos
; pos
+= sizeof(DWORD
);
667 r
->Data
.SIG
.dwTimeSigned
= *(const DWORD
*)pos
; pos
+= sizeof(DWORD
);
668 r
->Data
.SIG
.wKeyTag
= *(const WORD
*)pos
;
670 size
= rr
->rdata
+ rr
->rdlength
- pos
;
672 for (i
= 0; i
< size
; i
++)
673 r
->Data
.SIG
.Signature
[i
] = *pos
++;
675 *dlen
= sizeof(DNS_SIG_DATAA
) + (size
- 1) * sizeof(BYTE
);
680 r
->Data
.SOA
.pNamePrimaryServer
= dname_from_msg( msg
, pos
);
681 if (!r
->Data
.SOA
.pNamePrimaryServer
) return ERROR_NOT_ENOUGH_MEMORY
;
683 if (ns_name_skip( &pos
, ns_msg_end( msg
) ) < 0)
684 return DNS_ERROR_BAD_PACKET
;
686 r
->Data
.SOA
.pNameAdministrator
= dname_from_msg( msg
, pos
);
687 if (!r
->Data
.SOA
.pNameAdministrator
)
689 RtlFreeHeap( GetProcessHeap(), 0, r
->Data
.SOA
.pNamePrimaryServer
);
690 return ERROR_NOT_ENOUGH_MEMORY
;
693 if (ns_name_skip( &pos
, ns_msg_end( msg
) ) < 0)
694 return DNS_ERROR_BAD_PACKET
;
696 r
->Data
.SOA
.dwSerialNo
= ntohl( *(const DWORD
*)pos
); pos
+= sizeof(DWORD
);
697 r
->Data
.SOA
.dwRefresh
= ntohl( *(const DWORD
*)pos
); pos
+= sizeof(DWORD
);
698 r
->Data
.SOA
.dwRetry
= ntohl( *(const DWORD
*)pos
); pos
+= sizeof(DWORD
);
699 r
->Data
.SOA
.dwExpire
= ntohl( *(const DWORD
*)pos
); pos
+= sizeof(DWORD
);
700 r
->Data
.SOA
.dwDefaultTtl
= ntohl( *(const DWORD
*)pos
); pos
+= sizeof(DWORD
);
702 *dlen
= sizeof(DNS_SOA_DATAA
);
707 r
->Data
.SRV
.wPriority
= ntohs( *(const WORD
*)pos
); pos
+= sizeof(WORD
);
708 r
->Data
.SRV
.wWeight
= ntohs( *(const WORD
*)pos
); pos
+= sizeof(WORD
);
709 r
->Data
.SRV
.wPort
= ntohs( *(const WORD
*)pos
); pos
+= sizeof(WORD
);
711 r
->Data
.SRV
.pNameTarget
= dname_from_msg( msg
, pos
);
712 if (!r
->Data
.SRV
.pNameTarget
) return ERROR_NOT_ENOUGH_MEMORY
;
714 *dlen
= sizeof(DNS_SRV_DATAA
);
723 while (pos
[0] && pos
< rr
->rdata
+ rr
->rdlength
)
725 r
->Data
.TXT
.pStringArray
[i
] = str_from_rdata( pos
);
726 if (!r
->Data
.TXT
.pStringArray
[i
])
728 while (i
> 0) RtlFreeHeap( GetProcessHeap(), 0, r
->Data
.TXT
.pStringArray
[--i
] );
729 return ERROR_NOT_ENOUGH_MEMORY
;
734 r
->Data
.TXT
.dwStringCount
= i
;
735 *dlen
= sizeof(DNS_TXT_DATAA
) + (i
- 1) * sizeof(PCHAR
);
743 case 0x00f9: /* TKEY */
744 case 0xff01: /* WINS */
745 case 0xff02: /* WINSR */
747 FIXME( "unhandled type: %s\n", debugstr_type( rr
->type
) );
748 return DNS_ERROR_RCODE_NOT_IMPLEMENTED
;
754 static inline char *heap_strdup( const char *src
)
757 if (!src
) return NULL
;
758 if ((dst
= RtlAllocateHeap( GetProcessHeap(), 0, (strlen( src
) + 1) * sizeof(char) ))) strcpy( dst
, src
);
762 static DNS_STATUS
copy_record( ns_msg msg
, ns_sect section
, unsigned short num
, DNS_RECORDA
**recp
)
769 if (ns_parserr( &msg
, section
, num
, &rr
) < 0)
770 return DNS_ERROR_BAD_PACKET
;
772 if (!(record
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, get_record_size( &rr
) )))
773 return ERROR_NOT_ENOUGH_MEMORY
;
775 if (!(record
->pName
= heap_strdup( rr
.name
)))
777 RtlFreeHeap( GetProcessHeap(), 0, record
);
778 return ERROR_NOT_ENOUGH_MEMORY
;
781 record
->wType
= rr
.type
;
782 record
->Flags
.S
.Section
= section
;
783 record
->Flags
.S
.CharSet
= DnsCharSetUtf8
;
784 record
->dwTtl
= rr
.ttl
;
786 if ((ret
= copy_rdata( msg
, &rr
, record
, &dlen
)))
788 RtlFreeHeap( GetProcessHeap(), 0, record
->pName
);
789 RtlFreeHeap( GetProcessHeap(), 0, record
);
792 record
->wDataLength
= dlen
;
795 TRACE( "found %s record in %s section\n", debugstr_type( rr
.type
), debugstr_section( section
) );
796 return ERROR_SUCCESS
;
799 static void free_record_list( DNS_RECORD
*list
)
801 DNS_RECORD
*r
, *next
;
804 for (r
= list
; (list
= r
); r
= next
)
806 RtlFreeHeap( GetProcessHeap(), 0, r
->pName
);
815 for (i
= 0; i
< r
->Data
.TXT
.dwStringCount
; i
++)
816 RtlFreeHeap( GetProcessHeap(), 0, r
->Data
.TXT
.pStringArray
[i
] );
822 RtlFreeHeap( GetProcessHeap(), 0, r
->Data
.MINFO
.pNameMailbox
);
823 RtlFreeHeap( GetProcessHeap(), 0, r
->Data
.MINFO
.pNameErrorsMailbox
);
830 RtlFreeHeap( GetProcessHeap(), 0, r
->Data
.MX
.pNameExchange
);
835 RtlFreeHeap( GetProcessHeap(), 0, r
->Data
.NXT
.pNameNext
);
847 RtlFreeHeap( GetProcessHeap(), 0, r
->Data
.PTR
.pNameHost
);
852 RtlFreeHeap( GetProcessHeap(), 0, r
->Data
.SIG
.pNameSigner
);
857 RtlFreeHeap( GetProcessHeap(), 0, r
->Data
.SOA
.pNamePrimaryServer
);
858 RtlFreeHeap( GetProcessHeap(), 0, r
->Data
.SOA
.pNameAdministrator
);
863 RtlFreeHeap( GetProcessHeap(), 0, r
->Data
.SRV
.pNameTarget
);
870 RtlFreeHeap( GetProcessHeap(), 0, r
);
874 #define DNS_MAX_PACKET_SIZE 4096
875 DNS_STATUS CDECL
resolv_query( const char *name
, WORD type
, DWORD options
, DNS_RECORDA
**result
)
877 DNS_STATUS ret
= DNS_ERROR_RCODE_NOT_IMPLEMENTED
;
879 unsigned char answer
[DNS_MAX_PACKET_SIZE
];
880 ns_sect sections
[] = { ns_s_an
, ns_s_ar
};
882 DNS_RECORDA
*record
= NULL
;
886 DNS_RRSET_INIT( rrset
);
889 _res
.options
|= map_options( options
);
891 if ((len
= res_query( name
, ns_c_in
, type
, answer
, sizeof(answer
) )) < 0)
893 ret
= map_h_errno( h_errno
);
897 if (ns_initparse( answer
, len
, &msg
) < 0)
899 ret
= DNS_ERROR_BAD_PACKET
;
903 #define RCODE_MASK 0x0f
904 if ((msg
._flags
& RCODE_MASK
) != ns_r_noerror
)
906 ret
= map_error( msg
._flags
& RCODE_MASK
);
910 for (i
= 0; i
< ARRAY_SIZE(sections
); i
++)
912 for (num
= 0; num
< ns_msg_count( msg
, sections
[i
] ); num
++)
914 ret
= copy_record( msg
, sections
[i
], num
, &record
);
915 if (ret
!= ERROR_SUCCESS
) goto exit
;
917 DNS_RRSET_ADD( rrset
, (DNS_RECORD
*)record
);
922 DNS_RRSET_TERMINATE( rrset
);
924 if (ret
!= ERROR_SUCCESS
)
925 free_record_list( rrset
.pFirstRR
);
927 *result
= (DNS_RECORDA
*)rrset
.pFirstRR
;
932 static const struct resolv_funcs funcs
=
934 resolv_get_searchlist
,
935 resolv_get_serverlist
,
937 resolv_set_serverlist
940 NTSTATUS CDECL
__wine_init_unix_lib( HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
942 if (reason
!= DLL_PROCESS_ATTACH
) return STATUS_SUCCESS
;
943 *(const struct resolv_funcs
**)ptr_out
= &funcs
;
944 return STATUS_SUCCESS
;
947 #endif /* HAVE_RESOLV */