mf/session: Forward more events to the application.
[wine/zf.git] / dlls / dnsapi / libresolv.c
blobac52147af01ba174a5d2b7e999accde8cfd6ac32
1 /*
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
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
27 #ifdef HAVE_RESOLV
28 #include <stdarg.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <sys/types.h>
33 #ifdef HAVE_NETINET_IN_H
34 # include <netinet/in.h>
35 #endif
36 #ifdef HAVE_ARPA_NAMESER_H
37 # include <arpa/nameser.h>
38 #endif
39 #ifdef HAVE_RESOLV_H
40 # include <resolv.h>
41 #endif
42 #ifdef HAVE_NETDB_H
43 # include <netdb.h>
44 #endif
46 #include "ntstatus.h"
47 #define WIN32_NO_STATUS
48 #include "windef.h"
49 #include "winternl.h"
50 #include "winbase.h"
51 #include "winnls.h"
52 #include "windns.h"
54 #include "wine/debug.h"
55 #include "wine/heap.h"
56 #include "dnsapi.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi);
60 static const char *debugstr_type( unsigned short type )
62 const char *str;
64 switch (type)
66 #define X(x) case (x): str = #x; break;
67 X(DNS_TYPE_ZERO)
68 X(DNS_TYPE_A)
69 X(DNS_TYPE_NS)
70 X(DNS_TYPE_MD)
71 X(DNS_TYPE_MF)
72 X(DNS_TYPE_CNAME)
73 X(DNS_TYPE_SOA)
74 X(DNS_TYPE_MB)
75 X(DNS_TYPE_MG)
76 X(DNS_TYPE_MR)
77 X(DNS_TYPE_NULL)
78 X(DNS_TYPE_WKS)
79 X(DNS_TYPE_PTR)
80 X(DNS_TYPE_HINFO)
81 X(DNS_TYPE_MINFO)
82 X(DNS_TYPE_MX)
83 X(DNS_TYPE_TEXT)
84 X(DNS_TYPE_RP)
85 X(DNS_TYPE_AFSDB)
86 X(DNS_TYPE_X25)
87 X(DNS_TYPE_ISDN)
88 X(DNS_TYPE_RT)
89 X(DNS_TYPE_NSAP)
90 X(DNS_TYPE_NSAPPTR)
91 X(DNS_TYPE_SIG)
92 X(DNS_TYPE_KEY)
93 X(DNS_TYPE_PX)
94 X(DNS_TYPE_GPOS)
95 X(DNS_TYPE_AAAA)
96 X(DNS_TYPE_LOC)
97 X(DNS_TYPE_NXT)
98 X(DNS_TYPE_EID)
99 X(DNS_TYPE_NIMLOC)
100 X(DNS_TYPE_SRV)
101 X(DNS_TYPE_ATMA)
102 X(DNS_TYPE_NAPTR)
103 X(DNS_TYPE_KX)
104 X(DNS_TYPE_CERT)
105 X(DNS_TYPE_A6)
106 X(DNS_TYPE_DNAME)
107 X(DNS_TYPE_SINK)
108 X(DNS_TYPE_OPT)
109 X(DNS_TYPE_UINFO)
110 X(DNS_TYPE_UID)
111 X(DNS_TYPE_GID)
112 X(DNS_TYPE_UNSPEC)
113 X(DNS_TYPE_ADDRS)
114 X(DNS_TYPE_TKEY)
115 X(DNS_TYPE_TSIG)
116 X(DNS_TYPE_IXFR)
117 X(DNS_TYPE_AXFR)
118 X(DNS_TYPE_MAILB)
119 X(DNS_TYPE_MAILA)
120 X(DNS_TYPE_ANY)
121 X(DNS_TYPE_WINS)
122 X(DNS_TYPE_WINSR)
123 #undef X
124 default:
125 return wine_dbg_sprintf( "0x%04x", type );
128 return wine_dbg_sprintf( "%s", str );
131 static const char *debugstr_section( ns_sect section )
133 switch (section)
135 case ns_s_qd: return "Question";
136 case ns_s_an: return "Answer";
137 case ns_s_ns: return "Authority";
138 case ns_s_ar: return "Additional";
139 default:
140 return wine_dbg_sprintf( "0x%02x", section );
144 /* call res_init() just once because of a bug in Mac OS X 10.4 */
145 /* call once per thread on systems that have per-thread _res */
146 static void init_resolver( void )
148 if (!(_res.options & RES_INIT)) res_init();
151 static unsigned long map_options( DWORD options )
153 unsigned long ret = 0;
155 if (options == DNS_QUERY_STANDARD)
156 return RES_DEFAULT;
158 if (options & DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE)
159 ret |= RES_IGNTC;
160 if (options & DNS_QUERY_USE_TCP_ONLY)
161 ret |= RES_USEVC;
162 if (options & DNS_QUERY_NO_RECURSION)
163 ret &= ~RES_RECURSE;
164 if (options & DNS_QUERY_NO_LOCAL_NAME)
165 ret &= ~RES_DNSRCH;
166 if (options & DNS_QUERY_NO_HOSTS_FILE)
167 ret |= RES_NOALIASES;
168 if (options & DNS_QUERY_TREAT_AS_FQDN)
169 ret &= ~RES_DEFNAMES;
171 if (options & DNS_QUERY_DONT_RESET_TTL_VALUES)
172 FIXME( "option DNS_QUERY_DONT_RESET_TTL_VALUES not implemented\n" );
173 if (options & DNS_QUERY_RESERVED)
174 FIXME( "option DNS_QUERY_RESERVED not implemented\n" );
175 if (options & DNS_QUERY_WIRE_ONLY)
176 FIXME( "option DNS_QUERY_WIRE_ONLY not implemented\n" );
177 if (options & DNS_QUERY_NO_WIRE_QUERY)
178 FIXME( "option DNS_QUERY_NO_WIRE_QUERY not implemented\n" );
179 if (options & DNS_QUERY_BYPASS_CACHE)
180 FIXME( "option DNS_QUERY_BYPASS_CACHE not implemented\n" );
181 if (options & DNS_QUERY_RETURN_MESSAGE)
182 FIXME( "option DNS_QUERY_RETURN_MESSAGE not implemented\n" );
184 if (options & DNS_QUERY_NO_NETBT)
185 TRACE( "netbios query disabled\n" );
187 return ret;
190 static DNS_STATUS map_error( int error )
192 switch (error)
194 case ns_r_noerror: return ERROR_SUCCESS;
195 case ns_r_formerr: return DNS_ERROR_RCODE_FORMAT_ERROR;
196 case ns_r_servfail: return DNS_ERROR_RCODE_SERVER_FAILURE;
197 case ns_r_nxdomain: return DNS_ERROR_RCODE_NAME_ERROR;
198 case ns_r_notimpl: return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
199 case ns_r_refused: return DNS_ERROR_RCODE_REFUSED;
200 case ns_r_yxdomain: return DNS_ERROR_RCODE_YXDOMAIN;
201 case ns_r_yxrrset: return DNS_ERROR_RCODE_YXRRSET;
202 case ns_r_nxrrset: return DNS_ERROR_RCODE_NXRRSET;
203 case ns_r_notauth: return DNS_ERROR_RCODE_NOTAUTH;
204 case ns_r_notzone: return DNS_ERROR_RCODE_NOTZONE;
205 default:
206 FIXME( "unmapped error code: %d\n", error );
207 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
211 static DNS_STATUS map_h_errno( int error )
213 switch (error)
215 case NO_DATA:
216 case HOST_NOT_FOUND: return DNS_ERROR_RCODE_NAME_ERROR;
217 case TRY_AGAIN: return DNS_ERROR_RCODE_SERVER_FAILURE;
218 case NO_RECOVERY: return DNS_ERROR_RCODE_REFUSED;
219 #ifdef NETDB_INTERNAL
220 case NETDB_INTERNAL: return DNS_ERROR_RCODE;
221 #endif
222 default:
223 FIXME( "unmapped error code: %d\n", error );
224 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
228 DNS_STATUS CDECL resolv_get_serverlist( IP4_ARRAY *addrs, DWORD *len )
230 unsigned int size;
231 int i;
233 init_resolver();
235 size = FIELD_OFFSET(IP4_ARRAY, AddrArray[_res.nscount]);
236 if (!addrs || *len < size)
238 *len = size;
239 return ERROR_INSUFFICIENT_BUFFER;
242 addrs->AddrCount = _res.nscount;
244 for (i = 0; i < _res.nscount; i++)
245 addrs->AddrArray[i] = _res.nsaddr_list[i].sin_addr.s_addr;
247 return ERROR_SUCCESS;
250 DNS_STATUS CDECL resolv_set_serverlist( const IP4_ARRAY *addrs )
252 int i;
254 init_resolver();
256 if (!addrs || !addrs->AddrCount) return ERROR_SUCCESS;
257 if (addrs->AddrCount > MAXNS)
259 WARN( "too many servers: %d only using the first: %d\n",
260 addrs->AddrCount, MAXNS );
261 _res.nscount = MAXNS;
263 else _res.nscount = addrs->AddrCount;
265 for (i = 0; i < _res.nscount; i++)
266 _res.nsaddr_list[i].sin_addr.s_addr = addrs->AddrArray[i];
268 return ERROR_SUCCESS;
271 static char *dname_from_msg( ns_msg msg, const unsigned char *pos )
273 char *str, dname[NS_MAXDNAME] = ".";
275 /* returns *compressed* length, ignore it */
276 ns_name_uncompress( ns_msg_base(msg), ns_msg_end(msg), pos, dname, sizeof(dname) );
278 if ((str = RtlAllocateHeap( GetProcessHeap(), 0, strlen(dname) + 1 ))) strcpy( str, dname );
279 return str;
282 static char *str_from_rdata( const unsigned char *rdata )
284 char *str;
285 unsigned int len = rdata[0];
287 if ((str = RtlAllocateHeap( GetProcessHeap(), 0, len + 1 )))
289 memcpy( str, ++rdata, len );
290 str[len] = 0;
292 return str;
295 static unsigned int get_record_size( const ns_rr *rr )
297 const unsigned char *pos = rr->rdata;
298 unsigned int num = 0, size = sizeof(DNS_RECORDA);
300 switch (rr->type)
302 case ns_t_key:
304 pos += sizeof(WORD) + sizeof(BYTE) + sizeof(BYTE);
305 size += rr->rdata + rr->rdlength - pos - 1;
306 break;
308 case ns_t_sig:
310 pos += sizeof(PCHAR) + sizeof(WORD) + 2 * sizeof(BYTE);
311 pos += 3 * sizeof(DWORD) + 2 * sizeof(WORD);
312 size += rr->rdata + rr->rdlength - pos - 1;
313 break;
315 case ns_t_hinfo:
316 case ns_t_isdn:
317 case ns_t_txt:
318 case ns_t_x25:
320 while (pos[0] && pos < rr->rdata + rr->rdlength)
322 num++;
323 pos += pos[0] + 1;
325 size += (num - 1) * sizeof(PCHAR);
326 break;
328 case ns_t_null:
329 case ns_t_opt:
331 size += rr->rdlength - 1;
332 break;
334 case ns_t_nxt:
335 case ns_t_wks:
336 case 0xff01: /* WINS */
338 FIXME( "unhandled type: %s\n", debugstr_type( rr->type ) );
339 break;
341 default:
342 break;
344 return size;
347 static DNS_STATUS copy_rdata( ns_msg msg, const ns_rr *rr, DNS_RECORDA *r, WORD *dlen )
349 DNS_STATUS ret = ERROR_SUCCESS;
350 const unsigned char *pos = rr->rdata;
351 unsigned int i, size;
353 switch (rr->type)
355 case ns_t_a:
357 r->Data.A.IpAddress = *(const DWORD *)pos;
358 *dlen = sizeof(DNS_A_DATA);
359 break;
361 case ns_t_aaaa:
363 for (i = 0; i < sizeof(IP6_ADDRESS)/sizeof(DWORD); i++)
365 r->Data.AAAA.Ip6Address.IP6Dword[i] = *(const DWORD *)pos;
366 pos += sizeof(DWORD);
369 *dlen = sizeof(DNS_AAAA_DATA);
370 break;
372 case ns_t_key:
374 /* FIXME: byte order? */
375 r->Data.KEY.wFlags = *(const WORD *)pos; pos += sizeof(WORD);
376 r->Data.KEY.chProtocol = *pos++;
377 r->Data.KEY.chAlgorithm = *pos++;
379 size = rr->rdata + rr->rdlength - pos;
381 for (i = 0; i < size; i++)
382 r->Data.KEY.Key[i] = *pos++;
384 *dlen = sizeof(DNS_KEY_DATA) + (size - 1) * sizeof(BYTE);
385 break;
387 case ns_t_rp:
388 case ns_t_minfo:
390 r->Data.MINFO.pNameMailbox = dname_from_msg( msg, pos );
391 if (!r->Data.MINFO.pNameMailbox) return ERROR_NOT_ENOUGH_MEMORY;
393 if (ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
394 return DNS_ERROR_BAD_PACKET;
396 r->Data.MINFO.pNameErrorsMailbox = dname_from_msg( msg, pos );
397 if (!r->Data.MINFO.pNameErrorsMailbox)
399 RtlFreeHeap( GetProcessHeap(), 0, r->Data.MINFO.pNameMailbox );
400 return ERROR_NOT_ENOUGH_MEMORY;
403 *dlen = sizeof(DNS_MINFO_DATAA);
404 break;
406 case ns_t_afsdb:
407 case ns_t_rt:
408 case ns_t_mx:
410 r->Data.MX.wPreference = ntohs( *(const WORD *)pos );
411 r->Data.MX.pNameExchange = dname_from_msg( msg, pos + sizeof(WORD) );
412 if (!r->Data.MX.pNameExchange) return ERROR_NOT_ENOUGH_MEMORY;
414 *dlen = sizeof(DNS_MX_DATAA);
415 break;
417 case ns_t_null:
419 r->Data.Null.dwByteCount = rr->rdlength;
420 memcpy( r->Data.Null.Data, rr->rdata, rr->rdlength );
422 *dlen = sizeof(DNS_NULL_DATA) + rr->rdlength - 1;
423 break;
425 case ns_t_opt:
427 r->Data.OPT.wDataLength = rr->rdlength;
428 r->Data.OPT.wPad = 0;
429 memcpy( r->Data.OPT.Data, rr->rdata, rr->rdlength );
431 *dlen = sizeof(DNS_OPT_DATA) + rr->rdlength - 1;
432 break;
434 case ns_t_cname:
435 case ns_t_ns:
436 case ns_t_mb:
437 case ns_t_md:
438 case ns_t_mf:
439 case ns_t_mg:
440 case ns_t_mr:
441 case ns_t_ptr:
443 r->Data.PTR.pNameHost = dname_from_msg( msg, pos );
444 if (!r->Data.PTR.pNameHost) return ERROR_NOT_ENOUGH_MEMORY;
446 *dlen = sizeof(DNS_PTR_DATAA);
447 break;
449 case ns_t_sig:
451 r->Data.SIG.pNameSigner = dname_from_msg( msg, pos );
452 if (!r->Data.SIG.pNameSigner) return ERROR_NOT_ENOUGH_MEMORY;
454 if (ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
455 return DNS_ERROR_BAD_PACKET;
457 /* FIXME: byte order? */
458 r->Data.SIG.wTypeCovered = *(const WORD *)pos; pos += sizeof(WORD);
459 r->Data.SIG.chAlgorithm = *pos++;
460 r->Data.SIG.chLabelCount = *pos++;
461 r->Data.SIG.dwOriginalTtl = *(const DWORD *)pos; pos += sizeof(DWORD);
462 r->Data.SIG.dwExpiration = *(const DWORD *)pos; pos += sizeof(DWORD);
463 r->Data.SIG.dwTimeSigned = *(const DWORD *)pos; pos += sizeof(DWORD);
464 r->Data.SIG.wKeyTag = *(const WORD *)pos;
466 size = rr->rdata + rr->rdlength - pos;
468 for (i = 0; i < size; i++)
469 r->Data.SIG.Signature[i] = *pos++;
471 *dlen = sizeof(DNS_SIG_DATAA) + (size - 1) * sizeof(BYTE);
472 break;
474 case ns_t_soa:
476 r->Data.SOA.pNamePrimaryServer = dname_from_msg( msg, pos );
477 if (!r->Data.SOA.pNamePrimaryServer) return ERROR_NOT_ENOUGH_MEMORY;
479 if (ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
480 return DNS_ERROR_BAD_PACKET;
482 r->Data.SOA.pNameAdministrator = dname_from_msg( msg, pos );
483 if (!r->Data.SOA.pNameAdministrator)
485 RtlFreeHeap( GetProcessHeap(), 0, r->Data.SOA.pNamePrimaryServer );
486 return ERROR_NOT_ENOUGH_MEMORY;
489 if (ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
490 return DNS_ERROR_BAD_PACKET;
492 r->Data.SOA.dwSerialNo = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
493 r->Data.SOA.dwRefresh = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
494 r->Data.SOA.dwRetry = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
495 r->Data.SOA.dwExpire = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
496 r->Data.SOA.dwDefaultTtl = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
498 *dlen = sizeof(DNS_SOA_DATAA);
499 break;
501 case ns_t_srv:
503 r->Data.SRV.wPriority = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
504 r->Data.SRV.wWeight = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
505 r->Data.SRV.wPort = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
507 r->Data.SRV.pNameTarget = dname_from_msg( msg, pos );
508 if (!r->Data.SRV.pNameTarget) return ERROR_NOT_ENOUGH_MEMORY;
510 *dlen = sizeof(DNS_SRV_DATAA);
511 break;
513 case ns_t_hinfo:
514 case ns_t_isdn:
515 case ns_t_x25:
516 case ns_t_txt:
518 i = 0;
519 while (pos[0] && pos < rr->rdata + rr->rdlength)
521 r->Data.TXT.pStringArray[i] = str_from_rdata( pos );
522 if (!r->Data.TXT.pStringArray[i])
524 while (i > 0) RtlFreeHeap( GetProcessHeap(), 0, r->Data.TXT.pStringArray[--i] );
525 return ERROR_NOT_ENOUGH_MEMORY;
527 i++;
528 pos += pos[0] + 1;
530 r->Data.TXT.dwStringCount = i;
531 *dlen = sizeof(DNS_TXT_DATAA) + (i - 1) * sizeof(PCHAR);
532 break;
534 case ns_t_atma:
535 case ns_t_loc:
536 case ns_t_nxt:
537 case ns_t_tsig:
538 case ns_t_wks:
539 case 0x00f9: /* TKEY */
540 case 0xff01: /* WINS */
541 case 0xff02: /* WINSR */
542 default:
543 FIXME( "unhandled type: %s\n", debugstr_type( rr->type ) );
544 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
547 return ret;
550 static inline char *heap_strdup( const char *src )
552 char *dst;
553 if (!src) return NULL;
554 if ((dst = RtlAllocateHeap( GetProcessHeap(), 0, (strlen( src ) + 1) * sizeof(char) ))) strcpy( dst, src );
555 return dst;
558 static DNS_STATUS copy_record( ns_msg msg, ns_sect section, unsigned short num, DNS_RECORDA **recp )
560 DNS_STATUS ret;
561 DNS_RECORDA *record;
562 WORD dlen;
563 ns_rr rr;
565 if (ns_parserr( &msg, section, num, &rr ) < 0)
566 return DNS_ERROR_BAD_PACKET;
568 if (!(record = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, get_record_size( &rr ) )))
569 return ERROR_NOT_ENOUGH_MEMORY;
571 if (!(record->pName = heap_strdup( rr.name )))
573 RtlFreeHeap( GetProcessHeap(), 0, record );
574 return ERROR_NOT_ENOUGH_MEMORY;
577 record->wType = rr.type;
578 record->Flags.S.Section = section;
579 record->Flags.S.CharSet = DnsCharSetUtf8;
580 record->dwTtl = rr.ttl;
582 if ((ret = copy_rdata( msg, &rr, record, &dlen )))
584 RtlFreeHeap( GetProcessHeap(), 0, record->pName );
585 RtlFreeHeap( GetProcessHeap(), 0, record );
586 return ret;
588 record->wDataLength = dlen;
589 *recp = record;
591 TRACE( "found %s record in %s section\n", debugstr_type( rr.type ), debugstr_section( section ) );
592 return ERROR_SUCCESS;
595 static void free_record_list( DNS_RECORD *list )
597 DNS_RECORD *r, *next;
598 unsigned int i;
600 for (r = list; (list = r); r = next)
602 RtlFreeHeap( GetProcessHeap(), 0, r->pName );
604 switch (r->wType)
606 case DNS_TYPE_HINFO:
607 case DNS_TYPE_ISDN:
608 case DNS_TYPE_TEXT:
609 case DNS_TYPE_X25:
611 for (i = 0; i < r->Data.TXT.dwStringCount; i++)
612 RtlFreeHeap( GetProcessHeap(), 0, r->Data.TXT.pStringArray[i] );
613 break;
615 case DNS_TYPE_MINFO:
616 case DNS_TYPE_RP:
618 RtlFreeHeap( GetProcessHeap(), 0, r->Data.MINFO.pNameMailbox );
619 RtlFreeHeap( GetProcessHeap(), 0, r->Data.MINFO.pNameErrorsMailbox );
620 break;
622 case DNS_TYPE_AFSDB:
623 case DNS_TYPE_RT:
624 case DNS_TYPE_MX:
626 RtlFreeHeap( GetProcessHeap(), 0, r->Data.MX.pNameExchange );
627 break;
629 case DNS_TYPE_NXT:
631 RtlFreeHeap( GetProcessHeap(), 0, r->Data.NXT.pNameNext );
632 break;
634 case DNS_TYPE_CNAME:
635 case DNS_TYPE_MB:
636 case DNS_TYPE_MD:
637 case DNS_TYPE_MF:
638 case DNS_TYPE_MG:
639 case DNS_TYPE_MR:
640 case DNS_TYPE_NS:
641 case DNS_TYPE_PTR:
643 RtlFreeHeap( GetProcessHeap(), 0, r->Data.PTR.pNameHost );
644 break;
646 case DNS_TYPE_SIG:
648 RtlFreeHeap( GetProcessHeap(), 0, r->Data.SIG.pNameSigner );
649 break;
651 case DNS_TYPE_SOA:
653 RtlFreeHeap( GetProcessHeap(), 0, r->Data.SOA.pNamePrimaryServer );
654 RtlFreeHeap( GetProcessHeap(), 0, r->Data.SOA.pNameAdministrator );
655 break;
657 case DNS_TYPE_SRV:
659 RtlFreeHeap( GetProcessHeap(), 0, r->Data.SRV.pNameTarget );
660 break;
662 default: break;
665 next = r->pNext;
666 RtlFreeHeap( GetProcessHeap(), 0, r );
670 #define DNS_MAX_PACKET_SIZE 4096
671 DNS_STATUS CDECL resolv_query( const char *name, WORD type, DWORD options, DNS_RECORDA **result )
673 DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
674 unsigned int i, num;
675 unsigned char answer[DNS_MAX_PACKET_SIZE];
676 ns_sect sections[] = { ns_s_an, ns_s_ar };
677 ns_msg msg;
678 DNS_RECORDA *record = NULL;
679 DNS_RRSET rrset;
680 int len;
682 DNS_RRSET_INIT( rrset );
684 init_resolver();
685 _res.options |= map_options( options );
687 if ((len = res_query( name, ns_c_in, type, answer, sizeof(answer) )) < 0)
689 ret = map_h_errno( h_errno );
690 goto exit;
693 if (ns_initparse( answer, len, &msg ) < 0)
695 ret = DNS_ERROR_BAD_PACKET;
696 goto exit;
699 #define RCODE_MASK 0x0f
700 if ((msg._flags & RCODE_MASK) != ns_r_noerror)
702 ret = map_error( msg._flags & RCODE_MASK );
703 goto exit;
706 for (i = 0; i < ARRAY_SIZE(sections); i++)
708 for (num = 0; num < ns_msg_count( msg, sections[i] ); num++)
710 ret = copy_record( msg, sections[i], num, &record );
711 if (ret != ERROR_SUCCESS) goto exit;
713 DNS_RRSET_ADD( rrset, (DNS_RECORD *)record );
717 exit:
718 DNS_RRSET_TERMINATE( rrset );
720 if (ret != ERROR_SUCCESS)
721 free_record_list( rrset.pFirstRR );
722 else
723 *result = (DNS_RECORDA *)rrset.pFirstRR;
725 return ret;
728 static const struct resolv_funcs funcs =
730 resolv_get_serverlist,
731 resolv_query,
732 resolv_set_serverlist
735 NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
737 if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS;
738 *(const struct resolv_funcs **)ptr_out = &funcs;
739 return STATUS_SUCCESS;
742 #endif /* HAVE_RESOLV */