- Import Alex's dnslib
[reactos.git] / reactos / lib / dnslib / straddr.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS DNS Shared Library
4 * FILE: lib/dnslib/straddr.c
5 * PURPOSE: Functions for address<->string conversion.
6 */
7
8 /* INCLUDES ******************************************************************/
9 #include "precomp.h"
10
11 /* DATA **********************************************************************/
12
13 /* FUNCTIONS *****************************************************************/
14
15 LPWSTR
16 WINAPI
17 Dns_Ip6AddressToReverseName_W(OUT LPWSTR Name,
18 IN IN6_ADDR Address)
19 {
20 /* FIXME */
21 return NULL;
22 }
23
24 LPWSTR
25 WINAPI
26 Dns_Ip4AddressToReverseName_W(OUT LPWSTR Name,
27 IN IN_ADDR Address)
28 {
29 /* Simply append the ARPA string */
30 return Name + (wsprintfW(Name,
31 L"%u.%u.%u.%u.in-addr.arpa.",
32 Address.S_un.S_addr >> 24,
33 Address.S_un.S_addr >> 10,
34 Address.S_un.S_addr >> 8,
35 Address.S_un.S_addr) * sizeof(WCHAR));
36 }
37
38 BOOLEAN
39 WINAPI
40 Dns_Ip4ReverseNameToAddress_A(OUT PIN_ADDR Address,
41 IN LPSTR Name)
42 {
43 /* FIXME */
44 return FALSE;
45 }
46
47 BOOLEAN
48 WINAPI
49 Dns_Ip6ReverseNameToAddress_A(OUT PIN6_ADDR Address,
50 IN LPSTR Name)
51 {
52 /* FIXME */
53 return FALSE;
54 }
55
56 BOOLEAN
57 WINAPI
58 Dns_Ip6StringToAddress_A(OUT PIN6_ADDR Address,
59 IN LPSTR Name)
60 {
61 PCHAR Terminator;
62 NTSTATUS Status;
63
64 /* Let RTL Do it for us */
65 Status = RtlIpv6StringToAddressA(Name, &Terminator, Address);
66 if (NT_SUCCESS(Status)) return TRUE;
67
68 /* We failed */
69 return FALSE;
70 }
71
72 BOOLEAN
73 WINAPI
74 Dns_Ip6StringToAddress_W(OUT PIN6_ADDR Address,
75 IN LPWSTR Name)
76 {
77 PCHAR Terminator;
78 NTSTATUS Status;
79
80 /* Let RTL Do it for us */
81 Status = RtlIpv6StringToAddressW(Name, &Terminator, Address);
82 if (NT_SUCCESS(Status)) return TRUE;
83
84 /* We failed */
85 return FALSE;
86 }
87
88 BOOLEAN
89 WINAPI
90 Dns_Ip4StringToAddress_A(OUT PIN_ADDR Address,
91 IN LPSTR Name)
92 {
93 ULONG Addr;
94
95 /* Use inet_addr to convert it... */
96 Addr = inet_addr(Name);
97 if (Addr == -1)
98 {
99 /* Check if it's the wildcard (which is ok...) */
100 if (strcmp("255.255.255.255", Name)) return FALSE;
101 }
102
103 /* If we got here, then we suceeded... return the address */
104 Address->S_un.S_addr = Addr;
105 return TRUE;
106 }
107
108 BOOLEAN
109 WINAPI
110 Dns_Ip4StringToAddress_W(OUT PIN_ADDR Address,
111 IN LPWSTR Name)
112 {
113 CHAR AnsiName[16];
114 ULONG Size = sizeof(AnsiName);
115 INT ErrorCode;
116
117 /* Make a copy of the name in ANSI */
118 ErrorCode = Dns_StringCopy(&AnsiName,
119 &Size,
120 Name,
121 0,
122 UnicodeString,
123 AnsiString);
124 if (ErrorCode)
125 {
126 /* Copy made sucesfully, now convert it */
127 ErrorCode = Dns_Ip4StringToAddress_A(Address, AnsiName);
128 }
129
130 /* Return either 0 bytes copied (failure == false) or conversion status */
131 return ErrorCode;
132 }
133
134 BOOLEAN
135 WINAPI
136 Dns_Ip4ReverseNameToAddress_W(OUT PIN_ADDR Address,
137 IN LPWSTR Name)
138 {
139 CHAR AnsiName[32];
140 ULONG Size = sizeof(AnsiName);
141 INT ErrorCode;
142
143 /* Make a copy of the name in ANSI */
144 ErrorCode = Dns_StringCopy(&AnsiName,
145 &Size,
146 Name,
147 0,
148 UnicodeString,
149 AnsiString);
150 if (ErrorCode)
151 {
152 /* Copy made sucesfully, now convert it */
153 ErrorCode = Dns_Ip4ReverseNameToAddress_A(Address, AnsiName);
154 }
155
156 /* Return either 0 bytes copied (failure == false) or conversion status */
157 return ErrorCode;
158 }
159
160 BOOLEAN
161 WINAPI
162 Dns_StringToAddressEx(OUT PVOID Address,
163 IN OUT PULONG AddressSize,
164 IN PVOID AddressName,
165 IN OUT PDWORD AddressFamily,
166 IN BOOLEAN Unicode,
167 IN BOOLEAN Reverse)
168 {
169 DWORD Af = *AddressFamily;
170 ULONG AddrSize = *AddressSize;
171 IN6_ADDR Addr;
172 BOOLEAN Return;
173 INT ErrorCode;
174 CHAR AnsiName[INET6_ADDRSTRLEN + sizeof("ip6.arpa.")];
175 ULONG Size = sizeof(AnsiName);
176
177 /* First check if this is a reverse address string */
178 if (Reverse)
179 {
180 /* Convert it right now to ANSI as an optimization */
181 Dns_StringCopy(AnsiName,
182 &Size,
183 AddressName,
184 0,
185 UnicodeString,
186 AnsiString);
187
188 /* Use the ANSI Name instead */
189 AddressName = AnsiName;
190 }
191
192 /*
193 * If the caller doesn't know what the family is, we'll assume IPv4 and
194 * check if we failed or not. If the caller told us it's IPv4, then just
195 * do IPv4...
196 */
197 if ((Af == AF_UNSPEC) || (Af == AF_INET))
198 {
199 /* Now check if the caller gave us the reverse name or not */
200 if (Reverse)
201 {
202 /* Get the Address */
203 Return = Dns_Ip4ReverseNameToAddress_A((PIN_ADDR)&Addr, AddressName);
204 }
205 else
206 {
207 /* Check if the caller gave us unicode or not */
208 if (Unicode)
209 {
210 /* Get the Address */
211 Return = Dns_Ip4StringToAddress_W((PIN_ADDR)&Addr, AddressName);
212 }
213 else
214 {
215 /* Get the Address */
216 Return = Dns_Ip4StringToAddress_A((PIN_ADDR)&Addr, AddressName);
217 }
218 }
219
220 /* Check if we suceeded */
221 if (Return)
222 {
223 /* Save address family */
224 Af = AF_INET;
225
226 /* Check if the address size matches */
227 if (AddrSize < sizeof(IN_ADDR))
228 {
229 /* Invalid match, set error code */
230 ErrorCode = ERROR_MORE_DATA;
231 }
232 else
233 {
234 /* It matches, save the address! */
235 *(PIN_ADDR)Address = *(PIN_ADDR)&Addr;
236 }
237 }
238 }
239
240 /* If we are here, either AF_INET6 was specified or IPv4 failed */
241 if ((Af == AF_UNSPEC) || (Af == AF_INET6))
242 {
243 /* Now check if the caller gave us the reverse name or not */
244 if (Reverse)
245 {
246 /* Get the Address */
247 Return = Dns_Ip6ReverseNameToAddress_A(&Addr, AddressName);
248 }
249 else
250 {
251 /* Check if the caller gave us unicode or not */
252 if (Unicode)
253 {
254 /* Get the Address */
255 Return = Dns_Ip6StringToAddress_W(&Addr, AddressName);
256 }
257 else
258 {
259 /* Get the Address */
260 Return = Dns_Ip6StringToAddress_A(&Addr, AddressName);
261 }
262 }
263
264 /* Check if we suceeded */
265 if (Return)
266 {
267 /* Save address family */
268 Af = AF_INET6;
269
270 /* Check if the address size matches */
271 if (AddrSize < sizeof(IN6_ADDR))
272 {
273 /* Invalid match, set error code */
274 ErrorCode = ERROR_MORE_DATA;
275 }
276 else
277 {
278 /* It matches, save the address! */
279 *(PIN6_ADDR)Address = Addr;
280 }
281 }
282 }
283 else if (Af != AF_INET)
284 {
285 /* You're like.. ATM or something? Get outta here! */
286 Af = AF_UNSPEC;
287 ErrorCode = WSA_INVALID_PARAMETER;
288 }
289
290 /* Set error if we had one */
291 if (ErrorCode) SetLastError(ErrorCode);
292
293 /* Return the address family and size */
294 *AddressFamily = Af;
295 *AddressSize = AddrSize;
296
297 /* Return success or failure */
298 return (ErrorCode == ERROR_SUCCESS);
299 }
300
301 BOOLEAN
302 WINAPI
303 Dns_StringToAddressW(OUT PVOID Address,
304 IN OUT PULONG AddressSize,
305 IN LPWSTR AddressName,
306 IN OUT PDWORD AddressFamily)
307 {
308 /* Call the common API */
309 return Dns_StringToAddressEx(Address,
310 AddressSize,
311 AddressName,
312 AddressFamily,
313 TRUE,
314 FALSE);
315 }
316
317 BOOLEAN
318 WINAPI
319 Dns_StringToDnsAddrEx(OUT PDNS_ADDRESS DnsAddr,
320 IN PVOID AddressName,
321 IN DWORD AddressFamily,
322 IN BOOLEAN Unicode,
323 IN BOOLEAN Reverse)
324 {
325 IN6_ADDR Addr;
326 BOOLEAN Return;
327 INT ErrorCode = ERROR_SUCCESS;
328 CHAR AnsiName[INET6_ADDRSTRLEN + sizeof("ip6.arpa.")];
329 ULONG Size = sizeof(AnsiName);
330
331 /* First check if this is a reverse address string */
332 if ((Reverse) && (Unicode))
333 {
334 /* Convert it right now to ANSI as an optimization */
335 Dns_StringCopy(AnsiName,
336 &Size,
337 AddressName,
338 0,
339 UnicodeString,
340 AnsiString);
341
342 /* Use the ANSI Name instead */
343 AddressName = AnsiName;
344 }
345
346 /*
347 * If the caller doesn't know what the family is, we'll assume IPv4 and
348 * check if we failed or not. If the caller told us it's IPv4, then just
349 * do IPv4...
350 */
351 if ((AddressFamily == AF_UNSPEC) || (AddressFamily == AF_INET))
352 {
353 /* Now check if the caller gave us the reverse name or not */
354 if (Reverse)
355 {
356 /* Get the Address */
357 Return = Dns_Ip4ReverseNameToAddress_A((PIN_ADDR)&Addr, AddressName);
358 }
359 else
360 {
361 /* Check if the caller gave us unicode or not */
362 if (Unicode)
363 {
364 /* Get the Address */
365 Return = Dns_Ip4StringToAddress_W((PIN_ADDR)&Addr, AddressName);
366 }
367 else
368 {
369 /* Get the Address */
370 Return = Dns_Ip4StringToAddress_A((PIN_ADDR)&Addr, AddressName);
371 }
372 }
373
374 /* Check if we suceeded */
375 if (Return)
376 {
377 /* Build the IPv4 Address */
378 DnsAddr_BuildFromIp4(DnsAddr, *(PIN_ADDR)&Addr, 0);
379
380 /* So we don't go in the code below... */
381 AddressFamily = AF_INET;
382 }
383 }
384
385 /* If we are here, either AF_INET6 was specified or IPv4 failed */
386 if ((AddressFamily == AF_UNSPEC) || (AddressFamily == AF_INET6))
387 {
388 /* Now check if the caller gave us the reverse name or not */
389 if (Reverse)
390 {
391 /* Get the Address */
392 Return = Dns_Ip6ReverseNameToAddress_A(&Addr, AddressName);
393 if (Return)
394 {
395 /* Build the IPv6 Address */
396 DnsAddr_BuildFromIp6(DnsAddr, &Addr, 0, 0);
397 }
398 else
399 {
400 goto Quickie;
401 }
402 }
403 else
404 {
405 /* Check if the caller gave us unicode or not */
406 if (Unicode)
407 {
408 /* Get the Address */
409 if (NT_SUCCESS(RtlIpv6StringToAddressExW(AddressName,
410 &DnsAddr->Ip6Address.sin6_addr,
411 &DnsAddr->Ip6Address.sin6_scope_id,
412 &DnsAddr->Ip6Address.sin6_port)))
413 Return = TRUE;
414 else
415 Return = FALSE;
416 }
417 else
418 {
419 /* Get the Address */
420 if (NT_SUCCESS(RtlIpv6StringToAddressExA(AddressName,
421 &DnsAddr->Ip6Address.sin6_addr,
422 &DnsAddr->Ip6Address.sin6_scope_id,
423 &DnsAddr->Ip6Address.sin6_port)))
424 Return = TRUE;
425 else
426 Return = FALSE;
427 }
428 }
429
430 /* Check if we suceeded */
431 if (Return)
432 {
433 /* Finish setting up the structure */
434 DnsAddr->Ip6Address.sin6_family = AF_INET6;
435 DnsAddr->AddressLength = sizeof(SOCKADDR_IN6);
436 }
437 }
438 else if (AddressFamily != AF_INET)
439 {
440 /* You're like.. ATM or something? Get outta here! */
441 RtlZeroMemory(DnsAddr, sizeof(DNS_ADDRESS));
442 SetLastError(WSA_INVALID_PARAMETER);
443 }
444
445 Quickie:
446 /* Return success or failure */
447 return (ErrorCode == ERROR_SUCCESS);
448 }
449
450 BOOLEAN
451 WINAPI
452 Dns_ReverseNameToDnsAddr_W(OUT PDNS_ADDRESS DnsAddr,
453 IN LPWSTR Name)
454 {
455 /* Call the common API */
456 return Dns_StringToDnsAddrEx(DnsAddr,
457 Name,
458 AF_UNSPEC,
459 TRUE,
460 TRUE);
461 }
462