hidclass.sys: Pass sizeof(packet) as input for IOCTL_HID_SET_OUTPUT_REPORT.
[wine.git] / dlls / dnsapi / libresolv.c
blob7e545cf36fb83cba039b348d15fa58398406a402
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 <stdlib.h>
32 #include <sys/types.h>
34 #ifdef HAVE_NETINET_IN_H
35 # include <netinet/in.h>
36 #endif
37 #ifdef HAVE_ARPA_NAMESER_H
38 # include <arpa/nameser.h>
39 #endif
40 #ifdef HAVE_RESOLV_H
41 # include <resolv.h>
42 #endif
43 #ifdef HAVE_NETDB_H
44 # include <netdb.h>
45 #endif
47 #include "ntstatus.h"
48 #define WIN32_NO_STATUS
49 #include "windef.h"
50 #include "winternl.h"
51 #include "winbase.h"
52 #include "winnls.h"
53 #include "windns.h"
54 #define USE_WS_PREFIX
55 #include "ws2def.h"
56 #include "ws2ipdef.h"
58 #include "wine/debug.h"
59 #include "wine/heap.h"
60 #include "dnsapi.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];
72 SIZE_T size;
73 void *ptr;
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 );
82 return TRUE;
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;
95 DWORD len;
97 get_unix_codepage();
99 if (unix_cp == CP_UTF8)
101 RtlUTF8ToUnicodeN( dst, dstlen, &len, src, srclen );
102 return len;
104 else
106 len = srclen * sizeof(WCHAR);
107 if (dst) RtlCustomCPToUnicodeN( &unix_cptable, dst, dstlen, &len, src, srclen );
108 return len;
112 static const char *debugstr_type( unsigned short type )
114 const char *str;
116 switch (type)
118 #define X(x) case (x): str = #x; break;
119 X(DNS_TYPE_ZERO)
120 X(DNS_TYPE_A)
121 X(DNS_TYPE_NS)
122 X(DNS_TYPE_MD)
123 X(DNS_TYPE_MF)
124 X(DNS_TYPE_CNAME)
125 X(DNS_TYPE_SOA)
126 X(DNS_TYPE_MB)
127 X(DNS_TYPE_MG)
128 X(DNS_TYPE_MR)
129 X(DNS_TYPE_NULL)
130 X(DNS_TYPE_WKS)
131 X(DNS_TYPE_PTR)
132 X(DNS_TYPE_HINFO)
133 X(DNS_TYPE_MINFO)
134 X(DNS_TYPE_MX)
135 X(DNS_TYPE_TEXT)
136 X(DNS_TYPE_RP)
137 X(DNS_TYPE_AFSDB)
138 X(DNS_TYPE_X25)
139 X(DNS_TYPE_ISDN)
140 X(DNS_TYPE_RT)
141 X(DNS_TYPE_NSAP)
142 X(DNS_TYPE_NSAPPTR)
143 X(DNS_TYPE_SIG)
144 X(DNS_TYPE_KEY)
145 X(DNS_TYPE_PX)
146 X(DNS_TYPE_GPOS)
147 X(DNS_TYPE_AAAA)
148 X(DNS_TYPE_LOC)
149 X(DNS_TYPE_NXT)
150 X(DNS_TYPE_EID)
151 X(DNS_TYPE_NIMLOC)
152 X(DNS_TYPE_SRV)
153 X(DNS_TYPE_ATMA)
154 X(DNS_TYPE_NAPTR)
155 X(DNS_TYPE_KX)
156 X(DNS_TYPE_CERT)
157 X(DNS_TYPE_A6)
158 X(DNS_TYPE_DNAME)
159 X(DNS_TYPE_SINK)
160 X(DNS_TYPE_OPT)
161 X(DNS_TYPE_UINFO)
162 X(DNS_TYPE_UID)
163 X(DNS_TYPE_GID)
164 X(DNS_TYPE_UNSPEC)
165 X(DNS_TYPE_ADDRS)
166 X(DNS_TYPE_TKEY)
167 X(DNS_TYPE_TSIG)
168 X(DNS_TYPE_IXFR)
169 X(DNS_TYPE_AXFR)
170 X(DNS_TYPE_MAILB)
171 X(DNS_TYPE_MAILA)
172 X(DNS_TYPE_ANY)
173 X(DNS_TYPE_WINS)
174 X(DNS_TYPE_WINSR)
175 #undef X
176 default:
177 return wine_dbg_sprintf( "0x%04x", type );
180 return wine_dbg_sprintf( "%s", str );
183 static const char *debugstr_section( ns_sect section )
185 switch (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";
191 default:
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)
208 return RES_DEFAULT;
210 if (options & DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE)
211 ret |= RES_IGNTC;
212 if (options & DNS_QUERY_USE_TCP_ONLY)
213 ret |= RES_USEVC;
214 if (options & DNS_QUERY_NO_RECURSION)
215 ret &= ~RES_RECURSE;
216 if (options & DNS_QUERY_NO_LOCAL_NAME)
217 ret &= ~RES_DNSRCH;
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" );
239 return ret;
242 static DNS_STATUS map_error( int error )
244 switch (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;
257 default:
258 FIXME( "unmapped error code: %d\n", error );
259 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
263 static DNS_STATUS map_h_errno( int error )
265 switch (error)
267 case NO_DATA:
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;
273 #endif
274 default:
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;
283 char *ptr, *end;
285 init_resolver();
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)
294 *len = needed;
295 return !list ? ERROR_SUCCESS : ERROR_MORE_DATA;
298 *len = needed;
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;
318 return FALSE;
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;
329 init_resolver();
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;
348 found++;
350 if (!found) return DNS_ERROR_NO_DNS_SERVERS;
352 needed = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[found]);
353 if (!addrs || *len < needed)
355 *len = needed;
356 return !addrs ? ERROR_SUCCESS : ERROR_MORE_DATA;
358 *len = needed;
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);
373 else
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);
380 found++;
383 free( buf );
384 return ERROR_SUCCESS;
387 #else
389 DNS_STATUS CDECL resolv_get_serverlist( USHORT family, DNS_ADDR_ARRAY *addrs, DWORD *len )
391 DWORD needed, found, i;
393 init_resolver();
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;
407 #endif
408 if (filter( sin_family, family )) continue;
409 found++;
411 if (!found) return DNS_ERROR_NO_DNS_SERVERS;
413 needed = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[found]);
414 if (!addrs || *len < needed)
416 *len = needed;
417 return !addrs ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
419 *len = needed;
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;
428 #endif
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);
439 else
440 #endif
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);
447 found++;
450 return ERROR_SUCCESS;
452 #endif
454 DNS_STATUS CDECL resolv_set_serverlist( const IP4_ARRAY *addrs )
456 int i;
458 init_resolver();
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 );
483 return str;
486 static char *str_from_rdata( const unsigned char *rdata )
488 char *str;
489 unsigned int len = rdata[0];
491 if ((str = RtlAllocateHeap( GetProcessHeap(), 0, len + 1 )))
493 memcpy( str, ++rdata, len );
494 str[len] = 0;
496 return str;
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);
504 switch (rr->type)
506 case ns_t_key:
508 pos += sizeof(WORD) + sizeof(BYTE) + sizeof(BYTE);
509 size += rr->rdata + rr->rdlength - pos - 1;
510 break;
512 case ns_t_sig:
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;
517 break;
519 case ns_t_hinfo:
520 case ns_t_isdn:
521 case ns_t_txt:
522 case ns_t_x25:
524 while (pos[0] && pos < rr->rdata + rr->rdlength)
526 num++;
527 pos += pos[0] + 1;
529 size += (num - 1) * sizeof(PCHAR);
530 break;
532 case ns_t_null:
533 case ns_t_opt:
535 size += rr->rdlength - 1;
536 break;
538 case ns_t_nxt:
539 case ns_t_wks:
540 case 0xff01: /* WINS */
542 FIXME( "unhandled type: %s\n", debugstr_type( rr->type ) );
543 break;
545 default:
546 break;
548 return size;
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;
557 switch (rr->type)
559 case ns_t_a:
561 r->Data.A.IpAddress = *(const DWORD *)pos;
562 *dlen = sizeof(DNS_A_DATA);
563 break;
565 case ns_t_aaaa:
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);
574 break;
576 case ns_t_key:
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);
589 break;
591 case ns_t_rp:
592 case ns_t_minfo:
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);
608 break;
610 case ns_t_afsdb:
611 case ns_t_rt:
612 case ns_t_mx:
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);
619 break;
621 case ns_t_null:
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;
627 break;
629 case ns_t_opt:
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;
636 break;
638 case ns_t_cname:
639 case ns_t_ns:
640 case ns_t_mb:
641 case ns_t_md:
642 case ns_t_mf:
643 case ns_t_mg:
644 case ns_t_mr:
645 case ns_t_ptr:
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);
651 break;
653 case ns_t_sig:
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);
676 break;
678 case ns_t_soa:
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);
703 break;
705 case ns_t_srv:
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);
715 break;
717 case ns_t_hinfo:
718 case ns_t_isdn:
719 case ns_t_x25:
720 case ns_t_txt:
722 i = 0;
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;
731 i++;
732 pos += pos[0] + 1;
734 r->Data.TXT.dwStringCount = i;
735 *dlen = sizeof(DNS_TXT_DATAA) + (i - 1) * sizeof(PCHAR);
736 break;
738 case ns_t_atma:
739 case ns_t_loc:
740 case ns_t_nxt:
741 case ns_t_tsig:
742 case ns_t_wks:
743 case 0x00f9: /* TKEY */
744 case 0xff01: /* WINS */
745 case 0xff02: /* WINSR */
746 default:
747 FIXME( "unhandled type: %s\n", debugstr_type( rr->type ) );
748 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
751 return ret;
754 static inline char *heap_strdup( const char *src )
756 char *dst;
757 if (!src) return NULL;
758 if ((dst = RtlAllocateHeap( GetProcessHeap(), 0, (strlen( src ) + 1) * sizeof(char) ))) strcpy( dst, src );
759 return dst;
762 static DNS_STATUS copy_record( ns_msg msg, ns_sect section, unsigned short num, DNS_RECORDA **recp )
764 DNS_STATUS ret;
765 DNS_RECORDA *record;
766 WORD dlen;
767 ns_rr rr;
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 );
790 return ret;
792 record->wDataLength = dlen;
793 *recp = record;
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;
802 unsigned int i;
804 for (r = list; (list = r); r = next)
806 RtlFreeHeap( GetProcessHeap(), 0, r->pName );
808 switch (r->wType)
810 case DNS_TYPE_HINFO:
811 case DNS_TYPE_ISDN:
812 case DNS_TYPE_TEXT:
813 case DNS_TYPE_X25:
815 for (i = 0; i < r->Data.TXT.dwStringCount; i++)
816 RtlFreeHeap( GetProcessHeap(), 0, r->Data.TXT.pStringArray[i] );
817 break;
819 case DNS_TYPE_MINFO:
820 case DNS_TYPE_RP:
822 RtlFreeHeap( GetProcessHeap(), 0, r->Data.MINFO.pNameMailbox );
823 RtlFreeHeap( GetProcessHeap(), 0, r->Data.MINFO.pNameErrorsMailbox );
824 break;
826 case DNS_TYPE_AFSDB:
827 case DNS_TYPE_RT:
828 case DNS_TYPE_MX:
830 RtlFreeHeap( GetProcessHeap(), 0, r->Data.MX.pNameExchange );
831 break;
833 case DNS_TYPE_NXT:
835 RtlFreeHeap( GetProcessHeap(), 0, r->Data.NXT.pNameNext );
836 break;
838 case DNS_TYPE_CNAME:
839 case DNS_TYPE_MB:
840 case DNS_TYPE_MD:
841 case DNS_TYPE_MF:
842 case DNS_TYPE_MG:
843 case DNS_TYPE_MR:
844 case DNS_TYPE_NS:
845 case DNS_TYPE_PTR:
847 RtlFreeHeap( GetProcessHeap(), 0, r->Data.PTR.pNameHost );
848 break;
850 case DNS_TYPE_SIG:
852 RtlFreeHeap( GetProcessHeap(), 0, r->Data.SIG.pNameSigner );
853 break;
855 case DNS_TYPE_SOA:
857 RtlFreeHeap( GetProcessHeap(), 0, r->Data.SOA.pNamePrimaryServer );
858 RtlFreeHeap( GetProcessHeap(), 0, r->Data.SOA.pNameAdministrator );
859 break;
861 case DNS_TYPE_SRV:
863 RtlFreeHeap( GetProcessHeap(), 0, r->Data.SRV.pNameTarget );
864 break;
866 default: break;
869 next = r->pNext;
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;
878 unsigned int i, num;
879 unsigned char answer[DNS_MAX_PACKET_SIZE];
880 ns_sect sections[] = { ns_s_an, ns_s_ar };
881 ns_msg msg;
882 DNS_RECORDA *record = NULL;
883 DNS_RRSET rrset;
884 int len;
886 DNS_RRSET_INIT( rrset );
888 init_resolver();
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 );
894 goto exit;
897 if (ns_initparse( answer, len, &msg ) < 0)
899 ret = DNS_ERROR_BAD_PACKET;
900 goto exit;
903 #define RCODE_MASK 0x0f
904 if ((msg._flags & RCODE_MASK) != ns_r_noerror)
906 ret = map_error( msg._flags & RCODE_MASK );
907 goto exit;
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 );
921 exit:
922 DNS_RRSET_TERMINATE( rrset );
924 if (ret != ERROR_SUCCESS)
925 free_record_list( rrset.pFirstRR );
926 else
927 *result = (DNS_RECORDA *)rrset.pFirstRR;
929 return ret;
932 static const struct resolv_funcs funcs =
934 resolv_get_searchlist,
935 resolv_get_serverlist,
936 resolv_query,
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 */